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