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