xref: /AOO41X/main/sw/source/core/layout/colfrm.cxx (revision d1af8f7df76017fd1486450c13c1d29f7dd41d5c)
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