xref: /trunk/main/sw/source/core/doc/tblrwcl.cxx (revision dec99bbd)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 #include <com/sun/star/text/HoriOrientation.hpp>
28 #include <com/sun/star/chart2/XChartDocument.hpp>
29 #include <hintids.hxx>
30 
31 #define _ZFORLIST_DECLARE_TABLE
32 #include <editeng/brshitem.hxx>
33 #include <editeng/lrspitem.hxx>
34 #include <editeng/protitem.hxx>
35 #include <editeng/boxitem.hxx>
36 #include <tools/fract.hxx>
37 #include <fmtfsize.hxx>
38 #include <fmtornt.hxx>
39 #include <doc.hxx>
40 #include <cntfrm.hxx>
41 #include <tabfrm.hxx>
42 #include <frmtool.hxx>
43 #include <pam.hxx>
44 #include <swtable.hxx>
45 #include <ndtxt.hxx>
46 #include <tblsel.hxx>
47 #include <fldbas.hxx>
48 #include <swundo.hxx>
49 #include <rowfrm.hxx>
50 #include <ddefld.hxx>
51 #include <hints.hxx>
52 #include <UndoTable.hxx>
53 #include <cellatr.hxx>
54 #include <mvsave.hxx>
55 #include <swtblfmt.hxx>
56 #include <swddetbl.hxx>
57 #include <poolfmt.hxx>
58 #include <tblrwcl.hxx>
59 #include <unochart.hxx>
60 #include <boost/shared_ptr.hpp>
61 #include <switerator.hxx>
62 
63 using namespace com::sun::star;
64 using namespace com::sun::star::uno;
65 
66 
67 #define COLFUZZY 20
68 #define ROWFUZZY 10
69 
70 using namespace ::com::sun::star;
71 
72 #ifndef DBG_UTIL
73 #define CHECK_TABLE(t)
74 #else
75 #ifdef DEBUG
76 #define CHECK_TABLE(t) (t).CheckConsistency();
77 #else
78 #define CHECK_TABLE(t)
79 #endif
80 #endif
81 
82 typedef SwTableLine* SwTableLinePtr;
83 SV_DECL_PTRARR_SORT( SwSortTableLines, SwTableLinePtr, 16, 16 )
84 SV_IMPL_PTRARR_SORT( SwSortTableLines, SwTableLinePtr );
85 
86 SV_IMPL_PTRARR( _SwShareBoxFmts, SwShareBoxFmt* )
87 
88 // fuers setzen der Frame-Formate an den Boxen reicht es, das aktuelle
89 // im Array zu suchen. Ist es vorhanden, so gebe das neue zurueck
90 struct _CpyTabFrm
91 {
92 	union {
93 		SwTableBoxFmt *pFrmFmt;		// fuer CopyCol
94 		SwTwips nSize;				// fuer DelCol
95 	} Value;
96 	SwTableBoxFmt *pNewFrmFmt;
97 
_CpyTabFrm_CpyTabFrm98 	_CpyTabFrm( SwTableBoxFmt* pAktFrmFmt ) : pNewFrmFmt( 0 )
99 	{	Value.pFrmFmt = pAktFrmFmt;	}
100 
101 	_CpyTabFrm& operator=( const _CpyTabFrm& );
102 
operator ==_CpyTabFrm103 	sal_Bool operator==( const _CpyTabFrm& rCpyTabFrm )
104 		{ return  (sal_uLong)Value.nSize == (sal_uLong)rCpyTabFrm.Value.nSize; }
operator <_CpyTabFrm105 	sal_Bool operator<( const _CpyTabFrm& rCpyTabFrm )
106 		{ return  (sal_uLong)Value.nSize < (sal_uLong)rCpyTabFrm.Value.nSize; }
107 };
108 
109 struct CR_SetBoxWidth
110 {
111 	SwSelBoxes aBoxes;
112 	SwSortTableLines aLines;
113 	SvUShorts aLinesWidth;
114 	SwShareBoxFmts aShareFmts;
115 	SwTableNode* pTblNd;
116 	SwUndoTblNdsChg* pUndo;
117 	SwTwips nDiff, nSide, nMaxSize, nLowerDiff;
118     TblChgMode nMode;
119 	sal_uInt16 nTblWidth, nRemainWidth, nBoxWidth;
120 	sal_Bool bBigger, bLeft, bSplittBox, bAnyBoxFnd;
121 
CR_SetBoxWidthCR_SetBoxWidth122 	CR_SetBoxWidth( sal_uInt16 eType, SwTwips nDif, SwTwips nSid, SwTwips nTblW,
123 					SwTwips nMax, SwTableNode* pTNd )
124 		: pTblNd( pTNd ),
125         nDiff( nDif ), nSide( nSid ), nMaxSize( nMax ), nLowerDiff( 0 ),
126 		nTblWidth( (sal_uInt16)nTblW ), nRemainWidth( 0 ), nBoxWidth( 0 ),
127 		bSplittBox( sal_False ), bAnyBoxFnd( sal_False )
128 	{
129 		bLeft = nsTblChgWidthHeightType::WH_COL_LEFT == ( eType & 0xff ) ||
130 				nsTblChgWidthHeightType::WH_CELL_LEFT == ( eType & 0xff );
131 		bBigger = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_BIGGER );
132 		nMode = pTblNd->GetTable().GetTblChgMode();
133 	}
CR_SetBoxWidthCR_SetBoxWidth134 	CR_SetBoxWidth( const CR_SetBoxWidth& rCpy )
135 		: pTblNd( rCpy.pTblNd ),
136 		pUndo( rCpy.pUndo ),
137         nDiff( rCpy.nDiff ), nSide( rCpy.nSide ),
138 		nMaxSize( rCpy.nMaxSize ), nLowerDiff( 0 ),
139         nMode( rCpy.nMode ), nTblWidth( rCpy.nTblWidth ),
140         nRemainWidth( rCpy.nRemainWidth ), nBoxWidth( rCpy.nBoxWidth ),
141 		bBigger( rCpy.bBigger ), bLeft( rCpy.bLeft ),
142 		bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd )
143 	{
144 		aLines.Insert( &rCpy.aLines );
145 		aLinesWidth.Insert( &rCpy.aLinesWidth, 0 );
146 	}
147 
CreateUndoCR_SetBoxWidth148     SwUndoTblNdsChg* CreateUndo( SwUndoId eUndoType )
149 	{
150         return pUndo = new SwUndoTblNdsChg( eUndoType, aBoxes, *pTblNd );
151 	}
152 
LoopClearCR_SetBoxWidth153 	void LoopClear()
154 	{
155 		nLowerDiff = 0; nRemainWidth = 0;
156 	}
157 
AddBoxWidthCR_SetBoxWidth158 	void AddBoxWidth( const SwTableBox& rBox, sal_uInt16 nWidth )
159 	{
160 		SwTableLinePtr p = (SwTableLine*)rBox.GetUpper();
161 		sal_uInt16 nFndPos;
162 		if( aLines.Insert( p, nFndPos ))
163 			aLinesWidth.Insert( nWidth, nFndPos );
164 		else
165 			aLinesWidth[ nFndPos ] = aLinesWidth[ nFndPos ] + nWidth;
166 	}
167 
GetBoxWidthCR_SetBoxWidth168 	sal_uInt16 GetBoxWidth( const SwTableLine& rLn ) const
169 	{
170 		SwTableLinePtr p = (SwTableLine*)&rLn;
171 		sal_uInt16 nFndPos;
172 		if( aLines.Seek_Entry( p, &nFndPos ) )
173 			nFndPos = aLinesWidth[ nFndPos ];
174 		else
175 			nFndPos = 0;
176 		return nFndPos;
177 	}
178 };
179 
180 sal_Bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
181 						 SwTwips nDist, sal_Bool bCheck );
182 sal_Bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
183 								SwTwips nDist, sal_Bool bCheck );
184 sal_Bool lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
185 								SwTwips nDist, sal_Bool bCheck );
186 sal_Bool lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
187 								SwTwips nDist, sal_Bool bCheck );
188 sal_Bool lcl_DelSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
189 								SwTwips nDist, sal_Bool bCheck );
190 sal_Bool lcl_DelOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
191 								SwTwips nDist, sal_Bool bCheck );
192 
193 typedef sal_Bool (*FN_lcl_SetBoxWidth)(SwTableLine*, CR_SetBoxWidth&, SwTwips, sal_Bool );
194 
195 #if defined(DBG_UTIL) || defined( JP_DEBUG )
196 
197 void _CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize );
198 
199 #define CHECKBOXWIDTH 											\
200 	{ 															\
201 		SwTwips nSize = GetFrmFmt()->GetFrmSize().GetWidth(); 	\
202 		for( sal_uInt16 nTmp = 0; nTmp < aLines.Count(); ++nTmp )	\
203 			::_CheckBoxWidth( *aLines[ nTmp ], nSize );			\
204 	}
205 
206 #define CHECKTABLELAYOUT                                            \
207     {                                                               \
208         for ( sal_uInt16 i = 0; i < GetTabLines().Count(); ++i )        \
209         {                                                           \
210             SwFrmFmt* pFmt = GetTabLines()[i]->GetFrmFmt();  \
211             SwIterator<SwRowFrm,SwFmt> aIter( *pFmt );              \
212             for (SwRowFrm* pFrm=aIter.First(); pFrm; pFrm=aIter.Next())\
213             {                                                       \
214                 if ( pFrm->GetTabLine() == GetTabLines()[i] )       \
215                     {                                               \
216                         ASSERT( pFrm->GetUpper()->IsTabFrm(),       \
217                                 "Table layout does not match table structure" )       \
218                     }                                               \
219             }                                                       \
220         }                                                           \
221     }
222 
223 #else
224 
225 #define CHECKBOXWIDTH
226 #define CHECKTABLELAYOUT
227 
228 #endif
229 
230 
231 struct CR_SetLineHeight
232 {
233 	SwSelBoxes aBoxes;
234 	SwShareBoxFmts aShareFmts;
235 	SwTableNode* pTblNd;
236 	SwUndoTblNdsChg* pUndo;
237 	SwTwips nMaxSpace, nMaxHeight;
238 	TblChgMode nMode;
239     sal_uInt16 nLines;
240 	sal_Bool bBigger, bTop, bSplittBox, bAnyBoxFnd;
241 
CR_SetLineHeightCR_SetLineHeight242 	CR_SetLineHeight( sal_uInt16 eType, SwTableNode* pTNd )
243 		: pTblNd( pTNd ), pUndo( 0 ),
244         nMaxSpace( 0 ), nMaxHeight( 0 ), nLines( 0 ),
245 		bSplittBox( sal_False ), bAnyBoxFnd( sal_False )
246 	{
247 		bTop = nsTblChgWidthHeightType::WH_ROW_TOP == ( eType & 0xff ) || nsTblChgWidthHeightType::WH_CELL_TOP == ( eType & 0xff );
248 		bBigger = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_BIGGER );
249 		if( eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL )
250 			bBigger = !bBigger;
251         nMode = pTblNd->GetTable().GetTblChgMode();
252 	}
CR_SetLineHeightCR_SetLineHeight253 	CR_SetLineHeight( const CR_SetLineHeight& rCpy )
254 		: pTblNd( rCpy.pTblNd ), pUndo( rCpy.pUndo ),
255         nMaxSpace( rCpy.nMaxSpace ), nMaxHeight( rCpy.nMaxHeight ),
256 		nMode( rCpy.nMode ), nLines( rCpy.nLines ),
257         bBigger( rCpy.bBigger ), bTop( rCpy.bTop ),
258 		bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd )
259 	{}
260 
CreateUndoCR_SetLineHeight261     SwUndoTblNdsChg* CreateUndo( SwUndoId nUndoType )
262 	{
263 		return pUndo = new SwUndoTblNdsChg( nUndoType, aBoxes, *pTblNd );
264 	}
265 };
266 
267 sal_Bool lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
268 						 SwTwips nDist, sal_Bool bCheck );
269 sal_Bool lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
270 								SwTwips nDist, sal_Bool bCheck );
271 sal_Bool lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam,
272 								SwTwips nDist, sal_Bool bCheck );
273 
274 typedef sal_Bool (*FN_lcl_SetLineHeight)(SwTableLine*, CR_SetLineHeight&, SwTwips, sal_Bool );
275 
operator =(const _CpyTabFrm & rCpyTabFrm)276 _CpyTabFrm& _CpyTabFrm::operator=( const _CpyTabFrm& rCpyTabFrm )
277 {
278 	pNewFrmFmt = rCpyTabFrm.pNewFrmFmt;
279 	Value = rCpyTabFrm.Value;
280 	return *this;
281 }
282 
283 SV_DECL_VARARR_SORT( _CpyTabFrms, _CpyTabFrm, 0, 50 )
284 SV_IMPL_VARARR_SORT( _CpyTabFrms, _CpyTabFrm )
285 
286 void lcl_DelCpyTabFrmFmts( _CpyTabFrm& rArr );
287 
288 // ---------------------------------------------------------------
289 
290 struct _CpyPara
291 {
292     boost::shared_ptr< std::vector< std::vector< sal_uLong > > > pWidths;
293 	SwDoc* pDoc;
294 	SwTableNode* pTblNd;
295 	_CpyTabFrms& rTabFrmArr;
296 	SwTableLine* pInsLine;
297 	SwTableBox* pInsBox;
298 	sal_uLong nOldSize, nNewSize;			// zum Korrigieren der Size-Attribute
299     sal_uLong nMinLeft, nMaxRight;
300 	sal_uInt16 nCpyCnt, nInsPos;
301     sal_uInt16 nLnIdx, nBoxIdx;
302 	sal_uInt8 nDelBorderFlag;
303 	sal_Bool bCpyCntnt;
304 
_CpyPara_CpyPara305 	_CpyPara( SwTableNode* pNd, sal_uInt16 nCopies, _CpyTabFrms& rFrmArr,
306 			  sal_Bool bCopyContent = sal_True )
307 		: pDoc( pNd->GetDoc() ), pTblNd( pNd ), rTabFrmArr(rFrmArr),
308 		pInsLine(0), pInsBox(0), nOldSize(0), nNewSize(0),
309         nMinLeft(ULONG_MAX), nMaxRight(0),
310         nCpyCnt(nCopies), nInsPos(0),
311         nLnIdx(0), nBoxIdx(0),
312         nDelBorderFlag(0), bCpyCntnt( bCopyContent )
313 		{}
_CpyPara_CpyPara314 	_CpyPara( const _CpyPara& rPara, SwTableLine* pLine )
315 		: pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTblNd(rPara.pTblNd),
316 		rTabFrmArr(rPara.rTabFrmArr), pInsLine(pLine), pInsBox(rPara.pInsBox),
317         nOldSize(0), nNewSize(rPara.nNewSize), nMinLeft( rPara.nMinLeft ),
318         nMaxRight( rPara.nMaxRight ), nCpyCnt(rPara.nCpyCnt), nInsPos(0),
319         nLnIdx( rPara.nLnIdx), nBoxIdx( rPara.nBoxIdx ),
320 		nDelBorderFlag( rPara.nDelBorderFlag ), bCpyCntnt( rPara.bCpyCntnt )
321 		{}
_CpyPara_CpyPara322 	_CpyPara( const _CpyPara& rPara, SwTableBox* pBox )
323 		: pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTblNd(rPara.pTblNd),
324 		rTabFrmArr(rPara.rTabFrmArr), pInsLine(rPara.pInsLine), pInsBox(pBox),
325         nOldSize(rPara.nOldSize), nNewSize(rPara.nNewSize),
326         nMinLeft( rPara.nMinLeft ), nMaxRight( rPara.nMaxRight ),
327         nCpyCnt(rPara.nCpyCnt), nInsPos(0), nLnIdx(rPara.nLnIdx), nBoxIdx(rPara.nBoxIdx),
328 		nDelBorderFlag( rPara.nDelBorderFlag ), bCpyCntnt( rPara.bCpyCntnt )
329 		{}
330 	void SetBoxWidth( SwTableBox* pBox );
331 };
332 
333 
lcl_CopyCol(const _FndBox * & rpFndBox,void * pPara)334 sal_Bool lcl_CopyCol( const _FndBox*& rpFndBox, void* pPara )
335 {
336 	_CpyPara* pCpyPara = (_CpyPara*)pPara;
337 
338 	// suche das FrmFmt im Array aller Frame-Formate
339 	SwTableBox* pBox = (SwTableBox*)rpFndBox->GetBox();
340 	_CpyTabFrm aFindFrm( (SwTableBoxFmt*)pBox->GetFrmFmt() );
341 
342 	sal_uInt16 nFndPos;
343 	if( pCpyPara->nCpyCnt )
344 	{
345 		if( !pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos ))
346 		{
347 			// fuer das verschachtelte Kopieren sicher auch das neue Format
348 			// als alt.
349 			SwTableBoxFmt* pNewFmt = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
350 
351 			// suche die selektierten Boxen in der Line:
352 			_FndLine* pCmpLine = NULL;
353 			SwFmtFrmSize aFrmSz( pNewFmt->GetFrmSize() );
354 
355 			bool bDiffCount = false;
356 			if( pBox->GetTabLines().Count() )
357 			{
358 				pCmpLine = rpFndBox->GetLines()[ 0 ];
359 				if ( pCmpLine->GetBoxes().Count() != pCmpLine->GetLine()->GetTabBoxes().Count() )
360 					bDiffCount = true;
361 			}
362 
363 			if( bDiffCount )
364 			{
365 				// die erste Line sollte reichen
366 				_FndBoxes& rFndBoxes = pCmpLine->GetBoxes();
367 				long nSz = 0;
368 				for( sal_uInt16 n = rFndBoxes.Count(); n; )
369 					nSz += rFndBoxes[ --n ]->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth();
370 				aFrmSz.SetWidth( aFrmSz.GetWidth() -
371 											nSz / ( pCpyPara->nCpyCnt + 1 ) );
372                 pNewFmt->SetFmtAttr( aFrmSz );
373 				aFrmSz.SetWidth( nSz / ( pCpyPara->nCpyCnt + 1 ) );
374 
375 				// fuer die neue Box ein neues Format mit der Groesse anlegen!
376 				aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pNewFmt->GetDoc()->
377 											MakeTableLineFmt();
378 				*aFindFrm.pNewFrmFmt = *pNewFmt;
379                 aFindFrm.pNewFrmFmt->SetFmtAttr( aFrmSz );
380 			}
381 			else
382 			{
383 				aFrmSz.SetWidth( aFrmSz.GetWidth() / ( pCpyPara->nCpyCnt + 1 ) );
384                 pNewFmt->SetFmtAttr( aFrmSz );
385 
386 				aFindFrm.pNewFrmFmt = pNewFmt;
387 				pCpyPara->rTabFrmArr.Insert( aFindFrm );
388 				aFindFrm.Value.pFrmFmt = pNewFmt;
389 				pCpyPara->rTabFrmArr.Insert( aFindFrm );
390 			}
391 		}
392 		else
393 		{
394 			aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ];
395 //			aFindFrm.pNewFrmFmt->Add( pBox );
396 			pBox->ChgFrmFmt( (SwTableBoxFmt*)aFindFrm.pNewFrmFmt );
397 		}
398 	}
399 	else
400 	{
401 		if( pCpyPara->nDelBorderFlag &&
402 			pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos ))
403 			aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ];
404 		else
405 			aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
406 	}
407 
408 	if( rpFndBox->GetLines().Count() )
409 	{
410 		pBox = new SwTableBox( aFindFrm.pNewFrmFmt,
411 					rpFndBox->GetLines().Count(), pCpyPara->pInsLine );
412 		pCpyPara->pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, pCpyPara->nInsPos++);
413 		_CpyPara aPara( *pCpyPara, pBox );
414 		aPara.nDelBorderFlag &= 7;
415 
416 		((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CopyRow, &aPara );
417 	}
418 	else
419 	{
420 		::_InsTblBox( pCpyPara->pDoc, pCpyPara->pTblNd, pCpyPara->pInsLine,
421 					aFindFrm.pNewFrmFmt, pBox, pCpyPara->nInsPos++ );
422 
423 		const _FndBoxes& rFndBxs = rpFndBox->GetUpper()->GetBoxes();
424 		if( 8 > pCpyPara->nDelBorderFlag
425 				? pCpyPara->nDelBorderFlag
426 				: rpFndBox == rFndBxs[ rFndBxs.Count() - 1 ] )
427 		{
428 			const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
429 			if( 8 > pCpyPara->nDelBorderFlag
430 					? rBoxItem.GetTop()
431 					: rBoxItem.GetRight() )
432 			{
433 				aFindFrm.Value.pFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
434 
435 				SvxBoxItem aNew( rBoxItem );
436 				if( 8 > pCpyPara->nDelBorderFlag )
437 					aNew.SetLine( 0, BOX_LINE_TOP );
438 				else
439 					aNew.SetLine( 0, BOX_LINE_RIGHT );
440 
441 				if( 1 == pCpyPara->nDelBorderFlag ||
442 					8 == pCpyPara->nDelBorderFlag )
443 				{
444 					// es wird dahinter kopiert, bei allen Boxen die
445 					// TopBorderLine loeschen
446 					pBox = pCpyPara->pInsLine->GetTabBoxes()[
447 											pCpyPara->nInsPos - 1 ];
448 				}
449 
450 				aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
451 
452 				// ansonsten wird davor kopiert und die erste Line behaelt
453 				// die TopLine und an der originalen wird sie entfernt
454                 pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
455 
456 				if( !pCpyPara->nCpyCnt )
457 					pCpyPara->rTabFrmArr.Insert( aFindFrm );
458 			}
459 		}
460 	}
461 	return sal_True;
462 }
463 
lcl_CopyRow(const _FndLine * & rpFndLine,void * pPara)464 sal_Bool lcl_CopyRow( const _FndLine*& rpFndLine, void* pPara )
465 {
466 	_CpyPara* pCpyPara = (_CpyPara*)pPara;
467 	SwTableLine* pNewLine = new SwTableLine(
468 							(SwTableLineFmt*)rpFndLine->GetLine()->GetFrmFmt(),
469 						rpFndLine->GetBoxes().Count(), pCpyPara->pInsBox );
470 	if( pCpyPara->pInsBox )
471 	{
472 		pCpyPara->pInsBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, pCpyPara->nInsPos++ );
473 	}
474 	else
475 	{
476 		pCpyPara->pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pNewLine,
477 												pCpyPara->nInsPos++ );
478 	}
479 
480 	_CpyPara aPara( *pCpyPara, pNewLine );
481 	((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CopyCol, &aPara );
482 
483 	pCpyPara->nDelBorderFlag &= 0xf8;
484 	return sal_True;
485 }
486 
487 //-----------------------------------------------------------
488 
lcl_InsCol(_FndLine * pFndLn,_CpyPara & rCpyPara,sal_uInt16 nCpyCnt,sal_Bool bBehind)489 void lcl_InsCol( _FndLine* pFndLn, _CpyPara& rCpyPara, sal_uInt16 nCpyCnt,
490 				sal_Bool bBehind )
491 {
492 	// Bug 29124: nicht nur in den Grundlines kopieren. Wenns geht, so weit
493 	//				runter wie moeglich.
494 	_FndBox* pFBox;
495 	if( 1 == pFndLn->GetBoxes().Count() &&
496 		!( pFBox = pFndLn->GetBoxes()[ 0 ] )->GetBox()->GetSttNd() )
497 	{
498 		// eine Box mit mehreren Lines, also in diese Lines einfuegen
499 		for( sal_uInt16 n = 0; n < pFBox->GetLines().Count(); ++n )
500 			lcl_InsCol( pFBox->GetLines()[ n ], rCpyPara, nCpyCnt, bBehind );
501 	}
502 	else
503 	{
504 		rCpyPara.pInsLine = pFndLn->GetLine();
505 		SwTableBox* pBox = pFndLn->GetBoxes()[ bBehind ?
506 					pFndLn->GetBoxes().Count()-1 : 0 ]->GetBox();
507 		rCpyPara.nInsPos = pFndLn->GetLine()->GetTabBoxes().C40_GETPOS( SwTableBox, pBox );
508         if( bBehind )
509 			++rCpyPara.nInsPos;
510 
511 		for( sal_uInt16 n = 0; n < nCpyCnt; ++n )
512 		{
513 			if( n + 1 == nCpyCnt && bBehind )
514 				rCpyPara.nDelBorderFlag = 9;
515 			else
516 				rCpyPara.nDelBorderFlag = 8;
517 			pFndLn->GetBoxes().ForEach( &lcl_CopyCol, &rCpyPara );
518 		}
519 	}
520 }
521 
GetRowFrm(SwTableLine & rLine)522 SwRowFrm* GetRowFrm( SwTableLine& rLine )
523 {
524     SwIterator<SwRowFrm,SwFmt> aIter( *rLine.GetFrmFmt() );
525     for( SwRowFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
526         if( pFrm->GetTabLine() == &rLine )
527             return pFrm;
528     return 0;
529 }
530 
531 
InsertCol(SwDoc * pDoc,const SwSelBoxes & rBoxes,sal_uInt16 nCnt,sal_Bool bBehind)532 sal_Bool SwTable::InsertCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind )
533 {
534     ASSERT( rBoxes.Count() && nCnt, "keine gueltige Box-Liste" );
535 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
536 	if( !pTblNd )
537 		return sal_False;
538 
539 	sal_Bool bRes = sal_True;
540     if( IsNewModel() )
541         bRes = NewInsertCol( pDoc, rBoxes, nCnt, bBehind );
542 	else
543 	{
544 		// suche alle Boxen / Lines
545 		_FndBox aFndBox( 0, 0 );
546 		{
547 			_FndPara aPara( rBoxes, &aFndBox );
548 			GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
549 		}
550 		if( !aFndBox.GetLines().Count() )
551 			return sal_False;
552 
553 		SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
554 
555 		//Lines fuer das Layout-Update herausuchen.
556 		aFndBox.SetTableLines( *this );
557 		aFndBox.DelFrms( *this );
558 
559 		// TL_CHART2: nothing to be done since chart2 currently does not want to
560 		// get notified about new rows/cols.
561 
562 		_CpyTabFrms aTabFrmArr;
563 		_CpyPara aCpyPara( pTblNd, nCnt, aTabFrmArr );
564 
565 		for( sal_uInt16 n = 0; n < aFndBox.GetLines().Count(); ++n )
566 			lcl_InsCol( aFndBox.GetLines()[ n ], aCpyPara, nCnt, bBehind );
567 
568 		// dann raeume die Struktur dieser Line noch mal auf, generell alle
569 		GCLines();
570 
571 		//Layout updaten
572 		aFndBox.MakeFrms( *this );
573 
574 		CHECKBOXWIDTH
575 		CHECKTABLELAYOUT
576 		bRes = sal_True;
577 	}
578 
579 	SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
580 	if (pPCD && nCnt)
581 		pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
582     pDoc->UpdateCharts( GetFrmFmt()->GetName() );
583 
584 	return bRes;
585 }
586 
_InsertRow(SwDoc * pDoc,const SwSelBoxes & rBoxes,sal_uInt16 nCnt,sal_Bool bBehind)587 sal_Bool SwTable::_InsertRow( SwDoc* pDoc, const SwSelBoxes& rBoxes,
588 						sal_uInt16 nCnt, sal_Bool bBehind )
589 {
590 	ASSERT( pDoc && rBoxes.Count() && nCnt, "keine gueltige Box-Liste" );
591 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
592 	if( !pTblNd )
593 		return sal_False;
594 
595 	// suche alle Boxen / Lines
596 	_FndBox aFndBox( 0, 0 );
597 	{
598 		_FndPara aPara( rBoxes, &aFndBox );
599 		GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
600 	}
601 	if( !aFndBox.GetLines().Count() )
602 		return sal_False;
603 
604 	SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
605 
606 	_FndBox* pFndBox = &aFndBox;
607 	{
608 		_FndLine* pFndLine;
609 		while( 1 == pFndBox->GetLines().Count() &&
610 				1 == ( pFndLine = pFndBox->GetLines()[ 0 ])->GetBoxes().Count() )
611 		{
612 			// nicht zu weit runter, eine Line mit Boxen muss nachbleiben!!
613 			_FndBox* pTmpBox = pFndLine->GetBoxes()[ 0 ];
614 			if( pTmpBox->GetLines().Count() )
615 				pFndBox = pTmpBox;
616 			else
617 				break;
618 		}
619 	}
620 
621 	//Lines fuer das Layout-Update herausuchen.
622 	const sal_Bool bLayout = !IsNewModel() &&
623         0 != SwIterator<SwTabFrm,SwFmt>::FirstElement( *GetFrmFmt() );
624 
625     if ( bLayout )
626 	{
627 		aFndBox.SetTableLines( *this );
628 		if( pFndBox != &aFndBox )
629 			aFndBox.DelFrms( *this );
630 		// TL_CHART2: nothing to be done since chart2 currently does not want to
631 		// get notified about new rows/cols.
632 	}
633 
634 	_CpyTabFrms aTabFrmArr;
635 	_CpyPara aCpyPara( pTblNd, 0, aTabFrmArr );
636 
637 	SwTableLine* pLine = pFndBox->GetLines()[ bBehind ?
638 					pFndBox->GetLines().Count()-1 : 0 ]->GetLine();
639 	if( &aFndBox == pFndBox )
640 		aCpyPara.nInsPos = GetTabLines().C40_GETPOS( SwTableLine, pLine );
641 	else
642 	{
643 		aCpyPara.pInsBox = pFndBox->GetBox();
644 		aCpyPara.nInsPos = pFndBox->GetBox()->GetTabLines().C40_GETPOS( SwTableLine, pLine );
645 	}
646 
647     if( bBehind )
648 	{
649 		++aCpyPara.nInsPos;
650 		aCpyPara.nDelBorderFlag = 1;
651 	}
652 	else
653 		aCpyPara.nDelBorderFlag = 2;
654 
655 	for( sal_uInt16 nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt )
656 	{
657 		if( bBehind )
658 			aCpyPara.nDelBorderFlag = 1;
659 		pFndBox->GetLines().ForEach( &lcl_CopyRow, &aCpyPara );
660 	}
661 
662 	// dann raeume die Struktur dieser Line noch mal auf, generell alle
663 	if( !pDoc->IsInReading() )
664 		GCLines();
665 
666 	//Layout updaten
667 	if ( bLayout )
668 	{
669 		if( pFndBox != &aFndBox )
670 			aFndBox.MakeFrms( *this );
671 		else
672 			aFndBox.MakeNewFrms( *this, nCnt, bBehind );
673 	}
674 
675 	CHECKBOXWIDTH
676     CHECKTABLELAYOUT
677 
678 	SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
679 	if (pPCD && nCnt)
680 		pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
681     pDoc->UpdateCharts( GetFrmFmt()->GetName() );
682 
683 	return sal_True;
684 }
685 
686 sal_Bool _FndBoxAppendRowLine( const SwTableLine*& rpLine, void* pPara );
687 
_FndBoxAppendRowBox(const SwTableBox * & rpBox,void * pPara)688 sal_Bool _FndBoxAppendRowBox( const SwTableBox*& rpBox, void* pPara )
689 {
690 	_FndPara* pFndPara = (_FndPara*)pPara;
691 	_FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine );
692 	if( rpBox->GetTabLines().Count() )
693 	{
694 		_FndPara aPara( *pFndPara, pFndBox );
695 		pFndBox->GetBox()->GetTabLines().ForEach( &_FndBoxAppendRowLine, &aPara );
696 		if( !pFndBox->GetLines().Count() )
697 			delete pFndBox;
698 	}
699 	else
700 		pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox,
701 						pFndPara->pFndLine->GetBoxes().Count() );
702 	return sal_True;
703 }
704 
_FndBoxAppendRowLine(const SwTableLine * & rpLine,void * pPara)705 sal_Bool _FndBoxAppendRowLine( const SwTableLine*& rpLine, void* pPara )
706 {
707 	_FndPara* pFndPara = (_FndPara*)pPara;
708 	_FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox );
709 	_FndPara aPara( *pFndPara, pFndLine );
710 	pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxAppendRowBox, &aPara );
711 	if( pFndLine->GetBoxes().Count() )
712 	{
713 		pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine,
714 				pFndPara->pFndBox->GetLines().Count() );
715 	}
716 	else
717 		delete pFndLine;
718 	return sal_True;
719 }
720 
721 
AppendRow(SwDoc * pDoc,sal_uInt16 nCnt)722 sal_Bool SwTable::AppendRow( SwDoc* pDoc, sal_uInt16 nCnt )
723 {
724 	SwTableNode* pTblNd = (SwTableNode*)aSortCntBoxes[0]->GetSttNd()->FindTableNode();
725 	if( !pTblNd )
726 		return sal_False;
727 
728 	// suche alle Boxen / Lines
729 	_FndBox aFndBox( 0, 0 );
730 	{
731 		const SwTableLine* pLLine = GetTabLines()[ GetTabLines().Count()-1 ];
732 
733 		const SwSelBoxes* pBxs = 0;		// Dummy !!!
734 		_FndPara aPara( *pBxs, &aFndBox );
735 
736 		_FndBoxAppendRowLine( pLLine, &aPara );
737 	}
738 	if( !aFndBox.GetLines().Count() )
739 		return sal_False;
740 
741 	SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
742 
743 	//Lines fuer das Layout-Update herausuchen.
744 	bool bLayout = 0 != SwIterator<SwTabFrm,SwFmt>::FirstElement( *GetFrmFmt() );
745 	if( bLayout )
746 	{
747 		aFndBox.SetTableLines( *this );
748 		// TL_CHART2: nothing to be done since chart2 currently does not want to
749 		// get notified about new rows/cols.
750 	}
751 
752 	_CpyTabFrms aTabFrmArr;
753 	_CpyPara aCpyPara( pTblNd, 0, aTabFrmArr );
754 	aCpyPara.nInsPos = GetTabLines().Count();
755 	aCpyPara.nDelBorderFlag = 1;
756 
757 	for( sal_uInt16 nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt )
758 	{
759 		aCpyPara.nDelBorderFlag = 1;
760 		aFndBox.GetLines().ForEach( &lcl_CopyRow, &aCpyPara );
761 	}
762 
763 	// dann raeume die Struktur dieser Line noch mal auf, generell alle
764 	if( !pDoc->IsInReading() )
765 		GCLines();
766 
767 	//Layout updaten
768 	if ( bLayout )
769 	{
770 		aFndBox.MakeNewFrms( *this, nCnt, sal_True );
771 	}
772 	// TL_CHART2: need to inform chart of probably changed cell names
773     pDoc->UpdateCharts( GetFrmFmt()->GetName() );
774 
775 	CHECKBOXWIDTH
776     CHECKTABLELAYOUT
777 
778 	return sal_True;
779 }
780 
781 
782 void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset,
783 							sal_Bool bFirst, SwShareBoxFmts& rShareFmts );
784 
lcl_LastBoxSetWidthLine(SwTableLines & rLines,const long nOffset,sal_Bool bFirst,SwShareBoxFmts & rShareFmts)785 void lcl_LastBoxSetWidthLine( SwTableLines &rLines, const long nOffset,
786 								sal_Bool bFirst, SwShareBoxFmts& rShareFmts )
787 {
788 	for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
789 		::lcl_LastBoxSetWidth( rLines[i]->GetTabBoxes(), nOffset, bFirst,
790 								rShareFmts );
791 }
792 
lcl_LastBoxSetWidth(SwTableBoxes & rBoxes,const long nOffset,sal_Bool bFirst,SwShareBoxFmts & rShareFmts)793 void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset,
794 							sal_Bool bFirst, SwShareBoxFmts& rShareFmts )
795 {
796 	SwTableBox& rBox = *rBoxes[ bFirst ? 0 : rBoxes.Count() - 1 ];
797 	if( !rBox.GetSttNd() )
798 		::lcl_LastBoxSetWidthLine( rBox.GetTabLines(), nOffset,
799 									bFirst, rShareFmts );
800 
801 	//Die Box anpassen
802 	SwFrmFmt *pBoxFmt = rBox.GetFrmFmt();
803 	SwFmtFrmSize aNew( pBoxFmt->GetFrmSize() );
804 	aNew.SetWidth( aNew.GetWidth() + nOffset );
805 	SwFrmFmt *pFmt = rShareFmts.GetFormat( *pBoxFmt, aNew );
806 	if( pFmt )
807 		rBox.ChgFrmFmt( (SwTableBoxFmt*)pFmt );
808 	else
809 	{
810 		pFmt = rBox.ClaimFrmFmt();
811 
812 		pFmt->LockModify();
813         pFmt->SetFmtAttr( aNew );
814 		pFmt->UnlockModify();
815 
816 		rShareFmts.AddFormat( *pBoxFmt, *pFmt );
817 	}
818 }
819 
_DeleteBox(SwTable & rTbl,SwTableBox * pBox,SwUndo * pUndo,sal_Bool bCalcNewSize,const sal_Bool bCorrBorder,SwShareBoxFmts * pShareFmts)820 void _DeleteBox( SwTable& rTbl, SwTableBox* pBox, SwUndo* pUndo,
821 				sal_Bool bCalcNewSize, const sal_Bool bCorrBorder,
822 				SwShareBoxFmts* pShareFmts )
823 {
824 	do {
825 		SwTwips nBoxSz = bCalcNewSize ?
826 				pBox->GetFrmFmt()->GetFrmSize().GetWidth() : 0;
827 		SwTableLine* pLine = pBox->GetUpper();
828 		SwTableBoxes& rTblBoxes = pLine->GetTabBoxes();
829 		sal_uInt16 nDelPos = rTblBoxes.C40_GETPOS( SwTableBox, pBox );
830 		SwTableBox* pUpperBox = pBox->GetUpper()->GetUpper();
831 
832 		// Sonderbehandlung fuer Umrandung:
833 		if( bCorrBorder && 1 < rTblBoxes.Count() )
834 		{
835 			sal_Bool bChgd = sal_False;
836 			const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
837 
838 			if( rBoxItem.GetLeft() || rBoxItem.GetRight() )
839 			{
840 				//JP 02.04.97:  1.Teil fuer Bug 36271
841 				// zuerst die linken/rechten Kanten
842 				if( nDelPos + 1 < rTblBoxes.Count() )
843 				{
844 					SwTableBox* pNxtBox = rTblBoxes[ nDelPos + 1 ];
845 					const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrmFmt()->GetBox();
846 
847 					SwTableBox* pPrvBox = nDelPos ? rTblBoxes[ nDelPos - 1 ] : 0;
848 
849 					if( pNxtBox->GetSttNd() && !rNxtBoxItem.GetLeft() &&
850 						( !pPrvBox || !pPrvBox->GetFrmFmt()->GetBox().GetRight()) )
851 					{
852 						SvxBoxItem aTmp( rNxtBoxItem );
853 						aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
854 														 : rBoxItem.GetRight(),
855 															BOX_LINE_LEFT );
856 						if( pShareFmts )
857                             pShareFmts->SetAttr( *pNxtBox, aTmp );
858 						else
859                             pNxtBox->ClaimFrmFmt()->SetFmtAttr( aTmp );
860 						bChgd = sal_True;
861 					}
862 				}
863 				if( !bChgd && nDelPos )
864 				{
865 					SwTableBox* pPrvBox = rTblBoxes[ nDelPos - 1 ];
866 					const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrmFmt()->GetBox();
867 
868 					SwTableBox* pNxtBox = nDelPos + 1 < rTblBoxes.Count()
869 											? rTblBoxes[ nDelPos + 1 ] : 0;
870 
871 					if( pPrvBox->GetSttNd() && !rPrvBoxItem.GetRight() &&
872 						( !pNxtBox || !pNxtBox->GetFrmFmt()->GetBox().GetLeft()) )
873 					{
874 						SvxBoxItem aTmp( rPrvBoxItem );
875 						aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
876 														 : rBoxItem.GetRight(),
877 															BOX_LINE_RIGHT );
878 						if( pShareFmts )
879                             pShareFmts->SetAttr( *pPrvBox, aTmp );
880 						else
881                             pPrvBox->ClaimFrmFmt()->SetFmtAttr( aTmp );
882 					}
883 				}
884 			}
885 
886 		}
887 
888 		// erst die Box, dann die Nodes loeschen!!
889 		SwStartNode* pSttNd = (SwStartNode*)pBox->GetSttNd();
890 		if( pShareFmts )
891 			pShareFmts->RemoveFormat( *rTblBoxes[ nDelPos ]->GetFrmFmt() );
892 		rTblBoxes.DeleteAndDestroy( nDelPos );
893 
894 		if( pSttNd )
895 		{
896 			// ist das UndoObject zum speichern der Section vorbereitet?
897 			if( pUndo && pUndo->IsDelBox() )
898 				((SwUndoTblNdsChg*)pUndo)->SaveSection( pSttNd );
899 			else
900 				pSttNd->GetDoc()->DeleteSection( pSttNd );
901 		}
902 
903 		// auch die Zeile noch loeschen ??
904 		if( rTblBoxes.Count() )
905 		{
906 			// dann passe noch die Frame-SSize an
907 			sal_Bool bLastBox = nDelPos == rTblBoxes.Count();
908 			if( bLastBox )
909 				--nDelPos;
910 			pBox = rTblBoxes[nDelPos];
911 			if( bCalcNewSize )
912 			{
913 				SwFmtFrmSize aNew( pBox->GetFrmFmt()->GetFrmSize() );
914 				aNew.SetWidth( aNew.GetWidth() + nBoxSz );
915 				if( pShareFmts )
916 					pShareFmts->SetSize( *pBox, aNew );
917 				else
918                     pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
919 
920 				if( !pBox->GetSttNd() )
921 				{
922 					// dann muss es auch rekursiv in allen Zeilen, in allen
923 					// Zellen erfolgen!
924 					SwShareBoxFmts aShareFmts;
925 					::lcl_LastBoxSetWidthLine( pBox->GetTabLines(), nBoxSz,
926 												!bLastBox,
927 												pShareFmts ? *pShareFmts
928 														   : aShareFmts	);
929 				}
930 			}
931 			break;		// nichts mehr loeschen
932 		}
933 		// loesche die Line aus Tabelle/Box
934 		if( !pUpperBox )
935 		{
936 			// dann loesche auch noch die Line aus der Tabelle
937 			nDelPos = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
938 			if( pShareFmts )
939 				pShareFmts->RemoveFormat( *rTbl.GetTabLines()[ nDelPos ]->GetFrmFmt() );
940 			rTbl.GetTabLines().DeleteAndDestroy( nDelPos );
941 			break;  	// mehr kann nicht geloescht werden
942 		}
943 
944 		// dann loesche auch noch die Line
945 		pBox = pUpperBox;
946 		nDelPos = pBox->GetTabLines().C40_GETPOS( SwTableLine, pLine );
947 		if( pShareFmts )
948 			pShareFmts->RemoveFormat( *pBox->GetTabLines()[ nDelPos ]->GetFrmFmt() );
949 		pBox->GetTabLines().DeleteAndDestroy( nDelPos );
950 	} while( !pBox->GetTabLines().Count() );
951 }
952 
lcl_FndNxtPrvDelBox(const SwTableLines & rTblLns,SwTwips nBoxStt,SwTwips nBoxWidth,sal_uInt16 nLinePos,sal_Bool bNxt,SwSelBoxes * pAllDelBoxes,sal_uInt16 * pCurPos)953 SwTableBox* lcl_FndNxtPrvDelBox( const SwTableLines& rTblLns,
954 								SwTwips nBoxStt, SwTwips nBoxWidth,
955 								sal_uInt16 nLinePos, sal_Bool bNxt,
956 								SwSelBoxes* pAllDelBoxes, sal_uInt16* pCurPos )
957 {
958 	SwTableBox* pFndBox = 0;
959 	do {
960 		if( bNxt )
961 			++nLinePos;
962 		else
963 			--nLinePos;
964 		SwTableLine* pLine = rTblLns[ nLinePos ];
965         SwTwips nFndBoxWidth = 0;
966         SwTwips nFndWidth = nBoxStt + nBoxWidth;
967 		sal_uInt16 nBoxCnt = pLine->GetTabBoxes().Count();
968 
969         pFndBox = pLine->GetTabBoxes()[ 0 ];
970 		for( sal_uInt16 n = 0; 0 < nFndWidth && n < nBoxCnt; ++n )
971 		{
972 			pFndBox = pLine->GetTabBoxes()[ n ];
973 			nFndWidth -= (nFndBoxWidth = pFndBox->GetFrmFmt()->
974 										GetFrmSize().GetWidth());
975 		}
976 
977 		// suche die erste ContentBox
978 		while( !pFndBox->GetSttNd() )
979 		{
980 			const SwTableLines& rLowLns = pFndBox->GetTabLines();
981 			if( bNxt )
982 				pFndBox = rLowLns[ 0 ]->GetTabBoxes()[ 0 ];
983 			else
984 				pFndBox = rLowLns[ rLowLns.Count() - 1 ]->GetTabBoxes()[ 0 ];
985 		}
986 
987 		if( Abs( nFndWidth ) > COLFUZZY ||
988 			Abs( nBoxWidth - nFndBoxWidth ) > COLFUZZY )
989 			pFndBox = 0;
990 		else if( pAllDelBoxes )
991 		{
992 			// falls der Vorganger auch geloscht wird, ist nicht zu tun
993 			sal_uInt16 nFndPos;
994 			if( !pAllDelBoxes->Seek_Entry( pFndBox, &nFndPos ) )
995 				break;
996 
997 			// sonst noch mal weitersuchen
998 			// Die Box muessen wir aber nicht nochmal abpruefen
999 			pFndBox = 0;
1000 			if( nFndPos <= *pCurPos )
1001 				--*pCurPos;
1002 			pAllDelBoxes->Remove( nFndPos );
1003 		}
1004 	} while( bNxt ? ( nLinePos + 1 < rTblLns.Count() ) : nLinePos );
1005 	return pFndBox;
1006 }
1007 
lcl_SaveUpperLowerBorder(SwTable & rTbl,const SwTableBox & rBox,SwShareBoxFmts & rShareFmts,SwSelBoxes * pAllDelBoxes=0,sal_uInt16 * pCurPos=0)1008 void lcl_SaveUpperLowerBorder( SwTable& rTbl, const SwTableBox& rBox,
1009 								SwShareBoxFmts& rShareFmts,
1010 								SwSelBoxes* pAllDelBoxes = 0,
1011 								sal_uInt16* pCurPos = 0 )
1012 {
1013 //JP 16.04.97:  2.Teil fuer Bug 36271
1014 	sal_Bool bChgd = sal_False;
1015 	const SwTableLine* pLine = rBox.GetUpper();
1016 	const SwTableBoxes& rTblBoxes = pLine->GetTabBoxes();
1017 	const SwTableBox* pUpperBox = &rBox;
1018 	sal_uInt16 nDelPos = rTblBoxes.C40_GETPOS( SwTableBox, pUpperBox );
1019 	pUpperBox = rBox.GetUpper()->GetUpper();
1020 	const SvxBoxItem& rBoxItem = rBox.GetFrmFmt()->GetBox();
1021 
1022 	// dann die unteren/oberen Kanten
1023 	if( rBoxItem.GetTop() || rBoxItem.GetBottom() )
1024 	{
1025 		bChgd = sal_False;
1026 		const SwTableLines* pTblLns;
1027 		if( pUpperBox )
1028 			pTblLns = &pUpperBox->GetTabLines();
1029 		else
1030 			pTblLns = &rTbl.GetTabLines();
1031 
1032 		sal_uInt16 nLnPos = pTblLns->GetPos( pLine );
1033 
1034 		// bestimme die Attr.Position der akt. zu loeschenden Box
1035 		// und suche dann in der unteren / oberen Line die entspr.
1036 		// Gegenstuecke
1037 		SwTwips nBoxStt = 0;
1038 		for( sal_uInt16 n = 0; n < nDelPos; ++n )
1039 			nBoxStt += rTblBoxes[ n ]->GetFrmFmt()->GetFrmSize().GetWidth();
1040 		SwTwips nBoxWidth = rBox.GetFrmFmt()->GetFrmSize().GetWidth();
1041 
1042 		SwTableBox *pPrvBox = 0, *pNxtBox = 0;
1043 		if( nLnPos )		// Vorgaenger?
1044 			pPrvBox = ::lcl_FndNxtPrvDelBox( *pTblLns, nBoxStt, nBoxWidth,
1045 								nLnPos, sal_False, pAllDelBoxes, pCurPos );
1046 
1047 		if( nLnPos + 1 < pTblLns->Count() )		// Nachfolger?
1048 			pNxtBox = ::lcl_FndNxtPrvDelBox( *pTblLns, nBoxStt, nBoxWidth,
1049 								nLnPos, sal_True, pAllDelBoxes, pCurPos );
1050 
1051 		if( pNxtBox && pNxtBox->GetSttNd() )
1052 		{
1053 			const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrmFmt()->GetBox();
1054 			if( !rNxtBoxItem.GetTop() && ( !pPrvBox ||
1055 				!pPrvBox->GetFrmFmt()->GetBox().GetBottom()) )
1056 			{
1057 				SvxBoxItem aTmp( rNxtBoxItem );
1058 				aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
1059 												: rBoxItem.GetBottom(),
1060 												BOX_LINE_TOP );
1061                 rShareFmts.SetAttr( *pNxtBox, aTmp );
1062 				bChgd = sal_True;
1063 			}
1064 		}
1065 		if( !bChgd && pPrvBox && pPrvBox->GetSttNd() )
1066 		{
1067 			const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrmFmt()->GetBox();
1068 			if( !rPrvBoxItem.GetTop() && ( !pNxtBox ||
1069 				!pNxtBox->GetFrmFmt()->GetBox().GetTop()) )
1070 			{
1071 				SvxBoxItem aTmp( rPrvBoxItem );
1072 				aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
1073 												: rBoxItem.GetBottom(),
1074 												BOX_LINE_BOTTOM );
1075                 rShareFmts.SetAttr( *pPrvBox, aTmp );
1076 			}
1077 		}
1078 
1079 	}
1080 }
1081 
1082 
DeleteSel(SwDoc * pDoc,const SwSelBoxes & rBoxes,const SwSelBoxes * pMerged,SwUndo * pUndo,const sal_Bool bDelMakeFrms,const sal_Bool bCorrBorder)1083 sal_Bool SwTable::DeleteSel(
1084     SwDoc*     pDoc
1085     ,
1086     const SwSelBoxes& rBoxes,
1087     const SwSelBoxes* pMerged, SwUndo* pUndo,
1088 	const sal_Bool bDelMakeFrms, const sal_Bool bCorrBorder )
1089 {
1090     ASSERT( pDoc, "No doc?" );
1091     SwTableNode* pTblNd = 0;
1092     if( rBoxes.Count() )
1093     {
1094         pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1095         if( !pTblNd )
1096             return sal_False;
1097     }
1098 
1099 	SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
1100 
1101 	//Lines fuer das Layout-Update herausuchen.
1102 	_FndBox aFndBox( 0, 0 );
1103 	if ( bDelMakeFrms )
1104 	{
1105         if( pMerged && pMerged->Count() )
1106             aFndBox.SetTableLines( *pMerged, *this );
1107         else if( rBoxes.Count() )
1108             aFndBox.SetTableLines( rBoxes, *this );
1109         aFndBox.DelFrms( *this );
1110 	}
1111 
1112 	SwShareBoxFmts aShareFmts;
1113 
1114 	// erst die Umrandung umsetzen, dann loeschen
1115 	if( bCorrBorder )
1116 	{
1117 		SwSelBoxes aBoxes;
1118 		aBoxes.Insert( &rBoxes );
1119 		for( sal_uInt16 n = 0; n < aBoxes.Count(); ++n )
1120 			::lcl_SaveUpperLowerBorder( *this, *rBoxes[ n ], aShareFmts,
1121 										&aBoxes, &n );
1122 	}
1123 
1124     PrepareDelBoxes( rBoxes );
1125 
1126     SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
1127     //
1128     // delete boxes from last to first
1129     for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
1130     {
1131         sal_uInt16 nIdx = rBoxes.Count() - 1 - n;
1132 
1133         // first adapt the data-sequence for chart if necessary
1134         // (needed to move the implementation cursor properly to it's new
1135         // position which can't be done properly if the cell is already gone)
1136         if (pPCD && pTblNd)
1137             pPCD->DeleteBox( &pTblNd->GetTable(), *rBoxes[nIdx] );
1138 
1139         // ... then delete the boxes
1140         _DeleteBox( *this, rBoxes[nIdx], pUndo, sal_True, bCorrBorder, &aShareFmts );
1141     }
1142 
1143 	// dann raeume die Struktur aller Lines auf
1144 	GCLines();
1145 
1146 	if( bDelMakeFrms && aFndBox.AreLinesToRestore( *this ) )
1147 		aFndBox.MakeFrms( *this );
1148 
1149     // TL_CHART2: now inform chart that sth has changed
1150     pDoc->UpdateCharts( GetFrmFmt()->GetName() );
1151 
1152     CHECKTABLELAYOUT
1153     CHECK_TABLE( *this )
1154 
1155 	return sal_True;
1156 }
1157 
1158 
1159 // ---------------------------------------------------------------
1160 
OldSplitRow(SwDoc * pDoc,const SwSelBoxes & rBoxes,sal_uInt16 nCnt,sal_Bool bSameHeight)1161 sal_Bool SwTable::OldSplitRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt,
1162                         sal_Bool bSameHeight )
1163 {
1164 	ASSERT( pDoc && rBoxes.Count() && nCnt, "keine gueltigen Werte" );
1165 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1166 	if( !pTblNd )
1167 		return sal_False;
1168 
1169 	// TL_CHART2: splitting/merging of a number of cells or rows will usually make
1170 	// the table to complex to be handled with chart.
1171     // Thus we tell the charts to use their own data provider and forget about this table
1172     pDoc->CreateChartInternalDataProviders( this );
1173 
1174 	SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
1175 
1176     // If the rows should get the same (min) height, we first have
1177     // to store the old row heights before deleting the frames
1178     long* pRowHeights = 0;
1179     if ( bSameHeight )
1180     {
1181         pRowHeights = new long[ rBoxes.Count() ];
1182         for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
1183         {
1184             SwTableBox* pSelBox = *( rBoxes.GetData() + n );
1185             const SwRowFrm* pRow = GetRowFrm( *pSelBox->GetUpper() );
1186             ASSERT( pRow, "wo ist der Frm von der SwTableLine?" )
1187             SWRECTFN( pRow )
1188             pRowHeights[ n ] = (pRow->Frm().*fnRect->fnGetHeight)();
1189         }
1190     }
1191 
1192 	//Lines fuer das Layout-Update herausuchen.
1193 	_FndBox aFndBox( 0, 0 );
1194 	aFndBox.SetTableLines( rBoxes, *this );
1195 	aFndBox.DelFrms( *this );
1196 
1197     for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
1198 	{
1199 		SwTableBox* pSelBox = *( rBoxes.GetData() + n );
1200 		ASSERT( pSelBox, "Box steht nicht in der Tabelle" );
1201 
1202 		// dann fuege in die Box nCnt neue Zeilen ein
1203 		SwTableLine* pInsLine = pSelBox->GetUpper();
1204 		SwTableBoxFmt* pFrmFmt = (SwTableBoxFmt*)pSelBox->GetFrmFmt();
1205 
1206 		// Hoehe der Line beachten, gegebenenfalls neu setzen
1207         SwFmtFrmSize aFSz( pInsLine->GetFrmFmt()->GetFrmSize() );
1208         if ( bSameHeight && ATT_VAR_SIZE == aFSz.GetHeightSizeType() )
1209             aFSz.SetHeightSizeType( ATT_MIN_SIZE );
1210 
1211         sal_Bool bChgLineSz = 0 != aFSz.GetHeight() || bSameHeight;
1212         if ( bChgLineSz )
1213             aFSz.SetHeight( ( bSameHeight ? pRowHeights[ n ] : aFSz.GetHeight() ) /
1214                              (nCnt + 1) );
1215 
1216 		SwTableBox* pNewBox = new SwTableBox( pFrmFmt, nCnt, pInsLine );
1217 		sal_uInt16 nBoxPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSelBox );
1218 		pInsLine->GetTabBoxes().Remove( nBoxPos );	// alte loeschen
1219 		pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pNewBox, nBoxPos );
1220 
1221 		// Hintergrund- / Rand Attribut loeschen
1222 		SwTableBox* pLastBox = pSelBox; 		// zum verteilen der TextNodes !!
1223 		// sollte Bereiche in der Box stehen, dann bleibt sie so bestehen
1224 		// !! FALLS DAS GEAENDERT WIRD MUSS DAS UNDO ANGEPASST WERDEN !!!
1225 		sal_Bool bMoveNodes = sal_True;
1226 		{
1227 			sal_uLong nSttNd = pLastBox->GetSttIdx() + 1,
1228 					nEndNd = pLastBox->GetSttNd()->EndOfSectionIndex();
1229 			while( nSttNd < nEndNd )
1230 				if( !pDoc->GetNodes()[ nSttNd++ ]->IsTxtNode() )
1231 				{
1232 					bMoveNodes = sal_False;
1233 					break;
1234 				}
1235 		}
1236 
1237 		SwTableBoxFmt* pCpyBoxFrmFmt = (SwTableBoxFmt*)pSelBox->GetFrmFmt();
1238 		sal_Bool bChkBorder = 0 != pCpyBoxFrmFmt->GetBox().GetTop();
1239 		if( bChkBorder )
1240 			pCpyBoxFrmFmt = (SwTableBoxFmt*)pSelBox->ClaimFrmFmt();
1241 
1242 		for( sal_uInt16 i = 0; i <= nCnt; ++i )
1243 		{
1244 			// also erstmal eine neue Linie in der neuen Box
1245 			SwTableLine* pNewLine = new SwTableLine(
1246 					(SwTableLineFmt*)pInsLine->GetFrmFmt(), 1, pNewBox );
1247 			if( bChgLineSz )
1248 			{
1249                 pNewLine->ClaimFrmFmt()->SetFmtAttr( aFSz );
1250 			}
1251 
1252 			pNewBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, i );
1253 			// dann eine neue Box in der Line
1254 			if( !i ) 		// haenge die originale Box ein
1255 			{
1256 				pSelBox->SetUpper( pNewLine );
1257 				pNewLine->GetTabBoxes().C40_INSERT( SwTableBox, pSelBox, 0 );
1258 			}
1259 			else
1260 			{
1261 				::_InsTblBox( pDoc, pTblNd, pNewLine, pCpyBoxFrmFmt,
1262 								pLastBox, 0 );
1263 
1264 				if( bChkBorder )
1265 				{
1266 					pCpyBoxFrmFmt = (SwTableBoxFmt*)pNewLine->GetTabBoxes()[ 0 ]->ClaimFrmFmt();
1267 					SvxBoxItem aTmp( pCpyBoxFrmFmt->GetBox() );
1268 					aTmp.SetLine( 0, BOX_LINE_TOP );
1269                     pCpyBoxFrmFmt->SetFmtAttr( aTmp );
1270 					bChkBorder = sal_False;
1271 				}
1272 
1273 				if( bMoveNodes )
1274 				{
1275 					const SwNode* pEndNd = pLastBox->GetSttNd()->EndOfSectionNode();
1276 					if( pLastBox->GetSttIdx()+2 != pEndNd->GetIndex() )
1277 					{
1278 						// TextNodes verschieben
1279 						SwNodeRange aRg( *pLastBox->GetSttNd(), +2, *pEndNd );
1280 						pLastBox = pNewLine->GetTabBoxes()[0];	// neu setzen
1281 						SwNodeIndex aInsPos( *pLastBox->GetSttNd(), 1 );
1282 						pDoc->GetNodes()._MoveNodes(aRg, pDoc->GetNodes(), aInsPos, sal_False);
1283 						pDoc->GetNodes().Delete( aInsPos, 1 ); // den leeren noch loeschen
1284 					}
1285 				}
1286 			}
1287 		}
1288 		// in Boxen mit Lines darf es nur noch Size/Fillorder geben
1289 		pFrmFmt = (SwTableBoxFmt*)pNewBox->ClaimFrmFmt();
1290         pFrmFmt->ResetFmtAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
1291         pFrmFmt->ResetFmtAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
1292 	}
1293 
1294     delete[] pRowHeights;
1295 
1296 	GCLines();
1297 
1298     aFndBox.MakeFrms( *this );
1299 
1300 	CHECKBOXWIDTH
1301     CHECKTABLELAYOUT
1302     return sal_True;
1303 }
1304 
SplitCol(SwDoc * pDoc,const SwSelBoxes & rBoxes,sal_uInt16 nCnt)1305 sal_Bool SwTable::SplitCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt )
1306 {
1307 	ASSERT( pDoc && rBoxes.Count() && nCnt, "keine gueltigen Werte" );
1308 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1309 	if( !pTblNd )
1310 		return sal_False;
1311 
1312 	// TL_CHART2: splitting/merging of a number of cells or rows will usually make
1313 	// the table to complex to be handled with chart.
1314     // Thus we tell the charts to use their own data provider and forget about this table
1315     pDoc->CreateChartInternalDataProviders( this );
1316 
1317 	SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
1318     SwSelBoxes aSelBoxes;
1319     aSelBoxes.Insert(rBoxes.GetData(), rBoxes.Count());
1320     ExpandSelection( aSelBoxes );
1321 
1322 	//Lines fuer das Layout-Update herausuchen.
1323 	_FndBox aFndBox( 0, 0 );
1324 	aFndBox.SetTableLines( aSelBoxes, *this );
1325 	aFndBox.DelFrms( *this );
1326 
1327 	_CpyTabFrms aFrmArr;
1328 	SvPtrarr aLastBoxArr;
1329 	sal_uInt16 nFndPos;
1330 	for( sal_uInt16 n = 0; n < aSelBoxes.Count(); ++n )
1331 	{
1332 		SwTableBox* pSelBox = *( aSelBoxes.GetData() + n );
1333 		ASSERT( pSelBox, "Box steht nicht in der Tabelle" );
1334 
1335         // We don't want to split small table cells into very very small cells
1336         if( pSelBox->GetFrmFmt()->GetFrmSize().GetWidth()/( nCnt + 1 ) < 10 )
1337             continue;
1338 
1339 		// dann teile die Box nCnt in nCnt Boxen
1340 		SwTableLine* pInsLine = pSelBox->GetUpper();
1341 		sal_uInt16 nBoxPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSelBox );
1342 
1343 		// suche das FrmFmt im Array aller Frame-Formate
1344 		SwTableBoxFmt* pLastBoxFmt;
1345 		_CpyTabFrm aFindFrm( (SwTableBoxFmt*)pSelBox->GetFrmFmt() );
1346 		if( !aFrmArr.Seek_Entry( aFindFrm, &nFndPos ))
1347 		{
1348 			// aender das FrmFmt
1349 			aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pSelBox->ClaimFrmFmt();
1350 			SwTwips nBoxSz = aFindFrm.pNewFrmFmt->GetFrmSize().GetWidth();
1351 			SwTwips nNewBoxSz = nBoxSz / ( nCnt + 1 );
1352             aFindFrm.pNewFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1353 														nNewBoxSz, 0 ) );
1354 			aFrmArr.Insert( aFindFrm );
1355 
1356 			pLastBoxFmt = aFindFrm.pNewFrmFmt;
1357 			if( nBoxSz != ( nNewBoxSz * (nCnt + 1)))
1358 			{
1359 				// es bleibt ein Rest, also muss fuer die letzte Box ein
1360 				// eigenes Format definiert werden
1361 				pLastBoxFmt = new SwTableBoxFmt( *aFindFrm.pNewFrmFmt );
1362                 pLastBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1363 								nBoxSz - ( nNewBoxSz * nCnt ), 0 ) );
1364 			}
1365 			void* p = pLastBoxFmt;
1366 			aLastBoxArr.Insert( p, nFndPos );
1367 		}
1368 		else
1369 		{
1370 			aFindFrm = aFrmArr[ nFndPos ];
1371 			pSelBox->ChgFrmFmt( (SwTableBoxFmt*)aFindFrm.pNewFrmFmt );
1372 			pLastBoxFmt = (SwTableBoxFmt*)aLastBoxArr[ nFndPos ];
1373 		}
1374 
1375 		// dann fuege mal an der Position die neuen Boxen ein
1376 		for( sal_uInt16 i = 1; i < nCnt; ++i )
1377 			::_InsTblBox( pDoc, pTblNd, pInsLine, aFindFrm.pNewFrmFmt,
1378 						pSelBox, nBoxPos + i );	// dahinter einfuegen
1379 
1380 		::_InsTblBox( pDoc, pTblNd, pInsLine, pLastBoxFmt,
1381 					pSelBox, nBoxPos + nCnt );	// dahinter einfuegen
1382 
1383 		// Sonderbehandlung fuer die Umrandung:
1384 		const SvxBoxItem& aSelBoxItem = aFindFrm.pNewFrmFmt->GetBox();
1385 		if( aSelBoxItem.GetRight() )
1386 		{
1387 			pInsLine->GetTabBoxes()[ nBoxPos + nCnt ]->ClaimFrmFmt();
1388 
1389 			SvxBoxItem aTmp( aSelBoxItem );
1390 			aTmp.SetLine( 0, BOX_LINE_RIGHT );
1391             aFindFrm.pNewFrmFmt->SetFmtAttr( aTmp );
1392 
1393 			// und dann das Format aus dem "cache" entfernen
1394 			for( sal_uInt16 i = aFrmArr.Count(); i; )
1395 			{
1396 				const _CpyTabFrm& rCTF = aFrmArr[ --i ];
1397 				if( rCTF.pNewFrmFmt == aFindFrm.pNewFrmFmt ||
1398 					rCTF.Value.pFrmFmt == aFindFrm.pNewFrmFmt )
1399 				{
1400 					aFrmArr.Remove( i );
1401 					aLastBoxArr.Remove( i );
1402 				}
1403 			}
1404 		}
1405 	}
1406 
1407 	//Layout updaten
1408 	aFndBox.MakeFrms( *this );
1409 
1410 	CHECKBOXWIDTH
1411     CHECKTABLELAYOUT
1412 	return sal_True;
1413 }
1414 
1415 // ---------------------------------------------------------------
1416 
1417 /*
1418 	----------------------- >> MERGE << ------------------------
1419 	 Algorithmus:
1420 		ist in der _FndBox nur eine Line angegeben, nehme die Line
1421 		und teste die Anzahl der Boxen
1422 		- ist mehr als 1 Box angegeben, so wird auf Boxenebene zusammen-
1423 			gefasst, d.H. die neue Box wird so Breit wie die alten.
1424 			- Alle Lines die ueber/unter dem Bereich liegen werden in die
1425 			Box als Line + Box mit Lines eingefuegt
1426 			- Alle Lines die vor/hinter dem Bereich liegen werden in
1427 			die Boxen Left/Right eingetragen
1428 
1429 	----------------------- >> MERGE << ------------------------
1430 */
1431 
lcl_CpyLines(sal_uInt16 nStt,sal_uInt16 nEnd,SwTableLines & rLines,SwTableBox * pInsBox,sal_uInt16 nPos=USHRT_MAX)1432 void lcl_CpyLines( sal_uInt16 nStt, sal_uInt16 nEnd,
1433 								SwTableLines& rLines,
1434 								SwTableBox* pInsBox,
1435 								sal_uInt16 nPos = USHRT_MAX )
1436 {
1437 	for( sal_uInt16 n = nStt; n < nEnd; ++n )
1438 		rLines[n]->SetUpper( pInsBox );
1439 	if( USHRT_MAX == nPos )
1440 		nPos = pInsBox->GetTabLines().Count();
1441 	pInsBox->GetTabLines().Insert( &rLines, nPos, nStt, nEnd );
1442 	rLines.Remove( nStt, nEnd - nStt );
1443 }
1444 
lcl_CpyBoxes(sal_uInt16 nStt,sal_uInt16 nEnd,SwTableBoxes & rBoxes,SwTableLine * pInsLine,sal_uInt16 nPos=USHRT_MAX)1445 void lcl_CpyBoxes( sal_uInt16 nStt, sal_uInt16 nEnd,
1446 								SwTableBoxes& rBoxes,
1447 								SwTableLine* pInsLine,
1448 								sal_uInt16 nPos = USHRT_MAX )
1449 {
1450 	for( sal_uInt16 n = nStt; n < nEnd; ++n )
1451 		rBoxes[n]->SetUpper( pInsLine );
1452 	if( USHRT_MAX == nPos )
1453 		nPos = pInsLine->GetTabBoxes().Count();
1454 	pInsLine->GetTabBoxes().Insert( &rBoxes, nPos, nStt, nEnd );
1455 	rBoxes.Remove( nStt, nEnd - nStt );
1456 }
1457 
lcl_CalcWidth(SwTableBox * pBox)1458 void lcl_CalcWidth( SwTableBox* pBox )
1459 {
1460 	// Annahme: jede Line in der Box ist gleich gross
1461 	SwFrmFmt* pFmt = pBox->ClaimFrmFmt();
1462 	ASSERT( pBox->GetTabLines().Count(), "Box hat keine Lines" );
1463 
1464 	SwTableLine* pLine = pBox->GetTabLines()[0];
1465 	ASSERT( pLine, "Box steht in keiner Line" );
1466 
1467 	long nWidth = 0;
1468 	for( sal_uInt16 n = 0; n < pLine->GetTabBoxes().Count(); ++n )
1469 		nWidth += pLine->GetTabBoxes()[n]->GetFrmFmt()->GetFrmSize().GetWidth();
1470 
1471     pFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1472 
1473 	// in Boxen mit Lines darf es nur noch Size/Fillorder geben
1474     pFmt->ResetFmtAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
1475     pFmt->ResetFmtAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
1476 }
1477 
1478 
1479 
1480 struct _InsULPara
1481 {
1482 	SwTableNode* pTblNd;
1483 	SwTableLine* pInsLine;
1484 	SwTableBox* pInsBox;
1485 	sal_Bool bUL_LR : 1;		// Upper-Lower(sal_True) oder Left-Right(sal_False) ?
1486 	sal_Bool bUL : 1;           // Upper-Left(sal_True) oder Lower-Right(sal_False) ?
1487 
1488 	SwTableBox* pLeftBox;
1489 	SwTableBox* pRightBox;
1490 	SwTableBox* pMergeBox;
1491 
_InsULPara_InsULPara1492 	_InsULPara( SwTableNode* pTNd, sal_Bool bUpperLower, sal_Bool bUpper,
1493 				SwTableBox* pLeft, SwTableBox* pMerge, SwTableBox* pRight,
1494 				SwTableLine* pLine=0, SwTableBox* pBox=0 )
1495 		: pTblNd( pTNd ), pInsLine( pLine ), pInsBox( pBox ),
1496 		pLeftBox( pLeft ), pRightBox( pRight ), pMergeBox( pMerge )
1497 		{	bUL_LR = bUpperLower; bUL = bUpper;	}
1498 
SetLeft_InsULPara1499 	void SetLeft( SwTableBox* pBox=0 )
1500 		{ bUL_LR = sal_False;	bUL = sal_True; if( pBox ) pInsBox = pBox; }
SetRight_InsULPara1501 	void SetRight( SwTableBox* pBox=0 )
1502 		{ bUL_LR = sal_False;	bUL = sal_False; if( pBox ) pInsBox = pBox; }
SetUpper_InsULPara1503 	void SetUpper( SwTableLine* pLine=0 )
1504 		{ bUL_LR = sal_True;	bUL = sal_True;  if( pLine ) pInsLine = pLine; }
SetLower_InsULPara1505 	void SetLower( SwTableLine* pLine=0 )
1506 		{ bUL_LR = sal_True;	bUL = sal_False; if( pLine ) pInsLine = pLine; }
1507 };
1508 
1509 
lcl_Merge_MoveBox(const _FndBox * & rpFndBox,void * pPara)1510 sal_Bool lcl_Merge_MoveBox( const _FndBox*& rpFndBox, void* pPara )
1511 {
1512 	_InsULPara* pULPara = (_InsULPara*)pPara;
1513 	SwTableBoxes* pBoxes;
1514 
1515 	sal_uInt16 nStt = 0, nEnd = rpFndBox->GetLines().Count();
1516 	sal_uInt16 nInsPos = USHRT_MAX;
1517 	if( !pULPara->bUL_LR )	// Left/Right
1518 	{
1519 		sal_uInt16 nPos;
1520 		SwTableBox* pFndBox = (SwTableBox*)rpFndBox->GetBox();
1521 		pBoxes = &pFndBox->GetUpper()->GetTabBoxes();
1522 		if( pULPara->bUL )	// Left ?
1523 		{
1524 			// gibt es noch davor Boxen, dann move sie
1525 			if( 0 != ( nPos = pBoxes->C40_GETPOS( SwTableBox, pFndBox )) )
1526 				lcl_CpyBoxes( 0, nPos, *pBoxes, pULPara->pInsLine );
1527 		}
1528 		else				// Right
1529 			// gibt es noch dahinter Boxen, dann move sie
1530 			if( (nPos = pBoxes->C40_GETPOS( SwTableBox, pFndBox )) +1 < pBoxes->Count() )
1531 			{
1532 				nInsPos = pULPara->pInsLine->GetTabBoxes().Count();
1533 				lcl_CpyBoxes( nPos+1, pBoxes->Count(),
1534 									*pBoxes, pULPara->pInsLine );
1535 			}
1536 	}
1537 	// Upper/Lower und gehts noch tiefer ??
1538 	else if( rpFndBox->GetLines().Count() )
1539 	{
1540 		// suche nur die Line, ab der Verschoben werden muss
1541 		nStt = pULPara->bUL ? 0 : rpFndBox->GetLines().Count()-1;
1542 		nEnd = nStt+1;
1543 	}
1544 
1545 	pBoxes = &pULPara->pInsLine->GetTabBoxes();
1546 
1547 	// geht es noch eine weitere Stufe runter?
1548 	if( rpFndBox->GetBox()->GetTabLines().Count() )
1549 	{
1550 		SwTableBox* pBox = new SwTableBox(
1551 				(SwTableBoxFmt*)rpFndBox->GetBox()->GetFrmFmt(), 0,	pULPara->pInsLine );
1552 		_InsULPara aPara( *pULPara );
1553 		aPara.pInsBox = pBox;
1554 		((_FndBox*)rpFndBox)->GetLines().ForEach( nStt, nEnd,
1555 												&lcl_Merge_MoveLine, &aPara );
1556 		if( pBox->GetTabLines().Count() )
1557 		{
1558 			if( USHRT_MAX == nInsPos )
1559 				nInsPos = pBoxes->Count();
1560 			pBoxes->C40_INSERT( SwTableBox, pBox, nInsPos );
1561 			lcl_CalcWidth( pBox );		// bereche die Breite der Box
1562 		}
1563 		else
1564 			delete pBox;
1565 	}
1566 	return sal_True;
1567 }
1568 
lcl_Merge_MoveLine(const _FndLine * & rpFndLine,void * pPara)1569 sal_Bool lcl_Merge_MoveLine( const _FndLine*& rpFndLine, void* pPara )
1570 {
1571 	_InsULPara* pULPara = (_InsULPara*)pPara;
1572 	SwTableLines* pLines;
1573 
1574 	sal_uInt16 nStt = 0, nEnd = rpFndLine->GetBoxes().Count();
1575 	sal_uInt16 nInsPos = USHRT_MAX;
1576 	if( pULPara->bUL_LR ) 	// UpperLower ?
1577 	{
1578 		sal_uInt16 nPos;
1579 		SwTableLine* pFndLn = (SwTableLine*)rpFndLine->GetLine();
1580 		pLines = pFndLn->GetUpper() ?
1581 						&pFndLn->GetUpper()->GetTabLines() :
1582 						&pULPara->pTblNd->GetTable().GetTabLines();
1583 
1584 		SwTableBox* pLBx = rpFndLine->GetBoxes()[0]->GetBox();
1585 		SwTableBox* pRBx = rpFndLine->GetBoxes()[
1586 							rpFndLine->GetBoxes().Count()-1]->GetBox();
1587 		sal_uInt16 nLeft = pFndLn->GetTabBoxes().C40_GETPOS( SwTableBox, pLBx );
1588 		sal_uInt16 nRight = pFndLn->GetTabBoxes().C40_GETPOS( SwTableBox, pRBx );
1589 
1590 //		if( ( nLeft && nRight+1 < pFndLn->GetTabBoxes().Count() ) ||
1591 //			( !nLeft && nRight+1 >= pFndLn->GetTabBoxes().Count() ) )
1592 		if( !nLeft || nRight == pFndLn->GetTabBoxes().Count() )
1593 		{
1594 			if( pULPara->bUL )	// Upper ?
1595 			{
1596 				// gibt es noch davor Zeilen, dann move sie
1597 				if( 0 != ( nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) )
1598 					lcl_CpyLines( 0, nPos, *pLines, pULPara->pInsBox );
1599 			}
1600 			else
1601 				// gibt es noch dahinter Zeilen, dann move sie
1602 				if( (nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) +1 < pLines->Count() )
1603 				{
1604 					nInsPos = pULPara->pInsBox->GetTabLines().Count();
1605 					lcl_CpyLines( nPos+1, pLines->Count(), *pLines,
1606 										pULPara->pInsBox );
1607 				}
1608 		}
1609 		else if( nLeft )
1610 		{
1611 			// es gibt links noch weitere Boxen, also setze Left-
1612 			// und Merge-Box in eine Box und Line, fuege davor/dahinter
1613 			// eine Line mit Box ein, in die die oberen/unteren Lines
1614 			// eingefuegt werden
1615 			SwTableLine* pInsLine = pULPara->pLeftBox->GetUpper();
1616 			SwTableBox* pLMBox = new SwTableBox(
1617 				(SwTableBoxFmt*)pULPara->pLeftBox->GetFrmFmt(), 0, pInsLine );
1618 			SwTableLine* pLMLn = new SwTableLine(
1619 						(SwTableLineFmt*)pInsLine->GetFrmFmt(), 2, pLMBox );
1620             pLMLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE );
1621 
1622 			pLMBox->GetTabLines().C40_INSERT( SwTableLine, pLMLn, 0 );
1623 
1624 			lcl_CpyBoxes( 0, 2, pInsLine->GetTabBoxes(), pLMLn );
1625 
1626 			pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pLMBox, 0 );
1627 
1628 			if( pULPara->bUL )	// Upper ?
1629 			{
1630 				// gibt es noch davor Zeilen, dann move sie
1631 				if( 0 != ( nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) )
1632 					lcl_CpyLines( 0, nPos, *pLines, pLMBox, 0 );
1633 			}
1634 			else
1635 				// gibt es noch dahinter Zeilen, dann move sie
1636 				if( (nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) +1 < pLines->Count() )
1637 					lcl_CpyLines( nPos+1, pLines->Count(), *pLines,
1638 										pLMBox );
1639 			lcl_CalcWidth( pLMBox );		// bereche die Breite der Box
1640 		}
1641 		else if( nRight+1 < pFndLn->GetTabBoxes().Count() )
1642 		{
1643 			// es gibt rechts noch weitere Boxen, also setze Right-
1644 			// und Merge-Box in eine Box und Line, fuege davor/dahinter
1645 			// eine Line mit Box ein, in die die oberen/unteren Lines
1646 			// eingefuegt werden
1647 			SwTableLine* pInsLine = pULPara->pRightBox->GetUpper();
1648 			SwTableBox* pRMBox;
1649 			if( pULPara->pLeftBox->GetUpper() == pInsLine )
1650 			{
1651 				pRMBox = new SwTableBox(
1652 					(SwTableBoxFmt*)pULPara->pRightBox->GetFrmFmt(), 0, pInsLine );
1653 				SwTableLine* pRMLn = new SwTableLine(
1654 					(SwTableLineFmt*)pInsLine->GetFrmFmt(), 2, pRMBox );
1655                 pRMLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE );
1656 				pRMBox->GetTabLines().C40_INSERT( SwTableLine, pRMLn, 0 );
1657 
1658 				lcl_CpyBoxes( 1, 3, pInsLine->GetTabBoxes(), pRMLn );
1659 
1660 				pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pRMBox, 0 );
1661 			}
1662 			else
1663 			{
1664 				// Left und Merge wurden schon zusammengefuegt, also move
1665 				// Right auch mit in die Line
1666 
1667 				pInsLine = pULPara->pLeftBox->GetUpper();
1668 				sal_uInt16 nMvPos = pULPara->pRightBox->GetUpper()->GetTabBoxes().
1669 									C40_GETPOS( SwTableBox, pULPara->pRightBox );
1670 				lcl_CpyBoxes( nMvPos, nMvPos+1,
1671 							pULPara->pRightBox->GetUpper()->GetTabBoxes(),
1672 							pInsLine );
1673 				pRMBox = pInsLine->GetUpper();
1674 
1675 				// sind schon Lines vorhanden, dann muessen diese in eine
1676 				// neue Line und Box
1677 				nMvPos = pRMBox->GetTabLines().C40_GETPOS( SwTableLine, pInsLine );
1678 				if( pULPara->bUL ? nMvPos
1679 								: nMvPos+1 < pRMBox->GetTabLines().Count() )
1680 				{
1681 					// alle Lines zu einer neuen Line und Box zusammenfassen
1682 					SwTableLine* pNewLn = new SwTableLine(
1683 						(SwTableLineFmt*)pInsLine->GetFrmFmt(), 1, pRMBox );
1684                     pNewLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE );
1685 					pRMBox->GetTabLines().C40_INSERT( SwTableLine, pNewLn,
1686 							pULPara->bUL ? nMvPos : nMvPos+1 );
1687 					pRMBox = new SwTableBox( (SwTableBoxFmt*)pRMBox->GetFrmFmt(), 0, pNewLn );
1688 					pNewLn->GetTabBoxes().C40_INSERT( SwTableBox, pRMBox, 0 );
1689 
1690 					sal_uInt16 nPos1, nPos2;
1691 					if( pULPara->bUL )
1692 						nPos1 = 0,
1693 						nPos2 = nMvPos;
1694 					else
1695 						nPos1 = nMvPos+2,
1696 						nPos2 = pNewLn->GetUpper()->GetTabLines().Count();
1697 
1698 					lcl_CpyLines( nPos1, nPos2,
1699 								pNewLn->GetUpper()->GetTabLines(), pRMBox );
1700 					lcl_CalcWidth( pRMBox );		// bereche die Breite der Box
1701 
1702 					pRMBox = new SwTableBox( (SwTableBoxFmt*)pRMBox->GetFrmFmt(), 0, pNewLn );
1703 					pNewLn->GetTabBoxes().C40_INSERT( SwTableBox, pRMBox,
1704 									pNewLn->GetTabBoxes().Count() );
1705 				}
1706 			}
1707 			if( pULPara->bUL )	// Upper ?
1708 			{
1709 				// gibt es noch davor Zeilen, dann move sie
1710 				if( 0 != ( nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) )
1711 					lcl_CpyLines( 0, nPos, *pLines, pRMBox, 0 );
1712 			}
1713 			else
1714 				// gibt es noch dahinter Zeilen, dann move sie
1715 				if( (nPos = pLines->C40_GETPOS( SwTableLine, pFndLn )) +1 < pLines->Count() )
1716 					lcl_CpyLines( nPos+1, pLines->Count(), *pLines,
1717 										pRMBox );
1718 			lcl_CalcWidth( pRMBox );		// bereche die Breite der Box
1719 		}
1720 		else {
1721 			ASSERT( sal_False , "Was denn nun" );
1722         }
1723 	}
1724 	// Left/Right
1725 	else
1726 	{
1727 		// suche nur die Line, ab der Verschoben werden muss
1728 		nStt = pULPara->bUL ? 0 : rpFndLine->GetBoxes().Count()-1;
1729 		nEnd = nStt+1;
1730 	}
1731 	pLines = &pULPara->pInsBox->GetTabLines();
1732 
1733 	SwTableLine* pNewLine = new SwTableLine(
1734 		(SwTableLineFmt*)rpFndLine->GetLine()->GetFrmFmt(), 0, pULPara->pInsBox );
1735 	_InsULPara aPara( *pULPara );		// kopieren
1736 	aPara.pInsLine = pNewLine;
1737 	((_FndLine*)rpFndLine)->GetBoxes().ForEach( nStt, nEnd,
1738 												&lcl_Merge_MoveBox, &aPara );
1739 	if( pNewLine->GetTabBoxes().Count() )
1740 	{
1741 		if( USHRT_MAX == nInsPos )
1742 			nInsPos = pLines->Count();
1743 		pLines->C40_INSERT( SwTableLine, pNewLine, nInsPos );
1744 	}
1745 	else
1746 		delete pNewLine;
1747 
1748 	return sal_True;
1749 }
1750 
1751 
OldMerge(SwDoc * pDoc,const SwSelBoxes & rBoxes,SwTableBox * pMergeBox,SwUndoTblMerge * pUndo)1752 sal_Bool SwTable::OldMerge( SwDoc* pDoc, const SwSelBoxes& rBoxes,
1753     					SwTableBox* pMergeBox, SwUndoTblMerge* pUndo )
1754 {
1755     ASSERT( rBoxes.Count() && pMergeBox, "keine gueltigen Werte" );
1756 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1757 	if( !pTblNd )
1758 		return sal_False;
1759 
1760 	// suche alle Boxen / Lines
1761 	_FndBox aFndBox( 0, 0 );
1762 	{
1763 		_FndPara aPara( rBoxes, &aFndBox );
1764 		GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
1765 	}
1766 	if( !aFndBox.GetLines().Count() )
1767 		return sal_False;
1768 
1769 	// TL_CHART2: splitting/merging of a number of cells or rows will usually make
1770 	// the table to complex to be handled with chart.
1771     // Thus we tell the charts to use their own data provider and forget about this table
1772     pDoc->CreateChartInternalDataProviders( this );
1773 
1774 	SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
1775 
1776 	if( pUndo )
1777 		pUndo->SetSelBoxes( rBoxes );
1778 
1779 	//Lines fuer das Layout-Update herausuchen.
1780 	aFndBox.SetTableLines( *this );
1781 	aFndBox.DelFrms( *this );
1782 
1783 	_FndBox* pFndBox = &aFndBox;
1784 	while( 1 == pFndBox->GetLines().Count() &&
1785 			1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
1786 		pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
1787 
1788 	SwTableLine* pInsLine = new SwTableLine(
1789 				(SwTableLineFmt*)pFndBox->GetLines()[0]->GetLine()->GetFrmFmt(), 0,
1790 				!pFndBox->GetUpper() ? 0 : pFndBox->GetBox() );
1791     pInsLine->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE );
1792 
1793 	// trage die neue Line ein
1794 	SwTableLines* pLines =  pFndBox->GetUpper() ?
1795 				  &pFndBox->GetBox()->GetTabLines() :  &GetTabLines();
1796 
1797 	SwTableLine* pNewLine = pFndBox->GetLines()[0]->GetLine();
1798 	sal_uInt16 nInsPos = pLines->C40_GETPOS( SwTableLine, pNewLine );
1799 	pLines->C40_INSERT( SwTableLine, pInsLine, nInsPos );
1800 
1801 	SwTableBox* pLeftBox = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine );
1802 	SwTableBox* pRightBox = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine );
1803 	pMergeBox->SetUpper( pInsLine );
1804 	pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pLeftBox, 0 );
1805 	pLeftBox->ClaimFrmFmt();
1806 	pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pMergeBox, 1 );
1807 	pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pRightBox, 2 );
1808 	pRightBox->ClaimFrmFmt();
1809 
1810 	// in diese kommen alle Lines, die ueber dem selektierten Bereich stehen
1811 	// Sie bilden also eine Upper/Lower Line
1812 	_InsULPara aPara( pTblNd, sal_True, sal_True, pLeftBox, pMergeBox, pRightBox, pInsLine );
1813 
1814 	// move die oben/unten ueberhaengenden Lines vom selektierten Bereich
1815 	pFndBox->GetLines()[0]->GetBoxes().ForEach( &lcl_Merge_MoveBox,
1816 												&aPara );
1817 	aPara.SetLower( pInsLine );
1818 	sal_uInt16 nEnd = pFndBox->GetLines().Count()-1;
1819 	pFndBox->GetLines()[nEnd]->GetBoxes().ForEach( &lcl_Merge_MoveBox,
1820 													&aPara );
1821 
1822 	// move die links/rechts hereinreichenden Boxen vom selektierten Bereich
1823 	aPara.SetLeft( pLeftBox );
1824 	pFndBox->GetLines().ForEach( &lcl_Merge_MoveLine, &aPara );
1825 
1826 	aPara.SetRight( pRightBox );
1827 	pFndBox->GetLines().ForEach( &lcl_Merge_MoveLine, &aPara );
1828 
1829 	if( !pLeftBox->GetTabLines().Count() )
1830 		_DeleteBox( *this, pLeftBox, 0, sal_False, sal_False );
1831 	else
1832 	{
1833 		lcl_CalcWidth( pLeftBox );		// bereche die Breite der Box
1834 		if( pUndo && pLeftBox->GetSttNd() )
1835 			pUndo->AddNewBox( pLeftBox->GetSttIdx() );
1836 	}
1837 	if( !pRightBox->GetTabLines().Count() )
1838 		_DeleteBox( *this, pRightBox, 0, sal_False, sal_False );
1839 	else
1840 	{
1841 		lcl_CalcWidth( pRightBox );		// bereche die Breite der Box
1842 		if( pUndo && pRightBox->GetSttNd() )
1843 			pUndo->AddNewBox( pRightBox->GetSttIdx() );
1844 	}
1845 
1846 	DeleteSel( pDoc, rBoxes, 0, 0, sal_False, sal_False );
1847 
1848 	// dann raeume die Struktur dieser Line noch mal auf:
1849 	// generell alle Aufraeumen
1850 	GCLines();
1851 
1852 	GetTabLines()[0]->GetTabBoxes().ForEach( &lcl_BoxSetHeadCondColl, 0 );
1853 
1854 	aFndBox.MakeFrms( *this );
1855 
1856 	CHECKBOXWIDTH
1857     CHECKTABLELAYOUT
1858 
1859 	return sal_True;
1860 }
1861 
1862 // ---------------------------------------------------------------
1863 
lcl_CheckRowSpan(SwTable & rTbl)1864 void lcl_CheckRowSpan( SwTable &rTbl )
1865 {
1866     sal_uInt16 nLineCount = rTbl.GetTabLines().Count();
1867     sal_uInt16 nMaxSpan = nLineCount;
1868     long nMinSpan = 1;
1869     while( nMaxSpan )
1870     {
1871         SwTableLine* pLine = rTbl.GetTabLines()[ nLineCount - nMaxSpan ];
1872         for( sal_uInt16 nBox = 0; nBox < pLine->GetTabBoxes().Count(); ++nBox )
1873         {
1874             SwTableBox* pBox = pLine->GetTabBoxes()[nBox];
1875             long nRowSpan = pBox->getRowSpan();
1876             if( nRowSpan > nMaxSpan )
1877                 pBox->setRowSpan( nMaxSpan );
1878             else if( nRowSpan < nMinSpan )
1879                 pBox->setRowSpan( nMinSpan > 0 ? nMaxSpan : nMinSpan );
1880         }
1881         --nMaxSpan;
1882         nMinSpan = -nMaxSpan;
1883     }
1884 }
1885 
lcl_GetBoxOffset(const _FndBox & rBox)1886 sal_uInt16 lcl_GetBoxOffset( const _FndBox& rBox )
1887 {
1888 	// suche die erste Box
1889 	const _FndBox* pFirstBox = &rBox;
1890 	while( pFirstBox->GetLines().Count() )
1891 		pFirstBox = pFirstBox->GetLines()[ 0 ]->GetBoxes()[ 0 ];
1892 
1893 	sal_uInt16 nRet = 0;
1894 	// dann ueber die Lines nach oben die Position bestimmen
1895 	const SwTableBox* pBox = pFirstBox->GetBox();
1896 	do {
1897 		const SwTableBoxes& rBoxes = pBox->GetUpper()->GetTabBoxes();
1898 		const SwTableBox* pCmp;
1899 		for( sal_uInt16 n = 0; pBox != ( pCmp = rBoxes[ n ] ); ++n )
1900 			nRet = nRet + (sal_uInt16) pCmp->GetFrmFmt()->GetFrmSize().GetWidth();
1901 		pBox = pBox->GetUpper()->GetUpper();
1902 	} while( pBox );
1903 	return nRet;
1904 }
1905 
lcl_GetLineWidth(const _FndLine & rLine)1906 sal_uInt16 lcl_GetLineWidth( const _FndLine& rLine )
1907 {
1908 	sal_uInt16 nRet = 0;
1909 	for( sal_uInt16 n = rLine.GetBoxes().Count(); n; )
1910 		nRet = nRet + (sal_uInt16)rLine.GetBoxes()[ --n ]->GetBox()->GetFrmFmt()
1911 						->GetFrmSize().GetWidth();
1912 	return nRet;
1913 }
1914 
lcl_CalcNewWidths(const _FndLines & rFndLines,_CpyPara & rPara)1915 void lcl_CalcNewWidths( const _FndLines& rFndLines, _CpyPara& rPara )
1916 {
1917     rPara.pWidths.reset();
1918     sal_uInt16 nLineCount = rFndLines.Count();
1919     if( nLineCount )
1920     {
1921         rPara.pWidths = boost::shared_ptr< std::vector< std::vector< sal_uLong > > >
1922                         ( new std::vector< std::vector< sal_uLong > >( nLineCount ));
1923         // First we collect information about the left/right borders of all
1924         // selected cells
1925         for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1926         {
1927             std::vector< sal_uLong > &rWidth = (*rPara.pWidths.get())[ nLine ];
1928             const _FndLine *pFndLine = rFndLines[ nLine ];
1929             if( pFndLine && pFndLine->GetBoxes().Count() )
1930             {
1931                 const SwTableLine *pLine = pFndLine->GetLine();
1932                 if( pLine && pLine->GetTabBoxes().Count() )
1933                 {
1934                     sal_uInt16 nBoxCount = pLine->GetTabBoxes().Count();
1935                     sal_uLong nPos = 0;
1936                     // The first selected box...
1937                     const SwTableBox *pSel = pFndLine->GetBoxes()[0]->GetBox();
1938                     sal_uInt16 nBox = 0;
1939                     // Sum up the width of all boxes before the first selected box
1940                     while( nBox < nBoxCount )
1941                     {
1942                         SwTableBox* pBox = pLine->GetTabBoxes()[nBox++];
1943                         if( pBox != pSel )
1944                             nPos += pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1945                         else
1946                             break;
1947                     }
1948                     // nPos is now the left border of the first selceted box
1949                     if( rPara.nMinLeft > nPos )
1950                         rPara.nMinLeft = nPos;
1951                     nBoxCount = pFndLine->GetBoxes().Count();
1952                     rWidth = std::vector< sal_uLong >( nBoxCount+2 );
1953                     rWidth[ 0 ] = nPos;
1954                     // Add now the widths of all selected boxes and store
1955                     // the positions in the vector
1956                     for( nBox = 0; nBox < nBoxCount; )
1957                     {
1958                         nPos += pFndLine->GetBoxes()[nBox]
1959 						    ->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth();
1960                         rWidth[ ++nBox ] = nPos;
1961                     }
1962                     // nPos: The right border of the last selected box
1963                     if( rPara.nMaxRight < nPos )
1964                         rPara.nMaxRight = nPos;
1965                     if( nPos <= rWidth[ 0 ] )
1966                         rWidth.clear();
1967                 }
1968             }
1969         }
1970     }
1971     // Second step: calculate the new widths for the copied cells
1972     sal_uLong nSelSize = rPara.nMaxRight - rPara.nMinLeft;
1973     if( nSelSize )
1974     {
1975         for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1976         {
1977             std::vector< sal_uLong > &rWidth = (*rPara.pWidths.get())[ nLine ];
1978             sal_uInt16 nCount = (sal_uInt16)rWidth.size();
1979             if( nCount > 2 )
1980             {
1981                 rWidth[ nCount - 1 ] = rPara.nMaxRight;
1982                 sal_uLong nLastPos = 0;
1983                 for( sal_uInt16 nBox = 0; nBox < nCount; ++nBox )
1984                 {
1985                     sal_uInt64 nNextPos = rWidth[ nBox ];
1986                     nNextPos -= rPara.nMinLeft;
1987                     nNextPos *= rPara.nNewSize;
1988                     nNextPos /= nSelSize;
1989                     rWidth[ nBox ] = (sal_uLong)(nNextPos - nLastPos);
1990                     nLastPos = (sal_uLong)nNextPos;
1991                 }
1992             }
1993         }
1994     }
1995 }
1996 
lcl_CopyBoxToDoc(const _FndBox * & rpFndBox,void * pPara)1997 sal_Bool lcl_CopyBoxToDoc( const _FndBox*& rpFndBox, void* pPara )
1998 {
1999 	_CpyPara* pCpyPara = (_CpyPara*)pPara;
2000 
2001 	// Calculation of new size
2002     sal_uLong nRealSize;
2003     sal_uLong nDummy1 = 0;
2004     sal_uLong nDummy2 = 0;
2005     if( pCpyPara->pTblNd->GetTable().IsNewModel() )
2006     {
2007         if( pCpyPara->nBoxIdx == 1 )
2008             nDummy1 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][0];
2009         nRealSize = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx++];
2010         if( pCpyPara->nBoxIdx == (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx].size()-1 )
2011             nDummy2 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx];
2012     }
2013     else
2014     {
2015         nRealSize = pCpyPara->nNewSize;
2016         nRealSize *= rpFndBox->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth();
2017         nRealSize /= pCpyPara->nOldSize;
2018     }
2019 
2020     sal_uLong nSize;
2021     bool bDummy = nDummy1 > 0;
2022     if( bDummy )
2023         nSize = nDummy1;
2024     else
2025     {
2026         nSize = nRealSize;
2027         nRealSize = 0;
2028     }
2029     do
2030     {
2031         // suche das Frame-Format in der Liste aller Frame-Formate
2032         _CpyTabFrm aFindFrm( (SwTableBoxFmt*)rpFndBox->GetBox()->GetFrmFmt() );
2033 
2034         SwFmtFrmSize aFrmSz;
2035         sal_uInt16 nFndPos;
2036         if( !pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos ) ||
2037             ( aFrmSz = ( aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]).pNewFrmFmt->
2038                 GetFrmSize()).GetWidth() != (SwTwips)nSize )
2039         {
2040             // es ist noch nicht vorhanden, also kopiere es
2041             aFindFrm.pNewFrmFmt = pCpyPara->pDoc->MakeTableBoxFmt();
2042             aFindFrm.pNewFrmFmt->CopyAttrs( *rpFndBox->GetBox()->GetFrmFmt() );
2043             if( !pCpyPara->bCpyCntnt )
2044                 aFindFrm.pNewFrmFmt->ResetFmtAttr(  RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
2045             aFrmSz.SetWidth( nSize );
2046             aFindFrm.pNewFrmFmt->SetFmtAttr( aFrmSz );
2047             pCpyPara->rTabFrmArr.Insert( aFindFrm );
2048         }
2049 
2050         SwTableBox* pBox;
2051         if( rpFndBox->GetLines().Count() )
2052         {
2053             pBox = new SwTableBox( aFindFrm.pNewFrmFmt,
2054                         rpFndBox->GetLines().Count(), pCpyPara->pInsLine );
2055             pCpyPara->pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, pCpyPara->nInsPos++ );
2056             _CpyPara aPara( *pCpyPara, pBox );
2057             aPara.nNewSize = nSize;		// hole die Groesse
2058             ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CopyLineToDoc, &aPara );
2059         }
2060         else
2061         {
2062             // erzeuge eine leere Box
2063             pCpyPara->pDoc->GetNodes().InsBoxen( pCpyPara->pTblNd, pCpyPara->pInsLine,
2064                             aFindFrm.pNewFrmFmt,
2065                             (SwTxtFmtColl*)pCpyPara->pDoc->GetDfltTxtFmtColl(),
2066                             0, pCpyPara->nInsPos );
2067             pBox = pCpyPara->pInsLine->GetTabBoxes()[ pCpyPara->nInsPos ];
2068             if( bDummy )
2069                 pBox->setDummyFlag( true );
2070             else if( pCpyPara->bCpyCntnt )
2071             {
2072                 // dann kopiere mal den Inhalt in diese leere Box
2073                 pBox->setRowSpan( rpFndBox->GetBox()->getRowSpan() );
2074 
2075                 // der Inhalt kopiert wird, dann koennen auch Formeln&Values
2076                 // kopiert werden.
2077                 {
2078                     SfxItemSet aBoxAttrSet( pCpyPara->pDoc->GetAttrPool(),
2079                                             RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2080                     aBoxAttrSet.Put( rpFndBox->GetBox()->GetFrmFmt()->GetAttrSet() );
2081                     if( aBoxAttrSet.Count() )
2082                     {
2083                         const SfxPoolItem* pItem;
2084                         SvNumberFormatter* pN = pCpyPara->pDoc->GetNumberFormatter( sal_False );
2085                         if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == aBoxAttrSet.
2086                             GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) )
2087                         {
2088                             sal_uLong nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue();
2089                             sal_uLong nNewIdx = pN->GetMergeFmtIndex( nOldIdx );
2090                             if( nNewIdx != nOldIdx )
2091                                 aBoxAttrSet.Put( SwTblBoxNumFormat( nNewIdx ));
2092                         }
2093                         pBox->ClaimFrmFmt()->SetFmtAttr( aBoxAttrSet );
2094                     }
2095                 }
2096                 SwDoc* pFromDoc = rpFndBox->GetBox()->GetFrmFmt()->GetDoc();
2097                 SwNodeRange aCpyRg( *rpFndBox->GetBox()->GetSttNd(), 1,
2098                             *rpFndBox->GetBox()->GetSttNd()->EndOfSectionNode() );
2099                 SwNodeIndex aInsIdx( *pBox->GetSttNd(), 1 );
2100 
2101                 pFromDoc->CopyWithFlyInFly( aCpyRg, 0, aInsIdx, NULL, sal_False );
2102                 // den initialen TextNode loeschen
2103                 pCpyPara->pDoc->GetNodes().Delete( aInsIdx, 1 );
2104             }
2105             ++pCpyPara->nInsPos;
2106         }
2107         if( nRealSize )
2108         {
2109             bDummy = false;
2110             nSize = nRealSize;
2111             nRealSize = 0;
2112         }
2113         else
2114         {
2115             bDummy = true;
2116             nSize = nDummy2;
2117             nDummy2 = 0;
2118         }
2119     }
2120     while( nSize );
2121 	return sal_True;
2122 }
2123 
lcl_CopyLineToDoc(const _FndLine * & rpFndLine,void * pPara)2124 sal_Bool lcl_CopyLineToDoc( const _FndLine*& rpFndLine, void* pPara )
2125 {
2126 	_CpyPara* pCpyPara = (_CpyPara*)pPara;
2127 
2128 	// suche das Format in der Liste aller Formate
2129 	_CpyTabFrm aFindFrm( (SwTableBoxFmt*)rpFndLine->GetLine()->GetFrmFmt() );
2130 	sal_uInt16 nFndPos;
2131 	if( !pCpyPara->rTabFrmArr.Seek_Entry( aFindFrm, &nFndPos ))
2132 	{
2133 		// es ist noch nicht vorhanden, also kopiere es
2134 		aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pCpyPara->pDoc->MakeTableLineFmt();
2135 		aFindFrm.pNewFrmFmt->CopyAttrs( *rpFndLine->GetLine()->GetFrmFmt() );
2136 		pCpyPara->rTabFrmArr.Insert( aFindFrm );
2137 	}
2138 	else
2139 		aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ];
2140 
2141 	SwTableLine* pNewLine = new SwTableLine( (SwTableLineFmt*)aFindFrm.pNewFrmFmt,
2142 						rpFndLine->GetBoxes().Count(), pCpyPara->pInsBox );
2143 	if( pCpyPara->pInsBox )
2144 	{
2145 		pCpyPara->pInsBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine, pCpyPara->nInsPos++ );
2146 	}
2147 	else
2148 	{
2149 		pCpyPara->pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pNewLine,
2150 							pCpyPara->nInsPos++ );
2151 	}
2152 
2153 	_CpyPara aPara( *pCpyPara, pNewLine );
2154 
2155 	if( pCpyPara->pTblNd->GetTable().IsNewModel() )
2156     {
2157         aPara.nOldSize = 0; // will not be used
2158         aPara.nBoxIdx = 1;
2159     }
2160     else if( rpFndLine->GetBoxes().Count() ==
2161 					rpFndLine->GetLine()->GetTabBoxes().Count() )
2162 	{
2163 		// hole die Size vom Parent
2164 		const SwFrmFmt* pFmt;
2165 
2166 		if( rpFndLine->GetLine()->GetUpper() )
2167 			pFmt = rpFndLine->GetLine()->GetUpper()->GetFrmFmt();
2168 		else
2169 			pFmt = pCpyPara->pTblNd->GetTable().GetFrmFmt();
2170 		aPara.nOldSize = pFmt->GetFrmSize().GetWidth();
2171 	}
2172 	else
2173 		// errechne sie
2174 		for( sal_uInt16 n = 0; n < rpFndLine->GetBoxes().Count(); ++n )
2175 			aPara.nOldSize += rpFndLine->GetBoxes()[n]
2176 						->GetBox()->GetFrmFmt()->GetFrmSize().GetWidth();
2177 
2178 	((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CopyBoxToDoc, &aPara );
2179     if( pCpyPara->pTblNd->GetTable().IsNewModel() )
2180         ++pCpyPara->nLnIdx;
2181 	return sal_True;
2182 }
2183 
CopyHeadlineIntoTable(SwTableNode & rTblNd)2184 sal_Bool SwTable::CopyHeadlineIntoTable( SwTableNode& rTblNd )
2185 {
2186 	// suche alle Boxen / Lines
2187 	SwSelBoxes aSelBoxes;
2188 	SwTableBox* pBox = GetTabSortBoxes()[ 0 ];
2189     pBox = GetTblBox( pBox->GetSttNd()->StartOfSectionNode()->GetIndex() + 1 );
2190 	SelLineFromBox( pBox, aSelBoxes, sal_True );
2191 
2192 	_FndBox aFndBox( 0, 0 );
2193 	{
2194 		_FndPara aPara( aSelBoxes, &aFndBox );
2195 		((SwTableLines&)GetTabLines()).ForEach( &_FndLineCopyCol, &aPara );
2196 	}
2197 	if( !aFndBox.GetLines().Count() )
2198 		return sal_False;
2199 
2200 	{
2201 		// Tabellen-Formeln in die relative Darstellung umwandeln
2202 		SwTableFmlUpdate aMsgHnt( this );
2203 		aMsgHnt.eFlags = TBL_RELBOXNAME;
2204 		GetFrmFmt()->GetDoc()->UpdateTblFlds( &aMsgHnt );
2205 	}
2206 
2207 	_CpyTabFrms aCpyFmt;
2208 	_CpyPara aPara( &rTblNd, 1, aCpyFmt, sal_True );
2209 	aPara.nNewSize = aPara.nOldSize = rTblNd.GetTable().GetFrmFmt()->GetFrmSize().GetWidth();
2210 	// dann kopiere mal
2211     if( IsNewModel() )
2212         lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
2213 	aFndBox.GetLines().ForEach( &lcl_CopyLineToDoc, &aPara );
2214     if( rTblNd.GetTable().IsNewModel() )
2215     {   // The copied line must not contain any row span attributes > 1
2216         SwTableLine* pLine = rTblNd.GetTable().GetTabLines()[0];
2217         sal_uInt16 nColCount = pLine->GetTabBoxes().Count();
2218         ASSERT( nColCount, "Empty Table Line" )
2219         for( sal_uInt16 nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol )
2220         {
2221             SwTableBox* pTableBox = pLine->GetTabBoxes()[nCurrCol];
2222             ASSERT( pTableBox, "Missing Table Box" );
2223             pTableBox->setRowSpan( 1 );
2224         }
2225     }
2226 
2227 	return sal_True;
2228 }
2229 
MakeCopy(SwDoc * pInsDoc,const SwPosition & rPos,const SwSelBoxes & rSelBoxes,sal_Bool bCpyNds,sal_Bool bCpyName) const2230 sal_Bool SwTable::MakeCopy( SwDoc* pInsDoc, const SwPosition& rPos,
2231 						const SwSelBoxes& rSelBoxes, sal_Bool bCpyNds,
2232 						sal_Bool bCpyName ) const
2233 {
2234 	// suche alle Boxen / Lines
2235 	_FndBox aFndBox( 0, 0 );
2236 	{
2237 		_FndPara aPara( rSelBoxes, &aFndBox );
2238 		((SwTableLines&)GetTabLines()).ForEach( &_FndLineCopyCol, &aPara );
2239 	}
2240 	if( !aFndBox.GetLines().Count() )
2241 		return sal_False;
2242 
2243 	// erst die Poolvorlagen fuer die Tabelle kopieren, damit die dann
2244 	// wirklich kopiert und damit die gueltigen Werte haben.
2245 	SwDoc* pSrcDoc = GetFrmFmt()->GetDoc();
2246 	if( pSrcDoc != pInsDoc )
2247 	{
2248 		pInsDoc->CopyTxtColl( *pSrcDoc->GetTxtCollFromPool( RES_POOLCOLL_TABLE ) );
2249 		pInsDoc->CopyTxtColl( *pSrcDoc->GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN ) );
2250 	}
2251 
2252     SwTable* pNewTbl = (SwTable*)pInsDoc->InsertTable(
2253             SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 1 ),
2254             rPos, 1, 1, GetFrmFmt()->GetHoriOrient().GetHoriOrient(),
2255             0, 0, sal_False, IsNewModel() );
2256 	if( !pNewTbl )
2257 		return sal_False;
2258 
2259 	SwNodeIndex aIdx( rPos.nNode, -1 );
2260 	SwTableNode* pTblNd = aIdx.GetNode().FindTableNode();
2261 	aIdx++;
2262 	ASSERT( pTblNd, "wo ist denn nun der TableNode?" );
2263 
2264     pTblNd->GetTable().SetRowsToRepeat( GetRowsToRepeat() );
2265 
2266 	if( IS_TYPE( SwDDETable, this ))
2267 	{
2268 		// es wird eine DDE-Tabelle kopiert
2269 		// ist im neuen Dokument ueberhaupt der FeldTyp vorhanden ?
2270 		SwFieldType* pFldType = pInsDoc->InsertFldType(
2271 									*((SwDDETable*)this)->GetDDEFldType() );
2272 		ASSERT( pFldType, "unbekannter FieldType" );
2273 
2274 		// tauschen am Node den Tabellen-Pointer aus
2275 		pNewTbl = new SwDDETable( *pNewTbl,
2276 								 (SwDDEFieldType*)pFldType );
2277 		pTblNd->SetNewTable( pNewTbl, sal_False );
2278 	}
2279 
2280 	pNewTbl->GetFrmFmt()->CopyAttrs( *GetFrmFmt() );
2281 	pNewTbl->SetTblChgMode( GetTblChgMode() );
2282 
2283 	//Vernichten der Frms die bereits angelegt wurden.
2284 	pTblNd->DelFrms();
2285 
2286 	{
2287 		// Tabellen-Formeln in die relative Darstellung umwandeln
2288 		SwTableFmlUpdate aMsgHnt( this );
2289 		aMsgHnt.eFlags = TBL_RELBOXNAME;
2290 		pSrcDoc->UpdateTblFlds( &aMsgHnt );
2291 	}
2292 
2293 	SwTblNumFmtMerge aTNFM( *pSrcDoc, *pInsDoc );
2294 
2295 	// Namen auch kopieren oder neuen eindeutigen erzeugen
2296 	if( bCpyName )
2297 		pNewTbl->GetFrmFmt()->SetName( GetFrmFmt()->GetName() );
2298 
2299 	_CpyTabFrms aCpyFmt;
2300 	_CpyPara aPara( pTblNd, 1, aCpyFmt, bCpyNds );
2301 	aPara.nNewSize = aPara.nOldSize = GetFrmFmt()->GetFrmSize().GetWidth();
2302 
2303     if( IsNewModel() )
2304         lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
2305 	// dann kopiere mal
2306 	aFndBox.GetLines().ForEach( &lcl_CopyLineToDoc, &aPara );
2307 
2308 	// dann setze oben und unten noch die "richtigen" Raender:
2309 	{
2310 		_FndLine* pFndLn = aFndBox.GetLines()[ 0 ];
2311 		SwTableLine* pLn = pFndLn->GetLine();
2312 		const SwTableLine* pTmp = pLn;
2313 		sal_uInt16 nLnPos = GetTabLines().GetPos( pTmp );
2314 		if( USHRT_MAX != nLnPos && nLnPos )
2315 		{
2316 			// es gibt eine Line davor
2317 			SwCollectTblLineBoxes aLnPara( sal_False, HEADLINE_BORDERCOPY );
2318 
2319 			pLn = GetTabLines()[ nLnPos - 1 ];
2320 			pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aLnPara );
2321 
2322 			if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
2323 								lcl_GetLineWidth( *pFndLn )) )
2324 			{
2325 				aLnPara.SetValues( sal_True );
2326 				pLn = pNewTbl->GetTabLines()[ 0 ];
2327 				pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aLnPara );
2328 			}
2329 		}
2330 
2331 		pFndLn = aFndBox.GetLines()[ aFndBox.GetLines().Count() -1 ];
2332 		pLn = pFndLn->GetLine();
2333 		pTmp = pLn;
2334 		nLnPos = GetTabLines().GetPos( pTmp );
2335 		if( nLnPos < GetTabLines().Count() - 1 )
2336 		{
2337 			// es gibt eine Line dahinter
2338 			SwCollectTblLineBoxes aLnPara( sal_True, HEADLINE_BORDERCOPY );
2339 
2340 			pLn = GetTabLines()[ nLnPos + 1 ];
2341 			pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aLnPara );
2342 
2343 			if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
2344 								lcl_GetLineWidth( *pFndLn )) )
2345 			{
2346 				aLnPara.SetValues( sal_False );
2347 				pLn = pNewTbl->GetTabLines()[ pNewTbl->GetTabLines().Count()-1 ];
2348 				pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aLnPara );
2349 			}
2350 		}
2351 	}
2352 
2353 	// die initiale Box muss noch geloescht werden
2354 	_DeleteBox( *pNewTbl, pNewTbl->GetTabLines()[
2355 				pNewTbl->GetTabLines().Count() - 1 ]->GetTabBoxes()[0],
2356 				0, sal_False, sal_False );
2357 
2358     if( pNewTbl->IsNewModel() )
2359         lcl_CheckRowSpan( *pNewTbl );
2360 	// Mal kurz aufraeumen:
2361 	pNewTbl->GCLines();
2362 
2363 	pTblNd->MakeFrms( &aIdx ); 	// erzeuge die Frames neu
2364 
2365     CHECKTABLELAYOUT
2366 
2367 	return sal_True;
2368 }
2369 
2370 
2371 
2372 // ---------------------------------------------------------------
2373 
2374 // suche ab dieser Line nach der naechsten Box mit Inhalt
FindNextBox(const SwTable & rTbl,const SwTableBox * pSrchBox,sal_Bool bOvrTblLns) const2375 SwTableBox* SwTableLine::FindNextBox( const SwTable& rTbl,
2376 					 const SwTableBox* pSrchBox, sal_Bool bOvrTblLns ) const
2377 {
2378 	const SwTableLine* pLine = this;			// fuer M800
2379 	SwTableBox* pBox;
2380 	sal_uInt16 nFndPos;
2381 	if( GetTabBoxes().Count() && pSrchBox &&
2382 		USHRT_MAX != ( nFndPos = GetTabBoxes().GetPos( pSrchBox )) &&
2383 		nFndPos + 1 != GetTabBoxes().Count() )
2384 	{
2385 		pBox = GetTabBoxes()[ nFndPos + 1 ];
2386 		while( pBox->GetTabLines().Count() )
2387 			pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
2388 		return pBox;
2389 	}
2390 
2391 	if( GetUpper() )
2392 	{
2393 		nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
2394 		ASSERT( USHRT_MAX != nFndPos, "Line nicht in der Tabelle" );
2395 		// gibts eine weitere Line
2396 		if( nFndPos+1 >= GetUpper()->GetTabLines().Count() )
2397 			return GetUpper()->GetUpper()->FindNextBox( rTbl, GetUpper(), bOvrTblLns );
2398 		pLine = GetUpper()->GetTabLines()[nFndPos+1];
2399 	}
2400 	else if( bOvrTblLns )		// ueber die "GrundLines" einer Tabelle ?
2401 	{
2402 		// suche in der Tabelle nach der naechsten Line
2403 		nFndPos = rTbl.GetTabLines().GetPos( pLine );
2404 		if( nFndPos + 1 >= rTbl.GetTabLines().Count() )
2405 			return 0;			// es gibt keine weitere Box mehr
2406 
2407 		pLine = rTbl.GetTabLines()[ nFndPos+1 ];
2408 	}
2409 	else
2410 		return 0;
2411 
2412 	if( pLine->GetTabBoxes().Count() )
2413 	{
2414 		pBox = pLine->GetTabBoxes()[0];
2415 		while( pBox->GetTabLines().Count() )
2416 			pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
2417 		return pBox;
2418 	}
2419 	return pLine->FindNextBox( rTbl, 0, bOvrTblLns );
2420 }
2421 
2422 // suche ab dieser Line nach der vorherigen Box
FindPreviousBox(const SwTable & rTbl,const SwTableBox * pSrchBox,sal_Bool bOvrTblLns) const2423 SwTableBox* SwTableLine::FindPreviousBox( const SwTable& rTbl,
2424 						 const SwTableBox* pSrchBox, sal_Bool bOvrTblLns ) const
2425 {
2426 	const SwTableLine* pLine = this;			// fuer M800
2427 	SwTableBox* pBox;
2428 	sal_uInt16 nFndPos;
2429 	if( GetTabBoxes().Count() && pSrchBox &&
2430 		USHRT_MAX != ( nFndPos = GetTabBoxes().GetPos( pSrchBox )) &&
2431 		nFndPos )
2432 	{
2433 		pBox = GetTabBoxes()[ nFndPos - 1 ];
2434 		while( pBox->GetTabLines().Count() )
2435 		{
2436 			pLine = pBox->GetTabLines()[pBox->GetTabLines().Count()-1];
2437 			pBox = pLine->GetTabBoxes()[pLine->GetTabBoxes().Count()-1];
2438 		}
2439 		return pBox;
2440 	}
2441 
2442 	if( GetUpper() )
2443 	{
2444 		nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
2445 		ASSERT( USHRT_MAX != nFndPos, "Line nicht in der Tabelle" );
2446 		// gibts eine weitere Line
2447 		if( !nFndPos )
2448 			return GetUpper()->GetUpper()->FindPreviousBox( rTbl, GetUpper(), bOvrTblLns );
2449 		pLine = GetUpper()->GetTabLines()[nFndPos-1];
2450 	}
2451 	else if( bOvrTblLns )		// ueber die "GrundLines" einer Tabelle ?
2452 	{
2453 		// suche in der Tabelle nach der naechsten Line
2454 		nFndPos = rTbl.GetTabLines().GetPos( pLine );
2455 		if( !nFndPos )
2456 			return 0;			// es gibt keine weitere Box mehr
2457 
2458 		pLine = rTbl.GetTabLines()[ nFndPos-1 ];
2459 	}
2460 	else
2461 		return 0;
2462 
2463 	if( pLine->GetTabBoxes().Count() )
2464 	{
2465 		pBox = pLine->GetTabBoxes()[pLine->GetTabBoxes().Count()-1];
2466 		while( pBox->GetTabLines().Count() )
2467 		{
2468 			pLine = pBox->GetTabLines()[pBox->GetTabLines().Count()-1];
2469 			pBox = pLine->GetTabBoxes()[pLine->GetTabBoxes().Count()-1];
2470 		}
2471 		return pBox;
2472 	}
2473 	return pLine->FindPreviousBox( rTbl, 0, bOvrTblLns );
2474 }
2475 
2476 // suche ab dieser Line nach der naechsten Box mit Inhalt
FindNextBox(const SwTable & rTbl,const SwTableBox * pSrchBox,sal_Bool bOvrTblLns) const2477 SwTableBox* SwTableBox::FindNextBox( const SwTable& rTbl,
2478 						 const SwTableBox* pSrchBox, sal_Bool bOvrTblLns ) const
2479 {
2480 	if( !pSrchBox  && !GetTabLines().Count() )
2481 		return (SwTableBox*)this;
2482 	return GetUpper()->FindNextBox( rTbl, pSrchBox ? pSrchBox : this,
2483 										bOvrTblLns );
2484 
2485 }
2486 
2487 // suche ab dieser Line nach der naechsten Box mit Inhalt
FindPreviousBox(const SwTable & rTbl,const SwTableBox * pSrchBox,sal_Bool bOvrTblLns) const2488 SwTableBox* SwTableBox::FindPreviousBox( const SwTable& rTbl,
2489 						 const SwTableBox* pSrchBox, sal_Bool bOvrTblLns ) const
2490 {
2491 	if( !pSrchBox && !GetTabLines().Count() )
2492 		return (SwTableBox*)this;
2493 	return GetUpper()->FindPreviousBox( rTbl, pSrchBox ? pSrchBox : this,
2494 										bOvrTblLns );
2495 }
2496 
2497 
lcl_BoxSetHeadCondColl(const SwTableBox * & rpBox,void *)2498 sal_Bool lcl_BoxSetHeadCondColl( const SwTableBox*& rpBox, void* )
2499 {
2500 	// in der HeadLine sind die Absaetze mit BedingtenVorlage anzupassen
2501 	const SwStartNode* pSttNd = rpBox->GetSttNd();
2502 	if( pSttNd )
2503 		pSttNd->CheckSectionCondColl();
2504 	else
2505 		((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_LineSetHeadCondColl, 0 );
2506 	return sal_True;
2507 }
2508 
lcl_LineSetHeadCondColl(const SwTableLine * & rpLine,void *)2509 sal_Bool lcl_LineSetHeadCondColl( const SwTableLine*& rpLine, void* )
2510 {
2511 	((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetHeadCondColl, 0 );
2512 	return sal_True;
2513 }
2514 
2515 /*  */
2516 
lcl_GetDistance(SwTableBox * pBox,sal_Bool bLeft)2517 SwTwips lcl_GetDistance( SwTableBox* pBox, sal_Bool bLeft )
2518 {
2519 	sal_Bool bFirst = sal_True;
2520 	SwTwips nRet = 0;
2521 	SwTableLine* pLine;
2522 	while( pBox && 0 != ( pLine = pBox->GetUpper() ) )
2523 	{
2524 		sal_uInt16 nStt = 0, nPos = pLine->GetTabBoxes().C40_GETPOS( SwTableBox, pBox );
2525 
2526 		if( bFirst && !bLeft )
2527 			++nPos;
2528 		bFirst = sal_False;
2529 
2530 		while( nStt < nPos )
2531 			nRet += pLine->GetTabBoxes()[ nStt++ ]->GetFrmFmt()
2532 							->GetFrmSize().GetWidth();
2533 		pBox = pLine->GetUpper();
2534 	}
2535 	return nRet;
2536 }
2537 
lcl_SetSelBoxWidth(SwTableLine * pLine,CR_SetBoxWidth & rParam,SwTwips nDist,sal_Bool bCheck)2538 sal_Bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2539 						 SwTwips nDist, sal_Bool bCheck )
2540 {
2541 	SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2542 	for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
2543 	{
2544 		SwTableBox* pBox = rBoxes[ n ];
2545 		SwFrmFmt* pFmt = pBox->GetFrmFmt();
2546 		const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
2547 		SwTwips nWidth = rSz.GetWidth();
2548         sal_Bool bGreaterBox = sal_False;
2549 
2550 		if( bCheck )
2551 		{
2552 			for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
2553 				if( !::lcl_SetSelBoxWidth( pBox->GetTabLines()[ i ], rParam,
2554 											nDist, sal_True ))
2555 					return sal_False;
2556 
2557             // dann noch mal alle "ContentBoxen" sammeln
2558             if( ( 0 != ( bGreaterBox = TBLFIX_CHGABS != rParam.nMode && ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) ||
2559                 ( !rParam.bBigger && ( Abs( nDist + (( rParam.nMode && rParam.bLeft ) ? 0 : nWidth ) - rParam.nSide ) < COLFUZZY ) ) )
2560             {
2561 				rParam.bAnyBoxFnd = sal_True;
2562 				SwTwips nLowerDiff;
2563 				if( bGreaterBox && TBLFIX_CHGPROP == rParam.nMode )
2564 				{
2565 					// die "anderen Boxen" wurden angepasst,
2566 					// also sich um diesen Betrag aendern
2567 					nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
2568 					nLowerDiff *= rParam.nDiff;
2569 					nLowerDiff /= rParam.nMaxSize;
2570 					nLowerDiff = rParam.nDiff - nLowerDiff;
2571 				}
2572 				else
2573 					nLowerDiff = rParam.nDiff;
2574 
2575 				if( nWidth < nLowerDiff || nWidth - nLowerDiff < MINLAY )
2576 					return sal_False;
2577 			}
2578 		}
2579 		else
2580 		{
2581 			SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2582 			for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
2583 			{
2584 				rParam.nLowerDiff = 0;
2585 				lcl_SetSelBoxWidth( pBox->GetTabLines()[ i ], rParam, nDist, sal_False );
2586 
2587 				if( nLowerDiff < rParam.nLowerDiff )
2588 					nLowerDiff = rParam.nLowerDiff;
2589 			}
2590 			rParam.nLowerDiff = nOldLower;
2591 
2592 
2593 			if( nLowerDiff ||
2594                  ( 0 != ( bGreaterBox = !nOldLower && TBLFIX_CHGABS != rParam.nMode &&
2595                     ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) ||
2596                 ( Abs( nDist + ( (rParam.nMode && rParam.bLeft) ? 0 : nWidth )
2597                             - rParam.nSide ) < COLFUZZY ))
2598 			{
2599 				// in dieser Spalte ist der Cursor - also verkleinern / vergroessern
2600 				SwFmtFrmSize aNew( rSz );
2601 
2602 				if( !nLowerDiff )
2603 				{
2604 					if( bGreaterBox && TBLFIX_CHGPROP == rParam.nMode )
2605 					{
2606 						// die "anderen Boxen" wurden angepasst,
2607 						// also sich um diesen Betrag aendern
2608 						nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
2609 						nLowerDiff *= rParam.nDiff;
2610 						nLowerDiff /= rParam.nMaxSize;
2611 						nLowerDiff = rParam.nDiff - nLowerDiff;
2612 					}
2613 					else
2614 						nLowerDiff = rParam.nDiff;
2615 				}
2616 
2617 				rParam.nLowerDiff += nLowerDiff;
2618 
2619 				if( rParam.bBigger )
2620 					aNew.SetWidth( nWidth + nLowerDiff );
2621 				else
2622 					aNew.SetWidth( nWidth - nLowerDiff );
2623 				rParam.aShareFmts.SetSize( *pBox, aNew );
2624 				break;
2625 			}
2626 		}
2627 
2628 		if( rParam.bLeft && rParam.nMode && nDist >= rParam.nSide )
2629 			break;
2630 
2631 		nDist += nWidth;
2632 
2633 		// wenns groesser wird, dann wars das
2634 		if( ( TBLFIX_CHGABS == rParam.nMode || !rParam.bLeft ) &&
2635 				nDist >= rParam.nSide )
2636 			break;
2637 	}
2638 	return sal_True;
2639 }
2640 
lcl_SetOtherBoxWidth(SwTableLine * pLine,CR_SetBoxWidth & rParam,SwTwips nDist,sal_Bool bCheck)2641 sal_Bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2642 								SwTwips nDist, sal_Bool bCheck )
2643 {
2644 	SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2645 	for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
2646 	{
2647 		SwTableBox* pBox = rBoxes[ n ];
2648 		SwFrmFmt* pFmt = pBox->GetFrmFmt();
2649 		const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
2650 		SwTwips nWidth = rSz.GetWidth();
2651 
2652 		if( bCheck )
2653 		{
2654 			for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
2655 				if( !::lcl_SetOtherBoxWidth( pBox->GetTabLines()[ i ],
2656 													rParam, nDist, sal_True ))
2657 					return sal_False;
2658 
2659 			if( rParam.bBigger && ( TBLFIX_CHGABS == rParam.nMode
2660 					? Abs( nDist - rParam.nSide ) < COLFUZZY
2661 					: ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
2662 									 : nDist >= rParam.nSide - COLFUZZY )) )
2663 			{
2664 				rParam.bAnyBoxFnd = sal_True;
2665 				SwTwips nDiff;
2666 				if( TBLFIX_CHGPROP == rParam.nMode )		// Tabelle fix, proport.
2667 				{
2668 					// relativ berechnen
2669 					nDiff = nWidth;
2670 					nDiff *= rParam.nDiff;
2671 					nDiff /= rParam.nMaxSize;
2672 				}
2673 				else
2674 					nDiff = rParam.nDiff;
2675 
2676 				if( nWidth < nDiff || nWidth - nDiff < MINLAY )
2677 					return sal_False;
2678 			}
2679 		}
2680 		else
2681 		{
2682 			SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2683 			for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
2684 			{
2685 				rParam.nLowerDiff = 0;
2686 				lcl_SetOtherBoxWidth( pBox->GetTabLines()[ i ], rParam,
2687 											nDist, sal_False );
2688 
2689 				if( nLowerDiff < rParam.nLowerDiff )
2690 					nLowerDiff = rParam.nLowerDiff;
2691 			}
2692 			rParam.nLowerDiff = nOldLower;
2693 
2694 			if( nLowerDiff ||
2695 				( TBLFIX_CHGABS == rParam.nMode
2696 						? Abs( nDist - rParam.nSide ) < COLFUZZY
2697 						: ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
2698 										 : nDist >= rParam.nSide - COLFUZZY)
2699 				 ) )
2700 			{
2701 				SwFmtFrmSize aNew( rSz );
2702 
2703 				if( !nLowerDiff )
2704 				{
2705 					if( TBLFIX_CHGPROP == rParam.nMode )		// Tabelle fix, proport.
2706 					{
2707 						// relativ berechnen
2708 						nLowerDiff = nWidth;
2709 						nLowerDiff *= rParam.nDiff;
2710 						nLowerDiff /= rParam.nMaxSize;
2711 					}
2712 					else
2713 						nLowerDiff = rParam.nDiff;
2714 				}
2715 
2716 				rParam.nLowerDiff += nLowerDiff;
2717 
2718 				if( rParam.bBigger )
2719 					aNew.SetWidth( nWidth - nLowerDiff );
2720 				else
2721 					aNew.SetWidth( nWidth + nLowerDiff );
2722 
2723 				rParam.aShareFmts.SetSize( *pBox, aNew );
2724 			}
2725 		}
2726 
2727 		nDist += nWidth;
2728 		if( ( TBLFIX_CHGABS == rParam.nMode || rParam.bLeft ) &&
2729 			nDist > rParam.nSide )
2730 			break;
2731 	}
2732 	return sal_True;
2733 }
2734 
2735 /**/
2736 
lcl_InsSelBox(SwTableLine * pLine,CR_SetBoxWidth & rParam,SwTwips nDist,sal_Bool bCheck)2737 sal_Bool lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2738 							SwTwips nDist, sal_Bool bCheck )
2739 {
2740 	SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2741 	sal_uInt16 n, nCmp;
2742 	for( n = 0; n < rBoxes.Count(); ++n )
2743 	{
2744 		SwTableBox* pBox = rBoxes[ n ];
2745 		SwTableBoxFmt* pFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
2746 		const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
2747 		SwTwips nWidth = rSz.GetWidth();
2748 
2749 		if( bCheck )
2750 		{
2751 			for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
2752 				if( !::lcl_InsSelBox( pBox->GetTabLines()[ i ], rParam,
2753 											nDist, sal_True ))
2754 					return sal_False;
2755 
2756 			// dann noch mal alle "ContentBoxen" sammeln
2757 			if( Abs( nDist + ( rParam.bLeft ? 0 : nWidth )
2758 					- rParam.nSide ) < COLFUZZY )
2759 				nCmp = 1;
2760 			else if( nDist + ( rParam.bLeft ? 0 : nWidth/2 ) > rParam.nSide )
2761 				nCmp = 2;
2762 			else
2763 				nCmp = 0;
2764 
2765 			if( nCmp )
2766 			{
2767 				rParam.bAnyBoxFnd = sal_True;
2768 				if( pFmt->GetProtect().IsCntntProtected() )
2769 					return sal_False;
2770 
2771 				if( rParam.bSplittBox &&
2772 					nWidth - rParam.nDiff <= COLFUZZY +
2773 						( 567 / 2 /* min. 0,5 cm Platz lassen*/) )
2774 					return sal_False;
2775 
2776 				if( pBox->GetSttNd() )
2777 					rParam.aBoxes.Insert( pBox );
2778 
2779 				break;
2780 			}
2781 		}
2782 		else
2783 		{
2784 			SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2785 			for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
2786 			{
2787 				rParam.nLowerDiff = 0;
2788 				lcl_InsSelBox( pBox->GetTabLines()[ i ], rParam, nDist, sal_False );
2789 
2790 				if( nLowerDiff < rParam.nLowerDiff )
2791 					nLowerDiff = rParam.nLowerDiff;
2792 			}
2793 			rParam.nLowerDiff = nOldLower;
2794 
2795 			if( nLowerDiff )
2796 				nCmp = 1;
2797 			else if( Abs( nDist + ( rParam.bLeft ? 0 : nWidth )
2798 								- rParam.nSide ) < COLFUZZY )
2799 				nCmp = 2;
2800 			else if( nDist + nWidth / 2 > rParam.nSide )
2801 				nCmp = 3;
2802 			else
2803 				nCmp = 0;
2804 
2805 			if( nCmp )
2806 			{
2807 				// in dieser Spalte ist der Cursor - also verkleinern / vergroessern
2808 				if( 1 == nCmp )
2809 				{
2810 					if( !rParam.bSplittBox )
2811 					{
2812 						// die akt. Box auf
2813 						SwFmtFrmSize aNew( rSz );
2814 						aNew.SetWidth( nWidth + rParam.nDiff );
2815 						rParam.aShareFmts.SetSize( *pBox, aNew );
2816 					}
2817 				}
2818 				else
2819 				{
2820 					ASSERT( pBox->GetSttNd(), "Das muss eine EndBox sein!");
2821 
2822 					if( !rParam.bLeft && 3 != nCmp )
2823 						++n;
2824 
2825 					::_InsTblBox( pFmt->GetDoc(), rParam.pTblNd,
2826 										pLine, pFmt, pBox, n );
2827 
2828 					SwTableBox* pNewBox = rBoxes[ n ];
2829 					SwFmtFrmSize aNew( rSz );
2830 					aNew.SetWidth( rParam.nDiff );
2831 					rParam.aShareFmts.SetSize( *pNewBox, aNew );
2832 
2833 					// Sonderfall: kein Platz in den anderen Boxen
2834 					//				aber in der Zelle
2835 					if( rParam.bSplittBox )
2836 					{
2837 						// die akt. Box auf
2838 						SwFmtFrmSize aNewSize( rSz );
2839 						aNewSize.SetWidth( nWidth - rParam.nDiff );
2840 						rParam.aShareFmts.SetSize( *pBox, aNewSize );
2841 					}
2842 
2843 					// Sonderbehandlung fuer Umrandung die Rechte muss
2844 					// entfernt werden
2845 					{
2846 						const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
2847 						if( rBoxItem.GetRight() )
2848 						{
2849 							SvxBoxItem aTmp( rBoxItem );
2850 							aTmp.SetLine( 0, BOX_LINE_RIGHT );
2851                             rParam.aShareFmts.SetAttr( rParam.bLeft
2852 															? *pNewBox
2853 															: *pBox, aTmp );
2854 						}
2855 					}
2856 				}
2857 
2858 				rParam.nLowerDiff = rParam.nDiff;
2859 				break;
2860 			}
2861 		}
2862 
2863 		if( rParam.bLeft && rParam.nMode && nDist >= rParam.nSide )
2864 			break;
2865 
2866 		nDist += nWidth;
2867 	}
2868 	return sal_True;
2869 }
2870 
lcl_InsOtherBox(SwTableLine * pLine,CR_SetBoxWidth & rParam,SwTwips nDist,sal_Bool bCheck)2871 sal_Bool lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2872 								SwTwips nDist, sal_Bool bCheck )
2873 {
2874 	// Sonderfall: kein Platz in den anderen Boxen aber in der Zelle
2875 	if( rParam.bSplittBox )
2876 		return sal_True;
2877 
2878 	SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2879 	sal_uInt16 n;
2880 
2881 	// Tabelle fix, proport.
2882 	if( !rParam.nRemainWidth && TBLFIX_CHGPROP == rParam.nMode )
2883 	{
2884 		// dann die richtige Breite suchen, auf die sich die relative
2885 		// Breitenanpassung bezieht.
2886 		SwTwips nTmpDist = nDist;
2887 		for( n = 0; n < rBoxes.Count(); ++n )
2888 		{
2889 			SwTwips nWidth = rBoxes[ n ]->GetFrmFmt()->GetFrmSize().GetWidth();
2890 			if( (nTmpDist + nWidth / 2 ) > rParam.nSide )
2891 			{
2892 				rParam.nRemainWidth = rParam.bLeft
2893 										? sal_uInt16(nTmpDist)
2894 										: sal_uInt16(rParam.nTblWidth - nTmpDist);
2895 				break;
2896 			}
2897 			nTmpDist += nWidth;
2898 		}
2899 	}
2900 
2901 	for( n = 0; n < rBoxes.Count(); ++n )
2902 	{
2903 		SwTableBox* pBox = rBoxes[ n ];
2904 		SwFrmFmt* pFmt = pBox->GetFrmFmt();
2905 		const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
2906 		SwTwips nWidth = rSz.GetWidth();
2907 
2908 		if( bCheck )
2909 		{
2910 			for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
2911 				if( !::lcl_InsOtherBox( pBox->GetTabLines()[ i ],
2912 													rParam, nDist, sal_True ))
2913 					return sal_False;
2914 
2915 			if(
2916 				rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide &&
2917 								(TBLFIX_CHGABS != rParam.nMode ||
2918 								(n < rBoxes.Count() &&
2919 								(nDist + nWidth + rBoxes[ n+1 ]->
2920 									GetFrmFmt()->GetFrmSize().GetWidth() / 2)
2921 								  > rParam.nSide) ))
2922 							 : (nDist + nWidth / 2 ) > rParam.nSide
2923 				)
2924 			{
2925 				rParam.bAnyBoxFnd = sal_True;
2926 				SwTwips nDiff;
2927 				if( TBLFIX_CHGPROP == rParam.nMode )		// Tabelle fix, proport.
2928 				{
2929 					// relativ berechnen
2930 					nDiff = nWidth;
2931 					nDiff *= rParam.nDiff;
2932 					nDiff /= rParam.nRemainWidth;
2933 
2934 					if( nWidth < nDiff || nWidth - nDiff < MINLAY )
2935 						return sal_False;
2936 				}
2937 				else
2938 				{
2939 					nDiff = rParam.nDiff;
2940 
2941 					// teste ob die linke oder rechte Box gross genug
2942 					// ist, um den Platz abzugeben!
2943 					// es wird davor oder dahinter eine Box eingefuegt!
2944 					SwTwips nTmpWidth = nWidth;
2945 					if( rParam.bLeft && pBox->GetUpper()->GetUpper() )
2946 					{
2947 						const SwTableBox* pTmpBox = pBox;
2948 						sal_uInt16 nBoxPos = n;
2949 						while( !nBoxPos && pTmpBox->GetUpper()->GetUpper() )
2950 						{
2951 							pTmpBox = pTmpBox->GetUpper()->GetUpper();
2952 							nBoxPos = pTmpBox->GetUpper()->GetTabBoxes().GetPos( pTmpBox );
2953 						}
2954 //						if( nBoxPos )
2955 							nTmpWidth = pTmpBox->GetFrmFmt()->GetFrmSize().GetWidth();
2956 //						else
2957 //							nTmpWidth = 0;
2958 					}
2959 
2960 					if( nTmpWidth < nDiff || nTmpWidth - nDiff < MINLAY )
2961 						return sal_False;
2962 					break;
2963 				}
2964 			}
2965 		}
2966 		else
2967 		{
2968 			SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2969 			for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
2970 			{
2971 				rParam.nLowerDiff = 0;
2972 				lcl_InsOtherBox( pBox->GetTabLines()[ i ], rParam,
2973 										nDist, sal_False );
2974 
2975 				if( nLowerDiff < rParam.nLowerDiff )
2976 					nLowerDiff = rParam.nLowerDiff;
2977 			}
2978 			rParam.nLowerDiff = nOldLower;
2979 
2980 			if( nLowerDiff ||
2981 				(rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide &&
2982 								(TBLFIX_CHGABS != rParam.nMode ||
2983 								(n < rBoxes.Count() &&
2984 								(nDist + nWidth + rBoxes[ n+1 ]->
2985 									GetFrmFmt()->GetFrmSize().GetWidth() / 2)
2986 								  > rParam.nSide) ))
2987 							  : (nDist + nWidth / 2 ) > rParam.nSide ))
2988 			{
2989 				if( !nLowerDiff )
2990 				{
2991 					if( TBLFIX_CHGPROP == rParam.nMode )		// Tabelle fix, proport.
2992 					{
2993 						// relativ berechnen
2994 						nLowerDiff = nWidth;
2995 						nLowerDiff *= rParam.nDiff;
2996 						nLowerDiff /= rParam.nRemainWidth;
2997 					}
2998 					else
2999 						nLowerDiff = rParam.nDiff;
3000 				}
3001 
3002 				SwFmtFrmSize aNew( rSz );
3003 				rParam.nLowerDiff += nLowerDiff;
3004 
3005 				if( rParam.bBigger )
3006 					aNew.SetWidth( nWidth - nLowerDiff );
3007 				else
3008 					aNew.SetWidth( nWidth + nLowerDiff );
3009 				rParam.aShareFmts.SetSize( *pBox, aNew );
3010 
3011 				if( TBLFIX_CHGABS == rParam.nMode )
3012 					break;
3013 			}
3014 		}
3015 
3016 		nDist += nWidth;
3017 	}
3018 	return sal_True;
3019 }
3020 
3021 
3022 // das Ergebnis des Positions Vergleiches
3023 //	POS_BEFORE,				// Box liegt davor
3024 //	POS_BEHIND,				// Box liegt dahinter
3025 //	POS_INSIDE,				// Box liegt vollstaendig in Start/End
3026 //	POS_OUTSIDE,			// Box ueberlappt Start/End vollstaendig
3027 //	POS_EQUAL,				// Box und Start/End sind gleich
3028 //	POS_OVERLAP_BEFORE,		// Box ueberlappt den Start
3029 //	POS_OVERLAP_BEHIND 		// Box ueberlappt das Ende
3030 
_CheckBoxInRange(sal_uInt16 nStt,sal_uInt16 nEnd,sal_uInt16 nBoxStt,sal_uInt16 nBoxEnd)3031 SwComparePosition _CheckBoxInRange( sal_uInt16 nStt, sal_uInt16 nEnd,
3032 									sal_uInt16 nBoxStt, sal_uInt16 nBoxEnd )
3033 {
3034 // COLFUZZY noch beachten!!
3035 	SwComparePosition nRet;
3036 	if( nBoxStt + COLFUZZY < nStt )
3037 	{
3038 		if( nBoxEnd > nStt + COLFUZZY )
3039 		{
3040 			if( nBoxEnd >= nEnd + COLFUZZY )
3041 				nRet = POS_OUTSIDE;
3042 			else
3043 				nRet = POS_OVERLAP_BEFORE;
3044 		}
3045 		else
3046 			nRet = POS_BEFORE;
3047 	}
3048 	else if( nEnd > nBoxStt + COLFUZZY )
3049 	{
3050 		if( nEnd + COLFUZZY >= nBoxEnd )
3051 		{
3052 			if( COLFUZZY > Abs( long(nEnd) - long(nBoxEnd) ) &&
3053 				COLFUZZY > Abs( long(nStt) - long(nBoxStt) ) )
3054 				nRet = POS_EQUAL;
3055 			else
3056 				nRet = POS_INSIDE;
3057 		}
3058 		else
3059 			nRet = POS_OVERLAP_BEHIND;
3060 	}
3061 	else
3062 		nRet = POS_BEHIND;
3063 
3064 	return nRet;
3065 }
3066 
lcl_DelSelBox_CorrLowers(SwTableLine & rLine,CR_SetBoxWidth & rParam,SwTwips nWidth)3067 void lcl_DelSelBox_CorrLowers( SwTableLine& rLine, CR_SetBoxWidth& rParam,
3068 								SwTwips nWidth )
3069 {
3070 	// 1. Schritt die eigene Breite feststellen
3071 	SwTableBoxes& rBoxes = rLine.GetTabBoxes();
3072 	SwTwips nBoxWidth = 0;
3073 	sal_uInt16 n;
3074 
3075 	for( n = rBoxes.Count(); n; )
3076 		nBoxWidth += rBoxes[ --n ]->GetFrmFmt()->GetFrmSize().GetWidth();
3077 
3078 	if( COLFUZZY < Abs( nWidth - nBoxWidth ))
3079 	{
3080 		//  sie muessen also angepasst werden
3081 		for( n = rBoxes.Count(); n; )
3082 		{
3083 			SwTableBox* pBox = rBoxes[ --n ];
3084 			SwFmtFrmSize aNew( pBox->GetFrmFmt()->GetFrmSize() );
3085 			long nDiff = aNew.GetWidth();
3086 			nDiff *= nWidth;
3087 			nDiff /= nBoxWidth;
3088 			aNew.SetWidth( nDiff );
3089 
3090 			rParam.aShareFmts.SetSize( *pBox, aNew );
3091 
3092 			if( !pBox->GetSttNd() )
3093 			{
3094 				// hat selbst auch Lower, also auch die anpassen
3095 				for( sal_uInt16 i = pBox->GetTabLines().Count(); i; )
3096 					::lcl_DelSelBox_CorrLowers( *pBox->GetTabLines()[ --i ],
3097 												rParam, nDiff  );
3098 			}
3099 		}
3100 	}
3101 }
3102 
lcl_ChgBoxSize(SwTableBox & rBox,CR_SetBoxWidth & rParam,const SwFmtFrmSize & rOldSz,sal_uInt16 & rDelWidth,SwTwips nDist)3103 void lcl_ChgBoxSize( SwTableBox& rBox, CR_SetBoxWidth& rParam,
3104 					const SwFmtFrmSize& rOldSz,
3105 					sal_uInt16& rDelWidth, SwTwips nDist )
3106 {
3107 	long nDiff = 0;
3108 	sal_Bool bSetSize = sal_False;
3109 
3110 	switch( rParam.nMode )
3111 	{
3112 	case TBLFIX_CHGABS:		// Tabelle feste Breite, den Nachbar andern
3113 		nDiff = rDelWidth + rParam.nLowerDiff;
3114 		bSetSize = sal_True;
3115 		break;
3116 
3117 	case TBLFIX_CHGPROP:	// Tabelle feste Breite, alle Nachbarn aendern
3118 		if( !rParam.nRemainWidth )
3119 		{
3120 			// dann kurz berechnen:
3121 			if( rParam.bLeft )
3122 				rParam.nRemainWidth = sal_uInt16(nDist);
3123 			else
3124 				rParam.nRemainWidth = sal_uInt16(rParam.nTblWidth - nDist);
3125 		}
3126 
3127 		// relativ berechnen
3128 		nDiff = rOldSz.GetWidth();
3129 		nDiff *= rDelWidth + rParam.nLowerDiff;
3130 		nDiff /= rParam.nRemainWidth;
3131 
3132 		bSetSize = sal_True;
3133 		break;
3134 
3135 	case TBLVAR_CHGABS:		// Tabelle variable, alle Nachbarn aendern
3136 		if( COLFUZZY < Abs( rParam.nBoxWidth -
3137 							( rDelWidth + rParam.nLowerDiff )))
3138 		{
3139 			nDiff = rDelWidth + rParam.nLowerDiff - rParam.nBoxWidth;
3140 			if( 0 < nDiff )
3141 				rDelWidth = rDelWidth - sal_uInt16(nDiff);
3142 			else
3143 				rDelWidth = rDelWidth + sal_uInt16(-nDiff);
3144 			bSetSize = sal_True;
3145 		}
3146 		break;
3147 	}
3148 
3149 	if( bSetSize )
3150 	{
3151 		SwFmtFrmSize aNew( rOldSz );
3152 		aNew.SetWidth( aNew.GetWidth() + nDiff );
3153 		rParam.aShareFmts.SetSize( rBox, aNew );
3154 
3155 		// dann leider nochmals die Lower anpassen
3156 		for( sal_uInt16 i = rBox.GetTabLines().Count(); i; )
3157 			::lcl_DelSelBox_CorrLowers( *rBox.GetTabLines()[ --i ], rParam,
3158 											aNew.GetWidth() );
3159 	}
3160 }
3161 
lcl_DeleteBox_Rekursiv(CR_SetBoxWidth & rParam,SwTableBox & rBox,sal_Bool bCheck)3162 sal_Bool lcl_DeleteBox_Rekursiv( CR_SetBoxWidth& rParam, SwTableBox& rBox,
3163 							sal_Bool bCheck )
3164 {
3165 	sal_Bool bRet = sal_True;
3166 	if( rBox.GetSttNd() )
3167 	{
3168 		if( bCheck )
3169 		{
3170 			rParam.bAnyBoxFnd = sal_True;
3171 			if( rBox.GetFrmFmt()->GetProtect().IsCntntProtected() )
3172 				bRet = sal_False;
3173 			else
3174 			{
3175 				SwTableBox* pBox = &rBox;
3176 				rParam.aBoxes.Insert( pBox );
3177 			}
3178 		}
3179 		else
3180 			::_DeleteBox( rParam.pTblNd->GetTable(), &rBox,
3181 							rParam.pUndo, sal_False, sal_True, &rParam.aShareFmts );
3182 	}
3183 	else
3184 	{
3185 		// die muessen leider alle sequentiel ueber die
3186 		// Contentboxen geloescht werden
3187 		for( sal_uInt16 i = rBox.GetTabLines().Count(); i; )
3188 		{
3189 			SwTableLine& rLine = *rBox.GetTabLines()[ --i ];
3190 			for( sal_uInt16 n = rLine.GetTabBoxes().Count(); n; )
3191 				if( !::lcl_DeleteBox_Rekursiv( rParam,
3192 								*rLine.GetTabBoxes()[ --n ], bCheck ))
3193 					return sal_False;
3194 		}
3195 	}
3196 	return bRet;
3197 }
3198 
lcl_DelSelBox(SwTableLine * pTabLine,CR_SetBoxWidth & rParam,SwTwips nDist,sal_Bool bCheck)3199 sal_Bool lcl_DelSelBox( SwTableLine* pTabLine, CR_SetBoxWidth& rParam,
3200 					SwTwips nDist, sal_Bool bCheck )
3201 {
3202 	SwTableBoxes& rBoxes = pTabLine->GetTabBoxes();
3203 	sal_uInt16 n, nCntEnd, nBoxChkStt, nBoxChkEnd, nDelWidth = 0;
3204 	if( rParam.bLeft )
3205 	{
3206 		n = rBoxes.Count();
3207 		nCntEnd = 0;
3208 		nBoxChkStt = (sal_uInt16)rParam.nSide;
3209 		nBoxChkEnd = static_cast<sal_uInt16>(rParam.nSide + rParam.nBoxWidth);
3210 	}
3211 	else
3212 	{
3213 		n = 0;
3214 		nCntEnd = rBoxes.Count();
3215 		nBoxChkStt = static_cast<sal_uInt16>(rParam.nSide - rParam.nBoxWidth);
3216 		nBoxChkEnd = (sal_uInt16)rParam.nSide;
3217 	}
3218 
3219 
3220 	while( n != nCntEnd )
3221 	{
3222 		SwTableBox* pBox;
3223 		if( rParam.bLeft )
3224 			pBox = rBoxes[ --n ];
3225 		else
3226 			pBox = rBoxes[ n++ ];
3227 
3228 		SwFrmFmt* pFmt = pBox->GetFrmFmt();
3229 		const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
3230 		long nWidth = rSz.GetWidth();
3231 		sal_Bool bDelBox = sal_False, bChgLowers = sal_False;
3232 
3233 		// die Boxenbreite testen und entpsrechend reagieren
3234 		SwComparePosition ePosType = ::_CheckBoxInRange(
3235 							nBoxChkStt, nBoxChkEnd,
3236 							sal_uInt16(rParam.bLeft ? nDist - nWidth : nDist),
3237 							sal_uInt16(rParam.bLeft ? nDist : nDist + nWidth));
3238 
3239 		switch( ePosType )
3240 		{
3241 		case POS_BEFORE:
3242 			if( bCheck )
3243 			{
3244 				if( rParam.bLeft )
3245 					return sal_True;
3246 			}
3247 			else if( rParam.bLeft )
3248 			{
3249 				::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist );
3250 				if( TBLFIX_CHGABS == rParam.nMode )
3251 					n = nCntEnd;
3252 			}
3253 			break;
3254 
3255 		case POS_BEHIND:
3256 			if( bCheck )
3257 			{
3258 				if( !rParam.bLeft )
3259 					return sal_True;
3260 			}
3261 			else if( !rParam.bLeft )
3262 			{
3263 				::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist );
3264 				if( TBLFIX_CHGABS == rParam.nMode )
3265 					n = nCntEnd;
3266 			}
3267 			break;
3268 
3269 		case POS_OUTSIDE:			// Box ueberlappt Start/End vollstaendig
3270 		case POS_INSIDE:			// Box liegt vollstaendig in Start/End
3271 		case POS_EQUAL:				// Box und Start/End sind gleich
3272 			bDelBox = sal_True;
3273 			break;
3274 
3275 		case POS_OVERLAP_BEFORE:	 // Box ueberlappt den Start
3276 			if( nBoxChkStt <= ( nDist + (rParam.bLeft ? - nWidth / 2
3277 													  : nWidth / 2 )))
3278 			{
3279 				if( !pBox->GetSttNd() )
3280 					bChgLowers = sal_True;
3281 				else
3282 					bDelBox = sal_True;
3283 			}
3284 			else if( !bCheck && rParam.bLeft )
3285 			{
3286 				if( !pBox->GetSttNd() )
3287 					bChgLowers = sal_True;
3288 				else
3289 				{
3290 					::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist );
3291 					if( TBLFIX_CHGABS == rParam.nMode )
3292 						n = nCntEnd;
3293 				}
3294 			}
3295 			break;
3296 
3297 		case POS_OVERLAP_BEHIND: 	 // Box ueberlappt das Ende
3298 			// JP 10.02.99:
3299 			// generell loeschen oder wie beim OVERLAP_Before nur die, die
3300 			// bis zur Haelfte in die "Loesch-"Box reicht ???
3301 			if( !pBox->GetSttNd() )
3302 				bChgLowers = sal_True;
3303 			else
3304 				bDelBox = sal_True;
3305 			break;
3306         default: break;
3307 		}
3308 
3309 		if( bDelBox )
3310 		{
3311 			nDelWidth = nDelWidth + sal_uInt16(nWidth);
3312 			if( bCheck )
3313 			{
3314 				// die letzte/erste Box kann nur bei Tbl-Var geloescht werden,
3315 				// wenn diese so gross ist, wie die Aenderung an der Tabelle
3316 				if( (( TBLVAR_CHGABS != rParam.nMode ||
3317 						nDelWidth != rParam.nBoxWidth ) &&
3318 					 COLFUZZY > Abs( rParam.bLeft
3319 									? nWidth - nDist
3320 									: (nDist + nWidth - rParam.nTblWidth )))
3321 					|| !::lcl_DeleteBox_Rekursiv( rParam, *pBox, bCheck ) )
3322 					return sal_False;
3323 
3324 				if( pFmt->GetProtect().IsCntntProtected() )
3325 					return sal_False;
3326 			}
3327 			else
3328 			{
3329 				::lcl_DeleteBox_Rekursiv( rParam, *pBox, bCheck );
3330 
3331 				if( !rParam.bLeft )
3332 					--n, --nCntEnd;
3333 			}
3334 		}
3335 		else if( bChgLowers )
3336 		{
3337 			sal_Bool bFirst = sal_True, bCorrLowers = sal_False;
3338 			long nLowerDiff = 0;
3339 			long nOldLower = rParam.nLowerDiff;
3340 			sal_uInt16 nOldRemain = rParam.nRemainWidth;
3341 			sal_uInt16 i;
3342 
3343 			for( i = pBox->GetTabLines().Count(); i; )
3344 			{
3345 				rParam.nLowerDiff = nDelWidth + nOldLower;
3346 				rParam.nRemainWidth = nOldRemain;
3347 				SwTableLine* pLine = pBox->GetTabLines()[ --i ];
3348 				if( !::lcl_DelSelBox( pLine, rParam, nDist, bCheck ))
3349 					return sal_False;
3350 
3351 				// gibt es die Box und die darin enthaltenen Lines noch??
3352 				if( n < rBoxes.Count() &&
3353 					pBox == rBoxes[ rParam.bLeft ? n : n-1 ] &&
3354 					i < pBox->GetTabLines().Count() &&
3355 					pLine == pBox->GetTabLines()[ i ] )
3356 				{
3357 					if( !bFirst && !bCorrLowers &&
3358 						COLFUZZY < Abs( nLowerDiff - rParam.nLowerDiff ) )
3359 						bCorrLowers = sal_True;
3360 
3361 					// die groesste "loesch" Breite entscheidet, aber nur wenn
3362 					// nicht die gesamte Line geloescht wurde
3363 					if( nLowerDiff < rParam.nLowerDiff )
3364 						nLowerDiff = rParam.nLowerDiff;
3365 
3366 					bFirst = sal_False;
3367 				}
3368 			}
3369 			rParam.nLowerDiff = nOldLower;
3370 			rParam.nRemainWidth = nOldRemain;
3371 
3372 			// wurden alle Boxen geloescht? Dann ist die DelBreite natuerlich
3373 			// die Boxenbreite
3374 			if( !nLowerDiff )
3375 				nLowerDiff = nWidth;
3376 
3377 			// DelBreite anpassen!!
3378 			nDelWidth = nDelWidth + sal_uInt16(nLowerDiff);
3379 
3380 			if( !bCheck )
3381 			{
3382 				// wurde die Box schon entfernt?
3383 				if( n > rBoxes.Count() ||
3384 					pBox != rBoxes[ ( rParam.bLeft ? n : n-1 ) ] )
3385 				{
3386 					// dann beim Loeschen nach rechts die Laufvar. anpassen
3387 					if( !rParam.bLeft )
3388 						--n, --nCntEnd;
3389 				}
3390 				else
3391 				{
3392 					// sonst muss die Groesse der Box angepasst werden
3393 					SwFmtFrmSize aNew( rSz );
3394 					sal_Bool bCorrRel = sal_False;
3395 
3396 					if( TBLVAR_CHGABS != rParam.nMode )
3397 					{
3398 						switch( ePosType )
3399 						{
3400 						case POS_OVERLAP_BEFORE:	// Box ueberlappt den Start
3401 							if( TBLFIX_CHGPROP == rParam.nMode )
3402 								bCorrRel = rParam.bLeft;
3403 							else if( rParam.bLeft )	// TBLFIX_CHGABS
3404 							{
3405 								nLowerDiff = nLowerDiff - nDelWidth;
3406 								bCorrLowers = sal_True;
3407 								n = nCntEnd;
3408 							}
3409 							break;
3410 
3411 						case POS_OVERLAP_BEHIND: 	// Box ueberlappt das Ende
3412 							if( TBLFIX_CHGPROP == rParam.nMode )
3413 								bCorrRel = !rParam.bLeft;
3414 							else if( !rParam.bLeft )	// TBLFIX_CHGABS
3415 							{
3416 								nLowerDiff = nLowerDiff - nDelWidth;
3417 								bCorrLowers = sal_True;
3418 								n = nCntEnd;
3419 							}
3420 							break;
3421 
3422 						default:
3423 							ASSERT( !pBox, "hier sollte man nie hinkommen" );
3424 							break;
3425 						}
3426 					}
3427 
3428 					if( bCorrRel )
3429 					{
3430 						if( !rParam.nRemainWidth )
3431 						{
3432 							// dann kurz berechnen:
3433 							if( rParam.bLeft )
3434 								rParam.nRemainWidth = sal_uInt16(nDist - nLowerDiff);
3435 							else
3436 								rParam.nRemainWidth = sal_uInt16(rParam.nTblWidth - nDist
3437 																- nLowerDiff );
3438 						}
3439 
3440 						long nDiff = aNew.GetWidth() - nLowerDiff;
3441 						nDiff *= nDelWidth + rParam.nLowerDiff;
3442 						nDiff /= rParam.nRemainWidth;
3443 
3444 						aNew.SetWidth( aNew.GetWidth() - nLowerDiff + nDiff );
3445 					}
3446 					else
3447 						aNew.SetWidth( aNew.GetWidth() - nLowerDiff );
3448 					rParam.aShareFmts.SetSize( *pBox, aNew );
3449 
3450 					if( bCorrLowers )
3451 					{
3452 						// dann leider nochmals die Lower anpassen
3453 						for( i = pBox->GetTabLines().Count(); i; )
3454 							::lcl_DelSelBox_CorrLowers( *pBox->
3455 								GetTabLines()[ --i ], rParam, aNew.GetWidth() );
3456 					}
3457 				}
3458 			}
3459 		}
3460 
3461 		if( rParam.bLeft )
3462 			nDist -= nWidth;
3463 		else
3464 			nDist += nWidth;
3465 	}
3466 	rParam.nLowerDiff = nDelWidth;
3467 	return sal_True;
3468 }
3469 
3470 // Dummy Funktion fuer die Methode SetColWidth
lcl_DelOtherBox(SwTableLine *,CR_SetBoxWidth &,SwTwips,sal_Bool)3471 sal_Bool lcl_DelOtherBox( SwTableLine* , CR_SetBoxWidth& , SwTwips , sal_Bool )
3472 {
3473 	return sal_True;
3474 }
3475 
3476 /**/
3477 
lcl_AjustLines(SwTableLine * pLine,CR_SetBoxWidth & rParam)3478 void lcl_AjustLines( SwTableLine* pLine, CR_SetBoxWidth& rParam )
3479 {
3480 	SwTableBoxes& rBoxes = pLine->GetTabBoxes();
3481 	for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
3482 	{
3483 		SwTableBox* pBox = rBoxes[ n ];
3484 
3485 		SwFmtFrmSize aSz( pBox->GetFrmFmt()->GetFrmSize() );
3486 		SwTwips nWidth = aSz.GetWidth();
3487 		nWidth *= rParam.nDiff;
3488 		nWidth /= rParam.nMaxSize;
3489 		aSz.SetWidth( nWidth );
3490 		rParam.aShareFmts.SetSize( *pBox, aSz );
3491 
3492 		for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
3493 			::lcl_AjustLines( pBox->GetTabLines()[ i ], rParam );
3494 	}
3495 }
3496 
3497 #if defined(DBG_UTIL) || defined( JP_DEBUG )
3498 
_CheckBoxWidth(const SwTableLine & rLine,SwTwips nSize)3499 void _CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize )
3500 {
3501 	const SwTableBoxes& rBoxes = rLine.GetTabBoxes();
3502 
3503 	SwTwips nAktSize = 0;
3504 	// checke doch mal ob die Tabellen korrekte Breiten haben
3505 	for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n  )
3506 	{
3507 		const SwTableBox* pBox = rBoxes[ n ];
3508 		const SwTwips nBoxW = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
3509 		nAktSize += nBoxW;
3510 
3511 		for( sal_uInt16 i = 0; i < pBox->GetTabLines().Count(); ++i )
3512 			_CheckBoxWidth( *pBox->GetTabLines()[ i ], nBoxW );
3513 	}
3514 
3515 	if( Abs( nAktSize - nSize ) > ( COLFUZZY * rBoxes.Count() ) )
3516 	{
3517 		DBG_ERROR( "Boxen der Line zu klein/gross" );
3518 #if defined( WNT ) && defined( JP_DEBUG )
3519 		__asm int 3;
3520 #endif
3521 	}
3522 }
3523 
3524 #endif
3525 
lcl_SaveInsDelData(CR_SetBoxWidth & rParam,SwUndo ** ppUndo,SwTableSortBoxes & rTmpLst,SwTwips nDistStt)3526 _FndBox* lcl_SaveInsDelData( CR_SetBoxWidth& rParam, SwUndo** ppUndo,
3527 								SwTableSortBoxes& rTmpLst, SwTwips nDistStt )
3528 {
3529 	// suche alle Boxen / Lines
3530 	SwTable& rTbl = rParam.pTblNd->GetTable();
3531 
3532 	if( !rParam.aBoxes.Count() )
3533 	{
3534 		// erstmal die Boxen besorgen !
3535 		if( rParam.bBigger )
3536 			for( sal_uInt16 n = 0; n < rTbl.GetTabLines().Count(); ++n )
3537 				::lcl_DelSelBox( rTbl.GetTabLines()[ n ], rParam, nDistStt, sal_True );
3538 		else
3539 			for( sal_uInt16 n = 0; n < rTbl.GetTabLines().Count(); ++n )
3540 				::lcl_InsSelBox( rTbl.GetTabLines()[ n ], rParam, nDistStt, sal_True );
3541 	}
3542 
3543 	// loeschen der gesamten Tabelle verhindern
3544 	if( rParam.bBigger && rParam.aBoxes.Count() ==
3545 		rTbl.GetTabSortBoxes().Count() )
3546 		return 0;
3547 
3548 	_FndBox* pFndBox = new _FndBox( 0, 0 );
3549 	if( rParam.bBigger )
3550 		pFndBox->SetTableLines( rParam.aBoxes, rTbl );
3551 	else
3552 	{
3553 		_FndPara aPara( rParam.aBoxes, pFndBox );
3554 		rTbl.GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
3555 		ASSERT( pFndBox->GetLines().Count(), "Wo sind die Boxen" );
3556 		pFndBox->SetTableLines( rTbl );
3557 
3558 		if( ppUndo )
3559 			rTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
3560 	}
3561 
3562 	//Lines fuer das Layout-Update herausuchen.
3563 	pFndBox->DelFrms( rTbl );
3564 
3565 	// TL_CHART2: this function gest called from SetColWidth exclusively,
3566 	// thus it is currently speculated that nothing needs to be done here.
3567 	// Note: that SetColWidth is currently not completely understood though :-(
3568 
3569 	return pFndBox;
3570 }
3571 
SetColWidth(SwTableBox & rAktBox,sal_uInt16 eType,SwTwips nAbsDiff,SwTwips nRelDiff,SwUndo ** ppUndo)3572 sal_Bool SwTable::SetColWidth( SwTableBox& rAktBox, sal_uInt16 eType,
3573 						SwTwips nAbsDiff, SwTwips nRelDiff, SwUndo** ppUndo )
3574 {
3575 	SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
3576 
3577 	const SwFmtFrmSize& rSz = GetFrmFmt()->GetFrmSize();
3578 	const SvxLRSpaceItem& rLR = GetFrmFmt()->GetLRSpace();
3579 
3580 	_FndBox* pFndBox = 0;					// fuers Einfuegen/Loeschen
3581 	SwTableSortBoxes aTmpLst( 0, 5 );		// fuers Undo
3582 	sal_Bool bBigger,
3583 		bRet = sal_False,
3584 		bLeft = nsTblChgWidthHeightType::WH_COL_LEFT == ( eType & 0xff ) ||
3585 				nsTblChgWidthHeightType::WH_CELL_LEFT == ( eType & 0xff ),
3586 		bInsDel = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL );
3587 	sal_uInt16 n;
3588 	sal_uLong nBoxIdx = rAktBox.GetSttIdx();
3589 
3590 	// bestimme die akt. Kante der Box
3591 	// wird nur fuer die Breitenmanipulation benoetigt!
3592 	const SwTwips nDist = ::lcl_GetDistance( &rAktBox, bLeft );
3593     SwTwips nDistStt = 0;
3594 	CR_SetBoxWidth aParam( eType, nRelDiff, nDist, rSz.GetWidth(),
3595 							bLeft ? nDist : rSz.GetWidth() - nDist,
3596 							(SwTableNode*)rAktBox.GetSttNd()->FindTableNode() );
3597 	bBigger = aParam.bBigger;
3598 
3599 	FN_lcl_SetBoxWidth fnSelBox, fnOtherBox;
3600 	if( bInsDel )
3601 	{
3602 		if( bBigger )
3603 		{
3604 			fnSelBox = lcl_DelSelBox;
3605 			fnOtherBox = lcl_DelOtherBox;
3606 			aParam.nBoxWidth = (sal_uInt16)rAktBox.GetFrmFmt()->GetFrmSize().GetWidth();
3607 			if( bLeft )
3608 				nDistStt = rSz.GetWidth();
3609 		}
3610 		else
3611 		{
3612 			fnSelBox = lcl_InsSelBox;
3613 			fnOtherBox = lcl_InsOtherBox;
3614 		}
3615 	}
3616 	else
3617 	{
3618 		fnSelBox = lcl_SetSelBoxWidth;
3619 		fnOtherBox = lcl_SetOtherBoxWidth;
3620 	}
3621 
3622 
3623 	switch( eType & 0xff )
3624 	{
3625 	case nsTblChgWidthHeightType::WH_COL_RIGHT:
3626 	case nsTblChgWidthHeightType::WH_COL_LEFT:
3627 		if( TBLVAR_CHGABS == eTblChgMode )
3628 		{
3629 			if( bInsDel )
3630 				bBigger = !bBigger;
3631 
3632 			// erstmal testen, ob ueberhaupt Platz ist
3633 			sal_Bool bChgLRSpace = sal_True;
3634 			if( bBigger )
3635 			{
3636                 if( GetFrmFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) &&
3637 					!rSz.GetWidthPercent() )
3638 				{
3639 					bRet = rSz.GetWidth() < USHRT_MAX - nRelDiff;
3640 					bChgLRSpace = bLeft ? rLR.GetLeft() >= nAbsDiff
3641 										: rLR.GetRight() >= nAbsDiff;
3642 				}
3643 				else
3644 					bRet = bLeft ? rLR.GetLeft() >= nAbsDiff
3645 								 : rLR.GetRight() >= nAbsDiff;
3646 
3647 				if( !bRet && bInsDel &&
3648 					// auf der anderen Seite Platz?
3649 					( bLeft ? rLR.GetRight() >= nAbsDiff
3650 							: rLR.GetLeft() >= nAbsDiff ))
3651 				{
3652 					bRet = sal_True; bLeft = !bLeft;
3653 				}
3654 
3655 				if( !bRet )
3656 				{
3657 					// dann sich selbst rekursiv aufrufen; nur mit
3658 					// einem anderen Mode -> proprotional
3659 					TblChgMode eOld = eTblChgMode;
3660 					eTblChgMode = TBLFIX_CHGPROP;
3661 
3662 					bRet = SetColWidth( rAktBox, eType, nAbsDiff, nRelDiff,
3663 										ppUndo );
3664 					eTblChgMode = eOld;
3665 					return bRet;
3666 				}
3667 			}
3668 			else
3669 			{
3670 				bRet = sal_True;
3671 				for( n = 0; n < aLines.Count(); ++n )
3672 				{
3673 					aParam.LoopClear();
3674 					if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_True ))
3675 					{
3676 						bRet = sal_False;
3677 						break;
3678 					}
3679 				}
3680 			}
3681 
3682 			if( bRet )
3683 			{
3684 				if( bInsDel )
3685 				{
3686 					pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo,
3687 													aTmpLst, nDistStt );
3688 					if( aParam.bBigger && aParam.aBoxes.Count() ==
3689 									aSortCntBoxes.Count() )
3690 					{
3691 						// dies gesamte Tabelle soll geloescht werden!!
3692 						GetFrmFmt()->GetDoc()->DeleteRowCol( aParam.aBoxes );
3693 						return sal_False;
3694 					}
3695 
3696 					if( ppUndo )
3697 						*ppUndo = aParam.CreateUndo(
3698 										aParam.bBigger ? UNDO_COL_DELETE
3699 													   : UNDO_TABLE_INSCOL );
3700 				}
3701 				else if( ppUndo )
3702 					*ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
3703 
3704 				long nFrmWidth = LONG_MAX;
3705 				LockModify();
3706 				SwFmtFrmSize aSz( rSz );
3707 				SvxLRSpaceItem aLR( rLR );
3708 				if( bBigger )
3709 				{
3710 					// falls die Tabelle keinen Platz zum Wachsen hat, dann
3711 					// muessen wir welchen schaffen!
3712 					if( aSz.GetWidth() + nRelDiff > USHRT_MAX )
3713 					{
3714 						// dann mal herunterbrechen auf USHRT_MAX / 2
3715 						CR_SetBoxWidth aTmpPara( 0, aSz.GetWidth() / 2,
3716 										0, aSz.GetWidth(), aSz.GetWidth(), aParam.pTblNd );
3717 						for( sal_uInt16 nLn = 0; nLn < aLines.Count(); ++nLn )
3718 							::lcl_AjustLines( aLines[ nLn ], aTmpPara );
3719 						aSz.SetWidth( aSz.GetWidth() / 2 );
3720 						aParam.nDiff = nRelDiff /= 2;
3721 						aParam.nSide /= 2;
3722 						aParam.nMaxSize /= 2;
3723 					}
3724 
3725 					if( bLeft )
3726 						aLR.SetLeft( sal_uInt16( aLR.GetLeft() - nAbsDiff ) );
3727 					else
3728 						aLR.SetRight( sal_uInt16( aLR.GetRight() - nAbsDiff ) );
3729 				}
3730 				else if( bLeft )
3731 					aLR.SetLeft( sal_uInt16( aLR.GetLeft() + nAbsDiff ) );
3732 				else
3733 					aLR.SetRight( sal_uInt16( aLR.GetRight() + nAbsDiff ) );
3734 
3735 				if( bChgLRSpace )
3736                     GetFrmFmt()->SetFmtAttr( aLR );
3737 				const SwFmtHoriOrient& rHOri = GetFrmFmt()->GetHoriOrient();
3738                 if( text::HoriOrientation::FULL == rHOri.GetHoriOrient() ||
3739                     (text::HoriOrientation::LEFT == rHOri.GetHoriOrient() && aLR.GetLeft()) ||
3740                     (text::HoriOrientation::RIGHT == rHOri.GetHoriOrient() && aLR.GetRight()))
3741 				{
3742 					SwFmtHoriOrient aHOri( rHOri );
3743                     aHOri.SetHoriOrient( text::HoriOrientation::NONE );
3744                     GetFrmFmt()->SetFmtAttr( aHOri );
3745 
3746 					// sollte die Tabelle noch auf relativen Werten
3747 					// (USHRT_MAX) stehen dann muss es jetzt auf absolute
3748 					// umgerechnet werden. Bug 61494
3749                     if( GetFrmFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) &&
3750                         !rSz.GetWidthPercent() )
3751 					{
3752 	                    SwTabFrm* pTabFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *GetFrmFmt() );
3753 						if( pTabFrm &&
3754 							pTabFrm->Prt().Width() != rSz.GetWidth() )
3755 						{
3756 							nFrmWidth = pTabFrm->Prt().Width();
3757 							if( bBigger )
3758 								nFrmWidth += nAbsDiff;
3759 							else
3760 								nFrmWidth -= nAbsDiff;
3761 						}
3762 					}
3763 				}
3764 
3765 				if( bBigger )
3766 					aSz.SetWidth( aSz.GetWidth() + nRelDiff );
3767 				else
3768 					aSz.SetWidth( aSz.GetWidth() - nRelDiff );
3769 
3770 				if( rSz.GetWidthPercent() )
3771 					aSz.SetWidthPercent( static_cast<sal_uInt8>(( aSz.GetWidth() * 100 ) /
3772 						( aSz.GetWidth() + aLR.GetRight() + aLR.GetLeft())));
3773 
3774                 GetFrmFmt()->SetFmtAttr( aSz );
3775 				aParam.nTblWidth = sal_uInt16( aSz.GetWidth() );
3776 
3777 				UnlockModify();
3778 
3779 				for( n = aLines.Count(); n; )
3780 				{
3781 					--n;
3782 					aParam.LoopClear();
3783 					(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_False );
3784 				}
3785 
3786 				// sollte die Tabelle noch auf relativen Werten
3787 				// (USHRT_MAX) stehen dann muss es jetzt auf absolute
3788 				// umgerechnet werden. Bug 61494
3789 				if( LONG_MAX != nFrmWidth )
3790 				{
3791 					SwFmtFrmSize aAbsSz( aSz );
3792                     aAbsSz.SetWidth( nFrmWidth );
3793                     GetFrmFmt()->SetFmtAttr( aAbsSz );
3794 				}
3795 			}
3796 		}
3797 		else if( bInsDel ||
3798 				( bLeft ? nDist : Abs( rSz.GetWidth() - nDist ) > COLFUZZY ) )
3799 		{
3800 			bRet = sal_True;
3801 			if( bLeft && TBLFIX_CHGABS == eTblChgMode && !bInsDel )
3802 				aParam.bBigger = !bBigger;
3803 
3804 			// erstmal testen, ob ueberhaupt Platz ist
3805 			if( bInsDel )
3806 			{
3807 				if( aParam.bBigger )
3808 				{
3809 					for( n = 0; n < aLines.Count(); ++n )
3810 					{
3811 						aParam.LoopClear();
3812 						if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_True ))
3813 						{
3814 							bRet = sal_False;
3815 							break;
3816 						}
3817 					}
3818 				}
3819 				else
3820 				{
3821 					if( 0 != ( bRet = bLeft ? nDist != 0
3822 											: ( rSz.GetWidth() - nDist ) > COLFUZZY ) )
3823 					{
3824 						for( n = 0; n < aLines.Count(); ++n )
3825 						{
3826 							aParam.LoopClear();
3827 							if( !(*fnOtherBox)( aLines[ n ], aParam, 0, sal_True ))
3828 							{
3829 								bRet = sal_False;
3830 								break;
3831 							}
3832 						}
3833 						if( bRet && !aParam.bAnyBoxFnd )
3834 							bRet = sal_False;
3835 					}
3836 
3837 					if( !bRet && rAktBox.GetFrmFmt()->GetFrmSize().GetWidth()
3838 						- nRelDiff > COLFUZZY +
3839 							( 567 / 2 /* min. 0,5 cm Platz lassen*/) )
3840 					{
3841 						// dann den Platz von der akt. Zelle nehmen
3842 						aParam.bSplittBox = sal_True;
3843 						// aber das muss auch mal getestet werden!
3844 						bRet = sal_True;
3845 
3846 						for( n = 0; n < aLines.Count(); ++n )
3847 						{
3848 							aParam.LoopClear();
3849 							if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_True ))
3850 							{
3851 								bRet = sal_False;
3852 								break;
3853 							}
3854 						}
3855 					}
3856 				}
3857 			}
3858 			else if( aParam.bBigger )
3859 			{
3860 				for( n = 0; n < aLines.Count(); ++n )
3861 				{
3862 					aParam.LoopClear();
3863 					if( !(*fnOtherBox)( aLines[ n ], aParam, 0, sal_True ))
3864 					{
3865 						bRet = sal_False;
3866 						break;
3867 					}
3868 				}
3869 			}
3870 			else
3871 			{
3872 				for( n = 0; n < aLines.Count(); ++n )
3873 				{
3874 					aParam.LoopClear();
3875 					if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_True ))
3876 					{
3877 						bRet = sal_False;
3878 						break;
3879 					}
3880 				}
3881 			}
3882 
3883 			// wenn ja, dann setzen
3884 			if( bRet )
3885 			{
3886 				CR_SetBoxWidth aParam1( aParam );
3887 				if( bInsDel )
3888 				{
3889 					aParam1.bBigger = !aParam.bBigger;
3890 					pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo,
3891 													aTmpLst, nDistStt );
3892 					if( ppUndo )
3893 						*ppUndo = aParam.CreateUndo(
3894 										aParam.bBigger ? UNDO_TABLE_DELBOX
3895 													   : UNDO_TABLE_INSCOL );
3896 				}
3897 				else if( ppUndo )
3898 					*ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
3899 
3900 				if( bInsDel
3901 					? ( TBLFIX_CHGABS == eTblChgMode ? bLeft : bLeft )
3902 					: ( TBLFIX_CHGABS != eTblChgMode && bLeft ) )
3903 				{
3904 					for( n = aLines.Count(); n; )
3905 					{
3906 						--n;
3907 						aParam.LoopClear();
3908 						aParam1.LoopClear();
3909 						(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_False );
3910 						(*fnOtherBox)( aLines[ n ], aParam1, nDistStt, sal_False );
3911 					}
3912 				}
3913 				else
3914 					for( n = aLines.Count(); n; )
3915 					{
3916 						--n;
3917 						aParam.LoopClear();
3918 						aParam1.LoopClear();
3919 						(*fnOtherBox)( aLines[ n ], aParam1, nDistStt, sal_False );
3920 						(*fnSelBox)( aLines[ n ], aParam, nDistStt, sal_False );
3921 					}
3922 			}
3923 		}
3924 		break;
3925 
3926 	case nsTblChgWidthHeightType::WH_CELL_RIGHT:
3927 	case nsTblChgWidthHeightType::WH_CELL_LEFT:
3928 		if( TBLVAR_CHGABS == eTblChgMode )
3929 		{
3930 			// dann sich selbst rekursiv aufrufen; nur mit
3931 			// einem anderen Mode -> Nachbarn
3932 			TblChgMode eOld = eTblChgMode;
3933 			eTblChgMode = TBLFIX_CHGABS;
3934 
3935 			bRet = SetColWidth( rAktBox, eType, nAbsDiff, nRelDiff,
3936 								ppUndo );
3937 			eTblChgMode = eOld;
3938 			return bRet;
3939 		}
3940 		else if( bInsDel || ( bLeft ? nDist
3941 									: (rSz.GetWidth() - nDist) > COLFUZZY ))
3942 		{
3943 			if( bLeft && TBLFIX_CHGABS == eTblChgMode && !bInsDel )
3944 				aParam.bBigger = !bBigger;
3945 
3946 			// erstmal testen, ob ueberhaupt Platz ist
3947 			SwTableBox* pBox = &rAktBox;
3948 			SwTableLine* pLine = rAktBox.GetUpper();
3949 			while( pLine->GetUpper() )
3950 			{
3951 				sal_uInt16 nPos = pLine->GetTabBoxes().C40_GETPOS( SwTableBox, pBox );
3952 				if( bLeft ? nPos : nPos + 1 != pLine->GetTabBoxes().Count() )
3953 					break;
3954 
3955 				pBox = pLine->GetUpper();
3956 				pLine = pBox->GetUpper();
3957 			}
3958 
3959 			if( pLine->GetUpper() )
3960 			{
3961 				// dann muss die Distanz wieder korriegiert werden!
3962 				aParam.nSide -= ::lcl_GetDistance( pLine->GetUpper(), sal_True );
3963 
3964 				if( bLeft )
3965 					aParam.nMaxSize = aParam.nSide;
3966 				else
3967 					aParam.nMaxSize = pLine->GetUpper()->GetFrmFmt()->
3968 									GetFrmSize().GetWidth() - aParam.nSide;
3969 			}
3970 
3971 			// erstmal testen, ob ueberhaupt Platz ist
3972 			if( bInsDel )
3973 			{
3974 				if( 0 != ( bRet = bLeft ? nDist != 0
3975 								: ( rSz.GetWidth() - nDist ) > COLFUZZY ) &&
3976 					!aParam.bBigger )
3977 				{
3978                     bRet = (*fnOtherBox)( pLine, aParam, 0, sal_True );
3979 					if( bRet && !aParam.bAnyBoxFnd )
3980 						bRet = sal_False;
3981 				}
3982 
3983 				if( !bRet && !aParam.bBigger && rAktBox.GetFrmFmt()->
3984 					GetFrmSize().GetWidth() - nRelDiff > COLFUZZY +
3985 						( 567 / 2 /* min. 0,5 cm Platz lassen*/) )
3986 				{
3987 					// dann den Platz von der akt. Zelle nehmen
3988 					aParam.bSplittBox = sal_True;
3989 					bRet = sal_True;
3990 				}
3991 			}
3992 			else
3993 			{
3994 				FN_lcl_SetBoxWidth fnTmp = aParam.bBigger ? fnOtherBox : fnSelBox;
3995 				bRet = (*fnTmp)( pLine, aParam, nDistStt, sal_True );
3996 			}
3997 
3998 			// wenn ja, dann setzen
3999 			if( bRet )
4000 			{
4001 				CR_SetBoxWidth aParam1( aParam );
4002 				if( bInsDel )
4003 				{
4004 					aParam1.bBigger = !aParam.bBigger;
4005 					pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst, nDistStt );
4006 					if( ppUndo )
4007 						*ppUndo = aParam.CreateUndo(
4008 										aParam.bBigger ? UNDO_TABLE_DELBOX
4009 													   : UNDO_TABLE_INSCOL );
4010 				}
4011 				else if( ppUndo )
4012 					*ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
4013 
4014 				if( bInsDel
4015 					? ( TBLFIX_CHGABS == eTblChgMode ? (bBigger && bLeft) : bLeft )
4016 					: ( TBLFIX_CHGABS != eTblChgMode && bLeft ) )
4017 				{
4018 					(*fnSelBox)( pLine, aParam, nDistStt, sal_False );
4019 					(*fnOtherBox)( pLine, aParam1, nDistStt, sal_False );
4020 				}
4021 				else
4022 				{
4023 					(*fnOtherBox)( pLine, aParam1, nDistStt, sal_False );
4024 					(*fnSelBox)( pLine, aParam, nDistStt, sal_False );
4025 				}
4026 			}
4027 		}
4028 		break;
4029 
4030 	}
4031 
4032 	if( pFndBox )
4033 	{
4034 		// dann raeume die Struktur aller Lines auf
4035 		GCLines();
4036 
4037 		//Layout updaten
4038 		if( !bBigger || pFndBox->AreLinesToRestore( *this ) )
4039 			pFndBox->MakeFrms( *this );
4040 
4041 		// TL_CHART2: it is currently unclear if sth has to be done here.
4042 		// The function name hints that nothing needs to be done, on the other
4043 		// hand there is a case where sth gets deleted.  :-(
4044 
4045 		delete pFndBox;
4046 
4047 		if( ppUndo && *ppUndo )
4048 		{
4049 			aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<sal_uInt16>(eTblChgMode), eType,
4050 											nAbsDiff, nRelDiff );
4051 			if( !aParam.bBigger )
4052 				aParam.pUndo->SaveNewBoxes( *aParam.pTblNd, aTmpLst );
4053 		}
4054 	}
4055 
4056 	if( bRet )
4057 	{
4058 		CHECKBOXWIDTH
4059         CHECKTABLELAYOUT
4060 	}
4061 
4062 	return bRet;
4063 }
4064 /*  */
4065 
lcl_SaveInsDelData(CR_SetLineHeight & rParam,SwUndo ** ppUndo,SwTableSortBoxes & rTmpLst)4066 _FndBox* lcl_SaveInsDelData( CR_SetLineHeight& rParam, SwUndo** ppUndo,
4067 								SwTableSortBoxes& rTmpLst )
4068 {
4069 	// suche alle Boxen / Lines
4070 	SwTable& rTbl = rParam.pTblNd->GetTable();
4071 
4072 	ASSERT( rParam.aBoxes.Count(), "ohne Boxen ist nichts zu machen!" );
4073 
4074 	// loeschen der gesamten Tabelle verhindern
4075 	if( !rParam.bBigger && rParam.aBoxes.Count() ==
4076 		rTbl.GetTabSortBoxes().Count() )
4077 		return 0;
4078 
4079 	_FndBox* pFndBox = new _FndBox( 0, 0 );
4080 	if( !rParam.bBigger )
4081 		pFndBox->SetTableLines( rParam.aBoxes, rTbl );
4082 	else
4083 	{
4084 		_FndPara aPara( rParam.aBoxes, pFndBox );
4085 		rTbl.GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
4086 		ASSERT( pFndBox->GetLines().Count(), "Wo sind die Boxen" );
4087 		pFndBox->SetTableLines( rTbl );
4088 
4089 		if( ppUndo )
4090 			rTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
4091 	}
4092 
4093 	//Lines fuer das Layout-Update heraussuchen.
4094 	pFndBox->DelFrms( rTbl );
4095 
4096 	// TL_CHART2: it is currently unclear if sth has to be done here.
4097 
4098 	return pFndBox;
4099 }
4100 
SetLineHeight(SwTableLine & rLine,SwTwips nOldHeight,SwTwips nNewHeight,sal_Bool bMinSize)4101 void SetLineHeight( SwTableLine& rLine, SwTwips nOldHeight, SwTwips nNewHeight,
4102 					sal_Bool bMinSize )
4103 {
4104 	SwLayoutFrm* pLineFrm = GetRowFrm( rLine );
4105 	ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" );
4106 
4107 	SwFrmFmt* pFmt = rLine.ClaimFrmFmt();
4108 
4109 	SwTwips nMyNewH, nMyOldH = pLineFrm->Frm().Height();
4110 	if( !nOldHeight )						// die BaseLine und absolut
4111 		nMyNewH = nMyOldH + nNewHeight;
4112 	else
4113 	{
4114 		// moeglichst genau rechnen
4115 		Fraction aTmp( nMyOldH );
4116 		aTmp *= Fraction( nNewHeight, nOldHeight );
4117 		aTmp += Fraction( 1, 2 );		// ggfs. aufrunden
4118 		nMyNewH = aTmp;
4119 	}
4120 
4121 	SwFrmSize eSize = ATT_MIN_SIZE;
4122 	if( !bMinSize &&
4123 		( nMyOldH - nMyNewH ) > ( CalcRowRstHeight( pLineFrm ) + ROWFUZZY ))
4124 		eSize = ATT_FIX_SIZE;
4125 
4126     pFmt->SetFmtAttr( SwFmtFrmSize( eSize, 0, nMyNewH ) );
4127 
4128 	// erst alle inneren anpassen
4129 	SwTableBoxes& rBoxes = rLine.GetTabBoxes();
4130 	for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
4131 	{
4132 		SwTableBox& rBox = *rBoxes[ n ];
4133 		for( sal_uInt16 i = 0; i < rBox.GetTabLines().Count(); ++i )
4134 			SetLineHeight( *rBox.GetTabLines()[ i ], nMyOldH, nMyNewH, bMinSize );
4135 	}
4136 }
4137 
lcl_SetSelLineHeight(SwTableLine * pLine,CR_SetLineHeight & rParam,SwTwips nDist,sal_Bool bCheck)4138 sal_Bool lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
4139 							 SwTwips nDist, sal_Bool bCheck )
4140 {
4141 	sal_Bool bRet = sal_True;
4142 	if( !bCheck )
4143 	{
4144 		// Zeilenhoehe einstellen
4145 		SetLineHeight( *pLine, 0, rParam.bBigger ? nDist : -nDist,
4146 						rParam.bBigger );
4147 	}
4148 	else if( !rParam.bBigger )
4149 	{
4150 		// anhand der alten Size die neue relative errechnen
4151 		SwLayoutFrm* pLineFrm = GetRowFrm( *pLine );
4152 		ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" );
4153 		SwTwips nRstHeight = CalcRowRstHeight( pLineFrm );
4154 		if( (nRstHeight + ROWFUZZY) < nDist )
4155 			bRet = sal_False;
4156 	}
4157 	return bRet;
4158 }
4159 
lcl_SetOtherLineHeight(SwTableLine * pLine,CR_SetLineHeight & rParam,SwTwips nDist,sal_Bool bCheck)4160 sal_Bool lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
4161 								SwTwips nDist, sal_Bool bCheck )
4162 {
4163 	sal_Bool bRet = sal_True;
4164 	if( bCheck )
4165 	{
4166 		if( rParam.bBigger )
4167 		{
4168 			// anhand der alten Size die neue relative errechnen
4169 			SwLayoutFrm* pLineFrm = GetRowFrm( *pLine );
4170 			ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" );
4171 
4172 			if( TBLFIX_CHGPROP == rParam.nMode )
4173 			{
4174 				nDist *= pLineFrm->Frm().Height();
4175 				nDist /= rParam.nMaxHeight;
4176 			}
4177 			bRet = nDist <= CalcRowRstHeight( pLineFrm );
4178 		}
4179 	}
4180 	else
4181 	{
4182 		// Zeilenhoehe einstellen
4183 		// pLine ist die nachfolgende / vorhergehende -> also anpassen
4184 		if( TBLFIX_CHGPROP == rParam.nMode )
4185 		{
4186 			SwLayoutFrm* pLineFrm = GetRowFrm( *pLine );
4187 			ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" );
4188 
4189 			// aus der alten Size die neue relative errechnen
4190 			// Wird die selektierte Box groesser ueber den MaxSpace anpassen,
4191 			// sonst ueber die MaxHeight
4192 			if( 1 /*!rParam.bBigger*/ )
4193 			{
4194 				nDist *= pLineFrm->Frm().Height();
4195 				nDist /= rParam.nMaxHeight;
4196 			}
4197 			else
4198 			{
4199 				// aus der alten Size die neue relative errechnen
4200 				nDist *= CalcRowRstHeight( pLineFrm );
4201 				nDist /= rParam.nMaxSpace;
4202 			}
4203 		}
4204 		SetLineHeight( *pLine, 0, rParam.bBigger ? -nDist : nDist,
4205 						!rParam.bBigger );
4206 	}
4207 	return bRet;
4208 }
4209 
lcl_InsDelSelLine(SwTableLine * pLine,CR_SetLineHeight & rParam,SwTwips nDist,sal_Bool bCheck)4210 sal_Bool lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam,
4211 							SwTwips nDist, sal_Bool bCheck )
4212 {
4213 	sal_Bool bRet = sal_True;
4214 	if( !bCheck )
4215 	{
4216 		SwTableBoxes& rBoxes = pLine->GetTabBoxes();
4217 		SwDoc* pDoc = pLine->GetFrmFmt()->GetDoc();
4218 		if( !rParam.bBigger )
4219 		{
4220 			sal_uInt16 n;
4221 
4222 			for( n = rBoxes.Count(); n; )
4223 				::lcl_SaveUpperLowerBorder( rParam.pTblNd->GetTable(),
4224 													*rBoxes[ --n ],
4225 													rParam.aShareFmts );
4226 			for( n = rBoxes.Count(); n; )
4227 				::_DeleteBox( rParam.pTblNd->GetTable(),
4228 									rBoxes[ --n ], rParam.pUndo, sal_False,
4229 									sal_False, &rParam.aShareFmts );
4230 		}
4231 		else
4232 		{
4233 			// Zeile einfuegen
4234 			SwTableLine* pNewLine = new SwTableLine( (SwTableLineFmt*)pLine->GetFrmFmt(),
4235 										rBoxes.Count(), pLine->GetUpper() );
4236 			SwTableLines* pLines;
4237 			if( pLine->GetUpper() )
4238 				pLines = &pLine->GetUpper()->GetTabLines();
4239 			else
4240 				pLines = &rParam.pTblNd->GetTable().GetTabLines();
4241 			sal_uInt16 nPos = pLines->C40_GETPOS( SwTableLine, pLine );
4242 			if( !rParam.bTop )
4243 				++nPos;
4244 			pLines->C40_INSERT( SwTableLine, pNewLine, nPos );
4245 
4246 			SwFrmFmt* pNewFmt = pNewLine->ClaimFrmFmt();
4247             pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nDist ) );
4248 
4249 			// und noch mal die Anzahl Boxen erzeugen
4250 			SwTableBoxes& rNewBoxes = pNewLine->GetTabBoxes();
4251 			for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
4252 			{
4253 				SwTwips nWidth = 0;
4254 				SwTableBox* pOld = rBoxes[ n ];
4255 				if( !pOld->GetSttNd() )
4256 				{
4257 					// keine normale "Content"-Box also auf die 1. naechste
4258 					// Box zurueckfallen
4259 					nWidth = pOld->GetFrmFmt()->GetFrmSize().GetWidth();
4260 					while( !pOld->GetSttNd() )
4261 						pOld = pOld->GetTabLines()[ 0 ]->GetTabBoxes()[ 0 ];
4262 				}
4263 				::_InsTblBox( pDoc, rParam.pTblNd, pNewLine,
4264 									(SwTableBoxFmt*)pOld->GetFrmFmt(), pOld, n );
4265 
4266 				// Sonderbehandlung fuer Umrandung die Obere muss
4267 				// entfernt werden
4268 				const SvxBoxItem& rBoxItem = pOld->GetFrmFmt()->GetBox();
4269 				if( rBoxItem.GetTop() )
4270 				{
4271 					SvxBoxItem aTmp( rBoxItem );
4272 					aTmp.SetLine( 0, BOX_LINE_TOP );
4273                     rParam.aShareFmts.SetAttr( rParam.bTop
4274 												? *pOld
4275 												: *rNewBoxes[ n ], aTmp );
4276 				}
4277 
4278 				if( nWidth )
4279                     rParam.aShareFmts.SetAttr( *rNewBoxes[ n ],
4280 								SwFmtFrmSize( ATT_FIX_SIZE, nWidth, 0 ) );
4281 			}
4282 		}
4283 	}
4284 	else
4285 	{
4286 		// Boxen einsammeln!
4287 		SwTableBoxes& rBoxes = pLine->GetTabBoxes();
4288 		for( sal_uInt16 n = rBoxes.Count(); n; )
4289 		{
4290 			SwTableBox* pBox = rBoxes[ --n ];
4291 			if( pBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
4292 				return sal_False;
4293 
4294 			if( pBox->GetSttNd() )
4295 				rParam.aBoxes.Insert( pBox );
4296 			else
4297 			{
4298 				for( sal_uInt16 i = pBox->GetTabLines().Count(); i; )
4299 					lcl_InsDelSelLine( pBox->GetTabLines()[ --i ],
4300 										rParam, 0, sal_True );
4301 			}
4302 		}
4303 	}
4304 	return bRet;
4305 }
4306 
SetRowHeight(SwTableBox & rAktBox,sal_uInt16 eType,SwTwips nAbsDiff,SwTwips nRelDiff,SwUndo ** ppUndo)4307 sal_Bool SwTable::SetRowHeight( SwTableBox& rAktBox, sal_uInt16 eType,
4308 						SwTwips nAbsDiff, SwTwips nRelDiff,SwUndo** ppUndo )
4309 {
4310 	SwTableLine* pLine = rAktBox.GetUpper();
4311 
4312 	SwTableLine* pBaseLine = pLine;
4313 	while( pBaseLine->GetUpper() )
4314 		pBaseLine = pBaseLine->GetUpper()->GetUpper();
4315 
4316 	_FndBox* pFndBox = 0;					// fuers Einfuegen/Loeschen
4317 	SwTableSortBoxes aTmpLst( 0, 5 );		// fuers Undo
4318 	sal_Bool bBigger,
4319 		bRet = sal_False,
4320 		bTop = nsTblChgWidthHeightType::WH_ROW_TOP == ( eType & 0xff ) ||
4321 				nsTblChgWidthHeightType::WH_CELL_TOP == ( eType & 0xff ),
4322 		bInsDel = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL );
4323 	sal_uInt16 n, nBaseLinePos = GetTabLines().C40_GETPOS( SwTableLine, pBaseLine );
4324 	sal_uLong nBoxIdx = rAktBox.GetSttIdx();
4325 
4326 	CR_SetLineHeight aParam( eType,
4327 						(SwTableNode*)rAktBox.GetSttNd()->FindTableNode() );
4328 	bBigger = aParam.bBigger;
4329 
4330 	FN_lcl_SetLineHeight fnSelLine, fnOtherLine = lcl_SetOtherLineHeight;
4331 	if( bInsDel )
4332 		fnSelLine = lcl_InsDelSelLine;
4333 	else
4334 		fnSelLine = lcl_SetSelLineHeight;
4335 
4336 	SwTableLines* pLines = &aLines;
4337 
4338 	// wie kommt man an die Hoehen heran?
4339 	switch( eType & 0xff )
4340 	{
4341 	case nsTblChgWidthHeightType::WH_CELL_TOP:
4342 	case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
4343 		if( pLine == pBaseLine )
4344 			break;	// dann geht es nicht!
4345 
4346 		// ist eine verschachtelte Line (Box!)
4347 		pLines = &pLine->GetUpper()->GetTabLines();
4348 		nBaseLinePos = pLines->C40_GETPOS( SwTableLine, pLine );
4349 		pBaseLine = pLine;
4350 		// kein break!
4351 
4352 	case nsTblChgWidthHeightType::WH_ROW_TOP:
4353 	case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
4354 		{
4355 			if( bInsDel && !bBigger )		// um wieviel wird es Hoeher?
4356 			{
4357 				nAbsDiff = GetRowFrm( *pBaseLine )->Frm().Height();
4358 			}
4359 
4360 			if( TBLVAR_CHGABS == eTblChgMode )
4361 			{
4362 				// erstmal testen, ob ueberhaupt Platz ist
4363 				if( bBigger )
4364 				{
4365 					bRet = sal_True;
4366 // was ist mit Top, was ist mit Tabelle im Rahmen oder in Kopf-/Fusszeile
4367 // mit fester Hoehe ??
4368 					if( !bRet )
4369 					{
4370 						// dann sich selbst rekursiv aufrufen; nur mit
4371 						// einem anderen Mode -> proprotional
4372 						TblChgMode eOld = eTblChgMode;
4373 						eTblChgMode = TBLFIX_CHGPROP;
4374 
4375 						bRet = SetRowHeight( rAktBox, eType, nAbsDiff,
4376 											nRelDiff, ppUndo );
4377 
4378 						eTblChgMode = eOld;
4379 						return bRet;
4380 					}
4381 				}
4382 				else
4383 					bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4384 										nAbsDiff, sal_True );
4385 
4386 				if( bRet )
4387 				{
4388 					if( bInsDel )
4389 					{
4390 						if( !aParam.aBoxes.Count() )
4391 							::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ],
4392 													aParam, 0, sal_True );
4393 
4394 						pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst );
4395 
4396                         // #110525# delete complete table when last row is
4397                         // deleted
4398                         if( !bBigger &&
4399                             aParam.aBoxes.Count() == aSortCntBoxes.Count() )
4400                         {
4401                             GetFrmFmt()->GetDoc()->DeleteRowCol( aParam.aBoxes );
4402                             return sal_False;
4403                         }
4404 
4405 
4406 						if( ppUndo )
4407                             *ppUndo = aParam.CreateUndo(
4408 										bBigger ? UNDO_TABLE_INSROW
4409                                                 : UNDO_ROW_DELETE );
4410 					}
4411 					else if( ppUndo )
4412 						*ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
4413 
4414 					(*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4415 									nAbsDiff, sal_False );
4416 				}
4417 			}
4418 			else
4419 			{
4420 				bRet = sal_True;
4421 				sal_uInt16 nStt, nEnd;
4422 				if( bTop )
4423 					nStt = 0, nEnd = nBaseLinePos;
4424 				else
4425 					nStt = nBaseLinePos + 1, nEnd = pLines->Count();
4426 
4427 				// die akt. Hoehe der Lines besorgen
4428 				if( TBLFIX_CHGPROP == eTblChgMode )
4429 				{
4430 					for( n = nStt; n < nEnd; ++n )
4431 					{
4432 						SwLayoutFrm* pLineFrm = GetRowFrm( *(*pLines)[ n ] );
4433 						ASSERT( pLineFrm, "wo ist der Frm von der SwTableLine?" );
4434 						aParam.nMaxSpace += CalcRowRstHeight( pLineFrm );
4435 						aParam.nMaxHeight += pLineFrm->Frm().Height();
4436 					}
4437 					if( bBigger && aParam.nMaxSpace < nAbsDiff )
4438 						bRet = sal_False;
4439 				}
4440 				else
4441 				{
4442 					if( bTop ? nEnd : nStt < nEnd  )
4443 					{
4444 						if( bTop )
4445 							nStt = nEnd - 1;
4446 						else
4447 							nEnd = nStt + 1;
4448 					}
4449 					else
4450 						bRet = sal_False;
4451 				}
4452 
4453 				if( bRet )
4454 				{
4455 					if( bBigger )
4456 					{
4457 						for( n = nStt; n < nEnd; ++n )
4458 						{
4459 							if( !(*fnOtherLine)( (*pLines)[ n ], aParam,
4460 													nAbsDiff, sal_True ))
4461 							{
4462 								bRet = sal_False;
4463 								break;
4464 							}
4465 						}
4466 					}
4467 					else
4468 						bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4469 												nAbsDiff, sal_True );
4470 				}
4471 
4472 				if( bRet )
4473 				{
4474 					// dann mal anpassen
4475 					if( bInsDel )
4476 					{
4477 						if( !aParam.aBoxes.Count() )
4478 							::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ],
4479 													aParam, 0, sal_True );
4480 						pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst );
4481 						if( ppUndo )
4482                             *ppUndo = aParam.CreateUndo(
4483 										bBigger ? UNDO_TABLE_INSROW
4484                                                 : UNDO_ROW_DELETE );
4485 					}
4486 					else if( ppUndo )
4487 						*ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
4488 
4489 					CR_SetLineHeight aParam1( aParam );
4490 					if( TBLFIX_CHGPROP == eTblChgMode && !bBigger &&
4491 						!aParam.nMaxSpace )
4492 					{
4493 						// dann muss der gesamte Platz auf alle Lines
4494 						// gleichmaessig verteilt werden. Dafuer wird die
4495 						// Anzahl benoetigt
4496 						aParam1.nLines = nEnd - nStt;
4497 					}
4498 
4499 					if( bTop )
4500 					{
4501 						(*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4502 										nAbsDiff, sal_False );
4503 						for( n = nStt; n < nEnd; ++n )
4504 							(*fnOtherLine)( (*pLines)[ n ], aParam1,
4505 											nAbsDiff, sal_False );
4506 					}
4507 					else
4508 					{
4509 						for( n = nStt; n < nEnd; ++n )
4510 							(*fnOtherLine)( (*pLines)[ n ], aParam1,
4511 											nAbsDiff, sal_False );
4512 						(*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4513 										nAbsDiff, sal_False );
4514 					}
4515 				}
4516 				else
4517 				{
4518 					// dann sich selbst rekursiv aufrufen; nur mit
4519 					// einem anderen Mode -> proprotional
4520 					TblChgMode eOld = eTblChgMode;
4521 					eTblChgMode = TBLVAR_CHGABS;
4522 
4523 					bRet = SetRowHeight( rAktBox, eType, nAbsDiff,
4524 										nRelDiff, ppUndo );
4525 
4526 					eTblChgMode = eOld;
4527 					pFndBox = 0;
4528 				}
4529 			}
4530 		}
4531 		break;
4532 	}
4533 
4534 	if( pFndBox )
4535 	{
4536 		// dann raeume die Struktur aller Lines auf
4537 		GCLines();
4538 
4539 		//Layout updaten
4540 		if( bBigger || pFndBox->AreLinesToRestore( *this ) )
4541 			pFndBox->MakeFrms( *this );
4542 
4543 		// TL_CHART2: it is currently unclear if sth has to be done here.
4544 
4545 		delete pFndBox;
4546 
4547 		if( ppUndo && *ppUndo )
4548 		{
4549 			aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<sal_uInt16>(eTblChgMode), eType,
4550 											nAbsDiff, nRelDiff );
4551 			if( bBigger )
4552 				aParam.pUndo->SaveNewBoxes( *aParam.pTblNd, aTmpLst );
4553 		}
4554 	}
4555 
4556     CHECKTABLELAYOUT
4557 
4558 	return bRet;
4559 }
4560 
4561 /*  */
4562 
GetFormat(long nWidth) const4563 SwFrmFmt* SwShareBoxFmt::GetFormat( long nWidth ) const
4564 {
4565 	SwFrmFmt *pRet = 0, *pTmp;
4566 	for( sal_uInt16 n = aNewFmts.Count(); n; )
4567 		if( ( pTmp = (SwFrmFmt*)aNewFmts[ --n ])->GetFrmSize().GetWidth()
4568 				== nWidth )
4569 		{
4570 			pRet = pTmp;
4571 			break;
4572 		}
4573 	return pRet;
4574 }
4575 
GetFormat(const SfxPoolItem & rItem) const4576 SwFrmFmt* SwShareBoxFmt::GetFormat( const SfxPoolItem& rItem ) const
4577 {
4578 	const SfxPoolItem* pItem;
4579 	sal_uInt16 nWhich = rItem.Which();
4580 	SwFrmFmt *pRet = 0, *pTmp;
4581     const SfxPoolItem& rFrmSz = pOldFmt->GetFmtAttr( RES_FRM_SIZE, sal_False );
4582 	for( sal_uInt16 n = aNewFmts.Count(); n; )
4583 		if( SFX_ITEM_SET == ( pTmp = (SwFrmFmt*)aNewFmts[ --n ])->
4584 			GetItemState( nWhich, sal_False, &pItem ) && *pItem == rItem &&
4585             pTmp->GetFmtAttr( RES_FRM_SIZE, sal_False ) == rFrmSz )
4586 		{
4587 			pRet = pTmp;
4588 			break;
4589 		}
4590 	return pRet;
4591 }
4592 
AddFormat(const SwFrmFmt & rNew)4593 void SwShareBoxFmt::AddFormat( const SwFrmFmt& rNew )
4594 {
4595 	void* pFmt = (void*)&rNew;
4596 	aNewFmts.Insert( pFmt, aNewFmts.Count() );
4597 }
4598 
RemoveFormat(const SwFrmFmt & rFmt)4599 sal_Bool SwShareBoxFmt::RemoveFormat( const SwFrmFmt& rFmt )
4600 {
4601 	// returnt sal_True, wenn geloescht werden kann
4602 	if( pOldFmt == &rFmt )
4603 		return sal_True;
4604 
4605 	void* p = (void*)&rFmt;
4606 	sal_uInt16 nFnd = aNewFmts.GetPos( p );
4607 	if( USHRT_MAX != nFnd )
4608 		aNewFmts.Remove( nFnd );
4609 	return 0 == aNewFmts.Count();
4610 }
4611 
~SwShareBoxFmts()4612 SwShareBoxFmts::~SwShareBoxFmts()
4613 {
4614 }
4615 
GetFormat(const SwFrmFmt & rFmt,long nWidth) const4616 SwFrmFmt* SwShareBoxFmts::GetFormat( const SwFrmFmt& rFmt, long nWidth ) const
4617 {
4618 	sal_uInt16 nPos;
4619 	return Seek_Entry( rFmt, &nPos )
4620 					? aShareArr[ nPos ]->GetFormat( nWidth )
4621 					: 0;
4622 }
GetFormat(const SwFrmFmt & rFmt,const SfxPoolItem & rItem) const4623 SwFrmFmt* SwShareBoxFmts::GetFormat( const SwFrmFmt& rFmt,
4624 									 const SfxPoolItem& rItem ) const
4625 {
4626 	sal_uInt16 nPos;
4627 	return Seek_Entry( rFmt, &nPos )
4628 					? aShareArr[ nPos ]->GetFormat( rItem )
4629 					: 0;
4630 }
4631 
AddFormat(const SwFrmFmt & rOld,const SwFrmFmt & rNew)4632 void SwShareBoxFmts::AddFormat( const SwFrmFmt& rOld, const SwFrmFmt& rNew )
4633 {
4634 	// wenn das Format nicht geshared ist, braucht es auch nicht in die
4635 	// Liste aufgenommen werden. Denn es gibt keinen 2. der es sucht.
4636 //leider werden auch die CellFrms gefunden
4637 //	if( !rOld.IsLastDepend() )
4638 	{
4639 		sal_uInt16 nPos;
4640 		SwShareBoxFmt* pEntry;
4641 		if( !Seek_Entry( rOld, &nPos ))
4642 		{
4643 			pEntry = new SwShareBoxFmt( rOld );
4644 			aShareArr.C40_INSERT( SwShareBoxFmt, pEntry, nPos );
4645 		}
4646 		else
4647 			pEntry = aShareArr[ nPos ];
4648 
4649 		pEntry->AddFormat( rNew );
4650 	}
4651 }
ChangeFrmFmt(SwTableBox * pBox,SwTableLine * pLn,SwFrmFmt & rFmt)4652 void SwShareBoxFmts::ChangeFrmFmt( SwTableBox* pBox, SwTableLine* pLn,
4653 									SwFrmFmt& rFmt )
4654 {
4655 	SwClient aCl;
4656 	SwFrmFmt* pOld = 0;
4657 	if( pBox )
4658 	{
4659 		pOld = pBox->GetFrmFmt();
4660 		pOld->Add( &aCl );
4661 		pBox->ChgFrmFmt( (SwTableBoxFmt*)&rFmt );
4662 	}
4663 	else if( pLn )
4664 	{
4665 		pOld = pLn->GetFrmFmt();
4666 		pOld->Add( &aCl );
4667 		pLn->ChgFrmFmt( (SwTableLineFmt*)&rFmt );
4668 	}
4669 	if( pOld && pOld->IsLastDepend() )
4670 	{
4671 		RemoveFormat( *pOld );
4672 		delete pOld;
4673 	}
4674 }
4675 
SetSize(SwTableBox & rBox,const SwFmtFrmSize & rSz)4676 void SwShareBoxFmts::SetSize( SwTableBox& rBox, const SwFmtFrmSize& rSz )
4677 {
4678 	SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(),
4679 			 *pRet = GetFormat( *pBoxFmt, rSz.GetWidth() );
4680 	if( pRet )
4681 		ChangeFrmFmt( &rBox, 0, *pRet );
4682 	else
4683 	{
4684 		pRet = rBox.ClaimFrmFmt();
4685         pRet->SetFmtAttr( rSz );
4686 		AddFormat( *pBoxFmt, *pRet );
4687 	}
4688 }
4689 
SetAttr(SwTableBox & rBox,const SfxPoolItem & rItem)4690 void SwShareBoxFmts::SetAttr( SwTableBox& rBox, const SfxPoolItem& rItem )
4691 {
4692 	SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(),
4693 			 *pRet = GetFormat( *pBoxFmt, rItem );
4694 	if( pRet )
4695 		ChangeFrmFmt( &rBox, 0, *pRet );
4696 	else
4697 	{
4698 		pRet = rBox.ClaimFrmFmt();
4699         pRet->SetFmtAttr( rItem );
4700 		AddFormat( *pBoxFmt, *pRet );
4701 	}
4702 }
4703 
SetAttr(SwTableLine & rLine,const SfxPoolItem & rItem)4704 void SwShareBoxFmts::SetAttr( SwTableLine& rLine, const SfxPoolItem& rItem )
4705 {
4706 	SwFrmFmt *pLineFmt = rLine.GetFrmFmt(),
4707 			 *pRet = GetFormat( *pLineFmt, rItem );
4708 	if( pRet )
4709 		ChangeFrmFmt( 0, &rLine, *pRet );
4710 	else
4711 	{
4712 		pRet = rLine.ClaimFrmFmt();
4713         pRet->SetFmtAttr( rItem );
4714 		AddFormat( *pLineFmt, *pRet );
4715 	}
4716 }
4717 
RemoveFormat(const SwFrmFmt & rFmt)4718 void SwShareBoxFmts::RemoveFormat( const SwFrmFmt& rFmt )
4719 {
4720 	for( sal_uInt16 i = aShareArr.Count(); i; )
4721 		if( aShareArr[ --i ]->RemoveFormat( rFmt ))
4722 			aShareArr.DeleteAndDestroy( i );
4723 }
4724 
Seek_Entry(const SwFrmFmt & rFmt,sal_uInt16 * pPos) const4725 sal_Bool SwShareBoxFmts::Seek_Entry( const SwFrmFmt& rFmt, sal_uInt16* pPos ) const
4726 {
4727 	sal_uLong nIdx = (sal_uLong)&rFmt;
4728 	sal_uInt16 nO = aShareArr.Count(), nM, nU = 0;
4729 	if( nO > 0 )
4730 	{
4731 		nO--;
4732 		while( nU <= nO )
4733 		{
4734 			nM = nU + ( nO - nU ) / 2;
4735 			sal_uLong nFmt = (sal_uLong)&aShareArr[ nM ]->GetOldFormat();
4736 			if( nFmt == nIdx )
4737 			{
4738 				if( pPos )
4739 					*pPos = nM;
4740 				return sal_True;
4741 			}
4742 			else if( nFmt < nIdx )
4743 				nU = nM + 1;
4744 			else if( nM == 0 )
4745 			{
4746 				if( pPos )
4747 					*pPos = nU;
4748 				return sal_False;
4749 			}
4750 			else
4751 				nO = nM - 1;
4752 		}
4753 	}
4754 	if( pPos )
4755 		*pPos = nU;
4756 	return sal_False;
4757 }
4758 
4759 
4760