merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / docnode / ndtbl.cxx
blob1cf706fe23239c385ea4fb146c83bc2f09cbb012
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ndtbl.cxx,v $
10 * $Revision: 1.57 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
34 #include <com/sun/star/chart2/XChartDocument.hpp>
36 #ifdef WTC
37 #define private public
38 #endif
39 #include <hintids.hxx>
42 #include <svx/lrspitem.hxx>
43 #include <svx/brkitem.hxx>
44 #include <svx/protitem.hxx>
45 #include <svx/boxitem.hxx>
46 #include <svtools/stritem.hxx>
47 // OD 06.08.2003 #i17174#
48 #include <svx/shaditem.hxx>
49 #include <fmtfsize.hxx>
50 #include <fmtornt.hxx>
51 #include <fmtfordr.hxx>
52 #include <fmtpdsc.hxx>
53 #include <fmtanchr.hxx>
54 #include <fmtlsplt.hxx>
55 #include <frmatr.hxx>
56 #include <charatr.hxx>
57 #include <cellfrm.hxx>
58 #include <pagefrm.hxx>
59 #include <tabcol.hxx>
60 #include <doc.hxx>
61 #include <cntfrm.hxx>
62 #include <pam.hxx>
63 #include <swcrsr.hxx>
64 #include <viscrs.hxx>
65 #include <swtable.hxx>
66 #include <ndtxt.hxx>
67 #include <swundo.hxx>
68 #include <tblsel.hxx>
69 #include <fldbas.hxx>
70 #include <poolfmt.hxx>
71 #include <tabfrm.hxx>
72 #include <undobj.hxx>
73 #include <tblafmt.hxx>
74 #include <swcache.hxx>
75 #include <ddefld.hxx>
76 #include <frminf.hxx>
77 #include <cellatr.hxx>
78 #include <swtblfmt.hxx>
79 #include <swddetbl.hxx>
80 #include <mvsave.hxx>
81 #include <docary.hxx>
82 #include <redline.hxx>
83 #include <rolbck.hxx>
84 #include <tblrwcl.hxx>
85 #include <editsh.hxx>
86 #include <txtfrm.hxx>
87 #include <ftnfrm.hxx>
88 #include <section.hxx>
89 #include <frmtool.hxx>
90 #include <node2lay.hxx>
91 #ifndef _COMCORE_HRC
92 #include <comcore.hrc>
93 #endif
94 #include "docsh.hxx"
95 #ifdef LINUX
96 #include <tabcol.hxx>
97 #endif
98 #include <unochart.hxx>
100 #include <node.hxx>
101 #include <ndtxt.hxx>
103 #include <map>
104 #include <algorithm>
105 // --> OD 2005-12-05 #i27138#
106 #include <rootfrm.hxx>
107 // <--
108 #ifdef PRODUCT
109 #define CHECK_TABLE(t)
110 #else
111 #ifdef DEBUG
112 #define CHECK_TABLE(t) (t).CheckConsistency();
113 #else
114 #define CHECK_TABLE(t)
115 #endif
116 #endif
117 #include <fldupde.hxx>
120 using namespace ::com::sun::star;
122 // #i17764# delete table redlines when modifying the table structure?
123 // #define DEL_TABLE_REDLINES 1
125 const sal_Unicode T2T_PARA = 0x0a;
127 extern void ClearFEShellTabCols();
129 // steht im gctable.cxx
130 extern BOOL lcl_GC_Line_Border( const SwTableLine*& , void* pPara );
132 #ifdef DEL_TABLE_REDLINES
133 class lcl_DelRedlines
135 SwDoc* pDoc;
136 public:
137 lcl_DelRedlines( const SwTableNode& rNd, BOOL bCheckForOwnRedline );
138 lcl_DelRedlines( SwPaM& rPam );
140 ~lcl_DelRedlines() { pDoc->EndUndo(UNDO_EMPTY, NULL); }
143 lcl_DelRedlines::lcl_DelRedlines( SwPaM & rPam) : pDoc( rPam.GetDoc() )
145 pDoc->StartUndo(UNDO_EMPTY, NULL);
146 if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
147 pDoc->AcceptRedline( rPam, true );
149 #endif
151 void lcl_SetDfltBoxAttr( SwFrmFmt& rFmt, BYTE nId )
153 BOOL bTop = FALSE, bBottom = FALSE, bLeft = FALSE, bRight = FALSE;
154 switch ( nId )
156 case 0: bTop = bBottom = bLeft = TRUE; break;
157 case 1: bTop = bBottom = bLeft = bRight = TRUE; break;
158 case 2: bBottom = bLeft = TRUE; break;
159 case 3: bBottom = bLeft = bRight = TRUE; break;
162 const BOOL bHTML = rFmt.getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE);
163 Color aCol( bHTML ? COL_GRAY : COL_BLACK );
164 SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 );
165 if ( bHTML )
167 aLine.SetOutWidth( DEF_DOUBLE_LINE7_OUT );
168 aLine.SetInWidth ( DEF_DOUBLE_LINE7_IN );
169 aLine.SetDistance( DEF_DOUBLE_LINE7_DIST);
171 SvxBoxItem aBox(RES_BOX); aBox.SetDistance( 55 );
172 if ( bTop )
173 aBox.SetLine( &aLine, BOX_LINE_TOP );
174 if ( bBottom )
175 aBox.SetLine( &aLine, BOX_LINE_BOTTOM );
176 if ( bLeft )
177 aBox.SetLine( &aLine, BOX_LINE_LEFT );
178 if ( bRight )
179 aBox.SetLine( &aLine, BOX_LINE_RIGHT );
180 rFmt.SetFmtAttr( aBox );
183 void lcl_SetDfltBoxAttr( SwTableBox& rBox, SvPtrarr &rBoxFmtArr, BYTE nId,
184 const SwTableAutoFmt* pAutoFmt = 0 )
186 SvPtrarr* pArr = (SvPtrarr*)rBoxFmtArr[ nId ];
187 if( !pArr )
189 pArr = new SvPtrarr;
190 rBoxFmtArr.Replace( pArr, nId );
193 SwTableBoxFmt* pNewBoxFmt = 0;
194 SwFrmFmt* pBoxFmt = rBox.GetFrmFmt();
195 for( USHORT n = 0; n < pArr->Count(); n += 2 )
196 if( pArr->GetObject( n ) == pBoxFmt )
198 pNewBoxFmt = (SwTableBoxFmt*)pArr->GetObject( n + 1 );
199 break;
202 if( !pNewBoxFmt )
204 SwDoc* pDoc = pBoxFmt->GetDoc();
205 // das Format ist also nicht vorhanden, also neu erzeugen
206 pNewBoxFmt = pDoc->MakeTableBoxFmt();
207 pNewBoxFmt->SetFmtAttr( pBoxFmt->GetAttrSet().Get( RES_FRM_SIZE ) );
209 if( pAutoFmt )
210 pAutoFmt->UpdateToSet( nId, (SfxItemSet&)pNewBoxFmt->GetAttrSet(),
211 SwTableAutoFmt::UPDATE_BOX,
212 pDoc->GetNumberFormatter( TRUE ) );
213 else
214 ::lcl_SetDfltBoxAttr( *pNewBoxFmt, nId );
216 void* p = pBoxFmt;
217 pArr->Insert( p, pArr->Count() );
218 p = pNewBoxFmt;
219 pArr->Insert( p, pArr->Count() );
221 rBox.ChgFrmFmt( pNewBoxFmt );
224 SwTableBoxFmt *lcl_CreateDfltBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
225 USHORT nCols, BYTE nId )
227 if ( !rBoxFmtArr[nId] )
229 SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
230 if( USHRT_MAX != nCols )
231 pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
232 USHRT_MAX / nCols, 0 ));
233 ::lcl_SetDfltBoxAttr( *pBoxFmt, nId );
234 rBoxFmtArr.Replace( pBoxFmt, nId );
236 return (SwTableBoxFmt*)rBoxFmtArr[nId];
239 SwTableBoxFmt *lcl_CreateAFmtBoxFmt( SwDoc &rDoc, SvPtrarr &rBoxFmtArr,
240 const SwTableAutoFmt& rAutoFmt,
241 USHORT nCols, BYTE nId )
243 if( !rBoxFmtArr[nId] )
245 SwTableBoxFmt* pBoxFmt = rDoc.MakeTableBoxFmt();
246 rAutoFmt.UpdateToSet( nId, (SfxItemSet&)pBoxFmt->GetAttrSet(),
247 SwTableAutoFmt::UPDATE_BOX,
248 rDoc.GetNumberFormatter( TRUE ) );
249 if( USHRT_MAX != nCols )
250 pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
251 USHRT_MAX / nCols, 0 ));
252 rBoxFmtArr.Replace( pBoxFmt, nId );
254 return (SwTableBoxFmt*)rBoxFmtArr[nId];
257 SwTableNode* SwDoc::IsIdxInTbl(const SwNodeIndex& rIdx)
259 SwTableNode* pTableNd = 0;
260 ULONG nIndex = rIdx.GetIndex();
261 do {
262 SwNode* pNd = (SwNode*)GetNodes()[ nIndex ]->StartOfSectionNode();
263 if( 0 != ( pTableNd = pNd->GetTableNode() ) )
264 break;
266 nIndex = pNd->GetIndex();
267 } while ( nIndex );
268 return pTableNd;
272 // --------------- einfuegen einer neuen Box --------------
274 // fuege in der Line, vor der InsPos eine neue Box ein.
276 BOOL SwNodes::InsBoxen( SwTableNode* pTblNd,
277 SwTableLine* pLine,
278 SwTableBoxFmt* pBoxFmt,
279 SwTxtFmtColl* pTxtColl,
280 const SfxItemSet* pAutoAttr,
281 USHORT nInsPos,
282 USHORT nCnt )
284 if( !nCnt )
285 return FALSE;
286 ASSERT( pLine, "keine gueltige Zeile" );
288 // Index hinter die letzte Box der Line
289 ULONG nIdxPos = 0;
290 SwTableBox *pPrvBox = 0, *pNxtBox = 0;
291 if( pLine->GetTabBoxes().Count() )
293 if( nInsPos < pLine->GetTabBoxes().Count() )
295 if( 0 == (pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable(),
296 pLine->GetTabBoxes()[ nInsPos ] )))
297 pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
299 else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable(),
300 pLine->GetTabBoxes()[ nInsPos-1 ] )))
301 pNxtBox = pLine->FindNextBox( pTblNd->GetTable() );
303 else if( 0 == ( pNxtBox = pLine->FindNextBox( pTblNd->GetTable() )))
304 pPrvBox = pLine->FindPreviousBox( pTblNd->GetTable() );
306 if( !pPrvBox && !pNxtBox )
308 BOOL bSetIdxPos = TRUE;
309 if( pTblNd->GetTable().GetTabLines().Count() && !nInsPos )
311 const SwTableLine* pTblLn = pLine;
312 while( pTblLn->GetUpper() )
313 pTblLn = pTblLn->GetUpper()->GetUpper();
315 if( pTblNd->GetTable().GetTabLines()[ 0 ] == pTblLn )
317 // also vor die erste Box der Tabelle
318 while( ( pNxtBox = pLine->GetTabBoxes()[0])->GetTabLines().Count() )
319 pLine = pNxtBox->GetTabLines()[0];
320 nIdxPos = pNxtBox->GetSttIdx();
321 bSetIdxPos = FALSE;
324 if( bSetIdxPos )
325 // Tabelle ohne irgendeinen Inhalt oder am Ende, also vors Ende
326 nIdxPos = pTblNd->EndOfSectionIndex();
328 else if( pNxtBox ) // es gibt einen Nachfolger
329 nIdxPos = pNxtBox->GetSttIdx();
330 else // es gibt einen Vorgaenger
331 nIdxPos = pPrvBox->GetSttNd()->EndOfSectionIndex() + 1;
333 SwNodeIndex aEndIdx( *this, nIdxPos );
334 for( USHORT n = 0; n < nCnt; ++n )
336 SwStartNode* pSttNd = new SwStartNode( aEndIdx, ND_STARTNODE,
337 SwTableBoxStartNode );
338 pSttNd->pStartOfSection = pTblNd;
339 new SwEndNode( aEndIdx, *pSttNd );
341 pPrvBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
342 pLine->GetTabBoxes().C40_INSERT( SwTableBox, pPrvBox, nInsPos + n );
344 //if( NO_NUMBERING == pTxtColl->GetOutlineLevel()//#outline level,zhaojianwei
345 if( ! pTxtColl->IsAssignedToListLevelOfOutlineStyle()//<-end,zhaojianwei
346 //FEATURE::CONDCOLL
347 && RES_CONDTXTFMTCOLL != pTxtColl->Which()
348 //FEATURE::CONDCOLL
350 new SwTxtNode( SwNodeIndex( *pSttNd->EndOfSectionNode() ),
351 pTxtColl, pAutoAttr );
352 else
354 // Outline-Numerierung richtig behandeln !!!
355 SwTxtNode* pTNd = new SwTxtNode(
356 SwNodeIndex( *pSttNd->EndOfSectionNode() ),
357 (SwTxtFmtColl*)GetDoc()->GetDfltTxtFmtColl(),
358 pAutoAttr );
359 pTNd->ChgFmtColl( pTxtColl );
362 return TRUE;
365 // --------------- einfuegen einer neuen Tabelle --------------
367 const SwTable* SwDoc::InsertTable( const SwInsertTableOptions& rInsTblOpts,
368 const SwPosition& rPos, USHORT nRows,
369 USHORT nCols, sal_Int16 eAdjust,
370 const SwTableAutoFmt* pTAFmt,
371 const SvUShorts* pColArr,
372 BOOL bCalledFromShell,
373 BOOL bNewModel )
375 ASSERT( nRows, "Tabelle ohne Zeile?" );
376 ASSERT( nCols, "Tabelle ohne Spalten?" );
379 // nicht in Fussnoten kopieren !!
380 if( rPos.nNode < GetNodes().GetEndOfInserts().GetIndex() &&
381 rPos.nNode >= GetNodes().GetEndOfInserts().StartOfSectionIndex() )
382 return 0;
384 // sollte das ColumnArray die falsche Anzahl haben wird es ignoriert!
385 if( pColArr &&
386 (nCols + ( text::HoriOrientation::NONE == eAdjust ? 2 : 1 )) != pColArr->Count() )
387 pColArr = 0;
390 String aTblName = GetUniqueTblName();
392 if( DoesUndo() )
394 ClearRedo();
395 AppendUndo( new SwUndoInsTbl( rPos, nCols, nRows, static_cast<USHORT>(eAdjust),
396 rInsTblOpts, pTAFmt, pColArr,
397 aTblName));
400 // fuege erstmal die Nodes ein
401 // hole das Auto-Format fuer die Tabelle
402 SwTxtFmtColl *pBodyColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE ),
403 *pHeadColl = pBodyColl;
405 BOOL bDfltBorders = 0 != ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER );
407 if( (rInsTblOpts.mnInsMode & tabopts::HEADLINE) && (1 != nRows || !bDfltBorders) )
408 pHeadColl = GetTxtCollFromPool( RES_POOLCOLL_TABLE_HDLN );
410 const USHORT nRowsToRepeat =
411 tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
412 rInsTblOpts.mnRowsToRepeat :
415 /* #106283# Save content node to extract FRAMEDIR from. */
416 const SwCntntNode * pCntntNd = rPos.nNode.GetNode().GetCntntNode();
418 /* #109161# If we are called from a shell pass the attrset from
419 pCntntNd (aka the node the table is inserted at) thus causing
420 SwNodes::InsertTable to propagate an adjust item if
421 necessary. */
422 SwTableNode *pTblNd = GetNodes().InsertTable(
423 rPos.nNode,
424 nCols,
425 pBodyColl,
426 nRows,
427 nRowsToRepeat,
428 pHeadColl,
429 bCalledFromShell ? &pCntntNd->GetSwAttrSet() : 0 );
431 // dann erstelle die Box/Line/Table-Struktur
432 SwTableLineFmt* pLineFmt = MakeTableLineFmt();
433 SwTableFmt* pTableFmt = MakeTblFrmFmt( aTblName, GetDfltFrmFmt() );
435 /* #106283# If the node to insert the table at is a context node and has a
436 non-default FRAMEDIR propagate it to the table. */
437 if (pCntntNd)
439 const SwAttrSet & aNdSet = pCntntNd->GetSwAttrSet();
440 const SfxPoolItem *pItem = NULL;
442 if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, TRUE, &pItem )
443 && pItem != NULL)
445 pTableFmt->SetFmtAttr( *pItem );
449 //Orientation am Fmt der Table setzen
450 pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
451 // alle Zeilen haben die Fill-Order von links nach rechts !
452 pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
454 // die Tabelle bekommt USHRT_MAX als default SSize
455 SwTwips nWidth = USHRT_MAX;
456 if( pColArr )
458 USHORT nSttPos = (*pColArr)[ 0 ];
459 USHORT nLastPos = (*pColArr)[ USHORT(pColArr->Count()-1)];
460 if( text::HoriOrientation::NONE == eAdjust )
462 USHORT nFrmWidth = nLastPos;
463 nLastPos = (*pColArr)[ USHORT(pColArr->Count()-2)];
464 pTableFmt->SetFmtAttr( SvxLRSpaceItem( nSttPos, nFrmWidth - nLastPos, 0, 0, RES_LR_SPACE ) );
466 nWidth = nLastPos - nSttPos;
468 else if( nCols )
470 nWidth /= nCols;
471 nWidth *= nCols; // to avoid rounding problems
473 pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
474 if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
475 pTableFmt->SetFmtAttr( SwFmtLayoutSplit( FALSE ));
477 // verschiebe ggfs. die harten PageDesc/PageBreak Attribute:
478 SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]
479 ->GetCntntNode();
480 if( pNextNd && pNextNd->HasSwAttrSet() )
482 const SfxItemSet* pNdSet = pNextNd->GetpSwAttrSet();
483 const SfxPoolItem *pItem;
484 if( SFX_ITEM_SET == pNdSet->GetItemState( RES_PAGEDESC, FALSE,
485 &pItem ) )
487 pTableFmt->SetFmtAttr( *pItem );
488 pNextNd->ResetAttr( RES_PAGEDESC );
489 pNdSet = pNextNd->GetpSwAttrSet();
491 if( pNdSet && SFX_ITEM_SET == pNdSet->GetItemState( RES_BREAK, FALSE,
492 &pItem ) )
494 pTableFmt->SetFmtAttr( *pItem );
495 pNextNd->ResetAttr( RES_BREAK );
499 SwTable * pNdTbl = &pTblNd->GetTable();
500 pTableFmt->Add( pNdTbl ); // das Frame-Format setzen
502 pNdTbl->SetRowsToRepeat( nRowsToRepeat );
503 pNdTbl->SetTableModel( bNewModel );
505 SvPtrarr aBoxFmtArr( 0, 16 );
506 SwTableBoxFmt* pBoxFmt = 0;
507 if( !bDfltBorders && !pTAFmt )
509 pBoxFmt = MakeTableBoxFmt();
510 pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nCols, 0 ));
512 else
514 const USHORT nBoxArrLen = pTAFmt ? 16 : 4;
515 for( USHORT i = 0; i < nBoxArrLen; ++i )
516 aBoxFmtArr.Insert( (void*)0, i );
518 // --> OD 2008-02-25 #refactorlists#
519 // SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
520 SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
521 // <--
523 SwNodeIndex aNdIdx( *pTblNd, 1 ); // auf den ersten Box-StartNode
524 SwTableLines& rLines = pNdTbl->GetTabLines();
525 for( USHORT n = 0; n < nRows; ++n )
527 SwTableLine* pLine = new SwTableLine( pLineFmt, nCols, 0 );
528 rLines.C40_INSERT( SwTableLine, pLine, n );
529 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
530 for( USHORT i = 0; i < nCols; ++i )
532 SwTableBoxFmt *pBoxF;
533 if( pTAFmt )
535 BYTE nId = static_cast<BYTE>(!n ? 0 : (( n+1 == nRows )
536 ? 12 : (4 * (1 + ((n-1) & 1 )))));
537 nId = nId + static_cast<BYTE>( !i ? 0 :
538 ( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
539 pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr, *pTAFmt,
540 nCols, nId );
542 // ggfs. noch die Absatz/ZeichenAttribute setzen
543 if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
545 aCharSet.ClearItem();
546 pTAFmt->UpdateToSet( nId, aCharSet,
547 SwTableAutoFmt::UPDATE_CHAR, 0 );
548 if( aCharSet.Count() )
549 GetNodes()[ aNdIdx.GetIndex()+1 ]->GetCntntNode()->
550 SetAttr( aCharSet );
553 else if( bDfltBorders )
555 BYTE nBoxId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
556 pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr, nCols, nBoxId);
558 else
559 pBoxF = pBoxFmt;
561 // fuer AutoFormat bei der Eingabe: beim Einfuegen der Tabelle
562 // werden gleich die Spalten gesetzt. Im Array stehen die
563 // Positionen der Spalten!! (nicht deren Breite!)
564 if( pColArr )
566 nWidth = (*pColArr)[ USHORT(i + 1) ] - (*pColArr)[ i ];
567 if( pBoxF->GetFrmSize().GetWidth() != nWidth )
569 if( pBoxF->GetDepends() ) // neues Format erzeugen!
571 SwTableBoxFmt *pNewFmt = MakeTableBoxFmt();
572 *pNewFmt = *pBoxF;
573 pBoxF = pNewFmt;
575 pBoxF->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth ));
579 SwTableBox *pBox = new SwTableBox( pBoxF, aNdIdx, pLine);
580 rBoxes.C40_INSERT( SwTableBox, pBox, i );
581 aNdIdx += 3; // StartNode, TextNode, EndNode == 3 Nodes
584 // und Frms einfuegen.
585 GetNodes().GoNext( &aNdIdx ); // zum naechsten ContentNode
586 pTblNd->MakeFrms( &aNdIdx );
588 if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() ))
590 SwPaM aPam( *pTblNd->EndOfSectionNode(), *pTblNd, 1 );
591 if( IsRedlineOn() )
592 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
593 else
594 SplitRedline( aPam );
597 SetModified();
598 CHECK_TABLE( *pNdTbl );
599 return pNdTbl;
602 SwTableNode* SwNodes::InsertTable( const SwNodeIndex& rNdIdx,
603 USHORT nBoxes,
604 SwTxtFmtColl* pCntntTxtColl,
605 USHORT nLines,
606 USHORT nRepeat,
607 SwTxtFmtColl* pHeadlineTxtColl,
608 const SwAttrSet * pAttrSet)
610 if( !nBoxes )
611 return 0;
613 // wenn Lines angegeben, erzeuge die Matrix aus Lines & Boxen
614 if( !pHeadlineTxtColl || !nLines )
615 pHeadlineTxtColl = pCntntTxtColl;
617 SwTableNode * pTblNd = new SwTableNode( rNdIdx );
618 SwEndNode* pEndNd = new SwEndNode( rNdIdx, *pTblNd );
620 if( !nLines ) // fuer die FOR-Schleife
621 ++nLines;
623 SwNodeIndex aIdx( *pEndNd );
624 SwTxtFmtColl* pTxtColl = pHeadlineTxtColl;
625 for( USHORT nL = 0; nL < nLines; ++nL )
627 for( USHORT nB = 0; nB < nBoxes; ++nB )
629 SwStartNode* pSttNd = new SwStartNode( aIdx, ND_STARTNODE,
630 SwTableBoxStartNode );
631 pSttNd->pStartOfSection = pTblNd;
633 SwTxtNode * pTmpNd = new SwTxtNode( aIdx, pTxtColl );
635 // --> FME 2006-04-13 #i60422# Propagate some more attributes.
636 // Adjustment was done for #109161#
637 const SfxPoolItem* pItem = NULL;
638 if ( NULL != pAttrSet )
640 static const USHORT aPropagateItems[] = {
641 RES_PARATR_ADJUST,
642 RES_CHRATR_FONT, RES_CHRATR_FONTSIZE,
643 RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE,
644 RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE, 0 };
646 const USHORT* pIdx = aPropagateItems;
647 while ( *pIdx != 0 )
649 if ( SFX_ITEM_SET != pTmpNd->GetSwAttrSet().GetItemState( *pIdx ) &&
650 SFX_ITEM_SET == pAttrSet->GetItemState( *pIdx, TRUE, &pItem ) )
651 static_cast<SwCntntNode *>(pTmpNd)->SetAttr(*pItem);
652 ++pIdx;
655 // <--
657 new SwEndNode( aIdx, *pSttNd );
659 if ( nL + 1 >= nRepeat )
660 pTxtColl = pCntntTxtColl;
662 return pTblNd;
666 //---------------- Text -> Tabelle -----------------------
668 const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTblOpts,
669 const SwPaM& rRange, sal_Unicode cCh,
670 sal_Int16 eAdjust,
671 const SwTableAutoFmt* pTAFmt )
673 // pruefe ob in der Selection eine Tabelle liegt
674 const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
676 ULONG nCnt = pStt->nNode.GetIndex();
677 for( ; nCnt <= pEnd->nNode.GetIndex(); ++nCnt )
678 if( !GetNodes()[ nCnt ]->IsTxtNode() )
679 return 0;
682 /* #106283# Save first node in the selection if it is a context node. */
683 SwCntntNode * pSttCntntNd = pStt->nNode.GetNode().GetCntntNode();
685 SwPaM aOriginal( *pStt, *pEnd );
686 pStt = aOriginal.GetMark();
687 pEnd = aOriginal.GetPoint();
689 #ifdef DEL_TABLE_REDLINES
690 lcl_DelRedlines aDelRedl( aOriginal );
691 #endif
693 SwUndoTxtToTbl* pUndo = 0;
694 if( DoesUndo() )
696 StartUndo( UNDO_TEXTTOTABLE, NULL );
697 pUndo = new SwUndoTxtToTbl( aOriginal, rInsTblOpts, cCh,
698 static_cast<USHORT>(eAdjust), pTAFmt );
699 AppendUndo( pUndo );
701 // das Splitten vom TextNode nicht in die Undohistory aufnehmen
702 DoUndo( FALSE );
705 ::PaMCorrAbs( aOriginal, *pEnd );
707 // sorge dafuer, das der Bereich auf Node-Grenzen liegt
708 SwNodeRange aRg( pStt->nNode, pEnd->nNode );
709 if( pStt->nContent.GetIndex() )
710 SplitNode( *pStt, false );
712 BOOL bEndCntnt = 0 != pEnd->nContent.GetIndex();
713 // nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
714 if( bEndCntnt )
716 if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
717 || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
719 SplitNode( *pEnd, false );
720 ((SwNodeIndex&)pEnd->nNode)--;
721 ((SwIndex&)pEnd->nContent).Assign(
722 pEnd->nNode.GetNode().GetCntntNode(), 0 );
723 // ein Node und am Ende ??
724 if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
725 aRg.aStart--;
727 else
728 aRg.aEnd++;
732 if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
734 ASSERT( FALSE, "Kein Bereich" );
735 aRg.aEnd++;
738 // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
739 SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
741 DoUndo( 0 != pUndo );
743 // dann erstelle die Box/Line/Table-Struktur
744 SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
745 SwTableLineFmt* pLineFmt = MakeTableLineFmt();
746 SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
748 // alle Zeilen haben die Fill-Order von links nach rechts !
749 pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
750 // die Tabelle bekommt USHRT_MAX als default SSize
751 pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
752 if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
753 pTableFmt->SetFmtAttr( SwFmtLayoutSplit( FALSE ));
755 /* #106283# If the first node in the selection is a context node and if it
756 has an item FRAMEDIR set (no default) propagate the item to the
757 replacing table. */
758 if (pSttCntntNd)
760 const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
761 const SfxPoolItem *pItem = NULL;
763 if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, TRUE, &pItem )
764 && pItem != NULL)
766 pTableFmt->SetFmtAttr( *pItem );
770 SwTableNode* pTblNd = GetNodes().TextToTable(
771 aRg, cCh, pTableFmt, pLineFmt, pBoxFmt,
772 GetTxtCollFromPool( RES_POOLCOLL_STANDARD ), pUndo );
774 SwTable * pNdTbl = &pTblNd->GetTable();
775 ASSERT( pNdTbl, "kein Tabellen-Node angelegt." )
777 const USHORT nRowsToRepeat =
778 tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
779 rInsTblOpts.mnRowsToRepeat :
781 pNdTbl->SetRowsToRepeat( nRowsToRepeat );
783 BOOL bUseBoxFmt = FALSE;
784 if( !pBoxFmt->GetDepends() )
786 // die Formate an den Boxen haben schon die richtige Size, es darf
787 // also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
788 bUseBoxFmt = TRUE;
789 pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
790 delete pBoxFmt;
791 eAdjust = text::HoriOrientation::NONE;
794 //Orientation am Fmt der Table setzen
795 pTableFmt->SetFmtAttr( SwFmtHoriOrient( 0, eAdjust ) );
796 pTableFmt->Add( pNdTbl ); // das Frame-Format setzen
798 if( pTAFmt || ( rInsTblOpts.mnInsMode & tabopts::DEFAULT_BORDER) )
800 BYTE nBoxArrLen = pTAFmt ? 16 : 4;
801 SvPtrarr aBoxFmtArr( nBoxArrLen, 0 );
803 for( BYTE i = 0; i < nBoxArrLen; ++i )
804 aBoxFmtArr.Insert( (void*)0, i );
807 // --> OD 2008-02-25 #refactorlists#
808 // SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
809 SfxItemSet aCharSet( GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
810 // <--
811 SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
813 SwTableBoxFmt *pBoxF = 0;
814 SwTableLines& rLines = pNdTbl->GetTabLines();
815 USHORT nRows = rLines.Count();
816 for( USHORT n = 0; n < nRows; ++n )
818 SwTableBoxes& rBoxes = rLines[ n ]->GetTabBoxes();
819 USHORT nCols = rBoxes.Count();
820 for( USHORT i = 0; i < nCols; ++i )
822 SwTableBox* pBox = rBoxes[ i ];
823 BOOL bChgSz = FALSE;
825 if( pTAFmt )
827 BYTE nId = static_cast<BYTE>(!n ? 0 : (( n+1 == nRows )
828 ? 12 : (4 * (1 + ((n-1) & 1 )))));
829 nId = nId + static_cast<BYTE>(!i ? 0 :
830 ( i+1 == nCols ? 3 : (1 + ((i-1) & 1))));
831 if( bUseBoxFmt )
832 ::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId, pTAFmt );
833 else
835 bChgSz = 0 == aBoxFmtArr[ nId ];
836 pBoxF = ::lcl_CreateAFmtBoxFmt( *this, aBoxFmtArr,
837 *pTAFmt, USHRT_MAX, nId );
840 // ggfs. noch die Absatz/ZeichenAttribute setzen
841 if( pTAFmt->IsFont() || pTAFmt->IsJustify() )
843 aCharSet.ClearItem();
844 pTAFmt->UpdateToSet( nId, aCharSet,
845 SwTableAutoFmt::UPDATE_CHAR, 0 );
846 if( aCharSet.Count() )
848 ULONG nSttNd = pBox->GetSttIdx()+1;
849 ULONG nEndNd = pBox->GetSttNd()->EndOfSectionIndex();
850 for( ; nSttNd < nEndNd; ++nSttNd )
852 SwCntntNode* pNd = GetNodes()[ nSttNd ]->GetCntntNode();
853 if( pNd )
855 if( pHistory )
857 SwRegHistory aReg( pNd, *pNd, pHistory );
858 pNd->SetAttr( aCharSet );
860 else
861 pNd->SetAttr( aCharSet );
867 else
869 BYTE nId = (i < nCols - 1 ? 0 : 1) + (n ? 2 : 0 );
870 if( bUseBoxFmt )
871 ::lcl_SetDfltBoxAttr( *pBox, aBoxFmtArr, nId );
872 else
874 bChgSz = 0 == aBoxFmtArr[ nId ];
875 pBoxF = ::lcl_CreateDfltBoxFmt( *this, aBoxFmtArr,
876 USHRT_MAX, nId );
880 if( !bUseBoxFmt )
882 if( bChgSz )
883 pBoxF->SetFmtAttr( pBox->GetFrmFmt()->GetFrmSize() );
884 pBox->ChgFrmFmt( pBoxF );
889 if( bUseBoxFmt )
891 for( BYTE i = 0; i < nBoxArrLen; ++i )
893 SvPtrarr* pArr = (SvPtrarr*)aBoxFmtArr[ i ];
894 delete pArr;
899 // JP 03.04.97: Inhalt der Boxen auf Zahlen abpruefen
900 if( IsInsTblFormatNum() )
902 for( USHORT nBoxes = pNdTbl->GetTabSortBoxes().Count(); nBoxes; )
903 ChkBoxNumFmt( *pNdTbl->GetTabSortBoxes()[ --nBoxes ], FALSE );
906 ULONG nIdx = pTblNd->GetIndex();
907 aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
910 SwPaM& rTmp = (SwPaM&)rRange; // Point immer an den Anfang
911 rTmp.DeleteMark();
912 rTmp.GetPoint()->nNode = *pTblNd;
913 SwCntntNode* pCNd = GetNodes().GoNext( &rTmp.GetPoint()->nNode );
914 rTmp.GetPoint()->nContent.Assign( pCNd, 0 );
917 if( pUndo )
918 EndUndo( UNDO_TEXTTOTABLE, NULL );
920 SetModified();
921 SetFieldsDirty(true, NULL, 0);
922 return pNdTbl;
925 SwTableNode* SwNodes::TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
926 SwTableFmt* pTblFmt,
927 SwTableLineFmt* pLineFmt,
928 SwTableBoxFmt* pBoxFmt,
929 SwTxtFmtColl* pTxtColl,
930 SwUndoTxtToTbl* pUndo )
932 if( rRange.aStart >= rRange.aEnd )
933 return 0;
935 SwTableNode * pTblNd = new SwTableNode( rRange.aStart );
936 new SwEndNode( rRange.aEnd, *pTblNd );
938 SwDoc* pDoc = GetDoc();
939 SvUShorts aPosArr( 0, 16 );
940 SwTable * pTable = &pTblNd->GetTable();
941 SwTableLine* pLine;
942 SwTableBox* pBox;
943 USHORT nBoxes, nLines, nMaxBoxes = 0;
945 SwNodeIndex aSttIdx( *pTblNd, 1 );
946 SwNodeIndex aEndIdx( rRange.aEnd, -1 );
947 for( nLines = 0, nBoxes = 0;
948 aSttIdx.GetIndex() < aEndIdx.GetIndex();
949 aSttIdx += 2, nLines++, nBoxes = 0 )
951 SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
952 ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
954 if( !nLines && 0x0b == cCh )
956 cCh = 0x09;
958 // JP 28.10.96: vom 1. Node die Positionen des Trenners besorgen,
959 // damit die Boxen entsprechend eingestellt werden
960 SwTxtFrmInfo aFInfo( (SwTxtFrm*)pTxtNd->GetFrm() );
961 if( aFInfo.IsOneLine() ) // nur dann sinnvoll!
963 const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
964 for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
966 if( *pTxt == cCh )
968 aPosArr.Insert( static_cast<USHORT>(
969 aFInfo.GetCharPos( nChPos+1, FALSE )),
970 aPosArr.Count() );
974 aPosArr.Insert( /*aFInfo.GetFrm()->Frm().Left() +*/
975 static_cast<USHORT>(aFInfo.GetFrm()->IsVertical() ?
976 aFInfo.GetFrm()->Prt().Bottom() :
977 aFInfo.GetFrm()->Prt().Right()),
978 aPosArr.Count() );
982 // die alten Frames loeschen, es werden neue erzeugt
983 pTxtNd->DelFrms();
985 // PageBreaks/PageDesc/ColBreak rausschmeissen.
986 const SfxItemSet* pSet = pTxtNd->GetpSwAttrSet();
987 if( pSet )
989 // das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
990 // erfolgen, denn sonst stehen sie falsch in der History !!!
991 // SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
992 const SfxPoolItem* pItem;
993 if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, FALSE, &pItem ) )
995 if( !nLines )
996 pTblFmt->SetFmtAttr( *pItem );
997 pTxtNd->ResetAttr( RES_BREAK );
998 pSet = pTxtNd->GetpSwAttrSet();
1001 if( pSet && SFX_ITEM_SET == pSet->GetItemState(
1002 RES_PAGEDESC, FALSE, &pItem ) &&
1003 ((SwFmtPageDesc*)pItem)->GetPageDesc() )
1005 if( !nLines )
1006 pTblFmt->SetFmtAttr( *pItem );
1007 pTxtNd->ResetAttr( RES_PAGEDESC );
1011 // setze den bei allen TextNode in der Tabelle den TableNode
1012 // als StartNode
1013 pTxtNd->pStartOfSection = pTblNd;
1015 pLine = new SwTableLine( pLineFmt, 1, 0 );
1016 pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
1018 SwStartNode* pSttNd;
1019 SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
1021 SvULongs aBkmkArr( 15, 15 );
1022 _SaveCntntIdx( pDoc, aSttIdx.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
1024 const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
1026 if( T2T_PARA != cCh )
1027 for( xub_StrLen nChPos = 0; *pTxt; ++nChPos, ++pTxt )
1028 if( *pTxt == cCh )
1030 aCntPos.nContent = nChPos;
1031 SwCntntNode* pNewNd = pTxtNd->SplitCntntNode( aCntPos );
1033 if( aBkmkArr.Count() )
1034 _RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
1035 nChPos + 1 );
1037 // Trennzeichen loeschen und SuchString korrigieren
1038 pTxtNd->EraseText( aCntPos.nContent, 1 );
1039 pTxt = pTxtNd->GetTxt().GetBuffer();
1040 nChPos = 0;
1041 --nChPos, --pTxt; // for the ++ in the for loop !!!
1043 // setze bei allen TextNodes in der Tabelle den TableNode
1044 // als StartNode
1045 const SwNodeIndex aTmpIdx( aCntPos.nNode, -1 );
1046 pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
1047 SwTableBoxStartNode );
1048 new SwEndNode( aCntPos.nNode, *pSttNd );
1049 pNewNd->pStartOfSection = pSttNd;
1051 // Section der Box zuweisen
1052 pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
1053 pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
1056 // und jetzt den letzten Teil-String
1057 if( aBkmkArr.Count() )
1058 _RestoreCntntIdx( aBkmkArr, *pTxtNd, pTxtNd->GetTxt().Len(),
1059 pTxtNd->GetTxt().Len()+1 );
1061 pSttNd = new SwStartNode( aCntPos.nNode, ND_STARTNODE, SwTableBoxStartNode );
1062 const SwNodeIndex aTmpIdx( aCntPos.nNode, 1 );
1063 new SwEndNode( aTmpIdx, *pSttNd );
1064 pTxtNd->pStartOfSection = pSttNd;
1066 pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
1067 pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
1068 if( nMaxBoxes < nBoxes )
1069 nMaxBoxes = nBoxes;
1072 // die Tabelle ausgleichen, leere Sections einfuegen
1073 USHORT n;
1075 for( n = 0; n < pTable->GetTabLines().Count(); ++n )
1077 SwTableLine* pCurrLine = pTable->GetTabLines()[ n ];
1078 if( nMaxBoxes != ( nBoxes = pCurrLine->GetTabBoxes().Count() ))
1080 InsBoxen( pTblNd, pCurrLine, pBoxFmt, pTxtColl, 0,
1081 nBoxes, nMaxBoxes - nBoxes );
1083 if( pUndo )
1084 for( USHORT i = nBoxes; i < nMaxBoxes; ++i )
1085 pUndo->AddFillBox( *pCurrLine->GetTabBoxes()[ i ] );
1087 // fehlen der 1. Line Boxen, dann kann man das Breiten Array
1088 // vergessen!
1089 if( !n )
1090 aPosArr.Remove( 0, aPosArr.Count() );
1094 if( aPosArr.Count() )
1096 SwTableLines& rLns = pTable->GetTabLines();
1097 USHORT nLastPos = 0;
1098 for( n = 0; n < aPosArr.Count(); ++n )
1100 SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
1101 pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1102 aPosArr[ n ] - nLastPos ));
1103 for( USHORT nTmpLine = 0; nTmpLine < rLns.Count(); ++nTmpLine )
1104 //JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
1105 // von der rufenden Methode noch gebraucht wird!
1106 pNewFmt->Add( rLns[ nTmpLine ]->GetTabBoxes()[ n ] );
1108 nLastPos = aPosArr[ n ];
1111 // damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
1112 // Groesse nach "oben" transportieren.
1113 ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
1114 pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
1116 else
1117 pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
1119 // das wars doch wohl ??
1120 return pTblNd;
1122 /*-- 18.05.2006 10:30:29---------------------------------------------------
1124 -----------------------------------------------------------------------*/
1125 const SwTable* SwDoc::TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes )
1127 /* #106283# Save first node in the selection if it is a content node. */
1128 SwCntntNode * pSttCntntNd = rTableNodes.begin()->begin()->aStart.GetNode().GetCntntNode();
1130 /**debug**/
1131 #if OSL_DEBUG_LEVEL > 1
1132 const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
1133 const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
1134 (void) rStartRange;
1135 (void) rEndRange;
1136 #endif
1137 /**debug**/
1139 //!!! not necessarily TextNodes !!!
1140 SwPaM aOriginal( rTableNodes.begin()->begin()->aStart, rTableNodes.rbegin()->rbegin()->aEnd );
1141 const SwPosition *pStt = aOriginal.GetMark();
1142 const SwPosition *pEnd = aOriginal.GetPoint();
1144 #ifdef DEL_TABLE_REDLINES
1145 lcl_DelRedlines aDelRedl( aOriginal );
1146 #endif
1148 SwUndoTxtToTbl* pUndo = 0;
1149 if( DoesUndo() )
1151 // StartUndo( UNDO_TEXTTOTABLE );
1152 // pUndo = new SwUndoTxtToTbl( aOriginal, rInsTblOpts, cCh, eAdjust, pTAFmt );
1153 // AppendUndo( pUndo );
1155 // das Splitten vom TextNode nicht in die Undohistory aufnehmen
1156 DoUndo( FALSE );
1159 ::PaMCorrAbs( aOriginal, *pEnd );
1161 // sorge dafuer, das der Bereich auf Node-Grenzen liegt
1162 SwNodeRange aRg( pStt->nNode, pEnd->nNode );
1163 if( pStt->nContent.GetIndex() )
1164 SplitNode( *pStt, false );
1166 BOOL bEndCntnt = 0 != pEnd->nContent.GetIndex();
1167 // nicht splitten am Ende der Zeile (aber am Ende vom Doc!!)
1168 if( bEndCntnt )
1170 if( pEnd->nNode.GetNode().GetCntntNode()->Len() != pEnd->nContent.GetIndex()
1171 || pEnd->nNode.GetIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
1173 SplitNode( *pEnd, false );
1174 ((SwNodeIndex&)pEnd->nNode)--;
1175 ((SwIndex&)pEnd->nContent).Assign(
1176 pEnd->nNode.GetNode().GetCntntNode(), 0 );
1177 // ein Node und am Ende ??
1178 if( pStt->nNode.GetIndex() >= pEnd->nNode.GetIndex() )
1179 aRg.aStart--;
1181 else
1182 aRg.aEnd++;
1186 if( aRg.aEnd.GetIndex() == aRg.aStart.GetIndex() )
1188 ASSERT( FALSE, "Kein Bereich" );
1189 aRg.aEnd++;
1192 // Wir gehen jetzt immer ueber die Upper, um die Tabelle einzufuegen:
1193 SwNode2Layout aNode2Layout( aRg.aStart.GetNode() );
1195 DoUndo( 0 != pUndo );
1197 // dann erstelle die Box/Line/Table-Struktur
1198 SwTableBoxFmt* pBoxFmt = MakeTableBoxFmt();
1199 SwTableLineFmt* pLineFmt = MakeTableLineFmt();
1200 SwTableFmt* pTableFmt = MakeTblFrmFmt( GetUniqueTblName(), GetDfltFrmFmt() );
1202 // alle Zeilen haben die Fill-Order von links nach rechts !
1203 pLineFmt->SetFmtAttr( SwFmtFillOrder( ATT_LEFT_TO_RIGHT ));
1204 // die Tabelle bekommt USHRT_MAX als default SSize
1205 pTableFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX ));
1206 // if( !(rInsTblOpts.mnInsMode & tabopts::SPLIT_LAYOUT) )
1207 // pTableFmt->SetAttr( SwFmtLayoutSplit( FALSE ));
1209 /* #106283# If the first node in the selection is a context node and if it
1210 has an item FRAMEDIR set (no default) propagate the item to the
1211 replacing table. */
1212 if (pSttCntntNd)
1214 const SwAttrSet & aNdSet = pSttCntntNd->GetSwAttrSet();
1215 const SfxPoolItem *pItem = NULL;
1217 if (SFX_ITEM_SET == aNdSet.GetItemState( RES_FRAMEDIR, TRUE, &pItem )
1218 && pItem != NULL)
1220 pTableFmt->SetFmtAttr( *pItem );
1224 SwTableNode* pTblNd = GetNodes().TextToTable(
1225 rTableNodes, pTableFmt, pLineFmt, pBoxFmt,
1226 GetTxtCollFromPool( RES_POOLCOLL_STANDARD )/*, pUndo*/ );
1228 SwTable * pNdTbl = &pTblNd->GetTable();
1229 ASSERT( pNdTbl, "kein Tabellen-Node angelegt." )
1230 pTableFmt->Add( pNdTbl ); // das Frame-Format setzen
1232 // const USHORT nRowsToRepeat =
1233 // tabopts::HEADLINE == (rInsTblOpts.mnInsMode & tabopts::HEADLINE) ?
1234 // rInsTblOpts.mnRowsToRepeat :
1235 // 0;
1236 // pNdTbl->SetRowsToRepeat( nRowsToRepeat );
1238 BOOL bUseBoxFmt = FALSE;
1239 if( !pBoxFmt->GetDepends() )
1241 // die Formate an den Boxen haben schon die richtige Size, es darf
1242 // also nur noch die richtige Umrandung/AutoFmt gesetzt werden.
1243 bUseBoxFmt = TRUE;
1244 pTableFmt->SetFmtAttr( pBoxFmt->GetFrmSize() );
1245 delete pBoxFmt;
1246 // eAdjust = HORI_NONE;
1249 //Orientation am Fmt der Table setzen
1250 // pTableFmt->SetAttr( SwFmtHoriOrient( 0, eAdjust ) );
1251 // pTableFmt->Add( pNdTbl ); // das Frame-Format setzen
1254 ULONG nIdx = pTblNd->GetIndex();
1255 aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
1258 // SwPaM& rTmp = (SwPaM&)rRange; // Point immer an den Anfang
1259 // rTmp.DeleteMark();
1260 // rTmp.GetPoint()->nNode = *pTblNd;
1261 // SwCntntNode* pCNd = GetNodes().GoNext( &rTmp.GetPoint()->nNode );
1262 // rTmp.GetPoint()->nContent.Assign( pCNd, 0 );
1265 // if( pUndo )
1266 // EndUndo( UNDO_TEXTTOTABLE );
1268 SetModified();
1269 SetFieldsDirty( true, NULL, 0 );
1270 return pNdTbl;
1273 /*-- 18.05.2006 08:23:28---------------------------------------------------
1275 -----------------------------------------------------------------------*/
1276 SwTableNode* SwNodes::TextToTable( const std::vector< std::vector<SwNodeRange> >& rTableNodes,
1277 SwTableFmt* pTblFmt,
1278 SwTableLineFmt* pLineFmt,
1279 SwTableBoxFmt* pBoxFmt,
1280 SwTxtFmtColl* /*pTxtColl*/ /*, SwUndo... pUndo*/ )
1282 if( !rTableNodes.size() )
1283 return 0;
1285 SwTableNode * pTblNd = new SwTableNode( rTableNodes.begin()->begin()->aStart );
1286 //insert the end node after the last text node
1287 SwNodeIndex aInsertIndex( rTableNodes.rbegin()->rbegin()->aEnd );
1288 ++aInsertIndex;
1290 //!! owner ship will be transferred in c-tor to SwNodes array.
1291 //!! Thus no real problem here...
1292 new SwEndNode( aInsertIndex, *pTblNd );
1294 #if OSL_DEBUG_LEVEL > 1
1295 /**debug**/
1296 const SwNodeRange& rStartRange = *rTableNodes.begin()->begin();
1297 const SwNodeRange& rEndRange = *rTableNodes.rbegin()->rbegin();
1298 (void) rStartRange;
1299 (void) rEndRange;
1300 /**debug**/
1301 #endif
1303 SwDoc* pDoc = GetDoc();
1304 SvUShorts aPosArr( 0, 16 );
1305 SwTable * pTable = &pTblNd->GetTable();
1306 SwTableLine* pLine;
1307 SwTableBox* pBox;
1308 USHORT nBoxes, nLines, nMaxBoxes = 0;
1310 // SwHistory* pHistory = pUndo ? &pUndo->GetHistory() : 0;
1313 SwNodeIndex aNodeIndex = rTableNodes.begin()->begin()->aStart;
1314 // delete frames of all contained content nodes
1315 for( nLines = 0; aNodeIndex <= rTableNodes.rbegin()->rbegin()->aEnd; ++aNodeIndex,++nLines )
1317 SwNode& rNode = aNodeIndex.GetNode();
1318 if( rNode.IsCntntNode() )
1320 static_cast<SwCntntNode&>(rNode).DelFrms();
1321 if(rNode.IsTxtNode())
1323 SwTxtNode& rTxtNode = static_cast<SwTxtNode&>(rNode);
1324 // setze den bei allen TextNode in der Tabelle den TableNode
1325 // als StartNode
1326 // FIXME: this is setting wrong node StartOfSections in nested tables.
1327 // rTxtNode.pStartOfSection = pTblNd;
1328 // remove PageBreaks/PageDesc/ColBreak
1329 const SwAttrSet* pSet = rTxtNode.GetpSwAttrSet();
1330 if( pSet )
1332 // das entfernen der PageBreaks erst nach dem erzeugen der Tabelle
1333 // erfolgen, denn sonst stehen sie falsch in der History !!!
1334 // SwRegHistory aRegH( pTxtNd, *pTxtNd, pHistory );
1335 const SfxPoolItem* pItem;
1336 if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, FALSE, &pItem ) )
1338 if( !nLines )
1339 pTblFmt->SetFmtAttr( *pItem );
1340 rTxtNode.ResetAttr( RES_BREAK );
1341 pSet = rTxtNode.GetpSwAttrSet();
1344 if( pSet && SFX_ITEM_SET == pSet->GetItemState(
1345 RES_PAGEDESC, FALSE, &pItem ) &&
1346 ((SwFmtPageDesc*)pItem)->GetPageDesc() )
1348 if( !nLines )
1349 pTblFmt->SetFmtAttr( *pItem );
1350 rTxtNode.ResetAttr( RES_PAGEDESC );
1357 // SwNodeIndex aSttIdx( *pTblNd, 1 );
1358 // SwNodeIndex aEndIdx( rlNodes.rbegin()->aEnd, -1 );
1359 std::vector<std::vector < SwNodeRange > >::const_iterator aRowIter = rTableNodes.begin();
1360 for( nLines = 0, nBoxes = 0;
1361 aRowIter != rTableNodes.end();
1362 ++aRowIter, /*aSttIdx += 2, */nLines++, nBoxes = 0 )
1364 // SwTxtNode* pTxtNd = aSttIdx.GetNode().GetTxtNode();
1365 // ASSERT( pTxtNd, "nur TextNodes in der Tabelle aufnehmen" );
1367 pLine = new SwTableLine( pLineFmt, 1, 0 );
1368 pTable->GetTabLines().C40_INSERT( SwTableLine, pLine, nLines );
1370 // SwStartNode* pSttNd;
1371 // SwPosition aCntPos( aSttIdx, SwIndex( pTxtNd ));
1373 std::vector< SwNodeRange >::const_iterator aCellIter = aRowIter->begin();
1374 // SvULongs aBkmkArr( 15, 15 );
1375 // _SaveCntntIdx( pDoc, aCellIter->aStart.GetIndex(), pTxtNd->GetTxt().Len(), aBkmkArr );
1376 // const sal_Unicode* pTxt = pTxtNd->GetTxt().GetBuffer();
1378 for( ; aCellIter != aRowIter->end(); ++aCellIter )
1380 // aCellIter->aStart aCellIter->aEnd
1381 // aCntPos.nContent = nChPos;
1382 // SwCntntNode* pNewNd = pTxtNd->SplitNode( aCntPos );
1384 // auch f?rs undo?
1385 // if( aBkmkArr.Count() )
1386 // _RestoreCntntIdx( aBkmkArr, *pNewNd, nChPos,
1387 // nChPos + 1 );
1389 const SwNodeIndex aTmpIdx( aCellIter->aStart, 0 );
1391 SwNodeIndex aCellEndIdx(aCellIter->aEnd);
1392 ++aCellEndIdx;
1393 SwStartNode* pSttNd = new SwStartNode( aTmpIdx, ND_STARTNODE,
1394 SwTableBoxStartNode );
1395 new SwEndNode( aCellEndIdx, *pSttNd );
1396 //set the start node on all node of the current cell
1397 SwNodeIndex aCellNodeIdx = aCellIter->aStart;
1398 for(;aCellNodeIdx <= aCellIter->aEnd; ++aCellNodeIdx )
1400 aCellNodeIdx.GetNode().pStartOfSection = pSttNd;
1401 //skip start/end node pairs
1402 if( aCellNodeIdx.GetNode().IsStartNode() )
1403 aCellNodeIdx = SwNodeIndex( *aCellNodeIdx.GetNode().EndOfSectionNode() );
1406 // Section der Box zuweisen
1407 pBox = new SwTableBox( pBoxFmt, *pSttNd, pLine );
1408 pLine->GetTabBoxes().C40_INSERT( SwTableBox, pBox, nBoxes++ );
1410 if( nMaxBoxes < nBoxes )
1411 nMaxBoxes = nBoxes;
1414 // die Tabelle ausgleichen, leere Sections einfuegen
1415 USHORT n;
1417 if( aPosArr.Count() )
1419 SwTableLines& rLns = pTable->GetTabLines();
1420 USHORT nLastPos = 0;
1421 for( n = 0; n < aPosArr.Count(); ++n )
1423 SwTableBoxFmt *pNewFmt = pDoc->MakeTableBoxFmt();
1424 pNewFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE,
1425 aPosArr[ n ] - nLastPos ));
1426 for( USHORT nLines2 = 0; nLines2 < rLns.Count(); ++nLines2 )
1427 //JP 24.06.98: hier muss ein Add erfolgen, da das BoxFormat
1428 // von der rufenden Methode noch gebraucht wird!
1429 pNewFmt->Add( rLns[ nLines2 ]->GetTabBoxes()[ n ] );
1431 nLastPos = aPosArr[ n ];
1434 // damit die Tabelle die richtige Groesse bekommt, im BoxFormat die
1435 // Groesse nach "oben" transportieren.
1436 ASSERT( !pBoxFmt->GetDepends(), "wer ist in dem Format noch angemeldet" );
1437 pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nLastPos ));
1439 else
1440 pBoxFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, USHRT_MAX / nMaxBoxes ));
1442 // das wars doch wohl ??
1443 return pTblNd;
1447 //---------------- Tabelle -> Text -----------------------
1450 BOOL SwDoc::TableToText( const SwTableNode* pTblNd, sal_Unicode cCh )
1452 if( !pTblNd )
1453 return FALSE;
1455 // --> FME 2004-09-28 #i34471#
1456 // If this is trigged by SwUndoTblToTxt::Repeat() nobody ever deleted
1457 // the table cursor.
1458 SwEditShell* pESh = GetEditShell();
1459 if( pESh && pESh->IsTableMode() )
1460 pESh->ClearMark();
1461 // <--
1463 #ifdef DEL_TABLE_REDLINES
1464 lcl_DelRedlines aDelRedl( *pTblNd, FALSE );
1465 #endif
1467 SwNodeRange aRg( *pTblNd, 0, *pTblNd->EndOfSectionNode() );
1468 SwUndoTblToTxt* pUndo = 0;
1469 SwNodeRange* pUndoRg = 0;
1470 if( DoesUndo() )
1472 ClearRedo();
1473 pUndoRg = new SwNodeRange( aRg.aStart, -1, aRg.aEnd, +1 );
1474 pUndo = new SwUndoTblToTxt( pTblNd->GetTable(), cCh );
1477 SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
1478 aMsgHnt.eFlags = TBL_BOXNAME;
1479 UpdateTblFlds( &aMsgHnt );
1481 BOOL bRet = GetNodes().TableToText( aRg, cCh, pUndo );
1482 if( pUndoRg )
1484 pUndoRg->aStart++;
1485 pUndoRg->aEnd--;
1486 pUndo->SetRange( *pUndoRg );
1487 AppendUndo( pUndo );
1488 delete pUndoRg;
1491 if( bRet )
1492 SetModified();
1494 return bRet;
1497 // -- benutze die ForEach Methode vom PtrArray um aus einer Tabelle wieder
1498 // Text zuerzeugen. (Die Boxen koennen auch noch Lines enthalten !!)
1499 struct _DelTabPara
1501 SwTxtNode* pLastNd;
1502 SwNodes& rNds;
1503 SwUndoTblToTxt* pUndo;
1504 sal_Unicode cCh;
1506 _DelTabPara( SwNodes& rNodes, sal_Unicode cChar, SwUndoTblToTxt* pU ) :
1507 pLastNd(0), rNds( rNodes ), pUndo( pU ), cCh( cChar ) {}
1508 _DelTabPara( const _DelTabPara& rPara ) :
1509 pLastNd(rPara.pLastNd), rNds( rPara.rNds ),
1510 pUndo( rPara.pUndo ), cCh( rPara.cCh ) {}
1513 // forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
1514 // koennen.
1515 BOOL lcl_DelBox( const SwTableBox*&, void *pPara );
1517 BOOL lcl_DelLine( const SwTableLine*& rpLine, void* pPara )
1519 ASSERT( pPara, "die Parameter fehlen" );
1520 _DelTabPara aPara( *(_DelTabPara*)pPara );
1521 ((SwTableLine*&)rpLine)->GetTabBoxes().ForEach( &lcl_DelBox, &aPara );
1522 if( rpLine->GetUpper() ) // gibt es noch eine uebergeordnete Box ??
1523 // dann gebe den letzten TextNode zurueck
1524 ((_DelTabPara*)pPara)->pLastNd = aPara.pLastNd;
1525 return TRUE;
1529 BOOL lcl_DelBox( const SwTableBox*& rpBox, void* pPara )
1531 ASSERT( pPara, "die Parameter fehlen" );
1533 // loesche erstmal die Lines der Box
1534 _DelTabPara* pDelPara = (_DelTabPara*)pPara;
1535 if( rpBox->GetTabLines().Count() )
1536 ((SwTableBox*&)rpBox)->GetTabLines().ForEach( &lcl_DelLine, pDelPara );
1537 else
1539 SwDoc* pDoc = pDelPara->rNds.GetDoc();
1540 SwNodeRange aDelRg( *rpBox->GetSttNd(), 0,
1541 *rpBox->GetSttNd()->EndOfSectionNode() );
1542 // loesche die Section
1543 pDelPara->rNds.SectionUp( &aDelRg );
1544 const SwTxtNode* pCurTxtNd;
1545 if( T2T_PARA != pDelPara->cCh && pDelPara->pLastNd &&
1546 0 != ( pCurTxtNd = aDelRg.aStart.GetNode().GetTxtNode() ))
1548 // Join the current text node with the last from the previous box if possible
1549 ULONG nNdIdx = aDelRg.aStart.GetIndex();
1550 aDelRg.aStart--;
1551 if( pDelPara->pLastNd == &aDelRg.aStart.GetNode() )
1553 // Inserting the seperator
1554 SwIndex aCntIdx( pDelPara->pLastNd, pDelPara->pLastNd->GetTxt().Len());
1555 pDelPara->pLastNd->InsertText( pDelPara->cCh, aCntIdx,
1556 IDocumentContentOperations::INS_EMPTYEXPAND );
1557 if( pDelPara->pUndo )
1558 pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex(),
1559 aCntIdx.GetIndex() );
1561 SvULongs aBkmkArr( 4, 4 );
1562 xub_StrLen nOldTxtLen = aCntIdx.GetIndex();
1563 _SaveCntntIdx( pDoc, nNdIdx, pCurTxtNd->GetTxt().Len(),
1564 aBkmkArr );
1566 pDelPara->pLastNd->JoinNext();
1568 if( aBkmkArr.Count() )
1569 _RestoreCntntIdx( pDoc, aBkmkArr,
1570 pDelPara->pLastNd->GetIndex(),
1571 nOldTxtLen );
1573 else if( pDelPara->pUndo )
1575 aDelRg.aStart++;
1576 pDelPara->pUndo->AddBoxPos( *pDoc, nNdIdx, aDelRg.aEnd.GetIndex() );
1579 else if( pDelPara->pUndo )
1580 pDelPara->pUndo->AddBoxPos( *pDoc, aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
1581 aDelRg.aEnd--;
1582 pDelPara->pLastNd = aDelRg.aEnd.GetNode().GetTxtNode();
1584 //JP 03.04.97: die Ausrichtung der ZahlenFormatierung auf
1585 // keinen Fall uebernehmen
1586 if( pDelPara->pLastNd && pDelPara->pLastNd->HasSwAttrSet() )
1587 pDelPara->pLastNd->ResetAttr( RES_PARATR_ADJUST );
1589 return TRUE;
1593 BOOL SwNodes::TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
1594 SwUndoTblToTxt* pUndo )
1596 // ist eine Tabelle selektiert ?
1597 SwTableNode* pTblNd;
1598 if( rRange.aStart.GetIndex() >= rRange.aEnd.GetIndex() ||
1599 0 == ( pTblNd = (*this)[ rRange.aStart ]->GetTableNode()) ||
1600 &rRange.aEnd.GetNode() != pTblNd->EndOfSectionNode() )
1601 return FALSE;
1603 // stand die Tabelle ganz alleine in einer Section ?
1604 // dann ueber den Upper der Tabelle die Frames anlegen
1605 SwNode2Layout* pNode2Layout = 0;
1606 SwNodeIndex aFrmIdx( rRange.aStart );
1607 SwNode* pFrmNd = FindPrvNxtFrmNode( aFrmIdx, &rRange.aEnd.GetNode() );
1608 if( !pFrmNd )
1609 // dann sammel mal alle Uppers ein
1610 pNode2Layout = new SwNode2Layout( *pTblNd );
1612 // loesche schon mal die Frames
1613 pTblNd->DelFrms();
1615 // dann "loeschen" die Tabellen und fasse alle Lines/Boxen zusammen
1616 _DelTabPara aDelPara( *this, cCh, pUndo );
1617 pTblNd->pTable->GetTabLines().ForEach( &lcl_DelLine, &aDelPara );
1619 // jetzt ist aus jeder TableLine ein TextNode mit dem entsprechenden
1620 // Trenner erzeugt worden. Es braucht nur noch die Table-Section
1621 // geloescht und fuer die neuen TextNode die Frames erzeugt werden.
1622 SwNodeRange aDelRg( rRange.aStart, rRange.aEnd );
1624 // JP 14.01.97: hat die Tabelle PageDesc-/Break-Attribute? Dann in den
1625 // ersten TextNode uebernehmen
1627 // was ist mit UNDO???
1628 const SfxItemSet& rTblSet = pTblNd->pTable->GetFrmFmt()->GetAttrSet();
1629 const SfxPoolItem *pBreak, *pDesc;
1630 if( SFX_ITEM_SET != rTblSet.GetItemState( RES_PAGEDESC, FALSE, &pDesc ))
1631 pDesc = 0;
1632 if( SFX_ITEM_SET != rTblSet.GetItemState( RES_BREAK, FALSE, &pBreak ))
1633 pBreak = 0;
1635 if( pBreak || pDesc )
1637 SwNodeIndex aIdx( *pTblNd );
1638 SwCntntNode* pCNd = GoNext( &aIdx );
1639 if( pBreak )
1640 pCNd->SetAttr( *pBreak );
1641 if( pDesc )
1642 pCNd->SetAttr( *pDesc );
1646 SectionUp( &aDelRg ); // loesche die Section und damit die Tabelle
1647 // #i28006#
1648 ULONG nStt = aDelRg.aStart.GetIndex(), nEnd = aDelRg.aEnd.GetIndex();
1649 if( !pFrmNd )
1651 pNode2Layout->RestoreUpperFrms( *this,
1652 aDelRg.aStart.GetIndex(), aDelRg.aEnd.GetIndex() );
1653 delete pNode2Layout;
1655 else
1657 SwCntntNode *pCNd;
1658 SwSectionNode *pSNd;
1659 while( aDelRg.aStart.GetIndex() < nEnd )
1661 if( 0 != ( pCNd = aDelRg.aStart.GetNode().GetCntntNode()))
1663 if( pFrmNd->IsCntntNode() )
1664 ((SwCntntNode*)pFrmNd)->MakeFrms( *pCNd );
1665 else if( pFrmNd->IsTableNode() )
1666 ((SwTableNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
1667 else if( pFrmNd->IsSectionNode() )
1668 ((SwSectionNode*)pFrmNd)->MakeFrms( aDelRg.aStart );
1669 pFrmNd = pCNd;
1671 else if( 0 != ( pSNd = aDelRg.aStart.GetNode().GetSectionNode()))
1673 if( !pSNd->GetSection().IsHidden() && !pSNd->IsCntntHidden() )
1675 pSNd->MakeFrms( &aFrmIdx, &aDelRg.aEnd );
1676 pFrmNd = pSNd;
1677 break;
1679 aDelRg.aStart = *pSNd->EndOfSectionNode();
1681 aDelRg.aStart++;
1685 // #i28006# Fly frames have to be restored even if the table was
1686 // #alone in the section
1687 const SwSpzFrmFmts& rFlyArr = *GetDoc()->GetSpzFrmFmts();
1688 const SwPosition* pAPos;
1689 for( USHORT n = 0; n < rFlyArr.Count(); ++n )
1691 SwFrmFmt* pFmt = (SwFrmFmt*)rFlyArr[n];
1692 const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
1693 if( ( FLY_AT_CNTNT == rAnchor.GetAnchorId() ||
1694 FLY_AUTO_CNTNT == rAnchor.GetAnchorId() ) &&
1695 0 != ( pAPos = rAnchor.GetCntntAnchor() ) &&
1696 nStt <= pAPos->nNode.GetIndex() &&
1697 pAPos->nNode.GetIndex() < nEnd )
1698 pFmt->MakeFrms();
1701 return TRUE;
1705 // ----- einfuegen von Spalten/Zeilen ------------------------
1707 BOOL SwDoc::InsertCol( const SwCursor& rCursor, USHORT nCnt, BOOL bBehind )
1709 if( !::CheckSplitCells( rCursor, nCnt + 1, nsSwTblSearchType::TBLSEARCH_COL ) )
1710 return FALSE;
1712 // lasse ueber das Layout die Boxen suchen
1713 SwSelBoxes aBoxes;
1714 ::GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
1716 BOOL bRet = FALSE;
1717 if( aBoxes.Count() )
1718 bRet = InsertCol( aBoxes, nCnt, bBehind );
1719 return bRet;
1722 BOOL SwDoc::InsertCol( const SwSelBoxes& rBoxes, USHORT nCnt, BOOL bBehind )
1724 // uebers SwDoc fuer Undo !!
1725 ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
1726 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1727 if( !pTblNd )
1728 return FALSE;
1730 SwTable& rTbl = pTblNd->GetTable();
1731 if( rTbl.ISA( SwDDETable ))
1732 return FALSE;
1734 #ifdef DEL_TABLE_REDLINES
1735 lcl_DelRedlines aDelRedl( *pTblNd, TRUE );
1736 #endif
1738 SwTableSortBoxes aTmpLst( 0, 5 );
1739 SwUndoTblNdsChg* pUndo = 0;
1740 if( DoesUndo() )
1742 DoUndo( FALSE );
1743 pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSCOL, rBoxes, *pTblNd,
1744 0, 0, nCnt, bBehind, FALSE );
1745 aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
1748 SwTableFmlUpdate aMsgHnt( &rTbl );
1749 aMsgHnt.eFlags = TBL_BOXPTR;
1750 UpdateTblFlds( &aMsgHnt );
1752 BOOL bRet = rTbl.InsertCol( this, rBoxes, nCnt, bBehind );
1753 if( bRet )
1755 SetModified();
1756 ::ClearFEShellTabCols();
1757 SetFieldsDirty( true, NULL, 0 );
1760 if( pUndo )
1762 DoUndo( TRUE );
1763 if( bRet )
1765 ClearRedo();
1766 pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
1767 AppendUndo( pUndo );
1769 else
1770 delete pUndo;
1772 return bRet;
1775 BOOL SwDoc::InsertRow( const SwCursor& rCursor, USHORT nCnt, BOOL bBehind )
1777 // lasse ueber das Layout die Boxen suchen
1778 SwSelBoxes aBoxes;
1779 GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
1781 BOOL bRet = FALSE;
1782 if( aBoxes.Count() )
1783 bRet = InsertRow( aBoxes, nCnt, bBehind );
1784 return bRet;
1787 BOOL SwDoc::InsertRow( const SwSelBoxes& rBoxes, USHORT nCnt, BOOL bBehind )
1789 // uebers SwDoc fuer Undo !!
1790 ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
1791 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1792 if( !pTblNd )
1793 return FALSE;
1795 SwTable& rTbl = pTblNd->GetTable();
1796 if( rTbl.ISA( SwDDETable ))
1797 return FALSE;
1799 #ifdef DEL_TABLE_REDLINES
1800 lcl_DelRedlines aDelRedl( *pTblNd, TRUE );
1801 #endif
1803 SwTableSortBoxes aTmpLst( 0, 5 );
1804 SwUndoTblNdsChg* pUndo = 0;
1805 if( DoesUndo() )
1807 DoUndo( FALSE );
1808 pUndo = new SwUndoTblNdsChg( UNDO_TABLE_INSROW,rBoxes, *pTblNd,
1809 0, 0, nCnt, bBehind, FALSE );
1810 aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
1813 SwTableFmlUpdate aMsgHnt( &rTbl );
1814 aMsgHnt.eFlags = TBL_BOXPTR;
1815 UpdateTblFlds( &aMsgHnt );
1817 BOOL bRet = rTbl.InsertRow( this, rBoxes, nCnt, bBehind );
1818 if( bRet )
1820 SetModified();
1821 ::ClearFEShellTabCols();
1822 SetFieldsDirty( true, NULL, 0 );
1825 if( pUndo )
1827 DoUndo( TRUE );
1828 if( bRet )
1830 ClearRedo();
1831 pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
1832 AppendUndo( pUndo );
1834 else
1835 delete pUndo;
1837 return bRet;
1841 // ----- loeschen von Spalten/Zeilen ------------------------
1843 BOOL SwDoc::DeleteRow( const SwCursor& rCursor )
1845 // lasse ueber das Layout die Boxen suchen
1846 SwSelBoxes aBoxes;
1847 GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_ROW );
1848 if( ::HasProtectedCells( aBoxes ))
1849 return FALSE;
1851 // die Crsr aus dem Loeschbereich entfernen.
1852 // Der Cursor steht danach:
1853 // - es folgt noch eine Zeile, in dieser
1854 // - vorher steht noch eine Zeile, in dieser
1855 // - sonst immer dahinter
1857 SwTableNode* pTblNd = rCursor.GetNode()->FindTableNode();
1859 if( pTblNd->GetTable().ISA( SwDDETable ))
1860 return FALSE;
1862 // suche alle Boxen / Lines
1863 _FndBox aFndBox( 0, 0 );
1865 _FndPara aPara( aBoxes, &aFndBox );
1866 pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
1869 if( !aFndBox.GetLines().Count() )
1870 return FALSE;
1872 SwEditShell* pESh = GetEditShell();
1873 if( pESh )
1875 pESh->KillPams();
1876 // JP: eigentlich sollte man ueber alle Shells iterieren!!
1879 _FndBox* pFndBox = &aFndBox;
1880 while( 1 == pFndBox->GetLines().Count() &&
1881 1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
1883 _FndBox* pTmp = pFndBox->GetLines()[0]->GetBoxes()[0];
1884 if( pTmp->GetBox()->GetSttNd() )
1885 break; // das ist sonst zu weit
1886 pFndBox = pTmp;
1889 SwTableLine* pDelLine = pFndBox->GetLines()[
1890 pFndBox->GetLines().Count()-1 ]->GetLine();
1891 SwTableBox* pDelBox = pDelLine->GetTabBoxes()[
1892 pDelLine->GetTabBoxes().Count() - 1 ];
1893 while( !pDelBox->GetSttNd() )
1895 SwTableLine* pLn = pDelBox->GetTabLines()[
1896 pDelBox->GetTabLines().Count()-1 ];
1897 pDelBox = pLn->GetTabBoxes()[ pLn->GetTabBoxes().Count() - 1 ];
1899 SwTableBox* pNextBox = pDelLine->FindNextBox( pTblNd->GetTable(),
1900 pDelBox, TRUE );
1901 while( pNextBox &&
1902 pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
1903 pNextBox = pNextBox->FindNextBox( pTblNd->GetTable(), pNextBox );
1905 if( !pNextBox ) // keine nachfolgende? dann die vorhergehende
1907 pDelLine = pFndBox->GetLines()[ 0 ]->GetLine();
1908 pDelBox = pDelLine->GetTabBoxes()[ 0 ];
1909 while( !pDelBox->GetSttNd() )
1910 pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0];
1911 pNextBox = pDelLine->FindPreviousBox( pTblNd->GetTable(),
1912 pDelBox, TRUE );
1913 while( pNextBox &&
1914 pNextBox->GetFrmFmt()->GetProtect().IsCntntProtected() )
1915 pNextBox = pNextBox->FindPreviousBox( pTblNd->GetTable(), pNextBox );
1918 ULONG nIdx;
1919 if( pNextBox ) // dann den Cursor hier hinein
1920 nIdx = pNextBox->GetSttIdx() + 1;
1921 else // ansonsten hinter die Tabelle
1922 nIdx = pTblNd->EndOfSectionIndex() + 1;
1924 SwNodeIndex aIdx( GetNodes(), nIdx );
1925 SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
1926 if( !pCNd )
1927 pCNd = GetNodes().GoNext( &aIdx );
1929 if( pCNd )
1931 // die Cursor von der Shell oder den uebergebenen Cursor aendern?
1932 SwPaM* pPam = (SwPaM*)&rCursor;
1933 pPam->GetPoint()->nNode = aIdx;
1934 pPam->GetPoint()->nContent.Assign( pCNd, 0 );
1935 pPam->SetMark(); // beide wollen etwas davon haben
1936 pPam->DeleteMark();
1940 // dann loesche doch die Zeilen
1942 StartUndo(UNDO_ROW_DELETE, NULL);
1943 BOOL bResult = DeleteRowCol( aBoxes );
1944 EndUndo(UNDO_ROW_DELETE, NULL);
1946 return bResult;
1949 BOOL SwDoc::DeleteCol( const SwCursor& rCursor )
1951 // lasse ueber das Layout die Boxen suchen
1952 SwSelBoxes aBoxes;
1953 GetTblSel( rCursor, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
1954 if( ::HasProtectedCells( aBoxes ))
1955 return FALSE;
1957 // die Crsr muessen noch aus dem Loesch Bereich entfernt
1958 // werden. Setze sie immer hinter/auf die Tabelle; ueber die
1959 // Dokument-Position werden sie dann immer an die alte Position gesetzt.
1960 SwEditShell* pESh = GetEditShell();
1961 if( pESh )
1963 const SwNode* pNd = rCursor.GetNode()->FindTableBoxStartNode();
1964 pESh->ParkCrsr( SwNodeIndex( *pNd ) );
1967 // dann loesche doch die Spalten
1968 StartUndo(UNDO_COL_DELETE, NULL);
1969 BOOL bResult = DeleteRowCol( aBoxes, true );
1970 EndUndo(UNDO_COL_DELETE, NULL);
1972 return bResult;
1975 BOOL SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn )
1977 if( ::HasProtectedCells( rBoxes ))
1978 return FALSE;
1980 // uebers SwDoc fuer Undo !!
1981 ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
1982 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
1983 if( !pTblNd )
1984 return FALSE;
1986 if( pTblNd->GetTable().ISA( SwDDETable ))
1987 return FALSE;
1989 ::ClearFEShellTabCols();
1990 SwSelBoxes aSelBoxes;
1991 aSelBoxes.Insert(rBoxes.GetData(), rBoxes.Count());
1992 SwTable &rTable = pTblNd->GetTable();
1993 long nMin = 0;
1994 long nMax = 0;
1995 if( rTable.IsNewModel() )
1997 if( bColumn )
1998 rTable.ExpandColumnSelection( aSelBoxes, nMin, nMax );
1999 else
2000 rTable.FindSuperfluousRows( aSelBoxes );
2003 #ifdef DEL_TABLE_REDLINES
2004 lcl_DelRedlines aDelRedl( *pTblNd, TRUE );
2005 #endif
2007 // soll die gesamte Tabelle geloescht werden ??
2008 const ULONG nTmpIdx1 = pTblNd->GetIndex();
2009 const ULONG nTmpIdx2 = aSelBoxes[ aSelBoxes.Count()-1 ]->GetSttNd()->
2010 EndOfSectionIndex()+1;
2011 if( pTblNd->GetTable().GetTabSortBoxes().Count() == aSelBoxes.Count() &&
2012 aSelBoxes[0]->GetSttIdx()-1 == nTmpIdx1 &&
2013 nTmpIdx2 == pTblNd->EndOfSectionIndex() )
2015 BOOL bNewTxtNd = FALSE;
2016 // steht diese auch noch alleine in einem FlyFrame ?
2017 SwNodeIndex aIdx( *pTblNd, -1 );
2018 const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode();
2019 if( pSttNd )
2021 const ULONG nTblEnd = pTblNd->EndOfSectionIndex() + 1;
2022 const ULONG nSectEnd = pSttNd->EndOfSectionIndex();
2023 if( nTblEnd == nSectEnd )
2025 if( SwFlyStartNode == pSttNd->GetStartNodeType() )
2027 SwFrmFmt* pFmt = pSttNd->GetFlyFmt();
2028 if( pFmt )
2030 // Ok, das ist das gesuchte FlyFormat
2031 DelLayoutFmt( pFmt );
2032 return TRUE;
2035 // kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
2036 // TextNode ueberig lassen.
2037 // Undo koennen wir dann vergessen !!
2038 bNewTxtNd = TRUE;
2042 // kein Fly ?? also Kopf- oder Fusszeile: dann immer einen
2043 // TextNode ueberig lassen.
2044 aIdx++;
2045 if( DoesUndo() )
2047 ClearRedo();
2048 SwPaM aPaM( *pTblNd->EndOfSectionNode(), aIdx.GetNode() );
2050 if( bNewTxtNd )
2052 const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
2053 GetNodes().MakeTxtNode( aTmpIdx,
2054 GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
2057 // save the cursors (UNO and otherwise)
2058 SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
2059 if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
2061 *aSavePaM.GetMark() = SwPosition( *pTblNd );
2062 aSavePaM.Move( fnMoveBackward, fnGoNode );
2064 ::PaMCorrAbs( SwNodeIndex( *pTblNd ),
2065 SwNodeIndex( *pTblNd->EndOfSectionNode() ),
2066 *aSavePaM.GetMark() );
2068 // harte SeitenUmbrueche am nachfolgenden Node verschieben
2069 BOOL bSavePageBreak = FALSE, bSavePageDesc = FALSE;
2070 ULONG nNextNd = pTblNd->EndOfSectionIndex()+1;
2071 SwCntntNode* pNextNd = GetNodes()[ nNextNd ]->GetCntntNode();
2072 if( pNextNd )
2074 //JP 24.08.98: will man wirklich den PageDesc/Break vom
2075 // nachfolgen Absatz ueberbuegeln?
2076 // const SwAttrSet& rAttrSet = pNextNd->GetSwAttrSet();
2077 // if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) &&
2078 // SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK ))
2080 SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2081 const SfxPoolItem *pItem;
2082 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2083 FALSE, &pItem ) )
2085 pNextNd->SetAttr( *pItem );
2086 bSavePageDesc = TRUE;
2089 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2090 FALSE, &pItem ) )
2092 pNextNd->SetAttr( *pItem );
2093 bSavePageBreak = TRUE;
2097 SwUndoDelete* pUndo = new SwUndoDelete( aPaM );
2098 if( bNewTxtNd )
2099 pUndo->SetTblDelLastNd();
2100 pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
2101 pUndo->SetTableName(pTblNd->GetTable().GetFrmFmt()->GetName());
2102 AppendUndo( pUndo );
2104 else
2106 if( bNewTxtNd )
2108 const SwNodeIndex aTmpIdx( *pTblNd->EndOfSectionNode(), 1 );
2109 GetNodes().MakeTxtNode( aTmpIdx,
2110 GetTxtCollFromPool( RES_POOLCOLL_STANDARD ) );
2113 // save the cursors (UNO and otherwise)
2114 SwPaM aSavePaM( SwNodeIndex( *pTblNd->EndOfSectionNode() ) );
2115 if( ! aSavePaM.Move( fnMoveForward, fnGoNode ) )
2117 *aSavePaM.GetMark() = SwPosition( *pTblNd );
2118 aSavePaM.Move( fnMoveBackward, fnGoNode );
2120 ::PaMCorrAbs( SwNodeIndex( *pTblNd ),
2121 SwNodeIndex( *pTblNd->EndOfSectionNode() ),
2122 *aSavePaM.GetMark() );
2124 // harte SeitenUmbrueche am nachfolgenden Node verschieben
2125 SwCntntNode* pNextNd = GetNodes()[ pTblNd->EndOfSectionIndex()+1 ]->GetCntntNode();
2126 if( pNextNd )
2128 SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2129 const SfxPoolItem *pItem;
2130 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_PAGEDESC,
2131 FALSE, &pItem ) )
2132 pNextNd->SetAttr( *pItem );
2134 if( SFX_ITEM_SET == pTableFmt->GetItemState( RES_BREAK,
2135 FALSE, &pItem ) )
2136 pNextNd->SetAttr( *pItem );
2139 pTblNd->DelFrms();
2140 DeleteSection( pTblNd );
2142 SetModified();
2143 SetFieldsDirty( true, NULL, 0 );
2144 return TRUE;
2147 SwUndoTblNdsChg* pUndo = 0;
2148 if( DoesUndo() )
2150 DoUndo( FALSE );
2151 pUndo = new SwUndoTblNdsChg( UNDO_TABLE_DELBOX, aSelBoxes, *pTblNd,
2152 nMin, nMax, 0, FALSE, FALSE );
2155 SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
2156 aMsgHnt.eFlags = TBL_BOXPTR;
2157 UpdateTblFlds( &aMsgHnt );
2159 if( rTable.IsNewModel() )
2161 if( bColumn )
2162 rTable.PrepareDeleteCol( nMin, nMax );
2163 rTable.FindSuperfluousRows( aSelBoxes );
2164 if( pUndo )
2165 pUndo->ReNewBoxes( aSelBoxes );
2167 const BOOL bRet = rTable.DeleteSel( this, aSelBoxes, 0, pUndo, TRUE, TRUE );
2168 if( bRet )
2170 SetModified();
2171 SetFieldsDirty( true, NULL, 0 );
2174 if( pUndo )
2176 DoUndo( TRUE );
2177 if( bRet )
2179 ClearRedo();
2180 AppendUndo( pUndo );
2182 else
2183 delete pUndo;
2186 return bRet;
2190 // ---------- teilen / zusammenfassen von Boxen in der Tabelle --------
2192 BOOL SwDoc::SplitTbl( const SwSelBoxes& rBoxes, sal_Bool bVert, USHORT nCnt,
2193 sal_Bool bSameHeight )
2195 // uebers SwDoc fuer Undo !!
2196 ASSERT( rBoxes.Count() && nCnt, "keine gueltige Box-Liste" );
2197 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
2198 if( !pTblNd )
2199 return FALSE;
2201 SwTable& rTbl = pTblNd->GetTable();
2202 if( rTbl.ISA( SwDDETable ))
2203 return FALSE;
2205 #ifdef DEL_TABLE_REDLINES
2206 lcl_DelRedlines aDelRedl( *pTblNd, TRUE );
2207 #endif
2209 SvULongs aNdsCnts;
2210 SwTableSortBoxes aTmpLst( 0, 5 );
2211 SwUndoTblNdsChg* pUndo = 0;
2212 BOOL bDoUndo = DoesUndo();
2213 if( bDoUndo )
2215 DoUndo( FALSE );
2216 pUndo = new SwUndoTblNdsChg( UNDO_TABLE_SPLIT, rBoxes, *pTblNd, 0, 0,
2217 nCnt, bVert, bSameHeight );
2219 aTmpLst.Insert( &rTbl.GetTabSortBoxes(), 0, rTbl.GetTabSortBoxes().Count() );
2220 if( !bVert )
2222 for( USHORT n = 0; n < rBoxes.Count(); ++n )
2224 const SwStartNode* pSttNd = rBoxes[ n ]->GetSttNd();
2225 aNdsCnts.Insert( pSttNd->EndOfSectionIndex() -
2226 pSttNd->GetIndex(), n );
2231 SwTableFmlUpdate aMsgHnt( &rTbl );
2232 aMsgHnt.eFlags = TBL_BOXPTR;
2233 UpdateTblFlds( &aMsgHnt );
2235 BOOL bRet;
2236 if( bVert )
2237 bRet = rTbl.SplitCol( this, rBoxes, nCnt );
2238 else
2239 bRet = rTbl.SplitRow( this, rBoxes, nCnt, bSameHeight );
2241 if( bRet )
2243 SetModified();
2244 SetFieldsDirty( true, NULL, 0 );
2247 DoUndo( bDoUndo );
2248 if( pUndo )
2250 if( bRet )
2252 ClearRedo();
2253 if( bVert )
2254 pUndo->SaveNewBoxes( *pTblNd, aTmpLst );
2255 else
2256 pUndo->SaveNewBoxes( *pTblNd, aTmpLst, rBoxes, aNdsCnts );
2257 AppendUndo( pUndo );
2259 else
2260 delete pUndo;
2263 return bRet;
2267 USHORT SwDoc::MergeTbl( SwPaM& rPam )
2269 // pruefe ob vom aktuellen Crsr der SPoint/Mark in einer Tabelle stehen
2270 SwTableNode* pTblNd = rPam.GetNode()->FindTableNode();
2271 if( !pTblNd )
2272 return TBLMERGE_NOSELECTION;
2273 SwTable& rTable = pTblNd->GetTable();
2274 if( rTable.ISA(SwDDETable) )
2275 return TBLMERGE_NOSELECTION;
2276 USHORT nRet = TBLMERGE_NOSELECTION;
2277 if( !rTable.IsNewModel() )
2279 nRet =::CheckMergeSel( rPam );
2280 if( TBLMERGE_OK != nRet )
2281 return nRet;
2282 nRet = TBLMERGE_NOSELECTION;
2285 // --> FME 2004-10-08 #i33394#
2286 StartUndo( UNDO_TABLE_MERGE, NULL );
2287 // <--
2289 #ifdef DEL_TABLE_REDLINES
2290 if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
2291 DeleteRedline( *pTblNd, true, USHRT_MAX );
2292 #endif
2293 RedlineMode_t eOld = GetRedlineMode();
2294 SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
2296 SwUndoTblMerge* pUndo = 0;
2297 if( DoesUndo() )
2298 pUndo = new SwUndoTblMerge( rPam );
2300 // lasse ueber das Layout die Boxen suchen
2301 SwSelBoxes aBoxes;
2302 SwSelBoxes aMerged;
2303 SwTableBox* pMergeBox;
2305 if( !rTable.PrepareMerge( rPam, aBoxes, aMerged, &pMergeBox, pUndo ) )
2306 { // no cells found to merge
2307 SetRedlineMode_intern( eOld );
2308 if( pUndo )
2310 delete pUndo;
2311 if( UNDO_REDLINE == GetUndoIds(NULL, NULL) )
2313 SwUndoRedline* pU = (SwUndoRedline*)RemoveLastUndo( UNDO_REDLINE );
2314 if( pU->GetRedlSaveCount() )
2316 SwUndoIter aUndoIter( &rPam, UNDO_REDLINE );
2317 pU->Undo( aUndoIter );
2319 delete pU;
2323 else
2325 // die PaMs muessen noch aus dem Loesch Bereich entfernt
2326 // werden. Setze sie immer hinter/auf die Tabelle; ueber die
2327 // Dokument-Position werden sie dann immer an die alte Position gesetzt.
2328 // Erstmal einen Index auf die Parkposition merken, denn nach GetMergeSel
2329 // komme ich nicht mehr dran.
2331 rPam.DeleteMark();
2332 rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
2333 rPam.GetPoint()->nContent.Assign( 0, 0 );
2334 rPam.SetMark();
2335 rPam.DeleteMark();
2337 SwPaM* pTmp = &rPam;
2338 while( &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ))
2339 for( int i = 0; i < 2; ++i )
2340 pTmp->GetBound( (BOOL)i ) = *rPam.GetPoint();
2343 // dann fuege sie zusammen
2344 SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
2345 aMsgHnt.eFlags = TBL_BOXPTR;
2346 UpdateTblFlds( &aMsgHnt );
2348 if( pTblNd->GetTable().Merge( this, aBoxes, aMerged, pMergeBox, pUndo ))
2350 nRet = TBLMERGE_OK;
2351 SetModified();
2352 SetFieldsDirty( true, NULL, 0 );
2353 if( pUndo )
2354 AppendUndo( pUndo );
2356 else if( pUndo )
2357 delete pUndo;
2359 rPam.GetPoint()->nNode = *pMergeBox->GetSttNd();
2360 rPam.Move();
2362 ::ClearFEShellTabCols();
2363 SetRedlineMode_intern( eOld );
2365 EndUndo( UNDO_TABLE_MERGE, NULL );
2366 return nRet;
2371 // -------------------------------------------------------
2373 //---------
2374 // SwTableNode
2375 //---------
2377 SwTableNode::SwTableNode( const SwNodeIndex& rIdx )
2378 : SwStartNode( rIdx, ND_TABLENODE )
2380 pTable = new SwTable( 0 );
2383 SwTableNode::~SwTableNode()
2385 //don't forget to notify uno wrappers
2386 SwFrmFmt* pTblFmt = GetTable().GetFrmFmt();
2387 SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
2388 pTblFmt );
2389 pTblFmt->Modify( &aMsgHint, &aMsgHint );
2390 DelFrms();
2391 delete pTable;
2394 SwTabFrm *SwTableNode::MakeFrm()
2396 return new SwTabFrm( *pTable );
2399 //Methode erzeugt fuer den vorhergehenden Node alle Ansichten vom
2400 //Dokument. Die erzeugten Contentframes werden in das entsprechende
2401 //Layout gehaengt.
2402 void SwTableNode::MakeFrms(const SwNodeIndex & rIdx )
2404 if( !GetTable().GetFrmFmt()->GetDepends())//gibt es ueberhaupt Frames ??
2405 return;
2407 SwFrm *pFrm, *pNew;
2408 SwCntntNode * pNode = rIdx.GetNode().GetCntntNode();
2410 ASSERT( pNode, "Kein Contentnode oder Copy-Node und neuer Node identisch.");
2412 BOOL bBefore = rIdx < GetIndex();
2414 SwNode2Layout aNode2Layout( *this, rIdx.GetIndex() );
2416 while( 0 != (pFrm = aNode2Layout.NextFrm()) )
2418 pNew = pNode->MakeFrm();
2419 // wird ein Node vorher oder nachher mit Frames versehen
2420 if ( bBefore )
2421 // der neue liegt vor mir
2422 pNew->Paste( pFrm->GetUpper(), pFrm );
2423 else
2424 // der neue liegt hinter mir
2425 pNew->Paste( pFrm->GetUpper(), pFrm->GetNext() );
2429 //Fuer jede Shell einen TblFrm anlegen und vor den entsprechenden
2430 //CntntFrm pasten.
2432 void SwTableNode::MakeFrms( SwNodeIndex* pIdxBehind )
2434 ASSERT( pIdxBehind, "kein Index" );
2435 *pIdxBehind = *this;
2436 SwNode *pNd = GetNodes().FindPrvNxtFrmNode( *pIdxBehind, EndOfSectionNode() );
2437 if( !pNd )
2438 return ;
2440 SwFrm *pFrm( 0L );
2441 SwLayoutFrm *pUpper( 0L );
2442 SwNode2Layout aNode2Layout( *pNd, GetIndex() );
2443 while( 0 != (pUpper = aNode2Layout.UpperFrm( pFrm, *this )) )
2445 SwTabFrm* pNew = MakeFrm();
2446 pNew->Paste( pUpper, pFrm );
2447 // --> OD 2005-12-01 #i27138#
2448 // notify accessibility paragraphs objects about changed
2449 // CONTENT_FLOWS_FROM/_TO relation.
2450 // Relation CONTENT_FLOWS_FROM for next paragraph will change
2451 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
2453 ViewShell* pViewShell( pNew->GetShell() );
2454 if ( pViewShell && pViewShell->GetLayout() &&
2455 pViewShell->GetLayout()->IsAnyShellAccessible() )
2457 pViewShell->InvalidateAccessibleParaFlowRelation(
2458 dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
2459 dynamic_cast<SwTxtFrm*>(pNew->FindPrevCnt( true )) );
2462 // <--
2463 ((SwTabFrm*)pNew)->RegistFlys();
2467 void SwTableNode::DelFrms()
2469 //Erstmal die TabFrms ausschneiden und deleten, die Columns und Rows
2470 //nehmen sie mit in's Grab.
2471 //Die TabFrms haengen am FrmFmt des SwTable.
2472 //Sie muessen etwas umstaendlich zerstort werden, damit die Master
2473 //die Follows mit in's Grab nehmen.
2475 SwClientIter aIter( *(pTable->GetFrmFmt()) );
2476 SwClient *pLast = aIter.GoStart();
2477 while ( pLast )
2479 BOOL bAgain = FALSE;
2480 if ( pLast->IsA( TYPE(SwFrm) ) )
2482 SwTabFrm *pFrm = (SwTabFrm*)pLast;
2483 if ( !pFrm->IsFollow() )
2485 while ( pFrm->HasFollow() )
2486 pFrm->JoinAndDelFollows();
2487 // --> OD 2005-12-01 #i27138#
2488 // notify accessibility paragraphs objects about changed
2489 // CONTENT_FLOWS_FROM/_TO relation.
2490 // Relation CONTENT_FLOWS_FROM for current next paragraph will change
2491 // and relation CONTENT_FLOWS_TO for current previous paragraph will change.
2493 ViewShell* pViewShell( pFrm->GetShell() );
2494 if ( pViewShell && pViewShell->GetLayout() &&
2495 pViewShell->GetLayout()->IsAnyShellAccessible() )
2497 pViewShell->InvalidateAccessibleParaFlowRelation(
2498 dynamic_cast<SwTxtFrm*>(pFrm->FindNextCnt( true )),
2499 dynamic_cast<SwTxtFrm*>(pFrm->FindPrevCnt( true )) );
2502 // <--
2503 pFrm->Cut();
2504 delete pFrm;
2505 bAgain = TRUE;
2508 pLast = bAgain ? aIter.GoStart() : aIter++;
2513 void SwTableNode::SetNewTable( SwTable* pNewTable, BOOL bNewFrames )
2515 DelFrms();
2516 delete pTable;
2517 pTable = pNewTable;
2518 if( bNewFrames )
2520 SwNodeIndex aIdx( *EndOfSectionNode());
2521 GetNodes().GoNext( &aIdx );
2522 MakeFrms( &aIdx );
2526 void SwDoc::GetTabCols( SwTabCols &rFill, const SwCursor* pCrsr,
2527 const SwCellFrm* pBoxFrm ) const
2529 const SwTableBox* pBox = 0;
2530 SwTabFrm *pTab = 0;
2532 if( pBoxFrm )
2534 pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2535 pBox = pBoxFrm->GetTabBox();
2537 else if( pCrsr )
2539 const SwCntntNode* pCNd = pCrsr->GetCntntNode();
2540 if( !pCNd )
2541 return ;
2543 Point aPt;
2544 const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
2545 if( pShCrsr )
2546 aPt = pShCrsr->GetPtPos();
2548 const SwFrm* pTmpFrm = pCNd->GetFrm( &aPt, 0, FALSE );
2549 do {
2550 pTmpFrm = pTmpFrm->GetUpper();
2551 } while ( !pTmpFrm->IsCellFrm() );
2553 pBoxFrm = (SwCellFrm*)pTmpFrm;
2554 pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2555 pBox = pBoxFrm->GetTabBox();
2557 else if( !pCrsr && !pBoxFrm )
2559 ASSERT( !this, "einer von beiden muss angegeben werden!" );
2560 return ;
2563 //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2564 SWRECTFN( pTab )
2565 const SwPageFrm* pPage = pTab->FindPageFrm();
2566 const ULONG nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
2567 (pPage->Frm().*fnRect->fnGetLeft)();
2568 const ULONG nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
2569 (pPage->Frm().*fnRect->fnGetLeft)();
2571 rFill.SetLeftMin ( nLeftMin );
2572 rFill.SetLeft ( (pTab->Prt().*fnRect->fnGetLeft)() );
2573 rFill.SetRight ( (pTab->Prt().*fnRect->fnGetRight)());
2574 rFill.SetRightMax( nRightMax - nLeftMin );
2576 pTab->GetTable()->GetTabCols( rFill, pBox );
2580 // Here are some little helpers used in SwDoc::GetTabRows
2583 #define ROWFUZZY 25
2585 struct FuzzyCompare
2587 bool operator() ( long s1, long s2 ) const;
2590 bool FuzzyCompare::operator() ( long s1, long s2 ) const
2592 return ( s1 < s2 && abs( s1 - s2 ) > ROWFUZZY );
2595 bool lcl_IsFrmInColumn( const SwCellFrm& rFrm, SwSelBoxes& rBoxes )
2597 for( USHORT i = 0; i < rBoxes.Count(); ++i )
2599 if ( rFrm.GetTabBox() == rBoxes[ i ] )
2600 return true;
2603 return false;
2607 // SwDoc::GetTabRows()
2610 void SwDoc::GetTabRows( SwTabCols &rFill, const SwCursor* ,
2611 const SwCellFrm* pBoxFrm ) const
2613 ASSERT( pBoxFrm, "GetTabRows called without pBoxFrm" )
2615 // --> FME 2005-09-12 #121591# Make code robust:
2616 if ( !pBoxFrm )
2617 return;
2618 // <--
2620 // --> FME 2005-01-06 #i39552# Collection of the boxes of the current
2621 // column has to be done at the beginning of this function, because
2622 // the table may be formatted in ::GetTblSel.
2623 SwDeletionChecker aDelCheck( pBoxFrm );
2625 SwSelBoxes aBoxes;
2626 const SwCntntFrm* pCntnt = ::GetCellCntnt( *pBoxFrm );
2627 if ( pCntnt && pCntnt->IsTxtFrm() )
2629 const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
2630 const SwCursor aTmpCrsr( aPos, 0, false );
2631 ::GetTblSel( aTmpCrsr, aBoxes, nsSwTblSearchType::TBLSEARCH_COL );
2633 // <--
2635 // --> FME 2005-09-12 #121591# Make code robust:
2636 if ( aDelCheck.HasBeenDeleted() )
2638 ASSERT( false, "Current box has been deleted during GetTabRows()" )
2639 return;
2641 // <--
2643 // --> FME 2005-09-12 #121591# Make code robust:
2644 const SwTabFrm* pTab = pBoxFrm->FindTabFrm();
2645 ASSERT( pTab, "GetTabRows called without a table" )
2646 if ( !pTab )
2647 return;
2648 // <--
2650 const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
2652 //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2653 SWRECTFN( pTab )
2654 const SwPageFrm* pPage = pTab->FindPageFrm();
2655 const long nLeftMin = ( bVert ?
2656 pTab->GetPrtLeft() - pPage->Frm().Left() :
2657 pTab->GetPrtTop() - pPage->Frm().Top() );
2658 const long nLeft = bVert ? LONG_MAX : 0;
2659 const long nRight = (pTab->Prt().*fnRect->fnGetHeight)();
2660 const long nRightMax = bVert ? nRight : LONG_MAX;
2662 rFill.SetLeftMin( nLeftMin );
2663 rFill.SetLeft( nLeft );
2664 rFill.SetRight( nRight );
2665 rFill.SetRightMax( nRightMax );
2667 typedef std::map< long, std::pair< long, long >, FuzzyCompare > BoundaryMap;
2668 BoundaryMap aBoundaries;
2669 BoundaryMap::iterator aIter;
2670 std::pair< long, long > aPair;
2672 typedef std::map< long, bool > HiddenMap;
2673 HiddenMap aHidden;
2674 HiddenMap::iterator aHiddenIter;
2676 while ( pFrm && pTab->IsAnLower( pFrm ) )
2678 if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
2680 // upper and lower borders of current cell frame:
2681 long nUpperBorder = (pFrm->Frm().*fnRect->fnGetTop)();
2682 long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
2684 // get boundaries for nUpperBorder:
2685 aIter = aBoundaries.find( nUpperBorder );
2686 if ( aIter == aBoundaries.end() )
2688 aPair.first = nUpperBorder; aPair.second = LONG_MAX;
2689 aBoundaries[ nUpperBorder ] = aPair;
2692 // get boundaries for nLowerBorder:
2693 aIter = aBoundaries.find( nLowerBorder );
2694 if ( aIter == aBoundaries.end() )
2696 aPair.first = nUpperBorder; aPair.second = LONG_MAX;
2698 else
2700 nLowerBorder = (*aIter).first;
2701 long nNewLowerBorderUpperBoundary = Max( (*aIter).second.first, nUpperBorder );
2702 aPair.first = nNewLowerBorderUpperBoundary; aPair.second = LONG_MAX;
2704 aBoundaries[ nLowerBorder ] = aPair;
2706 // calculate hidden flags for entry nUpperBorder/nLowerBorder:
2707 long nTmpVal = nUpperBorder;
2708 for ( BYTE i = 0; i < 2; ++i )
2710 aHiddenIter = aHidden.find( nTmpVal );
2711 if ( aHiddenIter == aHidden.end() )
2712 aHidden[ nTmpVal ] = !lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes );
2713 else
2715 if ( aHidden[ nTmpVal ] &&
2716 lcl_IsFrmInColumn( *((SwCellFrm*)pFrm), aBoxes ) )
2717 aHidden[ nTmpVal ] = false;
2719 nTmpVal = nLowerBorder;
2723 pFrm = pFrm->GetNextLayoutLeaf();
2726 // transfer calculated values from BoundaryMap and HiddenMap into rFill:
2727 USHORT nIdx = 0;
2728 for ( aIter = aBoundaries.begin(); aIter != aBoundaries.end(); ++aIter )
2730 const long nTabTop = (pTab->*fnRect->fnGetPrtTop)();
2731 const long nKey = (*fnRect->fnYDiff)( (*aIter).first, nTabTop );
2732 const std::pair< long, long > aTmpPair = (*aIter).second;
2733 const long nFirst = (*fnRect->fnYDiff)( aTmpPair.first, nTabTop );
2734 const long nSecond = aTmpPair.second;
2736 aHiddenIter = aHidden.find( (*aIter).first );
2737 const bool bHidden = aHiddenIter != aHidden.end() && (*aHiddenIter).second;
2738 rFill.Insert( nKey, nFirst, nSecond, bHidden, nIdx++ );
2741 // delete first and last entry
2742 ASSERT( rFill.Count(), "Deleting from empty vector. Fasten your seatbelts!" )
2743 // --> FME 2006-01-19 #i60818# There may be only one entry in rFill. Make
2744 // code robust by checking count of rFill.
2745 if ( rFill.Count() ) rFill.Remove( 0, 1 );
2746 if ( rFill.Count() ) rFill.Remove( rFill.Count() - 1 , 1 );
2747 // <--
2748 rFill.SetLastRowAllowedToChange( !pTab->HasFollowFlowLine() );
2751 void SwDoc::SetTabCols( const SwTabCols &rNew, BOOL bCurRowOnly,
2752 const SwCursor* pCrsr, const SwCellFrm* pBoxFrm )
2754 const SwTableBox* pBox = 0;
2755 SwTabFrm *pTab = 0;
2757 if( pBoxFrm )
2759 pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2760 pBox = pBoxFrm->GetTabBox();
2762 else if( pCrsr )
2764 const SwCntntNode* pCNd = pCrsr->GetCntntNode();
2765 if( !pCNd )
2766 return ;
2768 Point aPt;
2769 const SwShellCrsr *pShCrsr = dynamic_cast<const SwShellCrsr*>(pCrsr);
2770 if( pShCrsr )
2771 aPt = pShCrsr->GetPtPos();
2773 const SwFrm* pTmpFrm = pCNd->GetFrm( &aPt, 0, FALSE );
2774 do {
2775 pTmpFrm = pTmpFrm->GetUpper();
2776 } while ( !pTmpFrm->IsCellFrm() );
2778 pBoxFrm = (SwCellFrm*)pTmpFrm;
2779 pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2780 pBox = pBoxFrm->GetTabBox();
2782 else if( !pCrsr && !pBoxFrm )
2784 ASSERT( !this, "einer von beiden muss angegeben werden!" );
2785 return ;
2788 // sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
2789 // dann muss es jetzt auf absolute umgerechnet werden.
2790 SwTable& rTab = *pTab->GetTable();
2791 const SwFmtFrmSize& rTblFrmSz = rTab.GetFrmFmt()->GetFrmSize();
2792 SWRECTFN( pTab )
2793 // OD 06.08.2003 #i17174# - With fix for #i9040# the shadow size is taken
2794 // from the table width. Thus, add its left and right size to current table
2795 // printing area width in order to get the correct table size attribute.
2796 SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)();
2798 SvxShadowItem aShadow( rTab.GetFrmFmt()->GetShadow() );
2799 nPrtWidth += aShadow.CalcShadowSpace( SHADOW_LEFT ) +
2800 aShadow.CalcShadowSpace( SHADOW_RIGHT );
2802 if( nPrtWidth != rTblFrmSz.GetWidth() )
2804 SwFmtFrmSize aSz( rTblFrmSz );
2805 aSz.SetWidth( nPrtWidth );
2806 rTab.GetFrmFmt()->SetFmtAttr( aSz );
2809 SwTabCols aOld( rNew.Count() );
2811 const SwPageFrm* pPage = pTab->FindPageFrm();
2812 const ULONG nLeftMin = (pTab->Frm().*fnRect->fnGetLeft)() -
2813 (pPage->Frm().*fnRect->fnGetLeft)();
2814 const ULONG nRightMax = (pTab->Frm().*fnRect->fnGetRight)() -
2815 (pPage->Frm().*fnRect->fnGetLeft)();
2817 //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2818 aOld.SetLeftMin ( nLeftMin );
2819 aOld.SetLeft ( (pTab->Prt().*fnRect->fnGetLeft)() );
2820 aOld.SetRight ( (pTab->Prt().*fnRect->fnGetRight)());
2821 aOld.SetRightMax( nRightMax - nLeftMin );
2823 rTab.GetTabCols( aOld, pBox );
2824 SetTabCols(rTab, rNew, aOld, pBox, bCurRowOnly );
2827 void SwDoc::SetTabRows( const SwTabCols &rNew, BOOL bCurColOnly, const SwCursor*,
2828 const SwCellFrm* pBoxFrm )
2830 const SwTableBox* pBox;
2831 SwTabFrm *pTab;
2833 ASSERT( pBoxFrm, "SetTabRows called without pBoxFrm" )
2835 pTab = ((SwFrm*)pBoxFrm)->ImplFindTabFrm();
2836 pBox = pBoxFrm->GetTabBox();
2838 // sollte die Tabelle noch auf relativen Werten (USHRT_MAX) stehen
2839 // dann muss es jetzt auf absolute umgerechnet werden.
2840 SWRECTFN( pTab )
2841 SwTabCols aOld( rNew.Count() );
2843 //Fix-Punkte setzen, LeftMin in Dokumentkoordinaten die anderen relativ.
2844 const SwPageFrm* pPage = pTab->FindPageFrm();
2846 aOld.SetRight( (pTab->Prt().*fnRect->fnGetHeight)() );
2847 long nLeftMin;
2848 if ( bVert )
2850 nLeftMin = pTab->GetPrtLeft() - pPage->Frm().Left();
2851 aOld.SetLeft ( LONG_MAX );
2852 aOld.SetRightMax( aOld.GetRight() );
2855 else
2857 nLeftMin = pTab->GetPrtTop() - pPage->Frm().Top();
2858 aOld.SetLeft ( 0 );
2859 aOld.SetRightMax( LONG_MAX );
2861 aOld.SetLeftMin ( nLeftMin );
2863 GetTabRows( aOld, 0, pBoxFrm );
2865 StartUndo( UNDO_TABLE_ATTR, NULL );
2867 // check for differences between aOld and rNew:
2868 const USHORT nCount = rNew.Count();
2869 const SwTable* pTable = pTab->GetTable();
2870 ASSERT( pTable, "My colleague told me, this couldn't happen" );
2872 for ( USHORT i = 0; i <= nCount; ++i )
2874 const USHORT nIdxStt = bVert ? nCount - i : i - 1;
2875 const USHORT nIdxEnd = bVert ? nCount - i - 1 : i;
2877 const long nOldRowStart = i == 0 ? 0 : aOld[ nIdxStt ];
2878 const long nOldRowEnd = i == nCount ? aOld.GetRight() : aOld[ nIdxEnd ];
2879 const long nOldRowHeight = nOldRowEnd - nOldRowStart;
2881 const long nNewRowStart = i == 0 ? 0 : rNew[ nIdxStt ];
2882 const long nNewRowEnd = i == nCount ? rNew.GetRight() : rNew[ nIdxEnd ];
2883 const long nNewRowHeight = nNewRowEnd - nNewRowStart;
2885 const long nDiff = nNewRowHeight - nOldRowHeight;
2886 if ( abs( nDiff ) >= ROWFUZZY )
2888 // For the old table model pTxtFrm and pLine will be set for every box.
2889 // For the new table model pTxtFrm will be set if the box is not covered,
2890 // but the pLine will be set if the box is not an overlapping box
2891 // In the new table model the row height can be adjusted,
2892 // when both variables are set.
2893 SwTxtFrm* pTxtFrm = 0;
2894 const SwTableLine* pLine = 0;
2896 // Iterate over all SwCellFrms with Bottom = nOldPos
2897 const SwFrm* pFrm = pTab->GetNextLayoutLeaf();
2898 while ( pFrm && pTab->IsAnLower( pFrm ) )
2900 if ( pFrm->IsCellFrm() && pFrm->FindTabFrm() == pTab )
2902 const long nLowerBorder = (pFrm->Frm().*fnRect->fnGetBottom)();
2903 const ULONG nTabTop = (pTab->*fnRect->fnGetPrtTop)();
2904 if ( abs( (*fnRect->fnYInc)( nTabTop, nOldRowEnd ) - nLowerBorder ) <= ROWFUZZY )
2906 if ( !bCurColOnly || pFrm == pBoxFrm )
2908 const SwFrm* pCntnt = ::GetCellCntnt( static_cast<const SwCellFrm&>(*pFrm) );
2910 if ( pCntnt && pCntnt->IsTxtFrm() )
2912 pBox = ((SwCellFrm*)pFrm)->GetTabBox();
2913 const long nRowSpan = pBox->getRowSpan();
2914 if( nRowSpan > 0 ) // Not overlapped
2915 pTxtFrm = (SwTxtFrm*)pCntnt;
2916 if( nRowSpan < 2 ) // Not overlapping for row height
2917 pLine = pBox->GetUpper();
2918 if( pLine && pTxtFrm ) // always for old table model
2920 // The new row height must not to be calculated from a overlapping box
2921 SwFmtFrmSize aNew( pLine->GetFrmFmt()->GetFrmSize() );
2922 const long nNewSize = (pFrm->Frm().*fnRect->fnGetHeight)() + nDiff;
2923 if( nNewSize != aNew.GetHeight() )
2925 aNew.SetHeight( nNewSize );
2926 if ( ATT_VAR_SIZE == aNew.GetHeightSizeType() )
2927 aNew.SetHeightSizeType( ATT_MIN_SIZE );
2928 // This position must not be in an overlapped box
2929 const SwPosition aPos( *((SwTxtFrm*)pCntnt)->GetTxtNode() );
2930 const SwCursor aTmpCrsr( aPos, 0, false );
2931 SetRowHeight( aTmpCrsr, aNew );
2932 // For the new table model we're done, for the old one
2933 // there might be another (sub)row to adjust...
2934 if( pTable->IsNewModel() )
2935 break;
2937 pLine = 0;
2943 pFrm = pFrm->GetNextLayoutLeaf();
2948 EndUndo( UNDO_TABLE_ATTR, NULL );
2950 ::ClearFEShellTabCols();
2953 /* -----------------18.07.98 11:45-------------------
2954 * Direktzugriff fuer UNO
2955 * --------------------------------------------------*/
2956 void SwDoc::SetTabCols(SwTable& rTab, const SwTabCols &rNew, const SwTabCols &rOld,
2957 const SwTableBox *pStart, BOOL bCurRowOnly )
2959 if( DoesUndo() )
2961 ClearRedo();
2962 AppendUndo( new SwUndoAttrTbl( *rTab.GetTableNode(), TRUE ));
2964 rTab.SetTabCols( rNew, rOld, pStart, bCurRowOnly );
2965 ::ClearFEShellTabCols();
2966 SetModified();
2969 void SwDoc::SetRowsToRepeat( SwTable &rTable, USHORT nSet )
2971 if( nSet == rTable.GetRowsToRepeat() )
2972 return;
2974 if( DoesUndo() )
2976 ClearRedo();
2977 AppendUndo( new SwUndoTblHeadline( rTable, rTable.GetRowsToRepeat() , nSet) );
2980 SwMsgPoolItem aChg( RES_TBLHEADLINECHG );
2981 rTable.SetRowsToRepeat( nSet );
2982 rTable.GetFrmFmt()->Modify( &aChg, &aChg );
2983 SetModified();
2989 // Splittet eine Tabelle in der Grund-Zeile, in der der Index steht.
2990 // Alle GrundZeilen dahinter wandern in eine neue Tabelle/-Node.
2991 // Ist das Flag bCalcNewSize auf TRUE, wird fuer beide neuen Tabellen
2992 // die neue Size aus dem Max der Boxen errechnet; vorrausgesetzt,
2993 // die Size ist "absolut" gesetzt (USHRT_MAX)
2995 void SwCollectTblLineBoxes::AddToUndoHistory( const SwCntntNode& rNd )
2997 if( pHst )
2998 pHst->Add( rNd.GetFmtColl(), rNd.GetIndex(), ND_TEXTNODE );
3001 void SwCollectTblLineBoxes::AddBox( const SwTableBox& rBox )
3003 aPosArr.Insert( nWidth, aPosArr.Count() );
3004 SwTableBox* p = (SwTableBox*)&rBox;
3005 aBoxes.Insert( p, aBoxes.Count() );
3006 nWidth = nWidth + (USHORT)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
3009 const SwTableBox* SwCollectTblLineBoxes::GetBoxOfPos( const SwTableBox& rBox )
3011 const SwTableBox* pRet = 0;
3012 USHORT n;
3014 if( aPosArr.Count() )
3016 for( n = 0; n < aPosArr.Count(); ++n )
3017 if( aPosArr[ n ] == nWidth )
3018 break;
3019 else if( aPosArr[ n ] > nWidth )
3021 if( n )
3022 --n;
3023 break;
3026 if( n >= aPosArr.Count() )
3027 --n;
3029 nWidth = nWidth + (USHORT)rBox.GetFrmFmt()->GetFrmSize().GetWidth();
3030 pRet = aBoxes[ n ];
3032 return pRet;
3035 BOOL SwCollectTblLineBoxes::Resize( USHORT nOffset, USHORT nOldWidth )
3037 USHORT n;
3039 if( aPosArr.Count() )
3041 for( n = 0; n < aPosArr.Count(); ++n )
3042 if( aPosArr[ n ] == nOffset )
3043 break;
3044 else if( aPosArr[ n ] > nOffset )
3046 if( n )
3047 --n;
3048 break;
3051 aPosArr.Remove( 0, n );
3052 aBoxes.Remove( 0, n );
3054 // dann die Positionen der neuen Size anpassen
3055 for( n = 0; n < aPosArr.Count(); ++n )
3057 ULONG nSize = nWidth;
3058 nSize *= ( aPosArr[ n ] - nOffset );
3059 nSize /= nOldWidth;
3060 aPosArr[ n ] = USHORT( nSize );
3063 return 0 != aPosArr.Count();
3066 BOOL lcl_Line_CollectBox( const SwTableLine*& rpLine, void* pPara )
3068 SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
3069 if( pSplPara->IsGetValues() )
3070 ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_Box_CollectBox, pPara );
3071 else
3072 ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, pPara );
3073 return TRUE;
3076 BOOL lcl_Box_CollectBox( const SwTableBox*& rpBox, void* pPara )
3078 SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
3079 USHORT nLen = rpBox->GetTabLines().Count();
3080 if( nLen )
3082 // dann mit der richtigen Line weitermachen
3083 if( pSplPara->IsGetFromTop() )
3084 nLen = 0;
3085 else
3086 --nLen;
3088 const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
3089 lcl_Line_CollectBox( pLn, pPara );
3091 else
3092 pSplPara->AddBox( *rpBox );
3093 return TRUE;
3096 BOOL lcl_BoxSetSplitBoxFmts( const SwTableBox*& rpBox, void* pPara )
3098 SwCollectTblLineBoxes* pSplPara = (SwCollectTblLineBoxes*)pPara;
3099 USHORT nLen = rpBox->GetTabLines().Count();
3100 if( nLen )
3102 // dann mit der richtigen Line weitermachen
3103 if( pSplPara->IsGetFromTop() )
3104 nLen = 0;
3105 else
3106 --nLen;
3108 const SwTableLine* pLn = rpBox->GetTabLines()[ nLen ];
3109 lcl_Line_CollectBox( pLn, pPara );
3111 else
3113 const SwTableBox* pSrcBox = pSplPara->GetBoxOfPos( *rpBox );
3114 SwFrmFmt* pFmt = pSrcBox->GetFrmFmt();
3115 SwTableBox* pBox = (SwTableBox*)rpBox;
3117 if( HEADLINE_BORDERCOPY == pSplPara->GetMode() )
3119 const SvxBoxItem& rBoxItem = pBox->GetFrmFmt()->GetBox();
3120 if( !rBoxItem.GetTop() )
3122 SvxBoxItem aNew( rBoxItem );
3123 aNew.SetLine( pFmt->GetBox().GetBottom(), BOX_LINE_TOP );
3124 if( aNew != rBoxItem )
3125 pBox->ClaimFrmFmt()->SetFmtAttr( aNew );
3128 else
3130 USHORT __FAR_DATA aTableSplitBoxSetRange[] = {
3131 RES_LR_SPACE, RES_UL_SPACE,
3132 RES_BACKGROUND, RES_SHADOW,
3133 RES_PROTECT, RES_PROTECT,
3134 RES_VERT_ORIENT, RES_VERT_ORIENT,
3135 0 };
3136 SfxItemSet aTmpSet( pFmt->GetDoc()->GetAttrPool(),
3137 aTableSplitBoxSetRange );
3138 aTmpSet.Put( pFmt->GetAttrSet() );
3139 if( aTmpSet.Count() )
3140 pBox->ClaimFrmFmt()->SetFmtAttr( aTmpSet );
3142 if( HEADLINE_BOXATRCOLLCOPY == pSplPara->GetMode() )
3144 SwNodeIndex aIdx( *pSrcBox->GetSttNd(), 1 );
3145 SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
3146 if( !pCNd )
3147 pCNd = aIdx.GetNodes().GoNext( &aIdx );
3148 aIdx = *pBox->GetSttNd();
3149 SwCntntNode* pDNd = aIdx.GetNodes().GoNext( &aIdx );
3151 // nur wenn der Node alleine in der Section steht
3152 if( 2 == pDNd->EndOfSectionIndex() -
3153 pDNd->StartOfSectionIndex() )
3155 pSplPara->AddToUndoHistory( *pDNd );
3156 pDNd->ChgFmtColl( pCNd->GetFmtColl() );
3160 // bedingte Vorlage beachten
3161 pBox->GetSttNd()->CheckSectionCondColl();
3164 return TRUE;
3168 BOOL SwDoc::SplitTable( const SwPosition& rPos, USHORT eHdlnMode,
3169 BOOL bCalcNewSize )
3171 SwNode* pNd = &rPos.nNode.GetNode();
3172 SwTableNode* pTNd = pNd->FindTableNode();
3173 if( !pTNd || pNd->IsTableNode() )
3174 return 0;
3176 if( pTNd->GetTable().ISA( SwDDETable ))
3177 return FALSE;
3179 SwTable& rTbl = pTNd->GetTable();
3180 rTbl.SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen
3182 SwTableFmlUpdate aMsgHnt( &rTbl );
3184 SwHistory aHistory;
3185 if( DoesUndo() )
3186 aMsgHnt.pHistory = &aHistory;
3189 ULONG nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
3191 // Suche die Grund-Line dieser Box:
3192 SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
3193 if( pBox )
3195 SwTableLine* pLine = pBox->GetUpper();
3196 while( pLine->GetUpper() )
3197 pLine = pLine->GetUpper()->GetUpper();
3199 // in pLine steht jetzt die GrundLine.
3200 aMsgHnt.nSplitLine = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
3203 String sNewTblNm( GetUniqueTblName() );
3204 aMsgHnt.DATA.pNewTblNm = &sNewTblNm;
3205 aMsgHnt.eFlags = TBL_SPLITTBL;
3206 UpdateTblFlds( &aMsgHnt );
3209 //Lines fuer das Layout-Update heraussuchen.
3210 _FndBox aFndBox( 0, 0 );
3211 aFndBox.SetTableLines( rTbl );
3212 aFndBox.DelFrms( rTbl );
3214 // TL_CHART2: need to inform chart of probably changed cell names
3215 //pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
3217 SwTableNode* pNew = GetNodes().SplitTable( rPos.nNode, FALSE, bCalcNewSize );
3219 if( pNew )
3221 SwSaveRowSpan* pSaveRowSp = pNew->GetTable().CleanUpTopRowSpan( rTbl.GetTabLines().Count() );
3222 SwUndoSplitTbl* pUndo = 0;
3223 if( DoesUndo() )
3225 ClearRedo();
3226 AppendUndo( pUndo = new SwUndoSplitTbl( *pNew, pSaveRowSp, eHdlnMode, bCalcNewSize ));
3227 if( aHistory.Count() )
3228 pUndo->SaveFormula( aHistory );
3231 switch( eHdlnMode )
3233 // setze die untere Border der vorherige Line,
3234 // an der aktuellen als obere
3235 case HEADLINE_BORDERCOPY:
3237 SwCollectTblLineBoxes aPara( FALSE, eHdlnMode );
3238 SwTableLine* pLn = rTbl.GetTabLines()[
3239 rTbl.GetTabLines().Count() - 1 ];
3240 pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
3242 aPara.SetValues( TRUE );
3243 pLn = pNew->GetTable().GetTabLines()[ 0 ];
3244 pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
3246 // Kopfzeile wiederholen abschalten
3247 pNew->GetTable().SetRowsToRepeat( 0 );
3249 break;
3251 // setze die Attributierung der ersten Line an der neuen ersten
3252 case HEADLINE_BOXATTRCOPY:
3253 case HEADLINE_BOXATRCOLLCOPY:
3255 SwHistory* pHst = 0;
3256 if( HEADLINE_BOXATRCOLLCOPY == eHdlnMode && pUndo )
3257 pHst = pUndo->GetHistory();
3259 SwCollectTblLineBoxes aPara( TRUE, eHdlnMode, pHst );
3260 SwTableLine* pLn = rTbl.GetTabLines()[ 0 ];
3261 pLn->GetTabBoxes().ForEach( &lcl_Box_CollectBox, &aPara );
3263 aPara.SetValues( TRUE );
3264 pLn = pNew->GetTable().GetTabLines()[ 0 ];
3265 pLn->GetTabBoxes().ForEach( &lcl_BoxSetSplitBoxFmts, &aPara );
3267 break;
3269 case HEADLINE_CNTNTCOPY:
3270 rTbl.CopyHeadlineIntoTable( *pNew );
3271 if( pUndo )
3272 pUndo->SetTblNodeOffset( pNew->GetIndex() );
3273 break;
3275 case HEADLINE_NONE:
3276 // Kopfzeile wiederholen abschalten
3277 pNew->GetTable().SetRowsToRepeat( 0 );
3278 break;
3281 // und Frms einfuegen.
3282 SwNodeIndex aNdIdx( *pNew->EndOfSectionNode() );
3283 GetNodes().GoNext( &aNdIdx ); // zum naechsten ContentNode
3284 pNew->MakeFrms( &aNdIdx );
3286 //Zwischen die Tabellen wird ein Absatz geschoben
3287 GetNodes().MakeTxtNode( SwNodeIndex( *pNew ),
3288 GetTxtCollFromPool( RES_POOLCOLL_TEXT ) );
3291 //Layout updaten
3292 aFndBox.MakeFrms( rTbl );
3294 // TL_CHART2: need to inform chart of probably changed cell names
3295 UpdateCharts( rTbl.GetFrmFmt()->GetName() );
3297 SetFieldsDirty( true, NULL, 0 );
3299 return 0 != pNew;
3302 BOOL lcl_ChgTblSize( SwTable& rTbl )
3304 // das Attribut darf nicht ueber das Modify an der
3305 // Tabelle gesetzt werden, denn sonst werden alle
3306 // Boxen wieder auf 0 zurueck gesetzt. Also locke das Format
3307 SwFrmFmt* pFmt = rTbl.GetFrmFmt();
3308 SwFmtFrmSize aTblMaxSz( pFmt->GetFrmSize() );
3310 if( USHRT_MAX == aTblMaxSz.GetWidth() )
3311 return FALSE;
3313 BOOL bLocked = pFmt->IsModifyLocked();
3314 pFmt->LockModify();
3316 aTblMaxSz.SetWidth( 0 );
3318 SwTableLines& rLns = rTbl.GetTabLines();
3319 for( USHORT nLns = 0; nLns < rLns.Count(); ++nLns )
3321 SwTwips nMaxLnWidth = 0;
3322 SwTableBoxes& rBoxes = rLns[ nLns ]->GetTabBoxes();
3323 for( USHORT nBox = 0; nBox < rBoxes.Count(); ++nBox )
3324 nMaxLnWidth += rBoxes[nBox]->GetFrmFmt()->GetFrmSize().GetWidth();
3326 if( nMaxLnWidth > aTblMaxSz.GetWidth() )
3327 aTblMaxSz.SetWidth( nMaxLnWidth );
3329 pFmt->SetFmtAttr( aTblMaxSz );
3330 if( !bLocked ) // und gegebenenfalls Lock wieder freigeben
3331 pFmt->UnlockModify();
3333 return TRUE;
3336 class _SplitTable_Para
3338 SvPtrarr aSrc, aDest;
3339 SwTableNode* pNewTblNd;
3340 SwTable& rOldTbl;
3342 public:
3343 _SplitTable_Para( SwTableNode* pNew, SwTable& rOld )
3344 : aSrc( 16, 16 ), aDest( 16, 16 ), pNewTblNd( pNew ), rOldTbl( rOld )
3346 USHORT SrcFmt_GetPos( void* pFmt ) const
3347 { return aSrc.GetPos( pFmt ); }
3349 void DestFmt_Insert( void* pFmt )
3350 { aDest.Insert( pFmt, aDest.Count() ); }
3352 void SrcFmt_Insert( void* pFmt )
3353 { aSrc.Insert( pFmt, aSrc.Count() ); }
3355 SwFrmFmt* DestFmt_Get( USHORT nPos ) const
3356 { return (SwFrmFmt*)aDest[ nPos ]; }
3358 void ChgBox( SwTableBox* pBox )
3360 rOldTbl.GetTabSortBoxes().Remove( pBox );
3361 pNewTblNd->GetTable().GetTabSortBoxes().Insert( pBox );
3366 BOOL lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara );
3368 BOOL lcl_SplitTable_CpyLine( const SwTableLine*& rpLine, void* pPara )
3370 SwTableLine* pLn = (SwTableLine*)rpLine;
3371 _SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
3373 SwFrmFmt *pSrcFmt = pLn->GetFrmFmt();
3374 USHORT nPos = rPara.SrcFmt_GetPos( pSrcFmt );
3375 if( USHRT_MAX == nPos )
3377 rPara.DestFmt_Insert( pLn->ClaimFrmFmt() );
3378 rPara.SrcFmt_Insert( pSrcFmt );
3380 else
3381 pLn->ChgFrmFmt( (SwTableLineFmt*)rPara.DestFmt_Get( nPos ) );
3383 pLn->GetTabBoxes().ForEach( &lcl_SplitTable_CpyBox, pPara );
3384 return TRUE;
3387 BOOL lcl_SplitTable_CpyBox( const SwTableBox*& rpBox, void* pPara )
3389 SwTableBox* pBox = (SwTableBox*)rpBox;
3390 _SplitTable_Para& rPara = *(_SplitTable_Para*)pPara;
3392 SwFrmFmt *pSrcFmt = pBox->GetFrmFmt();
3393 USHORT nPos = rPara.SrcFmt_GetPos( pSrcFmt );
3394 if( USHRT_MAX == nPos )
3396 rPara.DestFmt_Insert( pBox->ClaimFrmFmt() );
3397 rPara.SrcFmt_Insert( pSrcFmt );
3399 else
3400 pBox->ChgFrmFmt( (SwTableBoxFmt*)rPara.DestFmt_Get( nPos ) );
3402 if( pBox->GetSttNd() )
3403 rPara.ChgBox( pBox );
3404 else
3405 pBox->GetTabLines().ForEach( &lcl_SplitTable_CpyLine, pPara );
3406 return TRUE;
3409 SwTableNode* SwNodes::SplitTable( const SwNodeIndex& rPos, BOOL bAfter,
3410 BOOL bCalcNewSize )
3412 SwNode* pNd = &rPos.GetNode();
3413 SwTableNode* pTNd = pNd->FindTableNode();
3414 if( !pTNd || pNd->IsTableNode() )
3415 return 0;
3417 ULONG nSttIdx = pNd->FindTableBoxStartNode()->GetIndex();
3419 // Suche die Grund-Line dieser Box:
3420 SwTable& rTbl = pTNd->GetTable();
3421 SwTableBox* pBox = rTbl.GetTblBox( nSttIdx );
3422 if( !pBox )
3423 return 0;
3425 SwTableLine* pLine = pBox->GetUpper();
3426 while( pLine->GetUpper() )
3427 pLine = pLine->GetUpper()->GetUpper();
3429 // in pLine steht jetzt die GrundLine.
3430 USHORT nLinePos = rTbl.GetTabLines().C40_GETPOS( SwTableLine, pLine );
3431 if( USHRT_MAX == nLinePos ||
3432 ( bAfter ? ++nLinePos >= rTbl.GetTabLines().Count() : !nLinePos ))
3433 return 0; // nicht gefunden oder letze Line !!
3435 // Suche jetzt die 1. Box der nachfolgenden Line
3436 SwTableLine* pNextLine = rTbl.GetTabLines()[ nLinePos ];
3437 pBox = pNextLine->GetTabBoxes()[0];
3438 while( !pBox->GetSttNd() )
3439 pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
3441 // dann fuege mal einen End- und TabelleNode ins Nodes-Array ein.
3442 SwTableNode * pNewTblNd;
3444 SwEndNode* pOldTblEndNd = (SwEndNode*)pTNd->EndOfSectionNode()->GetEndNode();
3445 ASSERT( pOldTblEndNd, "wo ist der EndNode?" )
3447 SwNodeIndex aIdx( *pBox->GetSttNd() );
3448 new SwEndNode( aIdx, *pTNd );
3449 pNewTblNd = new SwTableNode( aIdx );
3450 pNewTblNd->GetTable().SetTableModel( rTbl.IsNewModel() );
3452 pOldTblEndNd->pStartOfSection = pNewTblNd;
3453 pNewTblNd->pEndOfSection = pOldTblEndNd;
3455 SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
3456 do {
3457 ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
3458 pBoxNd->pStartOfSection = pNewTblNd;
3459 pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
3460 } while( pBoxNd != pOldTblEndNd );
3464 // die Lines ruebermoven...
3465 SwTable& rNewTbl = pNewTblNd->GetTable();
3466 rNewTbl.GetTabLines().Insert( &rTbl.GetTabLines(), 0, nLinePos );
3468 // von hinten (unten-rechts) nach vorn (oben-links) alle Boxen
3469 // beim chart data provider austragen (das modified event wird dann
3470 // in der aufrufenden Funktion getriggert.
3471 // TL_CHART2:
3472 SwChartDataProvider *pPCD = rTbl.GetFrmFmt()->getIDocumentChartDataProviderAccess()->GetChartDataProvider();
3473 if( pPCD )
3475 for (USHORT k = nLinePos; k < rTbl.GetTabLines().Count(); ++k)
3477 USHORT nLineIdx = (rTbl.GetTabLines().Count() - 1) - k + nLinePos;
3478 USHORT nBoxCnt = rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes().Count();
3479 for (USHORT j = 0; j < nBoxCnt; ++j)
3481 USHORT nIdx = nBoxCnt - 1 - j;
3482 pPCD->DeleteBox( &rTbl, *rTbl.GetTabLines()[ nLineIdx ]->GetTabBoxes()[nIdx] );
3487 // ...und loeschen
3488 USHORT nDeleted = rTbl.GetTabLines().Count() - nLinePos;
3489 rTbl.GetTabLines().Remove( nLinePos, nDeleted );
3491 // und die betr. Boxen verschieben. Dabei die Formate eindeutig
3492 // machen und die StartNodes korrigieren
3493 _SplitTable_Para aPara( pNewTblNd, rTbl );
3494 rNewTbl.GetTabLines().ForEach( &lcl_SplitTable_CpyLine, &aPara );
3495 rTbl.CleanUpBottomRowSpan( nDeleted );
3499 // Das Tabellen-FrmFormat kopieren
3500 SwFrmFmt* pOldTblFmt = rTbl.GetFrmFmt();
3501 SwFrmFmt* pNewTblFmt = pOldTblFmt->GetDoc()->MakeTblFrmFmt(
3502 pOldTblFmt->GetDoc()->GetUniqueTblName(),
3503 pOldTblFmt->GetDoc()->GetDfltFrmFmt() );
3505 *pNewTblFmt = *pOldTblFmt;
3506 pNewTblFmt->Add( &pNewTblNd->GetTable() );
3508 // neue Size errechnen ? (lcl_ChgTblSize nur das 2. aufrufen, wenn es
3509 // beim 1. schon geklappt hat; also absolute Groesse hat)
3510 if( bCalcNewSize && lcl_ChgTblSize( rTbl ) )
3511 lcl_ChgTblSize( pNewTblNd->GetTable() );
3514 // TL_CHART2: need to inform chart of probably changed cell names
3515 rTbl.UpdateCharts();
3517 return pNewTblNd; // das wars
3520 // und die Umkehrung davon. rPos muss in der Tabelle stehen, die bestehen
3521 // bleibt. Das Flag besagt ob die aktuelle mit der davor oder dahinter
3522 // stehenden vereint wird.
3523 BOOL SwDoc::MergeTable( const SwPosition& rPos, BOOL bWithPrev, USHORT nMode )
3525 SwTableNode* pTblNd = rPos.nNode.GetNode().FindTableNode(), *pDelTblNd;
3526 if( !pTblNd )
3527 return FALSE;
3529 SwNodes& rNds = GetNodes();
3530 if( bWithPrev )
3531 pDelTblNd = rNds[ pTblNd->GetIndex() - 1 ]->FindTableNode();
3532 else
3533 pDelTblNd = rNds[ pTblNd->EndOfSectionIndex() + 1 ]->GetTableNode();
3534 if( !pDelTblNd )
3535 return FALSE;
3537 if( pTblNd->GetTable().ISA( SwDDETable ) ||
3538 pDelTblNd->GetTable().ISA( SwDDETable ))
3539 return FALSE;
3541 // MIB 9.7.97: HTML-Layout loeschen
3542 pTblNd->GetTable().SetHTMLTableLayout( 0 );
3543 pDelTblNd->GetTable().SetHTMLTableLayout( 0 );
3545 // beide Tabellen vorhanden, also kanns losgehen
3546 SwUndoMergeTbl* pUndo = 0;
3547 SwHistory* pHistory = 0;
3548 if( DoesUndo() )
3550 ClearRedo();
3551 AppendUndo( pUndo = new SwUndoMergeTbl( *pTblNd, *pDelTblNd,
3552 bWithPrev, nMode ));
3553 pHistory = new SwHistory;
3556 // alle "Tabellenformeln" anpassen
3557 SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
3558 aMsgHnt.DATA.pDelTbl = &pDelTblNd->GetTable();
3559 aMsgHnt.eFlags = TBL_MERGETBL;
3560 aMsgHnt.pHistory = pHistory;
3561 UpdateTblFlds( &aMsgHnt );
3563 // das eigentliche Mergen
3564 SwNodeIndex aIdx( bWithPrev ? *pTblNd : *pDelTblNd );
3565 BOOL bRet = rNds.MergeTable( aIdx, !bWithPrev, nMode, pHistory );
3567 if( pHistory )
3569 if( pHistory->Count() )
3570 pUndo->SaveFormula( *pHistory );
3571 delete pHistory;
3573 if( bRet )
3575 SetModified();
3576 SetFieldsDirty( true, NULL, 0 );
3578 return bRet;
3581 BOOL SwNodes::MergeTable( const SwNodeIndex& rPos, BOOL bWithPrev,
3582 USHORT nMode, SwHistory* )
3584 SwTableNode* pDelTblNd = rPos.GetNode().GetTableNode();
3585 ASSERT( pDelTblNd, "wo ist der TableNode geblieben?" );
3587 SwTableNode* pTblNd = (*this)[ rPos.GetIndex() - 1]->FindTableNode();
3588 ASSERT( pTblNd, "wo ist der TableNode geblieben?" );
3590 if( !pDelTblNd || !pTblNd )
3591 return FALSE;
3593 pDelTblNd->DelFrms();
3595 SwTable& rDelTbl = pDelTblNd->GetTable();
3596 SwTable& rTbl = pTblNd->GetTable();
3598 //Lines fuer das Layout-Update herausuchen.
3599 _FndBox aFndBox( 0, 0 );
3600 aFndBox.SetTableLines( rTbl );
3601 aFndBox.DelFrms( rTbl );
3603 // TL_CHART2: since chart currently does not want to get informed about
3604 // additional rows/cols there is no need for a modified event in the
3605 // remaining first table. Also, if it is required it should be done
3606 // after the merging and not here...
3607 // pDoc->UpdateCharts( rTbl.GetFrmFmt()->GetName() );
3610 // TL_CHART2:
3611 // tell the charts about the table to be deleted and have them use their own data
3612 GetDoc()->CreateChartInternalDataProviders( &rDelTbl );
3614 // die Breite der TabellenFormate abgleichen:
3616 const SwFmtFrmSize& rTblSz = rTbl.GetFrmFmt()->GetFrmSize();
3617 const SwFmtFrmSize& rDelTblSz = rDelTbl.GetFrmFmt()->GetFrmSize();
3618 if( rTblSz != rDelTblSz )
3620 // dann sollten die mal schleunigst korrigiert werden
3621 if( bWithPrev )
3622 rDelTbl.GetFrmFmt()->SetFmtAttr( rTblSz );
3623 else
3624 rTbl.GetFrmFmt()->SetFmtAttr( rDelTblSz );
3628 if( !bWithPrev )
3630 // dann mussen alle Attruibute der hinteren Tabelle auf die
3631 // vordere uebertragen werden, weil die hintere ueber das loeschen
3632 // des Node geloescht wird.
3633 rTbl.SetRowsToRepeat( rDelTbl.GetRowsToRepeat() );
3634 rTbl.SetTblChgMode( rDelTbl.GetTblChgMode() );
3636 rTbl.GetFrmFmt()->LockModify();
3637 *rTbl.GetFrmFmt() = *rDelTbl.GetFrmFmt();
3638 // auch den Namen umsetzen!
3639 rTbl.GetFrmFmt()->SetName( rDelTbl.GetFrmFmt()->GetName() );
3640 rTbl.GetFrmFmt()->UnlockModify();
3643 // die Lines und Boxen ruebermoven
3644 USHORT nOldSize = rTbl.GetTabLines().Count();
3645 rTbl.GetTabLines().Insert( &rDelTbl.GetTabLines(), nOldSize );
3646 rDelTbl.GetTabLines().Remove( 0, rDelTbl.GetTabLines().Count() );
3648 rTbl.GetTabSortBoxes().Insert( &rDelTbl.GetTabSortBoxes() );
3649 rDelTbl.GetTabSortBoxes().Remove( (USHORT)0, rDelTbl.GetTabSortBoxes().Count() );
3651 // die vordere Tabelle bleibt immer stehen, die hintere wird geloescht
3652 SwEndNode* pTblEndNd = pDelTblNd->EndOfSectionNode();
3653 pTblNd->pEndOfSection = pTblEndNd;
3655 SwNodeIndex aIdx( *pDelTblNd, 1 );
3657 SwNode* pBoxNd = aIdx.GetNode().GetStartNode();
3658 do {
3659 ASSERT( pBoxNd->IsStartNode(), "das muss ein StartNode sein!" );
3660 pBoxNd->pStartOfSection = pTblNd;
3661 pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
3662 } while( pBoxNd != pTblEndNd );
3663 pBoxNd->pStartOfSection = pTblNd;
3665 aIdx -= 2;
3666 DelNodes( aIdx, 2 );
3668 // jetzt an der 1. eingefuegten Line die bedingten Vorlagen umschubsen
3669 const SwTableLine* pFirstLn = rTbl.GetTabLines()[ nOldSize ];
3670 if( 1 == nMode ) //
3672 // Header-Vorlagen in der Zeile setzen
3673 // und ggfs. in der History speichern fuers Undo!!!
3675 lcl_LineSetHeadCondColl( pFirstLn, 0 );
3677 // und die Borders "aufrauemen"
3678 if( nOldSize )
3680 _SwGCLineBorder aPara( rTbl );
3681 aPara.nLinePos = --nOldSize;
3682 pFirstLn = rTbl.GetTabLines()[ nOldSize ];
3683 lcl_GC_Line_Border( pFirstLn, &aPara );
3686 //Layout updaten
3687 aFndBox.MakeFrms( rTbl );
3689 return TRUE;
3692 // -------------------------------------------------------------------
3695 // -- benutze die ForEach Methode vom PtrArray
3696 struct _SetAFmtTabPara
3698 SwTableAutoFmt& rTblFmt;
3699 SwUndoTblAutoFmt* pUndo;
3700 USHORT nEndBox, nCurBox;
3701 BYTE nAFmtLine, nAFmtBox;
3703 _SetAFmtTabPara( const SwTableAutoFmt& rNew )
3704 : rTblFmt( (SwTableAutoFmt&)rNew ), pUndo( 0 ),
3705 nEndBox( 0 ), nCurBox( 0 ), nAFmtLine( 0 ), nAFmtBox( 0 )
3709 // forward deklarieren damit sich die Lines und Boxen rekursiv aufrufen
3710 // koennen.
3711 BOOL lcl_SetAFmtBox( const _FndBox*&, void *pPara );
3712 BOOL lcl_SetAFmtLine( const _FndLine*&, void *pPara );
3714 BOOL lcl_SetAFmtLine( const _FndLine*& rpLine, void *pPara )
3716 ((_FndLine*&)rpLine)->GetBoxes().ForEach( &lcl_SetAFmtBox, pPara );
3717 return TRUE;
3720 BOOL lcl_SetAFmtBox( const _FndBox*& rpBox, void *pPara )
3722 _SetAFmtTabPara* pSetPara = (_SetAFmtTabPara*)pPara;
3724 if( !rpBox->GetUpper()->GetUpper() ) // Box auf 1. Ebene ?
3726 if( !pSetPara->nCurBox )
3727 pSetPara->nAFmtBox = 0;
3728 else if( pSetPara->nCurBox == pSetPara->nEndBox )
3729 pSetPara->nAFmtBox = 3;
3730 else
3731 pSetPara->nAFmtBox = (BYTE)(1 + ((pSetPara->nCurBox-1) & 1));
3734 if( rpBox->GetBox()->GetSttNd() )
3736 SwTableBox* pSetBox = (SwTableBox*)rpBox->GetBox();
3737 SwDoc* pDoc = pSetBox->GetFrmFmt()->GetDoc();
3738 // --> OD 2008-02-25 #refactorlists#
3739 // SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_END-1 );
3740 SfxItemSet aCharSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_PARATR_LIST_END-1 );
3741 // <--
3742 SfxItemSet aBoxSet( pDoc->GetAttrPool(), aTableBoxSetRange );
3743 BYTE nPos = pSetPara->nAFmtLine * 4 + pSetPara->nAFmtBox;
3744 pSetPara->rTblFmt.UpdateToSet( nPos, aCharSet,
3745 SwTableAutoFmt::UPDATE_CHAR, 0 );
3746 pSetPara->rTblFmt.UpdateToSet( nPos, aBoxSet,
3747 SwTableAutoFmt::UPDATE_BOX,
3748 pDoc->GetNumberFormatter( TRUE ) );
3749 if( aCharSet.Count() )
3751 ULONG nSttNd = pSetBox->GetSttIdx()+1;
3752 ULONG nEndNd = pSetBox->GetSttNd()->EndOfSectionIndex();
3753 for( ; nSttNd < nEndNd; ++nSttNd )
3755 SwCntntNode* pNd = pDoc->GetNodes()[ nSttNd ]->GetCntntNode();
3756 if( pNd )
3757 pNd->SetAttr( aCharSet );
3761 if( aBoxSet.Count() )
3763 if( pSetPara->pUndo &&
3764 SFX_ITEM_SET == aBoxSet.GetItemState( RES_BOXATR_FORMAT ))
3765 pSetPara->pUndo->SaveBoxCntnt( *pSetBox );
3767 pSetBox->ClaimFrmFmt()->SetFmtAttr( aBoxSet );
3770 else
3771 ((_FndBox*&)rpBox)->GetLines().ForEach( &lcl_SetAFmtLine, pPara );
3773 if( !rpBox->GetUpper()->GetUpper() ) // eine BaseLine
3774 ++pSetPara->nCurBox;
3775 return TRUE;
3779 // AutoFormat fuer die Tabelle/TabellenSelection
3780 BOOL SwDoc::SetTableAutoFmt( const SwSelBoxes& rBoxes, const SwTableAutoFmt& rNew )
3782 ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
3783 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
3784 if( !pTblNd )
3785 return FALSE;
3787 // suche alle Boxen / Lines
3788 _FndBox aFndBox( 0, 0 );
3790 _FndPara aPara( rBoxes, &aFndBox );
3791 pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
3793 if( !aFndBox.GetLines().Count() )
3794 return FALSE;
3796 pTblNd->GetTable().SetHTMLTableLayout( 0 );
3798 _FndBox* pFndBox = &aFndBox;
3799 while( 1 == pFndBox->GetLines().Count() &&
3800 1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
3801 pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
3803 if( !pFndBox->GetLines().Count() ) // eine zu weit? (nur 1 sel.Box)
3804 pFndBox = pFndBox->GetUpper()->GetUpper();
3807 // Undo abschalten, Attribute werden sich vorher gemerkt
3808 SwUndoTblAutoFmt* pUndo = 0;
3809 if( DoesUndo() )
3811 ClearRedo();
3812 AppendUndo( pUndo = new SwUndoTblAutoFmt( *pTblNd, rNew ) );
3813 DoUndo( FALSE );
3816 _SetAFmtTabPara aPara( rNew );
3817 _FndLines& rFLns = pFndBox->GetLines();
3818 _FndLine* pLine;
3820 for( USHORT n = 0; n < rFLns.Count(); ++n )
3822 pLine = rFLns[n];
3824 // Upper auf 0 setzen (Base-Line simulieren!)
3825 _FndBox* pSaveBox = pLine->GetUpper();
3826 pLine->SetUpper( 0 );
3828 if( !n )
3829 aPara.nAFmtLine = 0;
3830 else if( n+1 == rFLns.Count() )
3831 aPara.nAFmtLine = 3;
3832 else
3833 aPara.nAFmtLine = (BYTE)(1 + ((n-1) & 1 ));
3835 aPara.nAFmtBox = 0;
3836 aPara.nCurBox = 0;
3837 aPara.nEndBox = pLine->GetBoxes().Count()-1;
3838 aPara.pUndo = pUndo;
3839 pLine->GetBoxes().ForEach( &lcl_SetAFmtBox, &aPara );
3841 pLine->SetUpper( pSaveBox );
3844 if( pUndo )
3845 DoUndo( TRUE );
3847 SetModified();
3848 SetFieldsDirty( true, NULL, 0 );
3850 return TRUE;
3854 // Erfrage wie attributiert ist
3855 BOOL SwDoc::GetTableAutoFmt( const SwSelBoxes& rBoxes, SwTableAutoFmt& rGet )
3857 ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
3858 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
3859 if( !pTblNd )
3860 return FALSE;
3862 // suche alle Boxen / Lines
3863 _FndBox aFndBox( 0, 0 );
3865 _FndPara aPara( rBoxes, &aFndBox );
3866 pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
3868 if( !aFndBox.GetLines().Count() )
3869 return FALSE;
3871 _FndBox* pFndBox = &aFndBox;
3872 while( 1 == pFndBox->GetLines().Count() &&
3873 1 == pFndBox->GetLines()[0]->GetBoxes().Count() )
3874 pFndBox = pFndBox->GetLines()[0]->GetBoxes()[0];
3876 if( !pFndBox->GetLines().Count() ) // eine zu weit? (nur 1 sel.Box)
3877 pFndBox = pFndBox->GetUpper()->GetUpper();
3879 _FndLines& rFLns = pFndBox->GetLines();
3881 USHORT aLnArr[4];
3882 aLnArr[0] = 0;
3883 aLnArr[1] = 1 < rFLns.Count() ? 1 : 0;
3884 aLnArr[2] = 2 < rFLns.Count() ? 2 : aLnArr[1];
3885 aLnArr[3] = rFLns.Count() - 1;
3887 for( BYTE nLine = 0; nLine < 4; ++nLine )
3889 _FndLine& rLine = *rFLns[ aLnArr[ nLine ] ];
3891 USHORT aBoxArr[4];
3892 aBoxArr[0] = 0;
3893 aBoxArr[1] = 1 < rLine.GetBoxes().Count() ? 1 : 0;
3894 aBoxArr[2] = 2 < rLine.GetBoxes().Count() ? 2 : aBoxArr[1];
3895 aBoxArr[3] = rLine.GetBoxes().Count() - 1;
3897 for( BYTE nBox = 0; nBox < 4; ++nBox )
3899 SwTableBox* pFBox = rLine.GetBoxes()[ aBoxArr[ nBox ] ]->GetBox();
3900 // immer auf die 1. runterfallen
3901 while( !pFBox->GetSttNd() )
3902 pFBox = pFBox->GetTabLines()[0]->GetTabBoxes()[0];
3904 BYTE nPos = nLine * 4 + nBox;
3905 SwNodeIndex aIdx( *pFBox->GetSttNd(), 1 );
3906 SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
3907 if( !pCNd )
3908 pCNd = GetNodes().GoNext( &aIdx );
3910 if( pCNd )
3911 rGet.UpdateFromSet( nPos, pCNd->GetSwAttrSet(),
3912 SwTableAutoFmt::UPDATE_CHAR, 0 );
3913 rGet.UpdateFromSet( nPos, pFBox->GetFrmFmt()->GetAttrSet(),
3914 SwTableAutoFmt::UPDATE_BOX,
3915 GetNumberFormatter( TRUE ) );
3919 return TRUE;
3922 String SwDoc::GetUniqueTblName() const
3924 ResId aId( STR_TABLE_DEFNAME, *pSwResMgr );
3925 String aName( aId );
3926 xub_StrLen nNmLen = aName.Len();
3928 USHORT nNum, nTmp, nFlagSize = ( pTblFrmFmtTbl->Count() / 8 ) +2;
3929 USHORT n;
3931 BYTE* pSetFlags = new BYTE[ nFlagSize ];
3932 memset( pSetFlags, 0, nFlagSize );
3934 for( n = 0; n < pTblFrmFmtTbl->Count(); ++n )
3936 const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
3937 if( !pFmt->IsDefault() && IsUsed( *pFmt ) &&
3938 pFmt->GetName().Match( aName ) == nNmLen )
3940 // Nummer bestimmen und das Flag setzen
3941 nNum = static_cast<USHORT>(pFmt->GetName().Copy( nNmLen ).ToInt32());
3942 if( nNum-- && nNum < pTblFrmFmtTbl->Count() )
3943 pSetFlags[ nNum / 8 ] |= (0x01 << ( nNum & 0x07 ));
3947 // alle Nummern entsprechend geflag, also bestimme die richtige Nummer
3948 nNum = pTblFrmFmtTbl->Count();
3949 for( n = 0; n < nFlagSize; ++n )
3950 if( 0xff != ( nTmp = pSetFlags[ n ] ))
3952 // also die Nummer bestimmen
3953 nNum = n * 8;
3954 while( nTmp & 1 )
3955 ++nNum, nTmp >>= 1;
3956 break;
3959 delete [] pSetFlags;
3960 return aName += String::CreateFromInt32( ++nNum );
3963 SwTableFmt* SwDoc::FindTblFmtByName( const String& rName, BOOL bAll ) const
3965 const SwFmt* pRet = 0;
3966 if( bAll )
3967 pRet = FindFmtByName( (SvPtrarr&)*pTblFrmFmtTbl, rName );
3968 else
3970 // dann nur die, die im Doc gesetzt sind
3971 for( USHORT n = 0; n < pTblFrmFmtTbl->Count(); ++n )
3973 const SwFrmFmt* pFmt = (*pTblFrmFmtTbl)[ n ];
3974 if( !pFmt->IsDefault() && IsUsed( *pFmt ) &&
3975 pFmt->GetName() == rName )
3977 pRet = pFmt;
3978 break;
3982 return (SwTableFmt*)pRet;
3985 BOOL SwDoc::SetColRowWidthHeight( SwTableBox& rAktBox, USHORT eType,
3986 SwTwips nAbsDiff, SwTwips nRelDiff )
3988 SwTableNode* pTblNd = (SwTableNode*)rAktBox.GetSttNd()->FindTableNode();
3989 SwUndo* pUndo = 0;
3991 if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType && pTblNd->GetTable().ISA( SwDDETable ))
3992 return FALSE;
3994 SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
3995 aMsgHnt.eFlags = TBL_BOXPTR;
3996 UpdateTblFlds( &aMsgHnt );
3998 BOOL bRet = FALSE;
3999 switch( eType & 0xff )
4001 case nsTblChgWidthHeightType::WH_COL_LEFT:
4002 case nsTblChgWidthHeightType::WH_COL_RIGHT:
4003 case nsTblChgWidthHeightType::WH_CELL_LEFT:
4004 case nsTblChgWidthHeightType::WH_CELL_RIGHT:
4006 bRet = pTblNd->GetTable().SetColWidth( rAktBox,
4007 eType, nAbsDiff, nRelDiff,
4008 DoesUndo() ? &pUndo : 0 );
4010 break;
4011 case nsTblChgWidthHeightType::WH_ROW_TOP:
4012 case nsTblChgWidthHeightType::WH_ROW_BOTTOM:
4013 case nsTblChgWidthHeightType::WH_CELL_TOP:
4014 case nsTblChgWidthHeightType::WH_CELL_BOTTOM:
4015 bRet = pTblNd->GetTable().SetRowHeight( rAktBox,
4016 eType, nAbsDiff, nRelDiff,
4017 DoesUndo() ? &pUndo : 0 );
4018 break;
4021 if( pUndo )
4023 ClearRedo();
4024 AppendUndo( pUndo );
4025 DoUndo( TRUE ); // im SetColWidth kann es abgeschaltet werden!
4028 if( bRet )
4030 SetModified();
4031 if( nsTblChgWidthHeightType::WH_FLAG_INSDEL & eType )
4032 SetFieldsDirty( true, NULL, 0 );
4034 return bRet;
4038 void SwDoc::ChkBoxNumFmt( SwTableBox& rBox, BOOL bCallUpdate )
4040 //JP 09.07.97: Optimierung: wenn die Box schon sagt, das es Text
4041 // sein soll, dann bleibt das auch Text!
4042 const SfxPoolItem* pNumFmtItem = 0;
4043 if( SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT,
4044 FALSE, &pNumFmtItem ) && GetNumberFormatter()->IsTextFormat(
4045 ((SwTblBoxNumFormat*)pNumFmtItem)->GetValue() ))
4046 return ;
4048 SwUndoTblNumFmt* pUndo = 0;
4050 BOOL bIsEmptyTxtNd, bChgd = TRUE;
4051 sal_uInt32 nFmtIdx;
4052 double fNumber;
4053 if( rBox.HasNumCntnt( fNumber, nFmtIdx, bIsEmptyTxtNd ) )
4055 if( !rBox.IsNumberChanged() )
4056 bChgd = FALSE;
4057 else
4059 if( DoesUndo() )
4061 StartUndo( UNDO_TABLE_AUTOFMT, NULL );
4062 pUndo = new SwUndoTblNumFmt( rBox );
4063 pUndo->SetNumFmt( nFmtIdx, fNumber );
4066 SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
4067 SfxItemSet aBoxSet( GetAttrPool(), RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
4069 BOOL bSetNumFmt = IsInsTblFormatNum(), bLockModify = TRUE;
4070 if( bSetNumFmt )
4072 if( !IsInsTblChangeNumFormat() )
4074 if( !pNumFmtItem )
4075 bSetNumFmt = FALSE;
4076 else
4078 ULONG nOldNumFmt = ((SwTblBoxNumFormat*)pNumFmtItem)->
4079 GetValue();
4080 SvNumberFormatter* pNumFmtr = GetNumberFormatter();
4082 short nFmtType = pNumFmtr->GetType( nFmtIdx );
4083 if( nFmtType == pNumFmtr->GetType( nOldNumFmt ) ||
4084 NUMBERFORMAT_NUMBER == nFmtType )
4085 // eingstelltes und vorgegebenes NumFormat
4086 // stimmen ueberein -> altes Format beibehalten
4087 nFmtIdx = nOldNumFmt;
4088 else
4089 // eingstelltes und vorgegebenes NumFormat
4090 // stimmen nicht ueberein -> als Text einfuegen
4091 bLockModify = bSetNumFmt = FALSE;
4095 if( bSetNumFmt )
4097 pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
4099 aBoxSet.Put( SwTblBoxValue( fNumber ));
4100 aBoxSet.Put( SwTblBoxNumFormat( nFmtIdx ));
4104 // JP 28.04.98: Nur Formel zuruecksetzen reicht nicht.
4105 // Sorge dafuer, das der Text auch entsprechend
4106 // formatiert wird!
4108 if( !bSetNumFmt && !bIsEmptyTxtNd && pNumFmtItem )
4110 // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
4111 // Sorge dafuer, das der Text auch entsprechend
4112 // formatiert wird!
4113 pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
4116 if( bLockModify ) pBoxFmt->LockModify();
4117 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE );
4118 if( bLockModify ) pBoxFmt->UnlockModify();
4120 if( bSetNumFmt )
4121 pBoxFmt->SetFmtAttr( aBoxSet );
4124 else
4126 // es ist keine Zahl
4127 const SfxPoolItem* pValueItem = 0, *pFmtItem = 0;
4128 SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rBox.GetFrmFmt();
4129 if( SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_FORMAT,
4130 FALSE, &pFmtItem ) ||
4131 SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_VALUE,
4132 FALSE, &pValueItem ))
4134 if( DoesUndo() )
4136 StartUndo( UNDO_TABLE_AUTOFMT, NULL );
4137 pUndo = new SwUndoTblNumFmt( rBox );
4140 pBoxFmt = (SwTableBoxFmt*)rBox.ClaimFrmFmt();
4142 // alle Zahlenformate entfernen
4143 USHORT nWhich1 = RES_BOXATR_FORMULA;
4144 if( !bIsEmptyTxtNd )
4145 //JP 15.01.99: dieser Teil wurde doch schon oben abgeprueft!
4146 /* && pFmtItem && !GetNumberFormatter()->
4147 IsTextFormat( ((SwTblBoxNumFormat*)pFmtItem)->GetValue() ) )*/
4149 nWhich1 = RES_BOXATR_FORMAT;
4151 // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
4152 // Sorge dafuer, das der Text auch entsprechend
4153 // formatiert wird!
4154 pBoxFmt->SetFmtAttr( *GetDfltAttr( nWhich1 ));
4156 pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
4158 else
4159 bChgd = FALSE;
4162 if( bChgd )
4164 if( pUndo )
4166 pUndo->SetBox( rBox );
4167 AppendUndo( pUndo );
4168 EndUndo( UNDO_END, NULL );
4171 const SwTableNode* pTblNd = rBox.GetSttNd()->FindTableNode();
4172 if( bCallUpdate )
4174 SwTableFmlUpdate aTblUpdate( &pTblNd->GetTable() );
4175 UpdateTblFlds( &aTblUpdate );
4177 // TL_CHART2: update charts (when cursor leaves cell and
4178 // automatic update is enabled)
4179 if (AUTOUPD_FIELD_AND_CHARTS == getFieldUpdateFlags(true))
4180 pTblNd->GetTable().UpdateCharts();
4182 SetModified();
4186 void SwDoc::SetTblBoxFormulaAttrs( SwTableBox& rBox, const SfxItemSet& rSet )
4188 if( DoesUndo() )
4190 ClearRedo();
4191 AppendUndo( new SwUndoTblNumFmt( rBox, &rSet ) );
4194 SwFrmFmt* pBoxFmt = rBox.ClaimFrmFmt();
4195 if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA ))
4197 pBoxFmt->LockModify();
4198 pBoxFmt->ResetFmtAttr( RES_BOXATR_VALUE );
4199 pBoxFmt->UnlockModify();
4201 else if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE ))
4203 pBoxFmt->LockModify();
4204 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMULA );
4205 pBoxFmt->UnlockModify();
4207 pBoxFmt->SetFmtAttr( rSet );
4208 SetModified();
4211 void SwDoc::ClearLineNumAttrs( SwPosition & rPos )
4213 SwPaM aPam(rPos);
4214 aPam.Move(fnMoveBackward);
4215 SwCntntNode *pNode = aPam.GetCntntNode();
4216 if ( 0 == pNode )
4217 return ;
4218 if( pNode->IsTxtNode() )
4220 SwTxtNode * pTxtNode = pNode->GetTxtNode();
4221 if ( pTxtNode && pTxtNode->IsNumbered() && pTxtNode->GetTxt().Len()==0 )
4223 const SfxPoolItem* pFmtItem = 0;
4224 SfxItemSet rSet( const_cast<SwAttrPool&>(pTxtNode->GetDoc()->GetAttrPool()),
4225 RES_PARATR_BEGIN, RES_PARATR_END - 1,
4227 pTxtNode->SwCntntNode::GetAttr( rSet );
4228 if ( SFX_ITEM_SET == rSet.GetItemState( RES_PARATR_NUMRULE , FALSE , &pFmtItem ) )
4230 SwUndoDelNum * pUndo;
4231 if( DoesUndo() )
4233 ClearRedo();
4234 AppendUndo( pUndo = new SwUndoDelNum( aPam ) );
4236 else
4237 pUndo = 0;
4238 SwRegHistory aRegH( pUndo ? pUndo->GetHistory() : 0 );
4239 aRegH.RegisterInModify( pTxtNode , *pTxtNode );
4240 if ( pUndo )
4241 pUndo->AddNode( *pTxtNode , FALSE );
4242 String aStyle = String::CreateFromAscii("");
4243 SfxStringItem * pNewItem = (SfxStringItem*)pFmtItem->Clone();
4244 pNewItem->SetValue( aStyle );
4245 rSet.Put( *pNewItem );
4246 pTxtNode->SetAttr( rSet );
4247 delete pNewItem;
4253 void SwDoc::ClearBoxNumAttrs( const SwNodeIndex& rNode )
4255 SwStartNode* pSttNd;
4256 if( 0 != ( pSttNd = GetNodes()[ rNode ]->
4257 FindSttNodeByType( SwTableBoxStartNode )) &&
4258 2 == pSttNd->EndOfSectionIndex() - pSttNd->GetIndex() )
4260 SwTableBox* pBox = pSttNd->FindTableNode()->GetTable().
4261 GetTblBox( pSttNd->GetIndex() );
4263 const SfxPoolItem* pFmtItem = 0;
4264 const SfxItemSet& rSet = pBox->GetFrmFmt()->GetAttrSet();
4265 if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT, FALSE, &pFmtItem ) ||
4266 SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA, FALSE ) ||
4267 SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE, FALSE ))
4269 if( DoesUndo() )
4271 ClearRedo();
4272 AppendUndo( new SwUndoTblNumFmt( *pBox ) );
4275 SwFrmFmt* pBoxFmt = pBox->ClaimFrmFmt();
4277 //JP 01.09.97: TextFormate bleiben erhalten!
4278 USHORT nWhich1 = RES_BOXATR_FORMAT;
4279 if( pFmtItem && GetNumberFormatter()->IsTextFormat(
4280 ((SwTblBoxNumFormat*)pFmtItem)->GetValue() ))
4281 nWhich1 = RES_BOXATR_FORMULA;
4282 else
4283 // JP 15.01.99: Nur Attribute zuruecksetzen reicht nicht.
4284 // Sorge dafuer, das der Text auch entsprechend
4285 // formatiert wird!
4286 pBoxFmt->SetFmtAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
4288 pBoxFmt->ResetFmtAttr( nWhich1, RES_BOXATR_VALUE );
4289 SetModified();
4294 // kopiert eine Tabelle aus dem selben oder einem anderen Doc in sich
4295 // selbst. Dabei wird eine neue Tabelle angelegt oder eine bestehende
4296 // mit dem Inhalt gefuellt; wobei entweder der Inhalt ab einer Box oder
4297 // in eine bestehende TblSelektion gefuellt wird.
4298 // Gerufen wird es von: edglss.cxx/fecopy.cxx
4300 BOOL SwDoc::InsCopyOfTbl( SwPosition& rInsPos, const SwSelBoxes& rBoxes,
4301 const SwTable* pCpyTbl, BOOL bCpyName, BOOL bCorrPos )
4303 BOOL bRet;
4305 const SwTableNode* pSrcTblNd = pCpyTbl
4306 ? pCpyTbl->GetTableNode()
4307 : rBoxes[ 0 ]->GetSttNd()->FindTableNode();
4309 SwTableNode* pInsTblNd = GetNodes()[ rInsPos.nNode ]->FindTableNode();
4311 if( !pCpyTbl && !pInsTblNd )
4313 SwUndoCpyTbl* pUndo = 0;
4314 if( DoesUndo() )
4316 ClearRedo();
4317 pUndo = new SwUndoCpyTbl;
4318 DoUndo( FALSE );
4321 bRet = pSrcTblNd->GetTable().MakeCopy( this, rInsPos, rBoxes,
4322 TRUE, bCpyName );
4323 if( pUndo )
4325 if( !bRet )
4326 delete pUndo;
4327 else
4329 pInsTblNd = GetNodes()[ rInsPos.nNode.GetIndex() - 1 ]->FindTableNode();
4331 pUndo->SetTableSttIdx( pInsTblNd->GetIndex() );
4332 AppendUndo( pUndo );
4334 DoUndo( TRUE );
4337 else
4339 RedlineMode_t eOld = GetRedlineMode();
4340 if( IsRedlineOn() )
4341 SetRedlineMode( (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON |
4342 nsRedlineMode_t::REDLINE_SHOW_INSERT |
4343 nsRedlineMode_t::REDLINE_SHOW_DELETE));
4345 SwUndoTblCpyTbl* pUndo = 0;
4346 if( DoesUndo() )
4348 ClearRedo();
4349 pUndo = new SwUndoTblCpyTbl;
4350 DoUndo( FALSE );
4353 SwDoc* pCpyDoc = (SwDoc*)pSrcTblNd->GetDoc();
4354 SfxObjectShellRef* pRefForDocSh = 0;
4355 BOOL bDelCpyDoc = pCpyDoc == this;
4357 if( bDelCpyDoc )
4359 // kopiere die Tabelle erstmal in ein temp. Doc
4360 pCpyDoc = new SwDoc;
4361 pCpyDoc->acquire();
4362 pRefForDocSh = new SfxObjectShellRef();
4363 pCpyDoc->SetRefForDocShell( pRefForDocSh );
4365 SwPosition aPos( SwNodeIndex( pCpyDoc->GetNodes().GetEndOfContent() ));
4366 if( !pSrcTblNd->GetTable().MakeCopy( pCpyDoc, aPos, rBoxes, TRUE, TRUE ))
4368 delete pRefForDocSh;
4369 if( pCpyDoc->release() == 0 )
4370 delete pCpyDoc;
4372 if( pUndo )
4374 DoUndo( TRUE );
4375 delete pUndo;
4377 return FALSE;
4379 aPos.nNode -= 1; // auf den EndNode der Tabelle
4380 pSrcTblNd = aPos.nNode.GetNode().FindTableNode();
4382 pCpyDoc->SetRefForDocShell( NULL );
4385 const SwStartNode* pSttNd = rInsPos.nNode.GetNode().FindTableBoxStartNode();
4387 rInsPos.nContent.Assign( 0, 0 );
4389 // no complex into complex, but copy into or from new model is welcome
4390 if( ( !pSrcTblNd->GetTable().IsTblComplex() || pInsTblNd->GetTable().IsNewModel() )
4391 && ( bDelCpyDoc || rBoxes.Count() ) )
4393 // dann die Tabelle "relativ" kopieren
4394 const SwSelBoxes* pBoxes;
4395 SwSelBoxes aBoxes;
4397 if( bDelCpyDoc )
4399 SwTableBox* pBox = pInsTblNd->GetTable().GetTblBox(
4400 pSttNd->GetIndex() );
4401 ASSERT( pBox, "Box steht nicht in dieser Tabelle" );
4402 aBoxes.Insert( pBox );
4403 pBoxes = &aBoxes;
4405 else
4406 pBoxes = &rBoxes;
4408 // kopiere die Tabelle in die selktierten Zellen.
4409 bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
4410 *pBoxes, pUndo );
4412 else
4414 SwNodeIndex aNdIdx( *pSttNd, 1 );
4415 bRet = pInsTblNd->GetTable().InsTable( pSrcTblNd->GetTable(),
4416 aNdIdx, pUndo );
4419 if( bDelCpyDoc )
4421 delete pRefForDocSh;
4422 if( pCpyDoc->release() == 0 )
4423 delete pCpyDoc;
4426 if( pUndo )
4428 // falls die Tabelle nicht kopiert werden konnte, das Undo-Object
4429 // wieder loeschen
4430 if( !bRet && pUndo->IsEmpty() )
4431 delete pUndo;
4432 else
4433 AppendUndo( pUndo );
4434 DoUndo( TRUE );
4437 if( bCorrPos )
4439 rInsPos.nNode = *pSttNd;
4440 rInsPos.nContent.Assign( GetNodes().GoNext( &rInsPos.nNode ), 0 );
4442 SetRedlineMode( eOld );
4445 if( bRet )
4447 SetModified();
4448 SetFieldsDirty( true, NULL, 0 );
4450 return bRet;
4455 BOOL SwDoc::_UnProtectTblCells( SwTable& rTbl )
4457 BOOL bChgd = FALSE;
4458 SwUndoAttrTbl* pUndo = DoesUndo() ? new SwUndoAttrTbl( *rTbl.GetTableNode() )
4459 : 0;
4461 SwTableSortBoxes& rSrtBox = rTbl.GetTabSortBoxes();
4462 for( USHORT i = rSrtBox.Count(); i; )
4464 SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
4465 if( pBoxFmt->GetProtect().IsCntntProtected() )
4467 pBoxFmt->ResetFmtAttr( RES_PROTECT );
4468 bChgd = TRUE;
4472 if( pUndo )
4474 if( bChgd )
4476 ClearRedo();
4477 AppendUndo( pUndo );
4479 else
4480 delete pUndo;
4482 return bChgd;
4486 BOOL SwDoc::UnProtectCells( const String& rName )
4488 BOOL bChgd = FALSE;
4489 SwTableFmt* pFmt = FindTblFmtByName( rName );
4490 if( pFmt )
4492 bChgd = _UnProtectTblCells( *SwTable::FindTable( pFmt ) );
4493 if( bChgd )
4494 SetModified();
4497 return bChgd;
4500 BOOL SwDoc::UnProtectCells( const SwSelBoxes& rBoxes )
4502 BOOL bChgd = FALSE;
4503 if( rBoxes.Count() )
4505 SwUndoAttrTbl* pUndo = DoesUndo()
4506 ? new SwUndoAttrTbl( *rBoxes[0]->GetSttNd()->FindTableNode() )
4507 : 0;
4509 SvPtrarr aFmts( 16 ), aNewFmts( 16 );
4510 for( USHORT i = rBoxes.Count(); i; )
4512 SwTableBox* pBox = rBoxes[ --i ];
4513 SwFrmFmt* pBoxFmt = pBox->GetFrmFmt();
4514 if( pBoxFmt->GetProtect().IsCntntProtected() )
4516 USHORT nFnd = aFmts.GetPos( pBoxFmt );
4517 if( USHRT_MAX != nFnd )
4518 pBox->ChgFrmFmt( (SwTableBoxFmt*)aNewFmts[ nFnd ] );
4519 else
4521 aFmts.Insert( pBoxFmt, aFmts.Count() );
4522 pBoxFmt = pBox->ClaimFrmFmt();
4523 pBoxFmt->ResetFmtAttr( RES_PROTECT );
4524 aNewFmts.Insert( pBoxFmt, aNewFmts.Count() );
4526 bChgd = TRUE;
4530 if( pUndo )
4532 if( bChgd )
4534 ClearRedo();
4535 AppendUndo( pUndo );
4537 else
4538 delete pUndo;
4541 return bChgd;
4544 BOOL SwDoc::UnProtectTbls( const SwPaM& rPam )
4546 StartUndo(UNDO_EMPTY, NULL);
4548 BOOL bChgd = FALSE, bHasSel = rPam.HasMark() ||
4549 rPam.GetNext() != (SwPaM*)&rPam;
4550 SwFrmFmts& rFmts = *GetTblFrmFmts();
4551 SwTable* pTbl;
4552 const SwTableNode* pTblNd;
4553 for( USHORT n = rFmts.Count(); n ; )
4554 if( 0 != (pTbl = SwTable::FindTable( rFmts[ --n ] )) &&
4555 0 != (pTblNd = pTbl->GetTableNode() ) &&
4556 pTblNd->GetNodes().IsDocNodes() )
4558 ULONG nTblIdx = pTblNd->GetIndex();
4560 // dann ueberpruefe ob Tabelle in der Selection liegt
4561 if( bHasSel )
4563 int bFound = FALSE;
4564 SwPaM* pTmp = (SwPaM*)&rPam;
4565 do {
4566 const SwPosition *pStt = pTmp->Start(),
4567 *pEnd = pTmp->End();
4568 bFound = pStt->nNode.GetIndex() < nTblIdx &&
4569 nTblIdx < pEnd->nNode.GetIndex();
4571 } while( !bFound && &rPam != ( pTmp = (SwPaM*)pTmp->GetNext() ) );
4572 if( !bFound )
4573 continue; // weitersuchen
4576 // dann mal den Schutz aufheben
4577 bChgd |= _UnProtectTblCells( *pTbl );
4580 EndUndo(UNDO_EMPTY, NULL);
4581 if( bChgd )
4582 SetModified();
4584 return bChgd;
4587 BOOL SwDoc::HasTblAnyProtection( const SwPosition* pPos,
4588 const String* pTblName,
4589 BOOL* pFullTblProtection )
4591 BOOL bHasProtection = FALSE;
4592 SwTable* pTbl = 0;
4593 if( pTblName )
4594 pTbl = SwTable::FindTable( FindTblFmtByName( *pTblName ) );
4595 else if( pPos )
4597 SwTableNode* pTblNd = pPos->nNode.GetNode().FindTableNode();
4598 if( pTblNd )
4599 pTbl = &pTblNd->GetTable();
4602 if( pTbl )
4604 SwTableSortBoxes& rSrtBox = pTbl->GetTabSortBoxes();
4605 for( USHORT i = rSrtBox.Count(); i; )
4607 SwFrmFmt *pBoxFmt = rSrtBox[ --i ]->GetFrmFmt();
4608 if( pBoxFmt->GetProtect().IsCntntProtected() )
4610 if( !bHasProtection )
4612 bHasProtection = TRUE;
4613 if( !pFullTblProtection )
4614 break;
4615 *pFullTblProtection = TRUE;
4618 else if( bHasProtection && pFullTblProtection )
4620 *pFullTblProtection = FALSE;
4621 break;
4625 return bHasProtection;
4628 #ifdef DEL_TABLE_REDLINES
4629 lcl_DelRedlines::lcl_DelRedlines( const SwTableNode& rNd,
4630 BOOL bCheckForOwnRedline )
4631 : pDoc( (SwDoc*)rNd.GetNodes().GetDoc() )
4633 pDoc->StartUndo(UNDO_EMPTY, NULL);
4634 const SwRedlineTbl& rTbl = pDoc->GetRedlineTbl();
4635 if( !pDoc->IsIgnoreRedline() && rTbl.Count() )
4637 BOOL bDelete = TRUE;
4638 if( bCheckForOwnRedline )
4640 sal_uInt16 nRedlPos = pDoc->GetRedlinePos( rNd, USHRT_MAX );
4641 sal_uInt32 nSttNd = rNd.GetIndex(),
4642 nEndNd = rNd.EndOfSectionIndex();
4644 for ( ; nRedlPos < rTbl.Count(); ++nRedlPos )
4646 const SwRedline* pRedline = rTbl[ nRedlPos ];
4647 const SwPosition* pStt = pRedline->Start(),
4648 * pEnd = pStt == pRedline->GetPoint()
4649 ? pRedline->GetMark()
4650 : pRedline->GetPoint();
4651 if( pStt->nNode <= nSttNd )
4653 if( pEnd->nNode >= nEndNd &&
4654 pRedline->GetAuthor() == pDoc->GetRedlineAuthor() )
4656 bDelete = FALSE;
4657 break;
4660 else
4661 break;
4664 if( bDelete )
4666 SwPaM aPam(*rNd.EndOfSectionNode(), rNd);
4667 pDoc->AcceptRedline( aPam, true );
4671 #endif