1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 #include <hintids.hxx> 32 #include "cntfrm.hxx" 33 #include "doc.hxx" 34 35 #include "hintids.hxx" 36 #include <editeng/ulspitem.hxx> 37 #include <editeng/lrspitem.hxx> 38 #include <fmtclds.hxx> 39 #include <fmtfordr.hxx> 40 #include <frmfmt.hxx> 41 #include <node.hxx> 42 #include "frmtool.hxx" 43 #include "colfrm.hxx" 44 #include "pagefrm.hxx" 45 #include "bodyfrm.hxx" // ColumnFrms jetzt mit BodyFrm 46 #include "rootfrm.hxx" // wg. RemoveFtns 47 #include "sectfrm.hxx" // wg. FtnAtEnd-Flag 48 #include "switerator.hxx" 49 50 // ftnfrm.cxx: 51 void lcl_RemoveFtns( SwFtnBossFrm* pBoss, sal_Bool bPageOnly, sal_Bool bEndNotes ); 52 53 54 /************************************************************************* 55 |* 56 |* SwColumnFrm::SwColumnFrm() 57 |* 58 |* Ersterstellung MA ?? 59 |* Letzte Aenderung AMA 30. Oct 98 60 |* 61 |*************************************************************************/ 62 SwColumnFrm::SwColumnFrm( SwFrmFmt *pFmt, SwFrm* pSib ): 63 SwFtnBossFrm( pFmt, pSib ) 64 { 65 nType = FRMC_COLUMN; 66 SwBodyFrm* pColBody = new SwBodyFrm( pFmt->GetDoc()->GetDfltFrmFmt(), pSib ); 67 pColBody->InsertBehind( this, 0 ); // ColumnFrms jetzt mit BodyFrm 68 SetMaxFtnHeight( LONG_MAX ); 69 } 70 71 SwColumnFrm::~SwColumnFrm() 72 { 73 SwFrmFmt *pFmt = GetFmt(); 74 SwDoc *pDoc; 75 if ( !(pDoc = pFmt->GetDoc())->IsInDtor() && pFmt->IsLastDepend() ) 76 { 77 //Ich bin der einzige, weg mit dem Format. 78 //Vorher ummelden, damit die Basisklasse noch klarkommt. 79 pDoc->GetDfltFrmFmt()->Add( this ); 80 pDoc->DelFrmFmt( pFmt ); 81 } 82 } 83 84 /************************************************************************* 85 |* 86 |* SwLayoutFrm::ChgColumns() 87 |* 88 |* Ersterstellung MA 11. Feb. 93 89 |* Letzte Aenderung MA 12. Oct. 98 90 |* 91 |*************************************************************************/ 92 93 void MA_FASTCALL lcl_RemoveColumns( SwLayoutFrm *pCont, sal_uInt16 nCnt ) 94 { 95 ASSERT( pCont && pCont->Lower() && pCont->Lower()->IsColumnFrm(), 96 "Keine Spalten zu entfernen." ); 97 98 SwColumnFrm *pColumn = (SwColumnFrm*)pCont->Lower(); 99 ::lcl_RemoveFtns( pColumn, sal_True, sal_True ); 100 while ( pColumn->GetNext() ) 101 { 102 ASSERT( pColumn->GetNext()->IsColumnFrm(), 103 "Nachbar von ColFrm kein ColFrm." ); 104 pColumn = (SwColumnFrm*)pColumn->GetNext(); 105 } 106 for ( sal_uInt16 i = 0; i < nCnt; ++i ) 107 { 108 SwColumnFrm *pTmp = (SwColumnFrm*)pColumn->GetPrev(); 109 pColumn->Cut(); 110 delete pColumn; //Format wird ggf. im DTor mit vernichtet. 111 pColumn = pTmp; 112 } 113 } 114 115 SwLayoutFrm * MA_FASTCALL lcl_FindColumns( SwLayoutFrm *pLay, sal_uInt16 nCount ) 116 { 117 SwFrm *pCol = pLay->Lower(); 118 if ( pLay->IsPageFrm() ) 119 pCol = ((SwPageFrm*)pLay)->FindBodyCont()->Lower(); 120 121 if ( pCol && pCol->IsColumnFrm() ) 122 { 123 SwFrm *pTmp = pCol; 124 sal_uInt16 i; 125 for ( i = 0; pTmp; pTmp = pTmp->GetNext(), ++i ) 126 /* do nothing */; 127 return i == nCount ? (SwLayoutFrm*)pCol : 0; 128 } 129 return 0; 130 } 131 132 133 static sal_Bool lcl_AddColumns( SwLayoutFrm *pCont, sal_uInt16 nCount ) 134 { 135 SwDoc *pDoc = pCont->GetFmt()->GetDoc(); 136 const sal_Bool bMod = pDoc->IsModified(); 137 138 //Format sollen soweit moeglich geshared werden. Wenn es also schon einen 139 //Nachbarn mit den selben Spalteneinstellungen gibt, so koennen die 140 //Spalten an die selben Formate gehaengt werden. 141 //Der Nachbar kann ueber das Format gesucht werden, wer der Owner des Attributes 142 //ist, ist allerdings vom Frametyp abhaengig. 143 SwLayoutFrm *pAttrOwner = pCont; 144 if ( pCont->IsBodyFrm() ) 145 pAttrOwner = pCont->FindPageFrm(); 146 SwLayoutFrm *pNeighbourCol = 0; 147 SwIterator<SwLayoutFrm,SwFmt> aIter( *pAttrOwner->GetFmt() ); 148 SwLayoutFrm *pNeighbour = aIter.First(); 149 150 sal_uInt16 nAdd = 0; 151 SwFrm *pCol = pCont->Lower(); 152 if ( pCol && pCol->IsColumnFrm() ) 153 for ( nAdd = 1; pCol; pCol = pCol->GetNext(), ++nAdd ) 154 /* do nothing */; 155 while ( pNeighbour ) 156 { 157 if ( 0 != (pNeighbourCol = lcl_FindColumns( pNeighbour, nCount+nAdd )) && 158 pNeighbourCol != pCont ) 159 break; 160 pNeighbourCol = 0; 161 pNeighbour = aIter.Next(); 162 } 163 164 sal_Bool bRet; 165 SwTwips nMax = pCont->IsPageBodyFrm() ? 166 pCont->FindPageFrm()->GetMaxFtnHeight() : LONG_MAX; 167 if ( pNeighbourCol ) 168 { 169 bRet = sal_False; 170 SwFrm *pTmp = pCont->Lower(); 171 while ( pTmp ) 172 { 173 pTmp = pTmp->GetNext(); 174 pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext(); 175 } 176 for ( sal_uInt16 i = 0; i < nCount; ++i ) 177 { 178 SwColumnFrm *pTmpCol = new SwColumnFrm( pNeighbourCol->GetFmt(), pCont ); 179 pTmpCol->SetMaxFtnHeight( nMax ); 180 pTmpCol->InsertBefore( pCont, NULL ); 181 pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext(); 182 } 183 } 184 else 185 { 186 bRet = sal_True; 187 for ( sal_uInt16 i = 0; i < nCount; ++i ) 188 { 189 SwFrmFmt *pFmt = pDoc->MakeFrmFmt( aEmptyStr, pDoc->GetDfltFrmFmt()); 190 SwColumnFrm *pTmp = new SwColumnFrm( pFmt, pCont ); 191 pTmp->SetMaxFtnHeight( nMax ); 192 pTmp->Paste( pCont ); 193 } 194 } 195 196 if ( !bMod ) 197 pDoc->ResetModified(); 198 return bRet; 199 } 200 201 /*-----------------21.09.99 15:42------------------- 202 * ChgColumns() adds or removes columns from a layoutframe. 203 * Normally, a layoutframe with a column attribut of 1 or 0 columns contains 204 * no columnframe. However, a sectionframe with "footnotes at the end" needs 205 * a columnframe. If the bChgFtn-flag is set, the columnframe will be inserted 206 * or remove, if necessary. 207 * --------------------------------------------------*/ 208 209 void SwLayoutFrm::ChgColumns( const SwFmtCol &rOld, const SwFmtCol &rNew, 210 const sal_Bool bChgFtn ) 211 { 212 if ( rOld.GetNumCols() <= 1 && rNew.GetNumCols() <= 1 && !bChgFtn ) 213 return; 214 // --> OD 2009-08-12 #i97379# 215 // If current lower is a no text frame, then columns are not allowed 216 if ( Lower() && Lower()->IsNoTxtFrm() && 217 rNew.GetNumCols() > 1 ) 218 { 219 return; 220 } 221 // <-- 222 223 sal_uInt16 nNewNum, nOldNum = 1; 224 if( Lower() && Lower()->IsColumnFrm() ) 225 { 226 SwFrm* pCol = Lower(); 227 while( 0 != (pCol=pCol->GetNext()) ) 228 ++nOldNum; 229 } 230 nNewNum = rNew.GetNumCols(); 231 if( !nNewNum ) 232 ++nNewNum; 233 sal_Bool bAtEnd; 234 if( IsSctFrm() ) 235 bAtEnd = ((SwSectionFrm*)this)->IsAnyNoteAtEnd(); 236 else 237 bAtEnd = sal_False; 238 239 //Einstellung der Spaltenbreiten ist nur bei neuen Formaten notwendig. 240 sal_Bool bAdjustAttributes = nOldNum != rOld.GetNumCols(); 241 242 //Wenn die Spaltenanzahl unterschiedlich ist, wird der Inhalt 243 //gesichert und restored. 244 SwFrm *pSave = 0; 245 if( nOldNum != nNewNum || bChgFtn ) 246 { 247 SwDoc *pDoc = GetFmt()->GetDoc(); 248 ASSERT( pDoc, "FrmFmt gibt kein Dokument her." ); 249 // SaveCntnt wuerde auch den Inhalt der Fussnotencontainer aufsaugen 250 // und im normalen Textfluss unterbringen. 251 if( IsPageBodyFrm() ) 252 pDoc->GetCurrentLayout()->RemoveFtns( (SwPageFrm*)GetUpper(), sal_True, sal_False ); //swmod 080218 253 pSave = ::SaveCntnt( this ); 254 255 //Wenn Spalten existieren, jetzt aber eine Spaltenanzahl von 256 //0 oder eins gewuenscht ist, so werden die Spalten einfach vernichtet. 257 if ( nNewNum == 1 && !bAtEnd ) 258 { 259 ::lcl_RemoveColumns( this, nOldNum ); 260 if ( IsBodyFrm() ) 261 SetFrmFmt( pDoc->GetDfltFrmFmt() ); 262 else 263 GetFmt()->SetFmtAttr( SwFmtFillOrder() ); 264 if ( pSave ) 265 ::RestoreCntnt( pSave, this, 0, true ); 266 return; 267 } 268 if ( nOldNum == 1 ) 269 { 270 if ( IsBodyFrm() ) 271 SetFrmFmt( pDoc->GetColumnContFmt() ); 272 else 273 GetFmt()->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ) ); 274 if( !Lower() || !Lower()->IsColumnFrm() ) 275 --nOldNum; 276 } 277 if ( nOldNum > nNewNum ) 278 { 279 ::lcl_RemoveColumns( this, nOldNum - nNewNum ); 280 bAdjustAttributes = sal_True; 281 } 282 else if( nOldNum < nNewNum ) 283 { 284 sal_uInt16 nAdd = nNewNum - nOldNum; 285 bAdjustAttributes = lcl_AddColumns( this, nAdd ); 286 } 287 } 288 289 if ( !bAdjustAttributes ) 290 { 291 if ( rOld.GetLineWidth() != rNew.GetLineWidth() || 292 rOld.GetWishWidth() != rNew.GetWishWidth() || 293 rOld.IsOrtho() != rNew.IsOrtho() ) 294 bAdjustAttributes = sal_True; 295 else 296 { 297 sal_uInt16 nCount = Min( rNew.GetColumns().Count(), rOld.GetColumns().Count() ); 298 for ( sal_uInt16 i = 0; i < nCount; ++i ) 299 if ( !(*rOld.GetColumns()[i] == *rNew.GetColumns()[i]) ) 300 { 301 bAdjustAttributes = sal_True; 302 break; 303 } 304 } 305 } 306 307 //Sodele, jetzt koennen die Spalten bequem eingestellt werden. 308 AdjustColumns( &rNew, bAdjustAttributes ); 309 310 //Erst jetzt den Inhalt restaurieren. Ein frueheres Restaurieren wuerde 311 //unnuetzte Aktionen beim Einstellen zur Folge haben. 312 if ( pSave ) 313 { 314 ASSERT( Lower() && Lower()->IsLayoutFrm() && 315 ((SwLayoutFrm*)Lower())->Lower() && 316 ((SwLayoutFrm*)Lower())->Lower()->IsLayoutFrm(), 317 "Gesucht: Spaltenbody (Tod oder Lebend)." ); // ColumnFrms jetzt mit BodyFrm 318 ::RestoreCntnt( pSave, (SwLayoutFrm*)((SwLayoutFrm*)Lower())->Lower(), 0, true ); 319 } 320 } 321 322 /************************************************************************* 323 |* 324 |* SwLayoutFrm::AdjustColumns() 325 |* 326 |* Ersterstellung MA 19. Jan. 99 327 |* Letzte Aenderung MA 19. Jan. 99 328 |* 329 |*************************************************************************/ 330 331 void SwLayoutFrm::AdjustColumns( const SwFmtCol *pAttr, sal_Bool bAdjustAttributes ) 332 { 333 if( !Lower()->GetNext() ) 334 { 335 Lower()->ChgSize( Prt().SSize() ); 336 return; 337 } 338 339 const sal_Bool bVert = IsVertical(); 340 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin 341 SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori; 342 343 //Ist ein Pointer da, oder sollen wir die Attribute einstellen, 344 //so stellen wir auf jeden Fall die Spaltenbreiten ein. Andernfalls 345 //checken wir, ob eine Einstellung notwendig ist. 346 if ( !pAttr ) 347 { 348 pAttr = &GetFmt()->GetCol(); 349 if ( !bAdjustAttributes ) 350 { 351 long nAvail = (Prt().*fnRect->fnGetWidth)(); 352 for ( SwLayoutFrm *pCol = (SwLayoutFrm*)Lower(); 353 pCol; 354 pCol = (SwLayoutFrm*)pCol->GetNext() ) 355 nAvail -= (pCol->Frm().*fnRect->fnGetWidth)(); 356 if ( !nAvail ) 357 return; 358 } 359 } 360 361 //Sodele, jetzt koennen die Spalten bequem eingestellt werden. 362 //Die Breiten werden mitgezaehlt, damit wir dem letzten den Rest geben 363 //koennen. 364 SwTwips nAvail = (Prt().*fnRect->fnGetWidth)(); 365 const sal_Bool bLine = pAttr->GetLineAdj() != COLADJ_NONE; 366 const sal_uInt16 nMin = bLine ? sal_uInt16( 20 + ( pAttr->GetLineWidth() / 2) ) : 0; 367 368 const sal_Bool bR2L = IsRightToLeft(); 369 SwFrm *pCol = bR2L ? GetLastLower() : Lower(); 370 371 // --> FME 2004-07-16 #i27399# 372 // bOrtho means we have to adjust the column frames manually. Otherwise 373 // we may use the values returned by CalcColWidth: 374 const sal_Bool bOrtho = pAttr->IsOrtho() && pAttr->GetNumCols() > 0; 375 long nGutter = 0; 376 // <-- 377 378 for ( sal_uInt16 i = 0; i < pAttr->GetNumCols(); ++i ) 379 { 380 if( !bOrtho ) 381 { 382 const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ? 383 nAvail : 384 pAttr->CalcColWidth( i, sal_uInt16( (Prt().*fnRect->fnGetWidth)() ) ); 385 386 const Size aColSz = bVert ? 387 Size( Prt().Width(), nWidth ) : 388 Size( nWidth, Prt().Height() ); 389 390 pCol->ChgSize( aColSz ); 391 392 // Hierdurch werden die ColumnBodyFrms von Seitenspalten angepasst und 393 // ihr bFixHeight-Flag wird gesetzt, damit sie nicht schrumpfen/wachsen. 394 // Bei Rahmenspalten hingegen soll das Flag _nicht_ gesetzt werden, 395 // da BodyFrms in Rahmenspalten durchaus wachsen/schrumpfen duerfen. 396 if( IsBodyFrm() ) 397 ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz ); 398 399 nAvail -= nWidth; 400 } 401 402 if ( bOrtho || bAdjustAttributes ) 403 { 404 const SwColumn *pC = pAttr->GetColumns()[i]; 405 const SwAttrSet* pSet = pCol->GetAttrSet(); 406 SvxLRSpaceItem aLR( pSet->GetLRSpace() ); 407 408 //Damit die Trennlinien Platz finden, muessen sie hier 409 //Beruecksichtigung finden. Ueberall wo zwei Spalten aufeinanderstossen 410 //wird jeweils rechts bzw. links ein Sicherheitsabstand von 20 plus 411 //der halben Penbreite einkalkuliert. 412 const sal_uInt16 nLeft = pC->GetLeft(); 413 const sal_uInt16 nRight = pC->GetRight(); 414 415 aLR.SetLeft ( nLeft ); 416 aLR.SetRight( nRight ); 417 418 if ( bLine ) 419 { 420 if ( i == 0 ) 421 { 422 aLR.SetRight( Max( nRight, nMin ) ); 423 } 424 else if ( i == pAttr->GetNumCols() - 1 ) 425 { 426 aLR.SetLeft ( Max( nLeft, nMin ) ); 427 } 428 else 429 { 430 aLR.SetLeft ( Max( nLeft, nMin ) ); 431 aLR.SetRight( Max( nRight, nMin ) ); 432 } 433 } 434 435 if ( bAdjustAttributes ) 436 { 437 SvxULSpaceItem aUL( pSet->GetULSpace() ); 438 aUL.SetUpper( pC->GetUpper()); 439 aUL.SetLower( pC->GetLower()); 440 441 ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aLR ); 442 ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aUL ); 443 } 444 445 nGutter += aLR.GetLeft() + aLR.GetRight(); 446 } 447 448 pCol = bR2L ? pCol->GetPrev() : pCol->GetNext(); 449 } 450 451 if( bOrtho ) 452 { 453 long nInnerWidth = ( nAvail - nGutter ) / pAttr->GetNumCols(); 454 pCol = Lower(); 455 for( sal_uInt16 i = 0; i < pAttr->GetNumCols(); pCol = pCol->GetNext(), ++i ) 456 { 457 SwTwips nWidth; 458 if ( i == pAttr->GetNumCols() - 1 ) 459 nWidth = nAvail; 460 else 461 { 462 SvxLRSpaceItem aLR( pCol->GetAttrSet()->GetLRSpace() ); 463 nWidth = nInnerWidth + aLR.GetLeft() + aLR.GetRight(); 464 } 465 if( nWidth < 0 ) 466 nWidth = 0; 467 468 const Size aColSz = bVert ? 469 Size( Prt().Width(), nWidth ) : 470 Size( nWidth, Prt().Height() ); 471 472 pCol->ChgSize( aColSz ); 473 474 if( IsBodyFrm() ) 475 ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz ); 476 477 nAvail -= nWidth; 478 } 479 } 480 } 481 482 483 484 485 486