xref: /trunk/main/sw/source/core/docnode/ndtbl.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 
2 /*************************************************************************
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * Copyright 2000, 2010 Oracle and/or its affiliates.
7  *
8  * OpenOffice.org - a multi-platform office productivity suite
9  *
10  * This file is part of OpenOffice.org.
11  *
12  * OpenOffice.org is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU Lesser General Public License version 3
14  * only, as published by the Free Software Foundation.
15  *
16  * OpenOffice.org is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License version 3 for more details
20  * (a copy is included in the LICENSE file that accompanied this code).
21  *
22  * You should have received a copy of the GNU Lesser General Public License
23  * version 3 along with OpenOffice.org.  If not, see
24  * <http://www.openoffice.org/license.html>
25  * for a copy of the LGPLv3 License.
26  *
27  ************************************************************************/
28 
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_sw.hxx"
31 
32 #include <com/sun/star/chart2/XChartDocument.hpp>
33 #include <hintids.hxx>
34 #include <editeng/lrspitem.hxx>
35 #include <editeng/brkitem.hxx>
36 #include <editeng/protitem.hxx>
37 #include <editeng/boxitem.hxx>
38 #include <editeng/shaditem.hxx>
39 #include <fmtfsize.hxx>
40 #include <fmtornt.hxx>
41 #include <fmtfordr.hxx>
42 #include <fmtpdsc.hxx>
43 #include <fmtanchr.hxx>
44 #include <fmtlsplt.hxx>
45 #include <frmatr.hxx>
46 #include <charatr.hxx>
47 #include <cellfrm.hxx>
48 #include <pagefrm.hxx>
49 #include <tabcol.hxx>
50 #include <doc.hxx>
51 #include <IDocumentUndoRedo.hxx>
52 #include <UndoManager.hxx>
53 #include <cntfrm.hxx>
54 #include <pam.hxx>
55 #include <swcrsr.hxx>
56 #include <viscrs.hxx>
57 #include <swtable.hxx>
58 #include <ndtxt.hxx>
59 #include <swundo.hxx>
60 #include <tblsel.hxx>
61 #include <fldbas.hxx>
62 #include <poolfmt.hxx>
63 #include <tabfrm.hxx>
64 #include <UndoCore.hxx>
65 #include <UndoRedline.hxx>
66 #include <UndoDelete.hxx>
67 #include <UndoTable.hxx>
68 #include <hints.hxx>
69 #include <tblafmt.hxx>
70 #include <swcache.hxx>
71 #include <ddefld.hxx>
72 #include <frminf.hxx>
73 #include <cellatr.hxx>
74 #include <swtblfmt.hxx>
75 #include <swddetbl.hxx>
76 #include <mvsave.hxx>
77 #include <docary.hxx>
78 #include <redline.hxx>
79 #include <rolbck.hxx>
80 #include <tblrwcl.hxx>
81 #include <editsh.hxx>
82 #include <txtfrm.hxx>
83 #include <ftnfrm.hxx>
84 #include <section.hxx>
85 #include <frmtool.hxx>
86 #include <node2lay.hxx>
87 #include <comcore.hrc>
88 #include "docsh.hxx"
89 #include <tabcol.hxx>
90 #include <unochart.hxx>
91 #include <node.hxx>
92 #include <ndtxt.hxx>
93 #include <map>
94 #include <algorithm>
95 #include <rootfrm.hxx>
96 #include <fldupde.hxx>
97 #include <switerator.hxx>
98 
99 #ifndef DBG_UTIL
100 #define CHECK_TABLE(t)
101 #else
102 #ifdef DEBUG
103 #define CHECK_TABLE(t) (t).CheckConsistency();
104 #else
105 #define CHECK_TABLE(t)
106 #endif
107 #endif
108 
109 
110 using namespace ::com::sun::star;
111 
112 // #i17764# delete table redlines when modifying the table structure?
113 // #define DEL_TABLE_REDLINES 1
114 
115 const sal_Unicode T2T_PARA = 0x0a;
116 
117 extern void ClearFEShellTabCols();
118 
119 // steht im gctable.cxx
120 extern sal_Bool lcl_GC_Line_Border( const SwTableLine*& , void* pPara );
121 
122 #ifdef DEL_TABLE_REDLINES
123 class lcl_DelRedlines
124 {
125     SwDoc* pDoc;
126 public:
127     lcl_DelRedlines( const SwTableNode& rNd, sal_Bool bCheckForOwnRedline );
128     lcl_DelRedlines( SwPaM& rPam );
129 
130     ~lcl_DelRedlines() { pDoc->EndUndo(UNDO_EMPTY, NULL); }
131 };
132 
133 lcl_DelRedlines::lcl_DelRedlines( SwPaM & rPam) : pDoc( rPam.GetDoc() )
134 {
135     pDoc->GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
136     if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
137         pDoc->AcceptRedline( rPam, true );
138 }
139 #endif
140 
141 void lcl_SetDfltBoxAttr( SwFrmFmt& rFmt, sal_uInt8 nId )
142 {
143     sal_Bool bTop = sal_False, bBottom = sal_False, bLeft = sal_False, bRight = sal_False;
144     switch ( nId )
145     {
146     case 0: bTop = bBottom = bLeft = sal_True;          break;
147     case 1: bTop = bBottom = bLeft = bRight = sal_True; break;
148     case 2: bBottom = bLeft = sal_True;                 break;
149     case 3: bBottom = bLeft = bRight = sal_True;        break;
150     }
151 
152     const sal_Bool bHTML = rFmt.getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE);
153     Color aCol( bHTML ? COL_GRAY : COL_BLACK );
154     SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 );
155     if ( bHTML )
156     {
157         aLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT );
158         aLine.SetInWidth ( DEF_DOUBLE_LINE7_IN  );
159         aLine.SetDistance( DEF_DOUBLE_LINE7_DIST);
160     }
161     SvxBoxItem aBox(RES_BOX); aBox.SetDistance( 55 );
162     if ( bTop )
163         aBox.SetLine( &aLine, BOX_LINE_TOP );
164     if ( bBottom )
165         aBox.SetLine( &aLine, BOX_LINE_BOTTOM );
166     if ( bLeft )
167         aBox.SetLine( &aLine, BOX_LINE_LEFT );
168     if ( bRight )
169         aBox.SetLine( &aLine, BOX_LINE_RIGHT );
170     rFmt.SetFmtAttr( aBox );
171 }
172 
173 void lcl_SetDfltBoxAttr( SwTableBox& rBox, SvPtrarr &rBoxFmtArr, sal_uInt8 nId,
174                             const SwTableAutoFmt* pAutoFmt = 0 )
175 {
176     SvPtrarr* pArr = (SvPtrarr*)rBoxFmtArr[ nId ];
177     if( !pArr )
178     {
179         pArr = new SvPtrarr;
180         rBoxFmtArr.Replace( pArr, nId );
181     }
182 
183     SwTableBoxFmt* pNewBoxFmt = 0;
184     SwFrmFmt* pBoxFmt = rBox.GetFrmFmt();
185     for( sal_uInt16 n = 0; n < pArr->Count(); n += 2 )
186         if( pArr->GetObject( n ) == pBoxFmt )
187         {
188             pNewBoxFmt = (SwTableBoxFmt*)pArr->GetObject( n + 1 );
189             break;
190         }
191 
192     if( !pNewBoxFmt )
193     {
194         SwDoc* pDoc = pBoxFmt->GetDoc();
195         // das Format ist also nicht vorhanden, also neu erzeugen
196         pNewBoxFmt = pDoc->MakeTableBoxFmt();
197         pNewBoxFmt->SetFmtAttr( pBoxFmt->GetAttrSet().Get( RES_FRM_SIZE ) );
198 
199         if( pAutoFmt )
200             pAutoFmt->UpdateToSet( nId, (SfxItemSet&)pNewBoxFmt->GetAttrSet(),
201                                     SwTableAutoFmt::UPDATE_BOX,
202                                     pDoc->GetNumberFormatter( sal_True ) );
203         else
204             ::lcl_SetDfltBoxAttr( *pNewBoxFmt, nId );
205 
206         void* p = pBoxFmt;
207         pArr->Insert( p, pArr->Count() );
208         p = pNewBoxFmt;
209         pArr->Insert( p, pArr->Count() );
210     }
211     rBox.ChgFrmFmt( pNewBoxFmt );
212 }
213 
214 SwTableBoxFmt *lcl_CreateDfltBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
215                                     sal_uInt16 nCols, sal_uInt8 nId )
216 {
217     if ( !rBoxFmtArr[nId] )
218     {
219         SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
220         if( USHRT_MAX != nCols )
221             pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
222                                             USHRT_MAX / nCols, 0 ));
223         ::lcl_SetDfltBoxAttr( *pBoxFmt, nId );
224         rBoxFmtArr.Replace( pBoxFmt, nId );
225     }
226     return (SwTableBoxFmt*)rBoxFmtArr[nId];
227 }
228 
229 SwTableBoxFmt *lcl_CreateAFmtBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
230                                     const SwTableAutoFmt& rAutoFmt,
231                                     sal_uInt16 nCols, sal_uInt8 nId )
232 {
233     if( !rBoxFmtArr[nId] )
234     {
235         SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
236         rAutoFmt.UpdateToSet( nId, (SfxItemSet&)pBoxFmt->GetAttrSet(),
237                                 SwTableAutoFmt::UPDATE_BOX,
238                                 rDoc.GetNumberFormatter( sal_True ) );
239         if( USHRT_MAX != nCols )
240             pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
241                                             USHRT_MAX / nCols, 0 ));
242         rBoxFmtArr.Replace( pBoxFmt, nId );
243     }
244     return (SwTableBoxFmt*)rBoxFmtArr[nId];
245 }
246 
247 SwTableNode* SwDoc::IsIdxInTbl(const SwNodeIndex& rIdx)
248 {
249     SwTableNode* pTableNd = 0;
250     sal_uLong nIndex = rIdx.GetIndex();
251     do {
252         SwNode* pNd = (SwNode*)GetNodes()[ nIndex ]->StartOfSectionNode();
253         if( 0 != ( pTableNd = pNd->GetTableNode() ) )
254             break;
255 
256         nIndex = pNd->GetIndex();
257     } while ( nIndex );
258     return pTableNd;
259 }
260 
261 
262 // --------------- einfuegen einer neuen Box --------------
263 
264     // fuege in der Line, vor der InsPos eine neue Box ein.
265 
266 sal_Bool SwNodes::InsBoxen( SwTableNode* pTblNd,
267                         SwTableLine* pLine,
268                         SwTableBoxFmt* pBoxFmt,
269                         SwTxtFmtColl* pTxtColl,
270                         const SfxItemSet* pAutoAttr,
271                         sal_uInt16 nInsPos,
272                         sal_uInt16 nCnt )
273 {
274     if( !nCnt )
275         return sal_False;
276     ASSERT( pLine, "keine gueltige Zeile" );
277 
278     // Index hinter die letzte Box der Line
279     sal_uLong nIdxPos = 0;
280     SwTableBox *pPrvBox = 0, *pNxtBox = 0;
281     if( pLine->GetTabBoxes().Count() )
282     {
283         if( nInsPos < pLine->GetTabBoxes().Count() )
284         {
285             if( 0 == (pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable(),
286                             pLine->GetTabBoxes()[ nInsPos ] )))
287                 pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
288         }
289         else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable(),
290                             pLine->GetTabBoxes()[ nInsPos-1 ] )))
291                 pNxtBox = pLine->FindNextBox( pTblNd->GetTable() );
292     }
293     else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable() )))
294         pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
295 
296     if( !pPrvBox && !pNxtBox )
297     {
298         sal_Bool bSetIdxPos = sal_True;
299         if( pTblNd->GetTable().GetTabLines().Count() && !nInsPos )
300         {
301             const SwTableLine* pTblLn = pLine;
302             while( pTblLn->GetUpper() )
303                 pTblLn = pTblLn->GetUpper()->GetUpper();
304 
305             if( pTblNd->GetTable().GetTabLines()[ 0 ] == pTblLn )
306             {
307                 // also vor die erste Box der Tabelle
308                 while( ( pNxtBox = pLine->GetTabBoxes()[0])->GetTabLines().Count() )
309                     pLine = pNxtBox->GetTabLines()[0];
310                 nIdxPos = pNxtBox->GetSttIdx();
311                 bSetIdxPos = sal_False;
312             }
313         }
314         if( bSetIdxPos )
315             // Tabelle ohne irgendeinen Inhalt oder am Ende, also vors Ende
316             nIdxPos = pTblNd->EndOfSectionIndex();
317     }
318     else if( pNxtBox )          // es gibt einen Nachfolger
319         nIdxPos = pNxtBox->GetSttIdx();
320     else                        // es gibt einen Vorgaenger
321         nIdxPos = pPrvBox->GetSttNd()->EndOfSectionIndex() + 1;
322 
323     SwNodeIndex aEndIdx( *this, nIdxPos );
324     for( sal_uInt16 n = 0; n < nCnt; ++n )
325     {
326         SwStartNode* pSttNd = new SwStartNode( aEndIdx, ND_STARTNODE,
327                                                 SwTableBoxStartNode );
328         pSttNd->pStartOfSection = pTblNd;
329         new SwEndNode( aEndIdx, *pSttNd );
330 
331         pPrvBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
332 
333         SwTableBoxes & rTabBoxes = pLine->GetTabBoxes();
334         sal_uInt16 nRealInsPos = nInsPos + n;
335         if (nRealInsPos > rTabBoxes.Count())
336             nRealInsPos = rTabBoxes.Count();
337 
338         rTabBoxes.C40_INSERT( SwTableBox, pPrvBox, nRealInsPos );
339 
340         //if( NO_NUMBERING == pTxtColl->GetOutlineLevel()//#outline level,zhaojianwei
341         if( ! pTxtColl->IsAssignedToListLevelOfOutlineStyle()//<-end,zhaojianwei
342 //FEATURE::CONDCOLL
343             && RES_CONDTXTFMTCOLL != pTxtColl->Which()
344 //FEATURE::CONDCOLL
345         )
346             new SwTxtNode( SwNodeIndex( *pSttNd->EndOfSectionNode() ),
347                                 pTxtColl, pAutoAttr );
348         else
349         {
350             // Outline-Numerierung richtig behandeln !!!
351             SwTxtNode* pTNd = new SwTxtNode(
352                             SwNodeIndex( *pSttNd->EndOfSectionNode() ),
353                             (SwTxtFmtColl*)GetDoc()->GetDfltTxtFmtColl(),
354                             pAutoAttr );
355             pTNd->ChgFmtColl( pTxtColl );
356         }
357     }
358     return sal_True;
359 }
360 
361 // --------------- einfuegen einer neuen Tabelle --------------
362 
363 const SwTable* SwDoc::InsertTable( const SwInsertTableOptions& rInsTblOpts,
364                                    const SwPosition& rPos, sal_uInt16 nRows,
365                                    sal_uInt16 nCols, sal_Int16 eAdjust,
366                                    const SwTableAutoFmt* pTAFmt,
367                                    const SvUShorts* pColArr,
368                                    sal_Bool bCalledFromShell,
369                                    sal_Bool bNewModel )
370 {
371     ASSERT( nRows, "Tabelle ohne Zeile?" );
372     ASSERT( nCols, "Tabelle ohne Spalten?" );
373 
374     {
375         // nicht in Fussnoten kopieren !!
376         if( rPos.nNode < GetNodes().GetEndOfInserts().GetIndex() &&
377             rPos.nNode >= GetNodes().GetEndOfInserts().StartOfSectionIndex() )
378             return 0;
379 
380         // sollte das ColumnArray die falsche Anzahl haben wird es ignoriert!
381         if( pColArr &&
382             (nCols + ( text::HoriOrientation::NONE == eAdjust ? 2 : 1 )) != pColArr->Count() )
383             pColArr = 0;
384     }
385 
386     String aTblName = GetUniqueTblName();
387 
388     if( GetIDocumentUndoRedo().DoesUndo() )
389     {
390         GetIDocumentUndoRedo().AppendUndo(
391             new SwUndoInsTbl( rPos, nCols, nRows, static_cast<sal_uInt16>(eAdjust),
392                                       rInsTblOpts, pTAFmt, pColArr,
393                                       aTblName));
394     }
395 
396     // fuege erstmal die Nodes ein
397     // hole das Auto-Format fuer die Tabelle
398     SwTxtFmtColl *pBodyColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE ),
399                  *pHeadColl = pBodyColl;
400 
401     sal_Bool bDfltBorders = 0 != ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER );
402 
403     if( (rInsTblOpts.mnInsMode & tabopts::HEADLINE) && (1 != nRows || !bDfltBorders) )
404         pHeadColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN );
405 
406     const sal_uInt16 nRowsToRepeat =
407             tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
408             rInsTblOpts.mnRowsToRepeat :
409             0;
410 
411     /* #106283# Save content node to extract FRAMEDIR from. */
412     const SwCntntNode * pCntntNd = rPos.nNode.GetNode().GetCntntNode();
413 
414     /* #109161# If we are called from a shell pass the attrset from
415         pCntntNd (aka the node the table is inserted at) thus causing
416         SwNodes::InsertTable to propagate an adjust item if
417         necessary. */
418     SwTableNode *pTblNd = GetNodes().InsertTable(
419         rPos.nNode,
420         nCols,
421         pBodyColl,
422         nRows,
423         nRowsToRepeat,
424         pHeadColl,
425         bCalledFromShell ? &pCntntNd->GetSwAttrSet() : 0 );
426 
427     // dann erstelle die Box/Line/Table-Struktur
428     SwTableLineFmt* pLineFmt = MakeTableLineFmt();
429     SwTableFmt* pTableFmt = MakeTblFrmFmt( aTblName, GetDfltFrmFmt() );
430 
431     /* #106283# If the node to insert the table at is a context node and has a
432        non-default FRAMEDIR propagate it to the table. */
433     if (pCntntNd)
434     {
435         const SwAttrSet & aNdSet = pCntntNd->GetSwAttrSet();
436         const SfxPoolItem *pItem = NULL;
437 
438         if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
439             && pItem != NULL)
440         {
441             pTableFmt->SetFmtAttr( *pItem );
442         }
443     }
444 
445     //Orientation am Fmt der Table setzen
446     pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
447     // alle Zeilen haben die Fill-Order von links nach rechts !
448     pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
449 
450     // die Tabelle bekommt USHRT_MAX als default SSize
451     SwTwips nWidth = USHRT_MAX;
452     if( pColArr )
453     {
454         sal_uInt16 nSttPos = (*pColArr)[ 0 ];
455         sal_uInt16 nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-1)];
456         if( text::HoriOrientation::NONE == eAdjust )
457         {
458             sal_uInt16 nFrmWidth = nLastPos;
459             nLastPos = (*pColArr)[ sal_uInt16(pColArr->Count()-2)];
460             pTableFmt->SetFmtAttr( SvxLRSpaceItem( nSttPos, nFrmWidth - nLastPos, 0, 0, RES_LR_SPACE ) );
461         }
462         nWidth = nLastPos - nSttPos;
463     }
464     else if( nCols )
465     {
466         nWidth /= nCols;
467         nWidth *= nCols; // to avoid rounding problems
468     }
469     pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
470     if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
471         pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False ));
472 
473     // verschiebe ggfs. die harten PageDesc/PageBreak Attribute:
474     SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]
475                             ->GetCntntNode();
476     if( pNextNd && pNextNd->HasSwAttrSet() )
477     {
478         const SfxItemSet* pNdSet = pNextNd->GetpSwAttrSet();
479         const SfxPoolItem *pItem;
480         if( SFX_ITEM_SET == pNdSet->GetItemState( RES_PAGEDESC, sal_False,
481             &pItem ) )
482         {
483             pTableFmt->SetFmtAttr( *pItem );
484             pNextNd->ResetAttr( RES_PAGEDESC );
485             pNdSet = pNextNd->GetpSwAttrSet();
486         }
487         if( pNdSet && SFX_ITEM_SET == pNdSet->GetItemState( RES_BREAK, sal_False,
488              &pItem ) )
489         {
490             pTableFmt->SetFmtAttr( *pItem );
491             pNextNd->ResetAttr( RES_BREAK );
492         }
493     }
494 
495     SwTable * pNdTbl = &pTblNd->GetTable();
496     pNdTbl->RegisterToFormat( *pTableFmt );
497 
498     pNdTbl->SetRowsToRepeat( nRowsToRepeat );
499     pNdTbl->SetTableModel( bNewModel );
500 
501     SvPtrarr aBoxFmtArr( 0, 16 );
502     SwTableBoxFmt* pBoxFmt = 0;
503     if( !bDfltBorders && !pTAFmt )
504     {
505         pBoxFmt = MakeTableBoxFmt();
506         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nCols, 0 ));
507     }
508     else
509     {
510         const sal_uInt16 nBoxArrLen = pTAFmt ? 16 : 4;
511         for( sal_uInt16 i = 0; i < nBoxArrLen; ++i )
512             aBoxFmtArr.Insert( (void*)0, i );
513     }
514     // --> OD 2008-02-25 #refactorlists#
515 //    SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
516     SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
517     // <--
518 
519     SwNodeIndex aNdIdx( *pTblNd, 1 );   // auf den ersten Box-StartNode
520     SwTableLines& rLines = pNdTbl->GetTabLines();
521     for( sal_uInt16 n = 0; n < nRows; ++n )
522     {
523         SwTableLine* pLine = new SwTableLine( pLineFmt, nCols, 0 );
524         rLines.C40_INSERT( SwTableLine, pLine, n );
525         SwTableBoxes& rBoxes = pLine->GetTabBoxes();
526         for( sal_uInt16 i = 0; i < nCols; ++i )
527         {
528             SwTableBoxFmt *pBoxF;
529             if( pTAFmt )
530             {
531                 sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows )
532                                         ? 12 : (4 * (1 + ((n-1) & 1 )))));
533                 nId = nId + static_cast<sal_uInt8>( !i ? 0 :
534                             ( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
535                 pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr, *pTAFmt,
536                                                 nCols, nId );
537 
538                 // ggfs. noch die Absatz/ZeichenAttribute setzen
539                 if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
540                 {
541                     aCharSet.ClearItem();
542                     pTAFmt->UpdateToSet( nId, aCharSet,
543                                         SwTableAutoFmt::UPDATE_CHAR, 0 );
544                     if( aCharSet.Count() )
545                         GetNodes()[ aNdIdx.GetIndex()+1 ]->GetCntntNode()->
546                             SetAttr( aCharSet );
547                 }
548             }
549             else if( bDfltBorders )
550             {
551                 sal_uInt8 nBoxId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
552                 pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr, nCols, nBoxId);
553             }
554             else
555                 pBoxF = pBoxFmt;
556 
557             // fuer AutoFormat bei der Eingabe: beim Einfuegen der Tabelle
558             // werden gleich die Spalten gesetzt. Im Array stehen die
559             // Positionen der Spalten!! (nicht deren Breite!)
560             if( pColArr )
561             {
562                 nWidth = (*pColArr)[ sal_uInt16(i + 1) ] - (*pColArr)[ i ];
563                 if( pBoxF->GetFrmSize().GetWidth() != nWidth )
564                 {
565                     if( pBoxF->GetDepends() )       // neues Format erzeugen!
566                     {
567                         SwTableBoxFmt *pNewFmt = MakeTableBoxFmt();
568                         *pNewFmt = *pBoxF;
569                         pBoxF = pNewFmt;
570                     }
571                     pBoxF->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
572                 }
573             }
574 
575             SwTableBox *pBox = new SwTableBox( pBoxF, aNdIdx, pLine);
576             rBoxes.C40_INSERT( SwTableBox, pBox, i );
577             aNdIdx += 3;        // StartNode, TextNode, EndNode  == 3 Nodes
578         }
579     }
580     // und Frms einfuegen.
581     GetNodes().GoNext( &aNdIdx );      // zum naechsten ContentNode
582     pTblNd->MakeFrms( &aNdIdx );
583 
584     if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() ))
585     {
586         SwPaM aPam( *pTblNd->EndOfSectionNode(), *pTblNd, 1 );
587         if( IsRedlineOn() )
588             AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
589         else
590             SplitRedline( aPam );
591     }
592 
593     SetModified();
594     CHECK_TABLE( *pNdTbl );
595     return pNdTbl;
596 }
597 
598 SwTableNode* SwNodes::InsertTable( const SwNodeIndex& rNdIdx,
599                                    sal_uInt16 nBoxes,
600                                    SwTxtFmtColl* pCntntTxtColl,
601                                    sal_uInt16 nLines,
602                                    sal_uInt16 nRepeat,
603                                    SwTxtFmtColl* pHeadlineTxtColl,
604                                    const SwAttrSet * pAttrSet)
605 {
606     if( !nBoxes )
607         return 0;
608 
609     // wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen
610     if( !pHeadlineTxtColl || !nLines )
611         pHeadlineTxtColl = pCntntTxtColl;
612 
613     SwTableNode * pTblNd = new SwTableNode( rNdIdx );
614     SwEndNode* pEndNd = new SwEndNode( rNdIdx, *pTblNd );
615 
616     if( !nLines )       // fuer die FOR-Schleife
617         ++nLines;
618 
619     SwNodeIndex aIdx( *pEndNd );
620     SwTxtFmtColl* pTxtColl = pHeadlineTxtColl;
621     for( sal_uInt16 nL = 0; nL < nLines; ++nL )
622     {
623         for( sal_uInt16 nB = 0; nB < nBoxes; ++nB )
624         {
625             SwStartNode* pSttNd = new SwStartNode( aIdx, ND_STARTNODE,
626                                                     SwTableBoxStartNode );
627             pSttNd->pStartOfSection = pTblNd;
628 
629             SwTxtNode * pTmpNd = new SwTxtNode( aIdx, pTxtColl );
630 
631             // --> FME 2006-04-13 #i60422# Propagate some more attributes.
632             // Adjustment was done for #109161#
633             const SfxPoolItem* pItem = NULL;
634             if ( NULL != pAttrSet )
635             {
636                 static const sal_uInt16 aPropagateItems[] = {
637                     RES_PARATR_ADJUST,
638                     RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
639                     RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE,
640                     RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE, 0 };
641 
642                 const sal_uInt16* pIdx = aPropagateItems;
643                 while ( *pIdx != 0 )
644                 {
645                     if ( SFX_ITEM_SET != pTmpNd->GetSwAttrSet().GetItemState( *pIdx ) &&
646                          SFX_ITEM_SET == pAttrSet->GetItemState( *pIdx, sal_True, &pItem ) )
647                         static_cast<SwCntntNode *>(pTmpNd)->SetAttr(*pItem);
648                     ++pIdx;
649                 }
650             }
651             // <--
652 
653             new SwEndNode( aIdx, *pSttNd );
654         }
655         if ( nL + 1 >= nRepeat )
656             pTxtColl = pCntntTxtColl;
657     }
658     return pTblNd;
659 }
660 
661 
662 //---------------- Text -> Tabelle -----------------------
663 
664 const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTblOpts,
665                                    const SwPaM& rRange, sal_Unicode cCh,
666                                    sal_Int16 eAdjust,
667                                    const SwTableAutoFmt* pTAFmt )
668 {
669     // pruefe ob in der Selection eine Tabelle liegt
670     const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
671     {
672         sal_uLong nCnt = pStt->nNode.GetIndex();
673         for( ; nCnt <= pEnd->nNode.GetIndex(); ++nCnt )
674             if( !GetNodes()[ nCnt ]->IsTxtNode() )
675                 return 0;
676     }
677 
678     /* #106283# Save first node in the selection if it is a context node. */
679     SwCntntNode * pSttCntntNd = pStt->nNode.GetNode().GetCntntNode();
680 
681     SwPaM aOriginal( *pStt, *pEnd );
682     pStt = aOriginal.GetMark();
683     pEnd = aOriginal.GetPoint();
684 
685 #ifdef DEL_TABLE_REDLINES
686     lcl_DelRedlines aDelRedl( aOriginal );
687 #endif
688 
689     SwUndoTxtToTbl* pUndo = 0;
690     if( GetIDocumentUndoRedo().DoesUndo() )
691     {
692         GetIDocumentUndoRedo().StartUndo( UNDO_TEXTTOTABLE, NULL );
693         pUndo = new SwUndoTxtToTbl( aOriginal, rInsTblOpts, cCh,
694                     static_cast<sal_uInt16>(eAdjust), pTAFmt );
695         GetIDocumentUndoRedo().AppendUndo( pUndo );
696 
697         // das Splitten vom TextNode nicht in die Undohistory aufnehmen
698         GetIDocumentUndoRedo().DoUndo( false );
699     }
700 
701     ::PaMCorrAbs( aOriginal, *pEnd );
702 
703     // sorge dafuer, das der Bereich auf Node-Grenzen liegt
704     SwNodeRange aRg( pStt->nNode, pEnd->nNode );
705     if( pStt->nContent.GetIndex() )
706         SplitNode( *pStt, false );
707 
708     sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex();
709     // nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
710     if( bEndCntnt )
711     {
712         if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
713             || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
714         {
715             SplitNode( *pEnd, false );
716             ((SwNodeIndex&)pEnd->nNode)--;
717             ((SwIndex&)pEnd->nContent).Assign(
718                                 pEnd->nNode.GetNode().GetCntntNode(), 0 );
719             // ein Node und am Ende ??
720             if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
721                 aRg.aStart--;
722         }
723         else
724             aRg.aEnd++;
725     }
726 
727 
728     if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
729     {
730         ASSERT( sal_False, "Kein Bereich" );
731         aRg.aEnd++;
732     }
733 
734     // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
735     SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
736 
737     GetIDocumentUndoRedo().DoUndo( 0 != pUndo );
738 
739     // dann erstelle die Box/Line/Table-Struktur
740     SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
741     SwTableLineFmt* pLineFmt = MakeTableLineFmt();
742     SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
743 
744     // alle Zeilen haben die Fill-Order von links nach rechts !
745     pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
746     // die Tabelle bekommt USHRT_MAX als default SSize
747     pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
748     if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
749         pTableFmt->SetFmtAttr( SwFmtLayoutSplit( sal_False ));
750 
751     /* #106283# If the first node in the selection is a context node and if it
752        has an item FRAMEDIR set (no default) propagate the item to the
753        replacing table. */
754     if (pSttCntntNd)
755     {
756         const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
757         const SfxPoolItem *pItem = NULL;
758 
759         if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
760             && pItem != NULL)
761         {
762             pTableFmt->SetFmtAttr( *pItem );
763         }
764     }
765 
766     SwTableNode* pTblNd = GetNodes().TextToTable(
767             aRg, cCh, pTableFmt, pLineFmt, pBoxFmt,
768             GetTxtCollFromPool( RES_POOLCOLL_STANDARD ), pUndo );
769 
770     SwTable * pNdTbl = &pTblNd->GetTable();
771     ASSERT( pNdTbl, "kein Tabellen-Node angelegt."  )
772 
773     const sal_uInt16 nRowsToRepeat =
774             tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
775             rInsTblOpts.mnRowsToRepeat :
776             0;
777     pNdTbl->SetRowsToRepeat( nRowsToRepeat );
778 
779     sal_Bool bUseBoxFmt = sal_False;
780     if( !pBoxFmt->GetDepends() )
781     {
782         // die Formate an den Boxen haben schon die richtige Size, es darf
783         // also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
784         bUseBoxFmt = sal_True;
785         pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
786         delete pBoxFmt;
787         eAdjust = text::HoriOrientation::NONE;
788     }
789 
790     //Orientation am Fmt der Table setzen
791     pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
792     pNdTbl->RegisterToFormat( *pTableFmt );
793 
794     if( pTAFmt || ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER) )
795     {
796         sal_uInt8 nBoxArrLen = pTAFmt ? 16 : 4;
797         SvPtrarr aBoxFmtArr( nBoxArrLen, 0 );
798         {
799             for( sal_uInt8 i = 0; i < nBoxArrLen; ++i )
800                 aBoxFmtArr.Insert( (void*)0, i );
801         }
802 
803         // --> OD 2008-02-25 #refactorlists#
804 //        SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
805         SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
806         // <--
807         SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
808 
809         SwTableBoxFmt *pBoxF = 0;
810         SwTableLines& rLines = pNdTbl->GetTabLines();
811         sal_uInt16 nRows = rLines.Count();
812         for( sal_uInt16 n = 0; n < nRows; ++n )
813         {
814             SwTableBoxes& rBoxes = rLines[ n ]->GetTabBoxes();
815             sal_uInt16 nCols = rBoxes.Count();
816             for( sal_uInt16 i = 0; i < nCols; ++i )
817             {
818                 SwTableBox* pBox = rBoxes[ i ];
819                 sal_Bool bChgSz = sal_False;
820 
821                 if( pTAFmt )
822                 {
823                     sal_uInt8 nId = static_cast<sal_uInt8>(!n ? 0 : (( n+1 == nRows )
824                                             ? 12 : (4 * (1 + ((n-1) & 1 )))));
825                     nId = nId + static_cast<sal_uInt8>(!i ? 0 :
826                                 ( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
827                     if( bUseBoxFmt )
828                         ::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId, pTAFmt );
829                     else
830                     {
831                         bChgSz = 0 == aBoxFmtArr[ nId ];
832                         pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr,
833                                                 *pTAFmt, USHRT_MAX, nId );
834                     }
835 
836                     // ggfs. noch die Absatz/ZeichenAttribute setzen
837                     if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
838                     {
839                         aCharSet.ClearItem();
840                         pTAFmt->UpdateToSet( nId, aCharSet,
841                                             SwTableAutoFmt::UPDATE_CHAR, 0 );
842                         if( aCharSet.Count() )
843                         {
844                             sal_uLong nSttNd = pBox->GetSttIdx()+1;
845                             sal_uLong nEndNd = pBox->GetSttNd()->EndOfSectionIndex();
846                             for( ; nSttNd < nEndNd; ++nSttNd )
847                             {
848                                 SwCntntNode* pNd = GetNodes()[ nSttNd ]->GetCntntNode();
849                                 if( pNd )
850                                 {
851                                     if( pHistory )
852                                     {
853                                         SwRegHistory aReg( pNd, *pNd, pHistory );
854                                         pNd->SetAttr( aCharSet );
855                                     }
856                                     else
857                                         pNd->SetAttr( aCharSet );
858                                 }
859                             }
860                         }
861                     }
862                 }
863                 else
864                 {
865                     sal_uInt8 nId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
866                     if( bUseBoxFmt )
867                         ::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId );
868                     else
869                     {
870                         bChgSz = 0 == aBoxFmtArr[ nId ];
871                         pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr,
872                                                         USHRT_MAX, nId );
873                     }
874                 }
875 
876                 if( !bUseBoxFmt )
877                 {
878                     if( bChgSz )
879                         pBoxF->SetFmtAttr( pBox->GetFrmFmt()->GetFrmSize() );
880                     pBox->ChgFrmFmt( pBoxF );
881                 }
882             }
883         }
884 
885         if( bUseBoxFmt )
886         {
887             for( sal_uInt8 i = 0; i < nBoxArrLen; ++i )
888             {
889                 SvPtrarr* pArr = (SvPtrarr*)aBoxFmtArr[ i ];
890                 delete pArr;
891             }
892         }
893     }
894 
895     // JP 03.04.97: Inhalt der Boxen auf Zahlen abpruefen
896     if( IsInsTblFormatNum() )
897     {
898         for( sal_uInt16 nBoxes = pNdTbl->GetTabSortBoxes().Count(); nBoxes; )
899             ChkBoxNumFmt( *pNdTbl->GetTabSortBoxes()[ --nBoxes ], sal_False );
900     }
901 
902     sal_uLong nIdx = pTblNd->GetIndex();
903     aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
904 
905     {
906         SwPaM& rTmp = (SwPaM&)rRange;   // Point immer an den Anfang
907         rTmp.DeleteMark();
908         rTmp.GetPoint()->nNode = *pTblNd;
909         SwCntntNode* pCNd = GetNodes().GoNext( &rTmp.GetPoint()->nNode );
910         rTmp.GetPoint()->nContent.Assign( pCNd, 0 );
911     }
912 
913     if( pUndo )
914     {
915         GetIDocumentUndoRedo().EndUndo( UNDO_TEXTTOTABLE, NULL );
916     }
917 
918     SetModified();
919     SetFieldsDirty(true, NULL, 0);
920     return pNdTbl;
921 }
922 
923 SwTableNode* SwNodes::TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
924                                     SwTableFmt* pTblFmt,
925                                     SwTableLineFmt* pLineFmt,
926                                     SwTableBoxFmt* pBoxFmt,
927                                     SwTxtFmtColl* pTxtColl,
928                                     SwUndoTxtToTbl* pUndo )
929 {
930     if( rRange.aStart >= rRange.aEnd )
931         return 0;
932 
933     SwTableNode * pTblNd = new SwTableNode( rRange.aStart );
934     new SwEndNode( rRange.aEnd, *pTblNd );
935 
936     SwDoc* pDoc = GetDoc();
937     SvUShorts aPosArr( 0, 16 );
938     SwTable * pTable = &pTblNd->GetTable();
939     SwTableLine* pLine;
940     SwTableBox* pBox;
941     sal_uInt16 nBoxes, nLines, nMaxBoxes = 0;
942 
943     SwNodeIndex aSttIdx( *pTblNd, 1 );
944     SwNodeIndex aEndIdx( rRange.aEnd, -1 );
945     for( nLines = 0, nBoxes = 0;
946         aSttIdx.GetIndex() < aEndIdx.GetIndex();
947         aSttIdx += 2, nLines++, nBoxes = 0 )
948     {
949         SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
950         ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
951 
952         if( !nLines && 0x0b == cCh )
953         {
954             cCh = 0x09;
955 
956             // JP 28.10.96: vom 1. Node die Positionen des Trenners besorgen,
957             //              damit die Boxen entsprechend eingestellt werden
958             SwTxtFrmInfo aFInfo( (SwTxtFrm*)pTxtNd->getLayoutFrm( pTxtNd->GetDoc()->GetCurrentLayout() ) );
959             if( aFInfo.IsOneLine() )        // nur dann sinnvoll!
960             {
961                 const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
962                 for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
963                 {
964                     if( *pTxt == cCh )
965                     {
966                         aPosArr.Insert( static_cast<sal_uInt16>(
967                                         aFInfo.GetCharPos( nChPos+1, sal_False )),
968                                         aPosArr.Count() );
969                     }
970                 }
971 
972                 aPosArr.Insert( /*aFInfo.GetFrm()->Frm().Left() +*/
973                                 static_cast<sal_uInt16>(aFInfo.GetFrm()->IsVertical() ?
974                                 aFInfo.GetFrm()->Prt().Bottom() :
975                                 aFInfo.GetFrm()->Prt().Right()),
976                                 aPosArr.Count() );
977             }
978         }
979 
980         // die alten Frames loeschen, es werden neue erzeugt
981         pTxtNd->DelFrms();
982 
983         // PageBreaks/PageDesc/ColBreak rausschmeissen.
984         const SfxItemSet* pSet = pTxtNd->GetpSwAttrSet();
985         if( pSet )
986         {
987 // das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
988 // erfolgen, denn sonst stehen sie falsch in der History !!!
989 //          SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
990             const SfxPoolItem* pItem;
991             if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) )
992             {
993                 if( !nLines )
994                     pTblFmt->SetFmtAttr( *pItem );
995                 pTxtNd->ResetAttr( RES_BREAK );
996                 pSet = pTxtNd->GetpSwAttrSet();
997             }
998 
999             if( pSet && SFX_ITEM_SET == pSet->GetItemState(
1000                 RES_PAGEDESC, sal_False, &pItem ) &&
1001                 ((SwFmtPageDesc*)pItem)->GetPageDesc() )
1002             {
1003                 if( !nLines )
1004                     pTblFmt->SetFmtAttr( *pItem );
1005                 pTxtNd->ResetAttr( RES_PAGEDESC );
1006             }
1007         }
1008 
1009         // setze den bei allen TextNode in der Tabelle den TableNode
1010         // als StartNode
1011         pTxtNd->pStartOfSection = pTblNd;
1012 
1013         pLine = new SwTableLine( pLineFmt, 1, 0 );
1014         pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
1015 
1016         SwStartNode* pSttNd;
1017         SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
1018 
1019         SvULongs aBkmkArr( 15, 15 );
1020         _SaveCntntIdx( pDoc, aSttIdx.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
1021 
1022         const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
1023 
1024         if( T2T_PARA != cCh )
1025             for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
1026                 if( *pTxt == cCh )
1027                 {
1028                     aCntPos.nContent = nChPos;
1029                     SwCntntNode* pNewNd = pTxtNd->SplitCntntNode( aCntPos );
1030 
1031                     if( aBkmkArr.Count() )
1032                         _RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
1033                                             nChPos + 1 );
1034 
1035                     // Trennzeichen loeschen und SuchString korrigieren
1036                     pTxtNd->EraseText( aCntPos.nContent, 1 );
1037                     pTxt = pTxtNd->GetTxt().GetBuffer();
1038                     nChPos = 0;
1039                     --nChPos, --pTxt;           // for the ++ in the for loop !!!
1040 
1041                     // setze bei allen TextNodes in der Tabelle den TableNode
1042                     // als StartNode
1043                     const SwNodeIndex aTmpIdx( aCntPos.nNode, -1 );
1044                     pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
1045                                                 SwTableBoxStartNode );
1046                     new SwEndNode( aCntPos.nNode, *pSttNd );
1047                     pNewNd->pStartOfSection = pSttNd;
1048 
1049                     // Section der Box zuweisen
1050                     pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
1051                     pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
1052                 }
1053 
1054         // und jetzt den letzten Teil-String
1055         if( aBkmkArr.Count() )
1056             _RestoreCntntIdx( aBkmkArr, *pTxtNd, pTxtNd->GetTxt().Len(),
1057                                 pTxtNd->GetTxt().Len()+1 );
1058 
1059         pSttNd = new SwStartNode( aCntPos.nNode, ND_STARTNODE, SwTableBoxStartNode );
1060         const SwNodeIndex aTmpIdx( aCntPos.nNode, 1 );
1061         new SwEndNode( aTmpIdx, *pSttNd  );
1062         pTxtNd->pStartOfSection = pSttNd;
1063 
1064         pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
1065         pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
1066         if( nMaxBoxes < nBoxes )
1067             nMaxBoxes = nBoxes;
1068     }
1069 
1070     // die Tabelle ausgleichen, leere Sections einfuegen
1071     sal_uInt16 n;
1072 
1073     for( n = 0; n < pTable->GetTabLines().Count(); ++n )
1074     {
1075         SwTableLine* pCurrLine = pTable->GetTabLines()[ n ];
1076         if( nMaxBoxes != ( nBoxes = pCurrLine->GetTabBoxes().Count() ))
1077         {
1078             InsBoxen( pTblNd, pCurrLine, pBoxFmt, pTxtColl, 0,
1079                         nBoxes, nMaxBoxes - nBoxes );
1080 
1081             if( pUndo )
1082                 for( sal_uInt16 i = nBoxes; i < nMaxBoxes; ++i )
1083                     pUndo->AddFillBox( *pCurrLine->GetTabBoxes()[ i ] );
1084 
1085             // fehlen der 1. Line Boxen, dann kann man das Breiten Array
1086             // vergessen!
1087             if( !n )
1088                 aPosArr.Remove( 0, aPosArr.Count() );
1089         }
1090     }
1091 
1092     if( aPosArr.Count() )
1093     {
1094         SwTableLines& rLns = pTable->GetTabLines();
1095         sal_uInt16 nLastPos = 0;
1096         for( n = 0; n < aPosArr.Count(); ++n )
1097         {
1098             SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
1099             pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1100                                                 aPosArr[ n ] - nLastPos ));
1101             for( sal_uInt16 nTmpLine = 0; nTmpLine < rLns.Count(); ++nTmpLine )
1102                 //JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
1103                 //              von der rufenden Methode noch gebraucht wird!
1104                 pNewFmt->Add( rLns[ nTmpLine ]->GetTabBoxes()[ n ] );
1105 
1106             nLastPos = aPosArr[ n ];
1107         }
1108 
1109         // damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
1110         // Groesse nach "oben" transportieren.
1111         ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
1112         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
1113     }
1114     else
1115         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
1116 
1117     // das wars doch wohl ??
1118     return pTblNd;
1119 }
1120 /*-- 18.05.2006 10:30:29---------------------------------------------------
1121 
1122   -----------------------------------------------------------------------*/
1123 const SwTable* SwDoc::TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes )
1124 {
1125     /* #106283# Save first node in the selection if it is a content node. */
1126     SwCntntNode * pSttCntntNd = rTableNodes.begin()->begin()->aStart.GetNode().GetCntntNode();
1127 
1128     /**debug**/
1129 #if OSL_DEBUG_LEVEL > 1
1130     const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
1131     const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
1132     (void) rStartRange;
1133     (void) rEndRange;
1134 #endif
1135     /**debug**/
1136 
1137     //!!! not necessarily TextNodes !!!
1138     SwPaM aOriginal( rTableNodes.begin()->begin()->aStart, rTableNodes.rbegin()->rbegin()->aEnd );
1139     const SwPosition *pStt = aOriginal.GetMark();
1140     const SwPosition *pEnd = aOriginal.GetPoint();
1141 
1142 #ifdef DEL_TABLE_REDLINES
1143     lcl_DelRedlines aDelRedl( aOriginal );
1144 #endif
1145 
1146 //    SwUndoTxtToTbl* pUndo = 0;
1147     bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
1148     if (bUndo)
1149     {
1150         // das Splitten vom TextNode nicht in die Undohistory aufnehmen
1151         GetIDocumentUndoRedo().DoUndo(false);
1152     }
1153 
1154     ::PaMCorrAbs( aOriginal, *pEnd );
1155 
1156     // sorge dafuer, das der Bereich auf Node-Grenzen liegt
1157     SwNodeRange aRg( pStt->nNode, pEnd->nNode );
1158     if( pStt->nContent.GetIndex() )
1159         SplitNode( *pStt, false );
1160 
1161     sal_Bool bEndCntnt = 0 != pEnd->nContent.GetIndex();
1162     // nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
1163     if( bEndCntnt )
1164     {
1165         if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
1166             || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
1167         {
1168             SplitNode( *pEnd, false );
1169             ((SwNodeIndex&)pEnd->nNode)--;
1170             ((SwIndex&)pEnd->nContent).Assign(
1171                                 pEnd->nNode.GetNode().GetCntntNode(), 0 );
1172             // ein Node und am Ende ??
1173             if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
1174                 aRg.aStart--;
1175         }
1176         else
1177             aRg.aEnd++;
1178     }
1179 
1180 
1181     if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
1182     {
1183         ASSERT( sal_False, "Kein Bereich" );
1184         aRg.aEnd++;
1185     }
1186 
1187     // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
1188     SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
1189 
1190     GetIDocumentUndoRedo().DoUndo(bUndo);
1191 
1192     // dann erstelle die Box/Line/Table-Struktur
1193     SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
1194     SwTableLineFmt* pLineFmt = MakeTableLineFmt();
1195     SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
1196 
1197     // alle Zeilen haben die Fill-Order von links nach rechts !
1198     pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
1199     // die Tabelle bekommt USHRT_MAX als default SSize
1200     pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
1201 
1202     /* #106283# If the first node in the selection is a context node and if it
1203        has an item FRAMEDIR set (no default) propagate the item to the
1204        replacing table. */
1205     if (pSttCntntNd)
1206     {
1207         const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
1208         const SfxPoolItem *pItem = NULL;
1209 
1210         if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, sal_True, &pItem )
1211             && pItem != NULL)
1212         {
1213             pTableFmt->SetFmtAttr( *pItem );
1214         }
1215     }
1216 
1217     SwTableNode* pTblNd = GetNodes().TextToTable(
1218             rTableNodes, pTableFmt, pLineFmt, pBoxFmt,
1219             GetTxtCollFromPool( RES_POOLCOLL_STANDARD )/*, pUndo*/ );
1220 
1221     SwTable * pNdTbl = &pTblNd->GetTable();
1222     ASSERT( pNdTbl, "kein Tabellen-Node angelegt."  )
1223     pNdTbl->RegisterToFormat( *pTableFmt );
1224 
1225     sal_Bool bUseBoxFmt = sal_False;
1226     if( !pBoxFmt->GetDepends() )
1227     {
1228         // die Formate an den Boxen haben schon die richtige Size, es darf
1229         // also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
1230         bUseBoxFmt = sal_True;
1231         pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
1232         delete pBoxFmt;
1233     }
1234 
1235     sal_uLong nIdx = pTblNd->GetIndex();
1236     aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
1237 
1238     SetModified();
1239     SetFieldsDirty( true, NULL, 0 );
1240     return pNdTbl;
1241 }
1242 
1243 SwNodeRange * SwNodes::ExpandRangeForTableBox(const SwNodeRange & rRange)
1244 {
1245     SwNodeRange * pResult = NULL;
1246     bool bChanged = false;
1247 
1248     SwNodeIndex aNewStart = rRange.aStart;
1249     SwNodeIndex aNewEnd = rRange.aEnd;
1250 
1251     SwNodeIndex aEndIndex = rRange.aEnd;
1252     SwNodeIndex aIndex = rRange.aStart;
1253 
1254     while (aIndex < aEndIndex)
1255     {
1256         SwNode& rNode = aIndex.GetNode();
1257 
1258         if (rNode.IsStartNode())
1259         {
1260             // advance aIndex to the end node of this start node
1261             SwNode * pEndNode = rNode.EndOfSectionNode();
1262             aIndex = *pEndNode;
1263 
1264             if (aIndex > aNewEnd)
1265             {
1266                 aNewEnd = aIndex;
1267                 bChanged = true;
1268             }
1269         }
1270         else if (rNode.IsEndNode())
1271         {
1272             SwNode * pStartNode = rNode.StartOfSectionNode();
1273             SwNodeIndex aStartIndex = *pStartNode;
1274 
1275             if (aStartIndex < aNewStart)
1276             {
1277                 aNewStart = aStartIndex;
1278                 bChanged = true;
1279             }
1280         }
1281 
1282         if (aIndex < aEndIndex)
1283             ++aIndex;
1284     }
1285 
1286     SwNode * pNode = &aIndex.GetNode();
1287     while (pNode->IsEndNode())
1288     {
1289         SwNode * pStartNode = pNode->StartOfSectionNode();
1290         SwNodeIndex aStartIndex(*pStartNode);
1291         aNewStart = aStartIndex;
1292         aNewEnd = aIndex;
1293         bChanged = true;
1294 
1295         ++aIndex;
1296         pNode = &aIndex.GetNode();
1297     }
1298 
1299     if (bChanged)
1300         pResult = new SwNodeRange(aNewStart, aNewEnd);
1301 
1302     return pResult;
1303 }
1304 
1305 /*-- 18.05.2006 08:23:28---------------------------------------------------
1306 
1307   -----------------------------------------------------------------------*/
1308 SwTableNode* SwNodes::TextToTable( const SwNodes::TableRanges_t & rTableNodes,
1309                                     SwTableFmt* pTblFmt,
1310                                     SwTableLineFmt* pLineFmt,
1311                                     SwTableBoxFmt* pBoxFmt,
1312                                     SwTxtFmtColl* /*pTxtColl*/  /*, SwUndo... pUndo*/  )
1313 {
1314     if( !rTableNodes.size() )
1315         return 0;
1316 
1317     SwTableNode * pTblNd = new SwTableNode( rTableNodes.begin()->begin()->aStart );
1318     //insert the end node after the last text node
1319    SwNodeIndex aInsertIndex( rTableNodes.rbegin()->rbegin()->aEnd );
1320    ++aInsertIndex;
1321 
1322    //!! owner ship will be transferred in c-tor to SwNodes array.
1323    //!! Thus no real problem here...
1324    new SwEndNode( aInsertIndex, *pTblNd );
1325 
1326 #if OSL_DEBUG_LEVEL > 1
1327     /**debug**/
1328     const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
1329     const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
1330     (void) rStartRange;
1331     (void) rEndRange;
1332     /**debug**/
1333 #endif
1334 
1335     SwDoc* pDoc = GetDoc();
1336     SvUShorts aPosArr( 0, 16 );
1337     SwTable * pTable = &pTblNd->GetTable();
1338     SwTableLine* pLine;
1339     SwTableBox* pBox;
1340     sal_uInt16 nBoxes, nLines, nMaxBoxes = 0;
1341 
1342 //    SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
1343 
1344 
1345     SwNodeIndex aNodeIndex = rTableNodes.begin()->begin()->aStart;
1346     // delete frames of all contained content nodes
1347     for( nLines = 0; aNodeIndex <= rTableNodes.rbegin()->rbegin()->aEnd; ++aNodeIndex,++nLines )
1348     {
1349         SwNode& rNode = aNodeIndex.GetNode();
1350         if( rNode.IsCntntNode() )
1351         {
1352             static_cast<SwCntntNode&>(rNode).DelFrms();
1353             if(rNode.IsTxtNode())
1354             {
1355                 SwTxtNode& rTxtNode = static_cast<SwTxtNode&>(rNode);
1356                 // setze den bei allen TextNode in der Tabelle den TableNode
1357                 // als StartNode
1358 // FIXME: this is setting wrong node StartOfSections in nested tables.
1359 //                rTxtNode.pStartOfSection = pTblNd;
1360                 // remove PageBreaks/PageDesc/ColBreak
1361                 const SwAttrSet* pSet = rTxtNode.GetpSwAttrSet();
1362                 if( pSet )
1363                 {
1364         // das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
1365         // erfolgen, denn sonst stehen sie falsch in der History !!!
1366         //          SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
1367                     const SfxPoolItem* pItem;
1368                     if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pItem ) )
1369                     {
1370                         if( !nLines )
1371                             pTblFmt->SetFmtAttr( *pItem );
1372                         rTxtNode.ResetAttr( RES_BREAK );
1373                         pSet = rTxtNode.GetpSwAttrSet();
1374                     }
1375 
1376                     if( pSet && SFX_ITEM_SET == pSet->GetItemState(
1377                         RES_PAGEDESC, sal_False, &pItem ) &&
1378                         ((SwFmtPageDesc*)pItem)->GetPageDesc() )
1379                     {
1380                         if( !nLines )
1381                             pTblFmt->SetFmtAttr( *pItem );
1382                         rTxtNode.ResetAttr( RES_PAGEDESC );
1383                     }
1384                 }
1385             }
1386         }
1387     }
1388 
1389 //    SwNodeIndex aSttIdx( *pTblNd, 1 );
1390 //    SwNodeIndex aEndIdx( rlNodes.rbegin()->aEnd, -1 );
1391     std::vector<std::vector < SwNodeRange > >::const_iterator aRowIter = rTableNodes.begin();
1392     for( nLines = 0, nBoxes = 0;
1393         aRowIter != rTableNodes.end();
1394         ++aRowIter, /*aSttIdx += 2, */nLines++, nBoxes = 0 )
1395     {
1396 //        SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
1397 //        ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
1398 
1399         pLine = new SwTableLine( pLineFmt, 1, 0 );
1400         pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
1401 
1402 //        SwStartNode* pSttNd;
1403 //        SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
1404 
1405         std::vector< SwNodeRange >::const_iterator aCellIter = aRowIter->begin();
1406 //        SvULongs aBkmkArr( 15, 15 );
1407 //        _SaveCntntIdx( pDoc, aCellIter->aStart.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
1408 //        const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
1409 
1410         for( ; aCellIter != aRowIter->end(); ++aCellIter )
1411         {
1412 //            aCellIter->aStart aCellIter->aEnd
1413 //                aCntPos.nContent = nChPos;
1414 //                SwCntntNode* pNewNd = pTxtNd->SplitNode( aCntPos );
1415 
1416 //        auch f?rs undo?
1417 //                if( aBkmkArr.Count() )
1418 //                    _RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
1419 //                                        nChPos + 1 );
1420 
1421                 const SwNodeIndex aTmpIdx( aCellIter->aStart, 0 );
1422 
1423                SwNodeIndex aCellEndIdx(aCellIter->aEnd);
1424                ++aCellEndIdx;
1425                SwStartNode* pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
1426                                             SwTableBoxStartNode );
1427                 new SwEndNode( aCellEndIdx, *pSttNd );
1428                 //set the start node on all node of the current cell
1429                 SwNodeIndex aCellNodeIdx = aCellIter->aStart;
1430                 for(;aCellNodeIdx <= aCellIter->aEnd; ++aCellNodeIdx )
1431                 {
1432                     aCellNodeIdx.GetNode().pStartOfSection = pSttNd;
1433                     //skip start/end node pairs
1434                     if( aCellNodeIdx.GetNode().IsStartNode() )
1435                         aCellNodeIdx = SwNodeIndex( *aCellNodeIdx.GetNode().EndOfSectionNode() );
1436                 }
1437 
1438                 // Section der Box zuweisen
1439                 pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
1440                 pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
1441         }
1442         if( nMaxBoxes < nBoxes )
1443             nMaxBoxes = nBoxes;
1444     }
1445 
1446     // die Tabelle ausgleichen, leere Sections einfuegen
1447     sal_uInt16 n;
1448 
1449     if( aPosArr.Count() )
1450     {
1451         SwTableLines& rLns = pTable->GetTabLines();
1452         sal_uInt16 nLastPos = 0;
1453         for( n = 0; n < aPosArr.Count(); ++n )
1454         {
1455             SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
1456             pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1457                                                 aPosArr[ n ] - nLastPos ));
1458             for( sal_uInt16 nLines2 = 0; nLines2 < rLns.Count(); ++nLines2 )
1459                 //JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
1460                 //              von der rufenden Methode noch gebraucht wird!
1461                 pNewFmt->Add( rLns[ nLines2 ]->GetTabBoxes()[ n ] );
1462 
1463             nLastPos = aPosArr[ n ];
1464         }
1465 
1466         // damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
1467         // Groesse nach "oben" transportieren.
1468         ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
1469         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
1470     }
1471     else
1472         pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
1473 
1474     // das wars doch wohl ??
1475     return pTblNd;
1476 }
1477 
1478 
1479 //---------------- Tabelle -> Text -----------------------
1480 
1481 
1482 sal_Bool SwDoc::TableToText( const SwTableNode* pTblNd, sal_Unicode cCh )
1483 {
1484     if( !pTblNd )
1485         return sal_False;
1486 
1487     // --> FME 2004-09-28 #i34471#
1488     // If this is trigged by SwUndoTblToTxt::Repeat() nobody ever deleted
1489     // the table cursor.
1490     SwEditShell* pESh = GetEditShell();
1491     if( pESh && pESh->IsTableMode() )
1492         pESh->ClearMark();
1493     // <--
1494 
1495 #ifdef DEL_TABLE_REDLINES
1496     lcl_DelRedlines aDelRedl( *pTblNd, sal_False );
1497 #endif
1498 
1499     SwNodeRange aRg( *pTblNd, 0, *pTblNd->EndOfSectionNode() );
1500     SwUndoTblToTxt* pUndo = 0;
1501     SwNodeRange* pUndoRg = 0;
1502     if (GetIDocumentUndoRedo().DoesUndo())
1503     {
1504         GetIDocumentUndoRedo().ClearRedo();
1505         pUndoRg = new SwNodeRange( aRg.aStart, -1, aRg.aEnd, +1 );
1506         pUndo = new SwUndoTblToTxt( pTblNd->GetTable(), cCh );
1507     }
1508 
1509     SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
1510     aMsgHnt.eFlags = TBL_BOXNAME;
1511     UpdateTblFlds( &aMsgHnt );
1512 
1513     sal_Bool bRet = GetNodes().TableToText( aRg, cCh, pUndo );
1514     if( pUndoRg )
1515     {
1516         pUndoRg->aStart++;
1517         pUndoRg->aEnd--;
1518         pUndo->SetRange( *pUndoRg );
1519         GetIDocumentUndoRedo().AppendUndo(pUndo);
1520         delete pUndoRg;
1521     }
1522 
1523     if( bRet )
1524         SetModified();
1525 
1526     return bRet;
1527 }
1528 
1529 // -- benutze die ForEach Methode vom PtrArray um aus einer Tabelle wieder
1530 //      Text zuerzeugen. (Die Boxen koennen auch noch Lines enthalten !!)
1531 struct _DelTabPara
1532 {
1533     SwTxtNode* pLastNd;
1534     SwNodes& rNds;
1535     SwUndoTblToTxt* pUndo;
1536     sal_Unicode cCh;
1537 
1538     _DelTabPara( SwNodes& rNodes, sal_Unicode cChar, SwUndoTblToTxt* pU ) :
1539         pLastNd(0), rNds( rNodes ), pUndo( pU ), cCh( cChar ) {}
1540     _DelTabPara( const _DelTabPara& rPara ) :
1541         pLastNd(rPara.pLastNd), rNds( rPara.rNds ),
1542         pUndo( rPara.pUndo ), cCh( rPara.cCh ) {}
1543 };
1544 
1545 // forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
1546 // koennen.
1547 sal_Bool lcl_DelBox( const SwTableBox*&, void *pPara );
1548 
1549 sal_Bool lcl_DelLine( const SwTableLine*& rpLine, void* pPara )
1550 {
1551     ASSERT( pPara, "die Parameter fehlen" );
1552     _DelTabPara aPara( *(_DelTabPara*)pPara );
1553     ((SwTableLine*&)rpLine)->GetTabBoxes().ForEach( &lcl_DelBox, &aPara );
1554     if( rpLine->GetUpper() )        // gibt es noch eine uebergeordnete Box ??
1555         // dann gebe den letzten TextNode zurueck
1556         ((_DelTabPara*)pPara)->pLastNd = aPara.pLastNd;
1557     return sal_True;
1558 }
1559 
1560 
1561 sal_Bool lcl_DelBox( const SwTableBox*& rpBox, void* pPara )
1562 {
1563     ASSERT( pPara, "die Parameter fehlen" );
1564 
1565     // loesche erstmal die Lines der Box
1566     _DelTabPara* pDelPara = (_DelTabPara*)pPara;
1567     if( rpBox->GetTabLines().Count() )
1568         ((SwTableBox*&)rpBox)->GetTabLines().ForEach( &lcl_DelLine, pDelPara );
1569     else
1570     {
1571         SwDoc* pDoc = pDelPara->rNds.GetDoc();
1572         SwNodeRange aDelRg( *rpBox->GetSttNd(), 0,
1573                             *rpBox->GetSttNd()->EndOfSectionNode() );
1574         // loesche die Section
1575         pDelPara->rNds.SectionUp( &aDelRg );
1576         const SwTxtNode* pCurTxtNd;
1577         if( T2T_PARA != pDelPara->cCh && pDelPara->pLastNd &&
1578             0 != ( pCurTxtNd = aDelRg.aStart.GetNode().GetTxtNode() ))
1579         {
1580             // Join the current text node with the last from the previous box if possible
1581             sal_uLong nNdIdx = aDelRg.aStart.GetIndex();
1582             aDelRg.aStart--;
1583             if( pDelPara->pLastNd == &aDelRg.aStart.GetNode() )
1584             {
1585                 // Inserting the seperator
1586                 SwIndex aCntIdx( pDelPara->pLastNd, pDelPara->pLastNd->GetTxt().Len());
1587                 pDelPara->pLastNd->InsertText( pDelPara->cCh, aCntIdx,
1588                     IDocumentContentOperations::INS_EMPTYEXPAND );
1589                 if( pDelPara->pUndo )
1590                     pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex(),
1591                                                 aCntIdx.GetIndex() );
1592 
1593                 SvULongs aBkmkArr( 4, 4 );
1594                 xub_StrLen nOldTxtLen = aCntIdx.GetIndex();
1595                 _SaveCntntIdx( pDoc, nNdIdx, pCurTxtNd->GetTxt().Len(),
1596                                 aBkmkArr );
1597 
1598                 pDelPara->pLastNd->JoinNext();
1599 
1600                 if( aBkmkArr.Count() )
1601                     _RestoreCntntIdx( pDoc, aBkmkArr,
1602                                         pDelPara->pLastNd->GetIndex(),
1603                                         nOldTxtLen );
1604             }
1605             else if( pDelPara->pUndo )
1606             {
1607                 aDelRg.aStart++;
1608                 pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex() );
1609             }
1610         }
1611         else if( pDelPara->pUndo )
1612             pDelPara->pUndo->AddBoxPos( *pDoc, aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
1613         aDelRg.aEnd--;
1614         pDelPara->pLastNd = aDelRg.aEnd.GetNode().GetTxtNode();
1615 
1616         //JP 03.04.97: die Ausrichtung der ZahlenFormatierung auf
1617         //              keinen Fall uebernehmen
1618         if( pDelPara->pLastNd && pDelPara->pLastNd->HasSwAttrSet() )
1619             pDelPara->pLastNd->ResetAttr( RES_PARATR_ADJUST );
1620     }
1621     return sal_True;
1622 }
1623 
1624 
1625 sal_Bool SwNodes::TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
1626                             SwUndoTblToTxt* pUndo )
1627 {
1628     // ist eine Tabelle selektiert ?
1629     SwTableNode* pTblNd;
1630     if( rRange.aStart.GetIndex() >= rRange.aEnd.GetIndex() ||
1631         0 == ( pTblNd = rRange.aStart.GetNode().GetTableNode()) ||
1632         &rRange.aEnd.GetNode() != pTblNd->EndOfSectionNode() )
1633         return sal_False;
1634 
1635     // stand die Tabelle ganz alleine in einer Section ?
1636     // dann ueber den Upper der Tabelle die Frames anlegen
1637     SwNode2Layout* pNode2Layout = 0;
1638     SwNodeIndex aFrmIdx( rRange.aStart );
1639     SwNode* pFrmNd = FindPrvNxtFrmNode( aFrmIdx, &rRange.aEnd.GetNode() );
1640     if( !pFrmNd )
1641         // dann sammel mal alle Uppers ein
1642         pNode2Layout = new SwNode2Layout( *pTblNd );
1643 
1644     // loesche schon mal die Frames
1645     pTblNd->DelFrms();
1646 
1647     // dann "loeschen" die Tabellen und fasse alle Lines/Boxen zusammen
1648     _DelTabPara aDelPara( *this, cCh, pUndo );
1649     pTblNd->pTable->GetTabLines().ForEach( &lcl_DelLine, &aDelPara );
1650 
1651     // jetzt ist aus jeder TableLine ein TextNode mit dem entsprechenden
1652     // Trenner erzeugt worden. Es braucht nur noch die Table-Section
1653     // geloescht und fuer die neuen TextNode die Frames erzeugt werden.
1654     SwNodeRange aDelRg( rRange.aStart, rRange.aEnd );
1655 
1656     // JP 14.01.97: hat die Tabelle PageDesc-/Break-Attribute? Dann in den
1657     //              ersten TextNode uebernehmen
1658     {
1659 // was ist mit UNDO???
1660         const SfxItemSet& rTblSet = pTblNd->pTable->GetFrmFmt()->GetAttrSet();
1661         const SfxPoolItem *pBreak, *pDesc;
1662         if( SFX_ITEM_SET != rTblSet.GetItemState( RES_PAGEDESC, sal_False, &pDesc ))
1663             pDesc = 0;
1664         if( SFX_ITEM_SET != rTblSet.GetItemState( RES_BREAK, sal_False, &pBreak ))
1665             pBreak = 0;
1666 
1667         if( pBreak || pDesc )
1668         {
1669             SwNodeIndex aIdx( *pTblNd  );
1670             SwCntntNode* pCNd = GoNext( &aIdx );
1671             if( pBreak )
1672                 pCNd->SetAttr( *pBreak );
1673             if( pDesc )
1674                 pCNd->SetAttr( *pDesc );
1675         }
1676     }
1677 
1678     SectionUp( &aDelRg );       // loesche die Section und damit die Tabelle
1679     // #i28006#
1680     sal_uLong nStt = aDelRg.aStart.GetIndex(), nEnd = aDelRg.aEnd.GetIndex();
1681     if( !pFrmNd )
1682     {
1683         pNode2Layout->RestoreUpperFrms( *this,
1684                         aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
1685         delete pNode2Layout;
1686     }
1687     else
1688     {
1689         SwCntntNode *pCNd;
1690         SwSectionNode *pSNd;
1691         while( aDelRg.aStart.GetIndex() < nEnd )
1692         {
1693             if( 0 != ( pCNd = aDelRg.aStart.GetNode().GetCntntNode()))
1694             {
1695                 if( pFrmNd->IsCntntNode() )
1696                     ((SwCntntNode*)pFrmNd)->MakeFrms( *pCNd );
1697                 else if( pFrmNd->IsTableNode() )
1698                     ((SwTableNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
1699                 else if( pFrmNd->IsSectionNode() )
1700                     ((SwSectionNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
1701                 pFrmNd = pCNd;
1702             }
1703             else if( 0 != ( pSNd = aDelRg.aStart.GetNode().GetSectionNode()))
1704             {
1705                 if( !pSNd->GetSection().IsHidden() && !pSNd->IsCntntHidden() )
1706                 {
1707                     pSNd->MakeFrms( &aFrmIdx, &aDelRg.aEnd );
1708                     pFrmNd = pSNd;
1709                     break;
1710                 }
1711                 aDelRg.aStart = *pSNd->EndOfSectionNode();
1712             }
1713             aDelRg.aStart++;
1714         }
1715     }
1716 
1717     // #i28006# Fly frames have to be restored even if the table was
1718     // #alone in the section
1719     const SwSpzFrmFmts& rFlyArr = *GetDoc()->GetSpzFrmFmts();
1720     for( sal_uInt16 n = 0; n < rFlyArr.Count(); ++n )
1721     {
1722         SwFrmFmt *const pFmt = (SwFrmFmt*)rFlyArr[n];
1723         const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
1724         SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
1725         if (pAPos &&
1726             ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
1727              (FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
1728             nStt <= pAPos->nNode.GetIndex() &&
1729             pAPos->nNode.GetIndex() < nEnd )
1730         {
1731             pFmt->MakeFrms();
1732         }
1733     }
1734 
1735     return sal_True;
1736 }
1737 
1738 
1739 // ----- einfuegen von Spalten/Zeilen ------------------------
1740 
1741 sal_Bool SwDoc::InsertCol( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind )
1742 {
1743     if( !::CheckSplitCells( rCursor, nCnt + 1, nsSwTblSearchType::TBLSEARCH_COL ) )
1744         return sal_False;
1745 
1746     // lasse ueber das Layout die Boxen suchen
1747     SwSelBoxes aBoxes;
1748     ::GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
1749 
1750     sal_Bool bRet = sal_False;
1751     if( aBoxes.Count() )
1752         bRet = InsertCol( aBoxes, nCnt, bBehind );
1753     return bRet;
1754 }
1755 
1756 sal_Bool SwDoc::InsertCol( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind )
1757 {
1758     // uebers SwDoc fuer Undo !!
1759     ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
1760     SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1761     if( !pTblNd )
1762         return sal_False;
1763 
1764     SwTable& rTbl = pTblNd->GetTable();
1765     if( rTbl.ISA( SwDDETable ))
1766         return sal_False;
1767 
1768 #ifdef DEL_TABLE_REDLINES
1769     lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
1770 #endif
1771 
1772     SwTableSortBoxes aTmpLst( 0, 5 );
1773     SwUndoTblNdsChg* pUndo = 0;
1774     if (GetIDocumentUndoRedo().DoesUndo())
1775     {
1776         pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSCOL, rBoxes, *pTblNd,
1777                                      0, 0, nCnt, bBehind, sal_False );
1778         aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
1779     }
1780 
1781     bool bRet(false);
1782     {
1783         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
1784 
1785         SwTableFmlUpdate aMsgHnt( &rTbl );
1786         aMsgHnt.eFlags = TBL_BOXPTR;
1787         UpdateTblFlds( &aMsgHnt );
1788 
1789         bRet = rTbl.InsertCol( this, rBoxes, nCnt, bBehind );
1790         if (bRet)
1791         {
1792             SetModified();
1793             ::ClearFEShellTabCols();
1794             SetFieldsDirty( true, NULL, 0 );
1795         }
1796     }
1797 
1798     if( pUndo )
1799     {
1800         if( bRet )
1801         {
1802             pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
1803             GetIDocumentUndoRedo().AppendUndo( pUndo );
1804         }
1805         else
1806             delete pUndo;
1807     }
1808     return bRet;
1809 }
1810 
1811 sal_Bool SwDoc::InsertRow( const SwCursor& rCursor, sal_uInt16 nCnt, sal_Bool bBehind )
1812 {
1813     // lasse ueber das Layout die Boxen suchen
1814     SwSelBoxes aBoxes;
1815     GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
1816 
1817     sal_Bool bRet = sal_False;
1818     if( aBoxes.Count() )
1819         bRet = InsertRow( aBoxes, nCnt, bBehind );
1820     return bRet;
1821 }
1822 
1823 sal_Bool SwDoc::InsertRow( const SwSelBoxes& rBoxes, sal_uInt16 nCnt, sal_Bool bBehind )
1824 {
1825     // uebers SwDoc fuer Undo !!
1826     ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
1827     SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1828     if( !pTblNd )
1829         return sal_False;
1830 
1831     SwTable& rTbl = pTblNd->GetTable();
1832     if( rTbl.ISA( SwDDETable ))
1833         return sal_False;
1834 
1835 #ifdef DEL_TABLE_REDLINES
1836     lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
1837 #endif
1838 
1839     SwTableSortBoxes aTmpLst( 0, 5 );
1840     SwUndoTblNdsChg* pUndo = 0;
1841     if (GetIDocumentUndoRedo().DoesUndo())
1842     {
1843         pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW,rBoxes, *pTblNd,
1844                                      0, 0, nCnt, bBehind, sal_False );
1845         aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
1846     }
1847 
1848     bool bRet(false);
1849     {
1850         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
1851 
1852         SwTableFmlUpdate aMsgHnt( &rTbl );
1853         aMsgHnt.eFlags = TBL_BOXPTR;
1854         UpdateTblFlds( &aMsgHnt );
1855 
1856         bRet = rTbl.InsertRow( this, rBoxes, nCnt, bBehind );
1857         if (bRet)
1858         {
1859             SetModified();
1860             ::ClearFEShellTabCols();
1861             SetFieldsDirty( true, NULL, 0 );
1862         }
1863     }
1864 
1865     if( pUndo )
1866     {
1867         if( bRet )
1868         {
1869             pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
1870             GetIDocumentUndoRedo().AppendUndo( pUndo );
1871         }
1872         else
1873             delete pUndo;
1874     }
1875     return bRet;
1876 
1877 }
1878 
1879 // ----- loeschen von Spalten/Zeilen ------------------------
1880 
1881 sal_Bool SwDoc::DeleteRow( const SwCursor& rCursor )
1882 {
1883     // lasse ueber das Layout die Boxen suchen
1884     SwSelBoxes aBoxes;
1885     GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
1886     if( ::HasProtectedCells( aBoxes ))
1887         return sal_False;
1888 
1889     // die Crsr aus dem Loeschbereich entfernen.
1890     // Der Cursor steht danach:
1891     //  - es folgt noch eine Zeile, in dieser
1892     //  - vorher steht noch eine Zeile, in dieser
1893     //  - sonst immer dahinter
1894     {
1895         SwTableNode* pTblNd = rCursor.GetNode()->FindTableNode();
1896 
1897         if( pTblNd->GetTable().ISA( SwDDETable ))
1898             return sal_False;
1899 
1900         // suche alle Boxen / Lines
1901         _FndBox aFndBox( 0, 0 );
1902         {
1903             _FndPara aPara( aBoxes, &aFndBox );
1904             pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
1905         }
1906 
1907         if( !aFndBox.GetLines().Count() )
1908             return sal_False;
1909 
1910         SwEditShell* pESh = GetEditShell();
1911         if( pESh )
1912         {
1913             pESh->KillPams();
1914             // JP: eigentlich sollte man ueber alle Shells iterieren!!
1915         }
1916 
1917         _FndBox* pFndBox = &aFndBox;
1918         while( 1 == pFndBox->GetLines().Count() &&
1919                 1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
1920         {
1921             _FndBox* pTmp = pFndBox->GetLines()[0]->GetBoxes()[0];
1922             if( pTmp->GetBox()->GetSttNd() )
1923                 break;      // das ist sonst zu weit
1924             pFndBox = pTmp;
1925         }
1926 
1927         SwTableLine* pDelLine = pFndBox->GetLines()[
1928                         pFndBox->GetLines().Count()-1 ]->GetLine();
1929         SwTableBox* pDelBox = pDelLine->GetTabBoxes()[
1930                             pDelLine->GetTabBoxes().Count() - 1 ];
1931         while( !pDelBox->GetSttNd() )
1932         {
1933             SwTableLine* pLn = pDelBox->GetTabLines()[
1934                         pDelBox->GetTabLines().Count()-1 ];
1935             pDelBox = pLn->GetTabBoxes()[ pLn->GetTabBoxes().Count() - 1 ];
1936         }
1937         SwTableBox* pNextBox = pDelLine->FindNextBox( pTblNd->GetTable(),
1938                                                         pDelBox, sal_True );
1939         while( pNextBox &&
1940                 pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
1941             pNextBox = pNextBox->FindNextBox( pTblNd->GetTable(), pNextBox );
1942 
1943         if( !pNextBox )         // keine nachfolgende? dann die vorhergehende
1944         {
1945             pDelLine = pFndBox->GetLines()[ 0 ]->GetLine();
1946             pDelBox = pDelLine->GetTabBoxes()[ 0 ];
1947             while( !pDelBox->GetSttNd() )
1948                 pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0];
1949             pNextBox = pDelLine->FindPreviousBox( pTblNd->GetTable(),
1950                                                         pDelBox, sal_True );
1951             while( pNextBox &&
1952                     pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
1953                 pNextBox = pNextBox->FindPreviousBox( pTblNd->GetTable(), pNextBox );
1954         }
1955 
1956         sal_uLong nIdx;
1957         if( pNextBox )      // dann den Cursor hier hinein
1958             nIdx = pNextBox->GetSttIdx() + 1;
1959         else                // ansonsten hinter die Tabelle
1960             nIdx = pTblNd->EndOfSectionIndex() + 1;
1961 
1962         SwNodeIndex aIdx( GetNodes(), nIdx );
1963         SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
1964         if( !pCNd )
1965             pCNd = GetNodes().GoNext( &aIdx );
1966 
1967         if( pCNd )
1968         {
1969             // die Cursor von der Shell oder den uebergebenen Cursor aendern?
1970             SwPaM* pPam = (SwPaM*)&rCursor;
1971             pPam->GetPoint()->nNode = aIdx;
1972             pPam->GetPoint()->nContent.Assign( pCNd, 0 );
1973             pPam->SetMark();            // beide wollen etwas davon haben
1974             pPam->DeleteMark();
1975         }
1976     }
1977 
1978     // dann loesche doch die Zeilen
1979 
1980     GetIDocumentUndoRedo().StartUndo(UNDO_ROW_DELETE, NULL);
1981     sal_Bool bResult = DeleteRowCol( aBoxes );
1982     GetIDocumentUndoRedo().EndUndo(UNDO_ROW_DELETE, NULL);
1983 
1984     return bResult;
1985 }
1986 
1987 sal_Bool SwDoc::DeleteCol( const SwCursor& rCursor )
1988 {
1989     // lasse ueber das Layout die Boxen suchen
1990     SwSelBoxes aBoxes;
1991     GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
1992     if( ::HasProtectedCells( aBoxes ))
1993         return sal_False;
1994 
1995     // die Crsr muessen noch aus dem Loesch Bereich entfernt
1996     // werden. Setze sie immer hinter/auf die Tabelle; ueber die
1997     // Dokument-Position werden sie dann immer an die alte Position gesetzt.
1998     SwEditShell* pESh = GetEditShell();
1999     if( pESh )
2000     {
2001         const SwNode* pNd = rCursor.GetNode()->FindTableBoxStartNode();
2002         pESh->ParkCrsr( SwNodeIndex( *pNd ) );
2003     }
2004 
2005     // dann loesche doch die Spalten
2006     GetIDocumentUndoRedo().StartUndo(UNDO_COL_DELETE, NULL);
2007     sal_Bool bResult = DeleteRowCol( aBoxes, true );
2008     GetIDocumentUndoRedo().EndUndo(UNDO_COL_DELETE, NULL);
2009 
2010     return bResult;
2011 }
2012 
2013 sal_Bool SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn )
2014 {
2015     if( ::HasProtectedCells( rBoxes ))
2016         return sal_False;
2017 
2018     // uebers SwDoc fuer Undo !!
2019     ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
2020     SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
2021     if( !pTblNd )
2022         return sal_False;
2023 
2024     if( pTblNd->GetTable().ISA( SwDDETable ))
2025         return sal_False;
2026 
2027     ::ClearFEShellTabCols();
2028     SwSelBoxes aSelBoxes;
2029     aSelBoxes.Insert(rBoxes.GetData(), rBoxes.Count());
2030     SwTable &rTable = pTblNd->GetTable();
2031     long nMin = 0;
2032     long nMax = 0;
2033     if( rTable.IsNewModel() )
2034     {
2035         if( bColumn )
2036             rTable.ExpandColumnSelection( aSelBoxes, nMin, nMax );
2037         else
2038             rTable.FindSuperfluousRows( aSelBoxes );
2039     }
2040 
2041 #ifdef DEL_TABLE_REDLINES
2042     lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
2043 #endif
2044 
2045     // soll die gesamte Tabelle geloescht werden ??
2046     const sal_uLong nTmpIdx1 = pTblNd->GetIndex();
2047     const sal_uLong nTmpIdx2 = aSelBoxes[ aSelBoxes.Count()-1 ]->GetSttNd()->
2048                                 EndOfSectionIndex()+1;
2049     if( pTblNd->GetTable().GetTabSortBoxes().Count() == aSelBoxes.Count() &&
2050         aSelBoxes[0]->GetSttIdx()-1 == nTmpIdx1 &&
2051         nTmpIdx2 == pTblNd->EndOfSectionIndex() )
2052     {
2053         sal_Bool bNewTxtNd = sal_False;
2054         // steht diese auch noch alleine in einem FlyFrame ?
2055         SwNodeIndex aIdx( *pTblNd, -1 );
2056         const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode();
2057         if( pSttNd )
2058         {
2059             const sal_uLong nTblEnd = pTblNd->EndOfSectionIndex() + 1;
2060             const sal_uLong nSectEnd = pSttNd->EndOfSectionIndex();
2061             if( nTblEnd == nSectEnd )
2062             {
2063                 if( SwFlyStartNode == pSttNd->GetStartNodeType() )
2064                 {
2065                     SwFrmFmt* pFmt = pSttNd->GetFlyFmt();
2066                     if( pFmt )
2067                     {
2068                         // Ok, das ist das gesuchte FlyFormat
2069                         DelLayoutFmt( pFmt );
2070                         return sal_True;
2071                     }
2072                 }
2073                 // kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
2074                 // TextNode ueberig lassen.
2075                 // Undo koennen wir dann vergessen !!
2076                 bNewTxtNd = sal_True;
2077             }
2078         }
2079 
2080         // kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
2081         // TextNode ueberig lassen.
2082         aIdx++;
2083         if (GetIDocumentUndoRedo().DoesUndo())
2084         {
2085             GetIDocumentUndoRedo().ClearRedo();
2086             SwPaM aPaM( *pTblNd->EndOfSectionNode(), aIdx.GetNode() );
2087 
2088             if( bNewTxtNd )
2089             {
2090                 const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
2091                 GetNodes().MakeTxtNode( aTmpIdx,
2092                             GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
2093             }
2094 
2095             // save the cursors (UNO and otherwise)
2096             SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
2097             if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
2098             {
2099                 *aSavePaM.GetMark() = SwPosition( *pTblNd );
2100                 aSavePaM.Move( fnMoveBackward, fnGoNode );
2101             }
2102             {
2103                 SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode());
2104                 ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
2105             }
2106 
2107             // harte SeitenUmbrueche am nachfolgenden Node verschieben
2108             sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
2109             sal_uLong nNextNd = pTblNd->EndOfSectionIndex()+1;
2110             SwCntntNode* pNextNd = GetNodes()[ nNextNd ]->GetCntntNode();
2111             if( pNextNd )
2112             {
2113 //JP 24.08.98: will man wirklich den PageDesc/Break vom
2114 //              nachfolgen Absatz ueberbuegeln?
2115 //              const SwAttrSet& rAttrSet = pNextNd->GetSwAttrSet();
2116 //              if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) &&
2117 //                  SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK ))
2118                 {
2119                     SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2120                     const SfxPoolItem *pItem;
2121                     if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2122                         sal_False, &pItem ) )
2123                     {
2124                         pNextNd->SetAttr( *pItem );
2125                         bSavePageDesc = sal_True;
2126                     }
2127 
2128                     if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2129                         sal_False, &pItem ) )
2130                     {
2131                         pNextNd->SetAttr( *pItem );
2132                         bSavePageBreak = sal_True;
2133                     }
2134                 }
2135             }
2136             SwUndoDelete* pUndo = new SwUndoDelete( aPaM );
2137             if( bNewTxtNd )
2138                 pUndo->SetTblDelLastNd();
2139             pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
2140             pUndo->SetTableName(pTblNd->GetTable().GetFrmFmt()->GetName());
2141             GetIDocumentUndoRedo().AppendUndo( pUndo );
2142         }
2143         else
2144         {
2145             if( bNewTxtNd )
2146             {
2147                 const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
2148                 GetNodes().MakeTxtNode( aTmpIdx,
2149                             GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
2150             }
2151 
2152             // save the cursors (UNO and otherwise)
2153             SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
2154             if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
2155             {
2156                 *aSavePaM.GetMark() = SwPosition( *pTblNd );
2157                 aSavePaM.Move( fnMoveBackward, fnGoNode );
2158             }
2159             {
2160                 SwPaM const tmpPaM(*pTblNd, *pTblNd->EndOfSectionNode());
2161                 ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark());
2162             }
2163 
2164             // harte SeitenUmbrueche am nachfolgenden Node verschieben
2165             SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
2166             if( pNextNd )
2167             {
2168                 SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2169                 const SfxPoolItem *pItem;
2170                 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2171                     sal_False, &pItem ) )
2172                     pNextNd->SetAttr( *pItem );
2173 
2174                 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2175                     sal_False, &pItem ) )
2176                     pNextNd->SetAttr( *pItem );
2177             }
2178 
2179             pTblNd->DelFrms();
2180             DeleteSection( pTblNd );
2181         }
2182         SetModified();
2183         SetFieldsDirty( true, NULL, 0 );
2184         return sal_True;
2185     }
2186 
2187     SwUndoTblNdsChg* pUndo = 0;
2188     if (GetIDocumentUndoRedo().DoesUndo())
2189     {
2190         pUndo = new SwUndoTblNdsChg( UNDO_TABLE_DELBOX, aSelBoxes, *pTblNd,
2191                                      nMin, nMax, 0, sal_False, sal_False );
2192     }
2193 
2194     bool bRet(false);
2195     {
2196         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
2197 
2198         SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
2199         aMsgHnt.eFlags = TBL_BOXPTR;
2200         UpdateTblFlds( &aMsgHnt );
2201 
2202         if (rTable.IsNewModel())
2203         {
2204             if (bColumn)
2205                 rTable.PrepareDeleteCol( nMin, nMax );
2206             rTable.FindSuperfluousRows( aSelBoxes );
2207             if (pUndo)
2208                 pUndo->ReNewBoxes( aSelBoxes );
2209         }
2210         bRet = rTable.DeleteSel( this, aSelBoxes, 0, pUndo, sal_True, sal_True );
2211         if (bRet)
2212         {
2213             SetModified();
2214             SetFieldsDirty( true, NULL, 0 );
2215         }
2216     }
2217 
2218     if( pUndo )
2219     {
2220         if( bRet )
2221         {
2222             GetIDocumentUndoRedo().AppendUndo( pUndo );
2223         }
2224         else
2225             delete pUndo;
2226     }
2227 
2228     return bRet;
2229 }
2230 
2231 
2232 // ---------- teilen / zusammenfassen von Boxen in der Tabelle --------
2233 
2234 sal_Bool SwDoc::SplitTbl( const SwSelBoxes& rBoxes, sal_Bool bVert, sal_uInt16 nCnt,
2235                       sal_Bool bSameHeight )
2236 {
2237     // uebers SwDoc fuer Undo !!
2238     ASSERT( rBoxes.Count() && nCnt, "keine gueltige Box-Liste" );
2239     SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
2240     if( !pTblNd )
2241         return sal_False;
2242 
2243     SwTable& rTbl = pTblNd->GetTable();
2244     if( rTbl.ISA( SwDDETable ))
2245         return sal_False;
2246 
2247 #ifdef DEL_TABLE_REDLINES
2248     lcl_DelRedlines aDelRedl( *pTblNd, sal_True );
2249 #endif
2250 
2251     SvULongs aNdsCnts;
2252     SwTableSortBoxes aTmpLst( 0, 5 );
2253     SwUndoTblNdsChg* pUndo = 0;
2254     if (GetIDocumentUndoRedo().DoesUndo())
2255     {
2256         pUndo = new SwUndoTblNdsChg( UNDO_TABLE_SPLIT, rBoxes, *pTblNd, 0, 0,
2257                                      nCnt, bVert, bSameHeight );
2258 
2259         aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
2260         if( !bVert )
2261         {
2262             for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
2263             {
2264                 const SwStartNode* pSttNd = rBoxes[ n ]->GetSttNd();
2265                 aNdsCnts.Insert( pSttNd->EndOfSectionIndex() -
2266                                  pSttNd->GetIndex(), n );
2267             }
2268         }
2269     }
2270 
2271     bool bRet(false);
2272     {
2273         ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
2274 
2275         SwTableFmlUpdate aMsgHnt( &rTbl );
2276         aMsgHnt.eFlags = TBL_BOXPTR;
2277         UpdateTblFlds( &aMsgHnt );
2278 
2279         if (bVert)
2280             bRet = rTbl.SplitCol( this, rBoxes, nCnt );
2281         else
2282             bRet = rTbl.SplitRow( this, rBoxes, nCnt, bSameHeight );
2283 
2284         if (bRet)
2285         {
2286             SetModified();
2287             SetFieldsDirty( true, NULL, 0 );
2288         }
2289     }
2290 
2291     if( pUndo )
2292     {
2293         if( bRet )
2294         {
2295             if( bVert )
2296                 pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
2297             else
2298                 pUndo->SaveNewBoxes( *pTblNd, aTmpLst, rBoxes, aNdsCnts );
2299             GetIDocumentUndoRedo().AppendUndo( pUndo );
2300         }
2301         else
2302             delete pUndo;
2303     }
2304 
2305     return bRet;
2306 }
2307 
2308 
2309 sal_uInt16 SwDoc::MergeTbl( SwPaM& rPam )
2310 {
2311     // pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
2312     SwTableNode* pTblNd = rPam.GetNode()->FindTableNode();
2313     if( !pTblNd )
2314         return TBLMERGE_NOSELECTION;
2315     SwTable& rTable = pTblNd->GetTable();
2316     if( rTable.ISA(SwDDETable) )
2317         return TBLMERGE_NOSELECTION;
2318     sal_uInt16 nRet = TBLMERGE_NOSELECTION;
2319     if( !rTable.IsNewModel() )
2320     {
2321         nRet =::CheckMergeSel( rPam );
2322         if( TBLMERGE_OK != nRet )
2323             return nRet;
2324         nRet = TBLMERGE_NOSELECTION;
2325     }
2326 
2327     // --> FME 2004-10-08 #i33394#
2328     GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_MERGE, NULL );
2329     // <--
2330 
2331 #ifdef DEL_TABLE_REDLINES
2332     if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
2333         DeleteRedline( *pTblNd, true, USHRT_MAX );
2334 #endif
2335     RedlineMode_t eOld = GetRedlineMode();
2336     SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
2337 
2338     SwUndoTblMerge *const pUndo( (GetIDocumentUndoRedo().DoesUndo())
2339         ?   new SwUndoTblMerge( rPam )
2340         :   0 );
2341 
2342     // lasse ueber das Layout die Boxen suchen
2343     SwSelBoxes aBoxes;
2344     SwSelBoxes aMerged;
2345     SwTableBox* pMergeBox;
2346 
2347     if( !rTable.PrepareMerge( rPam, aBoxes, aMerged, &pMergeBox, pUndo ) )
2348     {   // no cells found to merge
2349         SetRedlineMode_intern( eOld );
2350         if( pUndo )
2351         {
2352             delete pUndo;
2353             SwUndoId nLastUndoId(UNDO_EMPTY);
2354             if (GetIDocumentUndoRedo().GetLastUndoInfo(0, & nLastUndoId)
2355                 && (UNDO_REDLINE == nLastUndoId))
2356             {
2357                 // FIXME: why is this horrible cleanup necessary?
2358                 SwUndoRedline *const pU = dynamic_cast<SwUndoRedline*>(
2359                         GetUndoManager().RemoveLastUndo());
2360                 if( pU->GetRedlSaveCount() )
2361                 {
2362                     SwEditShell *const pEditShell(GetEditShell(0));
2363                     OSL_ASSERT(pEditShell);
2364                     ::sw::UndoRedoContext context(*this, *pEditShell);
2365                     static_cast<SfxUndoAction *>(pU)->UndoWithContext(context);
2366                 }
2367                 delete pU;
2368             }
2369         }
2370     }
2371     else
2372     {
2373         // die PaMs muessen noch aus dem Loesch Bereich entfernt
2374         // werden. Setze sie immer hinter/auf die Tabelle; ueber die
2375         // Dokument-Position werden sie dann immer an die alte Position gesetzt.
2376         // Erstmal einen Index auf die Parkposition merken, denn nach GetMergeSel
2377         // komme ich nicht mehr dran.
2378         {
2379             rPam.DeleteMark();
2380             rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
2381             rPam.GetPoint()->nContent.Assign( 0, 0 );
2382             rPam.SetMark();
2383             rPam.DeleteMark();
2384 
2385             SwPaM* pTmp = &rPam;
2386             while( &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ))
2387                 for( int i = 0; i < 2; ++i )
2388                     pTmp->GetBound( (sal_Bool)i ) = *rPam.GetPoint();
2389         }
2390 
2391         // dann fuege sie zusammen
2392         SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
2393         aMsgHnt.eFlags = TBL_BOXPTR;
2394         UpdateTblFlds( &aMsgHnt );
2395 
2396         if( pTblNd->GetTable().Merge( this, aBoxes, aMerged, pMergeBox, pUndo ))
2397         {
2398             nRet = TBLMERGE_OK;
2399             SetModified();
2400             SetFieldsDirty( true, NULL, 0 );
2401             if( pUndo )
2402             {
2403                 GetIDocumentUndoRedo().AppendUndo( pUndo );
2404             }
2405         }
2406         else if( pUndo )
2407             delete pUndo;
2408 
2409         rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
2410         rPam.Move();
2411 
2412         ::ClearFEShellTabCols();
2413         SetRedlineMode_intern( eOld );
2414     }
2415     GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_MERGE, NULL );
2416     return nRet;
2417 }
2418 
2419 
2420 
2421 // -------------------------------------------------------
2422 
2423 //---------
2424 // SwTableNode
2425 //---------
2426 
2427 SwTableNode::SwTableNode( const SwNodeIndex& rIdx )
2428     : SwStartNode( rIdx, ND_TABLENODE )
2429 {
2430     pTable = new SwTable( 0 );
2431 }
2432 
2433 SwTableNode::~SwTableNode()
2434 {
2435     //don't forget to notify uno wrappers
2436     SwFrmFmt* pTblFmt = GetTable().GetFrmFmt();
2437     SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
2438                                 pTblFmt );
2439     pTblFmt->ModifyNotification( &aMsgHint, &aMsgHint );
2440     DelFrms();
2441     delete pTable;
2442 }
2443 
2444 SwTabFrm *SwTableNode::MakeFrm( SwFrm* pSib )
2445 {
2446     return new SwTabFrm( *pTable, pSib );
2447 }
2448 
2449 //Methode erzeugt fuer den vorhergehenden Node alle Ansichten vom
2450 //Dokument. Die erzeugten Contentframes werden in das entsprechende
2451 //Layout gehaengt.
2452 void SwTableNode::MakeFrms(const SwNodeIndex & rIdx )
2453 {
2454     if( !GetTable().GetFrmFmt()->GetDepends())//gibt es ueberhaupt Frames ??
2455         return;
2456 
2457     SwFrm *pFrm, *pNew;
2458     SwCntntNode * pNode = rIdx.GetNode().GetCntntNode();
2459 
2460     ASSERT( pNode, "Kein Contentnode oder Copy-Node und neuer Node identisch.");
2461 
2462     sal_Bool bBefore = rIdx < GetIndex();
2463 
2464     SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() );
2465 
2466     while( 0 != (pFrm = aNode2Layout.NextFrm()) )
2467     {
2468         pNew = pNode->MakeFrm( pFrm );
2469         // wird ein Node vorher oder nachher mit Frames versehen
2470         if ( bBefore )
2471             // der neue liegt vor mir
2472             pNew->Paste( pFrm->GetUpper(), pFrm );
2473         else
2474             // der neue liegt hinter mir
2475             pNew->Paste( pFrm->GetUpper(), pFrm->GetNext() );
2476     }
2477 }
2478 
2479 //Fuer jede Shell einen TblFrm anlegen und vor den entsprechenden
2480 //CntntFrm pasten.
2481 
2482 void SwTableNode::MakeFrms( SwNodeIndex* pIdxBehind )
2483 {
2484     ASSERT( pIdxBehind, "kein Index" );
2485     *pIdxBehind = *this;
2486     SwNode *pNd = GetNodes().FindPrvNxtFrmNode( *pIdxBehind, EndOfSectionNode() );
2487     if( !pNd )
2488         return ;
2489 
2490     SwFrm *pFrm( 0L );
2491     SwLayoutFrm *pUpper( 0L );
2492     SwNode2Layout aNode2Layout( *pNd, GetIndex() );
2493     while( 0 != (pUpper = aNode2Layout.UpperFrm( pFrm, *this )) )
2494     {
2495         SwTabFrm* pNew = MakeFrm( pUpper );
2496         pNew->Paste( pUpper, pFrm );
2497         // --> OD 2005-12-01 #i27138#
2498         // notify accessibility paragraphs objects about changed
2499         // CONTENT_FLOWS_FROM/_TO relation.
2500         // Relation CONTENT_FLOWS_FROM for next paragraph will change
2501         // and relation CONTENT_FLOWS_TO for previous paragraph will change.
2502         {
2503             ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() );
2504             if ( pViewShell && pViewShell->GetLayout() &&
2505                  pViewShell->GetLayout()->IsAnyShellAccessible() )
2506             {
2507                 pViewShell->InvalidateAccessibleParaFlowRelation(
2508                             dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
2509                             dynamic_cast<SwTxtFrm*>(pNew->FindPrevCnt( true )) );
2510             }
2511         }
2512         // <--
2513         ((SwTabFrm*)pNew)->RegistFlys();
2514     }
2515 }
2516 
2517 void SwTableNode::DelFrms()
2518 {
2519     //Erstmal die TabFrms ausschneiden und deleten, die Columns und Rows
2520     //nehmen sie mit in's Grab.
2521     //Die TabFrms haengen am FrmFmt des SwTable.
2522     //Sie muessen etwas umstaendlich zerstort werden, damit die Master
2523     //die Follows mit in's Grab nehmen.
2524 
2525     SwIterator<SwTabFrm,SwFmt> aIter( *(pTable->GetFrmFmt()) );
2526     SwTabFrm *pFrm = aIter.First();
2527     while ( pFrm )
2528     {
2529         sal_Bool bAgain = sal_False;
2530         {
2531             if ( !pFrm->IsFollow() )
2532             {
2533                 while ( pFrm->HasFollow() )
2534                     pFrm->JoinAndDelFollows();
2535                 // --> OD 2005-12-01 #i27138#
2536                 // notify accessibility paragraphs objects about changed
2537                 // CONTENT_FLOWS_FROM/_TO relation.
2538                 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
2539                 // and relation CONTENT_FLOWS_TO for current previous paragraph will change.
2540                 {
2541                     ViewShell* pViewShell( pFrm->getRootFrm()->GetCurrShell() );
2542                     if ( pViewShell && pViewShell->GetLayout() &&
2543                          pViewShell->GetLayout()->IsAnyShellAccessible() )
2544                     {
2545                         pViewShell->InvalidateAccessibleParaFlowRelation(
2546                             dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )),
2547                             dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) );
2548                     }
2549                 }
2550                 // <--
2551                 pFrm->Cut();
2552                 delete pFrm;
2553                 bAgain = sal_True;
2554             }
2555         }
2556         pFrm = bAgain ? aIter.First() : aIter.Next();
2557     }
2558 }
2559 
2560 
2561 void SwTableNode::SetNewTable( SwTable* pNewTable, sal_Bool bNewFrames )
2562 {
2563     DelFrms();
2564     delete pTable;
2565     pTable = pNewTable;
2566     if( bNewFrames )
2567     {
2568         SwNodeIndex aIdx( *EndOfSectionNode());
2569         GetNodes().GoNext( &aIdx );
2570         MakeFrms( &aIdx );
2571     }
2572 }
2573 
2574 void SwDoc::GetTabCols( SwTabCols &rFill, const SwCursor* pCrsr,
2575                         const SwCellFrm* pBoxFrm ) const
2576 {
2577     const SwTableBox* pBox = 0;
2578     SwTabFrm *pTab = 0;
2579 
2580     if( pBoxFrm )
2581     {
2582         pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2583         pBox = pBoxFrm->GetTabBox();
2584     }
2585     else if( pCrsr )
2586     {
2587         const SwCntntNode* pCNd = pCrsr->GetCntntNode();
2588         if( !pCNd )
2589             return ;
2590 
2591         Point aPt;
2592         const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
2593         if( pShCrsr )
2594             aPt = pShCrsr->GetPtPos();
2595 
2596         const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False );
2597         do {
2598             pTmpFrm = pTmpFrm->GetUpper();
2599         } while ( !pTmpFrm->IsCellFrm() );
2600 
2601         pBoxFrm = (SwCellFrm*)pTmpFrm;
2602         pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2603         pBox = pBoxFrm->GetTabBox();
2604     }
2605     else if( !pCrsr && !pBoxFrm )
2606     {
2607         ASSERT( !this, "einer von beiden muss angegeben werden!" );
2608         return ;
2609     }
2610 
2611     //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2612     SWRECTFN( pTab )
2613     const SwPageFrm* pPage = pTab->FindPageFrm();
2614     const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
2615                            (pPage->Frm().*fnRect->fnGetLeft)();
2616     const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
2617                             (pPage->Frm().*fnRect->fnGetLeft)();
2618 
2619     rFill.SetLeftMin ( nLeftMin );
2620     rFill.SetLeft    ( (pTab->Prt().*fnRect->fnGetLeft)() );
2621     rFill.SetRight   ( (pTab->Prt().*fnRect->fnGetRight)());
2622     rFill.SetRightMax( nRightMax - nLeftMin );
2623 
2624     pTab->GetTable()->GetTabCols( rFill, pBox );
2625 }
2626 
2627 //
2628 // Here are some little helpers used in SwDoc::GetTabRows
2629 //
2630 
2631 #define ROWFUZZY 25
2632 
2633 struct FuzzyCompare
2634 {
2635     bool operator() ( long s1, long s2 ) const;
2636 };
2637 
2638 bool FuzzyCompare::operator() ( long s1, long s2 ) const
2639 {
2640     return ( s1 < s2 && abs( s1 - s2 ) > ROWFUZZY );
2641 }
2642 
2643 bool lcl_IsFrmInColumn( const SwCellFrm& rFrm, SwSelBoxes& rBoxes )
2644 {
2645     for( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
2646     {
2647         if ( rFrm.GetTabBox() == rBoxes[ i ] )
2648             return true;
2649     }
2650 
2651     return false;
2652 }
2653 
2654 //
2655 // SwDoc::GetTabRows()
2656 //
2657 
2658 void SwDoc::GetTabRows( SwTabCols &rFill, const SwCursor* ,
2659                         const SwCellFrm* pBoxFrm ) const
2660 {
2661     ASSERT( pBoxFrm, "GetTabRows called without pBoxFrm" )
2662 
2663     // --> FME 2005-09-12 #121591# Make code robust:
2664     if ( !pBoxFrm )
2665         return;
2666     // <--
2667 
2668     // --> FME 2005-01-06 #i39552# Collection of the boxes of the current
2669     // column has to be done at the beginning of this function, because
2670     // the table may be formatted in ::GetTblSel.
2671     SwDeletionChecker aDelCheck( pBoxFrm );
2672 
2673     SwSelBoxes aBoxes;
2674     const SwCntntFrm* pCntnt = ::GetCellCntnt( *pBoxFrm );
2675     if ( pCntnt && pCntnt->IsTxtFrm() )
2676     {
2677         const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
2678         const SwCursor aTmpCrsr( aPos, 0, false );
2679         ::GetTblSel( aTmpCrsr, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
2680     }
2681     // <--
2682 
2683     // --> FME 2005-09-12 #121591# Make code robust:
2684     if ( aDelCheck.HasBeenDeleted() )
2685     {
2686         ASSERT( false, "Current box has been deleted during GetTabRows()" )
2687         return;
2688     }
2689     // <--
2690 
2691     // --> FME 2005-09-12 #121591# Make code robust:
2692     const SwTabFrm* pTab = pBoxFrm->FindTabFrm();
2693     ASSERT( pTab, "GetTabRows called without a table" )
2694     if ( !pTab )
2695         return;
2696     // <--
2697 
2698     const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
2699 
2700     //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2701     SWRECTFN( pTab )
2702     const SwPageFrm* pPage = pTab->FindPageFrm();
2703     const long nLeftMin  = ( bVert ?
2704                              pTab->GetPrtLeft() - pPage->Frm().Left() :
2705                              pTab->GetPrtTop() - pPage->Frm().Top() );
2706     const long nLeft     = bVert ? LONG_MAX : 0;
2707     const long nRight    = (pTab->Prt().*fnRect->fnGetHeight)();
2708     const long nRightMax = bVert ? nRight : LONG_MAX;
2709 
2710     rFill.SetLeftMin( nLeftMin );
2711     rFill.SetLeft( nLeft );
2712     rFill.SetRight( nRight );
2713     rFill.SetRightMax( nRightMax );
2714 
2715     typedef std::map< long, std::pair< long, long >, FuzzyCompare > BoundaryMap;
2716     BoundaryMap aBoundaries;
2717     BoundaryMap::iterator aIter;
2718     std::pair< long, long > aPair;
2719 
2720     typedef std::map< long, bool > HiddenMap;
2721     HiddenMap aHidden;
2722     HiddenMap::iterator aHiddenIter;
2723 
2724     while ( pFrm && pTab->IsAnLower( pFrm ) )
2725     {
2726         if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
2727         {
2728             // upper and lower borders of current cell frame:
2729             long nUpperBorder = (pFrm->Frm().*fnRect->fnGetTop)();
2730             long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
2731 
2732             // get boundaries for nUpperBorder:
2733             aIter = aBoundaries.find( nUpperBorder );
2734             if ( aIter == aBoundaries.end() )
2735             {
2736                 aPair.first = nUpperBorder; aPair.second = LONG_MAX;
2737                 aBoundaries[ nUpperBorder ] = aPair;
2738             }
2739 
2740             // get boundaries for nLowerBorder:
2741             aIter = aBoundaries.find( nLowerBorder );
2742             if ( aIter == aBoundaries.end() )
2743             {
2744                 aPair.first = nUpperBorder; aPair.second = LONG_MAX;
2745             }
2746             else
2747             {
2748                 nLowerBorder = (*aIter).first;
2749                 long nNewLowerBorderUpperBoundary = Max( (*aIter).second.first, nUpperBorder );
2750                 aPair.first = nNewLowerBorderUpperBoundary; aPair.second = LONG_MAX;
2751             }
2752             aBoundaries[ nLowerBorder ] = aPair;
2753 
2754             // calculate hidden flags for entry nUpperBorder/nLowerBorder:
2755             long nTmpVal = nUpperBorder;
2756             for ( sal_uInt8 i = 0; i < 2; ++i )
2757             {
2758                 aHiddenIter = aHidden.find( nTmpVal );
2759                 if ( aHiddenIter == aHidden.end() )
2760                     aHidden[ nTmpVal ] = !lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes );
2761                 else
2762                 {
2763                     if ( aHidden[ nTmpVal ] &&
2764                          lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes ) )
2765                         aHidden[ nTmpVal ] = false;
2766                 }
2767                 nTmpVal = nLowerBorder;
2768             }
2769         }
2770 
2771         pFrm = pFrm->GetNextLayoutLeaf();
2772     }
2773 
2774     // transfer calculated values from BoundaryMap and HiddenMap into rFill:
2775     sal_uInt16 nIdx = 0;
2776     for ( aIter = aBoundaries.begin(); aIter != aBoundaries.end(); ++aIter )
2777     {
2778         const long nTabTop = (pTab->*fnRect->fnGetPrtTop)();
2779         const long nKey = (*fnRect->fnYDiff)( (*aIter).first, nTabTop );
2780         const std::pair< long, long > aTmpPair = (*aIter).second;
2781         const long nFirst = (*fnRect->fnYDiff)( aTmpPair.first, nTabTop );
2782         const long nSecond = aTmpPair.second;
2783 
2784         aHiddenIter = aHidden.find( (*aIter).first );
2785         const bool bHidden = aHiddenIter != aHidden.end() && (*aHiddenIter).second;
2786         rFill.Insert( nKey, nFirst, nSecond, bHidden, nIdx++ );
2787     }
2788 
2789     // delete first and last entry
2790     ASSERT( rFill.Count(), "Deleting from empty vector. Fasten your seatbelts!" )
2791     // --> FME 2006-01-19 #i60818# There may be only one entry in rFill. Make
2792     // code robust by checking count of rFill.
2793     if ( rFill.Count() ) rFill.Remove( 0, 1 );
2794     if ( rFill.Count() ) rFill.Remove( rFill.Count() - 1 , 1 );
2795     // <--
2796     rFill.SetLastRowAllowedToChange( !pTab->HasFollowFlowLine() );
2797 }
2798 
2799 void SwDoc::SetTabCols( const SwTabCols &rNew, sal_Bool bCurRowOnly,
2800                         const SwCursor* pCrsr, const SwCellFrm* pBoxFrm )
2801 {
2802     const SwTableBox* pBox = 0;
2803     SwTabFrm *pTab = 0;
2804 
2805     if( pBoxFrm )
2806     {
2807         pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2808         pBox = pBoxFrm->GetTabBox();
2809     }
2810     else if( pCrsr )
2811     {
2812         const SwCntntNode* pCNd = pCrsr->GetCntntNode();
2813         if( !pCNd )
2814             return ;
2815 
2816         Point aPt;
2817         const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
2818         if( pShCrsr )
2819             aPt = pShCrsr->GetPtPos();
2820 
2821         const SwFrm* pTmpFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, 0, sal_False );
2822         do {
2823             pTmpFrm = pTmpFrm->GetUpper();
2824         } while ( !pTmpFrm->IsCellFrm() );
2825 
2826         pBoxFrm = (SwCellFrm*)pTmpFrm;
2827         pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2828         pBox = pBoxFrm->GetTabBox();
2829     }
2830     else if( !pCrsr && !pBoxFrm )
2831     {
2832         ASSERT( !this, "einer von beiden muss angegeben werden!" );
2833         return ;
2834     }
2835 
2836     // sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
2837     // dann muss es jetzt auf absolute umgerechnet werden.
2838     SwTable& rTab = *pTab->GetTable();
2839     const SwFmtFrmSize& rTblFrmSz = rTab.GetFrmFmt()->GetFrmSize();
2840     SWRECTFN( pTab )
2841     // OD 06.08.2003 #i17174# - With fix for #i9040# the shadow size is taken
2842     // from the table width. Thus, add its left and right size to current table
2843     // printing area width in order to get the correct table size attribute.
2844     SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
2845     {
2846         SvxShadowItem aShadow( rTab.GetFrmFmt()->GetShadow() );
2847         nPrtWidth += aShadow.CalcShadowSpace( SHADOW_LEFT ) +
2848                      aShadow.CalcShadowSpace( SHADOW_RIGHT );
2849     }
2850     if( nPrtWidth != rTblFrmSz.GetWidth() )
2851     {
2852         SwFmtFrmSize aSz( rTblFrmSz );
2853         aSz.SetWidth( nPrtWidth );
2854         rTab.GetFrmFmt()->SetFmtAttr( aSz );
2855     }
2856 
2857     SwTabCols aOld( rNew.Count() );
2858 
2859     const SwPageFrm* pPage = pTab->FindPageFrm();
2860     const sal_uLong nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
2861                            (pPage->Frm().*fnRect->fnGetLeft)();
2862     const sal_uLong nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
2863                             (pPage->Frm().*fnRect->fnGetLeft)();
2864 
2865     //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2866     aOld.SetLeftMin ( nLeftMin );
2867     aOld.SetLeft    ( (pTab->Prt().*fnRect->fnGetLeft)() );
2868     aOld.SetRight   ( (pTab->Prt().*fnRect->fnGetRight)());
2869     aOld.SetRightMax( nRightMax - nLeftMin );
2870 
2871     rTab.GetTabCols( aOld, pBox );
2872     SetTabCols(rTab, rNew, aOld, pBox, bCurRowOnly );
2873 }
2874 
2875 void SwDoc::SetTabRows( const SwTabCols &rNew, sal_Bool bCurColOnly, const SwCursor*,
2876                         const SwCellFrm* pBoxFrm )
2877 {
2878     const SwTableBox* pBox;
2879     SwTabFrm *pTab;
2880 
2881     ASSERT( pBoxFrm, "SetTabRows called without pBoxFrm" )
2882 
2883     pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2884     pBox = pBoxFrm->GetTabBox();
2885 
2886     // sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
2887     // dann muss es jetzt auf absolute umgerechnet werden.
2888     SWRECTFN( pTab )
2889     SwTabCols aOld( rNew.Count() );
2890 
2891     //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2892     const SwPageFrm* pPage = pTab->FindPageFrm();
2893 
2894     aOld.SetRight( (pTab->Prt().*fnRect->fnGetHeight)() );
2895     long nLeftMin;
2896     if ( bVert )
2897     {
2898         nLeftMin = pTab->GetPrtLeft() - pPage->Frm().Left();
2899         aOld.SetLeft    ( LONG_MAX );
2900         aOld.SetRightMax( aOld.GetRight() );
2901 
2902     }
2903     else
2904     {
2905         nLeftMin = pTab->GetPrtTop() - pPage->Frm().Top();
2906         aOld.SetLeft    ( 0 );
2907         aOld.SetRightMax( LONG_MAX );
2908     }
2909     aOld.SetLeftMin ( nLeftMin );
2910 
2911     GetTabRows( aOld, 0, pBoxFrm );
2912 
2913     GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_ATTR, NULL );
2914 
2915     // check for differences between aOld and rNew:
2916     const sal_uInt16 nCount = rNew.Count();
2917     const SwTable* pTable = pTab->GetTable();
2918     ASSERT( pTable, "My colleague told me, this couldn't happen" );
2919 
2920     for ( sal_uInt16 i = 0; i <= nCount; ++i )
2921     {
2922         const sal_uInt16 nIdxStt = bVert ? nCount - i : i - 1;
2923         const sal_uInt16 nIdxEnd = bVert ? nCount - i - 1 : i;
2924 
2925         const long nOldRowStart = i == 0  ? 0 : aOld[ nIdxStt ];
2926         const long nOldRowEnd =   i == nCount ? aOld.GetRight() : aOld[ nIdxEnd ];
2927         const long nOldRowHeight = nOldRowEnd - nOldRowStart;
2928 
2929         const long nNewRowStart = i == 0  ? 0 : rNew[ nIdxStt ];
2930         const long nNewRowEnd =   i == nCount ? rNew.GetRight() : rNew[ nIdxEnd ];
2931         const long nNewRowHeight = nNewRowEnd - nNewRowStart;
2932 
2933         const long nDiff = nNewRowHeight - nOldRowHeight;
2934         if ( abs( nDiff ) >= ROWFUZZY )
2935         {
2936             // For the old table model pTxtFrm and pLine will be set for every box.
2937             // For the new table model pTxtFrm will be set if the box is not covered,
2938             // but the pLine will be set if the box is not an overlapping box
2939             // In the new table model the row height can be adjusted,
2940             // when both variables are set.
2941             SwTxtFrm* pTxtFrm = 0;
2942             const SwTableLine* pLine = 0;
2943 
2944             // Iterate over all SwCellFrms with Bottom = nOldPos
2945             const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
2946             while ( pFrm && pTab->IsAnLower( pFrm ) )
2947             {
2948                 if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
2949                 {
2950                     const long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
2951                     const sal_uLong nTabTop = (pTab->*fnRect->fnGetPrtTop)();
2952                     if ( abs( (*fnRect->fnYInc)( nTabTop, nOldRowEnd ) - nLowerBorder ) <= ROWFUZZY )
2953                     {
2954                         if ( !bCurColOnly || pFrm == pBoxFrm )
2955                         {
2956                             const SwFrm* pCntnt = ::GetCellCntnt( static_cast<const SwCellFrm&>(*pFrm) );
2957 
2958                             if ( pCntnt && pCntnt->IsTxtFrm() )
2959                             {
2960                                 pBox = ((SwCellFrm*)pFrm)->GetTabBox();
2961                                 const long nRowSpan = pBox->getRowSpan();
2962                                 if( nRowSpan > 0 ) // Not overlapped
2963                                     pTxtFrm = (SwTxtFrm*)pCntnt;
2964                                 if( nRowSpan < 2 ) // Not overlapping for row height
2965                                     pLine = pBox->GetUpper();
2966                                 if( pLine && pTxtFrm ) // always for old table model
2967                                 {
2968                                     // The new row height must not to be calculated from a overlapping box
2969                                     SwFmtFrmSize aNew( pLine->GetFrmFmt()->GetFrmSize() );
2970                                     const long nNewSize = (pFrm->Frm().*fnRect->fnGetHeight)() + nDiff;
2971                                     if( nNewSize != aNew.GetHeight() )
2972                                     {
2973                                         aNew.SetHeight( nNewSize );
2974                                         if ( ATT_VAR_SIZE == aNew.GetHeightSizeType() )
2975                                             aNew.SetHeightSizeType( ATT_MIN_SIZE );
2976                                         // This position must not be in an overlapped box
2977                                         const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
2978                                         const SwCursor aTmpCrsr( aPos, 0, false );
2979                                         SetRowHeight( aTmpCrsr, aNew );
2980                                         // For the new table model we're done, for the old one
2981                                         // there might be another (sub)row to adjust...
2982                                         if( pTable->IsNewModel() )
2983                                             break;
2984                                     }
2985                                     pLine = 0;
2986                                 }
2987                             }
2988                         }
2989                     }
2990                 }
2991                 pFrm = pFrm->GetNextLayoutLeaf();
2992             }
2993         }
2994     }
2995 
2996     GetIDocumentUndoRedo().EndUndo( UNDO_TABLE_ATTR, NULL );
2997 
2998     ::ClearFEShellTabCols();
2999 }
3000 
3001 /* -----------------18.07.98 11:45-------------------
3002  *  Direktzugriff fuer UNO
3003  * --------------------------------------------------*/
3004 void SwDoc::SetTabCols(SwTable& rTab, const SwTabCols &rNew, const SwTabCols &rOld,
3005                                 const SwTableBox *pStart, sal_Bool bCurRowOnly )
3006 {
3007     if (GetIDocumentUndoRedo().DoesUndo())
3008     {
3009         GetIDocumentUndoRedo().AppendUndo(
3010             new SwUndoAttrTbl( *rTab.GetTableNode(), sal_True ));
3011     }
3012     rTab.SetTabCols( rNew, rOld, pStart, bCurRowOnly );
3013     ::ClearFEShellTabCols();
3014     SetModified();
3015 }
3016 
3017 void SwDoc::SetRowsToRepeat( SwTable &rTable, sal_uInt16 nSet )
3018 {
3019     if( nSet == rTable.GetRowsToRepeat() )
3020         return;
3021 
3022     if (GetIDocumentUndoRedo().DoesUndo())
3023     {
3024         GetIDocumentUndoRedo().AppendUndo(
3025             new SwUndoTblHeadline(rTable, rTable.GetRowsToRepeat(), nSet) );
3026     }
3027 
3028     SwMsgPoolItem aChg( RES_TBLHEADLINECHG );
3029     rTable.SetRowsToRepeat( nSet );
3030     rTable.GetFrmFmt()->ModifyNotification( &aChg, &aChg );
3031     SetModified();
3032 }
3033 
3034 
3035 
3036 
3037 // Splittet eine Tabelle in der Grund-Zeile, in der der Index steht.
3038 // Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node.
3039 // Ist das Flag bCalcNewSize auf sal_True, wird fuer beide neuen Tabellen
3040 // die neue Size aus dem Max der Boxen errechnet; vorrausgesetzt,
3041 // die Size ist "absolut" gesetzt (USHRT_MAX)
3042 
3043 void SwCollectTblLineBoxes::AddToUndoHistory( const SwCntntNode& rNd )
3044 {
3045     if( pHst )
3046         pHst->Add( rNd.GetFmtColl(), rNd.GetIndex(), ND_TEXTNODE );
3047 }
3048 
3049 void SwCollectTblLineBoxes::AddBox( const SwTableBox& rBox )
3050 {
3051     aPosArr.Insert( nWidth, aPosArr.Count() );
3052     SwTableBox* p = (SwTableBox*)&rBox;
3053     aBoxes.Insert( p, aBoxes.Count() );
3054     nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
3055 }
3056 
3057 const SwTableBox* SwCollectTblLineBoxes::GetBoxOfPos( const SwTableBox& rBox )
3058 {
3059     const SwTableBox* pRet = 0;
3060     sal_uInt16 n;
3061 
3062     if( aPosArr.Count() )
3063     {
3064         for( n = 0; n < aPosArr.Count(); ++n )
3065             if( aPosArr[ n ] == nWidth )
3066                 break;
3067             else if( aPosArr[ n ] > nWidth )
3068             {
3069                 if( n )
3070                     --n;
3071                 break;
3072             }
3073 
3074         if( n >= aPosArr.Count() )
3075             --n;
3076 
3077         nWidth = nWidth + (sal_uInt16)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
3078         pRet = aBoxes[ n ];
3079     }
3080     return pRet;
3081 }
3082 
3083 sal_Bool SwCollectTblLineBoxes::Resize( sal_uInt16 nOffset, sal_uInt16 nOldWidth )
3084 {
3085     sal_uInt16 n;
3086 
3087     if( aPosArr.Count() )
3088     {
3089         for( n = 0; n < aPosArr.Count(); ++n )
3090             if( aPosArr[ n ] == nOffset )
3091                 break;
3092             else if( aPosArr[ n ] > nOffset )
3093             {
3094                 if( n )
3095                     --n;
3096                 break;
3097             }
3098 
3099         aPosArr.Remove( 0, n );
3100         aBoxes.Remove( 0, n );
3101 
3102         // dann die Positionen der neuen Size anpassen
3103         for( n = 0; n < aPosArr.Count(); ++n )
3104         {
3105             sal_uLong nSize = nWidth;
3106             nSize *= ( aPosArr[ n ] - nOffset );
3107             nSize /= nOldWidth;
3108             aPosArr[ n ] = sal_uInt16( nSize );
3109         }
3110     }
3111     return 0 != aPosArr.Count();
3112 }
3113 
3114 sal_Bool lcl_Line_CollectBox( const SwTableLine*& rpLine, void* pPara )
3115 {
3116     SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
3117     if( pSplPara->IsGetValues() )
3118         ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_Box_CollectBox, pPara );
3119     else
3120         ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, pPara );
3121     return sal_True;
3122 }
3123 
3124 sal_Bool lcl_Box_CollectBox( const SwTableBox*& rpBox, void* pPara )
3125 {
3126     SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
3127     sal_uInt16 nLen = rpBox->GetTabLines().Count();
3128     if( nLen )
3129     {
3130         // dann mit der richtigen Line weitermachen
3131         if( pSplPara->IsGetFromTop() )
3132             nLen = 0;
3133         else
3134             --nLen;
3135 
3136         const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
3137         lcl_Line_CollectBox( pLn, pPara );
3138     }
3139     else
3140         pSplPara->AddBox( *rpBox );
3141     return sal_True;
3142 }
3143 
3144 sal_Bool lcl_BoxSetSplitBoxFmts( const SwTableBox*& rpBox, void* pPara )
3145 {
3146     SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
3147     sal_uInt16 nLen = rpBox->GetTabLines().Count();
3148     if( nLen )
3149     {
3150         // dann mit der richtigen Line weitermachen
3151         if( pSplPara->IsGetFromTop() )
3152             nLen = 0;
3153         else
3154             --nLen;
3155 
3156         const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
3157         lcl_Line_CollectBox( pLn, pPara );
3158     }
3159     else
3160     {
3161         const SwTableBox* pSrcBox = pSplPara->GetBoxOfPos( *rpBox );
3162         SwFrmFmt* pFmt = pSrcBox->GetFrmFmt();
3163         SwTableBox* pBox = (SwTableBox*)rpBox;
3164 
3165         if( HEADLINE_BORDERCOPY == pSplPara->GetMode() )
3166         {
3167             const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
3168             if( !rBoxItem.GetTop() )
3169             {
3170                 SvxBoxItem aNew( rBoxItem );
3171                 aNew.SetLine( pFmt->GetBox().GetBottom(), BOX_LINE_TOP );
3172                 if( aNew != rBoxItem )
3173                     pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
3174             }
3175         }
3176         else
3177         {
3178 sal_uInt16 __FAR_DATA aTableSplitBoxSetRange[] = {
3179     RES_LR_SPACE,       RES_UL_SPACE,
3180     RES_BACKGROUND,     RES_SHADOW,
3181     RES_PROTECT,        RES_PROTECT,
3182     RES_VERT_ORIENT,    RES_VERT_ORIENT,
3183     0 };
3184             SfxItemSet aTmpSet( pFmt->GetDoc()->GetAttrPool(),
3185                                 aTableSplitBoxSetRange );
3186             aTmpSet.Put( pFmt->GetAttrSet() );
3187             if( aTmpSet.Count() )
3188                 pBox->ClaimFrmFmt()->SetFmtAttr( aTmpSet );
3189 
3190             if( HEADLINE_BOXATRCOLLCOPY == pSplPara->GetMode() )
3191             {
3192                 SwNodeIndex aIdx( *pSrcBox->GetSttNd(), 1 );
3193                 SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
3194                 if( !pCNd )
3195                     pCNd = aIdx.GetNodes().GoNext( &aIdx );
3196                 aIdx = *pBox->GetSttNd();
3197                 SwCntntNode* pDNd = aIdx.GetNodes().GoNext( &aIdx );
3198 
3199                 // nur wenn der Node alleine in der Section steht
3200                 if( 2 == pDNd->EndOfSectionIndex() -
3201                         pDNd->StartOfSectionIndex() )
3202                 {
3203                     pSplPara->AddToUndoHistory( *pDNd );
3204                     pDNd->ChgFmtColl( pCNd->GetFmtColl() );
3205                 }
3206             }
3207 
3208             // bedingte Vorlage beachten
3209             pBox->GetSttNd()->CheckSectionCondColl();
3210         }
3211     }
3212     return sal_True;
3213 }
3214 
3215 
3216 sal_Bool SwDoc::SplitTable( const SwPosition& rPos, sal_uInt16 eHdlnMode,
3217                         sal_Bool bCalcNewSize )
3218 {
3219     SwNode* pNd = &rPos.nNode.GetNode();
3220     SwTableNode* pTNd = pNd->FindTableNode();
3221     if( !pTNd || pNd->IsTableNode() )
3222         return 0;
3223 
3224     if( pTNd->GetTable().ISA( SwDDETable ))
3225         return sal_False;
3226 
3227     SwTable& rTbl = pTNd->GetTable();
3228     rTbl.SetHTMLTableLayout( 0 );   // MIB 9.7.97: HTML-Layout loeschen
3229 
3230     SwTableFmlUpdate aMsgHnt( &rTbl );
3231 
3232     SwHistory aHistory;
3233     if (GetIDocumentUndoRedo().DoesUndo())
3234     {
3235         aMsgHnt.pHistory = &aHistory;
3236     }
3237 
3238     {
3239         sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
3240 
3241         // Suche die Grund-Line dieser Box:
3242         SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
3243         if( pBox )
3244         {
3245             SwTableLine* pLine = pBox->GetUpper();
3246             while( pLine->GetUpper() )
3247                 pLine = pLine->GetUpper()->GetUpper();
3248 
3249             // in pLine steht jetzt die GrundLine.
3250             aMsgHnt.nSplitLine = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
3251         }
3252 
3253         String sNewTblNm( GetUniqueTblName() );
3254         aMsgHnt.DATA.pNewTblNm = &sNewTblNm;
3255         aMsgHnt.eFlags = TBL_SPLITTBL;
3256         UpdateTblFlds( &aMsgHnt );
3257     }
3258 
3259     //Lines fuer das Layout-Update heraussuchen.
3260     _FndBox aFndBox( 0, 0 );
3261     aFndBox.SetTableLines( rTbl );
3262     aFndBox.DelFrms( rTbl );
3263 
3264     // TL_CHART2: need to inform chart of probably changed cell names
3265     //pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
3266 
3267     SwTableNode* pNew = GetNodes().SplitTable( rPos.nNode, sal_False, bCalcNewSize );
3268 
3269     if( pNew )
3270     {
3271         SwSaveRowSpan* pSaveRowSp = pNew->GetTable().CleanUpTopRowSpan( rTbl.GetTabLines().Count() );
3272         SwUndoSplitTbl* pUndo = 0;
3273         if (GetIDocumentUndoRedo().DoesUndo())
3274         {
3275             pUndo = new SwUndoSplitTbl(
3276                         *pNew, pSaveRowSp, eHdlnMode, bCalcNewSize);
3277             GetIDocumentUndoRedo().AppendUndo(pUndo);
3278             if( aHistory.Count() )
3279                 pUndo->SaveFormula( aHistory );
3280         }
3281 
3282         switch( eHdlnMode )
3283         {
3284             // setze die untere Border der vorherige Line,
3285             // an der aktuellen als obere
3286         case HEADLINE_BORDERCOPY:
3287             {
3288                 SwCollectTblLineBoxes aPara( sal_False, eHdlnMode );
3289                 SwTableLine* pLn = rTbl.GetTabLines()[
3290                             rTbl.GetTabLines().Count() - 1 ];
3291                 pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
3292 
3293                 aPara.SetValues( sal_True );
3294                 pLn = pNew->GetTable().GetTabLines()[ 0 ];
3295                 pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
3296 
3297                 // Kopfzeile wiederholen abschalten
3298                 pNew->GetTable().SetRowsToRepeat( 0 );
3299             }
3300             break;
3301 
3302             // setze die Attributierung der ersten Line an der neuen ersten
3303         case HEADLINE_BOXATTRCOPY:
3304         case HEADLINE_BOXATRCOLLCOPY:
3305             {
3306                 SwHistory* pHst = 0;
3307                 if( HEADLINE_BOXATRCOLLCOPY == eHdlnMode && pUndo )
3308                     pHst = pUndo->GetHistory();
3309 
3310                 SwCollectTblLineBoxes aPara( sal_True, eHdlnMode, pHst );
3311                 SwTableLine* pLn = rTbl.GetTabLines()[ 0 ];
3312                 pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
3313 
3314                 aPara.SetValues( sal_True );
3315                 pLn = pNew->GetTable().GetTabLines()[ 0 ];
3316                 pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
3317             }
3318             break;
3319 
3320         case HEADLINE_CNTNTCOPY:
3321             rTbl.CopyHeadlineIntoTable( *pNew );
3322             if( pUndo )
3323                 pUndo->SetTblNodeOffset( pNew->GetIndex() );
3324             break;
3325 
3326         case HEADLINE_NONE:
3327             // Kopfzeile wiederholen abschalten
3328             pNew->GetTable().SetRowsToRepeat( 0 );
3329             break;
3330         }
3331 
3332         // und Frms einfuegen.
3333         SwNodeIndex aNdIdx( *pNew->EndOfSectionNode() );
3334         GetNodes().GoNext( &aNdIdx );      // zum naechsten ContentNode
3335         pNew->MakeFrms( &aNdIdx );
3336 
3337         //Zwischen die Tabellen wird ein Absatz geschoben
3338         GetNodes().MakeTxtNode( SwNodeIndex( *pNew ),
3339                                 GetTxtCollFromPool( RES_POOLCOLL_TEXT ) );
3340     }
3341 
3342     //Layout updaten
3343     aFndBox.MakeFrms( rTbl );
3344 
3345     // TL_CHART2: need to inform chart of probably changed cell names
3346     UpdateCharts( rTbl.GetFrmFmt()->GetName() );
3347 
3348     SetFieldsDirty( true, NULL, 0 );
3349 
3350     return 0 != pNew;
3351 }
3352 
3353 sal_Bool lcl_ChgTblSize( SwTable& rTbl )
3354 {
3355     // das Attribut darf nicht ueber das Modify an der
3356     // Tabelle gesetzt werden, denn sonst werden alle
3357     // Boxen wieder auf 0 zurueck gesetzt. Also locke das Format
3358     SwFrmFmt* pFmt = rTbl.GetFrmFmt();
3359     SwFmtFrmSize aTblMaxSz( pFmt->GetFrmSize() );
3360 
3361     if( USHRT_MAX == aTblMaxSz.GetWidth() )
3362         return sal_False;
3363 
3364     sal_Bool bLocked = pFmt->IsModifyLocked();
3365     pFmt->LockModify();
3366 
3367     aTblMaxSz.SetWidth( 0 );
3368 
3369     SwTableLines& rLns = rTbl.GetTabLines();
3370     for( sal_uInt16 nLns = 0; nLns < rLns.Count(); ++nLns )
3371     {
3372         SwTwips nMaxLnWidth = 0;
3373         SwTableBoxes& rBoxes = rLns[ nLns ]->GetTabBoxes();
3374         for( sal_uInt16 nBox = 0; nBox < rBoxes.Count(); ++nBox )
3375             nMaxLnWidth += rBoxes[nBox]->GetFrmFmt()->GetFrmSize().GetWidth();
3376 
3377         if( nMaxLnWidth > aTblMaxSz.GetWidth() )
3378             aTblMaxSz.SetWidth( nMaxLnWidth );
3379     }
3380     pFmt->SetFmtAttr( aTblMaxSz );
3381     if( !bLocked )          // und gegebenenfalls Lock wieder freigeben
3382         pFmt->UnlockModify();
3383 
3384     return sal_True;
3385 }
3386 
3387 class _SplitTable_Para
3388 {
3389     SvPtrarr aSrc, aDest;
3390     SwTableNode* pNewTblNd;
3391     SwTable& rOldTbl;
3392 
3393 public:
3394     _SplitTable_Para( SwTableNode* pNew, SwTable& rOld )
3395         : aSrc( 16, 16 ), aDest( 16, 16 ), pNewTblNd( pNew ), rOldTbl( rOld )
3396     {}
3397     sal_uInt16 SrcFmt_GetPos( void* pFmt ) const
3398             { return aSrc.GetPos( pFmt ); }
3399 
3400     void DestFmt_Insert( void* pFmt )
3401             { aDest.Insert( pFmt, aDest.Count() ); }
3402 
3403     void SrcFmt_Insert( void* pFmt )
3404             { aSrc.Insert( pFmt, aSrc.Count() ); }
3405 
3406     SwFrmFmt* DestFmt_Get( sal_uInt16 nPos ) const
3407             { return (SwFrmFmt*)aDest[ nPos ]; }
3408 
3409     void ChgBox( SwTableBox* pBox )
3410     {
3411         rOldTbl.GetTabSortBoxes().Remove( pBox );
3412         pNewTblNd->GetTable().GetTabSortBoxes().Insert( pBox );
3413     }
3414 };
3415 
3416 
3417 sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara );
3418 
3419 sal_Bool lcl_SplitTable_CpyLine( const SwTableLine*& rpLine, void* pPara )
3420 {
3421     SwTableLine* pLn = (SwTableLine*)rpLine;
3422     _SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
3423 
3424     SwFrmFmt *pSrcFmt = pLn->GetFrmFmt();
3425     sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt );
3426     if( USHRT_MAX == nPos )
3427     {
3428         rPara.DestFmt_Insert( pLn->ClaimFrmFmt() );
3429         rPara.SrcFmt_Insert( pSrcFmt );
3430     }
3431     else
3432         pLn->ChgFrmFmt( (SwTableLineFmt*)rPara.DestFmt_Get( nPos ) );
3433 
3434     pLn->GetTabBoxes().ForEach( &lcl_SplitTable_CpyBox, pPara );
3435     return sal_True;
3436 }
3437 
3438 sal_Bool lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara )
3439 {
3440     SwTableBox* pBox = (SwTableBox*)rpBox;
3441     _SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
3442 
3443     SwFrmFmt *pSrcFmt = pBox->GetFrmFmt();
3444     sal_uInt16 nPos = rPara.SrcFmt_GetPos( pSrcFmt );
3445     if( USHRT_MAX == nPos )
3446     {
3447         rPara.DestFmt_Insert( pBox->ClaimFrmFmt() );
3448         rPara.SrcFmt_Insert( pSrcFmt );
3449     }
3450     else
3451         pBox->ChgFrmFmt( (SwTableBoxFmt*)rPara.DestFmt_Get( nPos ) );
3452 
3453     if( pBox->GetSttNd() )
3454         rPara.ChgBox( pBox );
3455     else
3456         pBox->GetTabLines().ForEach( &lcl_SplitTable_CpyLine, pPara );
3457     return sal_True;
3458 }
3459 
3460 SwTableNode* SwNodes::SplitTable( const SwNodeIndex& rPos, sal_Bool bAfter,
3461                                     sal_Bool bCalcNewSize )
3462 {
3463     SwNode* pNd = &rPos.GetNode();
3464     SwTableNode* pTNd = pNd->FindTableNode();
3465     if( !pTNd || pNd->IsTableNode() )
3466         return 0;
3467 
3468     sal_uLong nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
3469 
3470     // Suche die Grund-Line dieser Box:
3471     SwTable& rTbl = pTNd->GetTable();
3472     SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
3473     if( !pBox )
3474         return 0;
3475 
3476     SwTableLine* pLine = pBox->GetUpper();
3477     while( pLine->GetUpper() )
3478         pLine = pLine->GetUpper()->GetUpper();
3479 
3480     // in pLine steht jetzt die GrundLine.
3481     sal_uInt16 nLinePos = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
3482     if( USHRT_MAX == nLinePos ||
3483         ( bAfter ? ++nLinePos >= rTbl.GetTabLines().Count() : !nLinePos ))
3484         return 0;       // nicht gefunden oder letze Line !!
3485 
3486     // Suche jetzt die 1. Box der nachfolgenden Line
3487     SwTableLine* pNextLine = rTbl.GetTabLines()[ nLinePos ];
3488     pBox = pNextLine->GetTabBoxes()[0];
3489     while( !pBox->GetSttNd() )
3490         pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
3491 
3492     // dann fuege mal einen End- und TabelleNode ins Nodes-Array ein.
3493     SwTableNode * pNewTblNd;
3494     {
3495         SwEndNode* pOldTblEndNd = (SwEndNode*)pTNd->EndOfSectionNode()->GetEndNode();
3496         ASSERT( pOldTblEndNd, "wo ist der EndNode?" )
3497 
3498         SwNodeIndex aIdx( *pBox->GetSttNd() );
3499         new SwEndNode( aIdx, *pTNd );
3500         pNewTblNd = new SwTableNode( aIdx );
3501         pNewTblNd->GetTable().SetTableModel( rTbl.IsNewModel() );
3502 
3503         pOldTblEndNd->pStartOfSection = pNewTblNd;
3504         pNewTblNd->pEndOfSection = pOldTblEndNd;
3505 
3506         SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
3507         do {
3508             ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
3509             pBoxNd->pStartOfSection = pNewTblNd;
3510             pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
3511         } while( pBoxNd != pOldTblEndNd );
3512     }
3513 
3514     {
3515         // die Lines ruebermoven...
3516         SwTable& rNewTbl = pNewTblNd->GetTable();
3517         rNewTbl.GetTabLines().Insert( &rTbl.GetTabLines(), 0, nLinePos );
3518         //
3519         // von hinten (unten-rechts) nach vorn (oben-links) alle Boxen
3520         // beim chart data provider austragen (das modified event wird dann
3521         // in der aufrufenden Funktion getriggert.
3522         // TL_CHART2:
3523         SwChartDataProvider *pPCD = rTbl.GetFrmFmt()->getIDocumentChartDataProviderAccess()->GetChartDataProvider();
3524         if( pPCD )
3525         {
3526             for (sal_uInt16 k = nLinePos;  k < rTbl.GetTabLines().Count();  ++k)
3527             {
3528                 sal_uInt16 nLineIdx = (rTbl.GetTabLines().Count() - 1) - k + nLinePos;
3529                 sal_uInt16 nBoxCnt = rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes().Count();
3530                 for (sal_uInt16 j = 0;  j < nBoxCnt;  ++j)
3531                 {
3532                     sal_uInt16 nIdx = nBoxCnt - 1 - j;
3533                     pPCD->DeleteBox( &rTbl, *rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes()[nIdx] );
3534                 }
3535             }
3536         }
3537         //
3538         // ...und loeschen
3539         sal_uInt16 nDeleted = rTbl.GetTabLines().Count() - nLinePos;
3540         rTbl.GetTabLines().Remove( nLinePos, nDeleted );
3541 
3542         // und die betr. Boxen verschieben. Dabei die Formate eindeutig
3543         // machen und die StartNodes korrigieren
3544         _SplitTable_Para aPara( pNewTblNd, rTbl );
3545         rNewTbl.GetTabLines().ForEach( &lcl_SplitTable_CpyLine, &aPara );
3546         rTbl.CleanUpBottomRowSpan( nDeleted );
3547     }
3548 
3549     {
3550         // Das Tabellen-FrmFormat kopieren
3551         SwFrmFmt* pOldTblFmt = rTbl.GetFrmFmt();
3552         SwFrmFmt* pNewTblFmt = pOldTblFmt->GetDoc()->MakeTblFrmFmt(
3553                                 pOldTblFmt->GetDoc()->GetUniqueTblName(),
3554                                 pOldTblFmt->GetDoc()->GetDfltFrmFmt() );
3555 
3556         *pNewTblFmt = *pOldTblFmt;
3557         pNewTblNd->GetTable().RegisterToFormat( *pNewTblFmt );
3558 
3559         // neue Size errechnen ? (lcl_ChgTblSize nur das 2. aufrufen, wenn es
3560         // beim 1. schon geklappt hat; also absolute Groesse hat)
3561         if( bCalcNewSize && lcl_ChgTblSize( rTbl ) )
3562             lcl_ChgTblSize( pNewTblNd->GetTable() );
3563     }
3564 
3565     // TL_CHART2: need to inform chart of probably changed cell names
3566     rTbl.UpdateCharts();
3567 
3568     return pNewTblNd;       // das wars
3569 }
3570 
3571 // und die Umkehrung davon. rPos muss in der Tabelle stehen, die bestehen
3572 // bleibt. Das Flag besagt ob die aktuelle mit der davor oder dahinter
3573 // stehenden vereint wird.
3574 sal_Bool SwDoc::MergeTable( const SwPosition& rPos, sal_Bool bWithPrev, sal_uInt16 nMode )
3575 {
3576     SwTableNode* pTblNd = rPos.nNode.GetNode().FindTableNode(), *pDelTblNd;
3577     if( !pTblNd )
3578         return sal_False;
3579 
3580     SwNodes& rNds = GetNodes();
3581     if( bWithPrev )
3582         pDelTblNd = rNds[ pTblNd->GetIndex() - 1 ]->FindTableNode();
3583     else
3584         pDelTblNd = rNds[ pTblNd->EndOfSectionIndex() + 1 ]->GetTableNode();
3585     if( !pDelTblNd )
3586         return sal_False;
3587 
3588     if( pTblNd->GetTable().ISA( SwDDETable ) ||
3589         pDelTblNd->GetTable().ISA( SwDDETable ))
3590         return sal_False;
3591 
3592     // MIB 9.7.97: HTML-Layout loeschen
3593     pTblNd->GetTable().SetHTMLTableLayout( 0 );
3594     pDelTblNd->GetTable().SetHTMLTableLayout( 0 );
3595 
3596     // beide Tabellen vorhanden, also kanns losgehen
3597     SwUndoMergeTbl* pUndo = 0;
3598     SwHistory* pHistory = 0;
3599     if (GetIDocumentUndoRedo().DoesUndo())
3600     {
3601         pUndo = new SwUndoMergeTbl( *pTblNd, *pDelTblNd, bWithPrev, nMode );
3602         GetIDocumentUndoRedo().AppendUndo(pUndo);
3603         pHistory = new SwHistory;
3604     }
3605 
3606     // alle "Tabellenformeln" anpassen
3607     SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
3608     aMsgHnt.DATA.pDelTbl = &pDelTblNd->GetTable();
3609     aMsgHnt.eFlags = TBL_MERGETBL;
3610     aMsgHnt.pHistory = pHistory;
3611     UpdateTblFlds( &aMsgHnt );
3612 
3613     // das eigentliche Mergen
3614     SwNodeIndex aIdx( bWithPrev ? *pTblNd : *pDelTblNd );
3615     sal_Bool bRet = rNds.MergeTable( aIdx, !bWithPrev, nMode, pHistory );
3616 
3617     if( pHistory )
3618     {
3619         if( pHistory->Count() )
3620             pUndo->SaveFormula( *pHistory );
3621         delete pHistory;
3622     }
3623     if( bRet )
3624     {
3625         SetModified();
3626         SetFieldsDirty( true, NULL, 0 );
3627     }
3628     return bRet;
3629 }
3630 
3631 sal_Bool SwNodes::MergeTable( const SwNodeIndex& rPos, sal_Bool bWithPrev,
3632                             sal_uInt16 nMode, SwHistory* )
3633 {
3634     SwTableNode* pDelTblNd = rPos.GetNode().GetTableNode();
3635     ASSERT( pDelTblNd, "wo ist der TableNode geblieben?" );
3636 
3637     SwTableNode* pTblNd = (*this)[ rPos.GetIndex() - 1]->FindTableNode();
3638     ASSERT( pTblNd, "wo ist der TableNode geblieben?" );
3639 
3640     if( !pDelTblNd || !pTblNd )
3641         return sal_False;
3642 
3643     pDelTblNd->DelFrms();
3644 
3645     SwTable& rDelTbl = pDelTblNd->GetTable();
3646     SwTable& rTbl = pTblNd->GetTable();
3647 
3648     //Lines fuer das Layout-Update herausuchen.
3649     _FndBox aFndBox( 0, 0 );
3650     aFndBox.SetTableLines( rTbl );
3651     aFndBox.DelFrms( rTbl );
3652 
3653     // TL_CHART2: since chart currently does not want to get informed about
3654     // additional rows/cols there is no need for a modified event in the
3655     // remaining first table. Also, if it is required it  should be done
3656     // after the merging and not here...
3657     // pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
3658 
3659 
3660     // TL_CHART2:
3661     // tell the charts about the table to be deleted and have them use their own data
3662     GetDoc()->CreateChartInternalDataProviders( &rDelTbl );
3663 
3664     // die Breite der TabellenFormate abgleichen:
3665     {
3666         const SwFmtFrmSize& rTblSz = rTbl.GetFrmFmt()->GetFrmSize();
3667         const SwFmtFrmSize& rDelTblSz = rDelTbl.GetFrmFmt()->GetFrmSize();
3668         if( rTblSz != rDelTblSz )
3669         {
3670             // dann sollten die mal schleunigst korrigiert werden
3671             if( bWithPrev )
3672                 rDelTbl.GetFrmFmt()->SetFmtAttr( rTblSz );
3673             else
3674                 rTbl.GetFrmFmt()->SetFmtAttr( rDelTblSz );
3675         }
3676     }
3677 
3678     if( !bWithPrev )
3679     {
3680         // dann mussen alle Attruibute der hinteren Tabelle auf die
3681         // vordere uebertragen werden, weil die hintere ueber das loeschen
3682         // des Node geloescht wird.
3683         rTbl.SetRowsToRepeat( rDelTbl.GetRowsToRepeat() );
3684         rTbl.SetTblChgMode( rDelTbl.GetTblChgMode() );
3685 
3686         rTbl.GetFrmFmt()->LockModify();
3687         *rTbl.GetFrmFmt() = *rDelTbl.GetFrmFmt();
3688         // auch den Namen umsetzen!
3689         rTbl.GetFrmFmt()->SetName( rDelTbl.GetFrmFmt()->GetName() );
3690         rTbl.GetFrmFmt()->UnlockModify();
3691     }
3692 
3693     // die Lines und Boxen ruebermoven
3694     sal_uInt16 nOldSize = rTbl.GetTabLines().Count();
3695     rTbl.GetTabLines().Insert( &rDelTbl.GetTabLines(), nOldSize );
3696     rDelTbl.GetTabLines().Remove( 0, rDelTbl.GetTabLines().Count() );
3697 
3698     rTbl.GetTabSortBoxes().Insert( &rDelTbl.GetTabSortBoxes() );
3699     rDelTbl.GetTabSortBoxes().Remove( (sal_uInt16)0, rDelTbl.GetTabSortBoxes().Count() );
3700 
3701     // die vordere Tabelle bleibt immer stehen, die hintere wird geloescht
3702     SwEndNode* pTblEndNd = pDelTblNd->EndOfSectionNode();
3703     pTblNd->pEndOfSection = pTblEndNd;
3704 
3705     SwNodeIndex aIdx( *pDelTblNd, 1 );
3706 
3707     SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
3708     do {
3709         ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
3710         pBoxNd->pStartOfSection = pTblNd;
3711         pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
3712     } while( pBoxNd != pTblEndNd );
3713     pBoxNd->pStartOfSection = pTblNd;
3714 
3715     aIdx -= 2;
3716     DelNodes( aIdx, 2 );
3717 
3718     // jetzt an der 1. eingefuegten Line die bedingten Vorlagen umschubsen
3719     const SwTableLine* pFirstLn = rTbl.GetTabLines()[ nOldSize ];
3720     if( 1 == nMode )        //
3721     {
3722         // Header-Vorlagen in der Zeile setzen
3723         // und ggfs. in der History speichern fuers Undo!!!
3724     }
3725     lcl_LineSetHeadCondColl( pFirstLn, 0 );
3726 
3727     // und die Borders "aufrauemen"
3728     if( nOldSize )
3729     {
3730         _SwGCLineBorder aPara( rTbl );
3731         aPara.nLinePos = --nOldSize;
3732         pFirstLn = rTbl.GetTabLines()[ nOldSize ];
3733         lcl_GC_Line_Border( pFirstLn, &aPara );
3734     }
3735 
3736     //Layout updaten
3737     aFndBox.MakeFrms( rTbl );
3738 
3739     return sal_True;
3740 }
3741 
3742 // -------------------------------------------------------------------
3743 
3744 
3745 // -- benutze die ForEach Methode vom PtrArray
3746 struct _SetAFmtTabPara
3747 {
3748     SwTableAutoFmt& rTblFmt;
3749     SwUndoTblAutoFmt* pUndo;
3750     sal_uInt16 nEndBox, nCurBox;
3751     sal_uInt8 nAFmtLine, nAFmtBox;
3752 
3753     _SetAFmtTabPara( const SwTableAutoFmt& rNew )
3754         : rTblFmt( (SwTableAutoFmt&)rNew ), pUndo( 0 ),
3755         nEndBox( 0 ), nCurBox( 0 ), nAFmtLine( 0 ), nAFmtBox( 0 )
3756     {}
3757 };
3758 
3759 // forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
3760 // koennen.
3761 sal_Bool lcl_SetAFmtBox( const _FndBox*&, void *pPara );
3762 sal_Bool lcl_SetAFmtLine( const _FndLine*&, void *pPara );
3763 
3764 sal_Bool lcl_SetAFmtLine( const _FndLine*& rpLine, void *pPara )
3765 {
3766     ((_FndLine*&)rpLine)->GetBoxes().ForEach( &lcl_SetAFmtBox, pPara );
3767     return sal_True;
3768 }
3769 
3770 sal_Bool lcl_SetAFmtBox( const _FndBox*& rpBox, void *pPara )
3771 {
3772     _SetAFmtTabPara* pSetPara = (_SetAFmtTabPara*)pPara;
3773 
3774     if( !rpBox->GetUpper()->GetUpper() )    // Box auf 1. Ebene ?
3775     {
3776         if( !pSetPara->nCurBox )
3777             pSetPara->nAFmtBox = 0;
3778         else if( pSetPara->nCurBox == pSetPara->nEndBox )
3779             pSetPara->nAFmtBox = 3;
3780         else
3781             pSetPara->nAFmtBox = (sal_uInt8)(1 + ((pSetPara->nCurBox-1) & 1));
3782     }
3783 
3784     if( rpBox->GetBox()->GetSttNd() )
3785     {
3786         SwTableBox* pSetBox = (SwTableBox*)rpBox->GetBox();
3787         SwDoc* pDoc = pSetBox->GetFrmFmt()->GetDoc();
3788         // --> OD 2008-02-25 #refactorlists#
3789 //        SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
3790         SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
3791         // <--
3792         SfxItemSet aBoxSet( pDoc->GetAttrPool(), aTableBoxSetRange );
3793         sal_uInt8 nPos = pSetPara->nAFmtLine * 4 + pSetPara->nAFmtBox;
3794         pSetPara->rTblFmt.UpdateToSet( nPos, aCharSet,
3795                                         SwTableAutoFmt::UPDATE_CHAR, 0 );
3796         pSetPara->rTblFmt.UpdateToSet( nPos, aBoxSet,
3797                                         SwTableAutoFmt::UPDATE_BOX,
3798                                         pDoc->GetNumberFormatter( sal_True ) );
3799         if( aCharSet.Count() )
3800         {
3801             sal_uLong nSttNd = pSetBox->GetSttIdx()+1;
3802             sal_uLong nEndNd = pSetBox->GetSttNd()->EndOfSectionIndex();
3803             for( ; nSttNd < nEndNd; ++nSttNd )
3804             {
3805                 SwCntntNode* pNd = pDoc->GetNodes()[ nSttNd ]->GetCntntNode();
3806                 if( pNd )
3807                     pNd->SetAttr( aCharSet );
3808             }
3809         }
3810 
3811         if( aBoxSet.Count() )
3812         {
3813             if( pSetPara->pUndo &&
3814                 SFX_ITEM_SET == aBoxSet.GetItemState( RES_BOXATR_FORMAT ))
3815                 pSetPara->pUndo->SaveBoxCntnt( *pSetBox );
3816 
3817             pSetBox->ClaimFrmFmt()->SetFmtAttr( aBoxSet );
3818         }
3819     }
3820     else
3821         ((_FndBox*&)rpBox)->GetLines().ForEach( &lcl_SetAFmtLine, pPara );
3822 
3823     if( !rpBox->GetUpper()->GetUpper() )        // eine BaseLine
3824         ++pSetPara->nCurBox;
3825     return sal_True;
3826 }
3827 
3828 
3829         // AutoFormat fuer die Tabelle/TabellenSelection
3830 sal_Bool SwDoc::SetTableAutoFmt( const SwSelBoxes& rBoxes, const SwTableAutoFmt& rNew )
3831 {
3832     ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
3833     SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
3834     if( !pTblNd )
3835         return sal_False;
3836 
3837     // suche alle Boxen / Lines
3838     _FndBox aFndBox( 0, 0 );
3839     {
3840         _FndPara aPara( rBoxes, &aFndBox );
3841         pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
3842     }
3843     if( !aFndBox.GetLines().Count() )
3844         return sal_False;
3845 
3846     pTblNd->GetTable().SetHTMLTableLayout( 0 );
3847 
3848     _FndBox* pFndBox = &aFndBox;
3849     while( 1 == pFndBox->GetLines().Count() &&
3850             1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
3851         pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
3852 
3853     if( !pFndBox->GetLines().Count() )      // eine zu weit? (nur 1 sel.Box)
3854         pFndBox = pFndBox->GetUpper()->GetUpper();
3855 
3856 
3857     // Undo abschalten, Attribute werden sich vorher gemerkt
3858     SwUndoTblAutoFmt* pUndo = 0;
3859     bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
3860     if (bUndo)
3861     {
3862         pUndo = new SwUndoTblAutoFmt( *pTblNd, rNew );
3863         GetIDocumentUndoRedo().AppendUndo(pUndo);
3864         GetIDocumentUndoRedo().DoUndo(false);
3865     }
3866 
3867     _SetAFmtTabPara aPara( rNew );
3868     _FndLines& rFLns = pFndBox->GetLines();
3869     _FndLine* pLine;
3870 
3871     for( sal_uInt16 n = 0; n < rFLns.Count(); ++n )
3872     {
3873         pLine = rFLns[n];
3874 
3875         // Upper auf 0 setzen (Base-Line simulieren!)
3876         _FndBox* pSaveBox = pLine->GetUpper();
3877         pLine->SetUpper( 0 );
3878 
3879         if( !n )
3880             aPara.nAFmtLine = 0;
3881         else if( n+1 == rFLns.Count() )
3882             aPara.nAFmtLine = 3;
3883         else
3884             aPara.nAFmtLine = (sal_uInt8)(1 + ((n-1) & 1 ));
3885 
3886         aPara.nAFmtBox = 0;
3887         aPara.nCurBox = 0;
3888         aPara.nEndBox = pLine->GetBoxes().Count()-1;
3889         aPara.pUndo = pUndo;
3890         pLine->GetBoxes().ForEach( &lcl_SetAFmtBox, &aPara );
3891 
3892         pLine->SetUpper( pSaveBox );
3893     }
3894 
3895     if( pUndo )
3896     {
3897         GetIDocumentUndoRedo().DoUndo(bUndo);
3898     }
3899 
3900     SetModified();
3901     SetFieldsDirty( true, NULL, 0 );
3902 
3903     return sal_True;
3904 }
3905 
3906 
3907         // Erfrage wie attributiert ist
3908 sal_Bool SwDoc::GetTableAutoFmt( const SwSelBoxes& rBoxes, SwTableAutoFmt& rGet )
3909 {
3910     ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
3911     SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
3912     if( !pTblNd )
3913         return sal_False;
3914 
3915     // suche alle Boxen / Lines
3916     _FndBox aFndBox( 0, 0 );
3917     {
3918         _FndPara aPara( rBoxes, &aFndBox );
3919         pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
3920     }
3921     if( !aFndBox.GetLines().Count() )
3922         return sal_False;
3923 
3924     _FndBox* pFndBox = &aFndBox;
3925     while( 1 == pFndBox->GetLines().Count() &&
3926             1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
3927         pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
3928 
3929     if( !pFndBox->GetLines().Count() )      // eine zu weit? (nur 1 sel.Box)
3930         pFndBox = pFndBox->GetUpper()->GetUpper();
3931 
3932     _FndLines& rFLns = pFndBox->GetLines();
3933 
3934     sal_uInt16 aLnArr[4];
3935     aLnArr[0] = 0;
3936     aLnArr[1] = 1 < rFLns.Count() ? 1 : 0;
3937     aLnArr[2] = 2 < rFLns.Count() ? 2 : aLnArr[1];
3938     aLnArr[3] = rFLns.Count() - 1;
3939 
3940     for( sal_uInt8 nLine = 0; nLine < 4; ++nLine )
3941     {
3942         _FndLine& rLine = *rFLns[ aLnArr[ nLine ] ];
3943 
3944         sal_uInt16 aBoxArr[4];
3945         aBoxArr[0] = 0;
3946         aBoxArr[1] = 1 < rLine.GetBoxes().Count() ? 1 : 0;
3947         aBoxArr[2] = 2 < rLine.GetBoxes().Count() ? 2 : aBoxArr[1];
3948         aBoxArr[3] = rLine.GetBoxes().Count() - 1;
3949 
3950         for( sal_uInt8 nBox = 0; nBox < 4; ++nBox )
3951         {
3952             SwTableBox* pFBox = rLine.GetBoxes()[ aBoxArr[ nBox ] ]->GetBox();
3953             // immer auf die 1. runterfallen
3954             while( !pFBox->GetSttNd() )
3955                 pFBox = pFBox->GetTabLines()[0]->GetTabBoxes()[0];
3956 
3957             sal_uInt8 nPos = nLine * 4 + nBox;
3958             SwNodeIndex aIdx( *pFBox->GetSttNd(), 1 );
3959             SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
3960             if( !pCNd )
3961                 pCNd = GetNodes().GoNext( &aIdx );
3962 
3963             if( pCNd )
3964                 rGet.UpdateFromSet( nPos, pCNd->GetSwAttrSet(),
3965                                     SwTableAutoFmt::UPDATE_CHAR, 0 );
3966             rGet.UpdateFromSet( nPos, pFBox->GetFrmFmt()->GetAttrSet(),
3967                                 SwTableAutoFmt::UPDATE_BOX,
3968                                 GetNumberFormatter( sal_True ) );
3969         }
3970     }
3971 
3972     return sal_True;
3973 }
3974 
3975 String SwDoc::GetUniqueTblName() const
3976 {
3977     ResId aId( STR_TABLE_DEFNAME, *pSwResMgr );
3978     String aName( aId );
3979     xub_StrLen nNmLen = aName.Len();
3980 
3981     sal_uInt16 nNum, nTmp, nFlagSize = ( pTblFrmFmtTbl->Count() / 8 ) +2;
3982     sal_uInt16 n;
3983 
3984     sal_uInt8* pSetFlags = new sal_uInt8[ nFlagSize ];
3985     memset( pSetFlags, 0, nFlagSize );
3986 
3987     for( n = 0; n < pTblFrmFmtTbl->Count(); ++n )
3988     {
3989         const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
3990         if( !pFmt->IsDefault() && IsUsed( *pFmt )  &&
3991             pFmt->GetName().Match( aName ) == nNmLen )
3992         {
3993             // Nummer bestimmen und das Flag setzen
3994             nNum = static_cast<sal_uInt16>(pFmt->GetName().Copy( nNmLen ).ToInt32());
3995             if( nNum-- && nNum < pTblFrmFmtTbl->Count() )
3996                 pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
3997         }
3998     }
3999 
4000     // alle Nummern entsprechend geflag, also bestimme die richtige Nummer
4001     nNum = pTblFrmFmtTbl->Count();
4002     for( n = 0; n < nFlagSize; ++n )
4003         if( 0xff != ( nTmp = pSetFlags[ n ] ))
4004         {
4005             // also die Nummer bestimmen
4006             nNum = n * 8;
4007             while( nTmp & 1 )
4008                 ++nNum, nTmp >>= 1;
4009             break;
4010         }
4011 
4012     delete [] pSetFlags;
4013     return aName += String::CreateFromInt32( ++nNum );
4014 }
4015 
4016 SwTableFmt* SwDoc::FindTblFmtByName( const String& rName, sal_Bool bAll ) const
4017 {
4018     const SwFmt* pRet = 0;
4019     if( bAll )
4020         pRet = FindFmtByName( (SvPtrarr&)*pTblFrmFmtTbl, rName );
4021     else
4022     {
4023         // dann nur die, die im Doc gesetzt sind
4024         for( sal_uInt16 n = 0; n < pTblFrmFmtTbl->Count(); ++n )
4025         {
4026             const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
4027             if( !pFmt->IsDefault() && IsUsed( *pFmt ) &&
4028                 pFmt->GetName() == rName )
4029             {
4030                 pRet = pFmt;
4031                 break;
4032             }
4033         }
4034     }
4035     return (SwTableFmt*)pRet;
4036 }
4037 
4038 sal_Bool SwDoc::SetColRowWidthHeight( SwTableBox& rAktBox, sal_uInt16 eType,
4039                                     SwTwips nAbsDiff, SwTwips nRelDiff )
4040 {
4041     SwTableNode* pTblNd = (SwTableNode*)rAktBox.GetSttNd()->FindTableNode();
4042     SwUndo* pUndo = 0;
4043 
4044     if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType && pTblNd->GetTable().ISA( SwDDETable ))
4045         return sal_False;
4046 
4047     SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
4048     aMsgHnt.eFlags = TBL_BOXPTR;
4049     UpdateTblFlds( &aMsgHnt );
4050 
4051     bool const bUndo(GetIDocumentUndoRedo().DoesUndo());
4052     sal_Bool bRet = sal_False;
4053     switch( eType & 0xff )
4054     {
4055     case nsTblChgWidthHeightType::WH_COL_LEFT:
4056     case nsTblChgWidthHeightType::WH_COL_RIGHT:
4057     case nsTblChgWidthHeightType::WH_CELL_LEFT:
4058     case nsTblChgWidthHeightType::WH_CELL_RIGHT:
4059         {
4060              bRet = pTblNd->GetTable().SetColWidth( rAktBox,
4061                                 eType, nAbsDiff, nRelDiff,
4062                                 (bUndo) ? &pUndo : 0 );
4063         }
4064         break;
4065     case nsTblChgWidthHeightType::WH_ROW_TOP:
4066     case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
4067     case nsTblChgWidthHeightType::WH_CELL_TOP:
4068     case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
4069         bRet = pTblNd->GetTable().SetRowHeight( rAktBox,
4070                             eType, nAbsDiff, nRelDiff,
4071                             (bUndo) ? &pUndo : 0 );
4072         break;
4073     }
4074 
4075     GetIDocumentUndoRedo().DoUndo(bUndo); // SetColWidth can turn it off
4076     if( pUndo )
4077     {
4078         GetIDocumentUndoRedo().AppendUndo( pUndo );
4079     }
4080 
4081     if( bRet )
4082     {
4083         SetModified();
4084         if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType )
4085             SetFieldsDirty( true, NULL, 0 );
4086     }
4087     return bRet;
4088 }
4089 
4090 
4091 void SwDoc::ChkBoxNumFmt( SwTableBox& rBox, sal_Bool bCallUpdate )
4092 {
4093     //JP 09.07.97: Optimierung: wenn die Box schon sagt, das es Text
4094     //                          sein soll, dann bleibt das auch Text!
4095     const SfxPoolItem* pNumFmtItem = 0;
4096     if( SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT,
4097         sal_False, &pNumFmtItem ) && GetNumberFormatter()->IsTextFormat(
4098             ((SwTblBoxNumFormat*)pNumFmtItem)->GetValue() ))
4099         return ;
4100 
4101     SwUndoTblNumFmt* pUndo = 0;
4102 
4103     sal_Bool bIsEmptyTxtNd, bChgd = sal_True;
4104     sal_uInt32 nFmtIdx;
4105     double fNumber;
4106     if( rBox.HasNumCntnt( fNumber, nFmtIdx, bIsEmptyTxtNd ) )
4107     {
4108         if( !rBox.IsNumberChanged() )
4109             bChgd = sal_False;
4110         else
4111         {
4112             if (GetIDocumentUndoRedo().DoesUndo())
4113             {
4114                 GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL );
4115                 pUndo = new SwUndoTblNumFmt( rBox );
4116                 pUndo->SetNumFmt( nFmtIdx, fNumber );
4117             }
4118 
4119             SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
4120             SfxItemSet aBoxSet( GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
4121 
4122             sal_Bool bSetNumFmt = IsInsTblFormatNum(), bLockModify = sal_True;
4123             if( bSetNumFmt )
4124             {
4125                 if( !IsInsTblChangeNumFormat() )
4126                 {
4127                     if( !pNumFmtItem )
4128                         bSetNumFmt = sal_False;
4129                     else
4130                     {
4131                         sal_uLong nOldNumFmt = ((SwTblBoxNumFormat*)pNumFmtItem)->
4132                                             GetValue();
4133                         SvNumberFormatter* pNumFmtr = GetNumberFormatter();
4134 
4135                         short nFmtType = pNumFmtr->GetType( nFmtIdx );
4136                         if( nFmtType == pNumFmtr->GetType( nOldNumFmt ) ||
4137                             NUMBERFORMAT_NUMBER == nFmtType )
4138                             // eingstelltes und vorgegebenes NumFormat
4139                             // stimmen ueberein -> altes Format beibehalten
4140                             nFmtIdx = nOldNumFmt;
4141                         else
4142                             // eingstelltes und vorgegebenes NumFormat
4143                             // stimmen nicht ueberein -> als Text einfuegen
4144                             bLockModify = bSetNumFmt = sal_False;
4145                     }
4146                 }
4147 
4148                 if( bSetNumFmt )
4149                 {
4150                     pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
4151 
4152                     aBoxSet.Put( SwTblBoxValue( fNumber ));
4153                     aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx ));
4154                 }
4155             }
4156 
4157             // JP 28.04.98: Nur Formel zuruecksetzen reicht nicht.
4158             //              Sorge dafuer, das der Text auch entsprechend
4159             //              formatiert wird!
4160 
4161             if( !bSetNumFmt && !bIsEmptyTxtNd && pNumFmtItem )
4162             {
4163                 // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
4164                 //              Sorge dafuer, das der Text auch entsprechend
4165                 //              formatiert wird!
4166                 pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
4167             }
4168 
4169             if( bLockModify ) pBoxFmt->LockModify();
4170             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
4171             if( bLockModify ) pBoxFmt->UnlockModify();
4172 
4173             if( bSetNumFmt )
4174                 pBoxFmt->SetFmtAttr( aBoxSet );
4175         }
4176     }
4177     else
4178     {
4179         // es ist keine Zahl
4180         const SfxPoolItem* pValueItem = 0, *pFmtItem = 0;
4181         SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
4182         if( SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_FORMAT,
4183                 sal_False, &pFmtItem ) ||
4184             SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_VALUE,
4185                 sal_False, &pValueItem ))
4186         {
4187             if (GetIDocumentUndoRedo().DoesUndo())
4188             {
4189                 GetIDocumentUndoRedo().StartUndo( UNDO_TABLE_AUTOFMT, NULL );
4190                 pUndo = new SwUndoTblNumFmt( rBox );
4191             }
4192 
4193             pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
4194 
4195             // alle Zahlenformate entfernen
4196             sal_uInt16 nWhich1 = RES_BOXATR_FORMULA;
4197             if( !bIsEmptyTxtNd )
4198                 //JP 15.01.99: dieser Teil wurde doch schon oben abgeprueft!
4199                 /* && pFmtItem && !GetNumberFormatter()->
4200                 IsTextFormat( ((SwTblBoxNumFormat*)pFmtItem)->GetValue() ) )*/
4201             {
4202                 nWhich1 = RES_BOXATR_FORMAT;
4203 
4204                 // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
4205                 //              Sorge dafuer, das der Text auch entsprechend
4206                 //              formatiert wird!
4207                 pBoxFmt->SetFmtAttr( *GetDfltAttr( nWhich1 ));
4208             }
4209             pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
4210         }
4211         else
4212             bChgd = sal_False;
4213     }
4214 
4215     if( bChgd )
4216     {
4217         if( pUndo )
4218         {
4219             pUndo->SetBox( rBox );
4220             GetIDocumentUndoRedo().AppendUndo(pUndo);
4221             GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
4222         }
4223 
4224         const SwTableNode* pTblNd = rBox.GetSttNd()->FindTableNode();
4225         if( bCallUpdate )
4226         {
4227             SwTableFmlUpdate aTblUpdate( &pTblNd->GetTable() );
4228             UpdateTblFlds( &aTblUpdate );
4229 
4230             // TL_CHART2: update charts (when cursor leaves cell and
4231             // automatic update is enabled)
4232             if (AUTOUPD_FIELD_AND_CHARTS == getFieldUpdateFlags(true))
4233                 pTblNd->GetTable().UpdateCharts();
4234         }
4235         SetModified();
4236     }
4237 }
4238 
4239 void SwDoc::SetTblBoxFormulaAttrs( SwTableBox& rBox, const SfxItemSet& rSet )
4240 {
4241     if (GetIDocumentUndoRedo().DoesUndo())
4242     {
4243         GetIDocumentUndoRedo().AppendUndo( new SwUndoTblNumFmt(rBox, &rSet) );
4244     }
4245 
4246     SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
4247     if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA ))
4248     {
4249         pBoxFmt->LockModify();
4250         pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE );
4251         pBoxFmt->UnlockModify();
4252     }
4253     else if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE ))
4254     {
4255         pBoxFmt->LockModify();
4256         pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
4257         pBoxFmt->UnlockModify();
4258     }
4259     pBoxFmt->SetFmtAttr( rSet );
4260     SetModified();
4261 }
4262 
4263 void SwDoc::ClearBoxNumAttrs( const SwNodeIndex& rNode )
4264 {
4265     SwStartNode* pSttNd;
4266     if( 0 != ( pSttNd = rNode.GetNode().
4267                                 FindSttNodeByType( SwTableBoxStartNode )) &&
4268         2 == pSttNd->EndOfSectionIndex() - pSttNd->GetIndex() )
4269     {
4270         SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().
4271                             GetTblBox( pSttNd->GetIndex() );
4272 
4273         const SfxPoolItem* pFmtItem = 0;
4274         const SfxItemSet& rSet = pBox->GetFrmFmt()->GetAttrSet();
4275         if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT, sal_False, &pFmtItem ) ||
4276             SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA, sal_False ) ||
4277             SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE, sal_False ))
4278         {
4279             if (GetIDocumentUndoRedo().DoesUndo())
4280             {
4281                 GetIDocumentUndoRedo().AppendUndo(new SwUndoTblNumFmt(*pBox));
4282             }
4283 
4284             SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
4285 
4286             //JP 01.09.97: TextFormate bleiben erhalten!
4287             sal_uInt16 nWhich1 = RES_BOXATR_FORMAT;
4288             if( pFmtItem && GetNumberFormatter()->IsTextFormat(
4289                     ((SwTblBoxNumFormat*)pFmtItem)->GetValue() ))
4290                 nWhich1 = RES_BOXATR_FORMULA;
4291             else
4292                 // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
4293                 //              Sorge dafuer, das der Text auch entsprechend
4294                 //              formatiert wird!
4295                 pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
4296 
4297             pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
4298             SetModified();
4299         }
4300     }
4301 }
4302 
4303 // kopiert eine Tabelle aus dem selben oder einem anderen Doc in sich
4304 // selbst. Dabei wird eine neue Tabelle angelegt oder eine bestehende
4305 // mit dem Inhalt gefuellt; wobei entweder der Inhalt ab einer Box oder
4306 // in eine bestehende TblSelektion gefuellt wird.
4307 // Gerufen wird es von: edglss.cxx/fecopy.cxx
4308 
4309 sal_Bool SwDoc::InsCopyOfTbl( SwPosition& rInsPos, const SwSelBoxes& rBoxes,
4310                         const SwTable* pCpyTbl, sal_Bool bCpyName, sal_Bool bCorrPos )
4311 {
4312     sal_Bool bRet;
4313 
4314     const SwTableNode* pSrcTblNd = pCpyTbl
4315             ? pCpyTbl->GetTableNode()
4316             : rBoxes[ 0 ]->GetSttNd()->FindTableNode();
4317 
4318     SwTableNode * pInsTblNd = rInsPos.nNode.GetNode().FindTableNode();
4319 
4320     bool const bUndo( GetIDocumentUndoRedo().DoesUndo() );
4321     if( !pCpyTbl && !pInsTblNd )
4322     {
4323         SwUndoCpyTbl* pUndo = 0;
4324         if (bUndo)
4325         {
4326             GetIDocumentUndoRedo().ClearRedo();
4327             pUndo = new SwUndoCpyTbl;
4328         }
4329 
4330         {
4331             ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
4332             bRet = pSrcTblNd->GetTable().MakeCopy( this, rInsPos, rBoxes,
4333                                                 sal_True, bCpyName );
4334         }
4335 
4336         if( pUndo )
4337         {
4338             if( !bRet )
4339             {
4340                 delete pUndo;
4341                 pUndo = 0;
4342             }
4343             else
4344             {
4345                 pInsTblNd = GetNodes()[ rInsPos.nNode.GetIndex() - 1 ]->FindTableNode();
4346 
4347                 pUndo->SetTableSttIdx( pInsTblNd->GetIndex() );
4348                 GetIDocumentUndoRedo().AppendUndo( pUndo );
4349             }
4350         }
4351     }
4352     else
4353     {
4354         RedlineMode_t eOld = GetRedlineMode();
4355         if( IsRedlineOn() )
4356       SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON |
4357                                   nsRedlineMode_t::REDLINE_SHOW_INSERT |
4358                                   nsRedlineMode_t::REDLINE_SHOW_DELETE));
4359 
4360         SwUndoTblCpyTbl* pUndo = 0;
4361         if (bUndo)
4362         {
4363             GetIDocumentUndoRedo().ClearRedo();
4364             pUndo = new SwUndoTblCpyTbl;
4365             GetIDocumentUndoRedo().DoUndo(false);
4366         }
4367 
4368         SwDoc* pCpyDoc = (SwDoc*)pSrcTblNd->GetDoc();
4369         sal_Bool bDelCpyDoc = pCpyDoc == this;
4370 
4371         if( bDelCpyDoc )
4372         {
4373             // kopiere die Tabelle erstmal in ein temp. Doc
4374             pCpyDoc = new SwDoc;
4375             pCpyDoc->acquire();
4376 
4377             SwPosition aPos( SwNodeIndex( pCpyDoc->GetNodes().GetEndOfContent() ));
4378             if( !pSrcTblNd->GetTable().MakeCopy( pCpyDoc, aPos, rBoxes, sal_True, sal_True ))
4379             {
4380                 if( pCpyDoc->release() == 0 )
4381                     delete pCpyDoc;
4382 
4383                 if( pUndo )
4384                 {
4385                     GetIDocumentUndoRedo().DoUndo(bUndo);
4386                     delete pUndo;
4387                     pUndo = 0;
4388                 }
4389                 return sal_False;
4390             }
4391             aPos.nNode -= 1;        // auf den EndNode der Tabelle
4392             pSrcTblNd = aPos.nNode.GetNode().FindTableNode();
4393         }
4394 
4395         const SwStartNode* pSttNd = rInsPos.nNode.GetNode().FindTableBoxStartNode();
4396 
4397         rInsPos.nContent.Assign( 0, 0 );
4398 
4399         // no complex into complex, but copy into or from new model is welcome
4400         if( ( !pSrcTblNd->GetTable().IsTblComplex() || pInsTblNd->GetTable().IsNewModel() )
4401             && ( bDelCpyDoc || rBoxes.Count() ) )
4402         {
4403             // dann die Tabelle "relativ" kopieren
4404             const SwSelBoxes* pBoxes;
4405             SwSelBoxes aBoxes;
4406 
4407             if( bDelCpyDoc )
4408             {
4409                 SwTableBox* pBox = pInsTblNd->GetTable().GetTblBox(
4410                                         pSttNd->GetIndex() );
4411                 ASSERT( pBox, "Box steht nicht in dieser Tabelle" );
4412                 aBoxes.Insert( pBox );
4413                 pBoxes = &aBoxes;
4414             }
4415             else
4416                 pBoxes = &rBoxes;
4417 
4418             // kopiere die Tabelle in die selktierten Zellen.
4419             bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
4420                                                         *pBoxes, pUndo );
4421         }
4422         else
4423         {
4424             SwNodeIndex aNdIdx( *pSttNd, 1 );
4425             bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
4426                                                     aNdIdx, pUndo );
4427         }
4428 
4429         if( bDelCpyDoc )
4430         {
4431             if( pCpyDoc->release() == 0 )
4432                 delete pCpyDoc;
4433         }
4434 
4435         if( pUndo )
4436         {
4437             // falls die Tabelle nicht kopiert werden konnte, das Undo-Object
4438             // wieder loeschen
4439             GetIDocumentUndoRedo().DoUndo(bUndo);
4440             if( !bRet && pUndo->IsEmpty() )
4441                 delete pUndo;
4442             else
4443             {
4444                 GetIDocumentUndoRedo().AppendUndo(pUndo);
4445             }
4446         }
4447 
4448         if( bCorrPos )
4449         {
4450             rInsPos.nNode = *pSttNd;
4451             rInsPos.nContent.Assign( GetNodes().GoNext( &rInsPos.nNode ), 0 );
4452         }
4453         SetRedlineMode( eOld );
4454     }
4455 
4456     if( bRet )
4457     {
4458         SetModified();
4459         SetFieldsDirty( true, NULL, 0 );
4460     }
4461     return bRet;
4462 }
4463 
4464 
4465 
4466 sal_Bool SwDoc::_UnProtectTblCells( SwTable& rTbl )
4467 {
4468     sal_Bool bChgd = sal_False;
4469     SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
4470         ?   new SwUndoAttrTbl( *rTbl.GetTableNode() )
4471         :   0;
4472 
4473     SwTableSortBoxes& rSrtBox = rTbl.GetTabSortBoxes();
4474     for( sal_uInt16 i = rSrtBox.Count(); i; )
4475     {
4476         SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
4477         if( pBoxFmt->GetProtect().IsCntntProtected() )
4478         {
4479             pBoxFmt->ResetFmtAttr( RES_PROTECT );
4480             bChgd = sal_True;
4481         }
4482     }
4483 
4484     if( pUndo )
4485     {
4486         if( bChgd )
4487         {
4488             GetIDocumentUndoRedo().AppendUndo( pUndo );
4489         }
4490         else
4491             delete pUndo;
4492     }
4493     return bChgd;
4494 }
4495 
4496 
4497 sal_Bool SwDoc::UnProtectCells( const String& rName )
4498 {
4499     sal_Bool bChgd = sal_False;
4500     SwTableFmt* pFmt = FindTblFmtByName( rName );
4501     if( pFmt )
4502     {
4503         bChgd = _UnProtectTblCells( *SwTable::FindTable( pFmt ) );
4504         if( bChgd )
4505             SetModified();
4506     }
4507 
4508     return bChgd;
4509 }
4510 
4511 sal_Bool SwDoc::UnProtectCells( const SwSelBoxes& rBoxes )
4512 {
4513     sal_Bool bChgd = sal_False;
4514     if( rBoxes.Count() )
4515     {
4516         SwUndoAttrTbl *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
4517                 ? new SwUndoAttrTbl( *rBoxes[0]->GetSttNd()->FindTableNode() )
4518                 : 0;
4519 
4520         SvPtrarr aFmts( 16 ), aNewFmts( 16 );
4521         for( sal_uInt16 i = rBoxes.Count(); i; )
4522         {
4523             SwTableBox* pBox = rBoxes[ --i ];
4524             SwFrmFmt* pBoxFmt = pBox->GetFrmFmt();
4525             if( pBoxFmt->GetProtect().IsCntntProtected() )
4526             {
4527                 sal_uInt16 nFnd = aFmts.GetPos( pBoxFmt );
4528                 if( USHRT_MAX != nFnd )
4529                     pBox->ChgFrmFmt( (SwTableBoxFmt*)aNewFmts[ nFnd ] );
4530                 else
4531                 {
4532                     aFmts.Insert( pBoxFmt, aFmts.Count() );
4533                     pBoxFmt = pBox->ClaimFrmFmt();
4534                     pBoxFmt->ResetFmtAttr( RES_PROTECT );
4535                     aNewFmts.Insert( pBoxFmt, aNewFmts.Count() );
4536                 }
4537                 bChgd = sal_True;
4538             }
4539         }
4540 
4541         if( pUndo )
4542         {
4543             if( bChgd )
4544             {
4545                 GetIDocumentUndoRedo().AppendUndo( pUndo );
4546             }
4547             else
4548                 delete pUndo;
4549         }
4550     }
4551     return bChgd;
4552 }
4553 
4554 sal_Bool SwDoc::UnProtectTbls( const SwPaM& rPam )
4555 {
4556     GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
4557 
4558     sal_Bool bChgd = sal_False, bHasSel = rPam.HasMark() ||
4559                                     rPam.GetNext() != (SwPaM*)&rPam;
4560     SwFrmFmts& rFmts = *GetTblFrmFmts();
4561     SwTable* pTbl;
4562     const SwTableNode* pTblNd;
4563     for( sal_uInt16 n = rFmts.Count(); n ; )
4564         if( 0 != (pTbl = SwTable::FindTable( rFmts[ --n ] )) &&
4565             0 != (pTblNd = pTbl->GetTableNode() ) &&
4566             pTblNd->GetNodes().IsDocNodes() )
4567         {
4568             sal_uLong nTblIdx = pTblNd->GetIndex();
4569 
4570             // dann ueberpruefe ob Tabelle in der Selection liegt
4571             if( bHasSel )
4572             {
4573                 int bFound = sal_False;
4574                 SwPaM* pTmp = (SwPaM*)&rPam;
4575                 do {
4576                     const SwPosition *pStt = pTmp->Start(),
4577                                     *pEnd = pTmp->End();
4578                     bFound = pStt->nNode.GetIndex() < nTblIdx &&
4579                             nTblIdx < pEnd->nNode.GetIndex();
4580 
4581                 } while( !bFound && &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ) );
4582                 if( !bFound )
4583                     continue;       // weitersuchen
4584             }
4585 
4586             // dann mal den Schutz aufheben
4587             bChgd |= _UnProtectTblCells( *pTbl );
4588         }
4589 
4590     GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
4591     if( bChgd )
4592         SetModified();
4593 
4594     return bChgd;
4595 }
4596 
4597 sal_Bool SwDoc::HasTblAnyProtection( const SwPosition* pPos,
4598                                  const String* pTblName,
4599                                  sal_Bool* pFullTblProtection )
4600 {
4601     sal_Bool bHasProtection = sal_False;
4602     SwTable* pTbl = 0;
4603     if( pTblName )
4604         pTbl = SwTable::FindTable( FindTblFmtByName( *pTblName ) );
4605     else if( pPos )
4606     {
4607         SwTableNode* pTblNd = pPos->nNode.GetNode().FindTableNode();
4608         if( pTblNd )
4609             pTbl = &pTblNd->GetTable();
4610     }
4611 
4612     if( pTbl )
4613     {
4614         SwTableSortBoxes& rSrtBox = pTbl->GetTabSortBoxes();
4615         for( sal_uInt16 i = rSrtBox.Count(); i; )
4616         {
4617             SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
4618             if( pBoxFmt->GetProtect().IsCntntProtected() )
4619             {
4620                 if( !bHasProtection )
4621                 {
4622                     bHasProtection = sal_True;
4623                     if( !pFullTblProtection )
4624                         break;
4625                     *pFullTblProtection = sal_True;
4626                 }
4627             }
4628             else if( bHasProtection && pFullTblProtection )
4629             {
4630                 *pFullTblProtection = sal_False;
4631                 break;
4632             }
4633         }
4634     }
4635     return bHasProtection;
4636 }
4637 
4638 #ifdef DEL_TABLE_REDLINES
4639 lcl_DelRedlines::lcl_DelRedlines( const SwTableNode& rNd,
4640                                     sal_Bool bCheckForOwnRedline )
4641     : pDoc( (SwDoc*)rNd.GetNodes().GetDoc() )
4642 {
4643     pDoc->StartUndo(UNDO_EMPTY, NULL);
4644     const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
4645     if( !pDoc->IsIgnoreRedline() && rTbl.Count() )
4646     {
4647         sal_Bool bDelete = sal_True;
4648         if( bCheckForOwnRedline )
4649         {
4650             sal_uInt16 nRedlPos = pDoc->GetRedlinePos( rNd, USHRT_MAX );
4651             sal_uInt32 nSttNd = rNd.GetIndex(),
4652                        nEndNd = rNd.EndOfSectionIndex();
4653 
4654             for ( ; nRedlPos < rTbl.Count(); ++nRedlPos )
4655             {
4656                 const SwRedline* pRedline = rTbl[ nRedlPos ];
4657                 const SwPosition* pStt = pRedline->Start(),
4658                                 * pEnd = pStt == pRedline->GetPoint()
4659                                                     ? pRedline->GetMark()
4660                                                     : pRedline->GetPoint();
4661                 if( pStt->nNode <= nSttNd )
4662                 {
4663                     if( pEnd->nNode >= nEndNd &&
4664                         pRedline->GetAuthor() == pDoc->GetRedlineAuthor() )
4665                     {
4666                         bDelete = sal_False;
4667                         break;
4668                     }
4669                 }
4670                 else
4671                     break;
4672             }
4673         }
4674         if( bDelete )
4675         {
4676             SwPaM aPam(*rNd.EndOfSectionNode(), rNd);
4677             pDoc->AcceptRedline( aPam, true );
4678         }
4679     }
4680 }
4681 #endif
4682 
4683 
4684