xref: /trunk/main/sw/source/core/doc/gctable.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <hintids.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <tblrwcl.hxx>
35 #include <swtblfmt.hxx>
36 
37 
38 inline const SvxBorderLine* GetLineTB( const SvxBoxItem* pBox, sal_Bool bTop )
39 {
40     return bTop ? pBox->GetTop() : pBox->GetBottom();
41 }
42 
43 
44 sal_Bool _SwGCBorder_BoxBrd::CheckLeftBorderOfFormat( const SwFrmFmt& rFmt )
45 {
46     const SvxBorderLine* pBrd;
47     const SfxPoolItem* pItem;
48     if( SFX_ITEM_SET == rFmt.GetItemState( RES_BOX, sal_True, &pItem ) &&
49         0 != ( pBrd = ((SvxBoxItem*)pItem)->GetLeft() ) )
50     {
51         if( *pBrdLn == *pBrd )
52             bAnyBorderFnd = sal_True;
53         return sal_True;
54     }
55     return sal_False;
56 }
57 
58 
59 
60 sal_Bool lcl_GCBorder_ChkBoxBrd_L( const SwTableLine*& rpLine, void* pPara )
61 {
62     const SwTableBox* pBox = rpLine->GetTabBoxes()[ 0 ];
63     return lcl_GCBorder_ChkBoxBrd_B( pBox, pPara );
64 }
65 
66 sal_Bool lcl_GCBorder_ChkBoxBrd_B( const SwTableBox*& rpBox, void* pPara )
67 {
68     sal_Bool bRet = sal_True;
69     if( rpBox->GetTabLines().Count() )
70     {
71         for( sal_uInt16 n = 0, nLines = rpBox->GetTabLines().Count();
72                 n < nLines && bRet; ++n )
73         {
74             const SwTableLine* pLine = rpBox->GetTabLines()[ n ];
75             bRet = lcl_GCBorder_ChkBoxBrd_L( pLine, pPara );
76         }
77     }
78     else
79     {
80         _SwGCBorder_BoxBrd* pBPara = (_SwGCBorder_BoxBrd*)pPara;
81         bRet = pBPara->CheckLeftBorderOfFormat( *rpBox->GetFrmFmt() );
82     }
83     return bRet;
84 }
85 
86 sal_Bool lcl_GCBorder_GetLastBox_L( const SwTableLine*& rpLine, void* pPara )
87 {
88     const SwTableBoxes& rBoxes = rpLine->GetTabBoxes();
89     const SwTableBox* pBox = rBoxes[ rBoxes.Count()-1 ];
90     ::lcl_GCBorder_GetLastBox_B( pBox, pPara );
91     return sal_True;
92 }
93 
94 sal_Bool lcl_GCBorder_GetLastBox_B( const SwTableBox*& rpBox, void* pPara )
95 {
96     SwTableLines& rLines = (SwTableLines&)rpBox->GetTabLines();
97     if( rLines.Count() )
98         rLines.ForEach( &lcl_GCBorder_GetLastBox_L, pPara );
99     else
100         ((SwTableBoxes*)pPara)->Insert( rpBox, ((SwTableBoxes*)pPara)->Count() );
101     return sal_True;
102 }
103 
104 // suche das "Ende" der vorgegebene BorderLine. Returnt wird die "Layout"Pos!
105 sal_uInt16 lcl_FindEndPosOfBorder( const SwCollectTblLineBoxes& rCollTLB,
106                         const SvxBorderLine& rBrdLn, sal_uInt16& rStt, sal_Bool bTop )
107 {
108     sal_uInt16 nPos, nLastPos = 0;
109     for( sal_uInt16 nEnd = rCollTLB.Count(); rStt < nEnd; ++rStt )
110     {
111         const SfxPoolItem* pItem;
112         const SvxBorderLine* pBrd;
113         const SwTableBox& rBox = rCollTLB.GetBox( rStt, &nPos );
114 
115         if( SFX_ITEM_SET != rBox.GetFrmFmt()->GetItemState(RES_BOX,sal_True, &pItem )
116             || 0 == ( pBrd = GetLineTB( (SvxBoxItem*)pItem, bTop ))
117             || !( *pBrd == rBrdLn ))
118             break;
119         nLastPos = nPos;
120     }
121     return nLastPos;
122 }
123 
124 inline const SvxBorderLine* lcl_GCBorder_GetBorder( const SwTableBox& rBox,
125                                                 sal_Bool bTop,
126                                                 const SfxPoolItem** ppItem )
127 {
128     return SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOX, sal_True, ppItem )
129             ? GetLineTB( (SvxBoxItem*)*ppItem, bTop )
130             : 0;
131 }
132 
133 void lcl_GCBorder_DelBorder( const SwCollectTblLineBoxes& rCollTLB,
134                                 sal_uInt16& rStt, sal_Bool bTop,
135                                 const SvxBorderLine& rLine,
136                                 const SfxPoolItem* pItem,
137                                 sal_uInt16 nEndPos,
138                                 SwShareBoxFmts* pShareFmts )
139 {
140     SwTableBox* pBox = (SwTableBox*)&rCollTLB.GetBox( rStt );
141     sal_uInt16 nNextPos;
142     const SvxBorderLine* pLn = &rLine;
143 
144     do {
145         if( pLn && *pLn == rLine )
146         {
147             SvxBoxItem aBox( *(SvxBoxItem*)pItem );
148             if( bTop )
149                 aBox.SetLine( 0, BOX_LINE_TOP );
150             else
151                 aBox.SetLine( 0, BOX_LINE_BOTTOM );
152 
153             if( pShareFmts )
154                 pShareFmts->SetAttr( *pBox, aBox );
155             else
156                 pBox->ClaimFrmFmt()->SetFmtAttr( aBox );
157         }
158 
159         if( ++rStt >= rCollTLB.Count() )
160             break;
161 
162         pBox = (SwTableBox*)&rCollTLB.GetBox( rStt, &nNextPos );
163         if( nNextPos > nEndPos )
164             break;
165 
166         pLn = lcl_GCBorder_GetBorder( *pBox, bTop, &pItem );
167 
168     } while( sal_True );
169 }
170 
171 
172 sal_Bool lcl_GC_Line_Border( const SwTableLine*& rpLine, void* pPara )
173 {
174     _SwGCLineBorder* pGCPara = (_SwGCLineBorder*)pPara;
175 
176     // zuerst die rechte Kante mit der linken Kante der naechsten Box
177     // innerhalb dieser Line
178     {
179         _SwGCBorder_BoxBrd aBPara;
180         const SvxBorderLine* pBrd;
181         const SfxPoolItem* pItem;
182         const SwTableBoxes& rBoxes = rpLine->GetTabBoxes();
183         for( sal_uInt16 n = 0, nBoxes = rBoxes.Count() - 1; n < nBoxes; ++n )
184         {
185             SwTableBoxes aBoxes;
186             {
187                 const SwTableBox* pBox = rBoxes[ n ];
188                 if( pBox->GetSttNd() )
189                     aBoxes.Insert( pBox, 0 );
190                 else
191                     lcl_GCBorder_GetLastBox_B( pBox, &aBoxes );
192             }
193 
194             SwTableBox* pBox;
195             for( sal_uInt16 i = aBoxes.Count(); i; )
196                 if( SFX_ITEM_SET == (pBox = aBoxes[ --i ])->GetFrmFmt()->
197                     GetItemState( RES_BOX, sal_True, &pItem ) &&
198                     0 != ( pBrd = ((SvxBoxItem*)pItem)->GetRight() ) )
199                 {
200                     aBPara.SetBorder( *pBrd );
201                     const SwTableBox* pNextBox = rBoxes[n+1];
202                     if( lcl_GCBorder_ChkBoxBrd_B( pNextBox, &aBPara ) &&
203                         aBPara.IsAnyBorderFound() )
204                     {
205                         SvxBoxItem aBox( *(SvxBoxItem*)pItem );
206                         aBox.SetLine( 0, BOX_LINE_RIGHT );
207                         if( pGCPara->pShareFmts )
208                             pGCPara->pShareFmts->SetAttr( *pBox, aBox );
209                         else
210                             pBox->ClaimFrmFmt()->SetFmtAttr( aBox );
211                     }
212                 }
213 
214             aBoxes.Remove( 0, aBoxes.Count() );
215         }
216     }
217 
218     // und jetzt die eigene untere Kante mit der nachfolgenden oberen Kante
219     if( !pGCPara->IsLastLine() )
220     {
221         SwCollectTblLineBoxes aBottom( sal_False );
222         SwCollectTblLineBoxes aTop( sal_True );
223 
224         ::lcl_Line_CollectBox( rpLine, &aBottom );
225 
226         const SwTableLine* pNextLine = (*pGCPara->pLines)[ pGCPara->nLinePos+1 ];
227         ::lcl_Line_CollectBox( pNextLine, &aTop );
228 
229         // dann entferne mal alle "doppelten" gleichen Lines
230         sal_uInt16 nBtmPos, nTopPos,
231                 nSttBtm = 0, nSttTop = 0,
232                 nEndBtm = aBottom.Count(), nEndTop = aTop.Count();
233 
234         const SwTableBox *pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos ),
235                          *pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
236         const SfxPoolItem *pBtmItem = 0, *pTopItem = 0;
237         const SvxBorderLine *pBtmLine(0), *pTopLine(0);
238         sal_Bool bGetTopItem = sal_True, bGetBtmItem = sal_True;
239 
240         do {
241             if( bGetBtmItem )
242                 pBtmLine = lcl_GCBorder_GetBorder( *pBtmBox, sal_False, &pBtmItem );
243             if( bGetTopItem )
244                 pTopLine = lcl_GCBorder_GetBorder( *pTopBox, sal_True, &pTopItem );
245 
246             if( pTopLine && pBtmLine && *pTopLine == *pBtmLine )
247             {
248                 // dann kann einer entfernt werden, aber welche?
249                 sal_uInt16 nSavSttBtm = nSttBtm, nSavSttTop = nSttTop;
250                 sal_uInt16 nBtmEndPos = ::lcl_FindEndPosOfBorder( aBottom,
251                                                 *pTopLine, nSttBtm, sal_False );
252                 if( !nBtmEndPos ) nBtmEndPos = nBtmPos;
253                 sal_uInt16 nTopEndPos = ::lcl_FindEndPosOfBorder( aTop,
254                                                 *pTopLine, nSttTop, sal_True );
255                 if( !nTopEndPos ) nTopEndPos = nTopPos;
256 
257 
258                 if( nTopEndPos <= nBtmEndPos )
259                 {
260                     // dann die TopBorder bis zur BottomEndPos loeschen
261                     nSttTop = nSavSttTop;
262                     if( nTopPos <= nBtmEndPos )
263                         lcl_GCBorder_DelBorder( aTop, --nSttTop, sal_True,
264                                             *pBtmLine, pTopItem, nBtmEndPos,
265                                             pGCPara->pShareFmts );
266                     else
267                         nSttBtm = nSavSttBtm;
268                 }
269                 else
270                 {
271                     // sonst die BottomBorder bis zur TopEndPos loeschen
272                     nSttBtm = nSavSttBtm;
273                     if( nBtmPos <= nTopEndPos )
274                         lcl_GCBorder_DelBorder( aBottom, --nSttBtm, sal_False,
275                                             *pTopLine, pBtmItem, nTopEndPos,
276                                             pGCPara->pShareFmts );
277                     else
278                         nSttTop = nSavSttTop;
279                 }
280                 nTopPos = nBtmPos;
281             }
282 
283             if( nTopPos == nBtmPos )
284             {
285                 if( nSttBtm >= nEndBtm || nSttTop >= nEndTop )
286                     break;
287 
288                 pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
289                 pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
290                 bGetTopItem = bGetBtmItem = sal_True;
291             }
292             else if( nTopPos < nBtmPos )
293             {
294                 if( nSttTop >= nEndTop )
295                     break;
296                 pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
297                 bGetTopItem = sal_True;
298                 bGetBtmItem = sal_False;
299             }
300             else
301             {
302                 if( nSttBtm >= nEndBtm )
303                     break;
304                 pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
305                 bGetTopItem = sal_False;
306                 bGetBtmItem = sal_True;
307             }
308 
309         } while( sal_True );
310     }
311 
312     ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_GC_Box_Border, pPara );
313 
314     ++pGCPara->nLinePos;
315 
316     return sal_True;
317 }
318 
319 sal_Bool lcl_GC_Box_Border( const SwTableBox*& rpBox, void* pPara )
320 {
321     if( rpBox->GetTabLines().Count() )
322     {
323         _SwGCLineBorder aPara( *rpBox );
324         aPara.pShareFmts = ((_SwGCLineBorder*)pPara)->pShareFmts;
325         ((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_GC_Line_Border, &aPara );
326     }
327     return sal_True;
328 }
329 
330 struct _GCLinePara
331 {
332     SwTableLines* pLns;
333     SwShareBoxFmts* pShareFmts;
334 
335     _GCLinePara( SwTableLines& rLns, _GCLinePara* pPara = 0 )
336         : pLns( &rLns ), pShareFmts( pPara ? pPara->pShareFmts : 0 )
337     {}
338 };
339 
340 sal_Bool lcl_MergeGCBox( const SwTableBox*& rpTblBox, void* pPara )
341 {
342     SwTableBox*& rpBox = (SwTableBox*&)rpTblBox;
343     sal_uInt16 n, nLen = rpBox->GetTabLines().Count();
344     if( nLen )
345     {
346         // ACHTUNG: die Anzahl der Lines kann sich aendern!
347         _GCLinePara aPara( rpBox->GetTabLines(), (_GCLinePara*)pPara );
348         for( n = 0; n < rpBox->GetTabLines().Count() &&
349             lcl_MergeGCLine( *(rpBox->GetTabLines().GetData() + n), &aPara );
350             ++n )
351             ;
352 
353         if( 1 == rpBox->GetTabLines().Count() )
354         {
355             // Box mit einer Line, dann verschiebe alle Boxen der Line
356             // hinter diese Box in der Parent-Line und loesche diese Box
357             SwTableLine* pInsLine = rpBox->GetUpper();
358             SwTableLine* pCpyLine = rpBox->GetTabLines()[0];
359             sal_uInt16 nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, rpBox );
360             for( n = 0; n < pCpyLine->GetTabBoxes().Count(); ++n )
361                 pCpyLine->GetTabBoxes()[n]->SetUpper( pInsLine );
362 
363             pInsLine->GetTabBoxes().Insert( &pCpyLine->GetTabBoxes(), nInsPos+1 );
364             pCpyLine->GetTabBoxes().Remove( 0, n );
365             // loesche alte die Box mit der Line
366             pInsLine->GetTabBoxes().DeleteAndDestroy( nInsPos );
367 
368             return sal_False;       // neu aufsetzen
369         }
370     }
371     return sal_True;
372 }
373 
374 sal_Bool lcl_MergeGCLine( const SwTableLine*& rpLine, void* pPara )
375 {
376     SwTableLine* pLn = (SwTableLine*)rpLine;
377     sal_uInt16 nLen = pLn->GetTabBoxes().Count();
378     if( nLen )
379     {
380         _GCLinePara* pGCPara = (_GCLinePara*)pPara;
381         while( 1 == nLen )
382         {
383             // es gibt eine Box mit Lines
384             SwTableBox* pBox = pLn->GetTabBoxes()[0];
385             if( !pBox->GetTabLines().Count() )
386                 break;
387 
388             SwTableLine* pLine = pBox->GetTabLines()[0];
389 
390             // pLine wird zu der aktuellen, also der rpLine,
391             // die restlichen werden ins LinesArray hinter der akt.
392             // verschoben.
393             // Das LinesArray ist im pPara!
394             nLen = pBox->GetTabLines().Count();
395 
396             SwTableLines& rLns = *pGCPara->pLns;
397             const SwTableLine* pTmp = pLn;
398             sal_uInt16 nInsPos = rLns.GetPos( pTmp );
399             ASSERT( USHRT_MAX != nInsPos, "Line nicht gefunden!" );
400 
401             SwTableBox* pUpper = pLn->GetUpper();
402 
403             rLns.Remove( nInsPos, 1 );      // die Line dem aus Array loeschen
404             rLns.Insert( &pBox->GetTabLines(), nInsPos );
405 
406             // JP 31.03.99: Bug 60000 - die Attribute der zu loeschenden
407             // Line an die "eingefuegten" uebertragen
408             const SfxPoolItem* pItem;
409             if( SFX_ITEM_SET == pLn->GetFrmFmt()->GetItemState(
410                                     RES_BACKGROUND, sal_True, &pItem ))
411             {
412                 SwTableLines& rBoxLns = pBox->GetTabLines();
413                 for( sal_uInt16 nLns = 0; nLns < nLen; ++nLns )
414                     if( SFX_ITEM_SET != rBoxLns[ nLns ]->GetFrmFmt()->
415                             GetItemState( RES_BACKGROUND, sal_True ))
416                         pGCPara->pShareFmts->SetAttr( *rBoxLns[ nLns ], *pItem );
417             }
418 
419             pBox->GetTabLines().Remove( 0, nLen );  // Lines aus Array loeschen
420 
421             delete pLn;
422 
423             // Abhaengigkeit neu setzen
424             while( nLen-- )
425                 rLns[ nInsPos++ ]->SetUpper( pUpper );
426 
427             pLn = pLine;                        // und neu setzen
428             nLen = pLn->GetTabBoxes().Count();
429         }
430 
431         // ACHTUNG: die Anzahl der Boxen kann sich aendern!
432         for( nLen = 0; nLen < pLn->GetTabBoxes().Count(); ++nLen )
433             if( !lcl_MergeGCBox( *(pLn->GetTabBoxes().GetData() + nLen ), pPara ))
434                 --nLen;
435     }
436     return sal_True;
437 }
438 
439         // Struktur ein wenig aufraeumen
440 void SwTable::GCLines()
441 {
442     // ACHTUNG: die Anzahl der Lines kann sich aendern!
443     _GCLinePara aPara( GetTabLines() );
444     SwShareBoxFmts aShareFmts;
445     aPara.pShareFmts = &aShareFmts;
446     for( sal_uInt16 n = 0; n < GetTabLines().Count() &&
447             lcl_MergeGCLine( *(GetTabLines().GetData() + n ), &aPara ); ++n )
448         ;
449 }
450 
451 
452