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.
DebugHeaderFooterContent(const SwPageDesc & rPageDesc)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 
SwUndoPageDesc(const SwPageDesc & _aOld,const SwPageDesc & _aNew,SwDoc * _pDoc)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 
~SwUndoPageDesc()196 SwUndoPageDesc::~SwUndoPageDesc()
197 {
198 }
199 
200 
ExchangeContentNodes(SwPageDesc & rSource,SwPageDesc & rDest)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 
UndoImpl(::sw::UndoRedoContext &)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 
RedoImpl(::sw::UndoRedoContext &)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 
GetRewriter() const317 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#
SwUndoPageDescCreate(const SwPageDesc * pNew,SwDoc * _pDoc)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 
~SwUndoPageDescCreate()337 SwUndoPageDescCreate::~SwUndoPageDescCreate()
338 {
339 }
340 
UndoImpl(::sw::UndoRedoContext &)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 
DoImpl()354 void SwUndoPageDescCreate::DoImpl()
355 {
356     SwPageDesc aPageDesc = aNew;
357     pDoc->MakePageDesc(aNew.GetName(), &aPageDesc, sal_False, sal_True); // #116530#
358 }
359 
RedoImpl(::sw::UndoRedoContext &)360 void SwUndoPageDescCreate::RedoImpl(::sw::UndoRedoContext &)
361 {
362     DoImpl();
363 }
364 
RepeatImpl(::sw::RepeatContext &)365 void SwUndoPageDescCreate::RepeatImpl(::sw::RepeatContext &)
366 {
367     ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
368     DoImpl();
369 }
370 
GetRewriter() const371 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 
SwUndoPageDescDelete(const SwPageDesc & _aOld,SwDoc * _pDoc)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 
~SwUndoPageDescDelete()391 SwUndoPageDescDelete::~SwUndoPageDescDelete()
392 {
393 }
394 
UndoImpl(::sw::UndoRedoContext &)395 void SwUndoPageDescDelete::UndoImpl(::sw::UndoRedoContext &)
396 {
397     SwPageDesc aPageDesc = aOld;
398     pDoc->MakePageDesc(aOld.GetName(), &aPageDesc, sal_False, sal_True); // #116530#
399 }
400 
DoImpl()401 void SwUndoPageDescDelete::DoImpl()
402 {
403     pDoc->DelPageDesc(aOld.GetName(), sal_True); // #116530#
404 }
405 
RedoImpl(::sw::UndoRedoContext &)406 void SwUndoPageDescDelete::RedoImpl(::sw::UndoRedoContext &)
407 {
408     DoImpl();
409 }
410 
RepeatImpl(::sw::RepeatContext &)411 void SwUndoPageDescDelete::RepeatImpl(::sw::RepeatContext &)
412 {
413     ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
414     DoImpl();
415 }
416 
GetRewriter() const417 SwRewriter SwUndoPageDescDelete::GetRewriter() const
418 {
419     SwRewriter aResult;
420 
421     aResult.AddRule(UNDO_ARG1, aOld.GetName());
422 
423     return aResult;
424 }
425