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