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