merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / doc / gctable.cxx
blob4e69adef3a5c420dbf5a04826a3f6ca3994aca49
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gctable.cxx,v $
10 * $Revision: 1.9 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
36 #include <svx/boxitem.hxx>
37 #include <tblrwcl.hxx>
38 #include <swtblfmt.hxx>
41 inline const SvxBorderLine* GetLineTB( const SvxBoxItem* pBox, BOOL bTop )
43 return bTop ? pBox->GetTop() : pBox->GetBottom();
47 BOOL _SwGCBorder_BoxBrd::CheckLeftBorderOfFormat( const SwFrmFmt& rFmt )
49 const SvxBorderLine* pBrd;
50 const SfxPoolItem* pItem;
51 if( SFX_ITEM_SET == rFmt.GetItemState( RES_BOX, TRUE, &pItem ) &&
52 0 != ( pBrd = ((SvxBoxItem*)pItem)->GetLeft() ) )
54 if( *pBrdLn == *pBrd )
55 bAnyBorderFnd = TRUE;
56 return TRUE;
58 return FALSE;
63 BOOL lcl_GCBorder_ChkBoxBrd_L( const SwTableLine*& rpLine, void* pPara )
65 const SwTableBox* pBox = rpLine->GetTabBoxes()[ 0 ];
66 return lcl_GCBorder_ChkBoxBrd_B( pBox, pPara );
69 BOOL lcl_GCBorder_ChkBoxBrd_B( const SwTableBox*& rpBox, void* pPara )
71 BOOL bRet = TRUE;
72 if( rpBox->GetTabLines().Count() )
74 for( USHORT n = 0, nLines = rpBox->GetTabLines().Count();
75 n < nLines && bRet; ++n )
77 const SwTableLine* pLine = rpBox->GetTabLines()[ n ];
78 bRet = lcl_GCBorder_ChkBoxBrd_L( pLine, pPara );
81 else
83 _SwGCBorder_BoxBrd* pBPara = (_SwGCBorder_BoxBrd*)pPara;
84 bRet = pBPara->CheckLeftBorderOfFormat( *rpBox->GetFrmFmt() );
86 return bRet;
89 BOOL lcl_GCBorder_GetLastBox_L( const SwTableLine*& rpLine, void* pPara )
91 const SwTableBoxes& rBoxes = rpLine->GetTabBoxes();
92 const SwTableBox* pBox = rBoxes[ rBoxes.Count()-1 ];
93 ::lcl_GCBorder_GetLastBox_B( pBox, pPara );
94 return TRUE;
97 BOOL lcl_GCBorder_GetLastBox_B( const SwTableBox*& rpBox, void* pPara )
99 SwTableLines& rLines = (SwTableLines&)rpBox->GetTabLines();
100 if( rLines.Count() )
101 rLines.ForEach( &lcl_GCBorder_GetLastBox_L, pPara );
102 else
103 ((SwTableBoxes*)pPara)->Insert( rpBox, ((SwTableBoxes*)pPara)->Count() );
104 return TRUE;
107 // suche das "Ende" der vorgegebene BorderLine. Returnt wird die "Layout"Pos!
108 USHORT lcl_FindEndPosOfBorder( const SwCollectTblLineBoxes& rCollTLB,
109 const SvxBorderLine& rBrdLn, USHORT& rStt, BOOL bTop )
111 USHORT nPos, nLastPos = 0;
112 for( USHORT nEnd = rCollTLB.Count(); rStt < nEnd; ++rStt )
114 const SfxPoolItem* pItem;
115 const SvxBorderLine* pBrd;
116 const SwTableBox& rBox = rCollTLB.GetBox( rStt, &nPos );
118 if( SFX_ITEM_SET != rBox.GetFrmFmt()->GetItemState(RES_BOX,TRUE, &pItem )
119 || 0 == ( pBrd = GetLineTB( (SvxBoxItem*)pItem, bTop ))
120 || !( *pBrd == rBrdLn ))
121 break;
122 nLastPos = nPos;
124 return nLastPos;
127 inline const SvxBorderLine* lcl_GCBorder_GetBorder( const SwTableBox& rBox,
128 BOOL bTop,
129 const SfxPoolItem** ppItem )
131 return SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOX, TRUE, ppItem )
132 ? GetLineTB( (SvxBoxItem*)*ppItem, bTop )
133 : 0;
136 void lcl_GCBorder_DelBorder( const SwCollectTblLineBoxes& rCollTLB,
137 USHORT& rStt, BOOL bTop,
138 const SvxBorderLine& rLine,
139 const SfxPoolItem* pItem,
140 USHORT nEndPos,
141 SwShareBoxFmts* pShareFmts )
143 SwTableBox* pBox = (SwTableBox*)&rCollTLB.GetBox( rStt );
144 USHORT nNextPos;
145 const SvxBorderLine* pLn = &rLine;
147 do {
148 if( pLn && *pLn == rLine )
150 SvxBoxItem aBox( *(SvxBoxItem*)pItem );
151 if( bTop )
152 aBox.SetLine( 0, BOX_LINE_TOP );
153 else
154 aBox.SetLine( 0, BOX_LINE_BOTTOM );
156 if( pShareFmts )
157 pShareFmts->SetAttr( *pBox, aBox );
158 else
159 pBox->ClaimFrmFmt()->SetFmtAttr( aBox );
162 if( ++rStt >= rCollTLB.Count() )
163 break;
165 pBox = (SwTableBox*)&rCollTLB.GetBox( rStt, &nNextPos );
166 if( nNextPos > nEndPos )
167 break;
169 pLn = lcl_GCBorder_GetBorder( *pBox, bTop, &pItem );
171 } while( TRUE );
175 BOOL lcl_GC_Line_Border( const SwTableLine*& rpLine, void* pPara )
177 _SwGCLineBorder* pGCPara = (_SwGCLineBorder*)pPara;
179 // zuerst die rechte Kante mit der linken Kante der naechsten Box
180 // innerhalb dieser Line
182 _SwGCBorder_BoxBrd aBPara;
183 const SvxBorderLine* pBrd;
184 const SfxPoolItem* pItem;
185 const SwTableBoxes& rBoxes = rpLine->GetTabBoxes();
186 for( USHORT n = 0, nBoxes = rBoxes.Count() - 1; n < nBoxes; ++n )
188 SwTableBoxes aBoxes;
190 const SwTableBox* pBox = rBoxes[ n ];
191 if( pBox->GetSttNd() )
192 aBoxes.Insert( pBox, 0 );
193 else
194 lcl_GCBorder_GetLastBox_B( pBox, &aBoxes );
197 SwTableBox* pBox;
198 for( USHORT i = aBoxes.Count(); i; )
199 if( SFX_ITEM_SET == (pBox = aBoxes[ --i ])->GetFrmFmt()->
200 GetItemState( RES_BOX, TRUE, &pItem ) &&
201 0 != ( pBrd = ((SvxBoxItem*)pItem)->GetRight() ) )
203 aBPara.SetBorder( *pBrd );
204 const SwTableBox* pNextBox = rBoxes[n+1];
205 if( lcl_GCBorder_ChkBoxBrd_B( pNextBox, &aBPara ) &&
206 aBPara.IsAnyBorderFound() )
208 SvxBoxItem aBox( *(SvxBoxItem*)pItem );
209 aBox.SetLine( 0, BOX_LINE_RIGHT );
210 if( pGCPara->pShareFmts )
211 pGCPara->pShareFmts->SetAttr( *pBox, aBox );
212 else
213 pBox->ClaimFrmFmt()->SetFmtAttr( aBox );
217 aBoxes.Remove( 0, aBoxes.Count() );
221 // und jetzt die eigene untere Kante mit der nachfolgenden oberen Kante
222 if( !pGCPara->IsLastLine() )
224 SwCollectTblLineBoxes aBottom( FALSE );
225 SwCollectTblLineBoxes aTop( TRUE );
227 ::lcl_Line_CollectBox( rpLine, &aBottom );
229 const SwTableLine* pNextLine = (*pGCPara->pLines)[ pGCPara->nLinePos+1 ];
230 ::lcl_Line_CollectBox( pNextLine, &aTop );
232 // dann entferne mal alle "doppelten" gleichen Lines
233 USHORT nBtmPos, nTopPos,
234 nSttBtm = 0, nSttTop = 0,
235 nEndBtm = aBottom.Count(), nEndTop = aTop.Count();
237 const SwTableBox *pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos ),
238 *pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
239 const SfxPoolItem *pBtmItem = 0, *pTopItem = 0;
240 const SvxBorderLine *pBtmLine(0), *pTopLine(0);
241 BOOL bGetTopItem = TRUE, bGetBtmItem = TRUE;
243 do {
244 if( bGetBtmItem )
245 pBtmLine = lcl_GCBorder_GetBorder( *pBtmBox, FALSE, &pBtmItem );
246 if( bGetTopItem )
247 pTopLine = lcl_GCBorder_GetBorder( *pTopBox, TRUE, &pTopItem );
249 if( pTopLine && pBtmLine && *pTopLine == *pBtmLine )
251 // dann kann einer entfernt werden, aber welche?
252 USHORT nSavSttBtm = nSttBtm, nSavSttTop = nSttTop;
253 USHORT nBtmEndPos = ::lcl_FindEndPosOfBorder( aBottom,
254 *pTopLine, nSttBtm, FALSE );
255 if( !nBtmEndPos ) nBtmEndPos = nBtmPos;
256 USHORT nTopEndPos = ::lcl_FindEndPosOfBorder( aTop,
257 *pTopLine, nSttTop, TRUE );
258 if( !nTopEndPos ) nTopEndPos = nTopPos;
261 if( nTopEndPos <= nBtmEndPos )
263 // dann die TopBorder bis zur BottomEndPos loeschen
264 nSttTop = nSavSttTop;
265 if( nTopPos <= nBtmEndPos )
266 lcl_GCBorder_DelBorder( aTop, --nSttTop, TRUE,
267 *pBtmLine, pTopItem, nBtmEndPos,
268 pGCPara->pShareFmts );
269 else
270 nSttBtm = nSavSttBtm;
272 else
274 // sonst die BottomBorder bis zur TopEndPos loeschen
275 nSttBtm = nSavSttBtm;
276 if( nBtmPos <= nTopEndPos )
277 lcl_GCBorder_DelBorder( aBottom, --nSttBtm, FALSE,
278 *pTopLine, pBtmItem, nTopEndPos,
279 pGCPara->pShareFmts );
280 else
281 nSttTop = nSavSttTop;
283 nTopPos = nBtmPos;
286 if( nTopPos == nBtmPos )
288 if( nSttBtm >= nEndBtm || nSttTop >= nEndTop )
289 break;
291 pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
292 pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
293 bGetTopItem = bGetBtmItem = TRUE;
295 else if( nTopPos < nBtmPos )
297 if( nSttTop >= nEndTop )
298 break;
299 pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
300 bGetTopItem = TRUE;
301 bGetBtmItem = FALSE;
303 else
305 if( nSttBtm >= nEndBtm )
306 break;
307 pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
308 bGetTopItem = FALSE;
309 bGetBtmItem = TRUE;
312 } while( TRUE );
315 ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_GC_Box_Border, pPara );
317 ++pGCPara->nLinePos;
319 return TRUE;
322 BOOL lcl_GC_Box_Border( const SwTableBox*& rpBox, void* pPara )
324 if( rpBox->GetTabLines().Count() )
326 _SwGCLineBorder aPara( *rpBox );
327 aPara.pShareFmts = ((_SwGCLineBorder*)pPara)->pShareFmts;
328 ((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_GC_Line_Border, &aPara );
330 return TRUE;
333 struct _GCLinePara
335 SwTableLines* pLns;
336 SwShareBoxFmts* pShareFmts;
338 _GCLinePara( SwTableLines& rLns, _GCLinePara* pPara = 0 )
339 : pLns( &rLns ), pShareFmts( pPara ? pPara->pShareFmts : 0 )
343 BOOL lcl_MergeGCBox( const SwTableBox*& rpTblBox, void* pPara )
345 SwTableBox*& rpBox = (SwTableBox*&)rpTblBox;
346 USHORT n, nLen = rpBox->GetTabLines().Count();
347 if( nLen )
349 // ACHTUNG: die Anzahl der Lines kann sich aendern!
350 _GCLinePara aPara( rpBox->GetTabLines(), (_GCLinePara*)pPara );
351 for( n = 0; n < rpBox->GetTabLines().Count() &&
352 lcl_MergeGCLine( *(rpBox->GetTabLines().GetData() + n), &aPara );
353 ++n )
356 if( 1 == rpBox->GetTabLines().Count() )
358 // Box mit einer Line, dann verschiebe alle Boxen der Line
359 // hinter diese Box in der Parent-Line und loesche diese Box
360 SwTableLine* pInsLine = rpBox->GetUpper();
361 SwTableLine* pCpyLine = rpBox->GetTabLines()[0];
362 USHORT nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, rpBox );
363 for( n = 0; n < pCpyLine->GetTabBoxes().Count(); ++n )
364 pCpyLine->GetTabBoxes()[n]->SetUpper( pInsLine );
366 pInsLine->GetTabBoxes().Insert( &pCpyLine->GetTabBoxes(), nInsPos+1 );
367 pCpyLine->GetTabBoxes().Remove( 0, n );
368 // loesche alte die Box mit der Line
369 pInsLine->GetTabBoxes().DeleteAndDestroy( nInsPos );
371 return FALSE; // neu aufsetzen
374 return TRUE;
377 BOOL lcl_MergeGCLine( const SwTableLine*& rpLine, void* pPara )
379 SwTableLine* pLn = (SwTableLine*)rpLine;
380 USHORT nLen = pLn->GetTabBoxes().Count();
381 if( nLen )
383 _GCLinePara* pGCPara = (_GCLinePara*)pPara;
384 while( 1 == nLen )
386 // es gibt eine Box mit Lines
387 SwTableBox* pBox = pLn->GetTabBoxes()[0];
388 if( !pBox->GetTabLines().Count() )
389 break;
391 SwTableLine* pLine = pBox->GetTabLines()[0];
393 // pLine wird zu der aktuellen, also der rpLine,
394 // die restlichen werden ins LinesArray hinter der akt.
395 // verschoben.
396 // Das LinesArray ist im pPara!
397 nLen = pBox->GetTabLines().Count();
399 SwTableLines& rLns = *pGCPara->pLns;
400 const SwTableLine* pTmp = pLn;
401 USHORT nInsPos = rLns.GetPos( pTmp );
402 ASSERT( USHRT_MAX != nInsPos, "Line nicht gefunden!" );
404 SwTableBox* pUpper = pLn->GetUpper();
406 rLns.Remove( nInsPos, 1 ); // die Line dem aus Array loeschen
407 rLns.Insert( &pBox->GetTabLines(), nInsPos );
409 // JP 31.03.99: Bug 60000 - die Attribute der zu loeschenden
410 // Line an die "eingefuegten" uebertragen
411 const SfxPoolItem* pItem;
412 if( SFX_ITEM_SET == pLn->GetFrmFmt()->GetItemState(
413 RES_BACKGROUND, TRUE, &pItem ))
415 SwTableLines& rBoxLns = pBox->GetTabLines();
416 for( USHORT nLns = 0; nLns < nLen; ++nLns )
417 if( SFX_ITEM_SET != rBoxLns[ nLns ]->GetFrmFmt()->
418 GetItemState( RES_BACKGROUND, TRUE ))
419 pGCPara->pShareFmts->SetAttr( *rBoxLns[ nLns ], *pItem );
422 pBox->GetTabLines().Remove( 0, nLen ); // Lines aus Array loeschen
424 delete pLn;
426 // Abhaengigkeit neu setzen
427 while( nLen-- )
428 rLns[ nInsPos++ ]->SetUpper( pUpper );
430 pLn = pLine; // und neu setzen
431 nLen = pLn->GetTabBoxes().Count();
434 // ACHTUNG: die Anzahl der Boxen kann sich aendern!
435 for( nLen = 0; nLen < pLn->GetTabBoxes().Count(); ++nLen )
436 if( !lcl_MergeGCBox( *(pLn->GetTabBoxes().GetData() + nLen ), pPara ))
437 --nLen;
439 return TRUE;
442 // Struktur ein wenig aufraeumen
443 void SwTable::GCLines()
445 // ACHTUNG: die Anzahl der Lines kann sich aendern!
446 _GCLinePara aPara( GetTabLines() );
447 SwShareBoxFmts aShareFmts;
448 aPara.pShareFmts = &aShareFmts;
449 for( USHORT n = 0; n < GetTabLines().Count() &&
450 lcl_MergeGCLine( *(GetTabLines().GetData() + n ), &aPara ); ++n )