Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <editeng/ulspitem.hxx>
22 : #include <fmtclds.hxx>
23 : #include <fmtfordr.hxx>
24 : #include <frmfmt.hxx>
25 : #include "frmtool.hxx"
26 : #include "colfrm.hxx"
27 : #include "pagefrm.hxx"
28 : #include "bodyfrm.hxx" // ColumnFrms now with BodyFrm
29 : #include "rootfrm.hxx" // wg. RemoveFtns
30 : #include "sectfrm.hxx" // wg. FtnAtEnd-Flag
31 : #include "switerator.hxx"
32 :
33 : // ftnfrm.cxx:
34 : void sw_RemoveFtns( SwFtnBossFrm* pBoss, sal_Bool bPageOnly, sal_Bool bEndNotes );
35 :
36 :
37 : /*************************************************************************
38 : |*
39 : |* SwColumnFrm::SwColumnFrm()
40 : |*
41 : |*************************************************************************/
42 60 : SwColumnFrm::SwColumnFrm( SwFrmFmt *pFmt, SwFrm* pSib ):
43 60 : SwFtnBossFrm( pFmt, pSib )
44 : {
45 60 : mnType = FRMC_COLUMN;
46 60 : SwBodyFrm* pColBody = new SwBodyFrm( pFmt->GetDoc()->GetDfltFrmFmt(), pSib );
47 60 : pColBody->InsertBehind( this, 0 ); // ColumnFrms now with BodyFrm
48 60 : SetMaxFtnHeight( LONG_MAX );
49 60 : }
50 :
51 180 : SwColumnFrm::~SwColumnFrm()
52 : {
53 60 : SwFrmFmt *pFmt = GetFmt();
54 : SwDoc *pDoc;
55 60 : if ( !(pDoc = pFmt->GetDoc())->IsInDtor() && pFmt->IsLastDepend() )
56 : {
57 : //I'm the only one, delete the format.
58 : //Get default format before, so the base class can cope with it.
59 19 : pDoc->GetDfltFrmFmt()->Add( this );
60 19 : pDoc->DelFrmFmt( pFmt );
61 : }
62 120 : }
63 :
64 : /*************************************************************************
65 : |*
66 : |* SwLayoutFrm::ChgColumns()
67 : |*
68 : |*************************************************************************/
69 :
70 0 : static void lcl_RemoveColumns( SwLayoutFrm *pCont, sal_uInt16 nCnt )
71 : {
72 : OSL_ENSURE( pCont && pCont->Lower() && pCont->Lower()->IsColumnFrm(),
73 : "Keine Spalten zu entfernen." );
74 :
75 0 : SwColumnFrm *pColumn = (SwColumnFrm*)pCont->Lower();
76 0 : sw_RemoveFtns( pColumn, sal_True, sal_True );
77 0 : while ( pColumn->GetNext() )
78 : {
79 : OSL_ENSURE( pColumn->GetNext()->IsColumnFrm(),
80 : "Nachbar von ColFrm kein ColFrm." );
81 0 : pColumn = (SwColumnFrm*)pColumn->GetNext();
82 : }
83 0 : for ( sal_uInt16 i = 0; i < nCnt; ++i )
84 : {
85 0 : SwColumnFrm *pTmp = (SwColumnFrm*)pColumn->GetPrev();
86 0 : pColumn->Cut();
87 0 : delete pColumn; //format is going to be destroyed in the DTor if needed.
88 0 : pColumn = pTmp;
89 : }
90 0 : }
91 :
92 39 : static SwLayoutFrm * lcl_FindColumns( SwLayoutFrm *pLay, sal_uInt16 nCount )
93 : {
94 39 : SwFrm *pCol = pLay->Lower();
95 39 : if ( pLay->IsPageFrm() )
96 2 : pCol = ((SwPageFrm*)pLay)->FindBodyCont()->Lower();
97 :
98 39 : if ( pCol && pCol->IsColumnFrm() )
99 : {
100 15 : SwFrm *pTmp = pCol;
101 : sal_uInt16 i;
102 15 : for ( i = 0; pTmp; pTmp = pTmp->GetNext(), ++i )
103 : /* do nothing */;
104 15 : return i == nCount ? (SwLayoutFrm*)pCol : 0;
105 : }
106 24 : return 0;
107 : }
108 :
109 :
110 24 : static sal_Bool lcl_AddColumns( SwLayoutFrm *pCont, sal_uInt16 nCount )
111 : {
112 24 : SwDoc *pDoc = pCont->GetFmt()->GetDoc();
113 24 : const sal_Bool bMod = pDoc->IsModified();
114 :
115 : //Formats should be shared whenever possible. If a neighbour already has
116 : //the same column settings we can add them to the same format.
117 : //The neighbour can be searched using the format, however the owner of the
118 : //attribute depends on the frame type.
119 24 : SwLayoutFrm *pAttrOwner = pCont;
120 24 : if ( pCont->IsBodyFrm() )
121 2 : pAttrOwner = pCont->FindPageFrm();
122 24 : SwLayoutFrm *pNeighbourCol = 0;
123 24 : SwIterator<SwLayoutFrm,SwFmt> aIter( *pAttrOwner->GetFmt() );
124 24 : SwLayoutFrm *pNeighbour = aIter.First();
125 :
126 24 : sal_uInt16 nAdd = 0;
127 24 : SwFrm *pCol = pCont->Lower();
128 24 : if ( pCol && pCol->IsColumnFrm() )
129 0 : for ( nAdd = 1; pCol; pCol = pCol->GetNext(), ++nAdd )
130 : /* do nothing */;
131 72 : while ( pNeighbour )
132 : {
133 39 : if ( 0 != (pNeighbourCol = lcl_FindColumns( pNeighbour, nCount+nAdd )) &&
134 : pNeighbourCol != pCont )
135 15 : break;
136 24 : pNeighbourCol = 0;
137 24 : pNeighbour = aIter.Next();
138 : }
139 :
140 : sal_Bool bRet;
141 24 : SwTwips nMax = pCont->IsPageBodyFrm() ?
142 24 : pCont->FindPageFrm()->GetMaxFtnHeight() : LONG_MAX;
143 24 : if ( pNeighbourCol )
144 : {
145 15 : bRet = sal_False;
146 15 : SwFrm *pTmp = pCont->Lower();
147 30 : while ( pTmp )
148 : {
149 0 : pTmp = pTmp->GetNext();
150 0 : pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext();
151 : }
152 56 : for ( sal_uInt16 i = 0; i < nCount; ++i )
153 : {
154 41 : SwColumnFrm *pTmpCol = new SwColumnFrm( pNeighbourCol->GetFmt(), pCont );
155 41 : pTmpCol->SetMaxFtnHeight( nMax );
156 41 : pTmpCol->InsertBefore( pCont, NULL );
157 41 : pNeighbourCol = (SwLayoutFrm*)pNeighbourCol->GetNext();
158 : }
159 : }
160 : else
161 : {
162 9 : bRet = sal_True;
163 28 : for ( sal_uInt16 i = 0; i < nCount; ++i )
164 : {
165 19 : SwFrmFmt *pFmt = pDoc->MakeFrmFmt( aEmptyStr, pDoc->GetDfltFrmFmt());
166 19 : SwColumnFrm *pTmp = new SwColumnFrm( pFmt, pCont );
167 19 : pTmp->SetMaxFtnHeight( nMax );
168 19 : pTmp->Paste( pCont );
169 : }
170 : }
171 :
172 24 : if ( !bMod )
173 6 : pDoc->ResetModified();
174 24 : return bRet;
175 : }
176 :
177 : /*--------------------------------------------------
178 : * ChgColumns() adds or removes columns from a layoutframe.
179 : * Normally, a layoutframe with a column attribut of 1 or 0 columns contains
180 : * no columnframe. However, a sectionframe with "footnotes at the end" needs
181 : * a columnframe. If the bChgFtn-flag is set, the columnframe will be inserted
182 : * or remove, if necessary.
183 : * --------------------------------------------------*/
184 :
185 39 : void SwLayoutFrm::ChgColumns( const SwFmtCol &rOld, const SwFmtCol &rNew,
186 : const sal_Bool bChgFtn )
187 : {
188 39 : if ( rOld.GetNumCols() <= 1 && rNew.GetNumCols() <= 1 && !bChgFtn )
189 7 : return;
190 : // #i97379#
191 : // If current lower is a no text frame, then columns are not allowed
192 32 : if ( Lower() && Lower()->IsNoTxtFrm() &&
193 0 : rNew.GetNumCols() > 1 )
194 : {
195 0 : return;
196 : }
197 :
198 32 : sal_uInt16 nNewNum, nOldNum = 1;
199 32 : if( Lower() && Lower()->IsColumnFrm() )
200 : {
201 8 : SwFrm* pCol = Lower();
202 16 : while( 0 != (pCol=pCol->GetNext()) )
203 0 : ++nOldNum;
204 : }
205 32 : nNewNum = rNew.GetNumCols();
206 32 : if( !nNewNum )
207 12 : ++nNewNum;
208 : sal_Bool bAtEnd;
209 32 : if( IsSctFrm() )
210 30 : bAtEnd = ((SwSectionFrm*)this)->IsAnyNoteAtEnd();
211 : else
212 2 : bAtEnd = sal_False;
213 :
214 : //Setting the column width is only needed for new formats.
215 32 : sal_Bool bAdjustAttributes = nOldNum != rOld.GetNumCols();
216 :
217 : //The content is saved and restored if the column count is different.
218 32 : SwFrm *pSave = 0;
219 32 : if( nOldNum != nNewNum || bChgFtn )
220 : {
221 32 : SwDoc *pDoc = GetFmt()->GetDoc();
222 : OSL_ENSURE( pDoc, "FrmFmt doesn't return a document." );
223 : // SaveCntnt would also suck up the content of the footnote container
224 : // and store it within the normal text flow.
225 32 : if( IsPageBodyFrm() )
226 2 : pDoc->GetCurrentLayout()->RemoveFtns( (SwPageFrm*)GetUpper(), sal_True, sal_False ); //swmod 080218
227 32 : pSave = ::SaveCntnt( this );
228 :
229 : //If columns exist, they get deleted if a column count of 0 or 1 is requested.
230 32 : if ( nNewNum == 1 && !bAtEnd )
231 : {
232 0 : ::lcl_RemoveColumns( this, nOldNum );
233 0 : if ( IsBodyFrm() )
234 0 : SetFrmFmt( pDoc->GetDfltFrmFmt() );
235 : else
236 0 : GetFmt()->SetFmtAttr( SwFmtFillOrder() );
237 0 : if ( pSave )
238 0 : ::RestoreCntnt( pSave, this, 0, true );
239 0 : return;
240 : }
241 32 : if ( nOldNum == 1 )
242 : {
243 32 : if ( IsBodyFrm() )
244 2 : SetFrmFmt( pDoc->GetColumnContFmt() );
245 : else
246 30 : GetFmt()->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ) );
247 32 : if( !Lower() || !Lower()->IsColumnFrm() )
248 24 : --nOldNum;
249 : }
250 32 : if ( nOldNum > nNewNum )
251 : {
252 0 : ::lcl_RemoveColumns( this, nOldNum - nNewNum );
253 0 : bAdjustAttributes = sal_True;
254 : }
255 32 : else if( nOldNum < nNewNum )
256 : {
257 24 : sal_uInt16 nAdd = nNewNum - nOldNum;
258 24 : bAdjustAttributes = lcl_AddColumns( this, nAdd );
259 : }
260 : }
261 :
262 32 : if ( !bAdjustAttributes )
263 : {
264 45 : if ( rOld.GetLineWidth() != rNew.GetLineWidth() ||
265 30 : rOld.GetWishWidth() != rNew.GetWishWidth() ||
266 15 : rOld.IsOrtho() != rNew.IsOrtho() )
267 0 : bAdjustAttributes = sal_True;
268 : else
269 : {
270 15 : sal_uInt16 nCount = std::min( rNew.GetColumns().size(), rOld.GetColumns().size() );
271 15 : for ( sal_uInt16 i = 0; i < nCount; ++i )
272 0 : if ( !(rOld.GetColumns()[i] == rNew.GetColumns()[i]) )
273 : {
274 0 : bAdjustAttributes = sal_True;
275 0 : break;
276 : }
277 : }
278 : }
279 :
280 : //The columns can now be easily adjusted.
281 32 : AdjustColumns( &rNew, bAdjustAttributes );
282 :
283 : //Don't restore the content before. An earlier restore would trigger useless
284 : //actions during setup.
285 32 : if ( pSave )
286 : {
287 : OSL_ENSURE( Lower() && Lower()->IsLayoutFrm() &&
288 : ((SwLayoutFrm*)Lower())->Lower() &&
289 : ((SwLayoutFrm*)Lower())->Lower()->IsLayoutFrm(),
290 : "Gesucht: Spaltenbody (Tod oder Lebend)." ); // ColumnFrms jetzt mit BodyFrm
291 11 : ::RestoreCntnt( pSave, (SwLayoutFrm*)((SwLayoutFrm*)Lower())->Lower(), 0, true );
292 : }
293 : }
294 :
295 : /*************************************************************************
296 : |*
297 : |* SwLayoutFrm::AdjustColumns()
298 : |*
299 : |*************************************************************************/
300 :
301 83 : void SwLayoutFrm::AdjustColumns( const SwFmtCol *pAttr, sal_Bool bAdjustAttributes )
302 : {
303 83 : if( !Lower()->GetNext() )
304 : {
305 12 : Lower()->ChgSize( Prt().SSize() );
306 27 : return;
307 : }
308 :
309 71 : const sal_Bool bVert = IsVertical();
310 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
311 71 : SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
312 :
313 : //If we have a pointer or we have to configure an attribute, we set the
314 : //column widths in any case. Otherwise we check if a configuration is needed.
315 71 : if ( !pAttr )
316 : {
317 3 : pAttr = &GetFmt()->GetCol();
318 3 : if ( !bAdjustAttributes )
319 : {
320 3 : long nAvail = (Prt().*fnRect->fnGetWidth)();
321 11 : for ( SwLayoutFrm *pCol = (SwLayoutFrm*)Lower();
322 : pCol;
323 8 : pCol = (SwLayoutFrm*)pCol->GetNext() )
324 8 : nAvail -= (pCol->Frm().*fnRect->fnGetWidth)();
325 3 : if ( !nAvail )
326 3 : return;
327 : }
328 : }
329 :
330 : //The columns can now be easily adjusted.
331 : //The widths get counted so we can give the reminder to the last one.
332 68 : SwTwips nAvail = (Prt().*fnRect->fnGetWidth)();
333 68 : const sal_Bool bLine = pAttr->GetLineAdj() != COLADJ_NONE;
334 68 : const sal_uInt16 nMin = bLine ? sal_uInt16( 20 + ( pAttr->GetLineWidth() / 2) ) : 0;
335 :
336 68 : const sal_Bool bR2L = IsRightToLeft();
337 68 : SwFrm *pCol = bR2L ? GetLastLower() : Lower();
338 :
339 : // #i27399#
340 : // bOrtho means we have to adjust the column frames manually. Otherwise
341 : // we may use the values returned by CalcColWidth:
342 68 : const sal_Bool bOrtho = pAttr->IsOrtho() && pAttr->GetNumCols() > 0;
343 68 : long nGutter = 0;
344 :
345 270 : for ( sal_uInt16 i = 0; i < pAttr->GetNumCols() && pCol; ++i ) //i118878, value returned by GetNumCols() can't be trusted
346 : {
347 202 : if( !bOrtho )
348 : {
349 4 : const SwTwips nWidth = i == (pAttr->GetNumCols() - 1) ?
350 : nAvail :
351 4 : pAttr->CalcColWidth( i, sal_uInt16( (Prt().*fnRect->fnGetWidth)() ) );
352 :
353 : const Size aColSz = bVert ?
354 0 : Size( Prt().Width(), nWidth ) :
355 4 : Size( nWidth, Prt().Height() );
356 :
357 4 : pCol->ChgSize( aColSz );
358 :
359 : // With this, the ColumnBodyFrms from page columns gets adjusted and
360 : // their bFixHeight flag is set so they won't shrink/grow.
361 : // Don't use the flag with frame columns because BodyFrms in frame
362 : // columns can grow/shrink.
363 4 : if( IsBodyFrm() )
364 4 : ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz );
365 :
366 4 : nAvail -= nWidth;
367 : }
368 :
369 202 : if ( bOrtho || bAdjustAttributes )
370 : {
371 202 : const SwColumn *pC = &pAttr->GetColumns()[i];
372 202 : const SwAttrSet* pSet = pCol->GetAttrSet();
373 202 : SvxLRSpaceItem aLR( pSet->GetLRSpace() );
374 :
375 : //In order to have enough space for the separation lines, we have to
376 : //take them into account here. Every time two columns meet we
377 : //calculate a clearance of 20 + half the pen width on the left or
378 : //right side, respectively.
379 202 : const sal_uInt16 nLeft = pC->GetLeft();
380 202 : const sal_uInt16 nRight = pC->GetRight();
381 :
382 202 : aLR.SetLeft ( nLeft );
383 202 : aLR.SetRight( nRight );
384 :
385 202 : if ( bLine )
386 : {
387 0 : if ( i == 0 )
388 : {
389 0 : aLR.SetRight( std::max( nRight, nMin ) );
390 : }
391 0 : else if ( i == pAttr->GetNumCols() - 1 )
392 : {
393 0 : aLR.SetLeft ( std::max( nLeft, nMin ) );
394 : }
395 : else
396 : {
397 0 : aLR.SetLeft ( std::max( nLeft, nMin ) );
398 0 : aLR.SetRight( std::max( nRight, nMin ) );
399 : }
400 : }
401 :
402 202 : if ( bAdjustAttributes )
403 : {
404 16 : SvxULSpaceItem aUL( pSet->GetULSpace() );
405 16 : aUL.SetUpper( pC->GetUpper());
406 16 : aUL.SetLower( pC->GetLower());
407 :
408 16 : ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aLR );
409 16 : ((SwLayoutFrm*)pCol)->GetFmt()->SetFmtAttr( aUL );
410 : }
411 :
412 202 : nGutter += aLR.GetLeft() + aLR.GetRight();
413 : }
414 :
415 202 : pCol = bR2L ? pCol->GetPrev() : pCol->GetNext();
416 : }
417 :
418 68 : if( bOrtho )
419 : {
420 66 : long nInnerWidth = ( nAvail - nGutter ) / pAttr->GetNumCols();
421 66 : pCol = Lower();
422 264 : for( sal_uInt16 i = 0; i < pAttr->GetNumCols() && pCol; pCol = pCol->GetNext(), ++i ) //i118878, value returned by GetNumCols() can't be trusted
423 : {
424 : SwTwips nWidth;
425 198 : if ( i == pAttr->GetNumCols() - 1 )
426 66 : nWidth = nAvail;
427 : else
428 : {
429 132 : SvxLRSpaceItem aLR( pCol->GetAttrSet()->GetLRSpace() );
430 132 : nWidth = nInnerWidth + aLR.GetLeft() + aLR.GetRight();
431 : }
432 198 : if( nWidth < 0 )
433 0 : nWidth = 0;
434 :
435 : const Size aColSz = bVert ?
436 0 : Size( Prt().Width(), nWidth ) :
437 198 : Size( nWidth, Prt().Height() );
438 :
439 198 : pCol->ChgSize( aColSz );
440 :
441 198 : if( IsBodyFrm() )
442 0 : ((SwLayoutFrm*)pCol)->Lower()->ChgSize( aColSz );
443 :
444 198 : nAvail -= nWidth;
445 : }
446 : }
447 99 : }
448 :
449 :
450 :
451 :
452 :
453 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|