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 |*************************************************************************/
SwColumnFrm(SwFrmFmt * pFmt,SwFrm * pSib)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
~SwColumnFrm()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
lcl_RemoveColumns(SwLayoutFrm * pCont,sal_uInt16 nCnt)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
lcl_FindColumns(SwLayoutFrm * pLay,sal_uInt16 nCount)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
lcl_AddColumns(SwLayoutFrm * pCont,sal_uInt16 nCount)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
ChgColumns(const SwFmtCol & rOld,const SwFmtCol & rNew,const sal_Bool bChgFtn)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
AdjustColumns(const SwFmtCol * pAttr,sal_Bool bAdjustAttributes)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() && pCol; ++i ) //i118878, value returned by GetNumCols() can't be trusted
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 = pCol->GetNext(), ++i ) //i118878, value returned by GetNumCols() can't be trusted
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