1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sw.hxx" 26 27 #include <tools/resid.hxx> 28 #include <doc.hxx> 29 #include <IDocumentUndoRedo.hxx> 30 #include <swundo.hxx> 31 #include <pagedesc.hxx> 32 #include <SwUndoPageDesc.hxx> 33 #include <SwRewriter.hxx> 34 #include <undobj.hxx> 35 #include <comcore.hrc> 36 #include <fmtcntnt.hxx> 37 #include <fmthdft.hxx> 38 39 #ifdef DEBUG 40 #include <ndindex.hxx> 41 #endif 42 43 44 #ifdef DEBUG 45 // Pure debug help function to have a quick look at the header/footer attributes. 46 void DebugHeaderFooterContent( const SwPageDesc& rPageDesc ) 47 { 48 sal_uLong nHeaderMaster = ULONG_MAX; 49 sal_uLong nHeaderLeft = ULONG_MAX; 50 sal_uLong nFooterMaster = ULONG_MAX; 51 sal_uLong nFooterLeft = ULONG_MAX; 52 int nHeaderCount = 0; 53 int nLeftHeaderCount = 0; 54 int nFooterCount = 0; 55 int nLeftFooterCount = 0; 56 bool bSharedHeader = false; 57 bool bSharedFooter = false; 58 59 SwFmtHeader& rHead = (SwFmtHeader&)rPageDesc.GetMaster().GetHeader(); 60 SwFmtFooter& rFoot = (SwFmtFooter&)rPageDesc.GetMaster().GetFooter(); 61 SwFmtHeader& rLeftHead = (SwFmtHeader&)rPageDesc.GetLeft().GetHeader(); 62 SwFmtFooter& rLeftFoot = (SwFmtFooter&)rPageDesc.GetLeft().GetFooter(); 63 if( rHead.IsActive() ) 64 { 65 SwFrmFmt* pHeaderFmt = rHead.GetHeaderFmt(); 66 if( pHeaderFmt ) 67 { 68 nHeaderCount = pHeaderFmt->GetClientCount(); 69 const SwFmtCntnt* pCntnt = &pHeaderFmt->GetCntnt(); 70 if( pCntnt->GetCntntIdx() ) 71 nHeaderMaster = pCntnt->GetCntntIdx()->GetIndex(); 72 else 73 nHeaderMaster = 0; 74 } 75 bSharedHeader = rPageDesc.IsHeaderShared(); 76 SwFrmFmt* pLeftHeaderFmt = rLeftHead.GetHeaderFmt(); 77 if( pLeftHeaderFmt ) 78 { 79 nLeftHeaderCount = pLeftHeaderFmt->GetClientCount(); 80 const SwFmtCntnt* pLeftCntnt = &pLeftHeaderFmt->GetCntnt(); 81 if( pLeftCntnt->GetCntntIdx() ) 82 nHeaderLeft = pLeftCntnt->GetCntntIdx()->GetIndex(); 83 else 84 nHeaderLeft = 0; 85 } 86 } 87 if( rFoot.IsActive() ) 88 { 89 SwFrmFmt* pFooterFmt = rFoot.GetFooterFmt(); 90 if( pFooterFmt ) 91 { 92 nFooterCount = pFooterFmt->GetClientCount(); 93 const SwFmtCntnt* pCntnt = &pFooterFmt->GetCntnt(); 94 if( pCntnt->GetCntntIdx() ) 95 nFooterMaster = pCntnt->GetCntntIdx()->GetIndex(); 96 else 97 nFooterMaster = 0; 98 } 99 bSharedFooter = rPageDesc.IsFooterShared(); 100 SwFrmFmt* pLeftFooterFmt = rLeftFoot.GetFooterFmt(); 101 if( pLeftFooterFmt ) 102 { 103 nLeftFooterCount = pLeftFooterFmt->GetClientCount(); 104 const SwFmtCntnt* pLeftCntnt = &pLeftFooterFmt->GetCntnt(); 105 if( pLeftCntnt->GetCntntIdx() ) 106 nFooterLeft = pLeftCntnt->GetCntntIdx()->GetIndex(); 107 else 108 nFooterLeft = 0; 109 } 110 } 111 int i = 0; 112 ++i; // To set a breakpoint 113 } 114 #endif 115 116 SwUndoPageDesc::SwUndoPageDesc(const SwPageDesc & _aOld, 117 const SwPageDesc & _aNew, 118 SwDoc * _pDoc) 119 : SwUndo( _aOld.GetName() != _aNew.GetName() ? 120 UNDO_RENAME_PAGEDESC : 121 UNDO_CHANGE_PAGEDESC ), 122 aOld(_aOld, _pDoc), aNew(_aNew, _pDoc), pDoc(_pDoc), bExchange( false ) 123 { 124 ASSERT(0 != pDoc, "no document?"); 125 126 #ifdef DEBUG 127 DebugHeaderFooterContent( (SwPageDesc&)aOld ); 128 DebugHeaderFooterContent( (SwPageDesc&)aNew ); 129 #endif 130 131 /* 132 The page description changes. 133 If there are no header/footer content changes like header on/off or change from shared content 134 to unshared etc., there is no reason to duplicate the content nodes (Crash i55547) 135 But this happens, this Undo Ctor will destroy the unnecessary duplicate and manipulate the 136 content pointer of the both page descriptions. 137 */ 138 SwPageDesc &rOldDesc = (SwPageDesc&)aOld; 139 SwPageDesc &rNewDesc = (SwPageDesc&)aNew; 140 const SwFmtHeader& rOldHead = rOldDesc.GetMaster().GetHeader(); 141 const SwFmtHeader& rNewHead = rNewDesc.GetMaster().GetHeader(); 142 const SwFmtFooter& rOldFoot = rOldDesc.GetMaster().GetFooter(); 143 const SwFmtFooter& rNewFoot = rNewDesc.GetMaster().GetFooter(); 144 /* bExchange must not be set, if the old page descriptor will stay active. 145 Two known situations: 146 #i67735#: renaming a page descriptor 147 #i67334#: changing the follow style 148 If header/footer will be activated or deactivated, this undo will not work. 149 */ 150 bExchange = ( aOld.GetName() == aNew.GetName() ) && 151 ( _aOld.GetFollow() == _aNew.GetFollow() ) && 152 ( rOldHead.IsActive() == rNewHead.IsActive() ) && 153 ( rOldFoot.IsActive() == rNewFoot.IsActive() ); 154 if( rOldHead.IsActive() && ( rOldDesc.IsHeaderShared() != rNewDesc.IsHeaderShared() ) ) 155 bExchange = false; 156 if( rOldFoot.IsActive() && ( rOldDesc.IsFooterShared() != rNewDesc.IsFooterShared() ) ) 157 bExchange = false; 158 if( bExchange ) 159 { 160 if( rNewHead.IsActive() ) 161 { 162 SwFrmFmt* pFormat = new SwFrmFmt( *rNewHead.GetHeaderFmt() ); 163 // The Ctor of this object will remove the duplicate! 164 SwFmtHeader aFmtHeader( pFormat ); 165 if( !rNewDesc.IsHeaderShared() ) 166 { 167 pFormat = new SwFrmFmt( *rNewDesc.GetLeft().GetHeader().GetHeaderFmt() ); 168 // The Ctor of this object will remove the duplicate! 169 SwFmtHeader aFormatHeader( pFormat ); 170 } 171 } 172 // Same procedure for footers... 173 if( rNewFoot.IsActive() ) 174 { 175 SwFrmFmt* pFormat = new SwFrmFmt( *rNewFoot.GetFooterFmt() ); 176 // The Ctor of this object will remove the duplicate! 177 SwFmtFooter aFmtFooter( pFormat ); 178 if( !rNewDesc.IsFooterShared() ) 179 { 180 pFormat = new SwFrmFmt( *rNewDesc.GetLeft().GetFooter().GetFooterFmt() ); 181 // The Ctor of this object will remove the duplicate! 182 SwFmtFooter aFormatFooter( pFormat ); 183 } 184 } 185 186 // After this exchange method the old page description will point to zero, 187 // the new one will point to the node position of the original content nodes. 188 ExchangeContentNodes( (SwPageDesc&)aOld, (SwPageDesc&)aNew ); 189 #ifdef DEBUG 190 DebugHeaderFooterContent( (SwPageDesc&)aOld ); 191 DebugHeaderFooterContent( (SwPageDesc&)aNew ); 192 #endif 193 } 194 } 195 196 SwUndoPageDesc::~SwUndoPageDesc() 197 { 198 } 199 200 201 void SwUndoPageDesc::ExchangeContentNodes( SwPageDesc& rSource, SwPageDesc &rDest ) 202 { 203 ASSERT( bExchange, "You shouldn't do that." ); 204 const SwFmtHeader& rDestHead = rDest.GetMaster().GetHeader(); 205 const SwFmtHeader& rSourceHead = rSource.GetMaster().GetHeader(); 206 if( rDestHead.IsActive() ) 207 { 208 // Let the destination page descrition point to the source node position, 209 // from now on this descriptor is responsible for the content nodes! 210 const SfxPoolItem* pItem; 211 rDest.GetMaster().GetAttrSet().GetItemState( RES_HEADER, sal_False, &pItem ); 212 SfxPoolItem *pNewItem = pItem->Clone(); 213 SwFrmFmt* pNewFmt = ((SwFmtHeader*)pNewItem)->GetHeaderFmt(); 214 #ifdef DEBUG 215 const SwFmtCntnt& rSourceCntnt = rSourceHead.GetHeaderFmt()->GetCntnt(); 216 (void)rSourceCntnt; 217 const SwFmtCntnt& rDestCntnt = rDestHead.GetHeaderFmt()->GetCntnt(); 218 (void)rDestCntnt; 219 #endif 220 pNewFmt->SetFmtAttr( rSourceHead.GetHeaderFmt()->GetCntnt() ); 221 delete pNewItem; 222 223 // Let the source page description point to zero node position, 224 // it loses the responsible and can be destroyed without removing the content nodes. 225 rSource.GetMaster().GetAttrSet().GetItemState( RES_HEADER, sal_False, &pItem ); 226 pNewItem = pItem->Clone(); 227 pNewFmt = ((SwFmtHeader*)pNewItem)->GetHeaderFmt(); 228 pNewFmt->SetFmtAttr( SwFmtCntnt() ); 229 delete pNewItem; 230 231 if( !rDest.IsHeaderShared() ) 232 { 233 // Same procedure for unshared header.. 234 const SwFmtHeader& rSourceLeftHead = rSource.GetLeft().GetHeader(); 235 rDest.GetLeft().GetAttrSet().GetItemState( RES_HEADER, sal_False, &pItem ); 236 pNewItem = pItem->Clone(); 237 pNewFmt = ((SwFmtHeader*)pNewItem)->GetHeaderFmt(); 238 #ifdef DEBUG 239 const SwFmtCntnt& rSourceCntnt1 = rSourceLeftHead.GetHeaderFmt()->GetCntnt(); 240 (void)rSourceCntnt1; 241 const SwFmtCntnt& rDestCntnt1 = rDest.GetLeft().GetHeader().GetHeaderFmt()->GetCntnt(); 242 (void)rDestCntnt1; 243 #endif 244 pNewFmt->SetFmtAttr( rSourceLeftHead.GetHeaderFmt()->GetCntnt() ); 245 delete pNewItem; 246 rSource.GetLeft().GetAttrSet().GetItemState( RES_HEADER, sal_False, &pItem ); 247 pNewItem = pItem->Clone(); 248 pNewFmt = ((SwFmtHeader*)pNewItem)->GetHeaderFmt(); 249 pNewFmt->SetFmtAttr( SwFmtCntnt() ); 250 delete pNewItem; 251 } 252 } 253 // Same procedure for footers... 254 const SwFmtFooter& rDestFoot = rDest.GetMaster().GetFooter(); 255 const SwFmtFooter& rSourceFoot = rSource.GetMaster().GetFooter(); 256 if( rDestFoot.IsActive() ) 257 { 258 const SfxPoolItem* pItem; 259 rDest.GetMaster().GetAttrSet().GetItemState( RES_FOOTER, sal_False, &pItem ); 260 SfxPoolItem *pNewItem = pItem->Clone(); 261 SwFrmFmt *pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); 262 pNewFmt->SetFmtAttr( rSourceFoot.GetFooterFmt()->GetCntnt() ); 263 delete pNewItem; 264 265 #ifdef DEBUG 266 const SwFmtCntnt& rFooterSourceCntnt = rSourceFoot.GetFooterFmt()->GetCntnt(); 267 (void)rFooterSourceCntnt; 268 const SwFmtCntnt& rFooterDestCntnt = rDestFoot.GetFooterFmt()->GetCntnt(); 269 (void)rFooterDestCntnt; 270 #endif 271 rSource.GetMaster().GetAttrSet().GetItemState( RES_FOOTER, sal_False, &pItem ); 272 pNewItem = pItem->Clone(); 273 pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); 274 pNewFmt->SetFmtAttr( SwFmtCntnt() ); 275 delete pNewItem; 276 277 if( !rDest.IsFooterShared() ) 278 { 279 const SwFmtFooter& rSourceLeftFoot = rSource.GetLeft().GetFooter(); 280 #ifdef DEBUG 281 const SwFmtCntnt& rFooterSourceCntnt2 = rSourceLeftFoot.GetFooterFmt()->GetCntnt(); 282 const SwFmtCntnt& rFooterDestCntnt2 = 283 rDest.GetLeft().GetFooter().GetFooterFmt()->GetCntnt(); 284 (void)rFooterSourceCntnt2; 285 (void)rFooterDestCntnt2; 286 #endif 287 rDest.GetLeft().GetAttrSet().GetItemState( RES_FOOTER, sal_False, &pItem ); 288 pNewItem = pItem->Clone(); 289 pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); 290 pNewFmt->SetFmtAttr( rSourceLeftFoot.GetFooterFmt()->GetCntnt() ); 291 delete pNewItem; 292 rSource.GetLeft().GetAttrSet().GetItemState( RES_FOOTER, sal_False, &pItem ); 293 pNewItem = pItem->Clone(); 294 pNewFmt = ((SwFmtFooter*)pNewItem)->GetFooterFmt(); 295 pNewFmt->SetFmtAttr( SwFmtCntnt() ); 296 delete pNewItem; 297 } 298 } 299 } 300 301 void SwUndoPageDesc::UndoImpl(::sw::UndoRedoContext &) 302 { 303 // Move (header/footer)content node responsibility from new page descriptor to old one again. 304 if( bExchange ) 305 ExchangeContentNodes( (SwPageDesc&)aNew, (SwPageDesc&)aOld ); 306 pDoc->ChgPageDesc(aOld.GetName(), aOld); 307 } 308 309 void SwUndoPageDesc::RedoImpl(::sw::UndoRedoContext &) 310 { 311 // Move (header/footer)content node responsibility from old page descriptor to new one again. 312 if( bExchange ) 313 ExchangeContentNodes( (SwPageDesc&)aOld, (SwPageDesc&)aNew ); 314 pDoc->ChgPageDesc(aNew.GetName(), aNew); 315 } 316 317 SwRewriter SwUndoPageDesc::GetRewriter() const 318 { 319 SwRewriter aResult; 320 321 aResult.AddRule(UNDO_ARG1, aOld.GetName()); 322 aResult.AddRule(UNDO_ARG2, SW_RES(STR_YIELDS)); 323 aResult.AddRule(UNDO_ARG3, aNew.GetName()); 324 325 return aResult; 326 } 327 328 // #116530# 329 SwUndoPageDescCreate::SwUndoPageDescCreate(const SwPageDesc * pNew, 330 SwDoc * _pDoc) 331 : SwUndo(UNDO_CREATE_PAGEDESC), pDesc(pNew), aNew(*pNew, _pDoc), 332 pDoc(_pDoc) 333 { 334 ASSERT(0 != pDoc, "no document?"); 335 } 336 337 SwUndoPageDescCreate::~SwUndoPageDescCreate() 338 { 339 } 340 341 void SwUndoPageDescCreate::UndoImpl(::sw::UndoRedoContext &) 342 { 343 // -> #116530# 344 if (pDesc) 345 { 346 aNew = *pDesc; 347 pDesc = NULL; 348 } 349 // <- #116530# 350 351 pDoc->DelPageDesc(aNew.GetName(), sal_True); 352 } 353 354 void SwUndoPageDescCreate::DoImpl() 355 { 356 SwPageDesc aPageDesc = aNew; 357 pDoc->MakePageDesc(aNew.GetName(), &aPageDesc, sal_False, sal_True); // #116530# 358 } 359 360 void SwUndoPageDescCreate::RedoImpl(::sw::UndoRedoContext &) 361 { 362 DoImpl(); 363 } 364 365 void SwUndoPageDescCreate::RepeatImpl(::sw::RepeatContext &) 366 { 367 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); 368 DoImpl(); 369 } 370 371 SwRewriter SwUndoPageDescCreate::GetRewriter() const 372 { 373 SwRewriter aResult; 374 375 if (pDesc) 376 aResult.AddRule(UNDO_ARG1, pDesc->GetName()); 377 else 378 aResult.AddRule(UNDO_ARG1, aNew.GetName()); 379 380 381 return aResult; 382 } 383 384 SwUndoPageDescDelete::SwUndoPageDescDelete(const SwPageDesc & _aOld, 385 SwDoc * _pDoc) 386 : SwUndo(UNDO_DELETE_PAGEDESC), aOld(_aOld, _pDoc), pDoc(_pDoc) 387 { 388 ASSERT(0 != pDoc, "no document?"); 389 } 390 391 SwUndoPageDescDelete::~SwUndoPageDescDelete() 392 { 393 } 394 395 void SwUndoPageDescDelete::UndoImpl(::sw::UndoRedoContext &) 396 { 397 SwPageDesc aPageDesc = aOld; 398 pDoc->MakePageDesc(aOld.GetName(), &aPageDesc, sal_False, sal_True); // #116530# 399 } 400 401 void SwUndoPageDescDelete::DoImpl() 402 { 403 pDoc->DelPageDesc(aOld.GetName(), sal_True); // #116530# 404 } 405 406 void SwUndoPageDescDelete::RedoImpl(::sw::UndoRedoContext &) 407 { 408 DoImpl(); 409 } 410 411 void SwUndoPageDescDelete::RepeatImpl(::sw::RepeatContext &) 412 { 413 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); 414 DoImpl(); 415 } 416 417 SwRewriter SwUndoPageDescDelete::GetRewriter() const 418 { 419 SwRewriter aResult; 420 421 aResult.AddRule(UNDO_ARG1, aOld.GetName()); 422 423 return aResult; 424 } 425