xref: /trunk/main/sw/source/core/docnode/ndtbl1.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 #include "hintids.hxx"
32 #include <editeng/lrspitem.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <editeng/brshitem.hxx>
35 #include <editeng/frmdiritem.hxx>
36 #include <fmtornt.hxx>
37 #include <fmtfsize.hxx>
38 #include <fmtlsplt.hxx>
39 #include <fmtrowsplt.hxx>
40 #include <tabcol.hxx>
41 #include <frmatr.hxx>
42 #include <cellfrm.hxx>
43 #include <tabfrm.hxx>
44 #include <cntfrm.hxx>
45 #include <txtfrm.hxx>
46 #include <svx/svxids.hrc>
47 #include <doc.hxx>
48 #include <IDocumentUndoRedo.hxx>
49 #include "pam.hxx"
50 #include "swcrsr.hxx"
51 #include "viscrs.hxx"
52 #include "swtable.hxx"
53 #include "htmltbl.hxx"
54 #include "tblsel.hxx"
55 #include "swtblfmt.hxx"
56 #include "docary.hxx"
57 #include "ndindex.hxx"
58 #include "undobj.hxx"
59 #include "switerator.hxx"
60 #include <UndoTable.hxx>
61 
62 using namespace ::com::sun::star;
63 
64 
65 extern void ClearFEShellTabCols();
66 
67 //siehe auch swtable.cxx
68 #define COLFUZZY 20L
69 
70 inline sal_Bool IsSame( long nA, long nB ) { return  Abs(nA-nB) <= COLFUZZY; }
71 
72 class SwTblFmtCmp
73 {
74 public:
75     SwFrmFmt *pOld,
76              *pNew;
77     sal_Int16     nType;
78 
79     SwTblFmtCmp( SwFrmFmt *pOld, SwFrmFmt *pNew, sal_Int16 nType );
80 
81     static SwFrmFmt *FindNewFmt( SvPtrarr &rArr, SwFrmFmt*pOld, sal_Int16 nType );
82     static void Delete( SvPtrarr &rArr );
83 };
84 
85 
86 SwTblFmtCmp::SwTblFmtCmp( SwFrmFmt *pO, SwFrmFmt *pN, sal_Int16 nT )
87     : pOld ( pO ), pNew ( pN ), nType( nT )
88 {
89 }
90 
91 SwFrmFmt *SwTblFmtCmp::FindNewFmt( SvPtrarr &rArr, SwFrmFmt *pOld, sal_Int16 nType )
92 {
93     for ( sal_uInt16 i = 0; i < rArr.Count(); ++i )
94     {
95         SwTblFmtCmp *pCmp = (SwTblFmtCmp*)rArr[i];
96         if ( pCmp->pOld == pOld && pCmp->nType == nType )
97             return pCmp->pNew;
98     }
99     return 0;
100 }
101 
102 void SwTblFmtCmp::Delete( SvPtrarr &rArr )
103 {
104     for ( sal_uInt16 i = 0; i < rArr.Count(); ++i )
105         delete (SwTblFmtCmp*)rArr[i];
106 }
107 
108 void lcl_GetStartEndCell( const SwCursor& rCrsr,
109                         SwLayoutFrm *&prStart, SwLayoutFrm *&prEnd )
110 {
111     ASSERT( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( sal_False ),
112             "Tabselection nicht auf Cnt." );
113 
114     Point aPtPos, aMkPos;
115     const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
116     if( pShCrsr )
117     {
118         aPtPos = pShCrsr->GetPtPos();
119         aMkPos = pShCrsr->GetMkPos();
120     }
121 
122     // robust:
123     SwCntntNode* pPointNd = rCrsr.GetCntntNode();
124     SwCntntNode* pMarkNd  = rCrsr.GetCntntNode(sal_False);
125 
126     SwFrm* pPointFrm = pPointNd ? pPointNd->getLayoutFrm( pPointNd->GetDoc()->GetCurrentLayout(), &aPtPos ) : 0;
127     SwFrm* pMarkFrm  = pMarkNd  ? pMarkNd->getLayoutFrm( pMarkNd->GetDoc()->GetCurrentLayout(), &aMkPos )  : 0;
128 
129     prStart = pPointFrm ? pPointFrm->GetUpper() : 0;
130     prEnd   = pMarkFrm  ? pMarkFrm->GetUpper() : 0;
131 }
132 
133 sal_Bool lcl_GetBoxSel( const SwCursor& rCursor, SwSelBoxes& rBoxes,
134                     sal_Bool bAllCrsr = sal_False )
135 {
136     const SwTableCursor* pTblCrsr =
137         dynamic_cast<const SwTableCursor*>(&rCursor);
138     if( pTblCrsr )
139         ::GetTblSelCrs( *pTblCrsr, rBoxes );
140     else
141     {
142         const SwPaM *pCurPam = &rCursor, *pSttPam = pCurPam;
143         do {
144             const SwNode* pNd = pCurPam->GetNode()->FindTableBoxStartNode();
145             if( pNd )
146             {
147                 SwTableBox* pBox = (SwTableBox*)pNd->FindTableNode()->GetTable().
148                                             GetTblBox( pNd->GetIndex() );
149                 rBoxes.Insert( pBox );
150             }
151         } while( bAllCrsr &&
152                 pSttPam != ( pCurPam = (SwPaM*)pCurPam->GetNext()) );
153     }
154     return 0 != rBoxes.Count();
155 }
156 
157 /***********************************************************************
158 #*  Class      :  SwDoc
159 #*  Methoden   :  SetRowHeight(), GetRowHeight()
160 #*  Datum      :  MA 17. May. 93
161 #*  Update     :  JP 28.04.98
162 #***********************************************************************/
163 //Die Zeilenhoehe wird ausgehend von der Selektion ermittelt/gesetzt.
164 //Ausgehend von jeder Zelle innerhalb der Selektion werden nach oben alle
165 //Zeilen abgeklappert, die oberste Zeile erhaelt den gewuenschten Wert alle
166 //tieferliegenden Zeilen einen entsprechenden Wert der sich aus der
167 //Relation der alten und neuen Groesse der obersten Zeile und ihrer
168 //eigenen Groesse ergiebt.
169 //Alle veraenderten Zeilen erhalten ggf. ein eigenes FrmFmt.
170 //Natuerlich darf jede Zeile nur einmal angefasst werden.
171 
172 inline void InsertLine( SvPtrarr& rLineArr, SwTableLine* pLine )
173 {
174     if( USHRT_MAX == rLineArr.GetPos( pLine ) )
175         rLineArr.Insert( pLine, rLineArr.Count() );
176 }
177 
178 //-----------------------------------------------------------------------------
179 
180 sal_Bool lcl_IsAnLower( const SwTableLine *pLine, const SwTableLine *pAssumed )
181 {
182     const SwTableLine *pTmp = pAssumed->GetUpper() ?
183                                     pAssumed->GetUpper()->GetUpper() : 0;
184     while ( pTmp )
185     {
186         if ( pTmp == pLine )
187             return sal_True;
188         pTmp = pTmp->GetUpper() ? pTmp->GetUpper()->GetUpper() : 0;
189     }
190     return sal_False;
191 }
192 //-----------------------------------------------------------------------------
193 
194 struct LinesAndTable
195 {
196           SvPtrarr &rLines;
197     const SwTable  &rTable;
198           sal_Bool      bInsertLines;
199 
200     LinesAndTable( SvPtrarr &rL, const SwTable &rTbl ) :
201           rLines( rL ), rTable( rTbl ), bInsertLines( sal_True ) {}
202 };
203 
204 
205 sal_Bool _FindLine( const _FndLine*& rpLine, void* pPara );
206 
207 sal_Bool _FindBox( const _FndBox*& rpBox, void* pPara )
208 {
209     if ( rpBox->GetLines().Count() )
210     {
211         ((LinesAndTable*)pPara)->bInsertLines = sal_True;
212         ((_FndBox*)rpBox)->GetLines().ForEach( _FindLine, pPara );
213         if ( ((LinesAndTable*)pPara)->bInsertLines )
214         {
215             const SwTableLines &rLines = rpBox->GetBox()
216                                     ? rpBox->GetBox()->GetTabLines()
217                                     : ((LinesAndTable*)pPara)->rTable.GetTabLines();
218             if ( rpBox->GetLines().Count() == rLines.Count() )
219             {
220                 for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
221                     ::InsertLine( ((LinesAndTable*)pPara)->rLines,
222                                   (SwTableLine*)rLines[i] );
223             }
224             else
225                 ((LinesAndTable*)pPara)->bInsertLines = sal_False;
226         }
227     }
228     else if ( rpBox->GetBox() )
229         ::InsertLine( ((LinesAndTable*)pPara)->rLines,
230                       (SwTableLine*)rpBox->GetBox()->GetUpper() );
231     return sal_True;
232 }
233 
234 sal_Bool _FindLine( const _FndLine*& rpLine, void* pPara )
235 {
236     ((_FndLine*)rpLine)->GetBoxes().ForEach( _FindBox, pPara );
237     return sal_True;
238 }
239 
240 void lcl_CollectLines( SvPtrarr &rArr, const SwCursor& rCursor, bool bRemoveLines )
241 {
242     //Zuerst die selektierten Boxen einsammeln.
243     SwSelBoxes aBoxes;
244     if( !::lcl_GetBoxSel( rCursor, aBoxes ))
245         return ;
246 
247     //Die selektierte Struktur kopieren.
248     const SwTable &rTable = aBoxes[0]->GetSttNd()->FindTableNode()->GetTable();
249     LinesAndTable aPara( rArr, rTable );
250     _FndBox aFndBox( 0, 0 );
251     {
252         _FndPara aTmpPara( aBoxes, &aFndBox );
253         ((SwTableLines&)rTable.GetTabLines()).ForEach( &_FndLineCopyCol, &aTmpPara );
254     }
255 
256     //Diejenigen Lines einsammeln, die nur selektierte Boxen enthalten.
257     const _FndBox *pTmp = &aFndBox;
258     ::_FindBox( pTmp, &aPara );
259 
260     // Remove lines, that have a common superordinate row.
261     // (Not for row split)
262     if ( bRemoveLines )
263     {
264         for ( sal_uInt16 i = 0; i < rArr.Count(); ++i )
265         {
266             SwTableLine *pUpLine = (SwTableLine*)rArr[i];
267             for ( sal_uInt16 k = 0; k < rArr.Count(); ++k )
268             {
269                 if ( k != i && ::lcl_IsAnLower( pUpLine, (SwTableLine*)rArr[k] ) )
270                 {
271                     rArr.Remove( k );
272                     if ( k <= i )
273                         --i;
274                     --k;
275                 }
276             }
277         }
278     }
279 }
280 
281 //-----------------------------------------------------------------------------
282 
283 void lcl_ProcessRowAttr( SvPtrarr& rFmtCmp, SwTableLine* pLine, const SfxPoolItem& rNew )
284 {
285     SwFrmFmt *pNewFmt;
286     if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( rFmtCmp, pLine->GetFrmFmt(), 0 )))
287         pLine->ChgFrmFmt( (SwTableLineFmt*)pNewFmt );
288     else
289     {
290         SwFrmFmt *pOld = pLine->GetFrmFmt();
291         SwFrmFmt *pNew = pLine->ClaimFrmFmt();
292         pNew->SetFmtAttr( rNew );
293         rFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), rFmtCmp.Count());
294     }
295 }
296 
297 //-----------------------------------------------------------------------------
298 
299 void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew );
300 
301 void lcl_ProcessRowSize( SvPtrarr &rFmtCmp, SwTableLine *pLine, const SwFmtFrmSize &rNew )
302 {
303     lcl_ProcessRowAttr( rFmtCmp, pLine, rNew );
304     SwTableBoxes &rBoxes = pLine->GetTabBoxes();
305     for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
306         ::lcl_ProcessBoxSize( rFmtCmp, rBoxes[i], rNew );
307 }
308 
309 //-----------------------------------------------------------------------------
310 
311 void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew )
312 {
313     SwTableLines &rLines = pBox->GetTabLines();
314     if ( rLines.Count() )
315     {
316         SwFmtFrmSize aSz( rNew );
317         aSz.SetHeight( rNew.GetHeight() ? rNew.GetHeight() / rLines.Count() : 0 );
318         for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
319             ::lcl_ProcessRowSize( rFmtCmp, rLines[i], aSz );
320     }
321 }
322 
323 //-----------------------------------------------------------------------------
324 
325 /******************************************************************************
326  *              void SwDoc::SetRowSplit()
327  ******************************************************************************/
328 void SwDoc::SetRowSplit( const SwCursor& rCursor, const SwFmtRowSplit &rNew )
329 {
330     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
331     if( pTblNd )
332     {
333         SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines.
334         ::lcl_CollectLines( aRowArr, rCursor, false );
335 
336         if( aRowArr.Count() )
337         {
338             if (GetIDocumentUndoRedo().DoesUndo())
339             {
340                 GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd));
341             }
342 
343             SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 );
344 
345             for( sal_uInt16 i = 0; i < aRowArr.Count(); ++i )
346                 ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew );
347 
348             SwTblFmtCmp::Delete( aFmtCmp );
349             SetModified();
350         }
351     }
352 }
353 
354 
355 /******************************************************************************
356  *               SwTwips SwDoc::GetRowSplit() const
357  ******************************************************************************/
358 void SwDoc::GetRowSplit( const SwCursor& rCursor, SwFmtRowSplit *& rpSz ) const
359 {
360     rpSz = 0;
361 
362     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
363     if( pTblNd )
364     {
365         SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines.
366         ::lcl_CollectLines( aRowArr, rCursor, false );
367 
368         if( aRowArr.Count() )
369         {
370             rpSz = &(SwFmtRowSplit&)((SwTableLine*)aRowArr[0])->
371                                                 GetFrmFmt()->GetRowSplit();
372 
373             for ( sal_uInt16 i = 1; i < aRowArr.Count() && rpSz; ++i )
374             {
375                 if ( (*rpSz).GetValue() != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetRowSplit().GetValue() )
376                     rpSz = 0;
377             }
378             if ( rpSz )
379                 rpSz = new SwFmtRowSplit( *rpSz );
380         }
381     }
382 }
383 
384 
385 /******************************************************************************
386  *              void SwDoc::SetRowHeight( SwTwips nNew )
387  ******************************************************************************/
388 void SwDoc::SetRowHeight( const SwCursor& rCursor, const SwFmtFrmSize &rNew )
389 {
390     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
391     if( pTblNd )
392     {
393         SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines.
394         ::lcl_CollectLines( aRowArr, rCursor, true );
395 
396         if( aRowArr.Count() )
397         {
398             if (GetIDocumentUndoRedo().DoesUndo())
399             {
400                 GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd));
401             }
402 
403             SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 );
404             for ( sal_uInt16 i = 0; i < aRowArr.Count(); ++i )
405                 ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], rNew );
406             SwTblFmtCmp::Delete( aFmtCmp );
407 
408             SetModified();
409         }
410     }
411 }
412 
413 
414 /******************************************************************************
415  *               SwTwips SwDoc::GetRowHeight() const
416  ******************************************************************************/
417 void SwDoc::GetRowHeight( const SwCursor& rCursor, SwFmtFrmSize *& rpSz ) const
418 {
419     rpSz = 0;
420 
421     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
422     if( pTblNd )
423     {
424         SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines.
425         ::lcl_CollectLines( aRowArr, rCursor, true );
426 
427         if( aRowArr.Count() )
428         {
429             rpSz = &(SwFmtFrmSize&)((SwTableLine*)aRowArr[0])->
430                                                 GetFrmFmt()->GetFrmSize();
431 
432             for ( sal_uInt16 i = 1; i < aRowArr.Count() && rpSz; ++i )
433             {
434                 if ( *rpSz != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetFrmSize() )
435                     rpSz = 0;
436             }
437             if ( rpSz )
438                 rpSz = new SwFmtFrmSize( *rpSz );
439         }
440     }
441 }
442 
443 sal_Bool SwDoc::BalanceRowHeight( const SwCursor& rCursor, sal_Bool bTstOnly )
444 {
445     sal_Bool bRet = sal_False;
446     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
447     if( pTblNd )
448     {
449         SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines.
450         ::lcl_CollectLines( aRowArr, rCursor, true );
451 
452         if( 1 < aRowArr.Count() )
453         {
454             if( !bTstOnly )
455             {
456                 long nHeight = 0;
457                 sal_uInt16 i;
458 
459                 for ( i = 0; i < aRowArr.Count(); ++i )
460                 {
461                     SwIterator<SwFrm,SwFmt> aIter( *((SwTableLine*)aRowArr[i])->GetFrmFmt() );
462                     SwFrm* pFrm = aIter.First();
463                     while ( pFrm )
464                     {
465                         nHeight = Max( nHeight, pFrm->Frm().Height() );
466                         pFrm = aIter.Next();
467                     }
468                 }
469                 SwFmtFrmSize aNew( ATT_MIN_SIZE, 0, nHeight );
470 
471                 if (GetIDocumentUndoRedo().DoesUndo())
472                 {
473                     GetIDocumentUndoRedo().AppendUndo(
474                             new SwUndoAttrTbl(*pTblNd));
475                 }
476 
477                 SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 );
478                 for( i = 0; i < aRowArr.Count(); ++i )
479                     ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], aNew );
480                 SwTblFmtCmp::Delete( aFmtCmp );
481 
482                 SetModified();
483             }
484             bRet = sal_True;
485         }
486     }
487     return bRet;
488 }
489 
490 /******************************************************************************
491  *              void SwDoc::SetRowBackground()
492  ******************************************************************************/
493 void SwDoc::SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew )
494 {
495     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
496     if( pTblNd )
497     {
498         SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines.
499         ::lcl_CollectLines( aRowArr, rCursor, true );
500 
501         if( aRowArr.Count() )
502         {
503             if (GetIDocumentUndoRedo().DoesUndo())
504             {
505                 GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd));
506             }
507 
508             SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aRowArr.Count()) ), 255 );
509 
510             for( sal_uInt16 i = 0; i < aRowArr.Count(); ++i )
511                 ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew );
512 
513             SwTblFmtCmp::Delete( aFmtCmp );
514             SetModified();
515         }
516     }
517 }
518 
519 /******************************************************************************
520  *               SwTwips SwDoc::GetRowBackground() const
521  ******************************************************************************/
522 sal_Bool SwDoc::GetRowBackground( const SwCursor& rCursor, SvxBrushItem &rToFill ) const
523 {
524     sal_Bool bRet = sal_False;
525     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
526     if( pTblNd )
527     {
528         SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines.
529         ::lcl_CollectLines( aRowArr, rCursor, true );
530 
531         if( aRowArr.Count() )
532         {
533             rToFill = ((SwTableLine*)aRowArr[0])->GetFrmFmt()->GetBackground();
534 
535             bRet = sal_True;
536             for ( sal_uInt16 i = 1; i < aRowArr.Count(); ++i )
537                 if ( rToFill != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetBackground() )
538                 {
539                     bRet = sal_False;
540                     break;
541                 }
542         }
543     }
544     return bRet;
545 }
546 
547 /***********************************************************************
548 #*  Class      :  SwDoc
549 #*  Methoden   :  SetTabBorders(), GetTabBorders()
550 #*  Datum      :  MA 18. May. 93
551 #*  Update     :  JP 29.04.98
552 #***********************************************************************/
553 inline void InsertCell( SvPtrarr& rCellArr, SwCellFrm* pCellFrm )
554 {
555     if( USHRT_MAX == rCellArr.GetPos( pCellFrm ) )
556         rCellArr.Insert( pCellFrm, rCellArr.Count() );
557 }
558 
559 //-----------------------------------------------------------------------------
560 void lcl_CollectCells( SvPtrarr &rArr, const SwRect &rUnion,
561                           SwTabFrm *pTab )
562 {
563     SwLayoutFrm *pCell = pTab->FirstCell();
564     do
565     {
566         // Wenn in der Zelle ein spaltiger Bereich sitzt, muessen wir
567         // uns erst wieder zur Zelle hochhangeln
568         while ( !pCell->IsCellFrm() )
569             pCell = pCell->GetUpper();
570         ASSERT( pCell, "Frame ist keine Zelle." );
571         if ( rUnion.IsOver( pCell->Frm() ) )
572             ::InsertCell( rArr, (SwCellFrm*)pCell );
573         //Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche)
574         SwLayoutFrm *pTmp = pCell;
575         do
576         {   pTmp = pTmp->GetNextLayoutLeaf();
577         } while ( pCell->IsAnLower( pTmp ) );
578         pCell = pTmp;
579     } while( pCell && pTab->IsAnLower( pCell ) );
580 }
581 
582 void SwDoc::SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet )
583 {
584     SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode();
585     SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0;
586     if( !pTblNd )
587         return ;
588 
589     SwLayoutFrm *pStart, *pEnd;
590     ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
591 
592     SwSelUnions aUnions;
593     ::MakeSelUnions( aUnions, pStart, pEnd );
594 
595     if( aUnions.Count() )
596     {
597         SwTable& rTable = pTblNd->GetTable();
598         if (GetIDocumentUndoRedo().DoesUndo())
599         {
600             GetIDocumentUndoRedo().AppendUndo( new SwUndoAttrTbl(*pTblNd) );
601         }
602 
603         SvPtrarr aFmtCmp( 255, 255 );
604         const SvxBoxItem* pSetBox;
605         const SvxBoxInfoItem *pSetBoxInfo;
606 
607         const SvxBorderLine* pLeft = 0;
608         const SvxBorderLine* pRight = 0;
609         const SvxBorderLine* pTop = 0;
610         const SvxBorderLine* pBottom = 0;
611         const SvxBorderLine* pHori = 0;
612         const SvxBorderLine* pVert = 0;
613         sal_Bool bHoriValid = sal_True, bVertValid = sal_True,
614              bTopValid = sal_True, bBottomValid = sal_True,
615              bLeftValid = sal_True, bRightValid = sal_True;
616 
617         // JP 21.07.95: die Flags im BoxInfo-Item entscheiden, wann eine
618         //              BorderLine gueltig ist!!
619         if( SFX_ITEM_SET == rSet.GetItemState( SID_ATTR_BORDER_INNER, sal_False,
620             (const SfxPoolItem**)&pSetBoxInfo) )
621         {
622             pHori = pSetBoxInfo->GetHori();
623             pVert = pSetBoxInfo->GetVert();
624 
625             bHoriValid = pSetBoxInfo->IsValid(VALID_HORI);
626             bVertValid = pSetBoxInfo->IsValid(VALID_VERT);
627 
628             // wollen wir die auswerten ??
629             bTopValid = pSetBoxInfo->IsValid(VALID_TOP);
630             bBottomValid = pSetBoxInfo->IsValid(VALID_BOTTOM);
631             bLeftValid = pSetBoxInfo->IsValid(VALID_LEFT);
632             bRightValid = pSetBoxInfo->IsValid(VALID_RIGHT);
633         }
634 
635         if( SFX_ITEM_SET == rSet.GetItemState( RES_BOX, sal_False,
636             (const SfxPoolItem**)&pSetBox) )
637         {
638             pLeft = pSetBox->GetLeft();
639             pRight = pSetBox->GetRight();
640             pTop = pSetBox->GetTop();
641             pBottom = pSetBox->GetBottom();
642         }
643         else
644         {
645             // nicht gesetzt, also keine gueltigen Werte
646             bTopValid = bBottomValid = bLeftValid = bRightValid = sal_False;
647             pSetBox = 0;
648         }
649 
650         sal_Bool bFirst = sal_True;
651         for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i )
652         {
653             SwSelUnion *pUnion = aUnions[i];
654             SwTabFrm *pTab = pUnion->GetTable();
655             const SwRect &rUnion = pUnion->GetUnion();
656             const sal_Bool bLast  = i == aUnions.Count() - 1 ? sal_True : sal_False;
657 
658             SvPtrarr aCellArr( 255, 255 );
659             ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
660 
661             //Alle Zellenkanten, die mit dem UnionRect uebereinstimmen oder
662             //darueber hinausragen sind Aussenkanten. Alle anderen sind
663             //Innenkanten.
664             //neu: Die Aussenkanten koennen abhaengig davon, ob es sich um eine
665             //Start/Mittlere/Folge -Tabelle (bei Selektionen ueber FollowTabs)
666             //handelt doch keine Aussenkanten sein.
667             //Aussenkanten werden links, rechts, oben und unten gesetzt.
668             //Innenkanten werden nur oben und links gesetzt.
669             for ( sal_uInt16 j = 0; j < aCellArr.Count(); ++j )
670             {
671                 SwCellFrm *pCell = (SwCellFrm*)aCellArr[j];
672                 const sal_Bool bVert = pTab->IsVertical();
673                 const sal_Bool bRTL = pTab->IsRightToLeft();
674                 sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver;
675                 if ( bVert )
676                 {
677                     bTopOver = pCell->Frm().Right() >= rUnion.Right();
678                     bLeftOver = pCell->Frm().Top() <= rUnion.Top();
679                     bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom();
680                     bBottomOver = pCell->Frm().Left() <= rUnion.Left();
681                 }
682                 else
683                 {
684                     bTopOver = pCell->Frm().Top() <= rUnion.Top();
685                     bLeftOver = pCell->Frm().Left() <= rUnion.Left();
686                     bRightOver = pCell->Frm().Right() >= rUnion.Right();
687                     bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom();
688                 }
689 
690                 if ( bRTL )
691                 {
692                     sal_Bool bTmp = bRightOver;
693                     bRightOver = bLeftOver;
694                     bLeftOver = bTmp;
695                 }
696 
697                 //Grundsaetzlich nichts setzen in HeadlineRepeats.
698                 if ( pTab->IsFollow() &&
699                      ( pTab->IsInHeadline( *pCell ) ||
700                        // --> FME 2006-02-07 #126092# Same holds for follow flow rows.
701                        pCell->IsInFollowFlowRow() ) )
702                        // <--
703                     continue;
704 
705                 SvxBoxItem aBox( pCell->GetFmt()->GetBox() );
706 
707                 sal_Int16 nType = 0;
708 
709                 //Obere Kante
710                 if( bTopValid )
711                 {
712                     if ( bFirst && bTopOver )
713                     {
714                         aBox.SetLine( pTop, BOX_LINE_TOP );
715                         nType |= 0x0001;
716                     }
717                     else if ( bHoriValid )
718                     {
719                         aBox.SetLine( 0, BOX_LINE_TOP );
720                         nType |= 0x0002;
721                     }
722                 }
723 
724                 //Linke Kante
725                 if ( bLeftOver )
726                 {
727                     if( bLeftValid )
728                     {
729                         aBox.SetLine( pLeft, BOX_LINE_LEFT );
730                         nType |= 0x0004;
731                     }
732                 }
733                 else if( bVertValid )
734                 {
735                     aBox.SetLine( pVert, BOX_LINE_LEFT );
736                     nType |= 0x0008;
737                 }
738 
739                 //Rechte Kante
740                 if( bRightValid )
741                 {
742                     if ( bRightOver )
743                     {
744                         aBox.SetLine( pRight, BOX_LINE_RIGHT );
745                         nType |= 0x0010;
746                     }
747                     else if ( bVertValid )
748                     {
749                         aBox.SetLine( 0, BOX_LINE_RIGHT );
750                         nType |= 0x0020;
751                     }
752                 }
753 
754                 //Untere Kante
755                 if ( bLast && bBottomOver )
756                 {
757                     if( bBottomValid )
758                     {
759                         aBox.SetLine( pBottom, BOX_LINE_BOTTOM );
760                         nType |= 0x0040;
761                     }
762                 }
763                 else if( bHoriValid )
764                 {
765                     aBox.SetLine( pHori, BOX_LINE_BOTTOM );
766                     nType |= 0x0080;
767                 }
768 
769                 if( pSetBox )
770                 {
771                     static sal_uInt16 __READONLY_DATA aBorders[] = {
772                         BOX_LINE_BOTTOM, BOX_LINE_TOP,
773                         BOX_LINE_RIGHT, BOX_LINE_LEFT };
774                     const sal_uInt16* pBrd = aBorders;
775                     for( int k = 0; k < 4; ++k, ++pBrd )
776                         aBox.SetDistance( pSetBox->GetDistance( *pBrd ), *pBrd );
777                 }
778 
779                 SwTableBox *pBox = (SwTableBox*)pCell->GetTabBox();
780                 SwFrmFmt *pNewFmt;
781                 if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), nType )))
782                     pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt );
783                 else
784                 {
785                     SwFrmFmt *pOld = pBox->GetFrmFmt();
786                     SwFrmFmt *pNew = pBox->ClaimFrmFmt();
787                     pNew->SetFmtAttr( aBox );
788                     aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, nType ), aFmtCmp.Count());
789                 }
790             }
791 
792             bFirst = sal_False;
793         }
794 
795         SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
796         if( pTableLayout )
797         {
798             SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() );
799             SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm();
800 
801             pTableLayout->BordersChanged(
802                 pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True );
803         }
804         SwTblFmtCmp::Delete( aFmtCmp );
805         ::ClearFEShellTabCols();
806         SetModified();
807     }
808 }
809 
810 void lcl_SetLineStyle( SvxBorderLine *pToSet,
811                           const Color *pColor, const SvxBorderLine *pBorderLine)
812 {
813     if ( pBorderLine )
814     {
815         if ( !pColor )
816         {
817             Color aTmp( pToSet->GetColor() );
818             *pToSet = *pBorderLine;
819             pToSet->SetColor( aTmp );
820         }
821         else
822             *pToSet = *pBorderLine;
823     }
824     if ( pColor )
825         pToSet->SetColor( *pColor );
826 }
827 
828 void SwDoc::SetTabLineStyle( const SwCursor& rCursor,
829                              const Color* pColor, sal_Bool bSetLine,
830                              const SvxBorderLine* pBorderLine )
831 {
832     SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode();
833     SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0;
834     if( !pTblNd )
835         return ;
836 
837     SwLayoutFrm *pStart, *pEnd;
838     ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
839 
840     SwSelUnions aUnions;
841     ::MakeSelUnions( aUnions, pStart, pEnd );
842 
843     if( aUnions.Count() )
844     {
845         SwTable& rTable = pTblNd->GetTable();
846         if (GetIDocumentUndoRedo().DoesUndo())
847         {
848             GetIDocumentUndoRedo().AppendUndo(new SwUndoAttrTbl(*pTblNd));
849         }
850 
851         for( sal_uInt16 i = 0; i < aUnions.Count(); ++i )
852         {
853             SwSelUnion *pUnion = aUnions[i];
854             SwTabFrm *pTab = pUnion->GetTable();
855             SvPtrarr aCellArr( 255, 255 );
856             ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
857 
858             for ( sal_uInt16 j = 0; j < aCellArr.Count(); ++j )
859             {
860                 SwCellFrm *pCell = ( SwCellFrm* )aCellArr[j];
861 
862                 //Grundsaetzlich nichts setzen in HeadlineRepeats.
863                 if ( pTab->IsFollow() && pTab->IsInHeadline( *pCell ) )
864                     continue;
865 
866                 ((SwTableBox*)pCell->GetTabBox())->ClaimFrmFmt();
867                 SwFrmFmt *pFmt = pCell->GetFmt();
868                 SvxBoxItem aBox( pFmt->GetBox() );
869 
870                 if ( !pBorderLine && bSetLine )
871                     aBox = *(SvxBoxItem*)::GetDfltAttr( RES_BOX );
872                 else
873                 {
874                     if ( aBox.GetTop() )
875                         ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetTop(),
876                                         pColor, pBorderLine );
877                     if ( aBox.GetBottom() )
878                         ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetBottom(),
879                                         pColor, pBorderLine );
880                     if ( aBox.GetLeft() )
881                         ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetLeft(),
882                                         pColor, pBorderLine );
883                     if ( aBox.GetRight() )
884                         ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetRight(),
885                                         pColor, pBorderLine );
886                 }
887                 pFmt->SetFmtAttr( aBox );
888             }
889         }
890 
891         SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
892         if( pTableLayout )
893         {
894             SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() );
895             SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm();
896 
897             pTableLayout->BordersChanged(
898                 pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True );
899         }
900         ::ClearFEShellTabCols();
901         SetModified();
902     }
903 }
904 
905 void SwDoc::GetTabBorders( const SwCursor& rCursor, SfxItemSet& rSet ) const
906 {
907     SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode();
908     SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0;
909     if( !pTblNd )
910         return ;
911 
912     SwLayoutFrm *pStart, *pEnd;
913     ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
914 
915     SwSelUnions aUnions;
916     ::MakeSelUnions( aUnions, pStart, pEnd );
917 
918     if( aUnions.Count() )
919     {
920         SvxBoxItem     aSetBox    ((const SvxBoxItem    &) rSet.Get(RES_BOX    ));
921         SvxBoxInfoItem aSetBoxInfo((const SvxBoxInfoItem&) rSet.Get(SID_ATTR_BORDER_INNER));
922 
923         sal_Bool bTopSet      = sal_False,
924              bBottomSet   = sal_False,
925              bLeftSet     = sal_False,
926              bRightSet    = sal_False,
927              bHoriSet     = sal_False,
928              bVertSet     = sal_False,
929              bDistanceSet = sal_False;
930 
931         aSetBoxInfo.ResetFlags();
932 
933         for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i )
934         {
935             SwSelUnion *pUnion = aUnions[i];
936             const SwTabFrm *pTab = pUnion->GetTable();
937             const SwRect &rUnion = pUnion->GetUnion();
938             const sal_Bool bFirst = i == 0 ? sal_True : sal_False;
939             const sal_Bool bLast  = i == aUnions.Count() - 1 ? sal_True : sal_False;
940 
941             SvPtrarr aCellArr( 255, 255 );
942             ::lcl_CollectCells( aCellArr, rUnion, (SwTabFrm*)pTab );
943 
944             for ( sal_uInt16 j = 0; j < aCellArr.Count(); ++j )
945             {
946                 const SwCellFrm *pCell = (const SwCellFrm*)aCellArr[j];
947                 const sal_Bool bVert = pTab->IsVertical();
948                 const sal_Bool bRTL = pTab->IsRightToLeft();
949                 sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver;
950                 if ( bVert )
951                 {
952                     bTopOver = pCell->Frm().Right() >= rUnion.Right();
953                     bLeftOver = pCell->Frm().Top() <= rUnion.Top();
954                     bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom();
955                     bBottomOver = pCell->Frm().Left() <= rUnion.Left();
956                 }
957                 else
958                 {
959                     bTopOver = pCell->Frm().Top() <= rUnion.Top();
960                     bLeftOver = pCell->Frm().Left() <= rUnion.Left();
961                     bRightOver = pCell->Frm().Right() >= rUnion.Right();
962                     bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom();
963                 }
964 
965                 if ( bRTL )
966                 {
967                     sal_Bool bTmp = bRightOver;
968                     bRightOver = bLeftOver;
969                     bLeftOver = bTmp;
970                 }
971 
972                 const SwFrmFmt  *pFmt  = pCell->GetFmt();
973                 const SvxBoxItem  &rBox  = pFmt->GetBox();
974 
975                 //Obere Kante
976                 if ( bFirst && bTopOver )
977                 {
978                     if (aSetBoxInfo.IsValid(VALID_TOP))
979                     {
980                         if ( !bTopSet )
981                         {   bTopSet = sal_True;
982                             aSetBox.SetLine( rBox.GetTop(), BOX_LINE_TOP );
983                         }
984                         else if ((aSetBox.GetTop() && rBox.GetTop() &&
985                                  !(*aSetBox.GetTop() == *rBox.GetTop())) ||
986                                  ((!aSetBox.GetTop()) ^ (!rBox.GetTop()))) // XOR-Ausdruck ist sal_True, wenn genau einer der beiden Pointer 0 ist
987                         {
988                             aSetBoxInfo.SetValid(VALID_TOP, sal_False );
989                             aSetBox.SetLine( 0, BOX_LINE_TOP );
990                         }
991                     }
992                 }
993 
994                 //Linke Kante
995                 if ( bLeftOver )
996                 {
997                     if (aSetBoxInfo.IsValid(VALID_LEFT))
998                     {
999                         if ( !bLeftSet )
1000                         {   bLeftSet = sal_True;
1001                             aSetBox.SetLine( rBox.GetLeft(), BOX_LINE_LEFT );
1002                         }
1003                         else if ((aSetBox.GetLeft() && rBox.GetLeft() &&
1004                                  !(*aSetBox.GetLeft() == *rBox.GetLeft())) ||
1005                                  ((!aSetBox.GetLeft()) ^ (!rBox.GetLeft())))
1006                         {
1007                             aSetBoxInfo.SetValid(VALID_LEFT, sal_False );
1008                             aSetBox.SetLine( 0, BOX_LINE_LEFT );
1009                         }
1010                     }
1011                 }
1012                 else
1013                 {
1014                     if (aSetBoxInfo.IsValid(VALID_VERT))
1015                     {
1016                         if ( !bVertSet )
1017                         {   bVertSet = sal_True;
1018                             aSetBoxInfo.SetLine( rBox.GetLeft(), BOXINFO_LINE_VERT );
1019                         }
1020                         else if ((aSetBoxInfo.GetVert() && rBox.GetLeft() &&
1021                                  !(*aSetBoxInfo.GetVert() == *rBox.GetLeft())) ||
1022                                  ((!aSetBoxInfo.GetVert()) ^ (!rBox.GetLeft())))
1023                         {   aSetBoxInfo.SetValid( VALID_VERT, sal_False );
1024                             aSetBoxInfo.SetLine( 0, BOXINFO_LINE_VERT );
1025                         }
1026                     }
1027                 }
1028 
1029                 //Rechte Kante
1030                 if ( aSetBoxInfo.IsValid(VALID_RIGHT) && bRightOver )
1031                 {
1032                     if ( !bRightSet )
1033                     {   bRightSet = sal_True;
1034                         aSetBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT );
1035                     }
1036                     else if ((aSetBox.GetRight() && rBox.GetRight() &&
1037                              !(*aSetBox.GetRight() == *rBox.GetRight())) ||
1038                              (!aSetBox.GetRight() ^ !rBox.GetRight()))
1039                     {   aSetBoxInfo.SetValid( VALID_RIGHT, sal_False );
1040                         aSetBox.SetLine( 0, BOX_LINE_RIGHT );
1041                     }
1042                 }
1043 
1044                 //Untere Kante
1045                 if ( bLast && bBottomOver )
1046                 {
1047                     if ( aSetBoxInfo.IsValid(VALID_BOTTOM) )
1048                     {
1049                         if ( !bBottomSet )
1050                         {   bBottomSet = sal_True;
1051                             aSetBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM );
1052                         }
1053                         else if ((aSetBox.GetBottom() && rBox.GetBottom() &&
1054                                  !(*aSetBox.GetBottom() == *rBox.GetBottom())) ||
1055                                  (!aSetBox.GetBottom() ^ !rBox.GetBottom()))
1056                         {   aSetBoxInfo.SetValid( VALID_BOTTOM, sal_False );
1057                             aSetBox.SetLine( 0, BOX_LINE_BOTTOM );
1058                         }
1059                     }
1060                 }
1061                 //in allen Zeilen ausser der letzten werden die
1062                 // horiz. Linien aus der Bottom-Linie entnommen
1063                 else
1064                 {
1065                     if (aSetBoxInfo.IsValid(VALID_HORI))
1066                     {
1067                         if ( !bHoriSet )
1068                         {   bHoriSet = sal_True;
1069                             aSetBoxInfo.SetLine( rBox.GetBottom(), BOXINFO_LINE_HORI );
1070                         }
1071                         else if ((aSetBoxInfo.GetHori() && rBox.GetBottom() &&
1072                                  !(*aSetBoxInfo.GetHori() == *rBox.GetBottom())) ||
1073                                  ((!aSetBoxInfo.GetHori()) ^ (!rBox.GetBottom())))
1074                         {
1075                             aSetBoxInfo.SetValid( VALID_HORI, sal_False );
1076                             aSetBoxInfo.SetLine( 0, BOXINFO_LINE_HORI );
1077                         }
1078                     }
1079                 }
1080 
1081                 // Abstand zum Text
1082                 if (aSetBoxInfo.IsValid(VALID_DISTANCE))
1083                 {
1084                     static sal_uInt16 __READONLY_DATA aBorders[] = {
1085                         BOX_LINE_BOTTOM, BOX_LINE_TOP,
1086                         BOX_LINE_RIGHT, BOX_LINE_LEFT };
1087                     const sal_uInt16* pBrd = aBorders;
1088 
1089                     if( !bDistanceSet )     // bei 1. Durchlauf erstmal setzen
1090                     {
1091                         bDistanceSet = sal_True;
1092                         for( int k = 0; k < 4; ++k, ++pBrd )
1093                             aSetBox.SetDistance( rBox.GetDistance( *pBrd ),
1094                                                 *pBrd );
1095                     }
1096                     else
1097                     {
1098                         for( int k = 0; k < 4; ++k, ++pBrd )
1099                             if( aSetBox.GetDistance( *pBrd ) !=
1100                                 rBox.GetDistance( *pBrd ) )
1101                             {
1102                                 aSetBoxInfo.SetValid( VALID_DISTANCE, sal_False );
1103                                 aSetBox.SetDistance( (sal_uInt16) 0 );
1104                                 break;
1105                             }
1106                     }
1107                 }
1108             }
1109         }
1110         rSet.Put( aSetBox );
1111         rSet.Put( aSetBoxInfo );
1112     }
1113 }
1114 
1115 /***********************************************************************
1116 #*  Class      :  SwDoc
1117 #*  Methoden   :  SetBoxAttr
1118 #*  Datum      :  MA 18. Dec. 96
1119 #*  Update     :  JP 29.04.98
1120 #***********************************************************************/
1121 void SwDoc::SetBoxAttr( const SwCursor& rCursor, const SfxPoolItem &rNew )
1122 {
1123     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1124     SwSelBoxes aBoxes;
1125     if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes, sal_True ) )
1126     {
1127         SwTable& rTable = pTblNd->GetTable();
1128         if (GetIDocumentUndoRedo().DoesUndo())
1129         {
1130             GetIDocumentUndoRedo().AppendUndo( new SwUndoAttrTbl(*pTblNd) );
1131         }
1132 
1133         SvPtrarr aFmtCmp( Max( sal_uInt8(255), sal_uInt8(aBoxes.Count()) ), 255 );
1134         for ( sal_uInt16 i = 0; i < aBoxes.Count(); ++i )
1135         {
1136             SwTableBox *pBox = aBoxes[i];
1137 
1138             SwFrmFmt *pNewFmt;
1139             if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), 0 )))
1140                 pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt );
1141             else
1142             {
1143                 SwFrmFmt *pOld = pBox->GetFrmFmt();
1144                 SwFrmFmt *pNew = pBox->ClaimFrmFmt();
1145                 pNew->SetFmtAttr( rNew );
1146                 aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), aFmtCmp.Count());
1147             }
1148         }
1149 
1150         SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
1151         if( pTableLayout )
1152         {
1153             SwCntntFrm* pFrm = rCursor.GetCntntNode()->getLayoutFrm( rCursor.GetCntntNode()->GetDoc()->GetCurrentLayout() );
1154             SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm();
1155 
1156             pTableLayout->Resize(
1157                 pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), sal_True );
1158         }
1159         SwTblFmtCmp::Delete( aFmtCmp );
1160         SetModified();
1161     }
1162 }
1163 
1164 /***********************************************************************
1165 #*  Class      :  SwDoc
1166 #*  Methoden   :  GetBoxAttr()
1167 #*  Datum      :  MA 01. Jun. 93
1168 #*  Update     :  JP 29.04.98
1169 #***********************************************************************/
1170 
1171 sal_Bool SwDoc::GetBoxAttr( const SwCursor& rCursor, SfxPoolItem& rToFill ) const
1172 {
1173     sal_Bool bRet = sal_False;
1174     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1175     SwSelBoxes aBoxes;
1176     if( pTblNd && lcl_GetBoxSel( rCursor, aBoxes ))
1177     {
1178         bRet = sal_True;
1179         sal_Bool bOneFound = sal_False;
1180         const sal_uInt16 nWhich = rToFill.Which();
1181         for( sal_uInt16 i = 0; i < aBoxes.Count(); ++i )
1182         {
1183             switch ( nWhich )
1184             {
1185                 case RES_BACKGROUND:
1186                 {
1187                     const SvxBrushItem &rBack =
1188                                     aBoxes[i]->GetFrmFmt()->GetBackground();
1189                     if( !bOneFound )
1190                     {
1191                         (SvxBrushItem&)rToFill = rBack;
1192                         bOneFound = sal_True;
1193                     }
1194                     else if( rToFill != rBack )
1195                         bRet = sal_False;
1196                 }
1197                 break;
1198 
1199                 case RES_FRAMEDIR:
1200                 {
1201                     const SvxFrameDirectionItem& rDir =
1202                                     aBoxes[i]->GetFrmFmt()->GetFrmDir();
1203                     if( !bOneFound )
1204                     {
1205                         (SvxFrameDirectionItem&)rToFill = rDir;
1206                         bOneFound = sal_True;
1207                     }
1208                     else if( rToFill != rDir )
1209                         bRet = sal_False;
1210                 }
1211             }
1212 
1213             if ( sal_False == bRet )
1214                 break;
1215         }
1216     }
1217     return bRet;
1218 }
1219 
1220 /***********************************************************************
1221 #*  Class      :  SwDoc
1222 #*  Methoden   :  SetBoxAlign, SetBoxAlign
1223 #*  Datum      :  MA 18. Dec. 96
1224 #*  Update     :  JP 29.04.98
1225 #***********************************************************************/
1226 void SwDoc::SetBoxAlign( const SwCursor& rCursor, sal_uInt16 nAlign )
1227 {
1228     ASSERT( nAlign == text::VertOrientation::NONE   ||
1229             nAlign == text::VertOrientation::CENTER ||
1230             nAlign == text::VertOrientation::BOTTOM, "wrong alignment" );
1231     SwFmtVertOrient aVertOri( 0, nAlign );
1232     SetBoxAttr( rCursor, aVertOri );
1233 }
1234 
1235 sal_uInt16 SwDoc::GetBoxAlign( const SwCursor& rCursor ) const
1236 {
1237     sal_uInt16 nAlign = USHRT_MAX;
1238     SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1239     SwSelBoxes aBoxes;
1240     if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes ))
1241         for( sal_uInt16 i = 0; i < aBoxes.Count(); ++i )
1242         {
1243             const SwFmtVertOrient &rOri =
1244                             aBoxes[i]->GetFrmFmt()->GetVertOrient();
1245             if( USHRT_MAX == nAlign )
1246                 nAlign = static_cast<sal_uInt16>(rOri.GetVertOrient());
1247             else if( rOri.GetVertOrient() != nAlign )
1248             {
1249                 nAlign = USHRT_MAX;
1250                 break;
1251             }
1252         }
1253     return nAlign;
1254 }
1255 
1256 
1257 /***********************************************************************
1258 #*  Class      :  SwDoc
1259 #*  Methoden   :  AdjustCellWidth()
1260 #*  Datum      :  MA 20. Feb. 95
1261 #*  Update     :  JP 29.04.98
1262 #***********************************************************************/
1263 sal_uInt16 lcl_CalcCellFit( const SwLayoutFrm *pCell )
1264 {
1265     SwTwips nRet = 0;
1266     const SwFrm *pFrm = pCell->Lower(); //Die ganze Zelle.
1267     SWRECTFN( pCell )
1268     while ( pFrm )
1269     {
1270         const SwTwips nAdd = (pFrm->Frm().*fnRect->fnGetWidth)() -
1271                              (pFrm->Prt().*fnRect->fnGetWidth)();
1272 
1273         // --> FME 2005-12-02 #127801# pFrm does not necessarily have to be a SwTxtFrm!
1274         const SwTwips nCalcFitToContent = pFrm->IsTxtFrm() ?
1275                                           ((SwTxtFrm*)pFrm)->CalcFitToContent() :
1276                                           (pFrm->Prt().*fnRect->fnGetWidth)();
1277         // <--
1278 
1279         nRet = Max( nRet, nCalcFitToContent + nAdd );
1280         pFrm = pFrm->GetNext();
1281     }
1282     //Umrandung und linker/rechter Rand wollen mit kalkuliert werden.
1283     nRet += (pCell->Frm().*fnRect->fnGetWidth)() -
1284             (pCell->Prt().*fnRect->fnGetWidth)();
1285 
1286     //Um Rechenungenauikeiten, die spaeter bei SwTable::SetTabCols enstehen,
1287     //auszugleichen, addieren wir noch ein bischen.
1288     nRet += COLFUZZY;
1289     return (sal_uInt16)Max( long(MINLAY), nRet );
1290 }
1291 
1292 /*Die Zelle ist in der Selektion, wird aber nicht von den TabCols beschrieben.
1293  *Das bedeutet, dass die Zelle aufgrund der zweidimensionalen Darstellung von
1294  *anderen Zellen "geteilt" wurde. Wir muessen also den Wunsch- bzw. Minimalwert
1295  *der Zelle auf die Spalten, durch die sie geteilt wurde verteilen.
1296  *
1297  *Dazu sammeln wir zuerst die Spalten - nicht die Spaltentrenner! - ein, die
1298  *sich mit der Zelle ueberschneiden. Den Wunschwert der Zelle verteilen wir
1299  *dann anhand des Betrages der Ueberschneidung auf die Zellen.
1300  *Wenn eine Zelle bereits einen groesseren Wunschwert angemeldet hat, so bleibt
1301  *dieser erhalten, kleinere Wuensche werden ueberschrieben.
1302  */
1303 
1304 void lcl_CalcSubColValues( SvUShorts &rToFill, const SwTabCols &rCols,
1305                               const SwLayoutFrm *pCell, const SwLayoutFrm *pTab,
1306                               sal_Bool bWishValues )
1307 {
1308     const sal_uInt16 nWish = bWishValues ?
1309                     ::lcl_CalcCellFit( pCell ) :
1310                     MINLAY + sal_uInt16(pCell->Frm().Width() - pCell->Prt().Width());
1311 
1312     SWRECTFN( pTab )
1313 
1314     for ( sal_uInt16 i = 0 ; i <= rCols.Count(); ++i )
1315     {
1316         long nColLeft  = i == 0             ? rCols.GetLeft()  : rCols[i-1];
1317         long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1318         nColLeft  += rCols.GetLeftMin();
1319         nColRight += rCols.GetLeftMin();
1320 
1321         //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen.
1322         if ( rCols.GetLeftMin() !=  sal_uInt16((pTab->Frm().*fnRect->fnGetLeft)()) )
1323         {
1324             const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin();
1325             nColLeft  += nDiff;
1326             nColRight += nDiff;
1327         }
1328         const long nCellLeft  = (pCell->Frm().*fnRect->fnGetLeft)();
1329         const long nCellRight = (pCell->Frm().*fnRect->fnGetRight)();
1330 
1331         //Ueberschneidungsbetrag ermitteln.
1332         long nWidth = 0;
1333         if ( nColLeft <= nCellLeft && nColRight >= (nCellLeft+COLFUZZY) )
1334             nWidth = nColRight - nCellLeft;
1335         else if ( nColLeft <= (nCellRight-COLFUZZY) && nColRight >= nCellRight )
1336             nWidth = nCellRight - nColLeft;
1337         else if ( nColLeft >= nCellLeft && nColRight <= nCellRight )
1338             nWidth = nColRight - nColLeft;
1339         if ( nWidth && pCell->Frm().Width() )
1340         {
1341             long nTmp = nWidth * nWish / pCell->Frm().Width();
1342             if ( sal_uInt16(nTmp) > rToFill[i] )
1343                 rToFill[i] = sal_uInt16(nTmp);
1344         }
1345     }
1346 }
1347 
1348 /*Besorgt neue Werte zu Einstellung der TabCols.
1349  *Es wird nicht ueber die Eintrage in den TabCols itereriert, sondern
1350  *quasi ueber die Zwischenraeume, die ja die Zellen beschreiben.
1351  *
1352  *bWishValues == sal_True:  Es werden zur aktuellen Selektion bzw. zur aktuellen
1353  *                      Zelle die Wunschwerte aller betroffen Zellen ermittelt.
1354  *                      Sind mehrere Zellen in einer Spalte, so wird der
1355  *                      groesste Wunschwert als Ergebnis geliefert.
1356  *                      Fuer die TabCol-Eintraege, zu denen keine Zellen
1357  *                      ermittelt wurden, werden 0-en eingetragen.
1358  *
1359  *bWishValues == sal_False: Die Selektion wird senkrecht ausgedehnt. Zu jeder
1360  *                      Spalte in den TabCols, die sich mit der Selektion
1361  *                      schneidet wird der Minimalwert ermittelt.
1362  */
1363 
1364 void lcl_CalcColValues( SvUShorts &rToFill, const SwTabCols &rCols,
1365                            const SwLayoutFrm *pStart, const SwLayoutFrm *pEnd,
1366                            sal_Bool bWishValues )
1367 {
1368     SwSelUnions aUnions;
1369     ::MakeSelUnions( aUnions, pStart, pEnd,
1370                     bWishValues ? nsSwTblSearchType::TBLSEARCH_NONE : nsSwTblSearchType::TBLSEARCH_COL );
1371 
1372     for ( sal_uInt16 i2 = 0; i2 < aUnions.Count(); ++i2 )
1373     {
1374         SwSelUnion *pSelUnion = aUnions[i2];
1375         const SwTabFrm *pTab = pSelUnion->GetTable();
1376         const SwRect &rUnion = pSelUnion->GetUnion();
1377 
1378         SWRECTFN( pTab )
1379         sal_Bool bRTL = pTab->IsRightToLeft();
1380 
1381         const SwLayoutFrm *pCell = pTab->FirstCell();
1382         do
1383         {
1384             if ( pCell->IsCellFrm() && pCell->FindTabFrm() == pTab && ::IsFrmInTblSel( rUnion, pCell ) )
1385             {
1386                 const long nCLeft  = (pCell->Frm().*fnRect->fnGetLeft)();
1387                 const long nCRight = (pCell->Frm().*fnRect->fnGetRight)();
1388 
1389                 sal_Bool bNotInCols = sal_True;
1390 
1391                 for ( sal_uInt16 i = 0; i <= rCols.Count(); ++i )
1392                 {
1393                     sal_uInt16 nFit = rToFill[i];
1394                     long nColLeft  = i == 0             ? rCols.GetLeft()  : rCols[i-1];
1395                     long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1396 
1397                     if ( bRTL )
1398                     {
1399                         long nTmpRight = nColRight;
1400                         nColRight = rCols.GetRight() - nColLeft;
1401                         nColLeft = rCols.GetRight() - nTmpRight;
1402                     }
1403 
1404                     nColLeft  += rCols.GetLeftMin();
1405                     nColRight += rCols.GetLeftMin();
1406 
1407                     //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen.
1408                     long nLeftA  = nColLeft;
1409                     long nRightA = nColRight;
1410                     if ( rCols.GetLeftMin() !=  sal_uInt16((pTab->Frm().*fnRect->fnGetLeft)()) )
1411                     {
1412                         const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin();
1413                         nLeftA  += nDiff;
1414                         nRightA += nDiff;
1415                     }
1416 
1417                     //Wir wollen nicht allzu genau hinsehen.
1418                     if ( ::IsSame(nCLeft, nLeftA) && ::IsSame(nCRight, nRightA))
1419                     {
1420                         bNotInCols = sal_False;
1421                         if ( bWishValues )
1422                         {
1423                             const sal_uInt16 nWish = ::lcl_CalcCellFit( pCell );
1424                             if ( nWish > nFit )
1425                                 nFit = nWish;
1426                         }
1427                         else
1428                         {   const sal_uInt16 nMin = MINLAY + sal_uInt16(pCell->Frm().Width() -
1429                                                                 pCell->Prt().Width());
1430                             if ( !nFit || nMin < nFit )
1431                                 nFit = nMin;
1432                         }
1433                         if ( rToFill[i] < nFit )
1434                             rToFill[i] = nFit;
1435                     }
1436                 }
1437                 if ( bNotInCols )
1438                     ::lcl_CalcSubColValues( rToFill, rCols, pCell, pTab, bWishValues );
1439             }
1440             do {
1441                 pCell = pCell->GetNextLayoutLeaf();
1442             }while( pCell && pCell->Frm().Width() == 0 );
1443         } while ( pCell && pTab->IsAnLower( pCell ) );
1444     }
1445 }
1446 
1447 
1448 void SwDoc::AdjustCellWidth( const SwCursor& rCursor, sal_Bool bBalance )
1449 {
1450     // pruefe ob vom aktuellen Crsr der Point/Mark in einer Tabelle stehen
1451     SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode();
1452     SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0;
1453     if( !pTblNd )
1454         return ;
1455 
1456     SwLayoutFrm *pStart, *pEnd;
1457     ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
1458 
1459     //TabCols besorgen, den ueber diese stellen wir die Tabelle neu ein.
1460     SwFrm* pBoxFrm = pStart;
1461     while( pBoxFrm && !pBoxFrm->IsCellFrm() )
1462         pBoxFrm = pBoxFrm->GetUpper();
1463 
1464     if ( !pBoxFrm )
1465         return; // robust
1466 
1467     SwTabCols aTabCols;
1468     GetTabCols( aTabCols, 0, (SwCellFrm*)pBoxFrm );
1469 
1470     if ( ! aTabCols.Count() )
1471         return;
1472 
1473     const sal_uInt8 nTmp = (sal_uInt8)Max( sal_uInt16(255), sal_uInt16(aTabCols.Count() + 1) );
1474     SvUShorts aWish( nTmp, nTmp ),
1475               aMins( nTmp, nTmp );
1476     sal_uInt16 i;
1477 
1478     for ( i = 0; i <= aTabCols.Count(); ++i )
1479     {
1480         aWish.Insert( sal_uInt16(0), aWish.Count() );
1481         aMins.Insert( sal_uInt16(0), aMins.Count() );
1482     }
1483     ::lcl_CalcColValues( aWish, aTabCols, pStart, pEnd, sal_True  );
1484 
1485     //Es ist Robuster wenn wir die Min-Werte fuer die ganze Tabelle berechnen.
1486     const SwTabFrm *pTab = pStart->ImplFindTabFrm();
1487     pStart = (SwLayoutFrm*)pTab->FirstCell();
1488     pEnd   = (SwLayoutFrm*)pTab->FindLastCntnt()->GetUpper();
1489     while( !pEnd->IsCellFrm() )
1490         pEnd = pEnd->GetUpper();
1491     ::lcl_CalcColValues( aMins, aTabCols, pStart, pEnd, sal_False );
1492 
1493     if( bBalance )
1494     {
1495         //Alle Spalten, die makiert sind haben jetzt einen Wunschwert
1496         //eingtragen. Wir addieren die aktuellen Werte, teilen das Ergebnis
1497         //durch die Anzahl und haben eine Wunschwert fuer den ausgleich.
1498         sal_uInt16 nWish = 0, nCnt = 0;
1499         for ( i = 0; i <= aTabCols.Count(); ++i )
1500         {
1501             int nDiff = aWish[i];
1502             if ( nDiff )
1503             {
1504                 if ( i == 0 )
1505                     nWish = static_cast<sal_uInt16>( nWish + aTabCols[i] - aTabCols.GetLeft() );
1506                 else if ( i == aTabCols.Count() )
1507                     nWish = static_cast<sal_uInt16>(nWish + aTabCols.GetRight() - aTabCols[i-1] );
1508                 else
1509                     nWish = static_cast<sal_uInt16>(nWish + aTabCols[i] - aTabCols[i-1] );
1510                 ++nCnt;
1511             }
1512         }
1513         nWish = nWish / nCnt;
1514         for ( i = 0; i < aWish.Count(); ++i )
1515             if ( aWish[i] )
1516                 aWish[i] = nWish;
1517     }
1518 
1519     const sal_uInt16 nOldRight = static_cast<sal_uInt16>(aTabCols.GetRight());
1520 
1521     //Um die Impl. einfach zu gestalten, aber trotzdem in den meissten Faellen
1522     //den Platz richtig auszunutzen laufen wir zweimal.
1523     //Problem: Erste Spalte wird breiter, die anderen aber erst danach
1524     //schmaler. Die Wunschbreite der ersten Spalte wuerde abgelehnt, weil
1525     //mit ihr die max. Breite der Tabelle ueberschritten wuerde.
1526     for ( sal_uInt16 k= 0; k < 2; ++k )
1527     {
1528         for ( i = 0; i <= aTabCols.Count(); ++i )
1529         {
1530             int nDiff = aWish[i];
1531             if ( nDiff )
1532             {
1533                 int nMin = aMins[i];
1534                 if ( nMin > nDiff )
1535                     nDiff = nMin;
1536 
1537                 if ( i == 0 )
1538                 {
1539                     if( aTabCols.Count() )
1540                         nDiff -= aTabCols[0] - aTabCols.GetLeft();
1541                     else
1542                         nDiff -= aTabCols.GetRight() - aTabCols.GetLeft();
1543                 }
1544                 else if ( i == aTabCols.Count() )
1545                     nDiff -= aTabCols.GetRight() - aTabCols[i-1];
1546                 else
1547                     nDiff -= aTabCols[i] - aTabCols[i-1];
1548 
1549                 long nTabRight = aTabCols.GetRight() + nDiff;
1550 
1551                 //Wenn die Tabelle zu breit wuerde begrenzen wir die Anpassung
1552                 //auf das erlaubte Maximum.
1553                 if ( !bBalance && nTabRight > aTabCols.GetRightMax() )
1554                 {
1555                     const long nTmpD = nTabRight - aTabCols.GetRightMax();
1556                     nDiff     -= nTmpD;
1557                     nTabRight -= nTmpD;
1558                 }
1559                 for ( sal_uInt16 i2 = i; i2 < aTabCols.Count(); ++i2 )
1560                     aTabCols[i2] += nDiff;
1561                 aTabCols.SetRight( nTabRight );
1562             }
1563         }
1564     }
1565 
1566     const sal_uInt16 nNewRight = static_cast<sal_uInt16>(aTabCols.GetRight());
1567 
1568     SwFrmFmt *pFmt = pTblNd->GetTable().GetFrmFmt();
1569     const sal_Int16 nOriHori = pFmt->GetHoriOrient().GetHoriOrient();
1570 
1571     //So, die richtige Arbeit koennen wir jetzt der SwTable ueberlassen.
1572     SetTabCols( aTabCols, sal_False, 0, (SwCellFrm*)pBoxFrm );
1573 
1574     // i54248: lijian/fme
1575     // alignment might have been changed in SetTabCols, restore old value:
1576     const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient();
1577     SwFmtHoriOrient aHori( rHori );
1578     if ( aHori.GetHoriOrient() != nOriHori )
1579     {
1580         aHori.SetHoriOrient( nOriHori );
1581         pFmt->SetFmtAttr( aHori );
1582     }
1583 
1584     //Bei Automatischer Breite wird auf Linksbuendig umgeschaltet.
1585     //Bei Randattributen wird der Rechte Rand angepasst.
1586     if( !bBalance && nNewRight < nOldRight )
1587     {
1588         if( aHori.GetHoriOrient() == text::HoriOrientation::FULL )
1589         {
1590             aHori.SetHoriOrient( text::HoriOrientation::LEFT );
1591             pFmt->SetFmtAttr( aHori );
1592         }
1593     }
1594 
1595     SetModified();
1596 }
1597 
1598