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