1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 #include <UndoSection.hxx> 32 33 #include <sfx2/linkmgr.hxx> 34 #include <fmtcntnt.hxx> 35 #include <doc.hxx> 36 #include <docary.hxx> 37 #include <swundo.hxx> // fuer die UndoIds 38 #include <pam.hxx> 39 #include <ndtxt.hxx> 40 #include <UndoCore.hxx> 41 #include <section.hxx> 42 #include <rolbck.hxx> 43 #include <redline.hxx> 44 #include <doctxm.hxx> 45 #include <ftnidx.hxx> 46 #include <editsh.hxx> 47 /// OD 04.10.2002 #102894# 48 /// class Calc needed for calculation of the hidden condition of a section. 49 #include <calc.hxx> 50 51 52 SfxItemSet* lcl_GetAttrSet( const SwSection& rSect ) 53 { 54 // Attribute des Formate sichern (Spalten, Farbe, ... ) 55 // Cntnt- und Protect- Items interessieren nicht (stehen schon in der 56 // Section), muessen also entfernen werden 57 SfxItemSet* pAttr = 0; 58 if( rSect.GetFmt() ) 59 { 60 sal_uInt16 nCnt = 1; 61 if( rSect.IsProtect() ) 62 ++nCnt; 63 64 if( nCnt < rSect.GetFmt()->GetAttrSet().Count() ) 65 { 66 pAttr = new SfxItemSet( rSect.GetFmt()->GetAttrSet() ); 67 pAttr->ClearItem( RES_PROTECT ); 68 pAttr->ClearItem( RES_CNTNT ); 69 if( !pAttr->Count() ) 70 delete pAttr, pAttr = 0; 71 } 72 } 73 return pAttr; 74 } 75 76 77 //////////////////////////////////////////////////////////////////////////// 78 79 SwUndoInsSection::SwUndoInsSection( 80 SwPaM const& rPam, SwSectionData const& rNewData, 81 SfxItemSet const*const pSet, SwTOXBase const*const pTOXBase) 82 : SwUndo( UNDO_INSSECTION ), SwUndRng( rPam ) 83 , m_pSectionData(new SwSectionData(rNewData)) 84 , m_pTOXBase( (pTOXBase) ? new SwTOXBase(*pTOXBase) : 0 ) 85 , m_pAttrSet( (pSet && pSet->Count()) ? new SfxItemSet( *pSet ) : 0 ) 86 , m_pHistory(0) 87 , m_pRedlData(0) 88 , m_nSectionNodePos(0) 89 , m_bSplitAtStart(false) 90 , m_bSplitAtEnd(false) 91 , m_bUpdateFtn(false) 92 { 93 SwDoc& rDoc = *(SwDoc*)rPam.GetDoc(); 94 if( rDoc.IsRedlineOn() ) 95 { 96 m_pRedlData.reset(new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, 97 rDoc.GetRedlineAuthor() )); 98 SetRedlineMode( rDoc.GetRedlineMode() ); 99 } 100 101 102 if( !rPam.HasMark() ) 103 { 104 const SwCntntNode* pCNd = rPam.GetPoint()->nNode.GetNode().GetCntntNode(); 105 if( pCNd && pCNd->HasSwAttrSet() && ( 106 !rPam.GetPoint()->nContent.GetIndex() || 107 rPam.GetPoint()->nContent.GetIndex() == pCNd->Len() )) 108 { 109 SfxItemSet aBrkSet( rDoc.GetAttrPool(), aBreakSetRange ); 110 aBrkSet.Put( *pCNd->GetpSwAttrSet() ); 111 if( aBrkSet.Count() ) 112 { 113 m_pHistory.reset( new SwHistory ); 114 m_pHistory->CopyFmtAttr( aBrkSet, pCNd->GetIndex() ); 115 } 116 } 117 } 118 } 119 120 SwUndoInsSection::~SwUndoInsSection() 121 { 122 } 123 124 void SwUndoInsSection::UndoImpl(::sw::UndoRedoContext & rContext) 125 { 126 SwDoc & rDoc = rContext.GetDoc(); 127 128 RemoveIdxFromSection( rDoc, m_nSectionNodePos ); 129 130 SwSectionNode *const pNd = 131 rDoc.GetNodes()[ m_nSectionNodePos ]->GetSectionNode(); 132 ASSERT( pNd, "wo ist mein SectionNode?" ); 133 134 if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() )) 135 rDoc.DeleteRedline( *pNd, true, USHRT_MAX ); 136 137 // lag keine Selektion vor ?? 138 SwNodeIndex aIdx( *pNd ); 139 if( ( !nEndNode && STRING_MAXLEN == nEndCntnt ) || 140 ( nSttNode == nEndNode && nSttCntnt == nEndCntnt )) 141 // loesche einfach alle Nodes 142 rDoc.GetNodes().Delete( aIdx, pNd->EndOfSectionIndex() - 143 aIdx.GetIndex() ); 144 else 145 // einfach das Format loeschen, der Rest erfolgt automatisch 146 rDoc.DelSectionFmt( pNd->GetSection().GetFmt() ); 147 148 // muessen wir noch zusammenfassen ? 149 if (m_bSplitAtStart) 150 { 151 Join( rDoc, nSttNode ); 152 } 153 154 if (m_bSplitAtEnd) 155 { 156 Join( rDoc, nEndNode ); 157 } 158 159 if (m_pHistory.get()) 160 { 161 m_pHistory->TmpRollback( &rDoc, 0, false ); 162 } 163 164 if (m_bUpdateFtn) 165 { 166 rDoc.GetFtnIdxs().UpdateFtn( aIdx ); 167 } 168 169 AddUndoRedoPaM(rContext); 170 } 171 172 void SwUndoInsSection::RedoImpl(::sw::UndoRedoContext & rContext) 173 { 174 SwDoc & rDoc = rContext.GetDoc(); 175 SwPaM & rPam( AddUndoRedoPaM(rContext) ); 176 177 const SwTOXBaseSection* pUpdateTOX = 0; 178 if (m_pTOXBase.get()) 179 { 180 pUpdateTOX = rDoc.InsertTableOf( *rPam.GetPoint(), 181 *m_pTOXBase, m_pAttrSet.get(), true); 182 } 183 else 184 { 185 rDoc.InsertSwSection(rPam, *m_pSectionData, 0, m_pAttrSet.get(), true); 186 } 187 188 if (m_pHistory.get()) 189 { 190 m_pHistory->SetTmpEnd( m_pHistory->Count() ); 191 } 192 193 SwSectionNode *const pSectNd = 194 rDoc.GetNodes()[ m_nSectionNodePos ]->GetSectionNode(); 195 if (m_pRedlData.get() && 196 IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode())) 197 { 198 RedlineMode_t eOld = rDoc.GetRedlineMode(); 199 rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld & ~nsRedlineMode_t::REDLINE_IGNORE)); 200 201 SwPaM aPam( *pSectNd->EndOfSectionNode(), *pSectNd, 1 ); 202 rDoc.AppendRedline( new SwRedline( *m_pRedlData, aPam ), true); 203 rDoc.SetRedlineMode_intern( eOld ); 204 } 205 else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) && 206 rDoc.GetRedlineTbl().Count() ) 207 { 208 SwPaM aPam( *pSectNd->EndOfSectionNode(), *pSectNd, 1 ); 209 rDoc.SplitRedline( aPam ); 210 } 211 212 if( pUpdateTOX ) 213 { 214 // Formatierung anstossen 215 SwEditShell* pESh = rDoc.GetEditShell(); 216 if( pESh ) 217 pESh->CalcLayout(); 218 219 // Seitennummern eintragen 220 ((SwTOXBaseSection*)pUpdateTOX)->UpdatePageNum(); 221 } 222 } 223 224 void SwUndoInsSection::RepeatImpl(::sw::RepeatContext & rContext) 225 { 226 SwDoc & rDoc = rContext.GetDoc(); 227 if (m_pTOXBase.get()) 228 { 229 rDoc.InsertTableOf(*rContext.GetRepeatPaM().GetPoint(), 230 *m_pTOXBase, m_pAttrSet.get(), true); 231 } 232 else 233 { 234 rDoc.InsertSwSection(rContext.GetRepeatPaM(), 235 *m_pSectionData, 0, m_pAttrSet.get()); 236 } 237 } 238 239 void SwUndoInsSection::Join( SwDoc& rDoc, sal_uLong nNode ) 240 { 241 SwNodeIndex aIdx( rDoc.GetNodes(), nNode ); 242 SwTxtNode* pTxtNd = aIdx.GetNode().GetTxtNode(); 243 ASSERT( pTxtNd, "wo ist mein TextNode?" ); 244 245 { 246 RemoveIdxRel( nNode + 1, SwPosition( aIdx, 247 SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ))); 248 } 249 pTxtNd->JoinNext(); 250 251 if (m_pHistory.get()) 252 { 253 SwIndex aCntIdx( pTxtNd, 0 ); 254 pTxtNd->RstAttr( aCntIdx, pTxtNd->Len(), 0, 0, true ); 255 } 256 } 257 258 259 void 260 SwUndoInsSection::SaveSplitNode(SwTxtNode *const pTxtNd, bool const bAtStart) 261 { 262 if( pTxtNd->GetpSwpHints() ) 263 { 264 if (!m_pHistory.get()) 265 { 266 m_pHistory.reset( new SwHistory ); 267 } 268 m_pHistory->CopyAttr( pTxtNd->GetpSwpHints(), pTxtNd->GetIndex(), 0, 269 pTxtNd->GetTxt().Len(), false ); 270 } 271 272 if (bAtStart) 273 { 274 m_bSplitAtStart = true; 275 } 276 else 277 { 278 m_bSplitAtEnd = true; 279 } 280 } 281 282 283 //////////////////////////////////////////////////////////////////////////// 284 285 class SwUndoDelSection 286 : public SwUndo 287 { 288 private: 289 ::std::auto_ptr<SwSectionData> const m_pSectionData; /// section not TOX 290 ::std::auto_ptr<SwTOXBase> const m_pTOXBase; /// set iff section is TOX 291 ::std::auto_ptr<SfxItemSet> const m_pAttrSet; 292 ::boost::shared_ptr< ::sfx2::MetadatableUndo > const m_pMetadataUndo; 293 sal_uLong const m_nStartNode; 294 sal_uLong const m_nEndNode; 295 296 public: 297 SwUndoDelSection( 298 SwSectionFmt const&, SwSection const&, SwNodeIndex const*const); 299 300 virtual ~SwUndoDelSection(); 301 302 virtual void UndoImpl( ::sw::UndoRedoContext & ); 303 virtual void RedoImpl( ::sw::UndoRedoContext & ); 304 }; 305 306 SW_DLLPRIVATE SwUndo * MakeUndoDelSection(SwSectionFmt const& rFormat) 307 { 308 return new SwUndoDelSection(rFormat, *rFormat.GetSection(), 309 rFormat.GetCntnt().GetCntntIdx()); 310 } 311 312 SwUndoDelSection::SwUndoDelSection( 313 SwSectionFmt const& rSectionFmt, SwSection const& rSection, 314 SwNodeIndex const*const pIndex) 315 : SwUndo( UNDO_DELSECTION ) 316 , m_pSectionData( new SwSectionData(rSection) ) 317 , m_pTOXBase( rSection.ISA( SwTOXBaseSection ) 318 ? new SwTOXBase(static_cast<SwTOXBaseSection const&>(rSection)) 319 : 0 ) 320 , m_pAttrSet( ::lcl_GetAttrSet(rSection) ) 321 , m_pMetadataUndo( rSectionFmt.CreateUndo() ) 322 , m_nStartNode( pIndex->GetIndex() ) 323 , m_nEndNode( pIndex->GetNode().EndOfSectionIndex() ) 324 { 325 } 326 327 SwUndoDelSection::~SwUndoDelSection() 328 { 329 } 330 331 void SwUndoDelSection::UndoImpl(::sw::UndoRedoContext & rContext) 332 { 333 SwDoc & rDoc = rContext.GetDoc(); 334 335 if (m_pTOXBase.get()) 336 { 337 rDoc.InsertTableOf(m_nStartNode, m_nEndNode-2, *m_pTOXBase, 338 m_pAttrSet.get()); 339 } 340 else 341 { 342 SwNodeIndex aStt( rDoc.GetNodes(), m_nStartNode ); 343 SwNodeIndex aEnd( rDoc.GetNodes(), m_nEndNode-2 ); 344 SwSectionFmt* pFmt = rDoc.MakeSectionFmt( 0 ); 345 if (m_pAttrSet.get()) 346 { 347 pFmt->SetFmtAttr( *m_pAttrSet ); 348 } 349 350 /// OD 04.10.2002 #102894# 351 /// remember inserted section node for further calculations 352 SwSectionNode* pInsertedSectNd = rDoc.GetNodes().InsertTextSection( 353 aStt, *pFmt, *m_pSectionData, 0, & aEnd); 354 355 if( SFX_ITEM_SET == pFmt->GetItemState( RES_FTN_AT_TXTEND ) || 356 SFX_ITEM_SET == pFmt->GetItemState( RES_END_AT_TXTEND )) 357 { 358 rDoc.GetFtnIdxs().UpdateFtn( aStt ); 359 } 360 361 /// OD 04.10.2002 #102894# 362 /// consider that section is hidden by condition. 363 /// If section is hidden by condition, 364 /// recalculate condition and update hidden condition flag. 365 /// Recalculation is necessary, because fields, on which the hide 366 /// condition depends, can be changed - fields changes aren't undoable. 367 /// NOTE: setting hidden condition flag also creates/deletes corresponding 368 /// frames, if the hidden condition flag changes. 369 SwSection& aInsertedSect = pInsertedSectNd->GetSection(); 370 if ( aInsertedSect.IsHidden() && 371 aInsertedSect.GetCondition().Len() > 0 ) 372 { 373 SwCalc aCalc( rDoc ); 374 rDoc.FldsToCalc(aCalc, pInsertedSectNd->GetIndex(), USHRT_MAX); 375 bool bRecalcCondHidden = 376 aCalc.Calculate( aInsertedSect.GetCondition() ).GetBool() ? true : false; 377 aInsertedSect.SetCondHidden( bRecalcCondHidden ); 378 } 379 380 pFmt->RestoreMetadata(m_pMetadataUndo); 381 } 382 } 383 384 void SwUndoDelSection::RedoImpl(::sw::UndoRedoContext & rContext) 385 { 386 SwDoc & rDoc = rContext.GetDoc(); 387 388 SwSectionNode *const pNd = 389 rDoc.GetNodes()[ m_nStartNode ]->GetSectionNode(); 390 OSL_ENSURE(pNd, "SwUndoDelSection::RedoImpl(): no SectionNode?"); 391 // einfach das Format loeschen, der Rest erfolgt automatisch 392 rDoc.DelSectionFmt( pNd->GetSection().GetFmt() ); 393 } 394 395 396 //////////////////////////////////////////////////////////////////////////// 397 398 class SwUndoUpdateSection 399 : public SwUndo 400 { 401 private: 402 ::std::auto_ptr<SwSectionData> m_pSectionData; 403 ::std::auto_ptr<SfxItemSet> m_pAttrSet; 404 sal_uLong const m_nStartNode; 405 bool const m_bOnlyAttrChanged; 406 407 public: 408 SwUndoUpdateSection( 409 SwSection const&, SwNodeIndex const*const, bool const bOnlyAttr); 410 411 virtual ~SwUndoUpdateSection(); 412 413 virtual void UndoImpl( ::sw::UndoRedoContext & ); 414 virtual void RedoImpl( ::sw::UndoRedoContext & ); 415 }; 416 417 SW_DLLPRIVATE SwUndo * 418 MakeUndoUpdateSection(SwSectionFmt const& rFormat, bool const bOnlyAttr) 419 { 420 return new SwUndoUpdateSection(*rFormat.GetSection(), 421 rFormat.GetCntnt().GetCntntIdx(), bOnlyAttr); 422 } 423 424 SwUndoUpdateSection::SwUndoUpdateSection( 425 SwSection const& rSection, SwNodeIndex const*const pIndex, 426 bool const bOnlyAttr) 427 : SwUndo( UNDO_CHGSECTION ) 428 , m_pSectionData( new SwSectionData(rSection) ) 429 , m_pAttrSet( ::lcl_GetAttrSet(rSection) ) 430 , m_nStartNode( pIndex->GetIndex() ) 431 , m_bOnlyAttrChanged( bOnlyAttr ) 432 { 433 } 434 435 SwUndoUpdateSection::~SwUndoUpdateSection() 436 { 437 } 438 439 void SwUndoUpdateSection::UndoImpl(::sw::UndoRedoContext & rContext) 440 { 441 SwDoc & rDoc = rContext.GetDoc(); 442 SwSectionNode *const pSectNd = 443 rDoc.GetNodes()[ m_nStartNode ]->GetSectionNode(); 444 ASSERT( pSectNd, "wo ist mein SectionNode?" ); 445 446 SwSection& rNdSect = pSectNd->GetSection(); 447 SwFmt* pFmt = rNdSect.GetFmt(); 448 449 SfxItemSet* pCur = ::lcl_GetAttrSet( rNdSect ); 450 if (m_pAttrSet.get()) 451 { 452 // das Content- und Protect-Item muss bestehen bleiben 453 const SfxPoolItem* pItem; 454 m_pAttrSet->Put( pFmt->GetFmtAttr( RES_CNTNT )); 455 if( SFX_ITEM_SET == pFmt->GetItemState( RES_PROTECT, sal_True, &pItem )) 456 { 457 m_pAttrSet->Put( *pItem ); 458 } 459 pFmt->DelDiffs( *m_pAttrSet ); 460 m_pAttrSet->ClearItem( RES_CNTNT ); 461 pFmt->SetFmtAttr( *m_pAttrSet ); 462 } 463 else 464 { 465 // dann muessen die alten entfernt werden 466 pFmt->ResetFmtAttr( RES_FRMATR_BEGIN, RES_BREAK ); 467 pFmt->ResetFmtAttr( RES_HEADER, RES_OPAQUE ); 468 pFmt->ResetFmtAttr( RES_SURROUND, RES_FRMATR_END-1 ); 469 } 470 m_pAttrSet.reset(pCur); 471 472 if (!m_bOnlyAttrChanged) 473 { 474 const bool bUpdate = 475 (!rNdSect.IsLinkType() && m_pSectionData->IsLinkType()) 476 || ( m_pSectionData->GetLinkFileName().Len() 477 && (m_pSectionData->GetLinkFileName() != 478 rNdSect.GetLinkFileName())); 479 480 // swap stored section data with live section data 481 SwSectionData *const pOld( new SwSectionData(rNdSect) ); 482 rNdSect.SetSectionData(*m_pSectionData); 483 m_pSectionData.reset(pOld); 484 485 if( bUpdate ) 486 rNdSect.CreateLink( CREATE_UPDATE ); 487 else if( CONTENT_SECTION == rNdSect.GetType() && rNdSect.IsConnected() ) 488 { 489 rNdSect.Disconnect(); 490 rDoc.GetLinkManager().Remove( &rNdSect.GetBaseLink() ); 491 } 492 } 493 } 494 495 void SwUndoUpdateSection::RedoImpl(::sw::UndoRedoContext & rContext) 496 { 497 UndoImpl(rContext); 498 } 499 500