1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gctable.cxx,v $
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
)
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
)
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
);
83 _SwGCBorder_BoxBrd
* pBPara
= (_SwGCBorder_BoxBrd
*)pPara
;
84 bRet
= pBPara
->CheckLeftBorderOfFormat( *rpBox
->GetFrmFmt() );
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
);
97 BOOL
lcl_GCBorder_GetLastBox_B( const SwTableBox
*& rpBox
, void* pPara
)
99 SwTableLines
& rLines
= (SwTableLines
&)rpBox
->GetTabLines();
101 rLines
.ForEach( &lcl_GCBorder_GetLastBox_L
, pPara
);
103 ((SwTableBoxes
*)pPara
)->Insert( rpBox
, ((SwTableBoxes
*)pPara
)->Count() );
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
))
127 inline const SvxBorderLine
* lcl_GCBorder_GetBorder( const SwTableBox
& rBox
,
129 const SfxPoolItem
** ppItem
)
131 return SFX_ITEM_SET
== rBox
.GetFrmFmt()->GetItemState( RES_BOX
, TRUE
, ppItem
)
132 ? GetLineTB( (SvxBoxItem
*)*ppItem
, bTop
)
136 void lcl_GCBorder_DelBorder( const SwCollectTblLineBoxes
& rCollTLB
,
137 USHORT
& rStt
, BOOL bTop
,
138 const SvxBorderLine
& rLine
,
139 const SfxPoolItem
* pItem
,
141 SwShareBoxFmts
* pShareFmts
)
143 SwTableBox
* pBox
= (SwTableBox
*)&rCollTLB
.GetBox( rStt
);
145 const SvxBorderLine
* pLn
= &rLine
;
148 if( pLn
&& *pLn
== rLine
)
150 SvxBoxItem
aBox( *(SvxBoxItem
*)pItem
);
152 aBox
.SetLine( 0, BOX_LINE_TOP
);
154 aBox
.SetLine( 0, BOX_LINE_BOTTOM
);
157 pShareFmts
->SetAttr( *pBox
, aBox
);
159 pBox
->ClaimFrmFmt()->SetFmtAttr( aBox
);
162 if( ++rStt
>= rCollTLB
.Count() )
165 pBox
= (SwTableBox
*)&rCollTLB
.GetBox( rStt
, &nNextPos
);
166 if( nNextPos
> nEndPos
)
169 pLn
= lcl_GCBorder_GetBorder( *pBox
, bTop
, &pItem
);
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
)
190 const SwTableBox
* pBox
= rBoxes
[ n
];
191 if( pBox
->GetSttNd() )
192 aBoxes
.Insert( pBox
, 0 );
194 lcl_GCBorder_GetLastBox_B( pBox
, &aBoxes
);
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
);
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
;
245 pBtmLine
= lcl_GCBorder_GetBorder( *pBtmBox
, FALSE
, &pBtmItem
);
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
);
270 nSttBtm
= nSavSttBtm
;
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
);
281 nSttTop
= nSavSttTop
;
286 if( nTopPos
== nBtmPos
)
288 if( nSttBtm
>= nEndBtm
|| nSttTop
>= nEndTop
)
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
)
299 pTopBox
= &aTop
.GetBox( nSttTop
++, &nTopPos
);
305 if( nSttBtm
>= nEndBtm
)
307 pBtmBox
= &aBottom
.GetBox( nSttBtm
++, &nBtmPos
);
315 ((SwTableLine
*)rpLine
)->GetTabBoxes().ForEach( &lcl_GC_Box_Border
, pPara
);
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
);
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();
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
);
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
377 BOOL
lcl_MergeGCLine( const SwTableLine
*& rpLine
, void* pPara
)
379 SwTableLine
* pLn
= (SwTableLine
*)rpLine
;
380 USHORT nLen
= pLn
->GetTabBoxes().Count();
383 _GCLinePara
* pGCPara
= (_GCLinePara
*)pPara
;
386 // es gibt eine Box mit Lines
387 SwTableBox
* pBox
= pLn
->GetTabBoxes()[0];
388 if( !pBox
->GetTabLines().Count() )
391 SwTableLine
* pLine
= pBox
->GetTabLines()[0];
393 // pLine wird zu der aktuellen, also der rpLine,
394 // die restlichen werden ins LinesArray hinter der akt.
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
426 // Abhaengigkeit neu setzen
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
))
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
)