xref: /aoo41x/main/sw/source/core/docnode/ndtbl1.cxx (revision cdf0e10c)
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