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