1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "DocumentHelper.hxx"
22 #include "drawdoc.hxx"
23 #include "DrawDocShell.hxx"
26 #include "unmovss.hxx"
27 #include "strings.hrc"
28 #include "sdresid.hxx"
29 #include "undoback.hxx"
30 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
31 #include <com/sun/star/drawing/XDrawPages.hpp>
32 #include <com/sun/star/frame/XComponentLoader.hpp>
33 #include <com/sun/star/container/XIndexAccess.hpp>
34 #include "stlpool.hxx"
35 #include <svx/xfillit0.hxx>
36 #include <tools/diagnose_ex.h>
38 using namespace ::com::sun::star
;
40 namespace sd
{ namespace sidebar
{
42 SdPage
* DocumentHelper::CopyMasterPageToLocalDocument (
43 SdDrawDocument
& rTargetDocument
,
46 SdPage
* pNewMasterPage
= NULL
;
50 if (pMasterPage
== NULL
)
53 // Check the presence of the source document.
54 SdDrawDocument
* pSourceDocument
= static_cast<SdDrawDocument
*>(
55 pMasterPage
->GetModel());
56 if (pSourceDocument
== NULL
)
59 // When the given master page already belongs to the target document
60 // then there is nothing more to do.
61 if (pSourceDocument
== &rTargetDocument
)
63 pNewMasterPage
= pMasterPage
;
67 // Test if the master pages of both the slide and its notes page are
68 // present. This is not the case when we are called during the
69 // creation of the slide master page because then the notes master
71 sal_uInt16 nSourceMasterPageCount
= pSourceDocument
->GetMasterPageCount();
72 if (nSourceMasterPageCount
%2 == 0)
73 // There should be 1 handout page + n slide masters + n notes
74 // masters = 2*n+1. An even value indicates that a new slide
75 // master but not yet the notes master has been inserted.
77 sal_uInt16 nIndex
= pMasterPage
->GetPageNum();
78 if (nSourceMasterPageCount
<= nIndex
+1)
80 // Get the slide master page.
81 if (pMasterPage
!= static_cast<SdPage
*>(
82 pSourceDocument
->GetMasterPage(nIndex
)))
84 // Get the notes master page.
85 SdPage
* pNotesMasterPage
= static_cast<SdPage
*>(
86 pSourceDocument
->GetMasterPage(nIndex
+1));
87 if (pNotesMasterPage
== NULL
)
90 // Check if a master page with the same name as that of the given
91 // master page already exists.
92 bool bPageExists (false);
93 sal_uInt16
nMasterPageCount(rTargetDocument
.GetMasterSdPageCount(PK_STANDARD
));
94 for (sal_uInt16 nMaster
=0; nMaster
<nMasterPageCount
; nMaster
++)
96 SdPage
* pCandidate
= static_cast<SdPage
*>(
97 rTargetDocument
.GetMasterSdPage (nMaster
, PK_STANDARD
));
99 && pCandidate
->GetName() == pMasterPage
->GetName())
102 pNewMasterPage
= pCandidate
;
109 // Create a new slide (and its notes page.)
110 uno::Reference
<drawing::XDrawPagesSupplier
> xSlideSupplier (
111 rTargetDocument
.getUnoModel(), uno::UNO_QUERY
);
112 if ( ! xSlideSupplier
.is())
114 uno::Reference
<drawing::XDrawPages
> xSlides (
115 xSlideSupplier
->getDrawPages(), uno::UNO_QUERY
);
118 xSlides
->insertNewByIndex (xSlides
->getCount());
121 SdPage
* pSlide
= rTargetDocument
.GetSdPage(
122 rTargetDocument
.GetSdPageCount(PK_STANDARD
)-1,
126 pSlide
->SetAutoLayout(AUTOLAYOUT_TITLE
, true);
128 // Create a copy of the master page and the associated notes
129 // master page and insert them into our document.
130 pNewMasterPage
= AddMasterPage(rTargetDocument
, pMasterPage
);
131 if (pNewMasterPage
==NULL
)
133 SdPage
* pNewNotesMasterPage
134 = AddMasterPage(rTargetDocument
, pNotesMasterPage
);
135 if (pNewNotesMasterPage
==NULL
)
138 // Make the connection from the new slide to the master page
139 // (and do the same for the notes page.)
140 rTargetDocument
.SetMasterPage (
141 rTargetDocument
.GetSdPageCount(PK_STANDARD
)-1,
142 pNewMasterPage
->GetName(),
144 false, // Connect the new master page with the new slide but
145 // do not modify other (master) pages.
150 // We are not interested in any automatisms for our modified internal
152 rTargetDocument
.SetChanged(false);
154 return pNewMasterPage
;
157 SdPage
* DocumentHelper::GetSlideForMasterPage (SdPage
* pMasterPage
)
159 SdPage
* pCandidate
= NULL
;
161 SdDrawDocument
* pDocument
= NULL
;
162 if (pMasterPage
!= NULL
)
163 pDocument
= dynamic_cast<SdDrawDocument
*>(pMasterPage
->GetModel());
165 // Iterate over all pages and check if it references the given master
167 if (pDocument
!=NULL
&& pDocument
->GetSdPageCount(PK_STANDARD
) > 0)
169 // In most cases a new slide has just been inserted so start with
171 sal_uInt16
nPageIndex (pDocument
->GetSdPageCount(PK_STANDARD
)-1);
175 pCandidate
= pDocument
->GetSdPage(
178 if (pCandidate
!= NULL
)
180 if (static_cast<SdPage
*>(&pCandidate
->TRG_GetMasterPage())
194 // If no page was found that refernced the given master page reset
195 // the pointer that is returned.
203 SdPage
* DocumentHelper::AddMasterPage (
204 SdDrawDocument
& rTargetDocument
,
207 SdPage
* pClonedMasterPage
= NULL
;
209 if (pMasterPage
!=NULL
)
213 // Duplicate the master page.
214 pClonedMasterPage
= static_cast<SdPage
*>(pMasterPage
->Clone());
216 // Copy the necessary styles.
217 SdDrawDocument
* pSourceDocument
218 = static_cast<SdDrawDocument
*>(pMasterPage
->GetModel());
219 if (pSourceDocument
!= NULL
)
220 ProvideStyles (*pSourceDocument
, rTargetDocument
, pClonedMasterPage
);
222 // Copy the precious flag.
223 pClonedMasterPage
->SetPrecious(pMasterPage
->IsPrecious());
225 // Now that the styles are available we can insert the cloned
227 rTargetDocument
.InsertMasterPage (pClonedMasterPage
);
229 catch(const uno::Exception
&)
231 pClonedMasterPage
= NULL
;
232 DBG_UNHANDLED_EXCEPTION();
234 catch(const ::std::exception
&)
236 pClonedMasterPage
= NULL
;
237 OSL_TRACE ("caught general exception");
241 pClonedMasterPage
= NULL
;
242 OSL_TRACE ("caught general exception");
246 return pClonedMasterPage
;
249 void DocumentHelper::ProvideStyles (
250 SdDrawDocument
& rSourceDocument
,
251 SdDrawDocument
& rTargetDocument
,
254 // Get the layout name of the given page.
255 OUString
sLayoutName (pPage
->GetLayoutName());
256 sal_Int32 nIndex
= sLayoutName
.indexOf(SD_LT_SEPARATOR
);
258 sLayoutName
= sLayoutName
.copy(0, nIndex
);
260 // Copy the style sheet from source to target document.
261 SdStyleSheetPool
* pSourceStyleSheetPool
=
262 static_cast<SdStyleSheetPool
*>(rSourceDocument
.GetStyleSheetPool());
263 SdStyleSheetPool
* pTargetStyleSheetPool
=
264 static_cast<SdStyleSheetPool
*>(rTargetDocument
.GetStyleSheetPool());
265 SdStyleSheetVector aCreatedStyles
;
266 pTargetStyleSheetPool
->CopyLayoutSheets (
268 *pSourceStyleSheetPool
,
271 // Add an undo action for the copied style sheets.
272 if( !aCreatedStyles
.empty() )
274 ::svl::IUndoManager
* pUndoManager
= rTargetDocument
.GetDocSh()->GetUndoManager();
275 if (pUndoManager
!= NULL
)
277 SdMoveStyleSheetsUndoAction
* pMovStyles
=
278 new SdMoveStyleSheetsUndoAction (
282 pUndoManager
->AddUndoAction (pMovStyles
);
287 void DocumentHelper::AssignMasterPageToPageList (
288 SdDrawDocument
& rTargetDocument
,
290 const ::boost::shared_ptr
<std::vector
<SdPage
*> >& rpPageList
)
292 if (pMasterPage
== NULL
|| !pMasterPage
->IsMasterPage())
295 // Make the layout name by stripping ouf the layout postfix from the
296 // layout name of the given master page.
297 OUString
sFullLayoutName(pMasterPage
->GetLayoutName());
298 OUString
sBaseLayoutName (sFullLayoutName
);
299 sal_Int32 nIndex
= sBaseLayoutName
.indexOf(SD_LT_SEPARATOR
);
301 sBaseLayoutName
= sBaseLayoutName
.copy(0, nIndex
);
303 if (rpPageList
->empty())
306 // Create a second list that contains only the valid pointers to
307 // pages for which an assignment is necessary.
308 ::std::vector
<SdPage
*>::const_iterator iPage
;
309 ::std::vector
<SdPage
*> aCleanedList
;
310 for (iPage
=rpPageList
->begin(); iPage
!=rpPageList
->end(); ++iPage
)
312 OSL_ASSERT(*iPage
!=NULL
&& (*iPage
)->GetModel() == &rTargetDocument
);
313 if (*iPage
!= NULL
&& (*iPage
)->GetLayoutName() != sFullLayoutName
)
315 aCleanedList
.push_back(*iPage
);
318 if (aCleanedList
.empty() )
321 ::svl::IUndoManager
* pUndoMgr
= rTargetDocument
.GetDocSh()->GetUndoManager();
323 pUndoMgr
->EnterListAction(SD_RESSTR(STR_UNDO_SET_PRESLAYOUT
), OUString());
325 SdPage
* pMasterPageInDocument
= ProvideMasterPage(rTargetDocument
,pMasterPage
,rpPageList
);
326 if (pMasterPageInDocument
== NULL
)
329 // Assign the master pages to the given list of pages.
330 for (iPage
=aCleanedList
.begin();
331 iPage
!=aCleanedList
.end();
334 AssignMasterPageToPage (
335 pMasterPageInDocument
,
341 pUndoMgr
->LeaveListAction();
344 SdPage
* DocumentHelper::AddMasterPage (
345 SdDrawDocument
& rTargetDocument
,
347 sal_uInt16 nInsertionIndex
)
349 SdPage
* pClonedMasterPage
= NULL
;
351 if (pMasterPage
!=NULL
)
353 // Duplicate the master page.
354 pClonedMasterPage
= static_cast<SdPage
*>(pMasterPage
->Clone());
356 // Copy the precious flag.
357 pClonedMasterPage
->SetPrecious(pMasterPage
->IsPrecious());
359 // Copy the necessary styles.
360 SdDrawDocument
* pSourceDocument
361 = static_cast<SdDrawDocument
*>(pMasterPage
->GetModel());
362 if (pSourceDocument
!= NULL
)
364 ProvideStyles (*pSourceDocument
, rTargetDocument
, pClonedMasterPage
);
366 // Now that the styles are available we can insert the cloned
368 rTargetDocument
.InsertMasterPage (pClonedMasterPage
, nInsertionIndex
);
370 // Adapt the size of the new master page to that of the pages in
372 Size
aNewSize (rTargetDocument
.GetSdPage(0, pMasterPage
->GetPageKind())->GetSize());
374 pClonedMasterPage
->GetLftBorder(),
375 pClonedMasterPage
->GetUppBorder(),
376 pClonedMasterPage
->GetRgtBorder(),
377 pClonedMasterPage
->GetLwrBorder());
378 pClonedMasterPage
->ScaleObjects(aNewSize
, aBorders
, true);
379 pClonedMasterPage
->SetSize(aNewSize
);
380 pClonedMasterPage
->CreateTitleAndLayout(true);
384 return pClonedMasterPage
;
387 /** In here we have to handle three cases:
388 1. pPage is a normal slide. We can use SetMasterPage to assign the
390 2. pPage is a master page that is used by at least one slide. We can
391 assign the master page to these slides.
392 3. pPage is a master page that is currently not used by any slide.
393 We can delete that page and add copies of the given master pages
396 For points 2 and 3 where one master page A is assigned to another B we have
397 to keep in mind that the master page that page A has already been
398 inserted into the target document.
400 void DocumentHelper::AssignMasterPageToPage (
402 const OUString
& rsBaseLayoutName
,
405 // Leave early when the parameters are invalid.
406 if (pPage
== NULL
|| pMasterPage
== NULL
)
408 SdDrawDocument
* pDocument
= dynamic_cast<SdDrawDocument
*>(pPage
->GetModel());
409 if (pDocument
== NULL
)
412 if ( ! pPage
->IsMasterPage())
414 // 1. Remove the background object (so that, if it exists, does
415 // not override the new master page) and assign the master page to
416 // the regular slide.
417 pDocument
->GetDocSh()->GetUndoManager()->AddUndoAction(
418 new SdBackgroundObjUndoAction(
419 *pDocument
, *pPage
, pPage
->getSdrPageProperties().GetItemSet()),
421 pPage
->getSdrPageProperties().PutItem(XFillStyleItem(drawing::FillStyle_NONE
));
423 pDocument
->SetMasterPage (
424 (pPage
->GetPageNum()-1)/2,
432 // Find first slide that uses the master page.
433 SdPage
* pSlide
= NULL
;
434 sal_uInt16 nPageCount
= pDocument
->GetSdPageCount(PK_STANDARD
);
435 for (sal_uInt16 nPage
=0; nPage
<nPageCount
&&pSlide
==NULL
; nPage
++)
437 SdrPage
* pCandidate
= pDocument
->GetSdPage(nPage
,PK_STANDARD
);
438 if (pCandidate
!= NULL
439 && pCandidate
->TRG_HasMasterPage()
440 && &(pCandidate
->TRG_GetMasterPage()) == pPage
)
442 pSlide
= static_cast<SdPage
*>(pCandidate
);
448 // 2. Assign the given master pages to the first slide that was
449 // found above that uses the master page.
450 pDocument
->SetMasterPage (
451 (pSlide
->GetPageNum()-1)/2,
459 // 3. Replace the master page A by a copy of the given master
461 pDocument
->RemoveUnnecessaryMasterPages (
467 SdPage
* DocumentHelper::ProvideMasterPage (
468 SdDrawDocument
& rTargetDocument
,
470 const ::boost::shared_ptr
<std::vector
<SdPage
*> >& rpPageList
)
472 // Make sure that both the master page and its notes master exist
473 // in the source document. If one is missing then return without
474 // making any changes.
475 if (pMasterPage
== NULL
)
477 // The caller should make sure that the master page is valid.
478 OSL_ASSERT(pMasterPage
!= NULL
);
481 SdDrawDocument
* pSourceDocument
= static_cast<SdDrawDocument
*>(pMasterPage
->GetModel());
482 if (pSourceDocument
== NULL
)
484 SdPage
* pNotesMasterPage
= static_cast<SdPage
*>(
485 pSourceDocument
->GetMasterPage(pMasterPage
->GetPageNum()+1));
486 if (pNotesMasterPage
== NULL
)
488 // The model is not in a valid state. Maybe a new master page
489 // is being (not finished yet) created? Return without making
494 SdPage
* pMasterPageInDocument
= NULL
;
495 // Search for a master page with the same name as the given one in
496 // the target document.
497 const OUString
sMasterPageLayoutName (pMasterPage
->GetLayoutName());
498 for (sal_uInt16 nIndex
=0,nCount
=rTargetDocument
.GetMasterPageCount(); nIndex
<nCount
; ++nIndex
)
500 SdPage
* pCandidate
= static_cast<SdPage
*>(rTargetDocument
.GetMasterPage(nIndex
));
501 if (pCandidate
&& sMasterPageLayoutName
.equals(pCandidate
->GetLayoutName()))
503 // The requested master page does already exist in the
504 // target document, return it.
509 // The given master page does not already belong to the target
510 // document so we have to create copies and insert them into the
513 // Determine the position where the new master pages are inserted.
514 // By default they are inserted at the end. When we assign to a
515 // master page then insert after the last of the (selected) pages.
516 sal_uInt16 nInsertionIndex
= rTargetDocument
.GetMasterPageCount();
517 if (rpPageList
->front()->IsMasterPage())
519 nInsertionIndex
= rpPageList
->back()->GetPageNum();
522 // Clone the master page.
523 if (pMasterPage
->GetModel() != &rTargetDocument
)
525 pMasterPageInDocument
= AddMasterPage (rTargetDocument
, pMasterPage
, nInsertionIndex
);
526 if( rTargetDocument
.IsUndoEnabled() )
527 rTargetDocument
.AddUndo(
528 rTargetDocument
.GetSdrUndoFactory().CreateUndoNewPage(*pMasterPageInDocument
));
531 pMasterPageInDocument
= pMasterPage
;
533 // Clone the notes master.
534 if (pNotesMasterPage
->GetModel() != &rTargetDocument
)
536 SdPage
* pClonedNotesMasterPage
537 = AddMasterPage (rTargetDocument
, pNotesMasterPage
, nInsertionIndex
+1);
538 if( rTargetDocument
.IsUndoEnabled() )
539 rTargetDocument
.AddUndo(
540 rTargetDocument
.GetSdrUndoFactory().CreateUndoNewPage(*pClonedNotesMasterPage
));
543 return pMasterPageInDocument
;
546 } } // end of namespace sd::sidebar
548 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */