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 126 ~lcl_DelRedlines() { pDoc->EndUndo(UNDO_EMPTY, NULL); } 127 }; 128 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 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 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 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 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 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 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 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 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 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 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 -----------------------------------------------------------------------*/ 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 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 -----------------------------------------------------------------------*/ 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 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 1534 _DelTabPara( SwNodes& rNodes, sal_Unicode cChar, SwUndoTblToTxt* pU ) : 1535 pLastNd(0), rNds( rNodes ), pUndo( pU ), cCh( cChar ) {} 1536 _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 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 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 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 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 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 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 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 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 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 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 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 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 2423 SwTableNode::SwTableNode( const SwNodeIndex& rIdx ) 2424 : SwStartNode( rIdx, ND_TABLENODE ) 2425 { 2426 pTable = new SwTable( 0 ); 2427 } 2428 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 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. 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 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 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 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 2570 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( !this, "einer von beiden muss angegeben werden!" ); 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 2634 bool FuzzyCompare::operator() ( long s1, long s2 ) const 2635 { 2636 return ( s1 < s2 && abs( s1 - s2 ) > ROWFUZZY ); 2637 } 2638 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 2654 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 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( !this, "einer von beiden muss angegeben werden!" ); 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 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 * --------------------------------------------------*/ 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 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 3039 void SwCollectTblLineBoxes::AddToUndoHistory( const SwCntntNode& rNd ) 3040 { 3041 if( pHst ) 3042 pHst->Add( rNd.GetFmtColl(), rNd.GetIndex(), ND_TEXTNODE ); 3043 } 3044 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 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 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 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 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 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 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 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: 3390 _SplitTable_Para( SwTableNode* pNew, SwTable& rOld ) 3391 : aSrc( 16, 16 ), aDest( 16, 16 ), pNewTblNd( pNew ), rOldTbl( rOld ) 3392 {} 3393 sal_uInt16 SrcFmt_GetPos( void* pFmt ) const 3394 { return aSrc.GetPos( pFmt ); } 3395 3396 void DestFmt_Insert( void* pFmt ) 3397 { aDest.Insert( pFmt, aDest.Count() ); } 3398 3399 void SrcFmt_Insert( void* pFmt ) 3400 { aSrc.Insert( pFmt, aSrc.Count() ); } 3401 3402 SwFrmFmt* DestFmt_Get( sal_uInt16 nPos ) const 3403 { return (SwFrmFmt*)aDest[ nPos ]; } 3404 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 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 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 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. 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 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 3749 _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 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 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 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 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 3971 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 4012 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 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 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 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 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 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 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 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 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 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 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 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