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