Impress Remote 1.0.5, tag sdremote-1.0.5
[LibreOffice.git] / sw / source / core / doc / tblrwcl.cxx
blob65af1e53018b1e6da29ce902e5c3a1c35bf59455
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/text/HoriOrientation.hpp>
22 #include <com/sun/star/chart2/XChartDocument.hpp>
23 #include <hintids.hxx>
25 #include <editeng/brshitem.hxx>
26 #include <editeng/lrspitem.hxx>
27 #include <editeng/protitem.hxx>
28 #include <editeng/boxitem.hxx>
29 #include <tools/fract.hxx>
30 #include <fmtfsize.hxx>
31 #include <fmtornt.hxx>
32 #include <doc.hxx>
33 #include <cntfrm.hxx>
34 #include <tabfrm.hxx>
35 #include <frmtool.hxx>
36 #include <pam.hxx>
37 #include <swtable.hxx>
38 #include <ndtxt.hxx>
39 #include <tblsel.hxx>
40 #include <fldbas.hxx>
41 #include <swundo.hxx>
42 #include <rowfrm.hxx>
43 #include <ddefld.hxx>
44 #include <hints.hxx>
45 #include <UndoTable.hxx>
46 #include <cellatr.hxx>
47 #include <mvsave.hxx>
48 #include <swtblfmt.hxx>
49 #include <swddetbl.hxx>
50 #include <poolfmt.hxx>
51 #include <tblrwcl.hxx>
52 #include <unochart.hxx>
53 #include <boost/shared_ptr.hpp>
54 #include <boost/foreach.hpp>
55 #include <switerator.hxx>
57 using namespace com::sun::star;
58 using namespace com::sun::star::uno;
61 #define COLFUZZY 20
62 #define ROWFUZZY 10
64 using namespace ::com::sun::star;
66 #ifdef DBG_UTIL
67 #define CHECK_TABLE(t) (t).CheckConsistency();
68 #else
69 #define CHECK_TABLE(t)
70 #endif
72 typedef std::map<SwTableLine*, sal_uInt16> SwTableLineWidthMap_t;
74 // In order to set the Frame Formats for the Boxes, it's enough to look
75 // up the current one in the array. If it's already there return the new one.
76 struct _CpyTabFrm
78 union {
79 SwTableBoxFmt *pFrmFmt; // for CopyCol
80 SwTwips nSize; // for DelCol
81 } Value;
82 SwTableBoxFmt *pNewFrmFmt;
84 _CpyTabFrm( SwTableBoxFmt* pAktFrmFmt ) : pNewFrmFmt( 0 )
85 { Value.pFrmFmt = pAktFrmFmt; }
87 _CpyTabFrm& operator=( const _CpyTabFrm& );
89 bool operator==( const _CpyTabFrm& rCpyTabFrm ) const
90 { return (sal_uLong)Value.nSize == (sal_uLong)rCpyTabFrm.Value.nSize; }
91 bool operator<( const _CpyTabFrm& rCpyTabFrm ) const
92 { return (sal_uLong)Value.nSize < (sal_uLong)rCpyTabFrm.Value.nSize; }
95 struct CR_SetBoxWidth
97 SwSelBoxes m_Boxes;
98 SwTableLineWidthMap_t m_LineWidthMap;
99 SwShareBoxFmts aShareFmts;
100 SwTableNode* pTblNd;
101 SwUndoTblNdsChg* pUndo;
102 SwTwips nDiff, nSide, nMaxSize, nLowerDiff;
103 TblChgMode nMode;
104 sal_uInt16 nTblWidth, nRemainWidth, nBoxWidth;
105 bool bBigger, bLeft, bSplittBox, bAnyBoxFnd;
107 CR_SetBoxWidth( sal_uInt16 eType, SwTwips nDif, SwTwips nSid, SwTwips nTblW,
108 SwTwips nMax, SwTableNode* pTNd )
109 : pTblNd( pTNd ),
110 nDiff( nDif ), nSide( nSid ), nMaxSize( nMax ), nLowerDiff( 0 ),
111 nTblWidth( (sal_uInt16)nTblW ), nRemainWidth( 0 ), nBoxWidth( 0 ),
112 bSplittBox( false ), bAnyBoxFnd( false )
114 bLeft = nsTblChgWidthHeightType::WH_COL_LEFT == ( eType & 0xff ) ||
115 nsTblChgWidthHeightType::WH_CELL_LEFT == ( eType & 0xff );
116 bBigger = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_BIGGER );
117 nMode = pTblNd->GetTable().GetTblChgMode();
119 CR_SetBoxWidth( const CR_SetBoxWidth& rCpy )
120 : m_LineWidthMap(rCpy.m_LineWidthMap)
122 pTblNd( rCpy.pTblNd ),
123 pUndo( rCpy.pUndo ),
124 nDiff( rCpy.nDiff ), nSide( rCpy.nSide ),
125 nMaxSize( rCpy.nMaxSize ), nLowerDiff( 0 ),
126 nMode( rCpy.nMode ), nTblWidth( rCpy.nTblWidth ),
127 nRemainWidth( rCpy.nRemainWidth ), nBoxWidth( rCpy.nBoxWidth ),
128 bBigger( rCpy.bBigger ), bLeft( rCpy.bLeft ),
129 bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd )
133 SwUndoTblNdsChg* CreateUndo( SwUndoId eUndoType )
135 return pUndo = new SwUndoTblNdsChg( eUndoType, m_Boxes, *pTblNd );
138 void LoopClear()
140 nLowerDiff = 0; nRemainWidth = 0;
143 void AddBoxWidth( const SwTableBox& rBox, sal_uInt16 nWidth )
145 SwTableLine* p = (SwTableLine*)rBox.GetUpper();
146 std::pair<SwTableLineWidthMap_t::iterator, bool> aPair =
147 m_LineWidthMap.insert(std::make_pair(p,nWidth));
148 if (!aPair.second)
150 aPair.first->second += nWidth;
154 sal_uInt16 GetBoxWidth( const SwTableLine& rLn ) const
156 SwTableLine* p = (SwTableLine*)&rLn;
157 SwTableLineWidthMap_t::const_iterator const it = m_LineWidthMap.find(p);
158 return (it != m_LineWidthMap.end()) ? it->second : 0;
162 static bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
163 SwTwips nDist, bool bCheck );
164 static bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
165 SwTwips nDist, bool bCheck );
166 static bool lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
167 SwTwips nDist, bool bCheck );
168 static bool lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
169 SwTwips nDist, bool bCheck );
170 static bool lcl_DelSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
171 SwTwips nDist, bool bCheck );
172 static bool lcl_DelOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
173 SwTwips nDist, bool bCheck );
175 typedef bool (*FN_lcl_SetBoxWidth)(SwTableLine*, CR_SetBoxWidth&, SwTwips, bool );
177 #ifdef DBG_UTIL
179 void _CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize );
181 #define CHECKBOXWIDTH \
183 SwTwips nSize = GetFrmFmt()->GetFrmSize().GetWidth(); \
184 for (size_t nTmp = 0; nTmp < aLines.size(); ++nTmp) \
185 ::_CheckBoxWidth( *aLines[ nTmp ], nSize ); \
188 #define CHECKTABLELAYOUT \
190 for ( sal_uInt16 i = 0; i < GetTabLines().size(); ++i ) \
192 SwFrmFmt* pFmt = GetTabLines()[i]->GetFrmFmt(); \
193 SwIterator<SwRowFrm,SwFmt> aIter( *pFmt ); \
194 for (SwRowFrm* pFrm=aIter.First(); pFrm; pFrm=aIter.Next())\
196 if ( pFrm->GetTabLine() == GetTabLines()[i] ) \
198 OSL_ENSURE( pFrm->GetUpper()->IsTabFrm(), \
199 "Table layout does not match table structure" ); \
205 #else
207 #define CHECKBOXWIDTH
208 #define CHECKTABLELAYOUT
210 #endif // DBG_UTIL
212 struct CR_SetLineHeight
214 SwSelBoxes m_Boxes;
215 SwShareBoxFmts aShareFmts;
216 SwTableNode* pTblNd;
217 SwUndoTblNdsChg* pUndo;
218 SwTwips nMaxSpace, nMaxHeight;
219 TblChgMode nMode;
220 sal_uInt16 nLines;
221 bool bBigger, bTop, bSplittBox, bAnyBoxFnd;
223 CR_SetLineHeight( sal_uInt16 eType, SwTableNode* pTNd )
224 : pTblNd( pTNd ), pUndo( 0 ),
225 nMaxSpace( 0 ), nMaxHeight( 0 ), nLines( 0 ),
226 bSplittBox( false ), bAnyBoxFnd( false )
228 bTop = nsTblChgWidthHeightType::WH_ROW_TOP == ( eType & 0xff ) || nsTblChgWidthHeightType::WH_CELL_TOP == ( eType & 0xff );
229 bBigger = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_BIGGER );
230 if( eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL )
231 bBigger = !bBigger;
232 nMode = pTblNd->GetTable().GetTblChgMode();
234 CR_SetLineHeight( const CR_SetLineHeight& rCpy )
235 : pTblNd( rCpy.pTblNd ), pUndo( rCpy.pUndo ),
236 nMaxSpace( rCpy.nMaxSpace ), nMaxHeight( rCpy.nMaxHeight ),
237 nMode( rCpy.nMode ), nLines( rCpy.nLines ),
238 bBigger( rCpy.bBigger ), bTop( rCpy.bTop ),
239 bSplittBox( rCpy.bSplittBox ), bAnyBoxFnd( rCpy.bAnyBoxFnd )
242 SwUndoTblNdsChg* CreateUndo( SwUndoId nUndoType )
244 return pUndo = new SwUndoTblNdsChg( nUndoType, m_Boxes, *pTblNd );
248 static bool lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
249 SwTwips nDist, bool bCheck );
250 static bool lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
251 SwTwips nDist, bool bCheck );
252 static bool lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam,
253 SwTwips nDist, bool bCheck );
255 typedef bool (*FN_lcl_SetLineHeight)(SwTableLine*, CR_SetLineHeight&, SwTwips, bool );
257 _CpyTabFrm& _CpyTabFrm::operator=( const _CpyTabFrm& rCpyTabFrm )
259 pNewFrmFmt = rCpyTabFrm.pNewFrmFmt;
260 Value = rCpyTabFrm.Value;
261 return *this;
264 typedef o3tl::sorted_vector<_CpyTabFrm> _CpyTabFrms;
266 struct _CpyPara
268 boost::shared_ptr< std::vector< std::vector< sal_uLong > > > pWidths;
269 SwDoc* pDoc;
270 SwTableNode* pTblNd;
271 _CpyTabFrms& rTabFrmArr;
272 SwTableLine* pInsLine;
273 SwTableBox* pInsBox;
274 sal_uLong nOldSize, nNewSize; // in order to correct the size attributes
275 sal_uLong nMinLeft, nMaxRight;
276 sal_uInt16 nCpyCnt, nInsPos;
277 sal_uInt16 nLnIdx, nBoxIdx;
278 sal_uInt8 nDelBorderFlag;
279 bool bCpyCntnt;
281 _CpyPara( SwTableNode* pNd, sal_uInt16 nCopies, _CpyTabFrms& rFrmArr,
282 bool bCopyContent = true )
283 : pDoc( pNd->GetDoc() ), pTblNd( pNd ), rTabFrmArr(rFrmArr),
284 pInsLine(0), pInsBox(0), nOldSize(0), nNewSize(0),
285 nMinLeft(ULONG_MAX), nMaxRight(0),
286 nCpyCnt(nCopies), nInsPos(0),
287 nLnIdx(0), nBoxIdx(0),
288 nDelBorderFlag(0), bCpyCntnt( bCopyContent )
290 _CpyPara( const _CpyPara& rPara, SwTableLine* pLine )
291 : pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTblNd(rPara.pTblNd),
292 rTabFrmArr(rPara.rTabFrmArr), pInsLine(pLine), pInsBox(rPara.pInsBox),
293 nOldSize(0), nNewSize(rPara.nNewSize), nMinLeft( rPara.nMinLeft ),
294 nMaxRight( rPara.nMaxRight ), nCpyCnt(rPara.nCpyCnt), nInsPos(0),
295 nLnIdx( rPara.nLnIdx), nBoxIdx( rPara.nBoxIdx ),
296 nDelBorderFlag( rPara.nDelBorderFlag ), bCpyCntnt( rPara.bCpyCntnt )
298 _CpyPara( const _CpyPara& rPara, SwTableBox* pBox )
299 : pWidths( rPara.pWidths ), pDoc(rPara.pDoc), pTblNd(rPara.pTblNd),
300 rTabFrmArr(rPara.rTabFrmArr), pInsLine(rPara.pInsLine), pInsBox(pBox),
301 nOldSize(rPara.nOldSize), nNewSize(rPara.nNewSize),
302 nMinLeft( rPara.nMinLeft ), nMaxRight( rPara.nMaxRight ),
303 nCpyCnt(rPara.nCpyCnt), nInsPos(0), nLnIdx(rPara.nLnIdx), nBoxIdx(rPara.nBoxIdx),
304 nDelBorderFlag( rPara.nDelBorderFlag ), bCpyCntnt( rPara.bCpyCntnt )
306 void SetBoxWidth( SwTableBox* pBox );
309 static void lcl_CopyRow(_FndLine & rFndLine, _CpyPara *const pCpyPara);
311 static void lcl_CopyCol( _FndBox & rFndBox, _CpyPara *const pCpyPara)
313 // Look up the Frame Format in the Frame Format Array
314 SwTableBox* pBox = rFndBox.GetBox();
315 _CpyTabFrm aFindFrm( (SwTableBoxFmt*)pBox->GetFrmFmt() );
317 sal_uInt16 nFndPos;
318 if( pCpyPara->nCpyCnt )
320 _CpyTabFrms::const_iterator itFind = pCpyPara->rTabFrmArr.lower_bound( aFindFrm );
321 nFndPos = itFind - pCpyPara->rTabFrmArr.begin();
322 if( itFind == pCpyPara->rTabFrmArr.end() || !(*itFind == aFindFrm) )
324 // For nested copying, also save the new Format as an old one.
325 SwTableBoxFmt* pNewFmt = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
327 // Find the selected Boxes in the Line:
328 _FndLine const* pCmpLine = NULL;
329 SwFmtFrmSize aFrmSz( pNewFmt->GetFrmSize() );
331 bool bDiffCount = false;
332 if( pBox->GetTabLines().size() )
334 pCmpLine = &rFndBox.GetLines().front();
335 if ( pCmpLine->GetBoxes().size() != pCmpLine->GetLine()->GetTabBoxes().size() )
336 bDiffCount = true;
339 if( bDiffCount )
341 // The first Line should be enough
342 _FndBoxes const& rFndBoxes = pCmpLine->GetBoxes();
343 long nSz = 0;
344 for( sal_uInt16 n = rFndBoxes.size(); n; )
346 nSz += rFndBoxes[--n].GetBox()->
347 GetFrmFmt()->GetFrmSize().GetWidth();
349 aFrmSz.SetWidth( aFrmSz.GetWidth() -
350 nSz / ( pCpyPara->nCpyCnt + 1 ) );
351 pNewFmt->SetFmtAttr( aFrmSz );
352 aFrmSz.SetWidth( nSz / ( pCpyPara->nCpyCnt + 1 ) );
354 // Create a new Format for the new Box, specifying it's size.
355 aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pNewFmt->GetDoc()->
356 MakeTableLineFmt();
357 *aFindFrm.pNewFrmFmt = *pNewFmt;
358 aFindFrm.pNewFrmFmt->SetFmtAttr( aFrmSz );
360 else
362 aFrmSz.SetWidth( aFrmSz.GetWidth() / ( pCpyPara->nCpyCnt + 1 ) );
363 pNewFmt->SetFmtAttr( aFrmSz );
365 aFindFrm.pNewFrmFmt = pNewFmt;
366 pCpyPara->rTabFrmArr.insert( aFindFrm );
367 aFindFrm.Value.pFrmFmt = pNewFmt;
368 pCpyPara->rTabFrmArr.insert( aFindFrm );
371 else
373 aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ];
374 pBox->ChgFrmFmt( (SwTableBoxFmt*)aFindFrm.pNewFrmFmt );
377 else
379 _CpyTabFrms::const_iterator itFind = pCpyPara->rTabFrmArr.find( aFindFrm );
380 if( pCpyPara->nDelBorderFlag &&
381 itFind != pCpyPara->rTabFrmArr.end() )
382 aFindFrm = *itFind;
383 else
384 aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
387 if (!rFndBox.GetLines().empty())
389 pBox = new SwTableBox( aFindFrm.pNewFrmFmt,
390 rFndBox.GetLines().size(), pCpyPara->pInsLine );
391 pCpyPara->pInsLine->GetTabBoxes().insert( pCpyPara->pInsLine->GetTabBoxes().begin() + pCpyPara->nInsPos++, pBox );
392 _CpyPara aPara( *pCpyPara, pBox );
393 aPara.nDelBorderFlag &= 7;
395 BOOST_FOREACH( _FndLine & rFndLine, rFndBox.GetLines() )
396 lcl_CopyRow( rFndLine, &aPara );
398 else
400 ::_InsTblBox( pCpyPara->pDoc, pCpyPara->pTblNd, pCpyPara->pInsLine,
401 aFindFrm.pNewFrmFmt, pBox, pCpyPara->nInsPos++ );
403 const _FndBoxes& rFndBxs = rFndBox.GetUpper()->GetBoxes();
404 if( 8 > pCpyPara->nDelBorderFlag
405 ? pCpyPara->nDelBorderFlag
406 : &rFndBox == &rFndBxs[rFndBxs.size() - 1] )
408 const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
409 if( 8 > pCpyPara->nDelBorderFlag
410 ? rBoxItem.GetTop()
411 : rBoxItem.GetRight() )
413 aFindFrm.Value.pFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
415 SvxBoxItem aNew( rBoxItem );
416 if( 8 > pCpyPara->nDelBorderFlag )
417 aNew.SetLine( 0, BOX_LINE_TOP );
418 else
419 aNew.SetLine( 0, BOX_LINE_RIGHT );
421 if( 1 == pCpyPara->nDelBorderFlag ||
422 8 == pCpyPara->nDelBorderFlag )
424 // For all Boxes that delete TopBorderLine, we copy after that
425 pBox = pCpyPara->pInsLine->GetTabBoxes()[
426 pCpyPara->nInsPos - 1 ];
429 aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
431 // Else we copy before that and the first Line keeps the TopLine
432 // and we remove it at the original
433 pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
435 if( !pCpyPara->nCpyCnt )
436 pCpyPara->rTabFrmArr.insert( aFindFrm );
442 static void lcl_CopyRow(_FndLine& rFndLine, _CpyPara *const pCpyPara)
444 SwTableLine* pNewLine = new SwTableLine(
445 (SwTableLineFmt*)rFndLine.GetLine()->GetFrmFmt(),
446 rFndLine.GetBoxes().size(), pCpyPara->pInsBox );
447 if( pCpyPara->pInsBox )
449 SwTableLines& rLines = pCpyPara->pInsBox->GetTabLines();
450 rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
452 else
454 SwTableLines& rLines = pCpyPara->pTblNd->GetTable().GetTabLines();
455 rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
458 _CpyPara aPara( *pCpyPara, pNewLine );
459 for (_FndBoxes::iterator it = rFndLine.GetBoxes().begin();
460 it != rFndLine.GetBoxes().end(); ++it)
462 lcl_CopyCol(*it, &aPara);
465 pCpyPara->nDelBorderFlag &= 0xf8;
468 static void lcl_InsCol( _FndLine* pFndLn, _CpyPara& rCpyPara, sal_uInt16 nCpyCnt,
469 bool bBehind )
471 // Bug 29124: Not only copy in the BaseLines. If possible, we go down as far as possible
472 _FndBox* pFBox;
473 if( 1 == pFndLn->GetBoxes().size() &&
474 !( pFBox = &pFndLn->GetBoxes()[0] )->GetBox()->GetSttNd() )
476 // A Box with multiple Lines, so insert into these Lines
477 for( sal_uInt16 n = 0; n < pFBox->GetLines().size(); ++n )
478 lcl_InsCol( &pFBox->GetLines()[ n ], rCpyPara, nCpyCnt, bBehind );
480 else
482 rCpyPara.pInsLine = pFndLn->GetLine();
483 SwTableBox* pBox = pFndLn->GetBoxes()[ bBehind ?
484 pFndLn->GetBoxes().size()-1 : 0 ].GetBox();
485 rCpyPara.nInsPos = pFndLn->GetLine()->GetTabBoxes().GetPos( pBox );
486 if( bBehind )
487 ++rCpyPara.nInsPos;
489 for( sal_uInt16 n = 0; n < nCpyCnt; ++n )
491 if( n + 1 == nCpyCnt && bBehind )
492 rCpyPara.nDelBorderFlag = 9;
493 else
494 rCpyPara.nDelBorderFlag = 8;
495 for (_FndBoxes::iterator it = pFndLn->GetBoxes().begin();
496 it != pFndLn->GetBoxes().end(); ++it)
498 lcl_CopyCol(*it, &rCpyPara);
504 SwRowFrm* GetRowFrm( SwTableLine& rLine )
506 SwIterator<SwRowFrm,SwFmt> aIter( *rLine.GetFrmFmt() );
507 for( SwRowFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
508 if( pFrm->GetTabLine() == &rLine )
509 return pFrm;
510 return 0;
513 bool SwTable::InsertCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt, bool bBehind )
515 OSL_ENSURE( !rBoxes.empty() && nCnt, "No valid Box List" );
516 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
517 if( !pTblNd )
518 return false;
520 bool bRes = true;
521 if( IsNewModel() )
522 bRes = NewInsertCol( pDoc, rBoxes, nCnt, bBehind );
523 else
525 // Find all Boxes/Lines
526 _FndBox aFndBox( 0, 0 );
528 _FndPara aPara( rBoxes, &aFndBox );
529 ForEach_FndLineCopyCol( GetTabLines(), &aPara );
531 if( aFndBox.GetLines().empty() )
532 return false;
534 SetHTMLTableLayout( 0 ); // Delete HTML Layout
536 // Find Lines for the layout update
537 aFndBox.SetTableLines( *this );
538 aFndBox.DelFrms( *this );
540 // TL_CHART2: nothing to be done since chart2 currently does not want to
541 // get notified about new rows/cols.
543 _CpyTabFrms aTabFrmArr;
544 _CpyPara aCpyPara( pTblNd, nCnt, aTabFrmArr );
546 for( sal_uInt16 n = 0; n < aFndBox.GetLines().size(); ++n )
547 lcl_InsCol( &aFndBox.GetLines()[ n ], aCpyPara, nCnt, bBehind );
549 // clean up this Line's structure once again, generally all of them
550 GCLines();
552 // Update Layout
553 aFndBox.MakeFrms( *this );
555 CHECKBOXWIDTH;
556 CHECKTABLELAYOUT;
557 bRes = true;
560 SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
561 if (pPCD && nCnt)
562 pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
563 pDoc->UpdateCharts( GetFrmFmt()->GetName() );
565 return bRes;
568 bool SwTable::_InsertRow( SwDoc* pDoc, const SwSelBoxes& rBoxes,
569 sal_uInt16 nCnt, bool bBehind )
571 OSL_ENSURE( pDoc && !rBoxes.empty() && nCnt, "No valid Box List" );
572 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
573 if( !pTblNd )
574 return false;
576 // Find all Boxes/Lines
577 _FndBox aFndBox( 0, 0 );
579 _FndPara aPara( rBoxes, &aFndBox );
580 ForEach_FndLineCopyCol( GetTabLines(), &aPara );
582 if( aFndBox.GetLines().empty() )
583 return false;
585 SetHTMLTableLayout( 0 ); // Delete HTML Layout
587 _FndBox* pFndBox = &aFndBox;
589 _FndLine* pFndLine;
590 while( 1 == pFndBox->GetLines().size() &&
591 1 == ( pFndLine = &pFndBox->GetLines()[ 0 ])->GetBoxes().size() )
593 // Don't go down too far! One Line with Box needs to remain!
594 _FndBox* pTmpBox = &pFndLine->GetBoxes().front();
595 if( !pTmpBox->GetLines().empty() )
596 pFndBox = pTmpBox;
597 else
598 break;
602 // Find Lines for the layout update
603 const bool bLayout = !IsNewModel() &&
604 0 != SwIterator<SwTabFrm,SwFmt>::FirstElement( *GetFrmFmt() );
606 if ( bLayout )
608 aFndBox.SetTableLines( *this );
609 if( pFndBox != &aFndBox )
610 aFndBox.DelFrms( *this );
611 // TL_CHART2: nothing to be done since chart2 currently does not want to
612 // get notified about new rows/cols.
615 _CpyTabFrms aTabFrmArr;
616 _CpyPara aCpyPara( pTblNd, 0, aTabFrmArr );
618 SwTableLine* pLine = pFndBox->GetLines()[ bBehind ?
619 pFndBox->GetLines().size()-1 : 0 ].GetLine();
620 if( &aFndBox == pFndBox )
621 aCpyPara.nInsPos = GetTabLines().GetPos( pLine );
622 else
624 aCpyPara.pInsBox = pFndBox->GetBox();
625 aCpyPara.nInsPos = pFndBox->GetBox()->GetTabLines().GetPos( pLine );
628 if( bBehind )
630 ++aCpyPara.nInsPos;
631 aCpyPara.nDelBorderFlag = 1;
633 else
634 aCpyPara.nDelBorderFlag = 2;
636 for( sal_uInt16 nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt )
638 if( bBehind )
639 aCpyPara.nDelBorderFlag = 1;
640 BOOST_FOREACH( _FndLine& rFndLine, pFndBox->GetLines() )
641 lcl_CopyRow( rFndLine, &aCpyPara );
644 // clean up this Line's structure once again, generally all of them
645 if( !pDoc->IsInReading() )
646 GCLines();
648 // Update Layout
649 if ( bLayout )
651 if( pFndBox != &aFndBox )
652 aFndBox.MakeFrms( *this );
653 else
654 aFndBox.MakeNewFrms( *this, nCnt, bBehind );
657 CHECKBOXWIDTH;
658 CHECKTABLELAYOUT;
660 SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
661 if (pPCD && nCnt)
662 pPCD->AddRowCols( *this, rBoxes, nCnt, bBehind );
663 pDoc->UpdateCharts( GetFrmFmt()->GetName() );
665 return true;
668 void _FndBoxAppendRowLine( SwTableLine* pLine, _FndPara* pFndPara );
670 static void _FndBoxAppendRowBox( SwTableBox* pBox, _FndPara* pFndPara )
672 _FndBox* pFndBox = new _FndBox( pBox, pFndPara->pFndLine );
673 if( pBox->GetTabLines().size() )
675 _FndPara aPara( *pFndPara, pFndBox );
676 BOOST_FOREACH( SwTableLine* pLine, pFndBox->GetBox()->GetTabLines() )
677 _FndBoxAppendRowLine( pLine, &aPara );
678 if( pFndBox->GetLines().empty() )
679 delete pFndBox;
681 else
682 pFndPara->pFndLine->GetBoxes().push_back( pFndBox );
685 void _FndBoxAppendRowLine( SwTableLine* pLine, _FndPara* pFndPara )
687 _FndLine* pFndLine = new _FndLine( pLine, pFndPara->pFndBox );
688 _FndPara aPara( *pFndPara, pFndLine );
689 for( SwTableBoxes::iterator it = pFndLine->GetLine()->GetTabBoxes().begin();
690 it != pFndLine->GetLine()->GetTabBoxes().end(); ++it)
691 _FndBoxAppendRowBox(*it, &aPara );
692 if( pFndLine->GetBoxes().size() )
694 pFndPara->pFndBox->GetLines().push_back( pFndLine );
696 else
697 delete pFndLine;
700 bool SwTable::AppendRow( SwDoc* pDoc, sal_uInt16 nCnt )
702 SwTableNode *const pTblNd = const_cast<SwTableNode*>(
703 m_TabSortContentBoxes[0]->GetSttNd()->FindTableNode());
704 if( !pTblNd )
705 return false;
707 // Find all Boxes/Lines
708 _FndBox aFndBox( 0, 0 );
710 SwTableLine* pLLine = GetTabLines().back();
712 const SwSelBoxes* pBxs = 0; // Dummy!!!
713 _FndPara aPara( *pBxs, &aFndBox );
715 _FndBoxAppendRowLine(pLLine, &aPara);
717 if( aFndBox.GetLines().empty() )
718 return false;
720 SetHTMLTableLayout( 0 ); // Delete HTML Layout
722 // Find Lines for the Layout update
723 bool bLayout = 0 != SwIterator<SwTabFrm,SwFmt>::FirstElement( *GetFrmFmt() );
724 if( bLayout )
726 aFndBox.SetTableLines( *this );
727 // TL_CHART2: nothing to be done since chart2 currently does not want to
728 // get notified about new rows/cols.
731 _CpyTabFrms aTabFrmArr;
732 _CpyPara aCpyPara( pTblNd, 0, aTabFrmArr );
733 aCpyPara.nInsPos = GetTabLines().size();
734 aCpyPara.nDelBorderFlag = 1;
736 for( sal_uInt16 nCpyCnt = 0; nCpyCnt < nCnt; ++nCpyCnt )
738 aCpyPara.nDelBorderFlag = 1;
739 BOOST_FOREACH( _FndLine& rFndLine, aFndBox.GetLines() )
740 lcl_CopyRow( rFndLine, &aCpyPara );
743 // Clean up this Line's structure once again, generally all of them
744 if( !pDoc->IsInReading() )
745 GCLines();
747 // Update Layout
748 if ( bLayout )
750 aFndBox.MakeNewFrms( *this, nCnt, sal_True );
752 // TL_CHART2: need to inform chart of probably changed cell names
753 pDoc->UpdateCharts( GetFrmFmt()->GetName() );
755 CHECKBOXWIDTH;
756 CHECKTABLELAYOUT;
758 return true;
761 static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset,
762 bool bFirst, SwShareBoxFmts& rShareFmts );
764 static void lcl_LastBoxSetWidthLine( SwTableLines &rLines, const long nOffset,
765 bool bFirst, SwShareBoxFmts& rShareFmts )
767 for ( sal_uInt16 i = 0; i < rLines.size(); ++i )
768 ::lcl_LastBoxSetWidth( rLines[i]->GetTabBoxes(), nOffset, bFirst,
769 rShareFmts );
772 static void lcl_LastBoxSetWidth( SwTableBoxes &rBoxes, const long nOffset,
773 bool bFirst, SwShareBoxFmts& rShareFmts )
775 SwTableBox& rBox = *(bFirst ? rBoxes.front() : rBoxes.back());
776 if( !rBox.GetSttNd() )
777 ::lcl_LastBoxSetWidthLine( rBox.GetTabLines(), nOffset,
778 bFirst, rShareFmts );
780 // Adapt the Box
781 const SwFrmFmt *pBoxFmt = rBox.GetFrmFmt();
782 SwFmtFrmSize aNew( pBoxFmt->GetFrmSize() );
783 aNew.SetWidth( aNew.GetWidth() + nOffset );
784 SwFrmFmt *pFmt = rShareFmts.GetFormat( *pBoxFmt, aNew );
785 if( pFmt )
786 rBox.ChgFrmFmt( (SwTableBoxFmt*)pFmt );
787 else
789 pFmt = rBox.ClaimFrmFmt();
791 pFmt->LockModify();
792 pFmt->SetFmtAttr( aNew );
793 pFmt->UnlockModify();
795 rShareFmts.AddFormat( *pBoxFmt, *pFmt );
799 void _DeleteBox( SwTable& rTbl, SwTableBox* pBox, SwUndo* pUndo,
800 bool bCalcNewSize, const bool bCorrBorder,
801 SwShareBoxFmts* pShareFmts )
803 do {
804 SwTwips nBoxSz = bCalcNewSize ?
805 pBox->GetFrmFmt()->GetFrmSize().GetWidth() : 0;
806 SwTableLine* pLine = pBox->GetUpper();
807 SwTableBoxes& rTblBoxes = pLine->GetTabBoxes();
808 sal_uInt16 nDelPos = rTblBoxes.GetPos( pBox );
809 SwTableBox* pUpperBox = pBox->GetUpper()->GetUpper();
811 // Special treatment for the border:
812 if( bCorrBorder && 1 < rTblBoxes.size() )
814 bool bChgd = false;
815 const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
817 if( rBoxItem.GetLeft() || rBoxItem.GetRight() )
819 // JP 02.04.97: 1st part for Bug 36271
820 // First the left/right edges
821 if( nDelPos + 1 < (sal_uInt16)rTblBoxes.size() )
823 SwTableBox* pNxtBox = rTblBoxes[ nDelPos + 1 ];
824 const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrmFmt()->GetBox();
826 SwTableBox* pPrvBox = nDelPos ? rTblBoxes[ nDelPos - 1 ] : 0;
828 if( pNxtBox->GetSttNd() && !rNxtBoxItem.GetLeft() &&
829 ( !pPrvBox || !pPrvBox->GetFrmFmt()->GetBox().GetRight()) )
831 SvxBoxItem aTmp( rNxtBoxItem );
832 aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
833 : rBoxItem.GetRight(),
834 BOX_LINE_LEFT );
835 if( pShareFmts )
836 pShareFmts->SetAttr( *pNxtBox, aTmp );
837 else
838 pNxtBox->ClaimFrmFmt()->SetFmtAttr( aTmp );
839 bChgd = true;
842 if( !bChgd && nDelPos )
844 SwTableBox* pPrvBox = rTblBoxes[ nDelPos - 1 ];
845 const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrmFmt()->GetBox();
847 SwTableBox* pNxtBox = nDelPos + 1 < (sal_uInt16)rTblBoxes.size()
848 ? rTblBoxes[ nDelPos + 1 ] : 0;
850 if( pPrvBox->GetSttNd() && !rPrvBoxItem.GetRight() &&
851 ( !pNxtBox || !pNxtBox->GetFrmFmt()->GetBox().GetLeft()) )
853 SvxBoxItem aTmp( rPrvBoxItem );
854 aTmp.SetLine( rBoxItem.GetLeft() ? rBoxItem.GetLeft()
855 : rBoxItem.GetRight(),
856 BOX_LINE_RIGHT );
857 if( pShareFmts )
858 pShareFmts->SetAttr( *pPrvBox, aTmp );
859 else
860 pPrvBox->ClaimFrmFmt()->SetFmtAttr( aTmp );
867 // Delete the Box first, then the Nodes!
868 SwStartNode* pSttNd = (SwStartNode*)pBox->GetSttNd();
869 if( pShareFmts )
870 pShareFmts->RemoveFormat( *rTblBoxes[ nDelPos ]->GetFrmFmt() );
871 delete rTblBoxes[nDelPos];
872 rTblBoxes.erase( rTblBoxes.begin() + nDelPos );
874 if( pSttNd )
876 // Has the UndoObject been prepared to save the Section?
877 if( pUndo && pUndo->IsDelBox() )
878 ((SwUndoTblNdsChg*)pUndo)->SaveSection( pSttNd );
879 else
880 pSttNd->GetDoc()->DeleteSection( pSttNd );
883 // Also delete the Line?
884 if( !rTblBoxes.empty() )
886 // Then adapt the Frame-SSize
887 bool bLastBox = nDelPos == rTblBoxes.size();
888 if( bLastBox )
889 --nDelPos;
890 pBox = rTblBoxes[nDelPos];
891 if( bCalcNewSize )
893 SwFmtFrmSize aNew( pBox->GetFrmFmt()->GetFrmSize() );
894 aNew.SetWidth( aNew.GetWidth() + nBoxSz );
895 if( pShareFmts )
896 pShareFmts->SetSize( *pBox, aNew );
897 else
898 pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
900 if( !pBox->GetSttNd() )
902 // We need to this recursively in all Lines in all Cells!
903 SwShareBoxFmts aShareFmts;
904 ::lcl_LastBoxSetWidthLine( pBox->GetTabLines(), nBoxSz,
905 !bLastBox,
906 pShareFmts ? *pShareFmts
907 : aShareFmts );
910 break; // Stop deleting
912 // Delete the Line from the Table/Box
913 if( !pUpperBox )
915 // Also delete the Line from the Table
916 nDelPos = rTbl.GetTabLines().GetPos( pLine );
917 if( pShareFmts )
918 pShareFmts->RemoveFormat( *rTbl.GetTabLines()[ nDelPos ]->GetFrmFmt() );
919 delete rTbl.GetTabLines()[ nDelPos ];
920 rTbl.GetTabLines().erase( rTbl.GetTabLines().begin() + nDelPos );
921 break; // we cannot delete more
924 // finally also delete the Line
925 pBox = pUpperBox;
926 nDelPos = pBox->GetTabLines().GetPos( pLine );
927 if( pShareFmts )
928 pShareFmts->RemoveFormat( *pBox->GetTabLines()[ nDelPos ]->GetFrmFmt() );
929 delete pBox->GetTabLines()[ nDelPos ];
930 pBox->GetTabLines().erase( pBox->GetTabLines().begin() + nDelPos );
931 } while( pBox->GetTabLines().empty() );
934 static SwTableBox*
935 lcl_FndNxtPrvDelBox( const SwTableLines& rTblLns,
936 SwTwips nBoxStt, SwTwips nBoxWidth,
937 sal_uInt16 nLinePos, bool bNxt,
938 SwSelBoxes* pAllDelBoxes, size_t *const pCurPos)
940 SwTableBox* pFndBox = 0;
941 do {
942 if( bNxt )
943 ++nLinePos;
944 else
945 --nLinePos;
946 SwTableLine* pLine = rTblLns[ nLinePos ];
947 SwTwips nFndBoxWidth = 0;
948 SwTwips nFndWidth = nBoxStt + nBoxWidth;
949 sal_uInt16 nBoxCnt = pLine->GetTabBoxes().size();
951 pFndBox = pLine->GetTabBoxes()[ 0 ];
952 for( sal_uInt16 n = 0; 0 < nFndWidth && n < nBoxCnt; ++n )
954 pFndBox = pLine->GetTabBoxes()[ n ];
955 nFndWidth -= (nFndBoxWidth = pFndBox->GetFrmFmt()->
956 GetFrmSize().GetWidth());
959 // Find the first ContentBox
960 while( !pFndBox->GetSttNd() )
962 const SwTableLines& rLowLns = pFndBox->GetTabLines();
963 if( bNxt )
964 pFndBox = rLowLns.front()->GetTabBoxes().front();
965 else
966 pFndBox = rLowLns.back()->GetTabBoxes().front();
969 if( Abs( nFndWidth ) > COLFUZZY ||
970 Abs( nBoxWidth - nFndBoxWidth ) > COLFUZZY )
971 pFndBox = 0;
972 else if( pAllDelBoxes )
974 // If the predecessor will also be deleted, there's nothing to do
975 SwSelBoxes::const_iterator aFndIt = pAllDelBoxes->find( pFndBox);
976 if( aFndIt == pAllDelBoxes->end() )
977 break;
978 size_t const nFndPos = aFndIt - pAllDelBoxes->begin() ;
980 // else, we keep on searching.
981 // We do not need to recheck the Box, however
982 pFndBox = 0;
983 if( nFndPos <= *pCurPos )
984 --*pCurPos;
985 pAllDelBoxes->erase( pAllDelBoxes->begin() + nFndPos );
987 } while( bNxt ? ( nLinePos + 1 < (sal_uInt16)rTblLns.size() ) : nLinePos );
988 return pFndBox;
991 static void
992 lcl_SaveUpperLowerBorder( SwTable& rTbl, const SwTableBox& rBox,
993 SwShareBoxFmts& rShareFmts,
994 SwSelBoxes* pAllDelBoxes = 0,
995 size_t *const pCurPos = 0 )
997 //JP 16.04.97: 2. part for Bug 36271
998 bool bChgd = false;
999 const SwTableLine* pLine = rBox.GetUpper();
1000 const SwTableBoxes& rTblBoxes = pLine->GetTabBoxes();
1001 const SwTableBox* pUpperBox = &rBox;
1002 sal_uInt16 nDelPos = rTblBoxes.GetPos( pUpperBox );
1003 pUpperBox = rBox.GetUpper()->GetUpper();
1004 const SvxBoxItem& rBoxItem = rBox.GetFrmFmt()->GetBox();
1006 // then the top/bottom edges
1007 if( rBoxItem.GetTop() || rBoxItem.GetBottom() )
1009 bChgd = false;
1010 const SwTableLines* pTblLns;
1011 if( pUpperBox )
1012 pTblLns = &pUpperBox->GetTabLines();
1013 else
1014 pTblLns = &rTbl.GetTabLines();
1016 sal_uInt16 nLnPos = pTblLns->GetPos( pLine );
1018 // Calculate the attribute position of the top-be-deleted Box and then
1019 // search in the top/bottom Line of the respective counterparts.
1020 SwTwips nBoxStt = 0;
1021 for( sal_uInt16 n = 0; n < nDelPos; ++n )
1022 nBoxStt += rTblBoxes[ n ]->GetFrmFmt()->GetFrmSize().GetWidth();
1023 SwTwips nBoxWidth = rBox.GetFrmFmt()->GetFrmSize().GetWidth();
1025 SwTableBox *pPrvBox = 0, *pNxtBox = 0;
1026 if( nLnPos ) // Predecessor?
1027 pPrvBox = ::lcl_FndNxtPrvDelBox( *pTblLns, nBoxStt, nBoxWidth,
1028 nLnPos, false, pAllDelBoxes, pCurPos );
1030 if( nLnPos + 1 < (sal_uInt16)pTblLns->size() ) // Successor?
1031 pNxtBox = ::lcl_FndNxtPrvDelBox( *pTblLns, nBoxStt, nBoxWidth,
1032 nLnPos, true, pAllDelBoxes, pCurPos );
1034 if( pNxtBox && pNxtBox->GetSttNd() )
1036 const SvxBoxItem& rNxtBoxItem = pNxtBox->GetFrmFmt()->GetBox();
1037 if( !rNxtBoxItem.GetTop() && ( !pPrvBox ||
1038 !pPrvBox->GetFrmFmt()->GetBox().GetBottom()) )
1040 SvxBoxItem aTmp( rNxtBoxItem );
1041 aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
1042 : rBoxItem.GetBottom(),
1043 BOX_LINE_TOP );
1044 rShareFmts.SetAttr( *pNxtBox, aTmp );
1045 bChgd = true;
1048 if( !bChgd && pPrvBox && pPrvBox->GetSttNd() )
1050 const SvxBoxItem& rPrvBoxItem = pPrvBox->GetFrmFmt()->GetBox();
1051 if( !rPrvBoxItem.GetTop() && ( !pNxtBox ||
1052 !pNxtBox->GetFrmFmt()->GetBox().GetTop()) )
1054 SvxBoxItem aTmp( rPrvBoxItem );
1055 aTmp.SetLine( rBoxItem.GetTop() ? rBoxItem.GetTop()
1056 : rBoxItem.GetBottom(),
1057 BOX_LINE_BOTTOM );
1058 rShareFmts.SetAttr( *pPrvBox, aTmp );
1065 bool SwTable::DeleteSel(
1066 SwDoc* pDoc
1068 const SwSelBoxes& rBoxes,
1069 const SwSelBoxes* pMerged, SwUndo* pUndo,
1070 const bool bDelMakeFrms, const bool bCorrBorder )
1072 OSL_ENSURE( pDoc, "No doc?" );
1073 SwTableNode* pTblNd = 0;
1074 if( !rBoxes.empty() )
1076 pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1077 if( !pTblNd )
1078 return false;
1081 SetHTMLTableLayout( 0 ); // Delete HTML Layout
1083 // Find Lines for the Layout update
1084 _FndBox aFndBox( 0, 0 );
1085 if ( bDelMakeFrms )
1087 if( pMerged && !pMerged->empty() )
1088 aFndBox.SetTableLines( *pMerged, *this );
1089 else if( !rBoxes.empty() )
1090 aFndBox.SetTableLines( rBoxes, *this );
1091 aFndBox.DelFrms( *this );
1094 SwShareBoxFmts aShareFmts;
1096 // First switch the Border, then delete
1097 if( bCorrBorder )
1099 SwSelBoxes aBoxes( rBoxes );
1100 for (size_t n = 0; n < aBoxes.size(); ++n)
1102 ::lcl_SaveUpperLowerBorder( *this, *rBoxes[ n ], aShareFmts,
1103 &aBoxes, &n );
1107 PrepareDelBoxes( rBoxes );
1109 SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
1110 // Delete boxes from last to first
1111 for (size_t n = 0; n < rBoxes.size(); ++n)
1113 size_t const nIdx = rBoxes.size() - 1 - n;
1115 // First adapt the data-sequence for chart if necessary
1116 // (needed to move the implementation cursor properly to it's new
1117 // position which can't be done properly if the cell is already gone)
1118 if (pPCD && pTblNd)
1119 pPCD->DeleteBox( &pTblNd->GetTable(), *rBoxes[nIdx] );
1121 // ... then delete the boxes
1122 _DeleteBox( *this, rBoxes[nIdx], pUndo, true, bCorrBorder, &aShareFmts );
1125 // then clean up the structure of all Lines
1126 GCLines();
1128 if( bDelMakeFrms && aFndBox.AreLinesToRestore( *this ) )
1129 aFndBox.MakeFrms( *this );
1131 // TL_CHART2: now inform chart that sth has changed
1132 pDoc->UpdateCharts( GetFrmFmt()->GetName() );
1134 CHECKTABLELAYOUT;
1135 CHECK_TABLE( *this );
1137 return true;
1140 bool SwTable::OldSplitRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt,
1141 bool bSameHeight )
1143 OSL_ENSURE( pDoc && !rBoxes.empty() && nCnt, "No valid values" );
1144 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1145 if( !pTblNd )
1146 return false;
1148 // TL_CHART2: splitting/merging of a number of cells or rows will usually make
1149 // the table too complex to be handled with chart.
1150 // Thus we tell the charts to use their own data provider and forget about this table
1151 pDoc->CreateChartInternalDataProviders( this );
1153 SetHTMLTableLayout( 0 ); // Delete HTML Layout
1155 // If the rows should get the same (min) height, we first have
1156 // to store the old row heights before deleting the frames
1157 long* pRowHeights = 0;
1158 if ( bSameHeight )
1160 pRowHeights = new long[ rBoxes.size() ];
1161 for (size_t n = 0; n < rBoxes.size(); ++n)
1163 SwTableBox* pSelBox = rBoxes[n];
1164 const SwRowFrm* pRow = GetRowFrm( *pSelBox->GetUpper() );
1165 OSL_ENSURE( pRow, "Where is the SwTableLine's Frame?" );
1166 SWRECTFN( pRow )
1167 pRowHeights[ n ] = (pRow->Frm().*fnRect->fnGetHeight)();
1171 // Find Lines for the Layout update
1172 _FndBox aFndBox( 0, 0 );
1173 aFndBox.SetTableLines( rBoxes, *this );
1174 aFndBox.DelFrms( *this );
1176 for (size_t n = 0; n < rBoxes.size(); ++n)
1178 SwTableBox* pSelBox = rBoxes[n];
1179 OSL_ENSURE( pSelBox, "Box is not within the Table" );
1181 // Insert nCnt new Lines into the Box
1182 SwTableLine* pInsLine = pSelBox->GetUpper();
1183 SwTableBoxFmt* pFrmFmt = (SwTableBoxFmt*)pSelBox->GetFrmFmt();
1185 // Respect the Line's height, reset if needed
1186 SwFmtFrmSize aFSz( pInsLine->GetFrmFmt()->GetFrmSize() );
1187 if ( bSameHeight && ATT_VAR_SIZE == aFSz.GetHeightSizeType() )
1188 aFSz.SetHeightSizeType( ATT_MIN_SIZE );
1190 bool bChgLineSz = 0 != aFSz.GetHeight() || bSameHeight;
1191 if ( bChgLineSz )
1192 aFSz.SetHeight( ( bSameHeight ? pRowHeights[ n ] : aFSz.GetHeight() ) /
1193 (nCnt + 1) );
1195 SwTableBox* pNewBox = new SwTableBox( pFrmFmt, nCnt, pInsLine );
1196 sal_uInt16 nBoxPos = pInsLine->GetTabBoxes().GetPos( pSelBox );
1197 pInsLine->GetTabBoxes()[nBoxPos] = pNewBox; // overwrite old one
1199 // Delete background/border attribute
1200 SwTableBox* pLastBox = pSelBox; // To distribute the TextNodes!
1201 // If Areas are contained in the Box, it stays as is
1202 // !! If this is changed we need to adapt the Undo, too !!!
1203 bool bMoveNodes = true;
1205 sal_uLong nSttNd = pLastBox->GetSttIdx() + 1,
1206 nEndNd = pLastBox->GetSttNd()->EndOfSectionIndex();
1207 while( nSttNd < nEndNd )
1208 if( !pDoc->GetNodes()[ nSttNd++ ]->IsTxtNode() )
1210 bMoveNodes = false;
1211 break;
1215 SwTableBoxFmt* pCpyBoxFrmFmt = (SwTableBoxFmt*)pSelBox->GetFrmFmt();
1216 bool bChkBorder = 0 != pCpyBoxFrmFmt->GetBox().GetTop();
1217 if( bChkBorder )
1218 pCpyBoxFrmFmt = (SwTableBoxFmt*)pSelBox->ClaimFrmFmt();
1220 for( sal_uInt16 i = 0; i <= nCnt; ++i )
1222 // Create a new Line in the new Box
1223 SwTableLine* pNewLine = new SwTableLine(
1224 (SwTableLineFmt*)pInsLine->GetFrmFmt(), 1, pNewBox );
1225 if( bChgLineSz )
1227 pNewLine->ClaimFrmFmt()->SetFmtAttr( aFSz );
1230 pNewBox->GetTabLines().insert( pNewBox->GetTabLines().begin() + i, pNewLine );
1231 // then a new Box in the Line
1232 if( !i ) // hang up the original Box
1234 pSelBox->SetUpper( pNewLine );
1235 pNewLine->GetTabBoxes().insert( pNewLine->GetTabBoxes().begin(), pSelBox );
1237 else
1239 ::_InsTblBox( pDoc, pTblNd, pNewLine, pCpyBoxFrmFmt,
1240 pLastBox, 0 );
1242 if( bChkBorder )
1244 pCpyBoxFrmFmt = (SwTableBoxFmt*)pNewLine->GetTabBoxes()[ 0 ]->ClaimFrmFmt();
1245 SvxBoxItem aTmp( pCpyBoxFrmFmt->GetBox() );
1246 aTmp.SetLine( 0, BOX_LINE_TOP );
1247 pCpyBoxFrmFmt->SetFmtAttr( aTmp );
1248 bChkBorder = false;
1251 if( bMoveNodes )
1253 const SwNode* pEndNd = pLastBox->GetSttNd()->EndOfSectionNode();
1254 if( pLastBox->GetSttIdx()+2 != pEndNd->GetIndex() )
1256 // Move TextNodes
1257 SwNodeRange aRg( *pLastBox->GetSttNd(), +2, *pEndNd );
1258 pLastBox = pNewLine->GetTabBoxes()[0]; // reset
1259 SwNodeIndex aInsPos( *pLastBox->GetSttNd(), 1 );
1260 pDoc->GetNodes()._MoveNodes(aRg, pDoc->GetNodes(), aInsPos, sal_False);
1261 pDoc->GetNodes().Delete( aInsPos, 1 ); // delete the empty one
1266 // In Boxes with Lines, we can only have Size/Fillorder
1267 pFrmFmt = (SwTableBoxFmt*)pNewBox->ClaimFrmFmt();
1268 pFrmFmt->ResetFmtAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
1269 pFrmFmt->ResetFmtAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
1272 delete[] pRowHeights;
1274 GCLines();
1276 aFndBox.MakeFrms( *this );
1278 CHECKBOXWIDTH
1279 CHECKTABLELAYOUT
1280 return true;
1283 bool SwTable::SplitCol( SwDoc* pDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCnt )
1285 OSL_ENSURE( pDoc && !rBoxes.empty() && nCnt, "No valid values" );
1286 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1287 if( !pTblNd )
1288 return false;
1290 // TL_CHART2: splitting/merging of a number of cells or rows will usually make
1291 // the table too complex to be handled with chart.
1292 // Thus we tell the charts to use their own data provider and forget about this table
1293 pDoc->CreateChartInternalDataProviders( this );
1295 SetHTMLTableLayout( 0 ); // Delete HTML Layout
1296 SwSelBoxes aSelBoxes(rBoxes);
1297 ExpandSelection( aSelBoxes );
1299 // Find Lines for the Layout update
1300 _FndBox aFndBox( 0, 0 );
1301 aFndBox.SetTableLines( aSelBoxes, *this );
1302 aFndBox.DelFrms( *this );
1304 _CpyTabFrms aFrmArr;
1305 std::vector<SwTableBoxFmt*> aLastBoxArr;
1306 sal_uInt16 nFndPos;
1307 for (size_t n = 0; n < aSelBoxes.size(); ++n)
1309 SwTableBox* pSelBox = aSelBoxes[n];
1310 OSL_ENSURE( pSelBox, "Box steht nicht in der Tabelle" );
1312 // We don't want to split small table cells into very very small cells
1313 if( pSelBox->GetFrmFmt()->GetFrmSize().GetWidth()/( nCnt + 1 ) < 10 )
1314 continue;
1316 // Then split the nCnt Box up into nCnt Boxes
1317 SwTableLine* pInsLine = pSelBox->GetUpper();
1318 sal_uInt16 nBoxPos = pInsLine->GetTabBoxes().GetPos( pSelBox );
1320 // Find the Frame Format in the Frame Format Array
1321 SwTableBoxFmt* pLastBoxFmt;
1322 _CpyTabFrm aFindFrm( (SwTableBoxFmt*)pSelBox->GetFrmFmt() );
1323 _CpyTabFrms::const_iterator itFind = aFrmArr.lower_bound( aFindFrm );
1324 nFndPos = itFind - aFrmArr.begin();
1325 if( itFind == aFrmArr.end() || !(*itFind == aFindFrm) )
1327 // Change the FrmFmt
1328 aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pSelBox->ClaimFrmFmt();
1329 SwTwips nBoxSz = aFindFrm.pNewFrmFmt->GetFrmSize().GetWidth();
1330 SwTwips nNewBoxSz = nBoxSz / ( nCnt + 1 );
1331 aFindFrm.pNewFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1332 nNewBoxSz, 0 ) );
1333 aFrmArr.insert( aFindFrm );
1335 pLastBoxFmt = aFindFrm.pNewFrmFmt;
1336 if( nBoxSz != ( nNewBoxSz * (nCnt + 1)))
1338 // We have a remainder, so we need to define an own Format
1339 // for the last Box.
1340 pLastBoxFmt = new SwTableBoxFmt( *aFindFrm.pNewFrmFmt );
1341 pLastBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1342 nBoxSz - ( nNewBoxSz * nCnt ), 0 ) );
1344 aLastBoxArr.insert( aLastBoxArr.begin() + nFndPos, pLastBoxFmt );
1346 else
1348 aFindFrm = aFrmArr[ nFndPos ];
1349 pSelBox->ChgFrmFmt( (SwTableBoxFmt*)aFindFrm.pNewFrmFmt );
1350 pLastBoxFmt = aLastBoxArr[ nFndPos ];
1353 // Insert the Boxes at the Position
1354 for( sal_uInt16 i = 1; i < nCnt; ++i )
1355 ::_InsTblBox( pDoc, pTblNd, pInsLine, aFindFrm.pNewFrmFmt,
1356 pSelBox, nBoxPos + i ); // insert after
1358 ::_InsTblBox( pDoc, pTblNd, pInsLine, pLastBoxFmt,
1359 pSelBox, nBoxPos + nCnt ); // insert after
1361 // Special treatment for the Border:
1362 const SvxBoxItem& aSelBoxItem = aFindFrm.pNewFrmFmt->GetBox();
1363 if( aSelBoxItem.GetRight() )
1365 pInsLine->GetTabBoxes()[ nBoxPos + nCnt ]->ClaimFrmFmt();
1367 SvxBoxItem aTmp( aSelBoxItem );
1368 aTmp.SetLine( 0, BOX_LINE_RIGHT );
1369 aFindFrm.pNewFrmFmt->SetFmtAttr( aTmp );
1371 // Remove the Format from the "cache"
1372 for( sal_uInt16 i = aFrmArr.size(); i; )
1374 const _CpyTabFrm& rCTF = aFrmArr[ --i ];
1375 if( rCTF.pNewFrmFmt == aFindFrm.pNewFrmFmt ||
1376 rCTF.Value.pFrmFmt == aFindFrm.pNewFrmFmt )
1378 aFrmArr.erase( aFrmArr.begin() + i );
1379 aLastBoxArr.erase( aLastBoxArr.begin() + i );
1385 // Update Layout
1386 aFndBox.MakeFrms( *this );
1388 CHECKBOXWIDTH
1389 CHECKTABLELAYOUT
1390 return true;
1394 ----------------------- >> MERGE << ------------------------
1395 Algorithm:
1396 If we only have one Line in the _FndBox, take this Line and test
1397 the Box count:
1398 - If we have more than one Box, we merge on Box level, meaning
1399 the new Box will be as wide as the old ones.
1400 - All Lines that are above/under the Area, are inserted into
1401 the Box as Line + Box.
1402 - All Lines that come before/after the Area, are inserted into
1403 the Boxes Left/Right.
1405 ----------------------- >> MERGE << ------------------------
1407 static void lcl_CpyLines( sal_uInt16 nStt, sal_uInt16 nEnd,
1408 SwTableLines& rLines,
1409 SwTableBox* pInsBox,
1410 sal_uInt16 nPos = USHRT_MAX )
1412 for( sal_uInt16 n = nStt; n < nEnd; ++n )
1413 rLines[n]->SetUpper( pInsBox );
1414 if( USHRT_MAX == nPos )
1415 nPos = pInsBox->GetTabLines().size();
1416 pInsBox->GetTabLines().insert( pInsBox->GetTabLines().begin() + nPos,
1417 rLines.begin() + nStt, rLines.begin() + nEnd );
1418 rLines.erase( rLines.begin() + nStt, rLines.begin() + nEnd );
1421 static void lcl_CpyBoxes( sal_uInt16 nStt, sal_uInt16 nEnd,
1422 SwTableBoxes& rBoxes,
1423 SwTableLine* pInsLine,
1424 sal_uInt16 nPos = USHRT_MAX )
1426 for( sal_uInt16 n = nStt; n < nEnd; ++n )
1427 rBoxes[n]->SetUpper( pInsLine );
1428 if( USHRT_MAX == nPos )
1429 nPos = pInsLine->GetTabBoxes().size();
1430 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + nPos,
1431 rBoxes.begin() + nStt, rBoxes.begin() + nEnd );
1432 rBoxes.erase( rBoxes.begin() + nStt, rBoxes.begin() + nEnd );
1435 static void lcl_CalcWidth( SwTableBox* pBox )
1437 // Assertion: Every Line in the Box is as large
1438 SwFrmFmt* pFmt = pBox->ClaimFrmFmt();
1439 OSL_ENSURE( pBox->GetTabLines().size(), "Box does not have any Lines" );
1441 SwTableLine* pLine = pBox->GetTabLines()[0];
1442 OSL_ENSURE( pLine, "Box is not within a Line" );
1444 long nWidth = 0;
1445 for( sal_uInt16 n = 0; n < pLine->GetTabBoxes().size(); ++n )
1446 nWidth += pLine->GetTabBoxes()[n]->GetFrmFmt()->GetFrmSize().GetWidth();
1448 pFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 ));
1450 // Boxes with Lines can only have Size/Fillorder
1451 pFmt->ResetFmtAttr( RES_LR_SPACE, RES_FRMATR_END - 1 );
1452 pFmt->ResetFmtAttr( RES_BOXATR_BEGIN, RES_BOXATR_END - 1 );
1455 struct _InsULPara
1457 SwTableNode* pTblNd;
1458 SwTableLine* pInsLine;
1459 SwTableBox* pInsBox;
1460 bool bUL_LR : 1; // Upper-Lower(true) or Left-Right(false) ?
1461 bool bUL : 1; // Upper-Left(true) or Lower-Right(false) ?
1463 SwTableBox* pLeftBox;
1464 SwTableBox* pRightBox;
1465 SwTableBox* pMergeBox;
1467 _InsULPara( SwTableNode* pTNd, bool bUpperLower, bool bUpper,
1468 SwTableBox* pLeft, SwTableBox* pMerge, SwTableBox* pRight,
1469 SwTableLine* pLine=0, SwTableBox* pBox=0 )
1470 : pTblNd( pTNd ), pInsLine( pLine ), pInsBox( pBox ),
1471 pLeftBox( pLeft ), pRightBox( pRight ), pMergeBox( pMerge )
1472 { bUL_LR = bUpperLower; bUL = bUpper; }
1474 void SetLeft( SwTableBox* pBox=0 )
1475 { bUL_LR = false; bUL = true; if( pBox ) pInsBox = pBox; }
1476 void SetRight( SwTableBox* pBox=0 )
1477 { bUL_LR = false; bUL = false; if( pBox ) pInsBox = pBox; }
1478 void SetUpper( SwTableLine* pLine=0 )
1479 { bUL_LR = true; bUL = true; if( pLine ) pInsLine = pLine; }
1480 void SetLower( SwTableLine* pLine=0 )
1481 { bUL_LR = true; bUL = false; if( pLine ) pInsLine = pLine; }
1484 static void lcl_Merge_MoveLine(_FndLine & rFndLine, _InsULPara *const pULPara);
1486 static void lcl_Merge_MoveBox(_FndBox & rFndBox, _InsULPara *const pULPara)
1488 SwTableBoxes* pBoxes;
1490 sal_uInt16 nStt = 0, nEnd = rFndBox.GetLines().size();
1491 sal_uInt16 nInsPos = USHRT_MAX;
1492 if( !pULPara->bUL_LR ) // Left/Right
1494 sal_uInt16 nPos;
1495 SwTableBox* pFndTableBox = rFndBox.GetBox();
1496 pBoxes = &pFndTableBox->GetUpper()->GetTabBoxes();
1497 if( pULPara->bUL ) // Left ?
1499 // if there are Boxes before it, move them
1500 if( 0 != ( nPos = pBoxes->GetPos( pFndTableBox ) ) )
1501 lcl_CpyBoxes( 0, nPos, *pBoxes, pULPara->pInsLine );
1503 else // Right
1504 // if there are Boxes behind it, move them
1505 if( (nPos = pBoxes->GetPos( pFndTableBox )) +1 < (sal_uInt16)pBoxes->size() )
1507 nInsPos = pULPara->pInsLine->GetTabBoxes().size();
1508 lcl_CpyBoxes( nPos+1, pBoxes->size(),
1509 *pBoxes, pULPara->pInsLine );
1512 // Upper/Lower and still deeper?
1513 else if (!rFndBox.GetLines().empty())
1515 // Only search the Line from which we need to move
1516 nStt = pULPara->bUL ? 0 : rFndBox.GetLines().size()-1;
1517 nEnd = nStt+1;
1520 pBoxes = &pULPara->pInsLine->GetTabBoxes();
1522 // Is there still a level to step down to?
1523 if (rFndBox.GetBox()->GetTabLines().size())
1525 SwTableBox* pBox = new SwTableBox(
1526 static_cast<SwTableBoxFmt*>(rFndBox.GetBox()->GetFrmFmt()),
1527 0, pULPara->pInsLine );
1528 _InsULPara aPara( *pULPara );
1529 aPara.pInsBox = pBox;
1530 for (_FndLines::iterator it = rFndBox.GetLines().begin() + nStt;
1531 it != rFndBox.GetLines().begin() + nEnd; ++it )
1533 lcl_Merge_MoveLine(*it, &aPara );
1535 if( pBox->GetTabLines().size() )
1537 if( USHRT_MAX == nInsPos )
1538 nInsPos = pBoxes->size();
1539 pBoxes->insert( pBoxes->begin() + nInsPos, pBox );
1540 lcl_CalcWidth( pBox ); // calculate the Box's width
1542 else
1543 delete pBox;
1547 static void lcl_Merge_MoveLine(_FndLine& rFndLine, _InsULPara *const pULPara)
1549 SwTableLines* pLines;
1551 sal_uInt16 nStt = 0, nEnd = rFndLine.GetBoxes().size();
1552 sal_uInt16 nInsPos = USHRT_MAX;
1553 if( pULPara->bUL_LR ) // UpperLower ?
1555 sal_uInt16 nPos;
1556 SwTableLine* pFndLn = (SwTableLine*)rFndLine.GetLine();
1557 pLines = pFndLn->GetUpper() ?
1558 &pFndLn->GetUpper()->GetTabLines() :
1559 &pULPara->pTblNd->GetTable().GetTabLines();
1561 SwTableBox* pLBx = rFndLine.GetBoxes().front().GetBox();
1562 SwTableBox* pRBx = rFndLine.GetBoxes().back().GetBox();
1563 sal_uInt16 nLeft = pFndLn->GetTabBoxes().GetPos( pLBx );
1564 sal_uInt16 nRight = pFndLn->GetTabBoxes().GetPos( pRBx );
1566 if( !nLeft || nRight == pFndLn->GetTabBoxes().size() )
1568 if( pULPara->bUL ) // Upper ?
1570 // If there are Lines before it, move them
1571 if( 0 != ( nPos = pLines->GetPos( pFndLn )) )
1572 lcl_CpyLines( 0, nPos, *pLines, pULPara->pInsBox );
1574 else
1575 // If there are Lines after it, move them
1576 if( (nPos = pLines->GetPos( pFndLn )) + 1 < (sal_uInt16)pLines->size() )
1578 nInsPos = pULPara->pInsBox->GetTabLines().size();
1579 lcl_CpyLines( nPos+1, pLines->size(), *pLines,
1580 pULPara->pInsBox );
1583 else if( nLeft )
1585 // There are still Boxes on the left side, so put the Left-
1586 // and Merge-Box into one Box and Line, insert before/after
1587 // a Line with a Box, into which the upper/lower Lines are
1588 // inserted
1589 SwTableLine* pInsLine = pULPara->pLeftBox->GetUpper();
1590 SwTableBox* pLMBox = new SwTableBox(
1591 (SwTableBoxFmt*)pULPara->pLeftBox->GetFrmFmt(), 0, pInsLine );
1592 SwTableLine* pLMLn = new SwTableLine(
1593 (SwTableLineFmt*)pInsLine->GetFrmFmt(), 2, pLMBox );
1594 pLMLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE );
1596 pLMBox->GetTabLines().insert( pLMBox->GetTabLines().begin(), pLMLn );
1598 lcl_CpyBoxes( 0, 2, pInsLine->GetTabBoxes(), pLMLn );
1600 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin(), pLMBox );
1602 if( pULPara->bUL ) // Upper ?
1604 // If there are Lines before it, move them
1605 if( 0 != ( nPos = pLines->GetPos( pFndLn )) )
1606 lcl_CpyLines( 0, nPos, *pLines, pLMBox, 0 );
1608 else
1609 // If there are Lines after it, move them
1610 if( (nPos = pLines->GetPos( pFndLn )) + 1 < (sal_uInt16)pLines->size() )
1611 lcl_CpyLines( nPos+1, pLines->size(), *pLines,
1612 pLMBox );
1613 lcl_CalcWidth( pLMBox ); // calculate the Box's width
1615 else if( nRight+1 < (sal_uInt16)pFndLn->GetTabBoxes().size() )
1617 // There are still Boxes on the right, so put the Right-
1618 // and Merge-Box into one Box and Line, insert before/after
1619 // a Line with a Box, into which the upper/lower Lines are
1620 // inserted
1621 SwTableLine* pInsLine = pULPara->pRightBox->GetUpper();
1622 SwTableBox* pRMBox;
1623 if( pULPara->pLeftBox->GetUpper() == pInsLine )
1625 pRMBox = new SwTableBox(
1626 (SwTableBoxFmt*)pULPara->pRightBox->GetFrmFmt(), 0, pInsLine );
1627 SwTableLine* pRMLn = new SwTableLine(
1628 (SwTableLineFmt*)pInsLine->GetFrmFmt(), 2, pRMBox );
1629 pRMLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE );
1630 pRMBox->GetTabLines().insert( pRMBox->GetTabLines().begin(), pRMLn );
1632 lcl_CpyBoxes( 1, 3, pInsLine->GetTabBoxes(), pRMLn );
1634 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin(), pRMBox );
1636 else
1638 // Left and Merge have been merged, so also move Right into the Line
1639 pInsLine = pULPara->pLeftBox->GetUpper();
1640 sal_uInt16 nMvPos = pULPara->pRightBox->GetUpper()->GetTabBoxes().GetPos(
1641 pULPara->pRightBox );
1642 lcl_CpyBoxes( nMvPos, nMvPos+1,
1643 pULPara->pRightBox->GetUpper()->GetTabBoxes(),
1644 pInsLine );
1645 pRMBox = pInsLine->GetUpper();
1647 // If there are already Lines, then these need to go into a new Line and Box
1648 nMvPos = pRMBox->GetTabLines().GetPos( pInsLine );
1649 if( pULPara->bUL ? nMvPos
1650 : nMvPos+1 < (sal_uInt16)pRMBox->GetTabLines().size() )
1652 // Merge all Lines into a new Line and Box
1653 SwTableLine* pNewLn = new SwTableLine(
1654 (SwTableLineFmt*)pInsLine->GetFrmFmt(), 1, pRMBox );
1655 pNewLn->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE );
1656 pRMBox->GetTabLines().insert(
1657 pRMBox->GetTabLines().begin() + (pULPara->bUL ? nMvPos : nMvPos+1),
1658 pNewLn );
1659 pRMBox = new SwTableBox( (SwTableBoxFmt*)pRMBox->GetFrmFmt(), 0, pNewLn );
1660 pNewLn->GetTabBoxes().insert( pNewLn->GetTabBoxes().begin(), pRMBox );
1662 sal_uInt16 nPos1, nPos2;
1663 if( pULPara->bUL )
1664 nPos1 = 0,
1665 nPos2 = nMvPos;
1666 else
1667 nPos1 = nMvPos+2,
1668 nPos2 = pNewLn->GetUpper()->GetTabLines().size();
1670 lcl_CpyLines( nPos1, nPos2,
1671 pNewLn->GetUpper()->GetTabLines(), pRMBox );
1672 lcl_CalcWidth( pRMBox ); // calculate the Box's width
1674 pRMBox = new SwTableBox( (SwTableBoxFmt*)pRMBox->GetFrmFmt(), 0, pNewLn );
1675 pNewLn->GetTabBoxes().push_back( pRMBox );
1678 if( pULPara->bUL ) // Upper ?
1680 // If there are Lines before it, move them
1681 if( 0 != ( nPos = pLines->GetPos( pFndLn )) )
1682 lcl_CpyLines( 0, nPos, *pLines, pRMBox, 0 );
1684 else
1685 // If there are Lines after it, move them
1686 if( (nPos = pLines->GetPos( pFndLn )) + 1 < (sal_uInt16)pLines->size() )
1687 lcl_CpyLines( nPos+1, pLines->size(), *pLines,
1688 pRMBox );
1689 lcl_CalcWidth( pRMBox ); // calculate the Box's width
1691 else {
1692 OSL_FAIL( "So ... what do we do now?" );
1695 // Left/Right
1696 else
1698 // Find only the Line from which we need to move
1699 nStt = pULPara->bUL ? 0 : rFndLine.GetBoxes().size()-1;
1700 nEnd = nStt+1;
1702 pLines = &pULPara->pInsBox->GetTabLines();
1704 SwTableLine* pNewLine = new SwTableLine(
1705 (SwTableLineFmt*)rFndLine.GetLine()->GetFrmFmt(), 0, pULPara->pInsBox );
1706 _InsULPara aPara( *pULPara ); // kopieren
1707 aPara.pInsLine = pNewLine;
1708 _FndBoxes & rLineBoxes = rFndLine.GetBoxes();
1709 for (_FndBoxes::iterator it = rLineBoxes.begin() + nStt;
1710 it != rLineBoxes.begin() + nEnd; ++it)
1712 lcl_Merge_MoveBox(*it, &aPara);
1715 if( !pNewLine->GetTabBoxes().empty() )
1717 if( USHRT_MAX == nInsPos )
1718 nInsPos = pLines->size();
1719 pLines->insert( pLines->begin() + nInsPos, pNewLine );
1721 else
1722 delete pNewLine;
1725 static void lcl_BoxSetHeadCondColl( const SwTableBox* pBox );
1727 bool SwTable::OldMerge( SwDoc* pDoc, const SwSelBoxes& rBoxes,
1728 SwTableBox* pMergeBox, SwUndoTblMerge* pUndo )
1730 OSL_ENSURE( !rBoxes.empty() && pMergeBox, "no valid values" );
1731 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1732 if( !pTblNd )
1733 return false;
1735 // Find all Boxes/Lines
1736 _FndBox aFndBox( 0, 0 );
1738 _FndPara aPara( rBoxes, &aFndBox );
1739 ForEach_FndLineCopyCol( GetTabLines(), &aPara );
1741 if( aFndBox.GetLines().empty() )
1742 return false;
1744 // TL_CHART2: splitting/merging of a number of cells or rows will usually make
1745 // the table too complex to be handled with chart.
1746 // Thus we tell the charts to use their own data provider and forget about this table
1747 pDoc->CreateChartInternalDataProviders( this );
1749 SetHTMLTableLayout( 0 ); // Delete HTML Layout
1751 if( pUndo )
1752 pUndo->SetSelBoxes( rBoxes );
1754 // Find Lines for the Layout update
1755 aFndBox.SetTableLines( *this );
1756 aFndBox.DelFrms( *this );
1758 _FndBox* pFndBox = &aFndBox;
1759 while( 1 == pFndBox->GetLines().size() &&
1760 1 == pFndBox->GetLines().front().GetBoxes().size() )
1762 pFndBox = &pFndBox->GetLines().front().GetBoxes().front();
1765 SwTableLine* pInsLine = new SwTableLine(
1766 (SwTableLineFmt*)pFndBox->GetLines().front().GetLine()->GetFrmFmt(), 0,
1767 !pFndBox->GetUpper() ? 0 : pFndBox->GetBox() );
1768 pInsLine->ClaimFrmFmt()->ResetFmtAttr( RES_FRM_SIZE );
1770 // Add the new Line
1771 SwTableLines* pLines = pFndBox->GetUpper() ?
1772 &pFndBox->GetBox()->GetTabLines() : &GetTabLines();
1774 SwTableLine* pNewLine = pFndBox->GetLines().front().GetLine();
1775 sal_uInt16 nInsPos = pLines->GetPos( pNewLine );
1776 pLines->insert( pLines->begin() + nInsPos, pInsLine );
1778 SwTableBox* pLeftBox = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine );
1779 SwTableBox* pRightBox = new SwTableBox( (SwTableBoxFmt*)pMergeBox->GetFrmFmt(), 0, pInsLine );
1780 pMergeBox->SetUpper( pInsLine );
1781 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin(), pLeftBox );
1782 pLeftBox->ClaimFrmFmt();
1783 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + 1, pMergeBox);
1784 pInsLine->GetTabBoxes().insert( pInsLine->GetTabBoxes().begin() + 2, pRightBox );
1785 pRightBox->ClaimFrmFmt();
1787 // This contains all Lines that are above the selected Area,
1788 // thus they form a Upper/Lower Line
1789 _InsULPara aPara( pTblNd, true, true, pLeftBox, pMergeBox, pRightBox, pInsLine );
1791 // Move the overlapping upper/lower Lines of the selected Area
1792 _FndBoxes& rLineBoxes = pFndBox->GetLines().front().GetBoxes();
1793 for (_FndBoxes::iterator it = rLineBoxes.begin(); it != rLineBoxes.end(); ++it)
1795 lcl_Merge_MoveBox(*it, &aPara);
1797 aPara.SetLower( pInsLine );
1798 sal_uInt16 nEnd = pFndBox->GetLines().size()-1;
1799 rLineBoxes = pFndBox->GetLines()[nEnd].GetBoxes();
1800 for (_FndBoxes::iterator it = rLineBoxes.begin(); it != rLineBoxes.end(); ++it)
1802 lcl_Merge_MoveBox(*it, &aPara);
1805 // Move the Boxes extending into the selected Area from left/right
1806 aPara.SetLeft( pLeftBox );
1807 BOOST_FOREACH(_FndLine& rFndLine, pFndBox->GetLines() )
1808 lcl_Merge_MoveLine( rFndLine, &aPara );
1810 aPara.SetRight( pRightBox );
1811 BOOST_FOREACH(_FndLine& rFndLine, pFndBox->GetLines() )
1812 lcl_Merge_MoveLine( rFndLine, &aPara );
1814 if( pLeftBox->GetTabLines().empty() )
1815 _DeleteBox( *this, pLeftBox, 0, false, false );
1816 else
1818 lcl_CalcWidth( pLeftBox ); // calculate the Box's width
1819 if( pUndo && pLeftBox->GetSttNd() )
1820 pUndo->AddNewBox( pLeftBox->GetSttIdx() );
1822 if( pRightBox->GetTabLines().empty() )
1823 _DeleteBox( *this, pRightBox, 0, false, false );
1824 else
1826 lcl_CalcWidth( pRightBox ); // calculate the Box's width
1827 if( pUndo && pRightBox->GetSttNd() )
1828 pUndo->AddNewBox( pRightBox->GetSttIdx() );
1831 DeleteSel( pDoc, rBoxes, 0, 0, false, false );
1833 // Clean up this Line's structure once again, generally all of them
1834 GCLines();
1836 for( SwTableBoxes::iterator it = GetTabLines()[0]->GetTabBoxes().begin();
1837 it != GetTabLines()[0]->GetTabBoxes().end(); ++it)
1838 lcl_BoxSetHeadCondColl(*it);
1840 aFndBox.MakeFrms( *this );
1842 CHECKBOXWIDTH
1843 CHECKTABLELAYOUT
1845 return true;
1848 static void lcl_CheckRowSpan( SwTable &rTbl )
1850 sal_uInt16 nLineCount = rTbl.GetTabLines().size();
1851 sal_uInt16 nMaxSpan = nLineCount;
1852 long nMinSpan = 1;
1853 while( nMaxSpan )
1855 SwTableLine* pLine = rTbl.GetTabLines()[ nLineCount - nMaxSpan ];
1856 for( sal_uInt16 nBox = 0; nBox < pLine->GetTabBoxes().size(); ++nBox )
1858 SwTableBox* pBox = pLine->GetTabBoxes()[nBox];
1859 long nRowSpan = pBox->getRowSpan();
1860 if( nRowSpan > nMaxSpan )
1861 pBox->setRowSpan( nMaxSpan );
1862 else if( nRowSpan < nMinSpan )
1863 pBox->setRowSpan( nMinSpan > 0 ? nMaxSpan : nMinSpan );
1865 --nMaxSpan;
1866 nMinSpan = -nMaxSpan;
1870 static sal_uInt16 lcl_GetBoxOffset( const _FndBox& rBox )
1872 // Find the first Box
1873 const _FndBox* pFirstBox = &rBox;
1874 while( !pFirstBox->GetLines().empty() )
1875 pFirstBox = &pFirstBox->GetLines().front().GetBoxes().front();
1877 sal_uInt16 nRet = 0;
1878 // Calculate the position relative to above via the Lines
1879 const SwTableBox* pBox = pFirstBox->GetBox();
1880 do {
1881 const SwTableBoxes& rBoxes = pBox->GetUpper()->GetTabBoxes();
1882 const SwTableBox* pCmp;
1883 for( sal_uInt16 n = 0; pBox != ( pCmp = rBoxes[ n ] ); ++n )
1884 nRet = nRet + (sal_uInt16) pCmp->GetFrmFmt()->GetFrmSize().GetWidth();
1885 pBox = pBox->GetUpper()->GetUpper();
1886 } while( pBox );
1887 return nRet;
1890 static sal_uInt16 lcl_GetLineWidth( const _FndLine& rLine )
1892 sal_uInt16 nRet = 0;
1893 for( sal_uInt16 n = rLine.GetBoxes().size(); n; )
1895 nRet = nRet + static_cast<sal_uInt16>(rLine.GetBoxes()[--n].GetBox()
1896 ->GetFrmFmt()->GetFrmSize().GetWidth());
1898 return nRet;
1901 static void lcl_CalcNewWidths( const _FndLines& rFndLines, _CpyPara& rPara )
1903 rPara.pWidths.reset();
1904 sal_uInt16 nLineCount = rFndLines.size();
1905 if( nLineCount )
1907 rPara.pWidths = boost::shared_ptr< std::vector< std::vector< sal_uLong > > >
1908 ( new std::vector< std::vector< sal_uLong > >( nLineCount ));
1909 // First we collect information about the left/right borders of all
1910 // selected cells
1911 for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1913 std::vector< sal_uLong > &rWidth = (*rPara.pWidths.get())[ nLine ];
1914 const _FndLine *pFndLine = &rFndLines[ nLine ];
1915 if( pFndLine && pFndLine->GetBoxes().size() )
1917 const SwTableLine *pLine = pFndLine->GetLine();
1918 if( pLine && !pLine->GetTabBoxes().empty() )
1920 sal_uInt16 nBoxCount = pLine->GetTabBoxes().size();
1921 sal_uLong nPos = 0;
1922 // The first selected box...
1923 const SwTableBox *const pSel =
1924 pFndLine->GetBoxes().front().GetBox();
1925 sal_uInt16 nBox = 0;
1926 // Sum up the width of all boxes before the first selected box
1927 while( nBox < nBoxCount )
1929 SwTableBox* pBox = pLine->GetTabBoxes()[nBox++];
1930 if( pBox != pSel )
1931 nPos += pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1932 else
1933 break;
1935 // nPos is now the left border of the first selected box
1936 if( rPara.nMinLeft > nPos )
1937 rPara.nMinLeft = nPos;
1938 nBoxCount = pFndLine->GetBoxes().size();
1939 rWidth = std::vector< sal_uLong >( nBoxCount+2 );
1940 rWidth[ 0 ] = nPos;
1941 // Add now the widths of all selected boxes and store
1942 // the positions in the vector
1943 for( nBox = 0; nBox < nBoxCount; )
1945 nPos += pFndLine->GetBoxes()[nBox]
1946 .GetBox()->GetFrmFmt()->GetFrmSize().GetWidth();
1947 rWidth[ ++nBox ] = nPos;
1949 // nPos: The right border of the last selected box
1950 if( rPara.nMaxRight < nPos )
1951 rPara.nMaxRight = nPos;
1952 if( nPos <= rWidth[ 0 ] )
1953 rWidth.clear();
1958 // Second step: calculate the new widths for the copied cells
1959 sal_uLong nSelSize = rPara.nMaxRight - rPara.nMinLeft;
1960 if( nSelSize )
1962 for( sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1964 std::vector< sal_uLong > &rWidth = (*rPara.pWidths.get())[ nLine ];
1965 sal_uInt16 nCount = (sal_uInt16)rWidth.size();
1966 if( nCount > 2 )
1968 rWidth[ nCount - 1 ] = rPara.nMaxRight;
1969 sal_uLong nLastPos = 0;
1970 for( sal_uInt16 nBox = 0; nBox < nCount; ++nBox )
1972 sal_uInt64 nNextPos = rWidth[ nBox ];
1973 nNextPos -= rPara.nMinLeft;
1974 nNextPos *= rPara.nNewSize;
1975 nNextPos /= nSelSize;
1976 rWidth[ nBox ] = (sal_uLong)(nNextPos - nLastPos);
1977 nLastPos = (sal_uLong)nNextPos;
1984 static void
1985 lcl_CopyLineToDoc(_FndLine const& rpFndLn, _CpyPara *const pCpyPara);
1987 static void lcl_CopyBoxToDoc(_FndBox const& rFndBox, _CpyPara *const pCpyPara)
1989 // Calculation of new size
1990 sal_uLong nRealSize;
1991 sal_uLong nDummy1 = 0;
1992 sal_uLong nDummy2 = 0;
1993 if( pCpyPara->pTblNd->GetTable().IsNewModel() )
1995 if( pCpyPara->nBoxIdx == 1 )
1996 nDummy1 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][0];
1997 nRealSize = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx++];
1998 if( pCpyPara->nBoxIdx == (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx].size()-1 )
1999 nDummy2 = (*pCpyPara->pWidths.get())[pCpyPara->nLnIdx][pCpyPara->nBoxIdx];
2001 else
2003 nRealSize = pCpyPara->nNewSize;
2004 nRealSize *= rFndBox.GetBox()->GetFrmFmt()->GetFrmSize().GetWidth();
2005 nRealSize /= pCpyPara->nOldSize;
2008 sal_uLong nSize;
2009 bool bDummy = nDummy1 > 0;
2010 if( bDummy )
2011 nSize = nDummy1;
2012 else
2014 nSize = nRealSize;
2015 nRealSize = 0;
2019 // Find the Frame Format in the list of all Frame Formats
2020 _CpyTabFrm aFindFrm(static_cast<SwTableBoxFmt*>(rFndBox.GetBox()->GetFrmFmt()));
2022 SwFmtFrmSize aFrmSz;
2023 _CpyTabFrms::const_iterator itFind = pCpyPara->rTabFrmArr.lower_bound( aFindFrm );
2024 sal_uInt16 nFndPos = itFind - pCpyPara->rTabFrmArr.begin();
2025 if( itFind == pCpyPara->rTabFrmArr.end() || !(*itFind == aFindFrm) ||
2026 ( aFrmSz = ( aFindFrm = pCpyPara->rTabFrmArr[ nFndPos ]).pNewFrmFmt->
2027 GetFrmSize()).GetWidth() != (SwTwips)nSize )
2029 // It doesn't exist yet, so copy it
2030 aFindFrm.pNewFrmFmt = pCpyPara->pDoc->MakeTableBoxFmt();
2031 aFindFrm.pNewFrmFmt->CopyAttrs( *rFndBox.GetBox()->GetFrmFmt() );
2032 if( !pCpyPara->bCpyCntnt )
2033 aFindFrm.pNewFrmFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
2034 aFrmSz.SetWidth( nSize );
2035 aFindFrm.pNewFrmFmt->SetFmtAttr( aFrmSz );
2036 pCpyPara->rTabFrmArr.insert( aFindFrm );
2039 SwTableBox* pBox;
2040 if (!rFndBox.GetLines().empty())
2042 pBox = new SwTableBox( aFindFrm.pNewFrmFmt,
2043 rFndBox.GetLines().size(), pCpyPara->pInsLine );
2044 pCpyPara->pInsLine->GetTabBoxes().insert( pCpyPara->pInsLine->GetTabBoxes().begin() + pCpyPara->nInsPos++, pBox );
2045 _CpyPara aPara( *pCpyPara, pBox );
2046 aPara.nNewSize = nSize; // get the size
2047 BOOST_FOREACH(_FndLine const& rFndLine, rFndBox.GetLines())
2048 lcl_CopyLineToDoc( rFndLine, &aPara );
2050 else
2052 // Create an empty Box
2053 pCpyPara->pDoc->GetNodes().InsBoxen( pCpyPara->pTblNd, pCpyPara->pInsLine,
2054 aFindFrm.pNewFrmFmt,
2055 (SwTxtFmtColl*)pCpyPara->pDoc->GetDfltTxtFmtColl(),
2056 0, pCpyPara->nInsPos );
2057 pBox = pCpyPara->pInsLine->GetTabBoxes()[ pCpyPara->nInsPos ];
2058 if( bDummy )
2059 pBox->setDummyFlag( true );
2060 else if( pCpyPara->bCpyCntnt )
2062 // Copy the content into this empty Box
2063 pBox->setRowSpan(rFndBox.GetBox()->getRowSpan());
2065 // We can also copy formulas and values, if we copy the content
2067 SfxItemSet aBoxAttrSet( pCpyPara->pDoc->GetAttrPool(),
2068 RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2069 aBoxAttrSet.Put(rFndBox.GetBox()->GetFrmFmt()->GetAttrSet());
2070 if( aBoxAttrSet.Count() )
2072 const SfxPoolItem* pItem;
2073 SvNumberFormatter* pN = pCpyPara->pDoc->GetNumberFormatter( sal_False );
2074 if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == aBoxAttrSet.
2075 GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) )
2077 sal_uLong nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue();
2078 sal_uLong nNewIdx = pN->GetMergeFmtIndex( nOldIdx );
2079 if( nNewIdx != nOldIdx )
2080 aBoxAttrSet.Put( SwTblBoxNumFormat( nNewIdx ));
2082 pBox->ClaimFrmFmt()->SetFmtAttr( aBoxAttrSet );
2085 SwDoc* pFromDoc = rFndBox.GetBox()->GetFrmFmt()->GetDoc();
2086 SwNodeRange aCpyRg( *rFndBox.GetBox()->GetSttNd(), 1,
2087 *rFndBox.GetBox()->GetSttNd()->EndOfSectionNode() );
2088 SwNodeIndex aInsIdx( *pBox->GetSttNd(), 1 );
2090 pFromDoc->CopyWithFlyInFly( aCpyRg, 0, aInsIdx, sal_False );
2091 // Delete the initial TextNode
2092 pCpyPara->pDoc->GetNodes().Delete( aInsIdx, 1 );
2094 ++pCpyPara->nInsPos;
2096 if( nRealSize )
2098 bDummy = false;
2099 nSize = nRealSize;
2100 nRealSize = 0;
2102 else
2104 bDummy = true;
2105 nSize = nDummy2;
2106 nDummy2 = 0;
2109 while( nSize );
2112 static void
2113 lcl_CopyLineToDoc(const _FndLine& rFndLine, _CpyPara *const pCpyPara)
2115 // Find the Frame Format in the list of all Frame Formats
2116 _CpyTabFrm aFindFrm( (SwTableBoxFmt*)rFndLine.GetLine()->GetFrmFmt() );
2117 _CpyTabFrms::const_iterator itFind = pCpyPara->rTabFrmArr.find( aFindFrm );
2118 if( itFind == pCpyPara->rTabFrmArr.end() )
2120 // It doesn't exist yet, so copy it
2121 aFindFrm.pNewFrmFmt = (SwTableBoxFmt*)pCpyPara->pDoc->MakeTableLineFmt();
2122 aFindFrm.pNewFrmFmt->CopyAttrs( *rFndLine.GetLine()->GetFrmFmt() );
2123 pCpyPara->rTabFrmArr.insert( aFindFrm );
2125 else
2126 aFindFrm = *itFind;
2128 SwTableLine* pNewLine = new SwTableLine( (SwTableLineFmt*)aFindFrm.pNewFrmFmt,
2129 rFndLine.GetBoxes().size(), pCpyPara->pInsBox );
2130 if( pCpyPara->pInsBox )
2132 SwTableLines& rLines = pCpyPara->pInsBox->GetTabLines();
2133 rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine );
2135 else
2137 SwTableLines& rLines = pCpyPara->pTblNd->GetTable().GetTabLines();
2138 rLines.insert( rLines.begin() + pCpyPara->nInsPos++, pNewLine);
2141 _CpyPara aPara( *pCpyPara, pNewLine );
2143 if( pCpyPara->pTblNd->GetTable().IsNewModel() )
2145 aPara.nOldSize = 0; // will not be used
2146 aPara.nBoxIdx = 1;
2148 else if( rFndLine.GetBoxes().size() ==
2149 rFndLine.GetLine()->GetTabBoxes().size() )
2151 // Get the Parent's size
2152 const SwFrmFmt* pFmt;
2154 if( rFndLine.GetLine()->GetUpper() )
2155 pFmt = rFndLine.GetLine()->GetUpper()->GetFrmFmt();
2156 else
2157 pFmt = pCpyPara->pTblNd->GetTable().GetFrmFmt();
2158 aPara.nOldSize = pFmt->GetFrmSize().GetWidth();
2160 else
2161 // Calculate it
2162 for( sal_uInt16 n = 0; n < rFndLine.GetBoxes().size(); ++n )
2164 aPara.nOldSize += rFndLine.GetBoxes()[n]
2165 .GetBox()->GetFrmFmt()->GetFrmSize().GetWidth();
2168 const _FndBoxes& rBoxes = rFndLine.GetBoxes();
2169 for (_FndBoxes::const_iterator it = rBoxes.begin(); it != rBoxes.end(); ++it)
2170 lcl_CopyBoxToDoc(*it, &aPara);
2171 if( pCpyPara->pTblNd->GetTable().IsNewModel() )
2172 ++pCpyPara->nLnIdx;
2175 bool SwTable::CopyHeadlineIntoTable( SwTableNode& rTblNd )
2177 // Find all Boxes/Lines
2178 SwSelBoxes aSelBoxes;
2179 SwTableBox* pBox = GetTabSortBoxes()[ 0 ];
2180 pBox = GetTblBox( pBox->GetSttNd()->StartOfSectionNode()->GetIndex() + 1 );
2181 SelLineFromBox( pBox, aSelBoxes, true );
2183 _FndBox aFndBox( 0, 0 );
2185 _FndPara aPara( aSelBoxes, &aFndBox );
2186 ForEach_FndLineCopyCol( GetTabLines(), &aPara );
2188 if( aFndBox.GetLines().empty() )
2189 return false;
2192 // Convert Table formulas to their relative representation
2193 SwTableFmlUpdate aMsgHnt( this );
2194 aMsgHnt.eFlags = TBL_RELBOXNAME;
2195 GetFrmFmt()->GetDoc()->UpdateTblFlds( &aMsgHnt );
2198 _CpyTabFrms aCpyFmt;
2199 _CpyPara aPara( &rTblNd, 1, aCpyFmt, true );
2200 aPara.nNewSize = aPara.nOldSize = rTblNd.GetTable().GetFrmFmt()->GetFrmSize().GetWidth();
2201 // Copy
2202 if( IsNewModel() )
2203 lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
2204 BOOST_FOREACH( _FndLine& rFndLine, aFndBox.GetLines() )
2205 lcl_CopyLineToDoc( rFndLine, &aPara );
2206 if( rTblNd.GetTable().IsNewModel() )
2207 { // The copied line must not contain any row span attributes > 1
2208 SwTableLine* pLine = rTblNd.GetTable().GetTabLines()[0];
2209 sal_uInt16 nColCount = pLine->GetTabBoxes().size();
2210 OSL_ENSURE( nColCount, "Empty Table Line" );
2211 for( sal_uInt16 nCurrCol = 0; nCurrCol < nColCount; ++nCurrCol )
2213 SwTableBox* pTableBox = pLine->GetTabBoxes()[nCurrCol];
2214 OSL_ENSURE( pTableBox, "Missing Table Box" );
2215 pTableBox->setRowSpan( 1 );
2219 return true;
2222 bool SwTable::MakeCopy( SwDoc* pInsDoc, const SwPosition& rPos,
2223 const SwSelBoxes& rSelBoxes, bool bCpyNds,
2224 bool bCpyName ) const
2226 // Find all Boxes/Lines
2227 _FndBox aFndBox( 0, 0 );
2229 _FndPara aPara( rSelBoxes, &aFndBox );
2230 ForEach_FndLineCopyCol( (SwTableLines&)GetTabLines(), &aPara );
2232 if( aFndBox.GetLines().empty() )
2233 return false;
2235 // First copy the PoolTemplates for the Table, so that the Tables are
2236 // actually copied and have valid values.
2237 SwDoc* pSrcDoc = GetFrmFmt()->GetDoc();
2238 if( pSrcDoc != pInsDoc )
2240 pInsDoc->CopyTxtColl( *pSrcDoc->GetTxtCollFromPool( RES_POOLCOLL_TABLE ) );
2241 pInsDoc->CopyTxtColl( *pSrcDoc->GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN ) );
2244 SwTable* pNewTbl = (SwTable*)pInsDoc->InsertTable(
2245 SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 1 ),
2246 rPos, 1, 1, GetFrmFmt()->GetHoriOrient().GetHoriOrient(),
2247 0, 0, sal_False, IsNewModel() );
2248 if( !pNewTbl )
2249 return false;
2251 SwNodeIndex aIdx( rPos.nNode, -1 );
2252 SwTableNode* pTblNd = aIdx.GetNode().FindTableNode();
2253 ++aIdx;
2254 OSL_ENSURE( pTblNd, "Where is the TableNode now?" );
2256 pTblNd->GetTable().SetRowsToRepeat( GetRowsToRepeat() );
2258 if( IS_TYPE( SwDDETable, this ))
2260 // A DDE-Table is being copied
2261 // Does the new Document actually have it's FieldType?
2262 SwFieldType* pFldType = pInsDoc->InsertFldType(
2263 *((SwDDETable*)this)->GetDDEFldType() );
2264 OSL_ENSURE( pFldType, "unknown FieldType" );
2266 // Change the Table Pointer at the Node
2267 pNewTbl = new SwDDETable( *pNewTbl,
2268 (SwDDEFieldType*)pFldType );
2269 pTblNd->SetNewTable( pNewTbl, sal_False );
2272 pNewTbl->GetFrmFmt()->CopyAttrs( *GetFrmFmt() );
2273 pNewTbl->SetTblChgMode( GetTblChgMode() );
2275 // Destroy the already created Frames
2276 pTblNd->DelFrms();
2279 // Conver the Table formulas to their relative representation
2280 SwTableFmlUpdate aMsgHnt( this );
2281 aMsgHnt.eFlags = TBL_RELBOXNAME;
2282 pSrcDoc->UpdateTblFlds( &aMsgHnt );
2285 SwTblNumFmtMerge aTNFM( *pSrcDoc, *pInsDoc );
2287 // Also copy Names or enforce a new unique one
2288 if( bCpyName )
2289 pNewTbl->GetFrmFmt()->SetName( GetFrmFmt()->GetName() );
2291 _CpyTabFrms aCpyFmt;
2292 _CpyPara aPara( pTblNd, 1, aCpyFmt, bCpyNds );
2293 aPara.nNewSize = aPara.nOldSize = GetFrmFmt()->GetFrmSize().GetWidth();
2295 if( IsNewModel() )
2296 lcl_CalcNewWidths( aFndBox.GetLines(), aPara );
2297 // Copy
2298 BOOST_FOREACH( _FndLine& rFndLine, aFndBox.GetLines() )
2299 lcl_CopyLineToDoc( rFndLine, &aPara );
2301 // Set the "right" margin above/below
2303 _FndLine* pFndLn = &aFndBox.GetLines().front();
2304 SwTableLine* pLn = pFndLn->GetLine();
2305 const SwTableLine* pTmp = pLn;
2306 sal_uInt16 nLnPos = GetTabLines().GetPos( pTmp );
2307 if( USHRT_MAX != nLnPos && nLnPos )
2309 // There is a Line before it
2310 SwCollectTblLineBoxes aLnPara( sal_False, HEADLINE_BORDERCOPY );
2312 pLn = GetTabLines()[ nLnPos - 1 ];
2313 for( SwTableBoxes::iterator it = pLn->GetTabBoxes().begin();
2314 it != pLn->GetTabBoxes().end(); ++it)
2315 sw_Box_CollectBox( *it, &aLnPara );
2317 if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
2318 lcl_GetLineWidth( *pFndLn )) )
2320 aLnPara.SetValues( sal_True );
2321 pLn = pNewTbl->GetTabLines()[ 0 ];
2322 for( SwTableBoxes::iterator it = pLn->GetTabBoxes().begin();
2323 it != pLn->GetTabBoxes().end(); ++it)
2324 sw_BoxSetSplitBoxFmts(*it, &aLnPara );
2328 pFndLn = &aFndBox.GetLines().back();
2329 pLn = pFndLn->GetLine();
2330 pTmp = pLn;
2331 nLnPos = GetTabLines().GetPos( pTmp );
2332 if( nLnPos < GetTabLines().size() - 1 )
2334 // There is a Line following it
2335 SwCollectTblLineBoxes aLnPara( sal_True, HEADLINE_BORDERCOPY );
2337 pLn = GetTabLines()[ nLnPos + 1 ];
2338 for( SwTableBoxes::iterator it = pLn->GetTabBoxes().begin();
2339 it != pLn->GetTabBoxes().end(); ++it)
2340 sw_Box_CollectBox( *it, &aLnPara );
2342 if( aLnPara.Resize( lcl_GetBoxOffset( aFndBox ),
2343 lcl_GetLineWidth( *pFndLn )) )
2345 aLnPara.SetValues( sal_False );
2346 pLn = pNewTbl->GetTabLines().back();
2347 for( SwTableBoxes::iterator it = pLn->GetTabBoxes().begin();
2348 it != pLn->GetTabBoxes().end(); ++it)
2349 sw_BoxSetSplitBoxFmts(*it, &aLnPara );
2354 // We need to delete the initial Box
2355 _DeleteBox( *pNewTbl, pNewTbl->GetTabLines().back()->GetTabBoxes()[0],
2356 0, false, false );
2358 if( pNewTbl->IsNewModel() )
2359 lcl_CheckRowSpan( *pNewTbl );
2360 // Clean up
2361 pNewTbl->GCLines();
2363 pTblNd->MakeFrms( &aIdx ); // re-generate the Frames
2365 CHECKTABLELAYOUT
2367 return true;
2370 // Find the next Box with content from this Line
2371 SwTableBox* SwTableLine::FindNextBox( const SwTable& rTbl,
2372 const SwTableBox* pSrchBox, bool bOvrTblLns ) const
2374 const SwTableLine* pLine = this; // for M800
2375 SwTableBox* pBox;
2376 sal_uInt16 nFndPos;
2377 if( !GetTabBoxes().empty() && pSrchBox &&
2378 USHRT_MAX != ( nFndPos = GetTabBoxes().GetPos( pSrchBox )) &&
2379 nFndPos + 1 != (sal_uInt16)GetTabBoxes().size() )
2381 pBox = GetTabBoxes()[ nFndPos + 1 ];
2382 while( !pBox->GetTabLines().empty() )
2383 pBox = pBox->GetTabLines().front()->GetTabBoxes()[0];
2384 return pBox;
2387 if( GetUpper() )
2389 nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
2390 OSL_ENSURE( USHRT_MAX != nFndPos, "Line is not in the Table" );
2391 // Is there another Line?
2392 if( nFndPos+1 >= (sal_uInt16)GetUpper()->GetTabLines().size() )
2393 return GetUpper()->GetUpper()->FindNextBox( rTbl, GetUpper(), bOvrTblLns );
2394 pLine = GetUpper()->GetTabLines()[nFndPos+1];
2396 else if( bOvrTblLns ) // Over a Table's the "BaseLines"??
2398 // Search for the next Line in the Table
2399 nFndPos = rTbl.GetTabLines().GetPos( pLine );
2400 if( nFndPos + 1 >= (sal_uInt16)rTbl.GetTabLines().size() )
2401 return 0; // there are no more Boxes
2403 pLine = rTbl.GetTabLines()[ nFndPos+1 ];
2405 else
2406 return 0;
2408 if( !pLine->GetTabBoxes().empty() )
2410 pBox = pLine->GetTabBoxes().front();
2411 while( !pBox->GetTabLines().empty() )
2412 pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
2413 return pBox;
2415 return pLine->FindNextBox( rTbl, 0, bOvrTblLns );
2418 // Find the previous Box from this Line
2419 SwTableBox* SwTableLine::FindPreviousBox( const SwTable& rTbl,
2420 const SwTableBox* pSrchBox, bool bOvrTblLns ) const
2422 const SwTableLine* pLine = this; // for M800
2423 SwTableBox* pBox;
2424 sal_uInt16 nFndPos;
2425 if( !GetTabBoxes().empty() && pSrchBox &&
2426 USHRT_MAX != ( nFndPos = GetTabBoxes().GetPos( pSrchBox )) &&
2427 nFndPos )
2429 pBox = GetTabBoxes()[ nFndPos - 1 ];
2430 while( !pBox->GetTabLines().empty() )
2432 pLine = pBox->GetTabLines().back();
2433 pBox = pLine->GetTabBoxes().back();
2435 return pBox;
2438 if( GetUpper() )
2440 nFndPos = GetUpper()->GetTabLines().GetPos( pLine );
2441 OSL_ENSURE( USHRT_MAX != nFndPos, "Line is not in the Table" );
2442 // Is there another Line?
2443 if( !nFndPos )
2444 return GetUpper()->GetUpper()->FindPreviousBox( rTbl, GetUpper(), bOvrTblLns );
2445 pLine = GetUpper()->GetTabLines()[nFndPos-1];
2447 else if( bOvrTblLns ) // Over a Table's the "BaseLines"??
2449 // Search for the next Line in the Table
2450 nFndPos = rTbl.GetTabLines().GetPos( pLine );
2451 if( !nFndPos )
2452 return 0; // there are no more Boxes
2454 pLine = rTbl.GetTabLines()[ nFndPos-1 ];
2456 else
2457 return 0;
2459 if( !pLine->GetTabBoxes().empty() )
2461 pBox = pLine->GetTabBoxes().back();
2462 while( !pBox->GetTabLines().empty() )
2464 pLine = pBox->GetTabLines().back();
2465 pBox = pLine->GetTabBoxes().back();
2467 return pBox;
2469 return pLine->FindPreviousBox( rTbl, 0, bOvrTblLns );
2472 // Find the next Box with content from this Line
2473 SwTableBox* SwTableBox::FindNextBox( const SwTable& rTbl,
2474 const SwTableBox* pSrchBox, bool bOvrTblLns ) const
2476 if( !pSrchBox && GetTabLines().empty() )
2477 return (SwTableBox*)this;
2478 return GetUpper()->FindNextBox( rTbl, pSrchBox ? pSrchBox : this,
2479 bOvrTblLns );
2483 // Find the next Box with content from this Line
2484 SwTableBox* SwTableBox::FindPreviousBox( const SwTable& rTbl,
2485 const SwTableBox* pSrchBox, bool bOvrTblLns ) const
2487 if( !pSrchBox && GetTabLines().empty() )
2488 return (SwTableBox*)this;
2489 return GetUpper()->FindPreviousBox( rTbl, pSrchBox ? pSrchBox : this,
2490 bOvrTblLns );
2493 static void lcl_BoxSetHeadCondColl( const SwTableBox* pBox )
2495 // We need to adapt the paragraphs with conditional templates in the HeadLine
2496 const SwStartNode* pSttNd = pBox->GetSttNd();
2497 if( pSttNd )
2498 pSttNd->CheckSectionCondColl();
2499 else
2500 BOOST_FOREACH( const SwTableLine* pLine, pBox->GetTabLines() )
2501 sw_LineSetHeadCondColl( pLine );
2504 void sw_LineSetHeadCondColl( const SwTableLine* pLine )
2506 BOOST_FOREACH( const SwTableBox* pBox, pLine->GetTabBoxes() )
2507 lcl_BoxSetHeadCondColl(pBox);
2510 static SwTwips lcl_GetDistance( SwTableBox* pBox, bool bLeft )
2512 bool bFirst = true;
2513 SwTwips nRet = 0;
2514 SwTableLine* pLine;
2515 while( pBox && 0 != ( pLine = pBox->GetUpper() ) )
2517 sal_uInt16 nStt = 0, nPos = pLine->GetTabBoxes().GetPos( pBox );
2519 if( bFirst && !bLeft )
2520 ++nPos;
2521 bFirst = false;
2523 while( nStt < nPos )
2524 nRet += pLine->GetTabBoxes()[ nStt++ ]->GetFrmFmt()
2525 ->GetFrmSize().GetWidth();
2526 pBox = pLine->GetUpper();
2528 return nRet;
2531 static bool lcl_SetSelBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2532 SwTwips nDist, bool bCheck )
2534 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2535 for( sal_uInt16 n = 0; n < rBoxes.size(); ++n )
2537 SwTableBox* pBox = rBoxes[ n ];
2538 SwFrmFmt* pFmt = pBox->GetFrmFmt();
2539 const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
2540 SwTwips nWidth = rSz.GetWidth();
2541 bool bGreaterBox = false;
2543 if( bCheck )
2545 for( sal_uInt16 i = 0; i < pBox->GetTabLines().size(); ++i )
2546 if( !::lcl_SetSelBoxWidth( pBox->GetTabLines()[ i ], rParam,
2547 nDist, true ))
2548 return false;
2550 // Collect all "ContentBoxes"
2551 if( ( 0 != ( bGreaterBox = TBLFIX_CHGABS != rParam.nMode && ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) ||
2552 ( !rParam.bBigger && ( Abs( nDist + (( rParam.nMode && rParam.bLeft ) ? 0 : nWidth ) - rParam.nSide ) < COLFUZZY ) ) )
2554 rParam.bAnyBoxFnd = true;
2555 SwTwips nLowerDiff;
2556 if( bGreaterBox && TBLFIX_CHGPROP == rParam.nMode )
2558 // The "other Boxes" have been adapted, so change by this value
2559 nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
2560 nLowerDiff *= rParam.nDiff;
2561 nLowerDiff /= rParam.nMaxSize;
2562 nLowerDiff = rParam.nDiff - nLowerDiff;
2564 else
2565 nLowerDiff = rParam.nDiff;
2567 if( nWidth < nLowerDiff || nWidth - nLowerDiff < MINLAY )
2568 return false;
2571 else
2573 SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2574 for( sal_uInt16 i = 0; i < pBox->GetTabLines().size(); ++i )
2576 rParam.nLowerDiff = 0;
2577 lcl_SetSelBoxWidth( pBox->GetTabLines()[ i ], rParam, nDist, false );
2579 if( nLowerDiff < rParam.nLowerDiff )
2580 nLowerDiff = rParam.nLowerDiff;
2582 rParam.nLowerDiff = nOldLower;
2585 if( nLowerDiff ||
2586 ( 0 != ( bGreaterBox = !nOldLower && TBLFIX_CHGABS != rParam.nMode &&
2587 ( nDist + ( rParam.bLeft ? 0 : nWidth ) ) >= rParam.nSide)) ||
2588 ( Abs( nDist + ( (rParam.nMode && rParam.bLeft) ? 0 : nWidth )
2589 - rParam.nSide ) < COLFUZZY ))
2591 // This column contains the Cursor - so decrease/increase
2592 SwFmtFrmSize aNew( rSz );
2594 if( !nLowerDiff )
2596 if( bGreaterBox && TBLFIX_CHGPROP == rParam.nMode )
2598 // The "other Boxes" have been adapted, so change by this value
2599 nLowerDiff = (nDist + ( rParam.bLeft ? 0 : nWidth ) ) - rParam.nSide;
2600 nLowerDiff *= rParam.nDiff;
2601 nLowerDiff /= rParam.nMaxSize;
2602 nLowerDiff = rParam.nDiff - nLowerDiff;
2604 else
2605 nLowerDiff = rParam.nDiff;
2608 rParam.nLowerDiff += nLowerDiff;
2610 if( rParam.bBigger )
2611 aNew.SetWidth( nWidth + nLowerDiff );
2612 else
2613 aNew.SetWidth( nWidth - nLowerDiff );
2614 rParam.aShareFmts.SetSize( *pBox, aNew );
2615 break;
2619 if( rParam.bLeft && rParam.nMode && nDist >= rParam.nSide )
2620 break;
2622 nDist += nWidth;
2624 // If it gets bigger, then that's it
2625 if( ( TBLFIX_CHGABS == rParam.nMode || !rParam.bLeft ) &&
2626 nDist >= rParam.nSide )
2627 break;
2629 return true;
2632 static bool lcl_SetOtherBoxWidth( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2633 SwTwips nDist, bool bCheck )
2635 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2636 for( sal_uInt16 n = 0; n < rBoxes.size(); ++n )
2638 SwTableBox* pBox = rBoxes[ n ];
2639 SwFrmFmt* pFmt = pBox->GetFrmFmt();
2640 const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
2641 SwTwips nWidth = rSz.GetWidth();
2643 if( bCheck )
2645 for( sal_uInt16 i = 0; i < pBox->GetTabLines().size(); ++i )
2646 if( !::lcl_SetOtherBoxWidth( pBox->GetTabLines()[ i ],
2647 rParam, nDist, true ))
2648 return false;
2650 if( rParam.bBigger && ( TBLFIX_CHGABS == rParam.nMode
2651 ? Abs( nDist - rParam.nSide ) < COLFUZZY
2652 : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
2653 : nDist >= rParam.nSide - COLFUZZY )) )
2655 rParam.bAnyBoxFnd = true;
2656 SwTwips nDiff;
2657 if( TBLFIX_CHGPROP == rParam.nMode ) // Table fixed, proportional
2659 // calculate relative
2660 nDiff = nWidth;
2661 nDiff *= rParam.nDiff;
2662 nDiff /= rParam.nMaxSize;
2664 else
2665 nDiff = rParam.nDiff;
2667 if( nWidth < nDiff || nWidth - nDiff < MINLAY )
2668 return false;
2671 else
2673 SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2674 for( sal_uInt16 i = 0; i < pBox->GetTabLines().size(); ++i )
2676 rParam.nLowerDiff = 0;
2677 lcl_SetOtherBoxWidth( pBox->GetTabLines()[ i ], rParam,
2678 nDist, false );
2680 if( nLowerDiff < rParam.nLowerDiff )
2681 nLowerDiff = rParam.nLowerDiff;
2683 rParam.nLowerDiff = nOldLower;
2685 if( nLowerDiff ||
2686 ( TBLFIX_CHGABS == rParam.nMode
2687 ? Abs( nDist - rParam.nSide ) < COLFUZZY
2688 : ( rParam.bLeft ? nDist < rParam.nSide - COLFUZZY
2689 : nDist >= rParam.nSide - COLFUZZY)
2692 SwFmtFrmSize aNew( rSz );
2694 if( !nLowerDiff )
2696 if( TBLFIX_CHGPROP == rParam.nMode ) // Table fixed, proportional
2698 // calculate relative
2699 nLowerDiff = nWidth;
2700 nLowerDiff *= rParam.nDiff;
2701 nLowerDiff /= rParam.nMaxSize;
2703 else
2704 nLowerDiff = rParam.nDiff;
2707 rParam.nLowerDiff += nLowerDiff;
2709 if( rParam.bBigger )
2710 aNew.SetWidth( nWidth - nLowerDiff );
2711 else
2712 aNew.SetWidth( nWidth + nLowerDiff );
2714 rParam.aShareFmts.SetSize( *pBox, aNew );
2718 nDist += nWidth;
2719 if( ( TBLFIX_CHGABS == rParam.nMode || rParam.bLeft ) &&
2720 nDist > rParam.nSide )
2721 break;
2723 return true;
2726 static bool lcl_InsSelBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2727 SwTwips nDist, bool bCheck )
2729 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2730 sal_uInt16 n, nCmp;
2731 for( n = 0; n < rBoxes.size(); ++n )
2733 SwTableBox* pBox = rBoxes[ n ];
2734 SwTableBoxFmt* pFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
2735 const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
2736 SwTwips nWidth = rSz.GetWidth();
2738 if( bCheck )
2740 for( sal_uInt16 i = 0; i < pBox->GetTabLines().size(); ++i )
2741 if( !::lcl_InsSelBox( pBox->GetTabLines()[ i ], rParam,
2742 nDist, true ))
2743 return false;
2745 // Collect all "ContentBoxes"
2746 if( Abs( nDist + ( rParam.bLeft ? 0 : nWidth )
2747 - rParam.nSide ) < COLFUZZY )
2748 nCmp = 1;
2749 else if( nDist + ( rParam.bLeft ? 0 : nWidth/2 ) > rParam.nSide )
2750 nCmp = 2;
2751 else
2752 nCmp = 0;
2754 if( nCmp )
2756 rParam.bAnyBoxFnd = true;
2757 if( pFmt->GetProtect().IsCntntProtected() )
2758 return false;
2760 if( rParam.bSplittBox &&
2761 nWidth - rParam.nDiff <= COLFUZZY +
2762 ( 567 / 2 /*leave room for at least 0.5 cm*/) )
2763 return false;
2765 if( pBox->GetSttNd() )
2767 rParam.m_Boxes.insert(pBox);
2770 break;
2773 else
2775 SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2776 for( sal_uInt16 i = 0; i < pBox->GetTabLines().size(); ++i )
2778 rParam.nLowerDiff = 0;
2779 lcl_InsSelBox( pBox->GetTabLines()[ i ], rParam, nDist, false );
2781 if( nLowerDiff < rParam.nLowerDiff )
2782 nLowerDiff = rParam.nLowerDiff;
2784 rParam.nLowerDiff = nOldLower;
2786 if( nLowerDiff )
2787 nCmp = 1;
2788 else if( Abs( nDist + ( rParam.bLeft ? 0 : nWidth )
2789 - rParam.nSide ) < COLFUZZY )
2790 nCmp = 2;
2791 else if( nDist + nWidth / 2 > rParam.nSide )
2792 nCmp = 3;
2793 else
2794 nCmp = 0;
2796 if( nCmp )
2798 // This column contains the Cursor - so decrease/increase
2799 if( 1 == nCmp )
2801 if( !rParam.bSplittBox )
2803 // the current Box on
2804 SwFmtFrmSize aNew( rSz );
2805 aNew.SetWidth( nWidth + rParam.nDiff );
2806 rParam.aShareFmts.SetSize( *pBox, aNew );
2809 else
2811 OSL_ENSURE( pBox->GetSttNd(), "This must be an EndBox!");
2813 if( !rParam.bLeft && 3 != nCmp )
2814 ++n;
2816 ::_InsTblBox( pFmt->GetDoc(), rParam.pTblNd,
2817 pLine, pFmt, pBox, n );
2819 SwTableBox* pNewBox = rBoxes[ n ];
2820 SwFmtFrmSize aNew( rSz );
2821 aNew.SetWidth( rParam.nDiff );
2822 rParam.aShareFmts.SetSize( *pNewBox, aNew );
2824 // Special case: There is no space in the other Boxes, but in the Cell
2825 if( rParam.bSplittBox )
2827 // the current Box on
2828 SwFmtFrmSize aNewSize( rSz );
2829 aNewSize.SetWidth( nWidth - rParam.nDiff );
2830 rParam.aShareFmts.SetSize( *pBox, aNewSize );
2833 // Special treatment for the Border
2834 // The right one needs to be removed
2836 const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
2837 if( rBoxItem.GetRight() )
2839 SvxBoxItem aTmp( rBoxItem );
2840 aTmp.SetLine( 0, BOX_LINE_RIGHT );
2841 rParam.aShareFmts.SetAttr( rParam.bLeft
2842 ? *pNewBox
2843 : *pBox, aTmp );
2848 rParam.nLowerDiff = rParam.nDiff;
2849 break;
2853 if( rParam.bLeft && rParam.nMode && nDist >= rParam.nSide )
2854 break;
2856 nDist += nWidth;
2858 return true;
2861 static bool lcl_InsOtherBox( SwTableLine* pLine, CR_SetBoxWidth& rParam,
2862 SwTwips nDist, bool bCheck )
2864 // Special case: There is no space in the other Boxes, but in the cell
2865 if( rParam.bSplittBox )
2866 return true;
2868 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2869 sal_uInt16 n;
2871 // Table fixed, proportional
2872 if( !rParam.nRemainWidth && TBLFIX_CHGPROP == rParam.nMode )
2874 // Find the right width to which the relative width adjustment
2875 // corresponds to
2876 SwTwips nTmpDist = nDist;
2877 for( n = 0; n < rBoxes.size(); ++n )
2879 SwTwips nWidth = rBoxes[ n ]->GetFrmFmt()->GetFrmSize().GetWidth();
2880 if( (nTmpDist + nWidth / 2 ) > rParam.nSide )
2882 rParam.nRemainWidth = rParam.bLeft
2883 ? sal_uInt16(nTmpDist)
2884 : sal_uInt16(rParam.nTblWidth - nTmpDist);
2885 break;
2887 nTmpDist += nWidth;
2891 for( n = 0; n < rBoxes.size(); ++n )
2893 SwTableBox* pBox = rBoxes[ n ];
2894 SwFrmFmt* pFmt = pBox->GetFrmFmt();
2895 const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
2896 SwTwips nWidth = rSz.GetWidth();
2898 if( bCheck )
2900 for( sal_uInt16 i = 0; i < pBox->GetTabLines().size(); ++i )
2901 if( !::lcl_InsOtherBox( pBox->GetTabLines()[ i ],
2902 rParam, nDist, true ))
2903 return false;
2906 rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide &&
2907 (TBLFIX_CHGABS != rParam.nMode ||
2908 (n < rBoxes.size() &&
2909 (nDist + nWidth + rBoxes[ n+1 ]->
2910 GetFrmFmt()->GetFrmSize().GetWidth() / 2)
2911 > rParam.nSide) ))
2912 : (nDist + nWidth / 2 ) > rParam.nSide
2915 rParam.bAnyBoxFnd = true;
2916 SwTwips nDiff;
2917 if( TBLFIX_CHGPROP == rParam.nMode ) // Table fixed, proportional
2919 // relativ berechnen
2920 nDiff = nWidth;
2921 nDiff *= rParam.nDiff;
2922 nDiff /= rParam.nRemainWidth;
2924 if( nWidth < nDiff || nWidth - nDiff < MINLAY )
2925 return false;
2927 else
2929 nDiff = rParam.nDiff;
2931 // See if the left or right Box is big enough to give up space.
2932 // We're inserting a Box before or after.
2933 SwTwips nTmpWidth = nWidth;
2934 if( rParam.bLeft && pBox->GetUpper()->GetUpper() )
2936 const SwTableBox* pTmpBox = pBox;
2937 sal_uInt16 nBoxPos = n;
2938 while( !nBoxPos && pTmpBox->GetUpper()->GetUpper() )
2940 pTmpBox = pTmpBox->GetUpper()->GetUpper();
2941 nBoxPos = pTmpBox->GetUpper()->GetTabBoxes().GetPos( pTmpBox );
2943 // if( nBoxPos )
2944 nTmpWidth = pTmpBox->GetFrmFmt()->GetFrmSize().GetWidth();
2945 // else
2946 // nTmpWidth = 0;
2949 if( nTmpWidth < nDiff || nTmpWidth - nDiff < MINLAY )
2950 return false;
2951 break;
2955 else
2957 SwTwips nLowerDiff = 0, nOldLower = rParam.nLowerDiff;
2958 for( sal_uInt16 i = 0; i < pBox->GetTabLines().size(); ++i )
2960 rParam.nLowerDiff = 0;
2961 lcl_InsOtherBox( pBox->GetTabLines()[ i ], rParam,
2962 nDist, false );
2964 if( nLowerDiff < rParam.nLowerDiff )
2965 nLowerDiff = rParam.nLowerDiff;
2967 rParam.nLowerDiff = nOldLower;
2969 if( nLowerDiff ||
2970 (rParam.bLeft ? ((nDist + nWidth / 2 ) <= rParam.nSide &&
2971 (TBLFIX_CHGABS != rParam.nMode ||
2972 (n < rBoxes.size() &&
2973 (nDist + nWidth + rBoxes[ n+1 ]->
2974 GetFrmFmt()->GetFrmSize().GetWidth() / 2)
2975 > rParam.nSide) ))
2976 : (nDist + nWidth / 2 ) > rParam.nSide ))
2978 if( !nLowerDiff )
2980 if( TBLFIX_CHGPROP == rParam.nMode ) // Table fixed, proportional
2982 // Calculate relatively
2983 nLowerDiff = nWidth;
2984 nLowerDiff *= rParam.nDiff;
2985 nLowerDiff /= rParam.nRemainWidth;
2987 else
2988 nLowerDiff = rParam.nDiff;
2991 SwFmtFrmSize aNew( rSz );
2992 rParam.nLowerDiff += nLowerDiff;
2994 if( rParam.bBigger )
2995 aNew.SetWidth( nWidth - nLowerDiff );
2996 else
2997 aNew.SetWidth( nWidth + nLowerDiff );
2998 rParam.aShareFmts.SetSize( *pBox, aNew );
3000 if( TBLFIX_CHGABS == rParam.nMode )
3001 break;
3005 nDist += nWidth;
3007 return true;
3010 // The position comparison's result
3011 // POS_BEFORE, // Box comes before
3012 // POS_BEHIND, // Box comes after
3013 // POS_INSIDE, // Box is completely wthin start/end
3014 // POS_OUTSIDE, // Box overlaps start/end completely
3015 // POS_EQUAL, // Box and start/end are the same
3016 // POS_OVERLAP_BEFORE, // Box overlapps the start
3017 // POS_OVERLAP_BEHIND // Box overlapps the end
3018 SwComparePosition _CheckBoxInRange( sal_uInt16 nStt, sal_uInt16 nEnd,
3019 sal_uInt16 nBoxStt, sal_uInt16 nBoxEnd )
3021 // Still treat COLFUZZY!
3022 SwComparePosition nRet;
3023 if( nBoxStt + COLFUZZY < nStt )
3025 if( nBoxEnd > nStt + COLFUZZY )
3027 if( nBoxEnd >= nEnd + COLFUZZY )
3028 nRet = POS_OUTSIDE;
3029 else
3030 nRet = POS_OVERLAP_BEFORE;
3032 else
3033 nRet = POS_BEFORE;
3035 else if( nEnd > nBoxStt + COLFUZZY )
3037 if( nEnd + COLFUZZY >= nBoxEnd )
3039 if( COLFUZZY > Abs( long(nEnd) - long(nBoxEnd) ) &&
3040 COLFUZZY > Abs( long(nStt) - long(nBoxStt) ) )
3041 nRet = POS_EQUAL;
3042 else
3043 nRet = POS_INSIDE;
3045 else
3046 nRet = POS_OVERLAP_BEHIND;
3048 else
3049 nRet = POS_BEHIND;
3051 return nRet;
3054 static void lcl_DelSelBox_CorrLowers( SwTableLine& rLine, CR_SetBoxWidth& rParam,
3055 SwTwips nWidth )
3057 // 1. step: Calculate own width
3058 SwTableBoxes& rBoxes = rLine.GetTabBoxes();
3059 SwTwips nBoxWidth = 0;
3060 sal_uInt16 n;
3062 for( n = rBoxes.size(); n; )
3063 nBoxWidth += rBoxes[ --n ]->GetFrmFmt()->GetFrmSize().GetWidth();
3065 if( COLFUZZY < Abs( nWidth - nBoxWidth ))
3067 // Thus, they need to be adjusted
3068 for( n = rBoxes.size(); n; )
3070 SwTableBox* pBox = rBoxes[ --n ];
3071 SwFmtFrmSize aNew( pBox->GetFrmFmt()->GetFrmSize() );
3072 long nDiff = aNew.GetWidth();
3073 nDiff *= nWidth;
3074 nDiff /= nBoxWidth;
3075 aNew.SetWidth( nDiff );
3077 rParam.aShareFmts.SetSize( *pBox, aNew );
3079 if( !pBox->GetSttNd() )
3081 // Has Lower itself, so also adjust that
3082 for( sal_uInt16 i = pBox->GetTabLines().size(); i; )
3083 ::lcl_DelSelBox_CorrLowers( *pBox->GetTabLines()[ --i ],
3084 rParam, nDiff );
3090 static void lcl_ChgBoxSize( SwTableBox& rBox, CR_SetBoxWidth& rParam,
3091 const SwFmtFrmSize& rOldSz,
3092 sal_uInt16& rDelWidth, SwTwips nDist )
3094 long nDiff = 0;
3095 bool bSetSize = false;
3097 switch( rParam.nMode )
3099 case TBLFIX_CHGABS: // Fixed width table, change neighbor
3100 nDiff = rDelWidth + rParam.nLowerDiff;
3101 bSetSize = true;
3102 break;
3104 case TBLFIX_CHGPROP: // Fixed width table, change all neighbors
3105 if( !rParam.nRemainWidth )
3107 // Calculate
3108 if( rParam.bLeft )
3109 rParam.nRemainWidth = sal_uInt16(nDist);
3110 else
3111 rParam.nRemainWidth = sal_uInt16(rParam.nTblWidth - nDist);
3114 // Calculate relatively
3115 nDiff = rOldSz.GetWidth();
3116 nDiff *= rDelWidth + rParam.nLowerDiff;
3117 nDiff /= rParam.nRemainWidth;
3119 bSetSize = true;
3120 break;
3122 case TBLVAR_CHGABS: // Variable table, change all neighbors
3123 if( COLFUZZY < Abs( rParam.nBoxWidth -
3124 ( rDelWidth + rParam.nLowerDiff )))
3126 nDiff = rDelWidth + rParam.nLowerDiff - rParam.nBoxWidth;
3127 if( 0 < nDiff )
3128 rDelWidth = rDelWidth - sal_uInt16(nDiff);
3129 else
3130 rDelWidth = rDelWidth + sal_uInt16(-nDiff);
3131 bSetSize = true;
3133 break;
3136 if( bSetSize )
3138 SwFmtFrmSize aNew( rOldSz );
3139 aNew.SetWidth( aNew.GetWidth() + nDiff );
3140 rParam.aShareFmts.SetSize( rBox, aNew );
3142 // Change the Lower once again
3143 for( sal_uInt16 i = rBox.GetTabLines().size(); i; )
3144 ::lcl_DelSelBox_CorrLowers( *rBox.GetTabLines()[ --i ], rParam,
3145 aNew.GetWidth() );
3149 static bool lcl_DeleteBox_Rekursiv( CR_SetBoxWidth& rParam, SwTableBox& rBox,
3150 bool bCheck )
3152 bool bRet = true;
3153 if( rBox.GetSttNd() )
3155 if( bCheck )
3157 rParam.bAnyBoxFnd = true;
3158 if( rBox.GetFrmFmt()->GetProtect().IsCntntProtected() )
3159 bRet = false;
3160 else
3162 SwTableBox* pBox = &rBox;
3163 rParam.m_Boxes.insert(pBox);
3166 else
3167 ::_DeleteBox( rParam.pTblNd->GetTable(), &rBox,
3168 rParam.pUndo, false, true, &rParam.aShareFmts );
3170 else
3172 // We need to delete these sequentially via the ContentBoxes
3173 for( sal_uInt16 i = rBox.GetTabLines().size(); i; )
3175 SwTableLine& rLine = *rBox.GetTabLines()[ --i ];
3176 for( sal_uInt16 n = rLine.GetTabBoxes().size(); n; )
3177 if( !::lcl_DeleteBox_Rekursiv( rParam,
3178 *rLine.GetTabBoxes()[ --n ], bCheck ))
3179 return false;
3182 return bRet;
3185 static bool lcl_DelSelBox( SwTableLine* pTabLine, CR_SetBoxWidth& rParam,
3186 SwTwips nDist, bool bCheck )
3188 SwTableBoxes& rBoxes = pTabLine->GetTabBoxes();
3189 sal_uInt16 n, nCntEnd, nBoxChkStt, nBoxChkEnd, nDelWidth = 0;
3190 if( rParam.bLeft )
3192 n = rBoxes.size();
3193 nCntEnd = 0;
3194 nBoxChkStt = (sal_uInt16)rParam.nSide;
3195 nBoxChkEnd = static_cast<sal_uInt16>(rParam.nSide + rParam.nBoxWidth);
3197 else
3199 n = 0;
3200 nCntEnd = rBoxes.size();
3201 nBoxChkStt = static_cast<sal_uInt16>(rParam.nSide - rParam.nBoxWidth);
3202 nBoxChkEnd = (sal_uInt16)rParam.nSide;
3206 while( n != nCntEnd )
3208 SwTableBox* pBox;
3209 if( rParam.bLeft )
3210 pBox = rBoxes[ --n ];
3211 else
3212 pBox = rBoxes[ n++ ];
3214 SwFrmFmt* pFmt = pBox->GetFrmFmt();
3215 const SwFmtFrmSize& rSz = pFmt->GetFrmSize();
3216 long nWidth = rSz.GetWidth();
3217 bool bDelBox = false, bChgLowers = false;
3219 // Test the Box width and react accordingly
3220 SwComparePosition ePosType = ::_CheckBoxInRange(
3221 nBoxChkStt, nBoxChkEnd,
3222 sal_uInt16(rParam.bLeft ? nDist - nWidth : nDist),
3223 sal_uInt16(rParam.bLeft ? nDist : nDist + nWidth));
3225 switch( ePosType )
3227 case POS_BEFORE:
3228 if( bCheck )
3230 if( rParam.bLeft )
3231 return true;
3233 else if( rParam.bLeft )
3235 ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist );
3236 if( TBLFIX_CHGABS == rParam.nMode )
3237 n = nCntEnd;
3239 break;
3241 case POS_BEHIND:
3242 if( bCheck )
3244 if( !rParam.bLeft )
3245 return true;
3247 else if( !rParam.bLeft )
3249 ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist );
3250 if( TBLFIX_CHGABS == rParam.nMode )
3251 n = nCntEnd;
3253 break;
3255 case POS_OUTSIDE: // Box fully overlaps start/end
3256 case POS_INSIDE: // Box is completely within start/end
3257 case POS_EQUAL: // Box and start/end are the same
3258 bDelBox = true;
3259 break;
3261 case POS_OVERLAP_BEFORE: // Box overlaps the start
3262 if( nBoxChkStt <= ( nDist + (rParam.bLeft ? - nWidth / 2
3263 : nWidth / 2 )))
3265 if( !pBox->GetSttNd() )
3266 bChgLowers = true;
3267 else
3268 bDelBox = true;
3270 else if( !bCheck && rParam.bLeft )
3272 if( !pBox->GetSttNd() )
3273 bChgLowers = true;
3274 else
3276 ::lcl_ChgBoxSize( *pBox, rParam, rSz, nDelWidth, nDist );
3277 if( TBLFIX_CHGABS == rParam.nMode )
3278 n = nCntEnd;
3281 break;
3283 case POS_OVERLAP_BEHIND: // Box overlaps the end
3284 // JP 10.02.99:
3285 // Delete generally or (like in OVERLAP_BEFORE) only delete the one who reaches up to the half into the delete Box?
3286 if( !pBox->GetSttNd() )
3287 bChgLowers = true;
3288 else
3289 bDelBox = true;
3290 break;
3291 default: break;
3294 if( bDelBox )
3296 nDelWidth = nDelWidth + sal_uInt16(nWidth);
3297 if( bCheck )
3299 // The last/first Box can only be deleted for the variable Table,
3300 // if it's as large as the change in the Table.
3301 if( (( TBLVAR_CHGABS != rParam.nMode ||
3302 nDelWidth != rParam.nBoxWidth ) &&
3303 COLFUZZY > Abs( rParam.bLeft
3304 ? nWidth - nDist
3305 : (nDist + nWidth - rParam.nTblWidth )))
3306 || !::lcl_DeleteBox_Rekursiv( rParam, *pBox, bCheck ) )
3307 return false;
3309 if( pFmt->GetProtect().IsCntntProtected() )
3310 return false;
3312 else
3314 ::lcl_DeleteBox_Rekursiv( rParam, *pBox, bCheck );
3316 if( !rParam.bLeft )
3317 --n, --nCntEnd;
3320 else if( bChgLowers )
3322 bool bFirst = true, bCorrLowers = false;
3323 long nLowerDiff = 0;
3324 long nOldLower = rParam.nLowerDiff;
3325 sal_uInt16 nOldRemain = rParam.nRemainWidth;
3326 sal_uInt16 i;
3328 for( i = pBox->GetTabLines().size(); i; )
3330 rParam.nLowerDiff = nDelWidth + nOldLower;
3331 rParam.nRemainWidth = nOldRemain;
3332 SwTableLine* pLine = pBox->GetTabLines()[ --i ];
3333 if( !::lcl_DelSelBox( pLine, rParam, nDist, bCheck ))
3334 return false;
3336 // Do the Box and its Lines still exist?
3337 if( n < rBoxes.size() &&
3338 pBox == rBoxes[ rParam.bLeft ? n : n-1 ] &&
3339 i < pBox->GetTabLines().size() &&
3340 pLine == pBox->GetTabLines()[ i ] )
3342 if( !bFirst && !bCorrLowers &&
3343 COLFUZZY < Abs( nLowerDiff - rParam.nLowerDiff ) )
3344 bCorrLowers = true;
3346 // The largest deletion width counts, but only if we don't
3347 // delete the whole Line
3348 if( nLowerDiff < rParam.nLowerDiff )
3349 nLowerDiff = rParam.nLowerDiff;
3351 bFirst = false;
3354 rParam.nLowerDiff = nOldLower;
3355 rParam.nRemainWidth = nOldRemain;
3357 // Did we delete all Boxes? Then the deletion width = the Box width, of course
3358 if( !nLowerDiff )
3359 nLowerDiff = nWidth;
3361 // Adjust deletion width!
3362 nDelWidth = nDelWidth + sal_uInt16(nLowerDiff);
3364 if( !bCheck )
3366 // Has the Box already been removed?
3367 if( n > rBoxes.size() ||
3368 pBox != rBoxes[ ( rParam.bLeft ? n : n-1 ) ] )
3370 // Then change the loop variable when deleting to the right
3371 if( !rParam.bLeft )
3372 --n, --nCntEnd;
3374 else
3376 // Or else we need to adapt the Box's size
3377 SwFmtFrmSize aNew( rSz );
3378 bool bCorrRel = false;
3380 if( TBLVAR_CHGABS != rParam.nMode )
3382 switch( ePosType )
3384 case POS_OVERLAP_BEFORE: // Box overlaps the start
3385 if( TBLFIX_CHGPROP == rParam.nMode )
3386 bCorrRel = rParam.bLeft;
3387 else if( rParam.bLeft ) // TBLFIX_CHGABS
3389 nLowerDiff = nLowerDiff - nDelWidth;
3390 bCorrLowers = true;
3391 n = nCntEnd;
3393 break;
3395 case POS_OVERLAP_BEHIND: // Box overlaps the end
3396 if( TBLFIX_CHGPROP == rParam.nMode )
3397 bCorrRel = !rParam.bLeft;
3398 else if( !rParam.bLeft ) // TBLFIX_CHGABS
3400 nLowerDiff = nLowerDiff - nDelWidth;
3401 bCorrLowers = true;
3402 n = nCntEnd;
3404 break;
3406 default:
3407 OSL_ENSURE( !pBox, "we should never reach this!" );
3408 break;
3412 if( bCorrRel )
3414 if( !rParam.nRemainWidth )
3416 // Calculate
3417 if( rParam.bLeft )
3418 rParam.nRemainWidth = sal_uInt16(nDist - nLowerDiff);
3419 else
3420 rParam.nRemainWidth = sal_uInt16(rParam.nTblWidth - nDist
3421 - nLowerDiff );
3424 long nDiff = aNew.GetWidth() - nLowerDiff;
3425 nDiff *= nDelWidth + rParam.nLowerDiff;
3426 nDiff /= rParam.nRemainWidth;
3428 aNew.SetWidth( aNew.GetWidth() - nLowerDiff + nDiff );
3430 else
3431 aNew.SetWidth( aNew.GetWidth() - nLowerDiff );
3432 rParam.aShareFmts.SetSize( *pBox, aNew );
3434 if( bCorrLowers )
3436 // Adapt the Lower once again
3437 for( i = pBox->GetTabLines().size(); i; )
3438 ::lcl_DelSelBox_CorrLowers( *pBox->
3439 GetTabLines()[ --i ], rParam, aNew.GetWidth() );
3445 if( rParam.bLeft )
3446 nDist -= nWidth;
3447 else
3448 nDist += nWidth;
3450 rParam.nLowerDiff = nDelWidth;
3451 return true;
3454 // Dummy function for the method SetColWidth
3455 static bool lcl_DelOtherBox( SwTableLine* , CR_SetBoxWidth& , SwTwips , bool )
3457 return true;
3460 static void lcl_AjustLines( SwTableLine* pLine, CR_SetBoxWidth& rParam )
3462 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
3463 for( sal_uInt16 n = 0; n < rBoxes.size(); ++n )
3465 SwTableBox* pBox = rBoxes[ n ];
3467 SwFmtFrmSize aSz( pBox->GetFrmFmt()->GetFrmSize() );
3468 SwTwips nWidth = aSz.GetWidth();
3469 nWidth *= rParam.nDiff;
3470 nWidth /= rParam.nMaxSize;
3471 aSz.SetWidth( nWidth );
3472 rParam.aShareFmts.SetSize( *pBox, aSz );
3474 for( sal_uInt16 i = 0; i < pBox->GetTabLines().size(); ++i )
3475 ::lcl_AjustLines( pBox->GetTabLines()[ i ], rParam );
3479 #ifdef DBG_UTIL
3480 void _CheckBoxWidth( const SwTableLine& rLine, SwTwips nSize )
3482 const SwTableBoxes& rBoxes = rLine.GetTabBoxes();
3484 SwTwips nAktSize = 0;
3485 // See if the tables have a correct width
3486 for (SwTableBoxes::const_iterator i(rBoxes.begin()); i != rBoxes.end(); ++i)
3488 const SwTableBox* pBox = *i;
3489 const SwTwips nBoxW = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
3490 nAktSize += nBoxW;
3492 for( sal_uInt16 j = 0; j < pBox->GetTabLines().size(); ++j )
3493 _CheckBoxWidth( *pBox->GetTabLines()[ j ], nBoxW );
3496 if (sal::static_int_cast< unsigned long >(Abs(nAktSize - nSize)) >
3497 (COLFUZZY * rBoxes.size()))
3499 OSL_FAIL( "Line's Boxes are too small or too large" );
3502 #endif
3504 static _FndBox* lcl_SaveInsDelData( CR_SetBoxWidth& rParam, SwUndo** ppUndo,
3505 SwTableSortBoxes& rTmpLst, SwTwips nDistStt )
3507 // Find all Boxes/Lines
3508 SwTable& rTbl = rParam.pTblNd->GetTable();
3510 if (rParam.m_Boxes.empty())
3512 // Get the Boxes
3513 if( rParam.bBigger )
3514 for( sal_uInt16 n = 0; n < rTbl.GetTabLines().size(); ++n )
3515 ::lcl_DelSelBox( rTbl.GetTabLines()[ n ], rParam, nDistStt, true );
3516 else
3517 for( sal_uInt16 n = 0; n < rTbl.GetTabLines().size(); ++n )
3518 ::lcl_InsSelBox( rTbl.GetTabLines()[ n ], rParam, nDistStt, true );
3521 // Prevent deleting the whole Table
3522 if (rParam.bBigger
3523 && rParam.m_Boxes.size() == rTbl.GetTabSortBoxes().size())
3525 return 0;
3528 _FndBox* pFndBox = new _FndBox( 0, 0 );
3529 if( rParam.bBigger )
3530 pFndBox->SetTableLines( rParam.m_Boxes, rTbl );
3531 else
3533 _FndPara aPara(rParam.m_Boxes, pFndBox);
3534 ForEach_FndLineCopyCol( rTbl.GetTabLines(), &aPara );
3535 OSL_ENSURE( pFndBox->GetLines().size(), "Where are the Boxes" );
3536 pFndBox->SetTableLines( rTbl );
3538 if( ppUndo )
3539 rTmpLst.insert( rTbl.GetTabSortBoxes() );
3542 // Find Lines for the Layout update
3543 pFndBox->DelFrms( rTbl );
3545 // TL_CHART2: this function gest called from SetColWidth exclusively,
3546 // thus it is currently speculated that nothing needs to be done here.
3547 // Note: that SetColWidth is currently not completely understood though :-(
3549 return pFndBox;
3552 bool SwTable::SetColWidth( SwTableBox& rAktBox, sal_uInt16 eType,
3553 SwTwips nAbsDiff, SwTwips nRelDiff, SwUndo** ppUndo )
3555 SetHTMLTableLayout( 0 ); // Delete HTML Layout
3557 const SwFmtFrmSize& rSz = GetFrmFmt()->GetFrmSize();
3558 const SvxLRSpaceItem& rLR = GetFrmFmt()->GetLRSpace();
3560 _FndBox* pFndBox = 0; // for insertion/deletion
3561 SwTableSortBoxes aTmpLst; // for Undo
3562 bool bBigger,
3563 bRet = false,
3564 bLeft = nsTblChgWidthHeightType::WH_COL_LEFT == ( eType & 0xff ) ||
3565 nsTblChgWidthHeightType::WH_CELL_LEFT == ( eType & 0xff ),
3566 bInsDel = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL );
3567 sal_uInt16 n;
3568 sal_uLong nBoxIdx = rAktBox.GetSttIdx();
3570 // Get the current Box's edge
3571 // Only needed for manipulating the width
3572 const SwTwips nDist = ::lcl_GetDistance( &rAktBox, bLeft );
3573 SwTwips nDistStt = 0;
3574 CR_SetBoxWidth aParam( eType, nRelDiff, nDist, rSz.GetWidth(),
3575 bLeft ? nDist : rSz.GetWidth() - nDist,
3576 (SwTableNode*)rAktBox.GetSttNd()->FindTableNode() );
3577 bBigger = aParam.bBigger;
3579 FN_lcl_SetBoxWidth fnSelBox, fnOtherBox;
3580 if( bInsDel )
3582 if( bBigger )
3584 fnSelBox = lcl_DelSelBox;
3585 fnOtherBox = lcl_DelOtherBox;
3586 aParam.nBoxWidth = (sal_uInt16)rAktBox.GetFrmFmt()->GetFrmSize().GetWidth();
3587 if( bLeft )
3588 nDistStt = rSz.GetWidth();
3590 else
3592 fnSelBox = lcl_InsSelBox;
3593 fnOtherBox = lcl_InsOtherBox;
3596 else
3598 fnSelBox = lcl_SetSelBoxWidth;
3599 fnOtherBox = lcl_SetOtherBoxWidth;
3603 switch( eType & 0xff )
3605 case nsTblChgWidthHeightType::WH_COL_RIGHT:
3606 case nsTblChgWidthHeightType::WH_COL_LEFT:
3607 if( TBLVAR_CHGABS == eTblChgMode )
3609 if( bInsDel )
3610 bBigger = !bBigger;
3612 // First test if we have room at all
3613 bool bChgLRSpace = true;
3614 if( bBigger )
3616 if( GetFrmFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) &&
3617 !rSz.GetWidthPercent() )
3619 bRet = rSz.GetWidth() < USHRT_MAX - nRelDiff;
3620 bChgLRSpace = bLeft ? rLR.GetLeft() >= nAbsDiff
3621 : rLR.GetRight() >= nAbsDiff;
3623 else
3624 bRet = bLeft ? rLR.GetLeft() >= nAbsDiff
3625 : rLR.GetRight() >= nAbsDiff;
3627 if( !bRet && bInsDel &&
3628 // Is the room on the other side?
3629 ( bLeft ? rLR.GetRight() >= nAbsDiff
3630 : rLR.GetLeft() >= nAbsDiff ))
3632 bRet = true; bLeft = !bLeft;
3635 if( !bRet )
3637 // Then call itself recursively; only with another mode (proportional)
3638 TblChgMode eOld = eTblChgMode;
3639 eTblChgMode = TBLFIX_CHGPROP;
3641 bRet = SetColWidth( rAktBox, eType, nAbsDiff, nRelDiff,
3642 ppUndo );
3643 eTblChgMode = eOld;
3644 return bRet;
3647 else
3649 bRet = true;
3650 for( n = 0; n < aLines.size(); ++n )
3652 aParam.LoopClear();
3653 if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, true ))
3655 bRet = false;
3656 break;
3661 if( bRet )
3663 if( bInsDel )
3665 pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo,
3666 aTmpLst, nDistStt );
3667 if (aParam.bBigger &&
3668 aParam.m_Boxes.size() == m_TabSortContentBoxes.size())
3670 // This whole Table is to be deleted!
3671 GetFrmFmt()->GetDoc()->DeleteRowCol(aParam.m_Boxes);
3672 return false;
3675 if( ppUndo )
3676 *ppUndo = aParam.CreateUndo(
3677 aParam.bBigger ? UNDO_COL_DELETE
3678 : UNDO_TABLE_INSCOL );
3680 else if( ppUndo )
3681 *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
3683 long nFrmWidth = LONG_MAX;
3684 LockModify();
3685 SwFmtFrmSize aSz( rSz );
3686 SvxLRSpaceItem aLR( rLR );
3687 if( bBigger )
3689 // If the Table does not have any room to grow, we need to create some!
3690 if( aSz.GetWidth() + nRelDiff > USHRT_MAX )
3692 // Break down to USHRT_MAX / 2
3693 CR_SetBoxWidth aTmpPara( 0, aSz.GetWidth() / 2,
3694 0, aSz.GetWidth(), aSz.GetWidth(), aParam.pTblNd );
3695 for( sal_uInt16 nLn = 0; nLn < aLines.size(); ++nLn )
3696 ::lcl_AjustLines( aLines[ nLn ], aTmpPara );
3697 aSz.SetWidth( aSz.GetWidth() / 2 );
3698 aParam.nDiff = nRelDiff /= 2;
3699 aParam.nSide /= 2;
3700 aParam.nMaxSize /= 2;
3703 if( bLeft )
3704 aLR.SetLeft( sal_uInt16( aLR.GetLeft() - nAbsDiff ) );
3705 else
3706 aLR.SetRight( sal_uInt16( aLR.GetRight() - nAbsDiff ) );
3708 else if( bLeft )
3709 aLR.SetLeft( sal_uInt16( aLR.GetLeft() + nAbsDiff ) );
3710 else
3711 aLR.SetRight( sal_uInt16( aLR.GetRight() + nAbsDiff ) );
3713 if( bChgLRSpace )
3714 GetFrmFmt()->SetFmtAttr( aLR );
3715 const SwFmtHoriOrient& rHOri = GetFrmFmt()->GetHoriOrient();
3716 if( text::HoriOrientation::FULL == rHOri.GetHoriOrient() ||
3717 (text::HoriOrientation::LEFT == rHOri.GetHoriOrient() && aLR.GetLeft()) ||
3718 (text::HoriOrientation::RIGHT == rHOri.GetHoriOrient() && aLR.GetRight()))
3720 SwFmtHoriOrient aHOri( rHOri );
3721 aHOri.SetHoriOrient( text::HoriOrientation::NONE );
3722 GetFrmFmt()->SetFmtAttr( aHOri );
3724 // If the Table happens to contain relative values (USHORT_MAX),
3725 // we need to convert them to absolute ones now.
3726 // Bug 61494
3727 if( GetFrmFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::BROWSE_MODE) &&
3728 !rSz.GetWidthPercent() )
3730 SwTabFrm* pTabFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement( *GetFrmFmt() );
3731 if( pTabFrm &&
3732 pTabFrm->Prt().Width() != rSz.GetWidth() )
3734 nFrmWidth = pTabFrm->Prt().Width();
3735 if( bBigger )
3736 nFrmWidth += nAbsDiff;
3737 else
3738 nFrmWidth -= nAbsDiff;
3743 if( bBigger )
3744 aSz.SetWidth( aSz.GetWidth() + nRelDiff );
3745 else
3746 aSz.SetWidth( aSz.GetWidth() - nRelDiff );
3748 if( rSz.GetWidthPercent() )
3749 aSz.SetWidthPercent( static_cast<sal_uInt8>(( aSz.GetWidth() * 100 ) /
3750 ( aSz.GetWidth() + aLR.GetRight() + aLR.GetLeft())));
3752 GetFrmFmt()->SetFmtAttr( aSz );
3753 aParam.nTblWidth = sal_uInt16( aSz.GetWidth() );
3755 UnlockModify();
3757 for( n = aLines.size(); n; )
3759 --n;
3760 aParam.LoopClear();
3761 (*fnSelBox)( aLines[ n ], aParam, nDistStt, false );
3764 // If the Table happens to contain relative values (USHORT_MAX),
3765 // we need to convert them to absolute ones now.
3766 // Bug 61494
3767 if( LONG_MAX != nFrmWidth )
3769 SwFmtFrmSize aAbsSz( aSz );
3770 aAbsSz.SetWidth( nFrmWidth );
3771 GetFrmFmt()->SetFmtAttr( aAbsSz );
3775 else if( bInsDel ||
3776 ( bLeft ? nDist : Abs( rSz.GetWidth() - nDist ) > COLFUZZY ) )
3778 bRet = true;
3779 if( bLeft && TBLFIX_CHGABS == eTblChgMode && !bInsDel )
3780 aParam.bBigger = !bBigger;
3782 // First test if we have room at all
3783 if( bInsDel )
3785 if( aParam.bBigger )
3787 for( n = 0; n < aLines.size(); ++n )
3789 aParam.LoopClear();
3790 if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, true ))
3792 bRet = false;
3793 break;
3797 else
3799 if( ( bRet = bLeft ? nDist != 0
3800 : ( rSz.GetWidth() - nDist ) > COLFUZZY ) )
3802 for( n = 0; n < aLines.size(); ++n )
3804 aParam.LoopClear();
3805 if( !(*fnOtherBox)( aLines[ n ], aParam, 0, true ))
3807 bRet = false;
3808 break;
3811 if( bRet && !aParam.bAnyBoxFnd )
3812 bRet = false;
3815 if( !bRet && rAktBox.GetFrmFmt()->GetFrmSize().GetWidth()
3816 - nRelDiff > COLFUZZY +
3817 ( 567 / 2 /*leave room for at least 0.5 cm*/) )
3819 // Consume the space from the current Cell
3820 aParam.bSplittBox = true;
3821 // We also need to test this!
3822 bRet = true;
3824 for( n = 0; n < aLines.size(); ++n )
3826 aParam.LoopClear();
3827 if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, true ))
3829 bRet = false;
3830 break;
3836 else if( aParam.bBigger )
3838 for( n = 0; n < aLines.size(); ++n )
3840 aParam.LoopClear();
3841 if( !(*fnOtherBox)( aLines[ n ], aParam, 0, true ))
3843 bRet = false;
3844 break;
3848 else
3850 for( n = 0; n < aLines.size(); ++n )
3852 aParam.LoopClear();
3853 if( !(*fnSelBox)( aLines[ n ], aParam, nDistStt, true ))
3855 bRet = false;
3856 break;
3861 // If true, set it
3862 if( bRet )
3864 CR_SetBoxWidth aParam1( aParam );
3865 if( bInsDel )
3867 aParam1.bBigger = !aParam.bBigger;
3868 pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo,
3869 aTmpLst, nDistStt );
3870 if( ppUndo )
3871 *ppUndo = aParam.CreateUndo(
3872 aParam.bBigger ? UNDO_TABLE_DELBOX
3873 : UNDO_TABLE_INSCOL );
3875 else if( ppUndo )
3876 *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
3878 if( bInsDel
3879 ? ( TBLFIX_CHGABS == eTblChgMode ? bLeft : bLeft )
3880 : ( TBLFIX_CHGABS != eTblChgMode && bLeft ) )
3882 for( n = aLines.size(); n; )
3884 --n;
3885 aParam.LoopClear();
3886 aParam1.LoopClear();
3887 (*fnSelBox)( aLines[ n ], aParam, nDistStt, false );
3888 (*fnOtherBox)( aLines[ n ], aParam1, nDistStt, false );
3891 else
3892 for( n = aLines.size(); n; )
3894 --n;
3895 aParam.LoopClear();
3896 aParam1.LoopClear();
3897 (*fnOtherBox)( aLines[ n ], aParam1, nDistStt, false );
3898 (*fnSelBox)( aLines[ n ], aParam, nDistStt, false );
3902 break;
3904 case nsTblChgWidthHeightType::WH_CELL_RIGHT:
3905 case nsTblChgWidthHeightType::WH_CELL_LEFT:
3906 if( TBLVAR_CHGABS == eTblChgMode )
3908 // Then call itself recursively; only with another mode (proportional)
3909 TblChgMode eOld = eTblChgMode;
3910 eTblChgMode = TBLFIX_CHGABS;
3912 bRet = SetColWidth( rAktBox, eType, nAbsDiff, nRelDiff,
3913 ppUndo );
3914 eTblChgMode = eOld;
3915 return bRet;
3917 else if( bInsDel || ( bLeft ? nDist
3918 : (rSz.GetWidth() - nDist) > COLFUZZY ))
3920 if( bLeft && TBLFIX_CHGABS == eTblChgMode && !bInsDel )
3921 aParam.bBigger = !bBigger;
3923 // First, see if there is enough room at all
3924 SwTableBox* pBox = &rAktBox;
3925 SwTableLine* pLine = rAktBox.GetUpper();
3926 while( pLine->GetUpper() )
3928 sal_uInt16 nPos = pLine->GetTabBoxes().GetPos( pBox );
3929 if( bLeft ? nPos : nPos + 1 != (sal_uInt16)pLine->GetTabBoxes().size() )
3930 break;
3932 pBox = pLine->GetUpper();
3933 pLine = pBox->GetUpper();
3936 if( pLine->GetUpper() )
3938 // We need to correct the distance once again!
3939 aParam.nSide -= ::lcl_GetDistance( pLine->GetUpper(), true );
3941 if( bLeft )
3942 aParam.nMaxSize = aParam.nSide;
3943 else
3944 aParam.nMaxSize = pLine->GetUpper()->GetFrmFmt()->
3945 GetFrmSize().GetWidth() - aParam.nSide;
3948 // First, see if there is enough room at all
3949 if( bInsDel )
3951 if( 0 != ( bRet = bLeft ? nDist != 0
3952 : ( rSz.GetWidth() - nDist ) > COLFUZZY ) &&
3953 !aParam.bBigger )
3955 bRet = (*fnOtherBox)( pLine, aParam, 0, true );
3956 if( bRet && !aParam.bAnyBoxFnd )
3957 bRet = false;
3960 if( !bRet && !aParam.bBigger && rAktBox.GetFrmFmt()->
3961 GetFrmSize().GetWidth() - nRelDiff > COLFUZZY +
3962 ( 567 / 2 /*leave room for at least 0.5 cm*/) )
3964 // Consume the room from the current Cell
3965 aParam.bSplittBox = true;
3966 bRet = true;
3969 else
3971 FN_lcl_SetBoxWidth fnTmp = aParam.bBigger ? fnOtherBox : fnSelBox;
3972 bRet = (*fnTmp)( pLine, aParam, nDistStt, true );
3975 // If true, set it
3976 if( bRet )
3978 CR_SetBoxWidth aParam1( aParam );
3979 if( bInsDel )
3981 aParam1.bBigger = !aParam.bBigger;
3982 pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst, nDistStt );
3983 if( ppUndo )
3984 *ppUndo = aParam.CreateUndo(
3985 aParam.bBigger ? UNDO_TABLE_DELBOX
3986 : UNDO_TABLE_INSCOL );
3988 else if( ppUndo )
3989 *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
3991 if( bInsDel
3992 ? ( TBLFIX_CHGABS == eTblChgMode ? (bBigger && bLeft) : bLeft )
3993 : ( TBLFIX_CHGABS != eTblChgMode && bLeft ) )
3995 (*fnSelBox)( pLine, aParam, nDistStt, false );
3996 (*fnOtherBox)( pLine, aParam1, nDistStt, false );
3998 else
4000 (*fnOtherBox)( pLine, aParam1, nDistStt, false );
4001 (*fnSelBox)( pLine, aParam, nDistStt, false );
4005 break;
4009 if( pFndBox )
4011 // Clean up the structure of all Lines
4012 GCLines();
4014 // Update Layout
4015 if( !bBigger || pFndBox->AreLinesToRestore( *this ) )
4016 pFndBox->MakeFrms( *this );
4018 // TL_CHART2: it is currently unclear if sth has to be done here.
4019 // The function name hints that nothing needs to be done, on the other
4020 // hand there is a case where sth gets deleted. :-(
4022 delete pFndBox;
4024 if( ppUndo && *ppUndo )
4026 aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<sal_uInt16>(eTblChgMode), eType,
4027 nAbsDiff, nRelDiff );
4028 if( !aParam.bBigger )
4029 aParam.pUndo->SaveNewBoxes( *aParam.pTblNd, aTmpLst );
4033 if( bRet )
4035 CHECKBOXWIDTH
4036 CHECKTABLELAYOUT
4039 return bRet;
4042 static _FndBox* lcl_SaveInsDelData( CR_SetLineHeight& rParam, SwUndo** ppUndo,
4043 SwTableSortBoxes& rTmpLst )
4045 // Find all Boxes/Lines
4046 SwTable& rTbl = rParam.pTblNd->GetTable();
4048 OSL_ENSURE( !rParam.m_Boxes.empty(), "We can't go on without Boxes!" );
4050 // Prevent deleting the whole Table
4051 if (!rParam.bBigger
4052 && rParam.m_Boxes.size() == rTbl.GetTabSortBoxes().size())
4054 return 0;
4057 _FndBox* pFndBox = new _FndBox( 0, 0 );
4058 if( !rParam.bBigger )
4059 pFndBox->SetTableLines( rParam.m_Boxes, rTbl );
4060 else
4062 _FndPara aPara(rParam.m_Boxes, pFndBox);
4063 ForEach_FndLineCopyCol( rTbl.GetTabLines(), &aPara );
4064 OSL_ENSURE( pFndBox->GetLines().size(), "Where are the Boxes?" );
4065 pFndBox->SetTableLines( rTbl );
4067 if( ppUndo )
4068 rTmpLst.insert( rTbl.GetTabSortBoxes() );
4071 // Find Lines for the Layout update
4072 pFndBox->DelFrms( rTbl );
4074 // TL_CHART2: it is currently unclear if sth has to be done here.
4076 return pFndBox;
4079 void SetLineHeight( SwTableLine& rLine, SwTwips nOldHeight, SwTwips nNewHeight,
4080 bool bMinSize )
4082 SwLayoutFrm* pLineFrm = GetRowFrm( rLine );
4083 OSL_ENSURE( pLineFrm, "Where is the Frame from the SwTableLine?" );
4085 SwFrmFmt* pFmt = rLine.ClaimFrmFmt();
4087 SwTwips nMyNewH, nMyOldH = pLineFrm->Frm().Height();
4088 if( !nOldHeight ) // the BaseLine and absolute
4089 nMyNewH = nMyOldH + nNewHeight;
4090 else
4092 // Calculate as exactly as possible
4093 Fraction aTmp( nMyOldH );
4094 aTmp *= Fraction( nNewHeight, nOldHeight );
4095 aTmp += Fraction( 1, 2 ); // round up if needed
4096 nMyNewH = aTmp;
4099 SwFrmSize eSize = ATT_MIN_SIZE;
4100 if( !bMinSize &&
4101 ( nMyOldH - nMyNewH ) > ( CalcRowRstHeight( pLineFrm ) + ROWFUZZY ))
4102 eSize = ATT_FIX_SIZE;
4104 pFmt->SetFmtAttr( SwFmtFrmSize( eSize, 0, nMyNewH ) );
4106 // First adapt all internal ones
4107 SwTableBoxes& rBoxes = rLine.GetTabBoxes();
4108 for( sal_uInt16 n = 0; n < rBoxes.size(); ++n )
4110 SwTableBox& rBox = *rBoxes[ n ];
4111 for( sal_uInt16 i = 0; i < rBox.GetTabLines().size(); ++i )
4112 SetLineHeight( *rBox.GetTabLines()[ i ], nMyOldH, nMyNewH, bMinSize );
4116 static bool lcl_SetSelLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
4117 SwTwips nDist, bool bCheck )
4119 bool bRet = true;
4120 if( !bCheck )
4122 // Set line height
4123 SetLineHeight( *pLine, 0, rParam.bBigger ? nDist : -nDist,
4124 rParam.bBigger );
4126 else if( !rParam.bBigger )
4128 // Calculate the new relative size by means of the old one
4129 SwLayoutFrm* pLineFrm = GetRowFrm( *pLine );
4130 OSL_ENSURE( pLineFrm, "Where is the Frame from the SwTableLine?" );
4131 SwTwips nRstHeight = CalcRowRstHeight( pLineFrm );
4132 if( (nRstHeight + ROWFUZZY) < nDist )
4133 bRet = false;
4135 return bRet;
4138 static bool lcl_SetOtherLineHeight( SwTableLine* pLine, CR_SetLineHeight& rParam,
4139 SwTwips nDist, bool bCheck )
4141 bool bRet = true;
4142 if( bCheck )
4144 if( rParam.bBigger )
4146 // Calculate the new relative size by means of the old one
4147 SwLayoutFrm* pLineFrm = GetRowFrm( *pLine );
4148 OSL_ENSURE( pLineFrm, "Where is the Frame from the SwTableLine?" );
4150 if( TBLFIX_CHGPROP == rParam.nMode )
4152 nDist *= pLineFrm->Frm().Height();
4153 nDist /= rParam.nMaxHeight;
4155 bRet = nDist <= CalcRowRstHeight( pLineFrm );
4158 else
4160 // Set line height
4161 // pLine is the following/preceeding, thus adjust it
4162 if( TBLFIX_CHGPROP == rParam.nMode )
4164 SwLayoutFrm* pLineFrm = GetRowFrm( *pLine );
4165 OSL_ENSURE( pLineFrm, "Where is the Frame from the SwTableLine??" );
4167 // Calculate the new relative size by means of the old one
4168 // If the selected Box get bigger, adjust via the max space else
4169 // via the max height.
4170 if( 1 /*!rParam.bBigger*/ )
4172 nDist *= pLineFrm->Frm().Height();
4173 nDist /= rParam.nMaxHeight;
4175 else
4177 // Calculate the new relative size by means of the old one
4178 nDist *= CalcRowRstHeight( pLineFrm );
4179 nDist /= rParam.nMaxSpace;
4182 SetLineHeight( *pLine, 0, rParam.bBigger ? -nDist : nDist,
4183 !rParam.bBigger );
4185 return bRet;
4188 static bool lcl_InsDelSelLine( SwTableLine* pLine, CR_SetLineHeight& rParam,
4189 SwTwips nDist, bool bCheck )
4191 bool bRet = true;
4192 if( !bCheck )
4194 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
4195 SwDoc* pDoc = pLine->GetFrmFmt()->GetDoc();
4196 if( !rParam.bBigger )
4198 for (size_t n = rBoxes.size(); n; )
4200 ::lcl_SaveUpperLowerBorder( rParam.pTblNd->GetTable(),
4201 *rBoxes[ --n ],
4202 rParam.aShareFmts );
4204 for (size_t n = rBoxes.size(); n; )
4206 ::_DeleteBox( rParam.pTblNd->GetTable(),
4207 rBoxes[ --n ], rParam.pUndo, false,
4208 false, &rParam.aShareFmts );
4211 else
4213 // Insert Line
4214 SwTableLine* pNewLine = new SwTableLine( (SwTableLineFmt*)pLine->GetFrmFmt(),
4215 rBoxes.size(), pLine->GetUpper() );
4216 SwTableLines* pLines;
4217 if( pLine->GetUpper() )
4218 pLines = &pLine->GetUpper()->GetTabLines();
4219 else
4220 pLines = &rParam.pTblNd->GetTable().GetTabLines();
4221 sal_uInt16 nPos = pLines->GetPos( pLine );
4222 if( !rParam.bTop )
4223 ++nPos;
4224 pLines->insert( pLines->begin() + nPos, pNewLine );
4226 SwFrmFmt* pNewFmt = pNewLine->ClaimFrmFmt();
4227 pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_MIN_SIZE, 0, nDist ) );
4229 // And once again calculate the Box count
4230 SwTableBoxes& rNewBoxes = pNewLine->GetTabBoxes();
4231 for( sal_uInt16 n = 0; n < rBoxes.size(); ++n )
4233 SwTwips nWidth = 0;
4234 SwTableBox* pOld = rBoxes[ n ];
4235 if( !pOld->GetSttNd() )
4237 // Not a normal content Box, so fall back to the 1st next Box
4238 nWidth = pOld->GetFrmFmt()->GetFrmSize().GetWidth();
4239 while( !pOld->GetSttNd() )
4240 pOld = pOld->GetTabLines()[ 0 ]->GetTabBoxes()[ 0 ];
4242 ::_InsTblBox( pDoc, rParam.pTblNd, pNewLine,
4243 (SwTableBoxFmt*)pOld->GetFrmFmt(), pOld, n );
4245 // Special treatment for the border:
4246 // The top one needs to be removed
4247 const SvxBoxItem& rBoxItem = pOld->GetFrmFmt()->GetBox();
4248 if( rBoxItem.GetTop() )
4250 SvxBoxItem aTmp( rBoxItem );
4251 aTmp.SetLine( 0, BOX_LINE_TOP );
4252 rParam.aShareFmts.SetAttr( rParam.bTop
4253 ? *pOld
4254 : *rNewBoxes[ n ], aTmp );
4257 if( nWidth )
4258 rParam.aShareFmts.SetAttr( *rNewBoxes[ n ],
4259 SwFmtFrmSize( ATT_FIX_SIZE, nWidth, 0 ) );
4263 else
4265 // Collect Boxes!
4266 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
4267 for( sal_uInt16 n = rBoxes.size(); n; )
4269 SwTableBox* pBox = rBoxes[ --n ];
4270 if( pBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
4271 return false;
4273 if( pBox->GetSttNd() )
4275 rParam.m_Boxes.insert(pBox);
4277 else
4279 for( sal_uInt16 i = pBox->GetTabLines().size(); i; )
4280 lcl_InsDelSelLine( pBox->GetTabLines()[ --i ],
4281 rParam, 0, true );
4285 return bRet;
4288 bool SwTable::SetRowHeight( SwTableBox& rAktBox, sal_uInt16 eType,
4289 SwTwips nAbsDiff, SwTwips nRelDiff,SwUndo** ppUndo )
4291 SwTableLine* pLine = rAktBox.GetUpper();
4293 SwTableLine* pBaseLine = pLine;
4294 while( pBaseLine->GetUpper() )
4295 pBaseLine = pBaseLine->GetUpper()->GetUpper();
4297 _FndBox* pFndBox = 0; // for insertion/deletion
4298 SwTableSortBoxes aTmpLst; // for Undo
4299 bool bBigger,
4300 bRet = false,
4301 bTop = nsTblChgWidthHeightType::WH_ROW_TOP == ( eType & 0xff ) ||
4302 nsTblChgWidthHeightType::WH_CELL_TOP == ( eType & 0xff ),
4303 bInsDel = 0 != (eType & nsTblChgWidthHeightType::WH_FLAG_INSDEL );
4304 sal_uInt16 n, nBaseLinePos = GetTabLines().GetPos( pBaseLine );
4305 sal_uLong nBoxIdx = rAktBox.GetSttIdx();
4307 CR_SetLineHeight aParam( eType,
4308 (SwTableNode*)rAktBox.GetSttNd()->FindTableNode() );
4309 bBigger = aParam.bBigger;
4311 FN_lcl_SetLineHeight fnSelLine, fnOtherLine = lcl_SetOtherLineHeight;
4312 if( bInsDel )
4313 fnSelLine = lcl_InsDelSelLine;
4314 else
4315 fnSelLine = lcl_SetSelLineHeight;
4317 SwTableLines* pLines = &aLines;
4319 // How do we get to the height?
4320 switch( eType & 0xff )
4322 case nsTblChgWidthHeightType::WH_CELL_TOP:
4323 case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
4324 if( pLine == pBaseLine )
4325 break; // it doesn't work then!
4327 // Is a nested Line (Box!)
4328 pLines = &pLine->GetUpper()->GetTabLines();
4329 nBaseLinePos = pLines->GetPos( pLine );
4330 pBaseLine = pLine;
4331 // no break!
4333 case nsTblChgWidthHeightType::WH_ROW_TOP:
4334 case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
4336 if( bInsDel && !bBigger ) // By how much does it get higher?
4338 nAbsDiff = GetRowFrm( *pBaseLine )->Frm().Height();
4341 if( TBLVAR_CHGABS == eTblChgMode )
4343 // First test if we have room at all
4344 if( bBigger )
4346 bRet = true;
4347 // What's up with Top, Table in a Frame or Header/Footer with fixed width??
4348 if( !bRet )
4350 // Then call itself recursively; only with another mode (proportional)
4351 TblChgMode eOld = eTblChgMode;
4352 eTblChgMode = TBLFIX_CHGPROP;
4354 bRet = SetRowHeight( rAktBox, eType, nAbsDiff,
4355 nRelDiff, ppUndo );
4357 eTblChgMode = eOld;
4358 return bRet;
4361 else
4362 bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4363 nAbsDiff, true );
4365 if( bRet )
4367 if( bInsDel )
4369 if (aParam.m_Boxes.empty())
4371 ::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ],
4372 aParam, 0, true );
4375 pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst );
4377 // delete complete table when last row is deleted
4378 if( !bBigger &&
4379 aParam.m_Boxes.size() == m_TabSortContentBoxes.size())
4381 GetFrmFmt()->GetDoc()->DeleteRowCol(aParam.m_Boxes);
4382 return false;
4386 if( ppUndo )
4387 *ppUndo = aParam.CreateUndo(
4388 bBigger ? UNDO_TABLE_INSROW
4389 : UNDO_ROW_DELETE );
4391 else if( ppUndo )
4392 *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
4394 (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4395 nAbsDiff, false );
4398 else
4400 bRet = true;
4401 sal_uInt16 nStt, nEnd;
4402 if( bTop )
4403 nStt = 0, nEnd = nBaseLinePos;
4404 else
4405 nStt = nBaseLinePos + 1, nEnd = pLines->size();
4407 // Get the current Lines' height
4408 if( TBLFIX_CHGPROP == eTblChgMode )
4410 for( n = nStt; n < nEnd; ++n )
4412 SwLayoutFrm* pLineFrm = GetRowFrm( *(*pLines)[ n ] );
4413 OSL_ENSURE( pLineFrm, "Where is the Frame from the SwTableLine??" );
4414 aParam.nMaxSpace += CalcRowRstHeight( pLineFrm );
4415 aParam.nMaxHeight += pLineFrm->Frm().Height();
4417 if( bBigger && aParam.nMaxSpace < nAbsDiff )
4418 bRet = false;
4420 else
4422 if( bTop ? nEnd : nStt < nEnd )
4424 if( bTop )
4425 nStt = nEnd - 1;
4426 else
4427 nEnd = nStt + 1;
4429 else
4430 bRet = false;
4433 if( bRet )
4435 if( bBigger )
4437 for( n = nStt; n < nEnd; ++n )
4439 if( !(*fnOtherLine)( (*pLines)[ n ], aParam,
4440 nAbsDiff, true ))
4442 bRet = false;
4443 break;
4447 else
4448 bRet = (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4449 nAbsDiff, true );
4452 if( bRet )
4454 // Adjust
4455 if( bInsDel )
4457 if (aParam.m_Boxes.empty())
4459 ::lcl_InsDelSelLine( (*pLines)[ nBaseLinePos ],
4460 aParam, 0, true );
4462 pFndBox = ::lcl_SaveInsDelData( aParam, ppUndo, aTmpLst );
4463 if( ppUndo )
4464 *ppUndo = aParam.CreateUndo(
4465 bBigger ? UNDO_TABLE_INSROW
4466 : UNDO_ROW_DELETE );
4468 else if( ppUndo )
4469 *ppUndo = new SwUndoAttrTbl( *aParam.pTblNd, sal_True );
4471 CR_SetLineHeight aParam1( aParam );
4472 if( TBLFIX_CHGPROP == eTblChgMode && !bBigger &&
4473 !aParam.nMaxSpace )
4475 // We need to distribute the space evenly among all the Lines.
4476 // That's why we need their count.
4477 aParam1.nLines = nEnd - nStt;
4480 if( bTop )
4482 (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4483 nAbsDiff, false );
4484 for( n = nStt; n < nEnd; ++n )
4485 (*fnOtherLine)( (*pLines)[ n ], aParam1,
4486 nAbsDiff, false );
4488 else
4490 for( n = nStt; n < nEnd; ++n )
4491 (*fnOtherLine)( (*pLines)[ n ], aParam1,
4492 nAbsDiff, false );
4493 (*fnSelLine)( (*pLines)[ nBaseLinePos ], aParam,
4494 nAbsDiff, false );
4497 else
4499 // Then call itself recursively; only with another mode (proportional)
4500 TblChgMode eOld = eTblChgMode;
4501 eTblChgMode = TBLVAR_CHGABS;
4503 bRet = SetRowHeight( rAktBox, eType, nAbsDiff,
4504 nRelDiff, ppUndo );
4506 eTblChgMode = eOld;
4507 pFndBox = 0;
4511 break;
4514 if( pFndBox )
4516 // then clean up the structure of all Lines
4517 GCLines();
4519 // Update Layout
4520 if( bBigger || pFndBox->AreLinesToRestore( *this ) )
4521 pFndBox->MakeFrms( *this );
4523 // TL_CHART2: it is currently unclear if sth has to be done here.
4525 delete pFndBox;
4527 if( ppUndo && *ppUndo )
4529 aParam.pUndo->SetColWidthParam( nBoxIdx, static_cast<sal_uInt16>(eTblChgMode), eType,
4530 nAbsDiff, nRelDiff );
4531 if( bBigger )
4532 aParam.pUndo->SaveNewBoxes( *aParam.pTblNd, aTmpLst );
4536 CHECKTABLELAYOUT
4538 return bRet;
4541 SwFrmFmt* SwShareBoxFmt::GetFormat( long nWidth ) const
4543 SwFrmFmt *pRet = 0, *pTmp;
4544 for( sal_uInt16 n = aNewFmts.size(); n; )
4545 if( ( pTmp = aNewFmts[ --n ])->GetFrmSize().GetWidth()
4546 == nWidth )
4548 pRet = pTmp;
4549 break;
4551 return pRet;
4554 SwFrmFmt* SwShareBoxFmt::GetFormat( const SfxPoolItem& rItem ) const
4556 const SfxPoolItem* pItem;
4557 sal_uInt16 nWhich = rItem.Which();
4558 SwFrmFmt *pRet = 0, *pTmp;
4559 const SfxPoolItem& rFrmSz = pOldFmt->GetFmtAttr( RES_FRM_SIZE, sal_False );
4560 for( sal_uInt16 n = aNewFmts.size(); n; )
4561 if( SFX_ITEM_SET == ( pTmp = aNewFmts[ --n ])->
4562 GetItemState( nWhich, sal_False, &pItem ) && *pItem == rItem &&
4563 pTmp->GetFmtAttr( RES_FRM_SIZE, sal_False ) == rFrmSz )
4565 pRet = pTmp;
4566 break;
4568 return pRet;
4571 void SwShareBoxFmt::AddFormat( SwFrmFmt& rNew )
4573 aNewFmts.push_back( &rNew );
4576 bool SwShareBoxFmt::RemoveFormat( const SwFrmFmt& rFmt )
4578 // returns true, if we can delete
4579 if( pOldFmt == &rFmt )
4580 return true;
4582 std::vector<SwFrmFmt*>::iterator it = std::find( aNewFmts.begin(), aNewFmts.end(), &rFmt );
4583 if( aNewFmts.end() != it )
4584 aNewFmts.erase( it );
4585 return aNewFmts.empty();
4588 SwShareBoxFmts::~SwShareBoxFmts()
4592 SwFrmFmt* SwShareBoxFmts::GetFormat( const SwFrmFmt& rFmt, long nWidth ) const
4594 sal_uInt16 nPos;
4595 return Seek_Entry( rFmt, &nPos )
4596 ? aShareArr[ nPos ].GetFormat( nWidth )
4597 : 0;
4599 SwFrmFmt* SwShareBoxFmts::GetFormat( const SwFrmFmt& rFmt,
4600 const SfxPoolItem& rItem ) const
4602 sal_uInt16 nPos;
4603 return Seek_Entry( rFmt, &nPos )
4604 ? aShareArr[ nPos ].GetFormat( rItem )
4605 : 0;
4608 void SwShareBoxFmts::AddFormat( const SwFrmFmt& rOld, SwFrmFmt& rNew )
4611 sal_uInt16 nPos;
4612 SwShareBoxFmt* pEntry;
4613 if( !Seek_Entry( rOld, &nPos ))
4615 pEntry = new SwShareBoxFmt( rOld );
4616 aShareArr.insert( aShareArr.begin() + nPos, pEntry );
4618 else
4619 pEntry = &aShareArr[ nPos ];
4621 pEntry->AddFormat( rNew );
4625 void SwShareBoxFmts::ChangeFrmFmt( SwTableBox* pBox, SwTableLine* pLn,
4626 SwFrmFmt& rFmt )
4628 SwClient aCl;
4629 SwFrmFmt* pOld = 0;
4630 if( pBox )
4632 pOld = pBox->GetFrmFmt();
4633 pOld->Add( &aCl );
4634 pBox->ChgFrmFmt( (SwTableBoxFmt*)&rFmt );
4636 else if( pLn )
4638 pOld = pLn->GetFrmFmt();
4639 pOld->Add( &aCl );
4640 pLn->ChgFrmFmt( (SwTableLineFmt*)&rFmt );
4642 if( pOld && pOld->IsLastDepend() )
4644 RemoveFormat( *pOld );
4645 delete pOld;
4649 void SwShareBoxFmts::SetSize( SwTableBox& rBox, const SwFmtFrmSize& rSz )
4651 SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(),
4652 *pRet = GetFormat( *pBoxFmt, rSz.GetWidth() );
4653 if( pRet )
4654 ChangeFrmFmt( &rBox, 0, *pRet );
4655 else
4657 pRet = rBox.ClaimFrmFmt();
4658 pRet->SetFmtAttr( rSz );
4659 AddFormat( *pBoxFmt, *pRet );
4663 void SwShareBoxFmts::SetAttr( SwTableBox& rBox, const SfxPoolItem& rItem )
4665 SwFrmFmt *pBoxFmt = rBox.GetFrmFmt(),
4666 *pRet = GetFormat( *pBoxFmt, rItem );
4667 if( pRet )
4668 ChangeFrmFmt( &rBox, 0, *pRet );
4669 else
4671 pRet = rBox.ClaimFrmFmt();
4672 pRet->SetFmtAttr( rItem );
4673 AddFormat( *pBoxFmt, *pRet );
4677 void SwShareBoxFmts::SetAttr( SwTableLine& rLine, const SfxPoolItem& rItem )
4679 SwFrmFmt *pLineFmt = rLine.GetFrmFmt(),
4680 *pRet = GetFormat( *pLineFmt, rItem );
4681 if( pRet )
4682 ChangeFrmFmt( 0, &rLine, *pRet );
4683 else
4685 pRet = rLine.ClaimFrmFmt();
4686 pRet->SetFmtAttr( rItem );
4687 AddFormat( *pLineFmt, *pRet );
4691 void SwShareBoxFmts::RemoveFormat( const SwFrmFmt& rFmt )
4693 for( sal_uInt16 i = aShareArr.size(); i; )
4694 if( aShareArr[ --i ].RemoveFormat( rFmt ))
4695 aShareArr.erase( aShareArr.begin() + i );
4698 bool SwShareBoxFmts::Seek_Entry( const SwFrmFmt& rFmt, sal_uInt16* pPos ) const
4700 sal_uLong nIdx = (sal_uLong)&rFmt;
4701 sal_uInt16 nO = aShareArr.size(), nM, nU = 0;
4702 if( nO > 0 )
4704 nO--;
4705 while( nU <= nO )
4707 nM = nU + ( nO - nU ) / 2;
4708 sal_uLong nFmt = (sal_uLong)&aShareArr[ nM ].GetOldFormat();
4709 if( nFmt == nIdx )
4711 if( pPos )
4712 *pPos = nM;
4713 return true;
4715 else if( nFmt < nIdx )
4716 nU = nM + 1;
4717 else if( nM == 0 )
4719 if( pPos )
4720 *pPos = nU;
4721 return false;
4723 else
4724 nO = nM - 1;
4727 if( pPos )
4728 *pPos = nU;
4729 return false;
4732 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */