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