xref: /AOO41X/main/sw/source/core/undo/untbl.cxx (revision 69a743679e823ad8f875be547552acb607b8ada5)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 #include <UndoTable.hxx>
28 
29 #include <UndoRedline.hxx>
30 #include <UndoDelete.hxx>
31 #include <UndoSplitMove.hxx>
32 #include <UndoCore.hxx>
33 #include <hintids.hxx>
34 #include <hints.hxx>
35 #include <editeng/brkitem.hxx>
36 #include <fmtornt.hxx>
37 #include <fmtpdsc.hxx>
38 #include <doc.hxx>
39 #include <IDocumentUndoRedo.hxx>
40 #include <editsh.hxx>
41 #include <docary.hxx>
42 #include <ndtxt.hxx>
43 #include <swtable.hxx>
44 #include <pam.hxx>
45 #include <cntfrm.hxx>
46 #include <tblsel.hxx>
47 #include <swundo.hxx>           // fuer die UndoIds
48 #include <rolbck.hxx>
49 #include <ddefld.hxx>
50 #include <tabcol.hxx>
51 #include <tabfrm.hxx>
52 #include <rowfrm.hxx>
53 #include <cellfrm.hxx>
54 #include <swcache.hxx>
55 #include <tblafmt.hxx>
56 #include <poolfmt.hxx>
57 #include <mvsave.hxx>
58 #include <cellatr.hxx>
59 #include <swtblfmt.hxx>
60 #include <swddetbl.hxx>
61 #include <redline.hxx>
62 #include <node2lay.hxx>
63 #include <tblrwcl.hxx>
64 #include <fmtanchr.hxx>
65 #include <comcore.hrc>
66 #include <unochart.hxx>
67 #include <switerator.hxx>
68 
69 #ifndef DBG_UTIL
70 #define CHECK_TABLE(t)
71 #else
72 #ifdef DEBUG
73 #define CHECK_TABLE(t) (t).CheckConsistency();
74 #else
75 #define CHECK_TABLE(t)
76 #endif
77 #endif
78 
79 #ifndef DBG_UTIL
80     #define _DEBUG_REDLINE( pDoc )
81 #else
82     void lcl_DebugRedline( const SwDoc* pDoc );
83     #define _DEBUG_REDLINE( pDoc ) lcl_DebugRedline( pDoc );
84 #endif
85 
86 extern void ClearFEShellTabCols();
87 
88 typedef SfxItemSet* SfxItemSetPtr;
89 SV_DECL_PTRARR_DEL( SfxItemSets, SfxItemSetPtr, 10, 5 )
90 
91 typedef SwUndoSaveSection* SwUndoSaveSectionPtr;
92 SV_DECL_PTRARR_DEL( SwUndoSaveSections, SwUndoSaveSectionPtr, 0, 10 )
93 
94 typedef SwUndoMove* SwUndoMovePtr;
95 SV_DECL_PTRARR_DEL( SwUndoMoves, SwUndoMovePtr, 0, 10 )
96 
97 struct SwTblToTxtSave;
98 typedef SwTblToTxtSave* SwTblToTxtSavePtr;
99 SV_DECL_PTRARR_DEL( SwTblToTxtSaves, SwTblToTxtSavePtr, 0, 10 )
100 
101 struct _UndoTblCpyTbl_Entry
102 {
103     sal_uLong nBoxIdx, nOffset;
104     SfxItemSet* pBoxNumAttr;
105     SwUndo* pUndo;
106 
107     // Was the last paragraph of the new and the first paragraph of the old content joined?
108     bool bJoin; // For redlining only
109 
110     _UndoTblCpyTbl_Entry( const SwTableBox& rBox );
111     ~_UndoTblCpyTbl_Entry();
112 };
113 typedef _UndoTblCpyTbl_Entry* _UndoTblCpyTbl_EntryPtr;
114 SV_DECL_PTRARR_DEL( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr, 0, 10 )
115 
116 class _SaveBox;
117 class _SaveLine;
118 
119 class _SaveTable
120 {
121     friend class _SaveBox;
122     friend class _SaveLine;
123     SfxItemSet aTblSet;
124     _SaveLine* pLine;
125     const SwTable* pSwTable;
126     SfxItemSets aSets;
127     SwFrmFmts aFrmFmts;
128     sal_uInt16 nLineCount;
129     sal_Bool bModifyBox : 1;
130     sal_Bool bSaveFormula : 1;
131     sal_Bool bNewModel : 1;
132 
133 public:
134     _SaveTable( const SwTable& rTbl, sal_uInt16 nLnCnt = USHRT_MAX,
135                 sal_Bool bSaveFml = sal_True );
136     ~_SaveTable();
137 
138     sal_uInt16 AddFmt( SwFrmFmt* pFmt, bool bIsLine );
139     void NewFrmFmt( const SwTableLine* , const SwTableBox*, sal_uInt16 nFmtPos,
140                     SwFrmFmt* pOldFmt );
141 
142     void RestoreAttr( SwTable& rTbl, sal_Bool bModifyBox = sal_False );
143     void SaveCntntAttrs( SwDoc* pDoc );
144     void CreateNew( SwTable& rTbl, sal_Bool bCreateFrms = sal_True,
145                     sal_Bool bRestoreChart = sal_True );
IsNewModel() const146     sal_Bool IsNewModel() const { return bNewModel; }
147 };
148 
149 class _SaveLine
150 {
151     friend class _SaveTable;
152     friend class _SaveBox;
153 
154     _SaveLine* pNext;
155     _SaveBox* pBox;
156     sal_uInt16 nItemSet;
157 
158 public:
159 
160     _SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl );
161     ~_SaveLine();
162 
163     void RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl );
164     void SaveCntntAttrs( SwDoc* pDoc );
165 
166     void CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl  );
167 };
168 
169 class _SaveBox
170 {
171     friend class _SaveLine;
172 
173     _SaveBox* pNext;
174     sal_uLong nSttNode;
175     long nRowSpan;
176     sal_uInt16 nItemSet;
177     union
178     {
179         SfxItemSets* pCntntAttrs;
180         _SaveLine* pLine;
181     } Ptrs;
182 
183 public:
184     _SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl );
185     ~_SaveBox();
186 
187     void RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl );
188     void SaveCntntAttrs( SwDoc* pDoc );
189 
190     void CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl );
191 };
192 
193 void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos = 0 );
194 void InsertSort( SvULongs& rArr, sal_uLong nIdx, sal_uInt16* pInsPos = 0 );
195 
196 #if defined( JP_DEBUG ) && defined(DBG_UTIL)
197 #include "shellio.hxx"
198 void DumpDoc( SwDoc* pDoc, const String& rFileNm );
199 void CheckTable( const SwTable& );
200 #define DUMPDOC(p,s)    DumpDoc( p, s);
201 #define CHECKTABLE(t) CheckTable( t );
202 #else
203 #define DUMPDOC(p,s)
204 #define CHECKTABLE(t)
205 #endif
206 
207 /* #130880: Crash in undo of table to text when the table has (freshly) merged cells
208 The order of cell content nodes in the nodes array is not given by the recursive table structure.
209 The algorithmn must not rely on this even it holds for a fresh loaded table in odt file format.
210 So we need to remember not only the start node position but the end node position as well.
211 */
212 
213 struct SwTblToTxtSave
214 {
215     sal_uLong m_nSttNd;
216     sal_uLong m_nEndNd;
217     xub_StrLen m_nCntnt;
218     SwHistory* m_pHstry;
219     // metadata references for first and last paragraph in cell
220     ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoStart;
221     ::boost::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndoEnd;
222 
223     SwTblToTxtSave( SwDoc& rDoc, sal_uLong nNd, sal_uLong nEndIdx, xub_StrLen nCntnt );
~SwTblToTxtSaveSwTblToTxtSave224     ~SwTblToTxtSave() { delete m_pHstry; }
225 };
226 
227 SV_IMPL_PTRARR( SfxItemSets, SfxItemSetPtr )
228 SV_IMPL_PTRARR( SwUndoSaveSections, SwUndoSaveSectionPtr )
229 SV_IMPL_PTRARR( SwUndoMoves, SwUndoMovePtr )
230 SV_IMPL_PTRARR( SwTblToTxtSaves, SwTblToTxtSavePtr )
231 SV_IMPL_PTRARR( _UndoTblCpyTbl_Entries, _UndoTblCpyTbl_EntryPtr )
232 
233 sal_uInt16 __FAR_DATA aSave_BoxCntntSet[] = {
234     RES_CHRATR_COLOR, RES_CHRATR_CROSSEDOUT,
235     RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
236     RES_CHRATR_POSTURE, RES_CHRATR_POSTURE,
237     RES_CHRATR_SHADOWED, RES_CHRATR_WEIGHT,
238     RES_PARATR_ADJUST, RES_PARATR_ADJUST,
239     0 };
240 
241 
242 
SwUndoInsTbl(const SwPosition & rPos,sal_uInt16 nCl,sal_uInt16 nRw,sal_uInt16 nAdj,const SwInsertTableOptions & rInsTblOpts,const SwTableAutoFmt * pTAFmt,const SvUShorts * pColArr,const String & rName)243 SwUndoInsTbl::SwUndoInsTbl( const SwPosition& rPos, sal_uInt16 nCl, sal_uInt16 nRw,
244                             sal_uInt16 nAdj, const SwInsertTableOptions& rInsTblOpts,
245                             const SwTableAutoFmt* pTAFmt,
246                             const SvUShorts* pColArr,
247                             const String & rName)
248     : SwUndo( UNDO_INSTABLE ),
249     aInsTblOpts( rInsTblOpts ), pDDEFldType( 0 ), pColWidth( 0 ), pRedlData( 0 ), pAutoFmt( 0 ),
250     nSttNode( rPos.nNode.GetIndex() ), nRows( nRw ), nCols( nCl ), nAdjust( nAdj )
251 {
252     if( pColArr )
253     {
254         pColWidth = new SvUShorts( 0, 1 );
255         pColWidth->Insert( pColArr, 0 );
256     }
257     if( pTAFmt )
258         pAutoFmt = new SwTableAutoFmt( *pTAFmt );
259 
260     // Redline beachten
261     SwDoc& rDoc = *rPos.nNode.GetNode().GetDoc();
262     if( rDoc.IsRedlineOn() )
263     {
264         pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, rDoc.GetRedlineAuthor() );
265         SetRedlineMode( rDoc.GetRedlineMode() );
266     }
267 
268     sTblNm = rName;
269 }
270 
271 
~SwUndoInsTbl()272 SwUndoInsTbl::~SwUndoInsTbl()
273 {
274     delete pDDEFldType;
275     delete pColWidth;
276     delete pRedlData;
277     delete pAutoFmt;
278 }
279 
UndoImpl(::sw::UndoRedoContext & rContext)280 void SwUndoInsTbl::UndoImpl(::sw::UndoRedoContext & rContext)
281 {
282     SwDoc & rDoc = rContext.GetDoc();
283     SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode );
284 
285     SwTableNode* pTblNd = aIdx.GetNode().GetTableNode();
286     ASSERT( pTblNd, "kein TabellenNode" );
287     pTblNd->DelFrms();
288 
289     if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
290         rDoc.DeleteRedline( *pTblNd, true, USHRT_MAX );
291     RemoveIdxFromSection( rDoc, nSttNode );
292 
293     // harte SeitenUmbrueche am nachfolgenden Node verschieben
294     SwCntntNode* pNextNd = rDoc.GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
295     if( pNextNd )
296     {
297         SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
298         const SfxPoolItem *pItem;
299 
300         if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
301             sal_False, &pItem ) )
302             pNextNd->SetAttr( *pItem );
303 
304         if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
305             sal_False, &pItem ) )
306             pNextNd->SetAttr( *pItem );
307     }
308 
309 
310     sTblNm = pTblNd->GetTable().GetFrmFmt()->GetName();
311     if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) )
312         pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()).
313                                         GetDDEFldType()->Copy();
314 
315     rDoc.GetNodes().Delete( aIdx, pTblNd->EndOfSectionIndex() -
316                                 aIdx.GetIndex() + 1 );
317 
318     SwPaM & rPam( rContext.GetCursorSupplier().CreateNewShellCursor() );
319     rPam.DeleteMark();
320     rPam.GetPoint()->nNode = aIdx;
321     rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), 0 );
322 }
323 
324 
RedoImpl(::sw::UndoRedoContext & rContext)325 void SwUndoInsTbl::RedoImpl(::sw::UndoRedoContext & rContext)
326 {
327     SwDoc & rDoc = rContext.GetDoc();
328 
329     SwPosition const aPos(SwNodeIndex(rDoc.GetNodes(), nSttNode));
330     const SwTable* pTbl = rDoc.InsertTable( aInsTblOpts, aPos, nRows, nCols,
331                                             nAdjust,
332                                             pAutoFmt, pColWidth );
333     ((SwFrmFmt*)pTbl->GetFrmFmt())->SetName( sTblNm );
334     SwTableNode* pTblNode = (SwTableNode*)rDoc.GetNodes()[nSttNode]->GetTableNode();
335 
336     if( pDDEFldType )
337     {
338         SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType(
339                                                             *pDDEFldType);
340         SwDDETable* pDDETbl = new SwDDETable( pTblNode->GetTable(), pNewType );
341         pTblNode->SetNewTable( pDDETbl );       // setze die DDE-Tabelle
342         delete pDDEFldType, pDDEFldType = 0;
343     }
344 
345     if( (pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) ||
346         ( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) &&
347             rDoc.GetRedlineTbl().Count() ))
348     {
349         SwPaM aPam( *pTblNode->EndOfSectionNode(), *pTblNode, 1 );
350         SwCntntNode* pCNd = aPam.GetCntntNode( sal_False );
351         if( pCNd )
352             aPam.GetMark()->nContent.Assign( pCNd, 0 );
353 
354         if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
355         {
356             RedlineMode_t eOld = rDoc.GetRedlineMode();
357             rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE));
358 
359             rDoc.AppendRedline( new SwRedline( *pRedlData, aPam ), true);
360             rDoc.SetRedlineMode_intern( eOld );
361         }
362         else
363             rDoc.SplitRedline( aPam );
364     }
365 }
366 
367 
RepeatImpl(::sw::RepeatContext & rContext)368 void SwUndoInsTbl::RepeatImpl(::sw::RepeatContext & rContext)
369 {
370     rContext.GetDoc().InsertTable(
371             aInsTblOpts, *rContext.GetRepeatPaM().GetPoint(),
372             nRows, nCols, nAdjust, pAutoFmt, pColWidth );
373 }
374 
GetRewriter() const375 SwRewriter SwUndoInsTbl::GetRewriter() const
376 {
377     SwRewriter aRewriter;
378 
379     aRewriter.AddRule(UNDO_ARG1, SW_RES(STR_START_QUOTE));
380     aRewriter.AddRule(UNDO_ARG2, sTblNm);
381     aRewriter.AddRule(UNDO_ARG3, SW_RES(STR_END_QUOTE));
382 
383     return aRewriter;
384 }
385 
386 // -----------------------------------------------------
387 
SwTblToTxtSave(SwDoc & rDoc,sal_uLong nNd,sal_uLong nEndIdx,xub_StrLen nCnt)388 SwTblToTxtSave::SwTblToTxtSave( SwDoc& rDoc, sal_uLong nNd, sal_uLong nEndIdx, xub_StrLen nCnt )
389     : m_nSttNd( nNd ), m_nEndNd( nEndIdx), m_nCntnt( nCnt ), m_pHstry( 0 )
390 {
391     // Attributierung des gejointen Node merken.
392     SwTxtNode* pNd = rDoc.GetNodes()[ nNd ]->GetTxtNode();
393     if( pNd )
394     {
395         m_pHstry = new SwHistory;
396 
397         m_pHstry->Add( pNd->GetTxtColl(), nNd, ND_TEXTNODE );
398         if ( pNd->GetpSwpHints() )
399         {
400             m_pHstry->CopyAttr( pNd->GetpSwpHints(), nNd, 0,
401                         pNd->GetTxt().Len(), false );
402         }
403         if( pNd->HasSwAttrSet() )
404             m_pHstry->CopyFmtAttr( *pNd->GetpSwAttrSet(), nNd );
405 
406         if( !m_pHstry->Count() )
407             delete m_pHstry, m_pHstry = 0;
408 
409         // METADATA: store
410         m_pMetadataUndoStart = pNd->CreateUndo();
411     }
412 
413     // we also need to store the metadata reference of the _last_ paragraph
414     // we subtract 1 to account for the removed cell start/end node pair
415     // (after SectionUp, the end of the range points to the node after the cell)
416     if ( nEndIdx - 1 > nNd )
417     {
418         SwTxtNode* pLastNode( rDoc.GetNodes()[ nEndIdx - 1 ]->GetTxtNode() );
419         if( pLastNode )
420         {
421             // METADATA: store
422             m_pMetadataUndoEnd = pLastNode->CreateUndo();
423         }
424     }
425 }
426 
SwUndoTblToTxt(const SwTable & rTbl,sal_Unicode cCh)427 SwUndoTblToTxt::SwUndoTblToTxt( const SwTable& rTbl, sal_Unicode cCh )
428     : SwUndo( UNDO_TABLETOTEXT ),
429     sTblNm( rTbl.GetFrmFmt()->GetName() ), pDDEFldType( 0 ), pHistory( 0 ),
430     nSttNd( 0 ), nEndNd( 0 ),
431     nAdjust( static_cast<sal_uInt16>(rTbl.GetFrmFmt()->GetHoriOrient().GetHoriOrient()) ),
432     cTrenner( cCh ), nHdlnRpt( rTbl.GetRowsToRepeat() )
433 {
434     pTblSave = new _SaveTable( rTbl );
435     pBoxSaves = new SwTblToTxtSaves( (sal_uInt8)rTbl.GetTabSortBoxes().Count() );
436 
437     if( rTbl.IsA( TYPE( SwDDETable ) ) )
438         pDDEFldType = (SwDDEFieldType*)((SwDDETable&)rTbl).GetDDEFldType()->Copy();
439 
440     bCheckNumFmt = rTbl.GetFrmFmt()->GetDoc()->IsInsTblFormatNum();
441 
442     pHistory = new SwHistory;
443     const SwTableNode* pTblNd = rTbl.GetTableNode();
444     sal_uLong nTblStt = pTblNd->GetIndex(), nTblEnd = pTblNd->EndOfSectionIndex();
445 
446     const SwSpzFrmFmts& rFrmFmtTbl = *pTblNd->GetDoc()->GetSpzFrmFmts();
447     for( sal_uInt16 n = 0; n < rFrmFmtTbl.Count(); ++n )
448     {
449         SwFrmFmt* pFmt = rFrmFmtTbl[ n ];
450         SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
451         SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
452         if (pAPos &&
453             ((FLY_AT_CHAR == pAnchor->GetAnchorId()) ||
454              (FLY_AT_PARA == pAnchor->GetAnchorId())) &&
455             nTblStt <= pAPos->nNode.GetIndex() &&
456             pAPos->nNode.GetIndex() < nTblEnd )
457         {
458             pHistory->Add( *pFmt );
459         }
460     }
461 
462     if( !pHistory->Count() )
463         delete pHistory, pHistory = 0;
464 }
465 
466 
~SwUndoTblToTxt()467 SwUndoTblToTxt::~SwUndoTblToTxt()
468 {
469     delete pDDEFldType;
470     delete pTblSave;
471     delete pBoxSaves;
472     delete pHistory;
473 }
474 
475 
476 
UndoImpl(::sw::UndoRedoContext & rContext)477 void SwUndoTblToTxt::UndoImpl(::sw::UndoRedoContext & rContext)
478 {
479     SwDoc & rDoc = rContext.GetDoc();
480     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
481 
482     SwNodeIndex aFrmIdx( rDoc.GetNodes(), nSttNd );
483     SwNodeIndex aEndIdx( rDoc.GetNodes(), nEndNd );
484 
485     pPam->GetPoint()->nNode = aFrmIdx;
486     pPam->SetMark();
487     pPam->GetPoint()->nNode = aEndIdx;
488     rDoc.DelNumRules( *pPam );
489     pPam->DeleteMark();
490 
491     // dann sammel mal alle Uppers ein
492     SwNode2Layout aNode2Layout( aFrmIdx.GetNode() );
493 
494     // erzeuge die TabelleNode Structur
495     SwTableNode* pTblNd = rDoc.GetNodes().UndoTableToText( nSttNd, nEndNd, *pBoxSaves );
496     pTblNd->GetTable().SetTableModel( pTblSave->IsNewModel() );
497     SwTableFmt* pTableFmt = rDoc.MakeTblFrmFmt( sTblNm, rDoc.GetDfltFrmFmt() );
498     pTblNd->GetTable().RegisterToFormat( *pTableFmt );
499     pTblNd->GetTable().SetRowsToRepeat( nHdlnRpt );
500 
501     // erzeuge die alte Tabellen Struktur
502     pTblSave->CreateNew( pTblNd->GetTable() );
503 
504     if( pDDEFldType )
505     {
506         SwDDEFieldType* pNewType = (SwDDEFieldType*)rDoc.InsertFldType(
507                                                             *pDDEFldType);
508         SwDDETable* pDDETbl = new SwDDETable( pTblNd->GetTable(), pNewType );
509         pTblNd->SetNewTable( pDDETbl, sal_False );      // setze die DDE-Tabelle
510         delete pDDEFldType, pDDEFldType = 0;
511     }
512 
513     if( bCheckNumFmt )
514     {
515         SwTableSortBoxes& rBxs = pTblNd->GetTable().GetTabSortBoxes();
516         for( sal_uInt16 nBoxes = rBxs.Count(); nBoxes; )
517             rDoc.ChkBoxNumFmt( *rBxs[ --nBoxes ], sal_False );
518     }
519 
520     if( pHistory )
521     {
522         sal_uInt16 nTmpEnd = pHistory->GetTmpEnd();
523         pHistory->TmpRollback( &rDoc, 0 );
524         pHistory->SetTmpEnd( nTmpEnd );
525     }
526 
527     aNode2Layout.RestoreUpperFrms( rDoc.GetNodes(),
528                                    pTblNd->GetIndex(), pTblNd->GetIndex()+1 );
529 
530     // will man eine TabellenSelektion ??
531     pPam->DeleteMark();
532     pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode();
533     pPam->SetMark();
534     pPam->GetPoint()->nNode = *pPam->GetNode()->StartOfSectionNode();
535     pPam->Move( fnMoveForward, fnGoCntnt );
536     pPam->Exchange();
537     pPam->Move( fnMoveBackward, fnGoCntnt );
538 
539     ClearFEShellTabCols();
540 }
541 
542     // steht im untbl.cxx und darf nur vom Undoobject gerufen werden
UndoTableToText(sal_uLong nSttNd,sal_uLong nEndNd,const SwTblToTxtSaves & rSavedData)543 SwTableNode* SwNodes::UndoTableToText( sal_uLong nSttNd, sal_uLong nEndNd,
544                                 const SwTblToTxtSaves& rSavedData )
545 {
546     SwNodeIndex aSttIdx( *this, nSttNd );
547     SwNodeIndex aEndIdx( *this, nEndNd+1 );
548 
549     SwTableNode * pTblNd = new SwTableNode( aSttIdx );
550     SwEndNode* pEndNd = new SwEndNode( aEndIdx, *pTblNd  );
551 
552     aEndIdx = *pEndNd;
553 
554     /* Set pTblNd as start of section for all nodes in [nSttNd, nEndNd].
555        Delete all Frames attached to the nodes in that range. */
556     SwNode* pNd;
557     {
558         sal_uLong n, nTmpEnd = aEndIdx.GetIndex();
559         for( n = pTblNd->GetIndex() + 1; n < nTmpEnd; ++n )
560         {
561             if( ( pNd = (*this)[ n ] )->IsCntntNode() )
562                 ((SwCntntNode*)pNd)->DelFrms();
563             pNd->pStartOfSection = pTblNd;
564         }
565     }
566 
567     // dann die Tabellen Struktur teilweise aufbauen. Erstmal eine Line
568     // in der alle Boxen stehen! Die korrekte Struktur kommt dann aus der
569     // SaveStruct
570     SwTableBoxFmt* pBoxFmt = GetDoc()->MakeTableBoxFmt();
571     SwTableLineFmt* pLineFmt = GetDoc()->MakeTableLineFmt();
572     SwTableLine* pLine = new SwTableLine( pLineFmt, rSavedData.Count(), 0 );
573     pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pLine, 0 );
574 
575     SvULongs aBkmkArr( 0, 4 );
576     for( sal_uInt16 n = rSavedData.Count(); n; )
577     {
578         SwTblToTxtSave* pSave = rSavedData[ --n ];
579         // if the start node was merged with last from prev. cell,
580         // subtract 1 from index to get the merged paragraph, and split that
581         aSttIdx = pSave->m_nSttNd - ( ( USHRT_MAX != pSave->m_nCntnt ) ? 1 : 0);
582         SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
583 
584         if( USHRT_MAX != pSave->m_nCntnt )
585         {
586             // an der ContentPosition splitten, das vorherige Zeichen
587             // loeschen (ist der Trenner!)
588             ASSERT( pTxtNd, "Wo ist der TextNode geblieben?" );
589             SwIndex aCntPos( pTxtNd, pSave->m_nCntnt - 1 );
590 
591             pTxtNd->EraseText( aCntPos, 1 );
592             SwCntntNode* pNewNd = pTxtNd->SplitCntntNode(
593                                         SwPosition( aSttIdx, aCntPos ));
594             if( aBkmkArr.Count() )
595                 _RestoreCntntIdx( aBkmkArr, *pNewNd, pSave->m_nCntnt,
596                                                      pSave->m_nCntnt + 1 );
597         }
598         else
599         {
600             if( aBkmkArr.Count() )
601                 aBkmkArr.Remove( 0, aBkmkArr.Count() );
602             if( pTxtNd )
603                 _SaveCntntIdx( GetDoc(), aSttIdx.GetIndex(),
604                                 pTxtNd->GetTxt().Len(), aBkmkArr );
605         }
606 
607         if( pTxtNd )
608         {
609             // METADATA: restore
610             pTxtNd->GetTxtNode()->RestoreMetadata(pSave->m_pMetadataUndoStart);
611             if( pTxtNd->HasSwAttrSet() )
612                 pTxtNd->ResetAllAttr();
613 
614             if( pTxtNd->GetpSwpHints() )
615                 pTxtNd->ClearSwpHintsArr( false );
616         }
617 
618         if( pSave->m_pHstry )
619         {
620             sal_uInt16 nTmpEnd = pSave->m_pHstry->GetTmpEnd();
621             pSave->m_pHstry->TmpRollback( GetDoc(), 0 );
622             pSave->m_pHstry->SetTmpEnd( nTmpEnd );
623         }
624 
625         // METADATA: restore
626         // end points to node after cell
627         if ( pSave->m_nEndNd - 1 > pSave->m_nSttNd )
628         {
629             SwTxtNode* pLastNode = (*this)[ pSave->m_nEndNd - 1 ]->GetTxtNode();
630             if (pLastNode)
631             {
632                 pLastNode->RestoreMetadata(pSave->m_pMetadataUndoEnd);
633             }
634         }
635 
636         aEndIdx = pSave->m_nEndNd;
637         SwStartNode* pSttNd = new SwStartNode( aSttIdx, ND_STARTNODE,
638                                                 SwTableBoxStartNode );
639         pSttNd->pStartOfSection = pTblNd;
640         new SwEndNode( aEndIdx, *pSttNd );
641 
642         for( sal_uLong i = aSttIdx.GetIndex(); i < aEndIdx.GetIndex()-1; ++i )
643         {
644             pNd = (*this)[ i ];
645             pNd->pStartOfSection = pSttNd;
646             if( pNd->IsStartNode() )
647                 i = pNd->EndOfSectionIndex();
648         }
649 
650         SwTableBox* pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
651         pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, 0 );
652     }
653     return pTblNd;
654 }
655 
656 
RedoImpl(::sw::UndoRedoContext & rContext)657 void SwUndoTblToTxt::RedoImpl(::sw::UndoRedoContext & rContext)
658 {
659     SwDoc & rDoc = rContext.GetDoc();
660     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
661 
662     pPam->GetPoint()->nNode = nSttNd;
663     pPam->GetPoint()->nContent.Assign( 0, 0 );
664     SwNodeIndex aSaveIdx( pPam->GetPoint()->nNode, -1 );
665 
666     pPam->SetMark();            // alle Indizies abmelden
667     pPam->DeleteMark();
668 
669     SwTableNode* pTblNd = pPam->GetNode()->GetTableNode();
670     ASSERT( pTblNd, "keinen TableNode gefunden" );
671 
672     if( pTblNd->GetTable().IsA( TYPE( SwDDETable )) )
673         pDDEFldType = (SwDDEFieldType*)((SwDDETable&)pTblNd->GetTable()).
674                                                 GetDDEFldType()->Copy();
675 
676     rDoc.TableToText( pTblNd, cTrenner );
677 
678     aSaveIdx++;
679     SwCntntNode* pCNd = aSaveIdx.GetNode().GetCntntNode();
680     if( !pCNd && 0 == ( pCNd = rDoc.GetNodes().GoNext( &aSaveIdx ) ) &&
681         0 == ( pCNd = rDoc.GetNodes().GoPrevious( &aSaveIdx )) )
682     {
683         ASSERT( sal_False, "wo steht denn nun der TextNode" );
684     }
685 
686     pPam->GetPoint()->nNode = aSaveIdx;
687     pPam->GetPoint()->nContent.Assign( pCNd, 0 );
688 
689     pPam->SetMark();            // alle Indizies abmelden
690     pPam->DeleteMark();
691 }
692 
693 
RepeatImpl(::sw::RepeatContext & rContext)694 void SwUndoTblToTxt::RepeatImpl(::sw::RepeatContext & rContext)
695 {
696     SwPaM *const pPam = & rContext.GetRepeatPaM();
697     SwTableNode *const pTblNd = pPam->GetNode()->FindTableNode();
698     if( pTblNd )
699     {
700         // move cursor out of table
701         pPam->GetPoint()->nNode = *pTblNd->EndOfSectionNode();
702         pPam->Move( fnMoveForward, fnGoCntnt );
703         pPam->SetMark();
704         pPam->DeleteMark();
705 
706         rContext.GetDoc().TableToText( pTblNd, cTrenner );
707     }
708 }
709 
SetRange(const SwNodeRange & rRg)710 void SwUndoTblToTxt::SetRange( const SwNodeRange& rRg )
711 {
712     nSttNd = rRg.aStart.GetIndex();
713     nEndNd = rRg.aEnd.GetIndex();
714 }
715 
AddBoxPos(SwDoc & rDoc,sal_uLong nNdIdx,sal_uLong nEndIdx,xub_StrLen nCntntIdx)716 void SwUndoTblToTxt::AddBoxPos( SwDoc& rDoc, sal_uLong nNdIdx, sal_uLong nEndIdx, xub_StrLen nCntntIdx )
717 {
718     SwTblToTxtSave* pNew = new SwTblToTxtSave( rDoc, nNdIdx, nEndIdx, nCntntIdx );
719     pBoxSaves->Insert( pNew, pBoxSaves->Count() );
720 }
721 
722 // -----------------------------------------------------
723 
SwUndoTxtToTbl(const SwPaM & rRg,const SwInsertTableOptions & rInsTblOpts,sal_Unicode cCh,sal_uInt16 nAdj,const SwTableAutoFmt * pAFmt)724 SwUndoTxtToTbl::SwUndoTxtToTbl( const SwPaM& rRg,
725                                 const SwInsertTableOptions& rInsTblOpts,
726                                 sal_Unicode cCh, sal_uInt16 nAdj,
727                                 const SwTableAutoFmt* pAFmt )
728     : SwUndo( UNDO_TEXTTOTABLE ), SwUndRng( rRg ), aInsTblOpts( rInsTblOpts ),
729       pDelBoxes( 0 ), pAutoFmt( 0 ),
730       pHistory( 0 ), cTrenner( cCh ), nAdjust( nAdj )
731 {
732     if( pAFmt )
733         pAutoFmt = new SwTableAutoFmt( *pAFmt );
734 
735     const SwPosition* pEnd = rRg.End();
736     SwNodes& rNds = rRg.GetDoc()->GetNodes();
737     bSplitEnd = pEnd->nContent.GetIndex() && ( pEnd->nContent.GetIndex()
738                         != pEnd->nNode.GetNode().GetCntntNode()->Len() ||
739                 pEnd->nNode.GetIndex() >= rNds.GetEndOfContent().GetIndex()-1 );
740 }
741 
~SwUndoTxtToTbl()742 SwUndoTxtToTbl::~SwUndoTxtToTbl()
743 {
744     delete pDelBoxes;
745     delete pAutoFmt;
746 }
747 
UndoImpl(::sw::UndoRedoContext & rContext)748 void SwUndoTxtToTbl::UndoImpl(::sw::UndoRedoContext & rContext)
749 {
750     SwDoc & rDoc = rContext.GetDoc();
751 
752     sal_uLong nTblNd = nSttNode;
753     if( nSttCntnt )
754         ++nTblNd;       // Node wurde vorher gesplittet
755     SwNodeIndex aIdx( rDoc.GetNodes(), nTblNd );
756     SwTableNode *const pTNd = aIdx.GetNode().GetTableNode();
757     OSL_ENSURE( pTNd, "SwUndoTxtToTbl: no TableNode" );
758 
759     RemoveIdxFromSection( rDoc, nTblNd );
760 
761     sTblNm = pTNd->GetTable().GetFrmFmt()->GetName();
762 
763     if( pHistory )
764     {
765         pHistory->TmpRollback( &rDoc, 0 );
766         pHistory->SetTmpEnd( pHistory->Count() );
767     }
768 
769     if( pDelBoxes )
770     {
771         SwTable& rTbl = pTNd->GetTable();
772         for( sal_uInt16 n = pDelBoxes->Count(); n; )
773         {
774             SwTableBox* pBox = rTbl.GetTblBox( (*pDelBoxes)[ --n ] );
775             if( pBox )
776                 ::_DeleteBox( rTbl, pBox, 0, sal_False, sal_False );
777             else {
778                 ASSERT( !this, "Wo ist die Box geblieben?" );
779             }
780         }
781     }
782 
783     SwNodeIndex aEndIdx( *pTNd->EndOfSectionNode() );
784     rDoc.TableToText( pTNd, 0x0b == cTrenner ? 0x09 : cTrenner );
785 
786     // join again at start?
787     SwPaM aPam(rDoc.GetNodes().GetEndOfContent());
788     SwPosition *const pPos = aPam.GetPoint();
789     if( nSttCntnt )
790     {
791         pPos->nNode = nTblNd;
792         pPos->nContent.Assign(pPos->nNode.GetNode().GetCntntNode(), 0);
793         if (aPam.Move(fnMoveBackward, fnGoCntnt))
794         {
795             SwNodeIndex & rIdx = aPam.GetPoint()->nNode;
796 
797             // dann die Crsr/etc. nochmal relativ verschieben
798             RemoveIdxRel( rIdx.GetIndex()+1, *pPos );
799 
800             rIdx.GetNode().GetCntntNode()->JoinNext();
801         }
802     }
803 
804     // join again at end?
805     if( bSplitEnd )
806     {
807         SwNodeIndex& rIdx = pPos->nNode;
808         rIdx = nEndNode;
809         SwTxtNode* pTxtNd = rIdx.GetNode().GetTxtNode();
810         if( pTxtNd && pTxtNd->CanJoinNext() )
811         {
812             aPam.GetMark()->nContent.Assign( 0, 0 );
813             aPam.GetPoint()->nContent.Assign( 0, 0 );
814 
815             // dann die Crsr/etc. nochmal relativ verschieben
816             pPos->nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() );
817             RemoveIdxRel( nEndNode + 1, *pPos );
818 
819             pTxtNd->JoinNext();
820         }
821     }
822 
823     AddUndoRedoPaM(rContext);
824 }
825 
826 
RedoImpl(::sw::UndoRedoContext & rContext)827 void SwUndoTxtToTbl::RedoImpl(::sw::UndoRedoContext & rContext)
828 {
829     SwPaM & rPam( AddUndoRedoPaM(rContext) );
830     RemoveIdxFromRange(rPam, false);
831     SetPaM(rPam);
832 
833     SwTable const*const pTable = rContext.GetDoc().TextToTable(
834                 aInsTblOpts, rPam, cTrenner, nAdjust, pAutoFmt );
835     ((SwFrmFmt*)pTable->GetFrmFmt())->SetName( sTblNm );
836 }
837 
838 
RepeatImpl(::sw::RepeatContext & rContext)839 void SwUndoTxtToTbl::RepeatImpl(::sw::RepeatContext & rContext)
840 {
841     // no Table In Table
842     if (!rContext.GetRepeatPaM().GetNode()->FindTableNode())
843     {
844         rContext.GetDoc().TextToTable( aInsTblOpts, rContext.GetRepeatPaM(),
845                                         cTrenner, nAdjust,
846                                         pAutoFmt );
847     }
848 }
849 
AddFillBox(const SwTableBox & rBox)850 void SwUndoTxtToTbl::AddFillBox( const SwTableBox& rBox )
851 {
852     if( !pDelBoxes )
853         pDelBoxes = new SvULongs;
854     pDelBoxes->Insert( rBox.GetSttIdx(), pDelBoxes->Count() );
855 }
856 
GetHistory()857 SwHistory& SwUndoTxtToTbl::GetHistory()
858 {
859     if( !pHistory )
860         pHistory = new SwHistory;
861     return *pHistory;
862 }
863 
864 // -----------------------------------------------------
865 
SwUndoTblHeadline(const SwTable & rTbl,sal_uInt16 nOldHdl,sal_uInt16 nNewHdl)866 SwUndoTblHeadline::SwUndoTblHeadline( const SwTable& rTbl, sal_uInt16 nOldHdl,
867                                       sal_uInt16 nNewHdl )
868     : SwUndo( UNDO_TABLEHEADLINE ),
869     nOldHeadline( nOldHdl ),
870     nNewHeadline( nNewHdl )
871 {
872     ASSERT( rTbl.GetTabSortBoxes().Count(), "Tabelle ohne Inhalt" );
873     const SwStartNode *pSttNd = rTbl.GetTabSortBoxes()[ 0 ]->GetSttNd();
874     ASSERT( pSttNd, "Box ohne Inhalt" );
875 
876     nTblNd = pSttNd->StartOfSectionIndex();
877 }
878 
UndoImpl(::sw::UndoRedoContext & rContext)879 void SwUndoTblHeadline::UndoImpl(::sw::UndoRedoContext & rContext)
880 {
881     SwDoc & rDoc = rContext.GetDoc();
882     SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode();
883     ASSERT( pTNd, "keinen Tabellen-Node gefunden" );
884 
885     rDoc.SetRowsToRepeat( pTNd->GetTable(), nOldHeadline );
886 }
887 
RedoImpl(::sw::UndoRedoContext & rContext)888 void SwUndoTblHeadline::RedoImpl(::sw::UndoRedoContext & rContext)
889 {
890     SwDoc & rDoc = rContext.GetDoc();
891 
892     SwTableNode* pTNd = rDoc.GetNodes()[ nTblNd ]->GetTableNode();
893     ASSERT( pTNd, "keinen Tabellen-Node gefunden" );
894 
895     rDoc.SetRowsToRepeat( pTNd->GetTable(), nNewHeadline );
896 }
897 
RepeatImpl(::sw::RepeatContext & rContext)898 void SwUndoTblHeadline::RepeatImpl(::sw::RepeatContext & rContext)
899 {
900     SwTableNode *const pTblNd =
901         rContext.GetRepeatPaM().GetNode()->FindTableNode();
902     if( pTblNd )
903     {
904         rContext.GetDoc().SetRowsToRepeat( pTblNd->GetTable(), nNewHeadline );
905     }
906 }
907 
908 
909 //////////////////////////////////////////////////////////////////////////
910 
911 
_SaveTable(const SwTable & rTbl,sal_uInt16 nLnCnt,sal_Bool bSaveFml)912 _SaveTable::_SaveTable( const SwTable& rTbl, sal_uInt16 nLnCnt, sal_Bool bSaveFml )
913     : aTblSet( *rTbl.GetFrmFmt()->GetAttrSet().GetPool(), aTableSetRange ),
914     pSwTable( &rTbl ), nLineCount( nLnCnt ), bSaveFormula( bSaveFml )
915 {
916     bModifyBox = sal_False;
917     bNewModel = rTbl.IsNewModel();
918     aTblSet.Put( rTbl.GetFrmFmt()->GetAttrSet() );
919     pLine = new _SaveLine( 0, *rTbl.GetTabLines()[ 0 ], *this );
920 
921     _SaveLine* pLn = pLine;
922     if( USHRT_MAX == nLnCnt )
923         nLnCnt = rTbl.GetTabLines().Count();
924     for( sal_uInt16 n = 1; n < nLnCnt; ++n )
925         pLn = new _SaveLine( pLn, *rTbl.GetTabLines()[ n ], *this );
926 
927     aFrmFmts.Remove( 0, aFrmFmts.Count() );
928     pSwTable = 0;
929 }
930 
931 
~_SaveTable()932 _SaveTable::~_SaveTable()
933 {
934     delete pLine;
935 }
936 
937 
AddFmt(SwFrmFmt * pFmt,bool bIsLine)938 sal_uInt16 _SaveTable::AddFmt( SwFrmFmt* pFmt, bool bIsLine )
939 {
940     sal_uInt16 nRet = aFrmFmts.GetPos( pFmt );
941     if( USHRT_MAX == nRet )
942     {
943         // Kopie vom ItemSet anlegen
944         SfxItemSet* pSet = new SfxItemSet( *pFmt->GetAttrSet().GetPool(),
945             bIsLine ? aTableLineSetRange : aTableBoxSetRange );
946         pSet->Put( pFmt->GetAttrSet() );
947         //JP 20.04.98: Bug 49502 - wenn eine Formel gesetzt ist, nie den
948         //              Value mit sichern. Der muss gegebenfalls neu
949         //              errechnet werden!
950         //JP 30.07.98: Bug 54295 - Formeln immer im Klartext speichern
951         const SfxPoolItem* pItem;
952         if( SFX_ITEM_SET == pSet->GetItemState( RES_BOXATR_FORMULA, sal_True, &pItem ))
953         {
954             pSet->ClearItem( RES_BOXATR_VALUE );
955             if( pSwTable && bSaveFormula )
956             {
957                 SwTableFmlUpdate aMsgHnt( pSwTable );
958                 aMsgHnt.eFlags = TBL_BOXNAME;
959                 ((SwTblBoxFormula*)pItem)->ChgDefinedIn( pFmt );
960                 ((SwTblBoxFormula*)pItem)->ChangeState( &aMsgHnt );
961                 ((SwTblBoxFormula*)pItem)->ChgDefinedIn( 0 );
962             }
963         }
964         aSets.Insert( pSet, (nRet = aSets.Count() ) );
965         aFrmFmts.Insert( pFmt, nRet );
966     }
967     return nRet;
968 }
969 
970 
RestoreAttr(SwTable & rTbl,sal_Bool bMdfyBox)971 void _SaveTable::RestoreAttr( SwTable& rTbl, sal_Bool bMdfyBox )
972 {
973     sal_uInt16 n;
974 
975     bModifyBox = bMdfyBox;
976 
977     // zuerst die Attribute des TabellenFrmFormates zurueck holen
978     SwFrmFmt* pFmt = rTbl.GetFrmFmt();
979     SfxItemSet& rFmtSet  = (SfxItemSet&)pFmt->GetAttrSet();
980     rFmtSet.ClearItem();
981     rFmtSet.Put( aTblSet );
982 
983     if( pFmt->IsInCache() )
984     {
985         SwFrm::GetCache().Delete( pFmt );
986         pFmt->SetInCache( sal_False );
987     }
988 
989     // zur Sicherheit alle Tableframes invalidieren
990     SwIterator<SwTabFrm,SwFmt> aIter( *pFmt );
991     for( SwTabFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() )
992         if( pLast->GetTable() == &rTbl )
993         {
994             pLast->InvalidateAll();
995             pLast->SetCompletePaint();
996         }
997 
998     // FrmFmts mit Defaults (0) fuellen
999     pFmt = 0;
1000     for( n = aSets.Count(); n; --n )
1001         aFrmFmts.Insert( pFmt, aFrmFmts.Count() );
1002 
1003     sal_uInt16 nLnCnt = nLineCount;
1004     if( USHRT_MAX == nLnCnt )
1005         nLnCnt = rTbl.GetTabLines().Count();
1006 
1007     _SaveLine* pLn = pLine;
1008     for( n = 0; n < nLnCnt; ++n, pLn = pLn->pNext )
1009     {
1010         if( !pLn )
1011         {
1012             ASSERT( !this, "Anzahl der Lines hat sich veraendert" );
1013             break;
1014         }
1015 
1016         pLn->RestoreAttr( *rTbl.GetTabLines()[ n ], *this );
1017     }
1018 
1019     aFrmFmts.Remove( 0, aFrmFmts.Count() );
1020     bModifyBox = sal_False;
1021 }
1022 
1023 
SaveCntntAttrs(SwDoc * pDoc)1024 void _SaveTable::SaveCntntAttrs( SwDoc* pDoc )
1025 {
1026     pLine->SaveCntntAttrs( pDoc );
1027 }
1028 
1029 
CreateNew(SwTable & rTbl,sal_Bool bCreateFrms,sal_Bool bRestoreChart)1030 void _SaveTable::CreateNew( SwTable& rTbl, sal_Bool bCreateFrms,
1031                             sal_Bool bRestoreChart )
1032 {
1033     sal_uInt16 n;
1034 
1035     _FndBox aTmpBox( 0, 0 );
1036     //if( bRestoreChart )
1037     //    // ? TL_CHART2: notification or locking of controller required ?
1038     aTmpBox.DelFrms( rTbl );
1039 
1040     // zuerst die Attribute des TabellenFrmFormates zurueck holen
1041     SwFrmFmt* pFmt = rTbl.GetFrmFmt();
1042     SfxItemSet& rFmtSet  = (SfxItemSet&)pFmt->GetAttrSet();
1043     rFmtSet.ClearItem();
1044     rFmtSet.Put( aTblSet );
1045 
1046     if( pFmt->IsInCache() )
1047     {
1048         SwFrm::GetCache().Delete( pFmt );
1049         pFmt->SetInCache( sal_False );
1050     }
1051 
1052     // SwTableBox muss ein Format haben!!
1053     SwTableBox aParent( (SwTableBoxFmt*)pFmt, rTbl.GetTabLines().Count(), 0 );
1054 
1055     // FrmFmts mit Defaults (0) fuellen
1056     pFmt = 0;
1057     for( n = aSets.Count(); n; --n )
1058         aFrmFmts.Insert( pFmt, aFrmFmts.Count() );
1059 
1060     pLine->CreateNew( rTbl, aParent, *this );
1061     aFrmFmts.Remove( 0, aFrmFmts.Count() );
1062 
1063     // die neuen Lines eintragen, die alten loeschen
1064     sal_uInt16 nOldLines = nLineCount;
1065     if( USHRT_MAX == nLineCount )
1066         nOldLines = rTbl.GetTabLines().Count();
1067 
1068     SwDoc *pDoc = rTbl.GetFrmFmt()->GetDoc();
1069     SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
1070     for( n = 0; n < aParent.GetTabLines().Count(); ++n )
1071     {
1072         SwTableLine* pLn = aParent.GetTabLines()[ n ];
1073         pLn->SetUpper( 0 );
1074         if( n < nOldLines )
1075         {
1076             SwTableLine* pOld = rTbl.GetTabLines()[ n ];
1077 
1078             // TL_CHART2: notify chart about boxes to be removed
1079             const SwTableBoxes &rBoxes = pOld->GetTabBoxes();
1080             sal_uInt16 nBoxes = rBoxes.Count();
1081             for (sal_uInt16 k = 0;  k < nBoxes;  ++k)
1082             {
1083                 SwTableBox *pBox = rBoxes[k];
1084                 if (pPCD)
1085                     pPCD->DeleteBox( &rTbl, *pBox );
1086             }
1087 
1088             rTbl.GetTabLines().C40_REPLACE( SwTableLine, pLn, n );
1089             delete pOld;
1090         }
1091         else
1092             rTbl.GetTabLines().C40_INSERT( SwTableLine, pLn, n );
1093     }
1094 
1095     if( n < nOldLines )
1096     {
1097         // remove remaining lines...
1098 
1099         for (sal_uInt16 k1 = 0; k1 < nOldLines - n;  ++k1)
1100         {
1101             const SwTableBoxes &rBoxes = rTbl.GetTabLines()[n + k1]->GetTabBoxes();
1102             sal_uInt16 nBoxes = rBoxes.Count();
1103             for (sal_uInt16 k2 = 0;  k2 < nBoxes;  ++k2)
1104             {
1105                 SwTableBox *pBox = rBoxes[k2];
1106                 // TL_CHART2: notify chart about boxes to be removed
1107                 if (pPCD)
1108                     pPCD->DeleteBox( &rTbl, *pBox );
1109             }
1110         }
1111 
1112         rTbl.GetTabLines().DeleteAndDestroy( n, nOldLines - n );
1113     }
1114 
1115     aParent.GetTabLines().Remove( 0, n );
1116 
1117     if( bCreateFrms )
1118         aTmpBox.MakeFrms( rTbl );
1119     if( bRestoreChart )
1120     {
1121         // TL_CHART2: need to inform chart of probably changed cell names
1122         pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
1123     }
1124 }
1125 
1126 
NewFrmFmt(const SwTableLine * pTblLn,const SwTableBox * pTblBx,sal_uInt16 nFmtPos,SwFrmFmt * pOldFmt)1127 void _SaveTable::NewFrmFmt( const SwTableLine* pTblLn, const SwTableBox* pTblBx,
1128                             sal_uInt16 nFmtPos, SwFrmFmt* pOldFmt )
1129 {
1130     SwDoc* pDoc = pOldFmt->GetDoc();
1131 
1132     SwFrmFmt* pFmt = aFrmFmts[ nFmtPos ];
1133     if( !pFmt )
1134     {
1135         if( pTblLn )
1136             pFmt = pDoc->MakeTableLineFmt();
1137         else
1138             pFmt = pDoc->MakeTableBoxFmt();
1139         pFmt->SetFmtAttr( *aSets[ nFmtPos ] );
1140         aFrmFmts.Replace( pFmt, nFmtPos );
1141     }
1142 
1143     //Erstmal die Frms ummelden.
1144     SwIterator<SwTabFrm,SwFmt> aIter( *pOldFmt );
1145     for( SwFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1146     {
1147         if( pTblLn ? ((SwRowFrm*)pLast)->GetTabLine() == pTblLn
1148                     : ((SwCellFrm*)pLast)->GetTabBox() == pTblBx )
1149         {
1150             pLast->RegisterToFormat(*pFmt);
1151             pLast->InvalidateAll();
1152             pLast->ReinitializeFrmSizeAttrFlags();
1153             if ( !pTblLn )
1154             {
1155                 ((SwCellFrm*)pLast)->SetDerivedVert( sal_False );
1156                 ((SwCellFrm*)pLast)->CheckDirChange();
1157             }
1158         }
1159     }
1160 
1161     //Jetzt noch mich selbst ummelden.
1162     if ( pTblLn )
1163         const_cast<SwTableLine*>(pTblLn)->RegisterToFormat( *pFmt );
1164     else if ( pTblBx )
1165         const_cast<SwTableBox*>(pTblBx)->RegisterToFormat( *pFmt );
1166 
1167     if( bModifyBox && !pTblLn )
1168     {
1169         const SfxPoolItem& rOld = pOldFmt->GetFmtAttr( RES_BOXATR_FORMAT ),
1170                          & rNew = pFmt->GetFmtAttr( RES_BOXATR_FORMAT );
1171         if( rOld != rNew )
1172             pFmt->ModifyNotification( (SfxPoolItem*)&rOld, (SfxPoolItem*)&rNew );
1173     }
1174 
1175     if( !pOldFmt->GetDepends() )
1176         delete pOldFmt;
1177 
1178 }
1179 
1180 
_SaveLine(_SaveLine * pPrev,const SwTableLine & rLine,_SaveTable & rSTbl)1181 _SaveLine::_SaveLine( _SaveLine* pPrev, const SwTableLine& rLine, _SaveTable& rSTbl )
1182     : pNext( 0 )
1183 {
1184     if( pPrev )
1185         pPrev->pNext = this;
1186 
1187     nItemSet = rSTbl.AddFmt( rLine.GetFrmFmt(), true );
1188 
1189     pBox = new _SaveBox( 0, *rLine.GetTabBoxes()[ 0 ], rSTbl );
1190     _SaveBox* pBx = pBox;
1191     for( sal_uInt16 n = 1; n < rLine.GetTabBoxes().Count(); ++n )
1192         pBx = new _SaveBox( pBx, *rLine.GetTabBoxes()[ n ], rSTbl );
1193 }
1194 
1195 
~_SaveLine()1196 _SaveLine::~_SaveLine()
1197 {
1198     delete pBox;
1199     delete pNext;
1200 }
1201 
1202 
RestoreAttr(SwTableLine & rLine,_SaveTable & rSTbl)1203 void _SaveLine::RestoreAttr( SwTableLine& rLine, _SaveTable& rSTbl )
1204 {
1205     rSTbl.NewFrmFmt( &rLine, 0, nItemSet, rLine.GetFrmFmt() );
1206 
1207     _SaveBox* pBx = pBox;
1208     for( sal_uInt16 n = 0; n < rLine.GetTabBoxes().Count(); ++n, pBx = pBx->pNext )
1209     {
1210         if( !pBx )
1211         {
1212             ASSERT( !this, "Anzahl der Boxen hat sich veraendert" );
1213             break;
1214         }
1215         pBx->RestoreAttr( *rLine.GetTabBoxes()[ n ], rSTbl );
1216     }
1217 }
1218 
1219 
SaveCntntAttrs(SwDoc * pDoc)1220 void _SaveLine::SaveCntntAttrs( SwDoc* pDoc )
1221 {
1222     pBox->SaveCntntAttrs( pDoc );
1223     if( pNext )
1224         pNext->SaveCntntAttrs( pDoc );
1225 }
1226 
1227 
CreateNew(SwTable & rTbl,SwTableBox & rParent,_SaveTable & rSTbl)1228 void _SaveLine::CreateNew( SwTable& rTbl, SwTableBox& rParent, _SaveTable& rSTbl )
1229 {
1230     SwTableLineFmt* pFmt = (SwTableLineFmt*)rSTbl.aFrmFmts[ nItemSet ];
1231     if( !pFmt )
1232     {
1233         SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc();
1234         pFmt = pDoc->MakeTableLineFmt();
1235         pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] );
1236         rSTbl.aFrmFmts.Replace( pFmt, nItemSet );
1237     }
1238     SwTableLine* pNew = new SwTableLine( pFmt, 1, &rParent );
1239 
1240     rParent.GetTabLines().C40_INSERT( SwTableLine, pNew, rParent.GetTabLines().Count() );
1241 
1242     // HB, #127868# robustness: in some cases - which I
1243     // cannot reproduce nor see from the code - pNew seems
1244     // to be set to NULL in C40_INSERT.
1245     ASSERT(pNew, "Table line just created set to NULL in C40_INSERT");
1246 
1247     if (pNew)
1248     {
1249         pBox->CreateNew( rTbl, *pNew, rSTbl );
1250     }
1251 
1252     if( pNext )
1253         pNext->CreateNew( rTbl, rParent, rSTbl );
1254 }
1255 
1256 
_SaveBox(_SaveBox * pPrev,const SwTableBox & rBox,_SaveTable & rSTbl)1257 _SaveBox::_SaveBox( _SaveBox* pPrev, const SwTableBox& rBox, _SaveTable& rSTbl )
1258     : pNext( 0 ), nSttNode( ULONG_MAX ), nRowSpan(0)
1259 {
1260     Ptrs.pLine = 0;
1261 
1262     if( pPrev )
1263         pPrev->pNext = this;
1264 
1265     nItemSet = rSTbl.AddFmt( rBox.GetFrmFmt(), false );
1266 
1267     if( rBox.GetSttNd() )
1268     {
1269         nSttNode = rBox.GetSttIdx();
1270         nRowSpan = rBox.getRowSpan();
1271     }
1272     else
1273     {
1274         Ptrs.pLine = new _SaveLine( 0, *rBox.GetTabLines()[ 0 ], rSTbl );
1275 
1276         _SaveLine* pLn = Ptrs.pLine;
1277         for( sal_uInt16 n = 1; n < rBox.GetTabLines().Count(); ++n )
1278             pLn = new _SaveLine( pLn, *rBox.GetTabLines()[ n ], rSTbl );
1279     }
1280 }
1281 
1282 
~_SaveBox()1283 _SaveBox::~_SaveBox()
1284 {
1285     if( ULONG_MAX == nSttNode )     // keine EndBox
1286         delete Ptrs.pLine;
1287     else
1288         delete Ptrs.pCntntAttrs;
1289     delete pNext;
1290 }
1291 
1292 
RestoreAttr(SwTableBox & rBox,_SaveTable & rSTbl)1293 void _SaveBox::RestoreAttr( SwTableBox& rBox, _SaveTable& rSTbl )
1294 {
1295     rSTbl.NewFrmFmt( 0, &rBox, nItemSet, rBox.GetFrmFmt() );
1296 
1297     if( ULONG_MAX == nSttNode )     // keine EndBox
1298     {
1299         if( !rBox.GetTabLines().Count() )
1300         {
1301             ASSERT( !this, "Anzahl der Lines hat sich veraendert" );
1302         }
1303         else
1304         {
1305             _SaveLine* pLn = Ptrs.pLine;
1306             for( sal_uInt16 n = 0; n < rBox.GetTabLines().Count(); ++n, pLn = pLn->pNext )
1307             {
1308                 if( !pLn )
1309                 {
1310                     ASSERT( !this, "Anzahl der Lines hat sich veraendert" );
1311                     break;
1312                 }
1313 
1314                 pLn->RestoreAttr( *rBox.GetTabLines()[ n ], rSTbl );
1315             }
1316         }
1317     }
1318     else if( rBox.GetSttNd() && rBox.GetSttIdx() == nSttNode )
1319     {
1320         if( Ptrs.pCntntAttrs )
1321         {
1322             SwNodes& rNds = rBox.GetFrmFmt()->GetDoc()->GetNodes();
1323             sal_uInt16 nSet = 0;
1324             sal_uLong nEnd = rBox.GetSttNd()->EndOfSectionIndex();
1325             for( sal_uLong n = nSttNode + 1; n < nEnd; ++n )
1326             {
1327                 SwCntntNode* pCNd = rNds[ n ]->GetCntntNode();
1328                 if( pCNd )
1329                 {
1330                     SfxItemSet* pSet = (*Ptrs.pCntntAttrs)[ nSet++ ];
1331                     if( pSet )
1332                     {
1333                         sal_uInt16 *pRstAttr = aSave_BoxCntntSet;
1334                         while( *pRstAttr )
1335                         {
1336                             pCNd->ResetAttr( *pRstAttr, *(pRstAttr+1) );
1337                             pRstAttr += 2;
1338                         }
1339                         pCNd->SetAttr( *pSet );
1340                     }
1341                     else
1342                         pCNd->ResetAllAttr();
1343                 }
1344             }
1345         }
1346     }
1347     else
1348     {
1349         ASSERT( !this, "Box nicht mehr am gleichen Node" );
1350     }
1351 }
1352 
1353 
SaveCntntAttrs(SwDoc * pDoc)1354 void _SaveBox::SaveCntntAttrs( SwDoc* pDoc )
1355 {
1356     if( ULONG_MAX == nSttNode )     // keine EndBox
1357     {
1358         // weiter in der Line
1359         Ptrs.pLine->SaveCntntAttrs( pDoc );
1360     }
1361     else
1362     {
1363         sal_uLong nEnd = pDoc->GetNodes()[ nSttNode ]->EndOfSectionIndex();
1364         Ptrs.pCntntAttrs = new SfxItemSets( (sal_uInt8)(nEnd - nSttNode - 1 ), 5 );
1365         for( sal_uLong n = nSttNode + 1; n < nEnd; ++n )
1366         {
1367             SwCntntNode* pCNd = pDoc->GetNodes()[ n ]->GetCntntNode();
1368             if( pCNd )
1369             {
1370                 SfxItemSet* pSet = 0;
1371                 if( pCNd->HasSwAttrSet() )
1372                 {
1373                     pSet = new SfxItemSet( pDoc->GetAttrPool(),
1374                                             aSave_BoxCntntSet );
1375                     pSet->Put( *pCNd->GetpSwAttrSet() );
1376                 }
1377 
1378                 Ptrs.pCntntAttrs->Insert( pSet, Ptrs.pCntntAttrs->Count() );
1379             }
1380         }
1381     }
1382     if( pNext )
1383         pNext->SaveCntntAttrs( pDoc );
1384 }
1385 
1386 
CreateNew(SwTable & rTbl,SwTableLine & rParent,_SaveTable & rSTbl)1387 void _SaveBox::CreateNew( SwTable& rTbl, SwTableLine& rParent, _SaveTable& rSTbl )
1388 {
1389     SwTableBoxFmt* pFmt = (SwTableBoxFmt*)rSTbl.aFrmFmts[ nItemSet ];
1390     if( !pFmt )
1391     {
1392         SwDoc* pDoc = rTbl.GetFrmFmt()->GetDoc();
1393         pFmt = pDoc->MakeTableBoxFmt();
1394         pFmt->SetFmtAttr( *rSTbl.aSets[ nItemSet ] );
1395         rSTbl.aFrmFmts.Replace( pFmt, nItemSet );
1396     }
1397 
1398     if( ULONG_MAX == nSttNode )     // keine EndBox
1399     {
1400         SwTableBox* pNew = new SwTableBox( pFmt, 1, &rParent );
1401         rParent.GetTabBoxes().C40_INSERT( SwTableBox, pNew, rParent.GetTabBoxes().Count() );
1402 
1403         Ptrs.pLine->CreateNew( rTbl, *pNew, rSTbl );
1404     }
1405     else
1406     {
1407         // Box zum StartNode in der alten Tabelle suchen
1408         SwTableBox* pBox = rTbl.GetTblBox( nSttNode );
1409         ASSERT( pBox, "Wo ist meine TabellenBox geblieben?" );
1410 
1411         SwFrmFmt* pOld = pBox->GetFrmFmt();
1412         pBox->RegisterToFormat( *pFmt );
1413         if( !pOld->GetDepends() )
1414             delete pOld;
1415 
1416         pBox->setRowSpan( nRowSpan );
1417 
1418         SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
1419         pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) );
1420 
1421         pBox->SetUpper( &rParent );
1422         pTBoxes = &rParent.GetTabBoxes();
1423         pTBoxes->C40_INSERT( SwTableBox, pBox, pTBoxes->Count() );
1424     }
1425 
1426     if( pNext )
1427         pNext->CreateNew( rTbl, rParent, rSTbl );
1428 }
1429 
1430 
1431 //////////////////////////////////////////////////////////////////////////
1432 
1433 // UndoObject fuer Attribut Aenderung an der Tabelle
1434 
1435 
SwUndoAttrTbl(const SwTableNode & rTblNd,sal_Bool bClearTabCols)1436 SwUndoAttrTbl::SwUndoAttrTbl( const SwTableNode& rTblNd, sal_Bool bClearTabCols )
1437     : SwUndo( UNDO_TABLE_ATTR ),
1438     nSttNode( rTblNd.GetIndex() )
1439 {
1440     bClearTabCol = bClearTabCols;
1441     pSaveTbl = new _SaveTable( rTblNd.GetTable() );
1442 }
1443 
~SwUndoAttrTbl()1444 SwUndoAttrTbl::~SwUndoAttrTbl()
1445 {
1446     delete pSaveTbl;
1447 }
1448 
UndoImpl(::sw::UndoRedoContext & rContext)1449 void SwUndoAttrTbl::UndoImpl(::sw::UndoRedoContext & rContext)
1450 {
1451     SwDoc & rDoc = rContext.GetDoc();
1452     SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode();
1453     ASSERT( pTblNd, "kein TabellenNode" );
1454 
1455     if (pTblNd)
1456     {
1457         _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() );
1458         pSaveTbl->RestoreAttr( pTblNd->GetTable() );
1459         delete pSaveTbl;
1460         pSaveTbl = pOrig;
1461     }
1462 
1463     if( bClearTabCol )
1464         ClearFEShellTabCols();
1465 }
1466 
RedoImpl(::sw::UndoRedoContext & rContext)1467 void SwUndoAttrTbl::RedoImpl(::sw::UndoRedoContext & rContext)
1468 {
1469     UndoImpl(rContext);
1470 }
1471 
1472 
1473 //////////////////////////////////////////////////////////////////////////
1474 
1475 // UndoObject fuer AutoFormat an der Tabelle
1476 
1477 
SwUndoTblAutoFmt(const SwTableNode & rTblNd,const SwTableAutoFmt & rAFmt)1478 SwUndoTblAutoFmt::SwUndoTblAutoFmt( const SwTableNode& rTblNd,
1479                                     const SwTableAutoFmt& rAFmt )
1480     : SwUndo( UNDO_TABLE_AUTOFMT ),
1481     nSttNode( rTblNd.GetIndex() ),
1482     bSaveCntntAttr( sal_False )
1483 {
1484     pSaveTbl = new _SaveTable( rTblNd.GetTable() );
1485 
1486     if( rAFmt.IsFont() || rAFmt.IsJustify() )
1487     {
1488         // dann auch noch ueber die ContentNodes der EndBoxen und
1489         // und alle Absatz-Attribute zusammen sammeln
1490         pSaveTbl->SaveCntntAttrs( (SwDoc*)rTblNd.GetDoc() );
1491         bSaveCntntAttr = sal_True;
1492     }
1493 }
1494 
~SwUndoTblAutoFmt()1495 SwUndoTblAutoFmt::~SwUndoTblAutoFmt()
1496 {
1497     delete pSaveTbl;
1498 }
1499 
SaveBoxCntnt(const SwTableBox & rBox)1500 void SwUndoTblAutoFmt::SaveBoxCntnt( const SwTableBox& rBox )
1501 {
1502     ::boost::shared_ptr<SwUndoTblNumFmt> const p(new SwUndoTblNumFmt(rBox));
1503     m_Undos.push_back(p);
1504 }
1505 
1506 
1507 void
UndoRedo(bool const bUndo,::sw::UndoRedoContext & rContext)1508 SwUndoTblAutoFmt::UndoRedo(bool const bUndo, ::sw::UndoRedoContext & rContext)
1509 {
1510     SwDoc & rDoc = rContext.GetDoc();
1511     SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode();
1512     ASSERT( pTblNd, "kein TabellenNode" );
1513 
1514     _SaveTable* pOrig = new _SaveTable( pTblNd->GetTable() );
1515         // dann auch noch ueber die ContentNodes der EndBoxen und
1516         // und alle Absatz-Attribute zusammen sammeln
1517     if( bSaveCntntAttr )
1518         pOrig->SaveCntntAttrs( &rDoc );
1519 
1520     if (bUndo)
1521     {
1522         for (size_t n = m_Undos.size(); 0 < n; --n)
1523         {
1524             m_Undos.at(n-1)->UndoImpl(rContext);
1525         }
1526     }
1527 
1528     pSaveTbl->RestoreAttr( pTblNd->GetTable(), !bUndo );
1529     delete pSaveTbl;
1530     pSaveTbl = pOrig;
1531 }
1532 
UndoImpl(::sw::UndoRedoContext & rContext)1533 void SwUndoTblAutoFmt::UndoImpl(::sw::UndoRedoContext & rContext)
1534 {
1535     UndoRedo(true, rContext);
1536 }
1537 
RedoImpl(::sw::UndoRedoContext & rContext)1538 void SwUndoTblAutoFmt::RedoImpl(::sw::UndoRedoContext & rContext)
1539 {
1540     UndoRedo(false, rContext);
1541 }
1542 
1543 
1544 //////////////////////////////////////////////////////////////////////////
1545 
SwUndoTblNdsChg(SwUndoId nAction,const SwSelBoxes & rBoxes,const SwTableNode & rTblNd,long nMn,long nMx,sal_uInt16 nCnt,sal_Bool bFlg,sal_Bool bSmHght)1546 SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction,
1547                                     const SwSelBoxes& rBoxes,
1548                                     const SwTableNode& rTblNd,
1549                                     long nMn, long nMx,
1550                                     sal_uInt16 nCnt, sal_Bool bFlg, sal_Bool bSmHght )
1551     : SwUndo( nAction ),
1552     aBoxes( rBoxes.Count() < 255 ? (sal_uInt8)rBoxes.Count() : 255, 10 ),
1553     nMin( nMn ), nMax( nMx ),
1554     nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ),
1555     nCount( nCnt ), nRelDiff( 0 ), nAbsDiff( 0 ),
1556     nSetColType( USHRT_MAX ),
1557     bFlag( bFlg ),
1558     bSameHeight( bSmHght )
1559 {
1560     Ptrs.pNewSttNds = 0;
1561 
1562     const SwTable& rTbl = rTblNd.GetTable();
1563     pSaveTbl = new _SaveTable( rTbl );
1564 
1565     // und die Selektion merken
1566     for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
1567         aBoxes.Insert( rBoxes[n]->GetSttIdx(), n );
1568 }
1569 
1570 
SwUndoTblNdsChg(SwUndoId nAction,const SwSelBoxes & rBoxes,const SwTableNode & rTblNd)1571 SwUndoTblNdsChg::SwUndoTblNdsChg( SwUndoId nAction,
1572                                     const SwSelBoxes& rBoxes,
1573                                     const SwTableNode& rTblNd )
1574     : SwUndo( nAction ),
1575     aBoxes( rBoxes.Count() < 255 ? (sal_uInt8)rBoxes.Count() : 255, 10 ),
1576     nMin( 0 ), nMax( 0 ),
1577     nSttNode( rTblNd.GetIndex() ), nCurrBox( 0 ),
1578     nCount( 0 ), nRelDiff( 0 ), nAbsDiff( 0 ),
1579     nSetColType( USHRT_MAX ),
1580     bFlag( sal_False ),
1581     bSameHeight( sal_False )
1582 {
1583     Ptrs.pNewSttNds = 0;
1584 
1585     const SwTable& rTbl = rTblNd.GetTable();
1586     pSaveTbl = new _SaveTable( rTbl );
1587 
1588     // und die Selektion merken
1589     for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
1590         aBoxes.Insert( rBoxes[n]->GetSttIdx(), n );
1591 }
1592 
ReNewBoxes(const SwSelBoxes & rBoxes)1593 void SwUndoTblNdsChg::ReNewBoxes( const SwSelBoxes& rBoxes )
1594 {
1595     if( rBoxes.Count() != aBoxes.Count() )
1596     {
1597         aBoxes.Remove( 0, aBoxes.Count() );
1598         for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
1599             aBoxes.Insert( rBoxes[n]->GetSttIdx(), n );
1600     }
1601 }
1602 
~SwUndoTblNdsChg()1603 SwUndoTblNdsChg::~SwUndoTblNdsChg()
1604 {
1605     delete pSaveTbl;
1606 
1607     if( IsDelBox() )
1608         delete Ptrs.pDelSects;
1609     else
1610         delete Ptrs.pNewSttNds;
1611 }
1612 
SaveNewBoxes(const SwTableNode & rTblNd,const SwTableSortBoxes & rOld)1613 void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd,
1614                                     const SwTableSortBoxes& rOld )
1615 {
1616     const SwTable& rTbl = rTblNd.GetTable();
1617     const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes();
1618     sal_uInt16 n;
1619     sal_uInt16 i;
1620 
1621     ASSERT( ! IsDelBox(), "falsche Action" );
1622     Ptrs.pNewSttNds = new SvULongs( (sal_uInt8)(rTblBoxes.Count() - rOld.Count()), 5 );
1623 
1624     for( n = 0, i = 0; n < rOld.Count(); ++i )
1625     {
1626         if( rOld[ n ] == rTblBoxes[ i ] )
1627             ++n;
1628         else
1629             // neue Box: sortiert einfuegen!!
1630             InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() );
1631     }
1632 
1633     for( ; i < rTblBoxes.Count(); ++i )
1634         // neue Box: sortiert einfuegen!!
1635         InsertSort( *Ptrs.pNewSttNds, rTblBoxes[ i ]->GetSttIdx() );
1636 }
1637 
1638 
lcl_FindTableLine(const SwTable & rTable,const SwTableBox & rBox)1639 SwTableLine* lcl_FindTableLine( const SwTable& rTable,
1640                                 const SwTableBox& rBox )
1641 {
1642     SwTableLine* pRet = NULL;
1643     // i63949: For nested cells we have to take nLineNo - 1, too, not 0!
1644     const SwTableLines &rTableLines = ( rBox.GetUpper()->GetUpper() != NULL ) ?
1645                                   rBox.GetUpper()->GetUpper()->GetTabLines()
1646                                 : rTable.GetTabLines();
1647     const SwTableLine* pLine = rBox.GetUpper();
1648     sal_uInt16 nLineNo = rTableLines.C40_GETPOS( SwTableLine, pLine );
1649     pRet = rTableLines[nLineNo - 1];
1650 
1651     return pRet;
1652 }
1653 
lcl_FindParentLines(const SwTable & rTable,const SwTableBox & rBox)1654 const SwTableLines& lcl_FindParentLines( const SwTable& rTable,
1655                                        const SwTableBox& rBox )
1656 {
1657     const SwTableLines& rRet =
1658         ( rBox.GetUpper()->GetUpper() != NULL ) ?
1659             rBox.GetUpper()->GetUpper()->GetTabLines() :
1660             rTable.GetTabLines();
1661 
1662     return rRet;
1663 }
1664 
1665 
SaveNewBoxes(const SwTableNode & rTblNd,const SwTableSortBoxes & rOld,const SwSelBoxes & rBoxes,const SvULongs & rNodeCnts)1666 void SwUndoTblNdsChg::SaveNewBoxes( const SwTableNode& rTblNd,
1667                                     const SwTableSortBoxes& rOld,
1668                                     const SwSelBoxes& rBoxes,
1669                                     const SvULongs& rNodeCnts )
1670 {
1671     const SwTable& rTbl = rTblNd.GetTable();
1672     const SwTableSortBoxes& rTblBoxes = rTbl.GetTabSortBoxes();
1673 
1674     ASSERT( ! IsDelBox(), "falsche Action" );
1675     Ptrs.pNewSttNds = new SvULongs( (sal_uInt8)(rTblBoxes.Count() - rOld.Count()), 5 );
1676 
1677     ASSERT( rTbl.IsNewModel() || rOld.Count() + nCount * rBoxes.Count() == rTblBoxes.Count(),
1678         "unexpected boxes" );
1679     ASSERT( rOld.Count() <= rTblBoxes.Count(), "more unexpected boxes" );
1680     for( sal_uInt16 n = 0, i = 0; i < rTblBoxes.Count(); ++i )
1681     {
1682         if( ( n < rOld.Count() ) &&
1683             ( rOld[ n ] == rTblBoxes[ i ] ) )
1684         {
1685             // box already known? Then nothing to be done.
1686             ++n;
1687         }
1688         else
1689         {
1690             // new box found: insert (obey sort order)
1691             sal_uInt16 nInsPos;
1692             const SwTableBox* pBox = rTblBoxes[ i ];
1693             InsertSort( *Ptrs.pNewSttNds, pBox->GetSttIdx(), &nInsPos );
1694 
1695             // find the source box. It must be one in rBoxes.
1696             // We found the right one if it's in the same column as pBox.
1697             // No, if more than one selected cell in the same column has been splitted,
1698             // we have to look for the nearest one (i65201)!
1699             const SwTableBox* pSourceBox = NULL;
1700             const SwTableBox* pCheckBox = NULL;
1701             const SwTableLine* pBoxLine = pBox->GetUpper();
1702             sal_uInt16 nLineDiff = lcl_FindParentLines(rTbl,*pBox).C40_GETPOS(SwTableLine,pBoxLine);
1703             sal_uInt16 nLineNo = 0;
1704             for( sal_uInt16 j = 0; j < rBoxes.Count(); ++j )
1705             {
1706                 pCheckBox = rBoxes[j];
1707                 if( pCheckBox->GetUpper()->GetUpper() == pBox->GetUpper()->GetUpper() )
1708                 {
1709                     const SwTableLine* pCheckLine = pCheckBox->GetUpper();
1710                     sal_uInt16 nCheckLine = lcl_FindParentLines( rTbl, *pCheckBox ).
1711                     C40_GETPOS( SwTableLine, pCheckLine );
1712                     if( ( !pSourceBox || nCheckLine > nLineNo ) && nCheckLine < nLineDiff )
1713                     {
1714                         nLineNo = nCheckLine;
1715                         pSourceBox = pCheckBox;
1716                     }
1717                 }
1718             }
1719 
1720             // find the line number difference
1721             // (to help determine bNodesMoved flag below)
1722             nLineDiff = nLineDiff - nLineNo;
1723             ASSERT( pSourceBox, "Splitted source box not found!" );
1724             // find out how many nodes the source box used to have
1725             // (to help determine bNodesMoved flag below)
1726             sal_uInt16 nNdsPos = 0;
1727             while( rBoxes[ nNdsPos ] != pSourceBox )
1728                 ++nNdsPos;
1729             sal_uLong nNodes = rNodeCnts[ nNdsPos ];
1730 
1731             // When a new table cell is created, it either gets a new
1732             // node, or it gets node(s) from elsewhere. The undo must
1733             // know, of course, and thus we must determine here just
1734             // where pBox's nodes are from:
1735             // If 1) the source box has lost nodes, and
1736             //    2) we're in the node range that got nodes
1737             // then pBox received nodes from elsewhere.
1738             // If bNodesMoved is set for pBox the undo must move the
1739             // boxes back, otherwise it must delete them.
1740             // The bNodesMoved flag is stored in a seperate array
1741             // which mirrors Ptrs.pNewSttNds, i.e. Ptrs.pNewSttNds[i]
1742             // and aMvBoxes[i] belong together.
1743             sal_Bool bNodesMoved =
1744                 ( nNodes != ( pSourceBox->GetSttNd()->EndOfSectionIndex() -
1745                               pSourceBox->GetSttIdx() ) )
1746                 && ( nNodes - 1 > nLineDiff );
1747             aMvBoxes.insert( aMvBoxes.begin() + nInsPos, bNodesMoved );
1748         }
1749     }
1750 }
1751 
1752 
SaveSection(SwStartNode * pSttNd)1753 void SwUndoTblNdsChg::SaveSection( SwStartNode* pSttNd )
1754 {
1755     ASSERT( IsDelBox(), "falsche Action" );
1756     if( !Ptrs.pDelSects )
1757         Ptrs.pDelSects = new SwUndoSaveSections( 10, 5 );
1758 
1759     SwTableNode* pTblNd = pSttNd->FindTableNode();
1760     SwUndoSaveSection* pSave = new SwUndoSaveSection;
1761     pSave->SaveSection( pSttNd->GetDoc(), SwNodeIndex( *pSttNd ));
1762 
1763     Ptrs.pDelSects->Insert( pSave, Ptrs.pDelSects->Count() );
1764     nSttNode = pTblNd->GetIndex();
1765 }
1766 
1767 
UndoImpl(::sw::UndoRedoContext & rContext)1768 void SwUndoTblNdsChg::UndoImpl(::sw::UndoRedoContext & rContext)
1769 {
1770     SwDoc & rDoc = rContext.GetDoc();
1771     SwNodeIndex aIdx( rDoc.GetNodes(), nSttNode );
1772 
1773     SwTableNode *const pTblNd = aIdx.GetNode().GetTableNode();
1774     OSL_ENSURE( pTblNd, "SwUndoTblNdsChg: no TableNode" );
1775 
1776     SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
1777     aMsgHnt.eFlags = TBL_BOXPTR;
1778     rDoc.UpdateTblFlds( &aMsgHnt );
1779 
1780     CHECK_TABLE( pTblNd->GetTable() )
1781 
1782     _FndBox aTmpBox( 0, 0 );
1783     // ? TL_CHART2: notification or locking of controller required ?
1784 
1785     SwChartDataProvider *pPCD = rDoc.GetChartDataProvider();
1786     std::vector< SwTableBox* > aDelBoxes;
1787     if( IsDelBox() )
1788     {
1789         // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim
1790         // CreateNew werden sie korrekt verbunden.
1791         SwTableBox* pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0];
1792         SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes();
1793 
1794         // die Sections wieder herstellen
1795         for( sal_uInt16 n = Ptrs.pDelSects->Count(); n; )
1796         {
1797             SwUndoSaveSection* pSave = (*Ptrs.pDelSects)[ --n ];
1798             pSave->RestoreSection( &rDoc, &aIdx, SwTableBoxStartNode );
1799             if( pSave->GetHistory() )
1800                 pSave->GetHistory()->Rollback( &rDoc );
1801             SwTableBox* pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), aIdx,
1802                                                 pCpyBox->GetUpper() );
1803             rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() );
1804         }
1805         Ptrs.pDelSects->DeleteAndDestroy( 0, Ptrs.pDelSects->Count() );
1806     }
1807     else if( !aMvBoxes.empty() )
1808     {
1809         // dann muessen Nodes verschoben und nicht geloescht werden!
1810         // Dafuer brauchen wir aber ein temp Array
1811         SvULongs aTmp( 0, 5);
1812         aTmp.Insert( Ptrs.pNewSttNds, 0 );
1813 
1814         // von hinten anfangen
1815         for( sal_uInt16 n = aTmp.Count(); n; )
1816         {
1817             // Box aus der Tabellen-Struktur entfernen
1818             sal_uLong nIdx = aTmp[ --n ];
1819             SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx );
1820             ASSERT( pBox, "Wo ist meine TabellenBox geblieben?" );
1821 
1822             // TL_CHART2: notify chart about box to be removed
1823             if (pPCD)
1824                 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
1825 
1826             if( aMvBoxes[ n ] )
1827             {
1828                 SwNodeRange aRg( *pBox->GetSttNd(), 1,
1829                             *pBox->GetSttNd()->EndOfSectionNode() );
1830 
1831                 SwTableLine* pLine = lcl_FindTableLine( pTblNd->GetTable(), *pBox );
1832                 SwNodeIndex aInsPos( *(pLine->GetTabBoxes()[0]->GetSttNd()), 2 );
1833 
1834                 // alle StartNode Indizies anpassen
1835                 sal_uInt16 i = n;
1836                 sal_uLong nSttIdx = aInsPos.GetIndex() - 2,
1837                        nNdCnt = aRg.aEnd.GetIndex() - aRg.aStart.GetIndex();
1838                 while( i && aTmp[ --i ] > nSttIdx )
1839                     aTmp[ i ] += nNdCnt;
1840 
1841                 // erst die Box loeschen
1842                 delete pBox;
1843                 // dann die Nodes verschieben,
1844                 rDoc.GetNodes()._MoveNodes( aRg, rDoc.GetNodes(), aInsPos, sal_False );
1845             }
1846             else
1847                 rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
1848             aDelBoxes.insert( aDelBoxes.end(), pBox );
1849         }
1850     }
1851     else
1852     {
1853         // Remove nodes from nodes array (backwards!)
1854         for( sal_uInt16 n = Ptrs.pNewSttNds->Count(); n; )
1855         {
1856             sal_uLong nIdx = (*Ptrs.pNewSttNds)[ --n ];
1857             SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nIdx );
1858             ASSERT( pBox, "Where's my table box?" );
1859             // TL_CHART2: notify chart about box to be removed
1860             if (pPCD)
1861                 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
1862             aDelBoxes.insert( aDelBoxes.end(), pBox );
1863             rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
1864         }
1865     }
1866     // Remove boxes from table structure
1867     for( sal_uInt16 n = 0; n < aDelBoxes.size(); ++n )
1868     {
1869         SwTableBox* pCurrBox = aDelBoxes[n];
1870         SwTableBoxes* pTBoxes = &pCurrBox->GetUpper()->GetTabBoxes();
1871         pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pCurrBox ) );
1872         delete pCurrBox;
1873     }
1874 
1875     pSaveTbl->CreateNew( pTblNd->GetTable(), sal_True, sal_False );
1876 
1877     // TL_CHART2: need to inform chart of probably changed cell names
1878     rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() );
1879 
1880     if( IsDelBox() )
1881         nSttNode = pTblNd->GetIndex();
1882     ClearFEShellTabCols();
1883     CHECK_TABLE( pTblNd->GetTable() )
1884 }
1885 
1886 
RedoImpl(::sw::UndoRedoContext & rContext)1887 void SwUndoTblNdsChg::RedoImpl(::sw::UndoRedoContext & rContext)
1888 {
1889     SwDoc & rDoc = rContext.GetDoc();
1890 
1891     SwTableNode* pTblNd = rDoc.GetNodes()[ nSttNode ]->GetTableNode();
1892     ASSERT( pTblNd, "kein TabellenNode" );
1893     CHECK_TABLE( pTblNd->GetTable() )
1894 
1895     SwSelBoxes aSelBoxes;
1896     for( sal_uInt16 n = 0; n < aBoxes.Count(); ++n )
1897     {
1898         SwTableBox* pBox = pTblNd->GetTable().GetTblBox( aBoxes[ n ] );
1899         aSelBoxes.Insert( pBox );
1900     }
1901 
1902     // SelBoxes erzeugen und InsertCell/-Row/SplitTbl aufrufen
1903     switch( GetId() )
1904     {
1905     case UNDO_TABLE_INSCOL:
1906         if( USHRT_MAX == nSetColType )
1907             rDoc.InsertCol( aSelBoxes, nCount, bFlag );
1908         else
1909         {
1910             SwTableBox* pBox = pTblNd->GetTable().GetTblBox( nCurrBox );
1911             rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff,
1912                                         nRelDiff );
1913         }
1914         break;
1915 
1916     case UNDO_TABLE_INSROW:
1917         if( USHRT_MAX == nSetColType )
1918             rDoc.InsertRow( aSelBoxes, nCount, bFlag );
1919         else
1920         {
1921             SwTable& rTbl = pTblNd->GetTable();
1922             SwTableBox* pBox = rTbl.GetTblBox( nCurrBox );
1923             TblChgMode eOldMode = rTbl.GetTblChgMode();
1924             rTbl.SetTblChgMode( (TblChgMode)nCount );
1925             rDoc.SetColRowWidthHeight( *pBox, nSetColType, nAbsDiff, nRelDiff );
1926             rTbl.SetTblChgMode( eOldMode );
1927         }
1928         break;
1929 
1930     case UNDO_TABLE_SPLIT:
1931         rDoc.SplitTbl( aSelBoxes, bFlag, nCount, bSameHeight );
1932         break;
1933     case UNDO_TABLE_DELBOX:
1934     case UNDO_ROW_DELETE:
1935     case UNDO_COL_DELETE:
1936         if( USHRT_MAX == nSetColType )
1937         {
1938             SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
1939             aMsgHnt.eFlags = TBL_BOXPTR;
1940             rDoc.UpdateTblFlds( &aMsgHnt );
1941             SwTable &rTable = pTblNd->GetTable();
1942             if( nMax > nMin && rTable.IsNewModel() )
1943                 rTable.PrepareDeleteCol( nMin, nMax );
1944             rTable.DeleteSel( &rDoc, aSelBoxes, 0, this, sal_True, sal_True );
1945         }
1946         else
1947         {
1948             SwTable& rTbl = pTblNd->GetTable();
1949 
1950             SwTableFmlUpdate aMsgHnt( &rTbl );
1951             aMsgHnt.eFlags = TBL_BOXPTR;
1952             rDoc.UpdateTblFlds( &aMsgHnt );
1953 
1954             SwTableBox* pBox = rTbl.GetTblBox( nCurrBox );
1955             TblChgMode eOldMode = rTbl.GetTblChgMode();
1956             rTbl.SetTblChgMode( (TblChgMode)nCount );
1957 
1958             // need the SaveSections!
1959             rDoc.GetIDocumentUndoRedo().DoUndo( true );
1960             SwUndoTblNdsChg* pUndo = 0;
1961 
1962             switch( nSetColType & 0xff )
1963             {
1964             case nsTblChgWidthHeightType::WH_COL_LEFT:
1965             case nsTblChgWidthHeightType::WH_COL_RIGHT:
1966             case nsTblChgWidthHeightType::WH_CELL_LEFT:
1967             case nsTblChgWidthHeightType::WH_CELL_RIGHT:
1968                  rTbl.SetColWidth( *pBox, nSetColType, nAbsDiff,
1969                                     nRelDiff, (SwUndo**)&pUndo );
1970                 break;
1971             case nsTblChgWidthHeightType::WH_ROW_TOP:
1972             case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
1973             case nsTblChgWidthHeightType::WH_CELL_TOP:
1974             case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
1975                 rTbl.SetRowHeight( *pBox, nSetColType, nAbsDiff,
1976                                     nRelDiff, (SwUndo**)&pUndo );
1977                 break;
1978             }
1979 
1980             if( pUndo )
1981             {
1982                 Ptrs.pDelSects->Insert( pUndo->Ptrs.pDelSects, 0 );
1983                 pUndo->Ptrs.pDelSects->Remove( 0, pUndo->Ptrs.pDelSects->Count() );
1984 
1985                 delete pUndo;
1986             }
1987             rDoc.GetIDocumentUndoRedo().DoUndo( false );
1988 
1989             rTbl.SetTblChgMode( eOldMode );
1990         }
1991         nSttNode = pTblNd->GetIndex();
1992         break;
1993     default:
1994         ;
1995     }
1996     ClearFEShellTabCols();
1997     CHECK_TABLE( pTblNd->GetTable() )
1998 }
1999 
2000 
2001 //////////////////////////////////////////////////////////////////////////
2002 
SwUndoTblMerge(const SwPaM & rTblSel)2003 SwUndoTblMerge::SwUndoTblMerge( const SwPaM& rTblSel )
2004     : SwUndo( UNDO_TABLE_MERGE ), SwUndRng( rTblSel ), pHistory( 0 )
2005 {
2006     const SwTableNode* pTblNd = rTblSel.GetNode()->FindTableNode();
2007     ASSERT( pTblNd, "Wo ist TabllenNode" )
2008     pSaveTbl = new _SaveTable( pTblNd->GetTable() );
2009     pMoves = new SwUndoMoves;
2010     nTblNode = pTblNd->GetIndex();
2011 }
2012 
~SwUndoTblMerge()2013 SwUndoTblMerge::~SwUndoTblMerge()
2014 {
2015     delete pSaveTbl;
2016     delete pMoves;
2017     delete pHistory;
2018 }
2019 
UndoImpl(::sw::UndoRedoContext & rContext)2020 void SwUndoTblMerge::UndoImpl(::sw::UndoRedoContext & rContext)
2021 {
2022     SwDoc & rDoc = rContext.GetDoc();
2023     SwNodeIndex aIdx( rDoc.GetNodes(), nTblNode );
2024 
2025     SwTableNode *const pTblNd = aIdx.GetNode().GetTableNode();
2026     OSL_ENSURE( pTblNd, "SwUndoTblMerge: no TableNode" );
2027 
2028     SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
2029     aMsgHnt.eFlags = TBL_BOXPTR;
2030     rDoc.UpdateTblFlds( &aMsgHnt );
2031 
2032     _FndBox aTmpBox( 0, 0 );
2033     // ? TL_CHART2: notification or locking of controller required ?
2034 
2035 
2036     // 1. die geloeschten Boxen wiederherstellen:
2037 
2038     // Trick: die fehlenden Boxen in irgendeine Line einfuegen, beim
2039     // CreateNew werden sie korrekt verbunden.
2040     SwTableBox *pBox, *pCpyBox = pTblNd->GetTable().GetTabSortBoxes()[0];
2041     SwTableBoxes& rLnBoxes = pCpyBox->GetUpper()->GetTabBoxes();
2042 
2043 DUMPDOC( &rDoc, "d:\\tmp\\tab_a.db" )
2044 CHECKTABLE(pTblNd->GetTable())
2045 
2046     SwSelBoxes aSelBoxes;
2047     SwTxtFmtColl* pColl = rDoc.GetTxtCollFromPool( RES_POOLCOLL_STANDARD );
2048     sal_uInt16 n;
2049 
2050     for( n = 0; n < aBoxes.Count(); ++n )
2051     {
2052         aIdx = aBoxes[ n ];
2053         SwStartNode* pSttNd = rDoc.GetNodes().MakeTextSection( aIdx,
2054                                             SwTableBoxStartNode, pColl );
2055         pBox = new SwTableBox( (SwTableBoxFmt*)pCpyBox->GetFrmFmt(), *pSttNd,
2056                                 pCpyBox->GetUpper() );
2057         rLnBoxes.C40_INSERT( SwTableBox, pBox, rLnBoxes.Count() );
2058 
2059         aSelBoxes.Insert( pBox );
2060     }
2061 
2062 DUMPDOC( &rDoc, "d:\\tmp\\tab_b.db" )
2063 CHECKTABLE(pTblNd->GetTable())
2064 
2065     SwChartDataProvider *pPCD = rDoc.GetChartDataProvider();
2066     // 2. die eingefuegten Boxen loeschen
2067     // die Nodes loeschen (von Hinten!!)
2068     for( n = aNewSttNds.Count(); n; )
2069     {
2070         // Box aus der Tabellen-Struktur entfernen
2071         sal_uLong nIdx = aNewSttNds[ --n ];
2072 
2073         if( !nIdx && n )
2074         {
2075             nIdx = aNewSttNds[ --n ];
2076             pBox = pTblNd->GetTable().GetTblBox( nIdx );
2077             ASSERT( pBox, "Wo ist meine TabellenBox geblieben?" );
2078 
2079             if( !pSaveTbl->IsNewModel() )
2080                 rDoc.GetNodes().MakeTxtNode( SwNodeIndex(
2081                     *pBox->GetSttNd()->EndOfSectionNode() ), pColl );
2082 
2083             // das war der Trenner, -> die verschobenen herstellen
2084             for( sal_uInt16 i = pMoves->Count(); i; )
2085             {
2086                 SwTxtNode* pTxtNd = 0;
2087                 sal_uInt16 nDelPos = 0;
2088                 SwUndoMove* pUndo = (*pMoves)[ --i ];
2089                 if( !pUndo->IsMoveRange() )
2090                 {
2091                     pTxtNd = rDoc.GetNodes()[ pUndo->GetDestSttNode() ]->GetTxtNode();
2092                     nDelPos = pUndo->GetDestSttCntnt() - 1;
2093                 }
2094                 pUndo->UndoImpl(rContext);
2095                 if( pUndo->IsMoveRange() )
2096                 {
2097                     // den ueberfluessigen Node loeschen
2098                     aIdx = pUndo->GetEndNode();
2099                     SwCntntNode *pCNd = aIdx.GetNode().GetCntntNode();
2100                     if( pCNd )
2101                     {
2102                         SwNodeIndex aTmp( aIdx, -1 );
2103                         SwCntntNode *pMove = aTmp.GetNode().GetCntntNode();
2104                         if( pMove )
2105                             pCNd->MoveTo( *pMove );
2106                     }
2107                     rDoc.GetNodes().Delete( aIdx, 1 );
2108                 }
2109                 else if( pTxtNd )
2110                 {
2111                     // evt. noch ueberflussige Attribute loeschen
2112                     SwIndex aTmpIdx( pTxtNd, nDelPos );
2113                     if( pTxtNd->GetpSwpHints() && pTxtNd->GetpSwpHints()->Count() )
2114                         pTxtNd->RstTxtAttr( aTmpIdx, pTxtNd->GetTxt().Len() - nDelPos + 1 );
2115                     // das Trennzeichen loeschen
2116                     pTxtNd->EraseText( aTmpIdx, 1 );
2117                 }
2118 DUMPDOC( &rDoc, String( "d:\\tmp\\tab_") + String( aNewSttNds.Count() - i ) +
2119                 String(".db") )
2120             }
2121             nIdx = pBox->GetSttIdx();
2122         }
2123         else
2124             pBox = pTblNd->GetTable().GetTblBox( nIdx );
2125 
2126         if( !pSaveTbl->IsNewModel() )
2127         {
2128             // TL_CHART2: notify chart about box to be removed
2129             if (pPCD)
2130                 pPCD->DeleteBox( &pTblNd->GetTable(), *pBox );
2131 
2132             SwTableBoxes* pTBoxes = &pBox->GetUpper()->GetTabBoxes();
2133             pTBoxes->Remove( pTBoxes->C40_GETPOS( SwTableBox, pBox ) );
2134 
2135 
2136             // Indizies aus dem Bereich loeschen
2137             {
2138                 SwNodeIndex aTmpIdx( *pBox->GetSttNd() );
2139                 rDoc.CorrAbs( SwNodeIndex( aTmpIdx, 1 ),
2140                             SwNodeIndex( *aTmpIdx.GetNode().EndOfSectionNode() ),
2141                             SwPosition( aTmpIdx, SwIndex( 0, 0 )), sal_True );
2142             }
2143 
2144             delete pBox;
2145             rDoc.DeleteSection( rDoc.GetNodes()[ nIdx ] );
2146         }
2147     }
2148 DUMPDOC( &rDoc, "d:\\tmp\\tab_z.db" )
2149 CHECKTABLE(pTblNd->GetTable())
2150 
2151 
2152     pSaveTbl->CreateNew( pTblNd->GetTable(), sal_True, sal_False );
2153 
2154     // TL_CHART2: need to inform chart of probably changed cell names
2155     rDoc.UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() );
2156 
2157     if( pHistory )
2158     {
2159         pHistory->TmpRollback( &rDoc, 0 );
2160         pHistory->SetTmpEnd( pHistory->Count() );
2161     }
2162 //  nTblNode = pTblNd->GetIndex();
2163 
2164     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2165     pPam->DeleteMark();
2166     pPam->GetPoint()->nNode = nSttNode;
2167     pPam->GetPoint()->nContent.Assign( pPam->GetCntntNode(), nSttCntnt );
2168     pPam->SetMark();
2169     pPam->DeleteMark();
2170 
2171 CHECKTABLE(pTblNd->GetTable())
2172     ClearFEShellTabCols();
2173 }
2174 
RedoImpl(::sw::UndoRedoContext & rContext)2175 void SwUndoTblMerge::RedoImpl(::sw::UndoRedoContext & rContext)
2176 {
2177     SwDoc & rDoc = rContext.GetDoc();
2178     SwPaM & rPam( AddUndoRedoPaM(rContext) );
2179     rDoc.MergeTbl(rPam);
2180 }
2181 
MoveBoxCntnt(SwDoc * pDoc,SwNodeRange & rRg,SwNodeIndex & rPos)2182 void SwUndoTblMerge::MoveBoxCntnt( SwDoc* pDoc, SwNodeRange& rRg, SwNodeIndex& rPos )
2183 {
2184     SwNodeIndex aTmp( rRg.aStart, -1 ), aTmp2( rPos, -1 );
2185     SwUndoMove* pUndo = new SwUndoMove( pDoc, rRg, rPos );
2186     ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
2187     pDoc->MoveNodeRange( rRg, rPos, (pSaveTbl->IsNewModel()) ?
2188         IDocumentContentOperations::DOC_NO_DELFRMS :
2189         IDocumentContentOperations::DOC_MOVEDEFAULT );
2190     aTmp++;
2191     aTmp2++;
2192     pUndo->SetDestRange( aTmp2, rPos, aTmp );
2193 
2194     pMoves->Insert( pUndo, pMoves->Count() );
2195 }
2196 
SetSelBoxes(const SwSelBoxes & rBoxes)2197 void SwUndoTblMerge::SetSelBoxes( const SwSelBoxes& rBoxes )
2198 {
2199     // die Selektion merken
2200     for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
2201         InsertSort( aBoxes, rBoxes[n]->GetSttIdx() );
2202 
2203     // als Trennung fuers einfuegen neuer Boxen nach dem Verschieben!
2204     aNewSttNds.Insert( (sal_uLong)0, aNewSttNds.Count() );
2205 
2206      // The new table model does not delete overlapped cells (by row span),
2207      // so the rBoxes array might be empty even some cells have been merged.
2208     if( rBoxes.Count() )
2209         nTblNode = rBoxes[ 0 ]->GetSttNd()->FindTableNode()->GetIndex();
2210 }
2211 
SaveCollection(const SwTableBox & rBox)2212 void SwUndoTblMerge::SaveCollection( const SwTableBox& rBox )
2213 {
2214     if( !pHistory )
2215         pHistory = new SwHistory;
2216 
2217     SwNodeIndex aIdx( *rBox.GetSttNd(), 1 );
2218     SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
2219     if( !pCNd )
2220         pCNd = aIdx.GetNodes().GoNext( &aIdx );
2221 
2222     pHistory->Add( pCNd->GetFmtColl(), aIdx.GetIndex(), pCNd->GetNodeType());
2223     if( pCNd->HasSwAttrSet() )
2224         pHistory->CopyFmtAttr( *pCNd->GetpSwAttrSet(), aIdx.GetIndex() );
2225 }
2226 
2227 
2228 //////////////////////////////////////////////////////////////////////////
2229 
SwUndoTblNumFmt(const SwTableBox & rBox,const SfxItemSet * pNewSet)2230 SwUndoTblNumFmt::SwUndoTblNumFmt( const SwTableBox& rBox,
2231                                     const SfxItemSet* pNewSet )
2232     : SwUndo( UNDO_TBLNUMFMT ),
2233     pBoxSet( 0 ), pHistory( 0 ), nFmtIdx( NUMBERFORMAT_TEXT )
2234 {
2235     bNewFmt = bNewFml = bNewValue = sal_False;
2236     nNode = rBox.GetSttIdx();
2237 
2238     nNdPos = rBox.IsValidNumTxtNd( 0 == pNewSet );
2239     SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2240 
2241     if( ULONG_MAX != nNdPos )
2242     {
2243         SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2244 
2245         pHistory = new SwHistory;
2246         SwRegHistory aRHst( *rBox.GetSttNd(), pHistory );
2247         // always save all text atttibutes because of possibly overlapping
2248         // areas of on/off
2249         pHistory->CopyAttr( pTNd->GetpSwpHints(), nNdPos, 0,
2250                             pTNd->GetTxt().Len(), true );
2251 
2252         if( pTNd->HasSwAttrSet() )
2253             pHistory->CopyFmtAttr( *pTNd->GetpSwAttrSet(), nNdPos );
2254 
2255         aStr = pTNd->GetTxt();
2256         if( pTNd->GetpSwpHints() )
2257             pTNd->GetpSwpHints()->DeRegister();
2258     }
2259 
2260     pBoxSet = new SfxItemSet( pDoc->GetAttrPool(), aTableBoxSetRange );
2261     pBoxSet->Put( rBox.GetFrmFmt()->GetAttrSet() );
2262 
2263     if( pNewSet )
2264     {
2265         const SfxPoolItem* pItem;
2266         if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMAT,
2267                 sal_False, &pItem ))
2268         {
2269             bNewFmt = sal_True;
2270             nNewFmtIdx = ((SwTblBoxNumFormat*)pItem)->GetValue();
2271         }
2272         if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_FORMULA,
2273                 sal_False, &pItem ))
2274         {
2275             bNewFml = sal_True;
2276             aNewFml = ((SwTblBoxFormula*)pItem)->GetFormula();
2277         }
2278         if( SFX_ITEM_SET == pNewSet->GetItemState( RES_BOXATR_VALUE,
2279                 sal_False, &pItem ))
2280         {
2281             bNewValue = sal_True;
2282             fNewNum = ((SwTblBoxValue*)pItem)->GetValue();
2283         }
2284     }
2285 
2286     // wird die History ueberhaupt benoetigt ??
2287     if( pHistory && !pHistory->Count() )
2288         DELETEZ( pHistory );
2289 }
2290 
~SwUndoTblNumFmt()2291 SwUndoTblNumFmt::~SwUndoTblNumFmt()
2292 {
2293     delete pHistory;
2294     delete pBoxSet;
2295 }
2296 
UndoImpl(::sw::UndoRedoContext & rContext)2297 void SwUndoTblNumFmt::UndoImpl(::sw::UndoRedoContext & rContext)
2298 {
2299     ASSERT( pBoxSet, "Where's the stored item set?" )
2300 
2301     SwDoc & rDoc = rContext.GetDoc();
2302     SwStartNode* pSttNd = rDoc.GetNodes()[ nNode ]->
2303                             FindSttNodeByType( SwTableBoxStartNode );
2304     ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
2305     SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
2306                                     pSttNd->GetIndex() );
2307     ASSERT( pBox, "keine TabellenBox gefunden" );
2308 
2309     SwTableBoxFmt* pFmt = rDoc.MakeTableBoxFmt();
2310     pFmt->SetFmtAttr( *pBoxSet );
2311     pBox->ChgFrmFmt( pFmt );
2312 
2313     if( ULONG_MAX == nNdPos )
2314         return;
2315 
2316     SwTxtNode* pTxtNd = rDoc.GetNodes()[ nNdPos ]->GetTxtNode();
2317     // wenn mehr als ein Node geloescht wurde, dann wurden auch
2318     // alle "Node"-Attribute gespeichert
2319     if( pTxtNd->HasSwAttrSet() )
2320         pTxtNd->ResetAllAttr();
2321 
2322     if( pTxtNd->GetpSwpHints() && aStr.Len() )
2323         pTxtNd->ClearSwpHintsArr( true );
2324 
2325     // ChgTextToNum(..) only acts when the strings are different. We
2326     // need to do the same here.
2327     if( pTxtNd->GetTxt() != aStr )
2328     {
2329         rDoc.DeleteRedline( *( pBox->GetSttNd() ), false, USHRT_MAX );
2330 
2331         SwIndex aIdx( pTxtNd, 0 );
2332         if( aStr.Len() )
2333         {
2334             pTxtNd->EraseText( aIdx );
2335             pTxtNd->InsertText( aStr, aIdx,
2336                 IDocumentContentOperations::INS_NOHINTEXPAND );
2337         }
2338     }
2339 
2340     if( pHistory )
2341     {
2342         sal_uInt16 nTmpEnd = pHistory->GetTmpEnd();
2343         pHistory->TmpRollback( &rDoc, 0 );
2344         pHistory->SetTmpEnd( nTmpEnd );
2345     }
2346 
2347     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2348     pPam->DeleteMark();
2349     pPam->GetPoint()->nNode = nNode + 1;
2350     pPam->GetPoint()->nContent.Assign( pTxtNd, 0 );
2351 }
2352 
2353 /** switch the RedlineMode on the given document, using
2354  * SetRedlineMode_intern. This class set the mode in the constructor,
2355  * and changes it back in the destructor, i.e. it uses the
2356  * initialization-is-resource-acquisition idiom.
2357  */
2358 class RedlineModeInternGuard
2359 {
2360     SwDoc& mrDoc;
2361     RedlineMode_t meOldRedlineMode;
2362 
2363 public:
2364     RedlineModeInternGuard(
2365         SwDoc& rDoc,                      /// change mode of this document
2366         RedlineMode_t eNewRedlineMode,    /// new redline mode
2367         RedlineMode_t eRedlineModeMask  = (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_IGNORE /*change only bits set in this mask*/));
2368 
2369     ~RedlineModeInternGuard();
2370 };
2371 
RedlineModeInternGuard(SwDoc & rDoc,RedlineMode_t eNewRedlineMode,RedlineMode_t eRedlineModeMask)2372 RedlineModeInternGuard::RedlineModeInternGuard(
2373     SwDoc& rDoc,
2374     RedlineMode_t eNewRedlineMode,
2375     RedlineMode_t eRedlineModeMask )
2376     : mrDoc( rDoc ),
2377       meOldRedlineMode( rDoc.GetRedlineMode() )
2378 {
2379     mrDoc.SetRedlineMode_intern((RedlineMode_t)( ( meOldRedlineMode & ~eRedlineModeMask ) |
2380                                      ( eNewRedlineMode & eRedlineModeMask ) ));
2381 }
2382 
~RedlineModeInternGuard()2383 RedlineModeInternGuard::~RedlineModeInternGuard()
2384 {
2385     mrDoc.SetRedlineMode_intern( meOldRedlineMode );
2386 }
2387 
2388 
2389 
RedoImpl(::sw::UndoRedoContext & rContext)2390 void SwUndoTblNumFmt::RedoImpl(::sw::UndoRedoContext & rContext)
2391 {
2392     // konnte die Box veraendert werden ?
2393     if( !pBoxSet )
2394         return ;
2395 
2396     SwDoc & rDoc = rContext.GetDoc();
2397     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2398 
2399     pPam->DeleteMark();
2400     pPam->GetPoint()->nNode = nNode;
2401 
2402     SwNode * pNd = & pPam->GetPoint()->nNode.GetNode();
2403     SwStartNode* pSttNd = pNd->FindSttNodeByType( SwTableBoxStartNode );
2404     ASSERT( pSttNd, "ohne StartNode kein TabellenBox" );
2405     SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().GetTblBox(
2406                                     pSttNd->GetIndex() );
2407     ASSERT( pBox, "keine TabellenBox gefunden" );
2408 
2409     SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
2410     if( bNewFmt || bNewFml || bNewValue )
2411     {
2412         SfxItemSet aBoxSet( rDoc.GetAttrPool(),
2413                                 RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2414 
2415         // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2416         //              Sorge dafuer, das der Text auch entsprechend
2417         //              formatiert wird!
2418         pBoxFmt->LockModify();
2419 
2420         if( bNewFml )
2421             aBoxSet.Put( SwTblBoxFormula( aNewFml ));
2422         else
2423             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
2424         if( bNewFmt )
2425             aBoxSet.Put( SwTblBoxNumFormat( nNewFmtIdx ));
2426         else
2427             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2428         if( bNewValue )
2429             aBoxSet.Put( SwTblBoxValue( fNewNum ));
2430         else
2431             pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE );
2432         pBoxFmt->UnlockModify();
2433 
2434         // dvo: When redlining is (was) enabled, setting the attribute
2435         // will also change the cell content. To allow this, the
2436         // REDLINE_IGNORE flag must be removed during Redo. #108450#
2437         RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE );
2438         pBoxFmt->SetFmtAttr( aBoxSet );
2439     }
2440     else if( NUMBERFORMAT_TEXT != nFmtIdx )
2441     {
2442         SfxItemSet aBoxSet( rDoc.GetAttrPool(),
2443                             RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2444 
2445         aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx ));
2446         aBoxSet.Put( SwTblBoxValue( fNum ));
2447 
2448         // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2449         //              Sorge dafuer, das der Text auch entsprechend
2450         //              formatiert wird!
2451         pBoxFmt->LockModify();
2452         pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
2453         pBoxFmt->UnlockModify();
2454 
2455         // dvo: When redlining is (was) enabled, setting the attribute
2456         // will also change the cell content. To allow this, the
2457         // REDLINE_IGNORE flag must be removed during Redo. #108450#
2458         RedlineModeInternGuard aGuard( rDoc, nsRedlineMode_t::REDLINE_NONE, nsRedlineMode_t::REDLINE_IGNORE );
2459         pBoxFmt->SetFmtAttr( aBoxSet );
2460     }
2461     else
2462     {
2463         // es ist keine Zahl
2464 
2465         // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
2466         //              Sorge dafuer, das der Text auch entsprechend
2467         //              formatiert wird!
2468         pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
2469 
2470         pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2471     }
2472 
2473     if( bNewFml )
2474     {
2475         // egal was gesetzt wurde, ein Update der Tabelle macht sich immer gut
2476         SwTableFmlUpdate aTblUpdate( &pSttNd->FindTableNode()->GetTable() );
2477         rDoc.UpdateTblFlds( &aTblUpdate );
2478     }
2479 
2480     if( !pNd->IsCntntNode() )
2481         pNd = rDoc.GetNodes().GoNext( &pPam->GetPoint()->nNode );
2482     pPam->GetPoint()->nContent.Assign( (SwCntntNode*)pNd, 0 );
2483 }
2484 
SetBox(const SwTableBox & rBox)2485 void SwUndoTblNumFmt::SetBox( const SwTableBox& rBox )
2486 {
2487     nNode = rBox.GetSttIdx();
2488 }
2489 
2490 
2491 //////////////////////////////////////////////////////////////////////////
2492 
_UndoTblCpyTbl_Entry(const SwTableBox & rBox)2493 _UndoTblCpyTbl_Entry::_UndoTblCpyTbl_Entry( const SwTableBox& rBox )
2494     : nBoxIdx( rBox.GetSttIdx() ), nOffset( 0 ),
2495     pBoxNumAttr( 0 ), pUndo( 0 ), bJoin( false )
2496 {
2497 }
2498 
~_UndoTblCpyTbl_Entry()2499 _UndoTblCpyTbl_Entry::~_UndoTblCpyTbl_Entry()
2500 {
2501     delete pUndo;
2502     delete pBoxNumAttr;
2503 }
2504 
2505 
SwUndoTblCpyTbl()2506 SwUndoTblCpyTbl::SwUndoTblCpyTbl()
2507     : SwUndo( UNDO_TBLCPYTBL ), pInsRowUndo( 0 )
2508 {
2509     pArr = new _UndoTblCpyTbl_Entries;
2510 }
2511 
~SwUndoTblCpyTbl()2512 SwUndoTblCpyTbl::~SwUndoTblCpyTbl()
2513 {
2514     delete pArr;
2515     delete pInsRowUndo;
2516 }
2517 
UndoImpl(::sw::UndoRedoContext & rContext)2518 void SwUndoTblCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext)
2519 {
2520     SwDoc & rDoc = rContext.GetDoc();
2521     _DEBUG_REDLINE( &rDoc )
2522 
2523     SwTableNode* pTblNd = 0;
2524     for( sal_uInt16 n = pArr->Count(); n; )
2525     {
2526         _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ --n ];
2527         sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2528         SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2529         if( !pTblNd )
2530             pTblNd = pSNd->FindTableNode();
2531 
2532         SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos );
2533 
2534         SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2535         rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() );
2536 
2537         // b62341295: Redline for copying tables
2538         const SwNode *pEndNode = rBox.GetSttNd()->EndOfSectionNode();
2539         SwPaM aPam( aInsIdx.GetNode(), *pEndNode );
2540         SwUndoDelete* pUndo = 0;
2541 
2542         if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
2543         {
2544             bool bDeleteCompleteParagraph = false;
2545             bool bShiftPam = false;
2546             // There are a couple of different situations to consider during redlining
2547             if( pEntry->pUndo )
2548             {
2549                 SwUndoDelete *const pUndoDelete =
2550                     dynamic_cast<SwUndoDelete*>(pEntry->pUndo);
2551                 SwUndoRedlineDelete *const pUndoRedlineDelete =
2552                     dynamic_cast<SwUndoRedlineDelete*>(pEntry->pUndo);
2553                 OSL_ASSERT(pUndoDelete || pUndoRedlineDelete);
2554                 if (pUndoRedlineDelete)
2555                 {
2556                     // The old content was not empty or he has been merged with the new content
2557                     bDeleteCompleteParagraph = !pEntry->bJoin; // bJoin is set when merged
2558                     // Set aTmpIdx to the beginning fo the old content
2559                     SwNodeIndex aTmpIdx( *pEndNode,
2560                             pUndoRedlineDelete->NodeDiff()-1 );
2561                     SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2562                     if( pTxt )
2563                     {
2564                         aPam.GetPoint()->nNode = *pTxt;
2565                         aPam.GetPoint()->nContent.Assign( pTxt,
2566                                 pUndoRedlineDelete->ContentStart() );
2567                     }
2568                     else
2569                         *aPam.GetPoint() = SwPosition( aTmpIdx );
2570                 }
2571                 else if (pUndoDelete && pUndoDelete->IsDelFullPara())
2572                 {
2573                     // When the old content was an empty paragraph, but could not be joined
2574                     // with the new content (e.g. because of a section or table)
2575                     // We "save" the aPam.Point, we go one step backwards (because later on the
2576                     // empty paragraph will be inserted by the undo) and set the "ShiftPam-flag
2577                     // for step forward later on.
2578                     bDeleteCompleteParagraph = true;
2579                     bShiftPam = true;
2580                     SwNodeIndex aTmpIdx( *pEndNode, -1 );
2581                     SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2582                     if( pTxt )
2583                     {
2584                         aPam.GetPoint()->nNode = *pTxt;
2585                         aPam.GetPoint()->nContent.Assign( pTxt, 0 );
2586                     }
2587                     else
2588                         *aPam.GetPoint() = SwPosition( aTmpIdx );
2589                 }
2590             }
2591             rDoc.DeleteRedline( aPam, true, USHRT_MAX );
2592 
2593             if( pEntry->pUndo )
2594             {
2595                 pEntry->pUndo->UndoImpl(rContext);
2596                 delete pEntry->pUndo;
2597                 pEntry->pUndo = 0;
2598             }
2599             if( bShiftPam )
2600             {
2601                 // The aPam.Point is at the moment at the last position of the new content and has to be
2602                 // moved to the first postion of the old content for the SwUndoDelete operation
2603                 SwNodeIndex aTmpIdx( aPam.GetPoint()->nNode, 1 );
2604                 SwTxtNode *pTxt = aTmpIdx.GetNode().GetTxtNode();
2605                 if( pTxt )
2606                 {
2607                     aPam.GetPoint()->nNode = *pTxt;
2608                     aPam.GetPoint()->nContent.Assign( pTxt, 0 );
2609                 }
2610                 else
2611                     *aPam.GetPoint() = SwPosition( aTmpIdx );
2612             }
2613             pUndo = new SwUndoDelete( aPam, bDeleteCompleteParagraph, sal_True );
2614         }
2615         else
2616         {
2617             pUndo = new SwUndoDelete( aPam, true );
2618             if( pEntry->pUndo )
2619             {
2620                 pEntry->pUndo->UndoImpl(rContext);
2621                 delete pEntry->pUndo;
2622                 pEntry->pUndo = 0;
2623             }
2624         }
2625         pEntry->pUndo = pUndo;
2626 
2627         aInsIdx = rBox.GetSttIdx() + 1;
2628         rDoc.GetNodes().Delete( aInsIdx, 1 );
2629 
2630         SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2631                                                 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2632         aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() );
2633         if( aTmpSet.Count() )
2634         {
2635             SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
2636             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2637             pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT );
2638         }
2639 
2640         if( pEntry->pBoxNumAttr )
2641         {
2642             rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr );
2643             delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2644         }
2645 
2646         if( aTmpSet.Count() )
2647         {
2648             pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(),
2649                                     RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2650                                     RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2651             pEntry->pBoxNumAttr->Put( aTmpSet );
2652         }
2653 
2654         pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2655     }
2656 
2657     if( pInsRowUndo )
2658     {
2659         pInsRowUndo->UndoImpl(rContext);
2660     }
2661     _DEBUG_REDLINE( &rDoc )
2662 }
2663 
RedoImpl(::sw::UndoRedoContext & rContext)2664 void SwUndoTblCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext)
2665 {
2666     SwDoc & rDoc = rContext.GetDoc();
2667     _DEBUG_REDLINE( &rDoc )
2668 
2669     if( pInsRowUndo )
2670     {
2671         pInsRowUndo->RedoImpl(rContext);
2672     }
2673 
2674     SwTableNode* pTblNd = 0;
2675     for( sal_uInt16 n = 0; n < pArr->Count(); ++n )
2676     {
2677         _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ n ];
2678         sal_uLong nSttPos = pEntry->nBoxIdx + pEntry->nOffset;
2679         SwStartNode* pSNd = rDoc.GetNodes()[ nSttPos ]->StartOfSectionNode();
2680         if( !pTblNd )
2681             pTblNd = pSNd->FindTableNode();
2682 
2683         SwTableBox& rBox = *pTblNd->GetTable().GetTblBox( nSttPos );
2684 
2685         SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2686 
2687         // b62341295: Redline for copying tables - Start.
2688         rDoc.GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)rDoc.GetDfltTxtFmtColl() );
2689         SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode());
2690         SwUndo* pUndo = IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) ? 0 : new SwUndoDelete( aPam, sal_True );
2691         if( pEntry->pUndo )
2692         {
2693             pEntry->pUndo->UndoImpl(rContext);
2694             if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ) )
2695             {
2696                 // PrepareRedline has to be called with the beginning of the old content
2697                 // When new and old content has been joined, the rIter.pAktPam has been set
2698                 // by the Undo operation to this point.
2699                 // Otherwise aInsIdx has been moved during the Undo operation
2700                 if( pEntry->bJoin )
2701                 {
2702                     SwPaM const& rLastPam =
2703                         rContext.GetCursorSupplier().GetCurrentShellCursor();
2704                     pUndo = PrepareRedline( &rDoc, rBox, *rLastPam.GetPoint(),
2705                                             pEntry->bJoin, true );
2706                 }
2707                 else
2708                 {
2709                     SwPosition aTmpPos( aInsIdx );
2710                     pUndo = PrepareRedline( &rDoc, rBox, aTmpPos, pEntry->bJoin, true );
2711                 }
2712             }
2713             delete pEntry->pUndo;
2714             pEntry->pUndo = 0;
2715         }
2716         pEntry->pUndo = pUndo;
2717         // b62341295: Redline for copying tables - End.
2718 
2719         aInsIdx = rBox.GetSttIdx() + 1;
2720         rDoc.GetNodes().Delete( aInsIdx, 1 );
2721 
2722         SfxItemSet aTmpSet( rDoc.GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2723                                                 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2724         aTmpSet.Put( rBox.GetFrmFmt()->GetAttrSet() );
2725         if( aTmpSet.Count() )
2726         {
2727             SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
2728             pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
2729             pBoxFmt->ResetFmtAttr( RES_VERT_ORIENT );
2730         }
2731         if( pEntry->pBoxNumAttr )
2732         {
2733             rBox.ClaimFrmFmt()->SetFmtAttr( *pEntry->pBoxNumAttr );
2734             delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2735         }
2736 
2737         if( aTmpSet.Count() )
2738         {
2739             pEntry->pBoxNumAttr = new SfxItemSet( rDoc.GetAttrPool(),
2740                                     RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2741                                     RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2742             pEntry->pBoxNumAttr->Put( aTmpSet );
2743         }
2744 
2745         pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2746     }
2747     _DEBUG_REDLINE( &rDoc )
2748 }
2749 
AddBoxBefore(const SwTableBox & rBox,sal_Bool bDelCntnt)2750 void SwUndoTblCpyTbl::AddBoxBefore( const SwTableBox& rBox, sal_Bool bDelCntnt )
2751 {
2752     if( pArr->Count() && !bDelCntnt )
2753         return;
2754 
2755     _UndoTblCpyTbl_Entry* pEntry = new _UndoTblCpyTbl_Entry( rBox );
2756     pArr->Insert( pEntry, pArr->Count() );
2757 
2758     SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2759     _DEBUG_REDLINE( pDoc )
2760     if( bDelCntnt )
2761     {
2762         SwNodeIndex aInsIdx( *rBox.GetSttNd(), 1 );
2763         pDoc->GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
2764         SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode() );
2765 
2766         if( !pDoc->IsRedlineOn() )
2767             pEntry->pUndo = new SwUndoDelete( aPam, sal_True );
2768     }
2769 
2770     pEntry->pBoxNumAttr = new SfxItemSet( pDoc->GetAttrPool(),
2771                                     RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
2772                                     RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
2773     pEntry->pBoxNumAttr->Put( rBox.GetFrmFmt()->GetAttrSet() );
2774     if( !pEntry->pBoxNumAttr->Count() )
2775         delete pEntry->pBoxNumAttr, pEntry->pBoxNumAttr = 0;
2776     _DEBUG_REDLINE( pDoc )
2777 }
2778 
AddBoxAfter(const SwTableBox & rBox,const SwNodeIndex & rIdx,sal_Bool bDelCntnt)2779 void SwUndoTblCpyTbl::AddBoxAfter( const SwTableBox& rBox, const SwNodeIndex& rIdx, sal_Bool bDelCntnt )
2780 {
2781     _UndoTblCpyTbl_Entry* pEntry = (*pArr)[ pArr->Count() - 1 ];
2782 
2783     // wurde der Inhalt geloescht, so loesche jetzt auch noch den temp.
2784     // erzeugten Node
2785     if( bDelCntnt )
2786     {
2787         SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2788         _DEBUG_REDLINE( pDoc )
2789 
2790         if( pDoc->IsRedlineOn() )
2791         {
2792             SwPosition aTmpPos( rIdx );
2793             pEntry->pUndo = PrepareRedline( pDoc, rBox, aTmpPos, pEntry->bJoin, false );
2794         }
2795         SwNodeIndex aDelIdx( *rBox.GetSttNd(), 1 );
2796         rBox.GetFrmFmt()->GetDoc()->GetNodes().Delete( aDelIdx, 1 );
2797         _DEBUG_REDLINE( pDoc )
2798     }
2799 
2800     pEntry->nOffset = rBox.GetSttIdx() - pEntry->nBoxIdx;
2801 }
2802 
2803 // PrepareRedline is called from AddBoxAfter() and from Redo() in slightly different situations.
2804 // bRedo is set by calling from Redo()
2805 // rJoin is false by calling from AddBoxAfter() and will be set if the old and new content has
2806 // been merged.
2807 // rJoin is true if Redo() is calling and the content has already been merged
2808 
PrepareRedline(SwDoc * pDoc,const SwTableBox & rBox,const SwPosition & rPos,bool & rJoin,bool bRedo)2809 SwUndo* SwUndoTblCpyTbl::PrepareRedline( SwDoc* pDoc, const SwTableBox& rBox,
2810     const SwPosition& rPos, bool& rJoin, bool bRedo )
2811 {
2812     SwUndo *pUndo = 0;
2813     // b62341295: Redline for copying tables
2814     // What's to do?
2815     // Mark the cell content before rIdx as insertion,
2816     // mark the cell content behind rIdx as deletion
2817     // merge text nodes at rIdx if possible
2818     RedlineMode_t eOld = pDoc->GetRedlineMode();
2819     pDoc->SetRedlineMode_intern((RedlineMode_t)( ( eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES ) &
2820                                      ~nsRedlineMode_t::REDLINE_IGNORE ));
2821     SwPosition aInsertEnd( rPos );
2822     SwTxtNode* pTxt;
2823     if( !rJoin )
2824     {
2825         // If the content is not merged, the end of the insertion is at the end of the node
2826         // _before_ the given position rPos
2827         --aInsertEnd.nNode;
2828         pTxt = aInsertEnd.nNode.GetNode().GetTxtNode();
2829         if( pTxt )
2830         {
2831             aInsertEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() );
2832             if( !bRedo && rPos.nNode.GetNode().GetTxtNode() )
2833             {   // Try to merge, if not called by Redo()
2834                 rJoin = true;
2835                 pTxt->JoinNext();
2836             }
2837         }
2838         else
2839             aInsertEnd.nContent = SwIndex( 0 );
2840     }
2841     // For joined (merged) contents the start of deletionm and end of insertion are identical
2842     // otherwise adjacent nodes.
2843     SwPosition aDeleteStart( rJoin ? aInsertEnd : rPos );
2844     if( !rJoin )
2845     {
2846         pTxt = aDeleteStart.nNode.GetNode().GetTxtNode();
2847         if( pTxt )
2848             aDeleteStart.nContent.Assign( pTxt, 0 );
2849     }
2850     SwPosition aCellEnd( SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode(), -1 ) );
2851     pTxt = aCellEnd.nNode.GetNode().GetTxtNode();
2852     if( pTxt )
2853         aCellEnd.nContent.Assign( pTxt, pTxt->GetTxt().Len() );
2854     if( aDeleteStart != aCellEnd )
2855     {   // If the old (deleted) part is not empty, here we are...
2856         SwPaM aDeletePam( aDeleteStart, aCellEnd );
2857         pUndo = new SwUndoRedlineDelete( aDeletePam, UNDO_DELETE );
2858         pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDeletePam ), true );
2859     }
2860     else if( !rJoin ) // If the old part is empty and joined, we are finished
2861     {   // if it is not joined, we have to delete this empty paragraph
2862         aCellEnd = SwPosition(
2863             SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode() ));
2864         SwPaM aTmpPam( aDeleteStart, aCellEnd );
2865         pUndo = new SwUndoDelete( aTmpPam, sal_True );
2866     }
2867     SwPosition aCellStart( SwNodeIndex( *rBox.GetSttNd(), 2 ) );
2868     pTxt = aCellStart.nNode.GetNode().GetTxtNode();
2869     if( pTxt )
2870         aCellStart.nContent.Assign( pTxt, 0 );
2871     if( aCellStart != aInsertEnd ) // An empty insertion will not been marked
2872     {
2873         SwPaM aTmpPam( aCellStart, aInsertEnd );
2874         pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aTmpPam ), true );
2875     }
2876 
2877     pDoc->SetRedlineMode_intern( eOld );
2878     return pUndo;
2879 }
2880 
2881 
InsertRow(SwTable & rTbl,const SwSelBoxes & rBoxes,sal_uInt16 nCnt)2882 sal_Bool SwUndoTblCpyTbl::InsertRow( SwTable& rTbl, const SwSelBoxes& rBoxes,
2883                                 sal_uInt16 nCnt )
2884 {
2885     SwTableNode* pTblNd = (SwTableNode*)rTbl.GetTabSortBoxes()[0]->
2886                                 GetSttNd()->FindTableNode();
2887 
2888     SwTableSortBoxes aTmpLst( 0, 5 );
2889     pInsRowUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW, rBoxes, *pTblNd,
2890                                        0, 0, nCnt, sal_True, sal_False );
2891     aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
2892 
2893     sal_Bool bRet = rTbl.InsertRow( rTbl.GetFrmFmt()->GetDoc(), rBoxes, nCnt, sal_True );
2894     if( bRet )
2895         pInsRowUndo->SaveNewBoxes( *pTblNd, aTmpLst );
2896     else
2897         delete pInsRowUndo, pInsRowUndo = 0;
2898     return bRet;
2899 }
2900 
IsEmpty() const2901 sal_Bool SwUndoTblCpyTbl::IsEmpty() const
2902 {
2903     return !pInsRowUndo && !pArr->Count();
2904 }
2905 
2906 
2907 //////////////////////////////////////////////////////////////////////////
2908 
SwUndoCpyTbl()2909 SwUndoCpyTbl::SwUndoCpyTbl()
2910     : SwUndo( UNDO_CPYTBL ), pDel( 0 ), nTblNode( 0 )
2911 {
2912 }
2913 
~SwUndoCpyTbl()2914 SwUndoCpyTbl::~SwUndoCpyTbl()
2915 {
2916     delete pDel;
2917 }
2918 
UndoImpl(::sw::UndoRedoContext & rContext)2919 void SwUndoCpyTbl::UndoImpl(::sw::UndoRedoContext & rContext)
2920 {
2921     SwDoc & rDoc = rContext.GetDoc();
2922     SwTableNode* pTNd = rDoc.GetNodes()[ nTblNode ]->GetTableNode();
2923 
2924     // harte SeitenUmbrueche am nachfolgenden Node verschieben
2925     SwCntntNode* pNextNd = rDoc.GetNodes()[ pTNd->EndOfSectionIndex()+1 ]->GetCntntNode();
2926     if( pNextNd )
2927     {
2928         SwFrmFmt* pTableFmt = pTNd->GetTable().GetFrmFmt();
2929         const SfxPoolItem *pItem;
2930 
2931         if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2932             sal_False, &pItem ) )
2933             pNextNd->SetAttr( *pItem );
2934 
2935         if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2936             sal_False, &pItem ) )
2937             pNextNd->SetAttr( *pItem );
2938     }
2939 
2940     SwPaM aPam( *pTNd, *pTNd->EndOfSectionNode(), 0 , 1 );
2941     pDel = new SwUndoDelete( aPam, sal_True );
2942 }
2943 
RedoImpl(::sw::UndoRedoContext & rContext)2944 void SwUndoCpyTbl::RedoImpl(::sw::UndoRedoContext & rContext)
2945 {
2946     pDel->UndoImpl(rContext);
2947     delete pDel, pDel = 0;
2948 }
2949 
2950 
2951 //////////////////////////////////////////////////////////////////////////
2952 
SwUndoSplitTbl(const SwTableNode & rTblNd,SwSaveRowSpan * pRowSp,sal_uInt16 eMode,sal_Bool bNewSize)2953 SwUndoSplitTbl::SwUndoSplitTbl( const SwTableNode& rTblNd,
2954     SwSaveRowSpan* pRowSp, sal_uInt16 eMode, sal_Bool bNewSize )
2955     : SwUndo( UNDO_SPLIT_TABLE ),
2956     nTblNode( rTblNd.GetIndex() ), nOffset( 0 ), mpSaveRowSpan( pRowSp ), pSavTbl( 0 ),
2957     pHistory( 0 ), nMode( eMode ), nFmlEnd( 0 ), bCalcNewSize( bNewSize )
2958 {
2959     switch( nMode )
2960     {
2961     case HEADLINE_BOXATRCOLLCOPY:
2962             pHistory = new SwHistory;
2963             // kein break;
2964     case HEADLINE_BORDERCOPY:
2965     case HEADLINE_BOXATTRCOPY:
2966         pSavTbl = new _SaveTable( rTblNd.GetTable(), 1, sal_False );
2967         break;
2968     }
2969 }
2970 
~SwUndoSplitTbl()2971 SwUndoSplitTbl::~SwUndoSplitTbl()
2972 {
2973     delete pSavTbl;
2974     delete pHistory;
2975     delete mpSaveRowSpan;
2976 }
2977 
UndoImpl(::sw::UndoRedoContext & rContext)2978 void SwUndoSplitTbl::UndoImpl(::sw::UndoRedoContext & rContext)
2979 {
2980     SwDoc *const pDoc = & rContext.GetDoc();
2981     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
2982 
2983     pPam->DeleteMark();
2984     SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
2985     rIdx = nTblNode + nOffset;
2986 
2987     //Den implizit erzeugten Absatz wieder entfernen.
2988     pDoc->GetNodes().Delete( rIdx, 1 );
2989 
2990     rIdx = nTblNode + nOffset;
2991     SwTableNode* pTblNd = rIdx.GetNode().GetTableNode();
2992     SwTable& rTbl = pTblNd->GetTable();
2993 
2994     SwTableFmlUpdate aMsgHnt( &rTbl );
2995     aMsgHnt.eFlags = TBL_BOXPTR;
2996     pDoc->UpdateTblFlds( &aMsgHnt );
2997 
2998     switch( nMode )
2999     {
3000     case HEADLINE_BOXATRCOLLCOPY:
3001         if( pHistory )
3002             pHistory->TmpRollback( pDoc, nFmlEnd );
3003 
3004         // kein break
3005     case HEADLINE_BOXATTRCOPY:
3006     case HEADLINE_BORDERCOPY:
3007         {
3008             pSavTbl->CreateNew( rTbl, sal_False );
3009             pSavTbl->RestoreAttr( rTbl );
3010         }
3011         break;
3012 
3013     case HEADLINE_CNTNTCOPY:
3014         // die erzeugte 1. Line muss wieder entfernt werden
3015         {
3016             SwSelBoxes aSelBoxes;
3017             SwTableBox* pBox = rTbl.GetTblBox( nTblNode + nOffset + 1 );
3018             rTbl.SelLineFromBox( pBox, aSelBoxes, sal_True );
3019             _FndBox aTmpBox( 0, 0 );
3020             aTmpBox.SetTableLines( aSelBoxes, rTbl );
3021             aTmpBox.DelFrms( rTbl );
3022             rTbl.DeleteSel( pDoc, aSelBoxes, 0, 0, sal_False, sal_False );
3023         }
3024         break;
3025     }
3026 
3027     pDoc->GetNodes().MergeTable( rIdx );
3028 
3029     if( pHistory )
3030     {
3031         pHistory->TmpRollback( pDoc, 0 );
3032         pHistory->SetTmpEnd( pHistory->Count() );
3033     }
3034     if( mpSaveRowSpan )
3035     {
3036         pTblNd = rIdx.GetNode().FindTableNode();
3037         if( pTblNd )
3038             pTblNd->GetTable().RestoreRowSpan( *mpSaveRowSpan );
3039     }
3040     ClearFEShellTabCols();
3041 }
3042 
RedoImpl(::sw::UndoRedoContext & rContext)3043 void SwUndoSplitTbl::RedoImpl(::sw::UndoRedoContext & rContext)
3044 {
3045     SwDoc *const pDoc = & rContext.GetDoc();
3046     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3047 
3048     pPam->DeleteMark();
3049     pPam->GetPoint()->nNode = nTblNode;
3050     pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize );
3051 
3052     ClearFEShellTabCols();
3053 }
3054 
RepeatImpl(::sw::RepeatContext & rContext)3055 void SwUndoSplitTbl::RepeatImpl(::sw::RepeatContext & rContext)
3056 {
3057     SwPaM *const pPam = & rContext.GetRepeatPaM();
3058     SwDoc *const pDoc = & rContext.GetDoc();
3059 
3060     pDoc->SplitTable( *pPam->GetPoint(), nMode, bCalcNewSize );
3061     ClearFEShellTabCols();
3062 }
3063 
SaveFormula(SwHistory & rHistory)3064 void SwUndoSplitTbl::SaveFormula( SwHistory& rHistory )
3065 {
3066     if( !pHistory )
3067         pHistory = new SwHistory;
3068 
3069     nFmlEnd = rHistory.Count();
3070     pHistory->Move( 0, &rHistory );
3071 }
3072 
3073 
3074 //////////////////////////////////////////////////////////////////////////
3075 
SwUndoMergeTbl(const SwTableNode & rTblNd,const SwTableNode & rDelTblNd,sal_Bool bWithPrv,sal_uInt16 nMd)3076 SwUndoMergeTbl::SwUndoMergeTbl( const SwTableNode& rTblNd,
3077                                 const SwTableNode& rDelTblNd,
3078                                 sal_Bool bWithPrv, sal_uInt16 nMd )
3079     : SwUndo( UNDO_MERGE_TABLE ), pSavTbl( 0 ),
3080     pHistory( 0 ), nMode( nMd ), bWithPrev( bWithPrv )
3081 {
3082     // Endnode der letzen Tabellenzelle merken, die auf der Position verbleibt
3083     if( bWithPrev )
3084         nTblNode = rDelTblNd.EndOfSectionIndex() - 1;
3085     else
3086         nTblNode = rTblNd.EndOfSectionIndex() - 1;
3087 
3088     aName = rDelTblNd.GetTable().GetFrmFmt()->GetName();
3089     pSavTbl = new _SaveTable( rDelTblNd.GetTable() );
3090 
3091     pSavHdl = bWithPrev ? new _SaveTable( rTblNd.GetTable(), 1 ) : 0;
3092 }
3093 
~SwUndoMergeTbl()3094 SwUndoMergeTbl::~SwUndoMergeTbl()
3095 {
3096     delete pSavTbl;
3097     delete pSavHdl;
3098     delete pHistory;
3099 }
3100 
UndoImpl(::sw::UndoRedoContext & rContext)3101 void SwUndoMergeTbl::UndoImpl(::sw::UndoRedoContext & rContext)
3102 {
3103     SwDoc *const pDoc = & rContext.GetDoc();
3104     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3105 
3106     pPam->DeleteMark();
3107     SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
3108     rIdx = nTblNode;
3109 
3110     SwTableNode* pTblNd = rIdx.GetNode().FindTableNode();
3111     SwTable* pTbl = &pTblNd->GetTable();
3112 
3113     SwTableFmlUpdate aMsgHnt( pTbl );
3114     aMsgHnt.eFlags = TBL_BOXPTR;
3115     pDoc->UpdateTblFlds( &aMsgHnt );
3116 
3117     //Lines fuer das Layout-Update herausuchen.
3118     _FndBox aFndBox( 0, 0 );
3119     aFndBox.SetTableLines( *pTbl );
3120     aFndBox.DelFrms( *pTbl );
3121     // ? TL_CHART2: notification or locking of controller required ?
3122 
3123     SwTableNode* pNew = pDoc->GetNodes().SplitTable( rIdx, sal_True, sal_False );
3124 
3125     //Layout updaten
3126     aFndBox.MakeFrms( *pTbl );
3127     // ? TL_CHART2: notification or locking of controller required ?
3128 
3129     if( bWithPrev )
3130     {
3131         // den Namen umsetzen
3132         pNew->GetTable().GetFrmFmt()->SetName( pTbl->GetFrmFmt()->GetName() );
3133         pSavHdl->RestoreAttr( pNew->GetTable() );
3134     }
3135     else
3136         pTbl = &pNew->GetTable();
3137     pTbl->GetFrmFmt()->SetName( aName );
3138 
3139 //  pSavTbl->CreateNew( *pTbl, sal_False );
3140     pSavTbl->RestoreAttr( *pTbl );
3141 
3142 
3143     if( pHistory )
3144     {
3145         pHistory->TmpRollback( pDoc, 0 );
3146         pHistory->SetTmpEnd( pHistory->Count() );
3147     }
3148 
3149     // fuer die neue Tabelle die Frames anlegen
3150     SwNodeIndex aTmpIdx( *pNew );
3151     pNew->MakeFrms( &aTmpIdx );
3152 
3153     // Cursor  irgendwo in den Content stellen
3154     SwCntntNode* pCNd = pDoc->GetNodes().GoNext( &rIdx );
3155     pPam->GetPoint()->nContent.Assign( pCNd, 0 );
3156 
3157     ClearFEShellTabCols();
3158 
3159     // TL_CHART2: need to inform chart of probably changed cell names
3160     SwChartDataProvider *pPCD = pDoc->GetChartDataProvider();
3161     if (pPCD)
3162     {
3163         pDoc->UpdateCharts( pTbl->GetFrmFmt()->GetName() );
3164         pDoc->UpdateCharts( pNew->GetTable().GetFrmFmt()->GetName() );
3165     }
3166 }
3167 
RedoImpl(::sw::UndoRedoContext & rContext)3168 void SwUndoMergeTbl::RedoImpl(::sw::UndoRedoContext & rContext)
3169 {
3170     SwDoc *const pDoc = & rContext.GetDoc();
3171     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
3172 
3173     pPam->DeleteMark();
3174     pPam->GetPoint()->nNode = nTblNode;
3175     if( bWithPrev )
3176         pPam->GetPoint()->nNode = nTblNode + 3;
3177     else
3178         pPam->GetPoint()->nNode = nTblNode;
3179 
3180     pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode );
3181 
3182     ClearFEShellTabCols();
3183 }
3184 
RepeatImpl(::sw::RepeatContext & rContext)3185 void SwUndoMergeTbl::RepeatImpl(::sw::RepeatContext & rContext)
3186 {
3187     SwDoc *const pDoc = & rContext.GetDoc();
3188     SwPaM *const pPam = & rContext.GetRepeatPaM();
3189 
3190     pDoc->MergeTable( *pPam->GetPoint(), bWithPrev, nMode );
3191     ClearFEShellTabCols();
3192 }
3193 
SaveFormula(SwHistory & rHistory)3194 void SwUndoMergeTbl::SaveFormula( SwHistory& rHistory )
3195 {
3196     if( !pHistory )
3197         pHistory = new SwHistory;
3198     pHistory->Move( 0, &rHistory );
3199 }
3200 
3201 
3202 //////////////////////////////////////////////////////////////////////////
3203 
InsertSort(SvUShorts & rArr,sal_uInt16 nIdx,sal_uInt16 * pInsPos)3204 void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos )
3205 {
3206     sal_uInt16 nO   = rArr.Count(), nM, nU = 0;
3207     if( nO > 0 )
3208     {
3209         nO--;
3210         while( nU <= nO )
3211         {
3212             nM = nU + ( nO - nU ) / 2;
3213             if( *(rArr.GetData() + nM) == nIdx )
3214             {
3215                 ASSERT( sal_False, "Index ist schon vorhanden, darf nie sein!" );
3216                 return;
3217             }
3218             if( *(rArr.GetData() + nM) < nIdx )
3219                 nU = nM + 1;
3220             else if( nM == 0 )
3221                 break;
3222             else
3223                 nO = nM - 1;
3224         }
3225     }
3226     rArr.Insert( nIdx, nU );
3227     if( pInsPos )
3228         *pInsPos = nU;
3229 }
3230 
InsertSort(SvULongs & rArr,sal_uLong nIdx,sal_uInt16 * pInsPos)3231 void InsertSort( SvULongs& rArr, sal_uLong nIdx, sal_uInt16* pInsPos )
3232 {
3233     sal_uInt16 nO   = rArr.Count(), nM, nU = 0;
3234     if( nO > 0 )
3235     {
3236         nO--;
3237         while( nU <= nO )
3238         {
3239             nM = nU + ( nO - nU ) / 2;
3240             if( *(rArr.GetData() + nM) == nIdx )
3241             {
3242                 ASSERT( sal_False, "Index ist schon vorhanden, darf nie sein!" );
3243                 return;
3244             }
3245             if( *(rArr.GetData() + nM) < nIdx )
3246                 nU = nM + 1;
3247             else if( nM == 0 )
3248                 break;
3249             else
3250                 nO = nM - 1;
3251         }
3252     }
3253     rArr.Insert( nIdx, nU );
3254     if( pInsPos )
3255         *pInsPos = nU;
3256 }
3257 
3258 #if defined( JP_DEBUG ) && defined(DBG_UTIL)
3259 
3260 
DumpDoc(SwDoc * pDoc,const String & rFileNm)3261 void DumpDoc( SwDoc* pDoc, const String& rFileNm )
3262 {
3263     Writer* pWrt = SwIoSystem::GetWriter( "DEBUG" );
3264     if( pWrt )
3265     {
3266         SvFileStream aStream( rFileNm, STREAM_STD_WRITE );
3267         SwPaM* pPam = new SwPaM( pDoc, SwPosition( pDoc->GetNodes().EndOfContent ,
3268                                                  pDoc->GetNodes().EndOfContent ));
3269         pPam->Move( fnMoveBackward, fnGoDoc );
3270         pPam->SetMark();
3271         pPam->Move( fnMoveForward, fnGoDoc );
3272 
3273         pWrt->Write( pPam, *pDoc, aStream, rFileNm.GetStr() );
3274 
3275         delete pPam;
3276     }
3277 }
CheckTable(const SwTable & rTbl)3278 void CheckTable( const SwTable& rTbl )
3279 {
3280     const SwNodes& rNds = rTbl.GetFrmFmt()->GetDoc()->GetNodes();
3281     const SwTableSortBoxes& rSrtArr = pTblNd->GetTable().GetTabSortBoxes();
3282     for( sal_uInt16 n = 0; n < rSrtArr.Count(); ++n )
3283     {
3284         const SwTableBox* pBox = rSrtArr[ n ];
3285         const SwNode* pNd = pBox->GetSttNd();
3286         ASSERT( rNds[ *pBox->GetSttIdx() ] == pNd, "Box mit falchem StartNode"  );
3287     }
3288 }
3289 #endif
3290 
3291 
3292