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 #include "precompiled_sd.hxx"
23
24 #include "DocumentHelper.hxx"
25
26 #include "drawdoc.hxx"
27 #include "DrawDocShell.hxx"
28 #include "sdpage.hxx"
29 #include "glob.hxx"
30 #include "unmovss.hxx"
31 #include "strings.hrc"
32 #include "sdresid.hxx"
33 #include "undoback.hxx"
34 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
35 #include <com/sun/star/drawing/XDrawPages.hpp>
36 #include <com/sun/star/frame/XComponentLoader.hpp>
37 #include <com/sun/star/container/XIndexAccess.hpp>
38 #include "stlpool.hxx"
39 #include <svx/xfillit0.hxx>
40 #include <tools/diagnose_ex.h>
41
42 using namespace ::com::sun::star;
43
44 namespace sd { namespace sidebar {
45
CopyMasterPageToLocalDocument(SdDrawDocument & rTargetDocument,SdPage * pMasterPage)46 SdPage* DocumentHelper::CopyMasterPageToLocalDocument (
47 SdDrawDocument& rTargetDocument,
48 SdPage* pMasterPage)
49 {
50 SdPage* pNewMasterPage = NULL;
51
52 do
53 {
54 if (pMasterPage == NULL)
55 break;
56
57 // Check the presence of the source document.
58 SdDrawDocument* pSourceDocument = static_cast<SdDrawDocument*>(
59 pMasterPage->GetModel());
60 if (pSourceDocument == NULL)
61 break;
62
63 // When the given master page already belongs to the target document
64 // then there is nothing more to do.
65 if (pSourceDocument == &rTargetDocument)
66 {
67 pNewMasterPage = pMasterPage;
68 break;
69 }
70
71 // Test if the master pages of both the slide and its notes page are
72 // present. This is not the case when we are called during the
73 // creation of the slide master page because then the notes master
74 // page is not there.
75 sal_uInt16 nSourceMasterPageCount = pSourceDocument->GetMasterPageCount();
76 if (nSourceMasterPageCount%2 == 0)
77 // There should be 1 handout page + n slide masters + n notes
78 // masters = 2*n+1. An even value indicates that a new slide
79 // master but not yet the notes master has been inserted.
80 break;
81 sal_uInt16 nIndex = pMasterPage->GetPageNum();
82 if (nSourceMasterPageCount <= nIndex+1)
83 break;
84 // Get the slide master page.
85 if (pMasterPage != static_cast<SdPage*>(
86 pSourceDocument->GetMasterPage(nIndex)))
87 break;
88 // Get the notes master page.
89 SdPage* pNotesMasterPage = static_cast<SdPage*>(
90 pSourceDocument->GetMasterPage(nIndex+1));
91 if (pNotesMasterPage == NULL)
92 break;
93
94
95 // Check if a master page with the same name as that of the given
96 // master page already exists.
97 bool bPageExists (false);
98 sal_uInt16 nMasterPageCount(rTargetDocument.GetMasterSdPageCount(PK_STANDARD));
99 for (sal_uInt16 nMaster=0; nMaster<nMasterPageCount; nMaster++)
100 {
101 SdPage* pCandidate = static_cast<SdPage*>(
102 rTargetDocument.GetMasterSdPage (nMaster, PK_STANDARD));
103 if (pMasterPage!=NULL
104 && pCandidate->GetName().CompareTo(pMasterPage->GetName())==0)
105 {
106 bPageExists = true;
107 pNewMasterPage = pCandidate;
108 break;
109 }
110 }
111 if (bPageExists)
112 break;
113
114 // Create a new slide (and its notes page.)
115 uno::Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
116 rTargetDocument.getUnoModel(), uno::UNO_QUERY);
117 if ( ! xSlideSupplier.is())
118 break;
119 uno::Reference<drawing::XDrawPages> xSlides (
120 xSlideSupplier->getDrawPages(), uno::UNO_QUERY);
121 if ( ! xSlides.is())
122 break;
123 xSlides->insertNewByIndex (xSlides->getCount());
124
125 // Set a layout.
126 SdPage* pSlide = rTargetDocument.GetSdPage(
127 rTargetDocument.GetSdPageCount(PK_STANDARD)-1,
128 PK_STANDARD);
129 if (pSlide == NULL)
130 break;
131 pSlide->SetAutoLayout(AUTOLAYOUT_TITLE, sal_True);
132
133 // Create a copy of the master page and the associated notes
134 // master page and insert them into our document.
135 pNewMasterPage = AddMasterPage(rTargetDocument, pMasterPage);
136 if (pNewMasterPage==NULL)
137 break;
138 SdPage* pNewNotesMasterPage
139 = AddMasterPage(rTargetDocument, pNotesMasterPage);
140 if (pNewNotesMasterPage==NULL)
141 break;
142
143 // Make the connection from the new slide to the master page
144 // (and do the same for the notes page.)
145 rTargetDocument.SetMasterPage (
146 rTargetDocument.GetSdPageCount(PK_STANDARD)-1,
147 pNewMasterPage->GetName(),
148 &rTargetDocument,
149 sal_False, // Connect the new master page with the new slide but
150 // do not modify other (master) pages.
151 sal_True);
152 }
153 while (false);
154
155 // We are not interested in any automatisms for our modified internal
156 // document.
157 rTargetDocument.SetChanged (sal_False);
158
159 return pNewMasterPage;
160 }
161
162
163
164
GetSlideForMasterPage(SdPage * pMasterPage)165 SdPage* DocumentHelper::GetSlideForMasterPage (SdPage* pMasterPage)
166 {
167 SdPage* pCandidate = NULL;
168
169 SdDrawDocument* pDocument = NULL;
170 if (pMasterPage != NULL)
171 pDocument = dynamic_cast<SdDrawDocument*>(pMasterPage->GetModel());
172
173 // Iterate over all pages and check if it references the given master
174 // page.
175 if (pDocument!=NULL && pDocument->GetSdPageCount(PK_STANDARD) > 0)
176 {
177 // In most cases a new slide has just been inserted so start with
178 // the last page.
179 sal_uInt16 nPageIndex (pDocument->GetSdPageCount(PK_STANDARD)-1);
180 bool bFound (false);
181 while ( ! bFound)
182 {
183 pCandidate = pDocument->GetSdPage(
184 nPageIndex,
185 PK_STANDARD);
186 if (pCandidate != NULL)
187 {
188 if (static_cast<SdPage*>(&pCandidate->TRG_GetMasterPage())
189 == pMasterPage)
190 {
191 bFound = true;
192 break;
193 }
194 }
195
196 if (nPageIndex == 0)
197 break;
198 else
199 nPageIndex --;
200 }
201
202 // If no page was found that refernced the given master page reset
203 // the pointer that is returned.
204 if ( ! bFound)
205 pCandidate = NULL;
206 }
207
208 return pCandidate;
209 }
210
211
212
213
AddMasterPage(SdDrawDocument & rTargetDocument,SdPage * pMasterPage)214 SdPage* DocumentHelper::AddMasterPage (
215 SdDrawDocument& rTargetDocument,
216 SdPage* pMasterPage)
217 {
218 SdPage* pClonedMasterPage = NULL;
219
220 if (pMasterPage!=NULL)
221 {
222 try
223 {
224 // Duplicate the master page.
225 pClonedMasterPage = static_cast<SdPage*>(pMasterPage->Clone());
226
227 // Copy the necessary styles.
228 SdDrawDocument* pSourceDocument
229 = static_cast<SdDrawDocument*>(pMasterPage->GetModel());
230 if (pSourceDocument != NULL)
231 ProvideStyles (*pSourceDocument, rTargetDocument, pClonedMasterPage);
232
233 // Copy the precious flag.
234 pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious());
235
236 // Now that the styles are available we can insert the cloned
237 // master page.
238 rTargetDocument.InsertMasterPage (pClonedMasterPage);
239 }
240 catch (uno::Exception& rException)
241 {
242 pClonedMasterPage = NULL;
243 DBG_UNHANDLED_EXCEPTION();
244 }
245 catch (::std::exception rException)
246 {
247 pClonedMasterPage = NULL;
248 OSL_TRACE ("caught general exception");
249 }
250 catch (...)
251 {
252 pClonedMasterPage = NULL;
253 OSL_TRACE ("caught general exception");
254 }
255 }
256
257 return pClonedMasterPage;
258 }
259
260
261
262
ProvideStyles(SdDrawDocument & rSourceDocument,SdDrawDocument & rTargetDocument,SdPage * pPage)263 void DocumentHelper::ProvideStyles (
264 SdDrawDocument& rSourceDocument,
265 SdDrawDocument& rTargetDocument,
266 SdPage* pPage)
267 {
268 // Get the layout name of the given page.
269 String sLayoutName (pPage->GetLayoutName());
270 sLayoutName.Erase (sLayoutName.SearchAscii (SD_LT_SEPARATOR));
271
272 // Copy the style sheet from source to target document.
273 SdStyleSheetPool* pSourceStyleSheetPool =
274 static_cast<SdStyleSheetPool*>(rSourceDocument.GetStyleSheetPool());
275 SdStyleSheetPool* pTargetStyleSheetPool =
276 static_cast<SdStyleSheetPool*>(rTargetDocument.GetStyleSheetPool());
277 SdStyleSheetVector aCreatedStyles;
278 pTargetStyleSheetPool->CopyLayoutSheets (
279 sLayoutName,
280 *pSourceStyleSheetPool,
281 aCreatedStyles);
282
283 // Add an undo action for the copied style sheets.
284 if( !aCreatedStyles.empty() )
285 {
286 ::svl::IUndoManager* pUndoManager = rTargetDocument.GetDocSh()->GetUndoManager();
287 if (pUndoManager != NULL)
288 {
289 SdMoveStyleSheetsUndoAction* pMovStyles =
290 new SdMoveStyleSheetsUndoAction (
291 &rTargetDocument,
292 aCreatedStyles,
293 sal_True);
294 pUndoManager->AddUndoAction (pMovStyles);
295 }
296 }
297 }
298
299
300
301
AssignMasterPageToPageList(SdDrawDocument & rTargetDocument,SdPage * pMasterPage,const::boost::shared_ptr<std::vector<SdPage * >> & rpPageList)302 void DocumentHelper::AssignMasterPageToPageList (
303 SdDrawDocument& rTargetDocument,
304 SdPage* pMasterPage,
305 const ::boost::shared_ptr<std::vector<SdPage*> >& rpPageList)
306 {
307 do
308 {
309 if (pMasterPage == NULL && pMasterPage->IsMasterPage())
310 break;
311
312 // Make the layout name by stripping ouf the layout postfix from the
313 // layout name of the given master page.
314 String sFullLayoutName (pMasterPage->GetLayoutName());
315 String sBaseLayoutName (sFullLayoutName);
316 sBaseLayoutName.Erase (sBaseLayoutName.SearchAscii (SD_LT_SEPARATOR));
317
318 if (rpPageList->empty())
319 break;
320
321 // Create a second list that contains only the valid pointers to
322 // pages for which an assignment is necessary.
323 ::std::vector<SdPage*>::const_iterator iPage;
324 ::std::vector<SdPage*> aCleanedList;
325 for (iPage=rpPageList->begin(); iPage!=rpPageList->end(); ++iPage)
326 {
327 OSL_ASSERT(*iPage!=NULL && (*iPage)->GetModel() == &rTargetDocument);
328 if (*iPage != NULL
329 && (*iPage)->GetLayoutName().CompareTo(sFullLayoutName)!=0)
330 {
331 aCleanedList.push_back(*iPage);
332 }
333 }
334 if (aCleanedList.empty() )
335 break;
336
337 ::svl::IUndoManager* pUndoMgr = rTargetDocument.GetDocSh()->GetUndoManager();
338 if( pUndoMgr )
339 pUndoMgr->EnterListAction(String(SdResId(STR_UNDO_SET_PRESLAYOUT)), String());
340
341 SdPage* pMasterPageInDocument = ProvideMasterPage(rTargetDocument,pMasterPage,rpPageList);
342 if (pMasterPageInDocument == NULL)
343 break;
344
345 // Assign the master pages to the given list of pages.
346 for (iPage=aCleanedList.begin();
347 iPage!=aCleanedList.end();
348 ++iPage)
349 {
350 AssignMasterPageToPage (
351 pMasterPageInDocument,
352 sBaseLayoutName,
353 *iPage);
354 }
355
356 if( pUndoMgr )
357 pUndoMgr->LeaveListAction();
358 }
359 while (false);
360 }
361
362
363
364
AddMasterPage(SdDrawDocument & rTargetDocument,SdPage * pMasterPage,sal_uInt16 nInsertionIndex)365 SdPage* DocumentHelper::AddMasterPage (
366 SdDrawDocument& rTargetDocument,
367 SdPage* pMasterPage,
368 sal_uInt16 nInsertionIndex)
369 {
370 SdPage* pClonedMasterPage = NULL;
371
372 if (pMasterPage!=NULL)
373 {
374 // Duplicate the master page.
375 pClonedMasterPage = static_cast<SdPage*>(pMasterPage->Clone());
376
377 // Copy the precious flag.
378 pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious());
379
380 // Copy the necessary styles.
381 SdDrawDocument* pSourceDocument
382 = static_cast<SdDrawDocument*>(pMasterPage->GetModel());
383 if (pSourceDocument != NULL)
384 {
385 ProvideStyles (*pSourceDocument, rTargetDocument, pClonedMasterPage);
386
387 // Now that the styles are available we can insert the cloned
388 // master page.
389 rTargetDocument.InsertMasterPage (pClonedMasterPage, nInsertionIndex);
390
391 // Adapt the size of the new master page to that of the pages in
392 // the document.
393 Size aNewSize (rTargetDocument.GetSdPage(0, pMasterPage->GetPageKind())->GetSize());
394 Rectangle aBorders (
395 pClonedMasterPage->GetLftBorder(),
396 pClonedMasterPage->GetUppBorder(),
397 pClonedMasterPage->GetRgtBorder(),
398 pClonedMasterPage->GetLwrBorder());
399 pClonedMasterPage->ScaleObjects(aNewSize, aBorders, sal_True);
400 pClonedMasterPage->SetSize(aNewSize);
401 pClonedMasterPage->CreateTitleAndLayout(sal_True);
402 }
403 }
404
405 return pClonedMasterPage;
406 }
407
408
409
410
411 /** In here we have to handle three cases:
412 1. pPage is a normal slide. We can use SetMasterPage to assign the
413 master pages to it.
414 2. pPage is a master page that is used by at least one slide. We can
415 assign the master page to these slides.
416 3. pPage is a master page that is currently not used by any slide.
417 We can delete that page and add copies of the given master pages
418 instead.
419
420 For points 2 and 3 where one master page A is assigned to another B we have
421 to keep in mind that the master page that page A has already been
422 inserted into the target document.
423 */
AssignMasterPageToPage(SdPage * pMasterPage,const String & rsBaseLayoutName,SdPage * pPage)424 void DocumentHelper::AssignMasterPageToPage (
425 SdPage* pMasterPage,
426 const String& rsBaseLayoutName,
427 SdPage* pPage)
428 {
429 // Leave early when the parameters are invalid.
430 if (pPage == NULL || pMasterPage == NULL)
431 return;
432 SdDrawDocument* pDocument = dynamic_cast<SdDrawDocument*>(pPage->GetModel());
433 if (pDocument == NULL)
434 return;
435
436 if ( ! pPage->IsMasterPage())
437 {
438 // 1. Remove the background object (so that that, if it exists, does
439 // not override the new master page) and assign the master page to
440 // the regular slide.
441 pDocument->GetDocSh()->GetUndoManager()->AddUndoAction(
442 new SdBackgroundObjUndoAction(
443 *pDocument, *pPage, pPage->getSdrPageProperties().GetItemSet()),
444 sal_True);
445 pPage->getSdrPageProperties().PutItem(XFillStyleItem(XFILL_NONE));
446
447 pDocument->SetMasterPage (
448 (pPage->GetPageNum()-1)/2,
449 rsBaseLayoutName,
450 pDocument,
451 sal_False,
452 sal_False);
453 }
454 else
455 {
456 // Find first slide that uses the master page.
457 SdPage* pSlide = NULL;
458 sal_uInt16 nPageCount = pDocument->GetSdPageCount(PK_STANDARD);
459 for (sal_uInt16 nPage=0; nPage<nPageCount&&pSlide==NULL; nPage++)
460 {
461 SdrPage* pCandidate = pDocument->GetSdPage(nPage,PK_STANDARD);
462 if (pCandidate != NULL
463 && pCandidate->TRG_HasMasterPage()
464 && &(pCandidate->TRG_GetMasterPage()) == pPage)
465 {
466 pSlide = static_cast<SdPage*>(pCandidate);
467 }
468 }
469
470 if (pSlide != NULL)
471 {
472 // 2. Assign the given master pages to the first slide that was
473 // found above that uses the master page.
474 pDocument->SetMasterPage (
475 (pSlide->GetPageNum()-1)/2,
476 rsBaseLayoutName,
477 pDocument,
478 sal_False,
479 sal_False);
480 }
481 else
482 {
483 // 3. Replace the master page A by a copy of the given master
484 // page B.
485 pDocument->RemoveUnnecessaryMasterPages (
486 pPage, sal_False);
487 }
488 }
489 }
490
491
492
493
ProvideMasterPage(SdDrawDocument & rTargetDocument,SdPage * pMasterPage,const::boost::shared_ptr<std::vector<SdPage * >> & rpPageList)494 SdPage* DocumentHelper::ProvideMasterPage (
495 SdDrawDocument& rTargetDocument,
496 SdPage* pMasterPage,
497 const ::boost::shared_ptr<std::vector<SdPage*> >& rpPageList)
498 {
499 // Make sure that both the master page and its notes master exist
500 // in the source document. If one is missing then return without
501 // making any changes.
502 if (pMasterPage == NULL)
503 {
504 // The caller should make sure that the master page is valid.
505 OSL_ASSERT(pMasterPage != NULL);
506 return NULL;
507 }
508 SdDrawDocument* pSourceDocument = static_cast<SdDrawDocument*>(pMasterPage->GetModel());
509 if (pSourceDocument == NULL)
510 return NULL;
511 SdPage* pNotesMasterPage = static_cast<SdPage*>(
512 pSourceDocument->GetMasterPage(pMasterPage->GetPageNum()+1));
513 if (pNotesMasterPage == NULL)
514 {
515 // The model is not in a valid state. Maybe a new master page
516 // is being (not finished yet) created? Return without making
517 // any changes.
518 return NULL;
519 }
520
521 SdPage* pMasterPageInDocument = NULL;
522 // Search for a master page with the same name as the given one in
523 // the target document.
524 const XubString sMasterPageLayoutName (pMasterPage->GetLayoutName());
525 for (sal_uInt16 nIndex=0,nCount=rTargetDocument.GetMasterPageCount(); nIndex<nCount; ++nIndex)
526 {
527 SdPage* pCandidate = static_cast<SdPage*>(rTargetDocument.GetMasterPage(nIndex));
528 if (pCandidate!=NULL
529 && sMasterPageLayoutName==pCandidate->GetLayoutName())
530 {
531 // The requested master page does already exist in the
532 // target document, return it.
533 return pCandidate;
534 }
535 }
536
537 // The given master page does not already belong to the target
538 // document so we have to create copies and insert them into the
539 // targer document.
540
541 // Determine the position where the new master pages are inserted.
542 // By default they are inserted at the end. When we assign to a
543 // master page then insert after the last of the (selected) pages.
544 sal_uInt16 nInsertionIndex = rTargetDocument.GetMasterPageCount();
545 if (rpPageList->front()->IsMasterPage())
546 {
547 nInsertionIndex = rpPageList->back()->GetPageNum();
548 }
549
550 // Clone the master page.
551 if (pMasterPage->GetModel() != &rTargetDocument)
552 {
553 pMasterPageInDocument = AddMasterPage (rTargetDocument, pMasterPage, nInsertionIndex);
554 if( rTargetDocument.IsUndoEnabled() )
555 rTargetDocument.AddUndo(
556 rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pMasterPageInDocument));
557 }
558 else
559 pMasterPageInDocument = pMasterPage;
560
561 // Clone the notes master.
562 if (pNotesMasterPage->GetModel() != &rTargetDocument)
563 {
564 SdPage* pClonedNotesMasterPage
565 = AddMasterPage (rTargetDocument, pNotesMasterPage, nInsertionIndex+1);
566 if( rTargetDocument.IsUndoEnabled() )
567 rTargetDocument.AddUndo(
568 rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pClonedNotesMasterPage));
569 }
570
571 return pMasterPageInDocument;
572 }
573
574
575
576
577
578 } } // end of namespace sd::sidebar
579