bump product version to 5.0.4.1
[LibreOffice.git] / sd / source / ui / sidebar / DocumentHelper.cxx
blob4dedf6d69d4e14e69023d6770317e96979404eb0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
24 #include "sdpage.hxx"
25 #include "glob.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,
44 SdPage* pMasterPage)
46 SdPage* pNewMasterPage = NULL;
50 if (pMasterPage == NULL)
51 break;
53 // Check the presence of the source document.
54 SdDrawDocument* pSourceDocument = static_cast<SdDrawDocument*>(
55 pMasterPage->GetModel());
56 if (pSourceDocument == NULL)
57 break;
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;
64 break;
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
70 // page is not there.
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.
76 break;
77 sal_uInt16 nIndex = pMasterPage->GetPageNum();
78 if (nSourceMasterPageCount <= nIndex+1)
79 break;
80 // Get the slide master page.
81 if (pMasterPage != static_cast<SdPage*>(
82 pSourceDocument->GetMasterPage(nIndex)))
83 break;
84 // Get the notes master page.
85 SdPage* pNotesMasterPage = static_cast<SdPage*>(
86 pSourceDocument->GetMasterPage(nIndex+1));
87 if (pNotesMasterPage == NULL)
88 break;
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));
98 if (pMasterPage!=NULL
99 && pCandidate->GetName() == pMasterPage->GetName())
101 bPageExists = true;
102 pNewMasterPage = pCandidate;
103 break;
106 if (bPageExists)
107 break;
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())
113 break;
114 uno::Reference<drawing::XDrawPages> xSlides (
115 xSlideSupplier->getDrawPages(), uno::UNO_QUERY);
116 if ( ! xSlides.is())
117 break;
118 xSlides->insertNewByIndex (xSlides->getCount());
120 // Set a layout.
121 SdPage* pSlide = rTargetDocument.GetSdPage(
122 rTargetDocument.GetSdPageCount(PK_STANDARD)-1,
123 PK_STANDARD);
124 if (pSlide == NULL)
125 break;
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)
132 break;
133 SdPage* pNewNotesMasterPage
134 = AddMasterPage(rTargetDocument, pNotesMasterPage);
135 if (pNewNotesMasterPage==NULL)
136 break;
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(),
143 &rTargetDocument,
144 false, // Connect the new master page with the new slide but
145 // do not modify other (master) pages.
146 true);
148 while (false);
150 // We are not interested in any automatisms for our modified internal
151 // document.
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
166 // page.
167 if (pDocument!=NULL && pDocument->GetSdPageCount(PK_STANDARD) > 0)
169 // In most cases a new slide has just been inserted so start with
170 // the last page.
171 sal_uInt16 nPageIndex (pDocument->GetSdPageCount(PK_STANDARD)-1);
172 bool bFound (false);
173 while ( ! bFound)
175 pCandidate = pDocument->GetSdPage(
176 nPageIndex,
177 PK_STANDARD);
178 if (pCandidate != NULL)
180 if (static_cast<SdPage*>(&pCandidate->TRG_GetMasterPage())
181 == pMasterPage)
183 bFound = true;
184 break;
188 if (nPageIndex == 0)
189 break;
190 else
191 nPageIndex --;
194 // If no page was found that refernced the given master page reset
195 // the pointer that is returned.
196 if ( ! bFound)
197 pCandidate = NULL;
200 return pCandidate;
203 SdPage* DocumentHelper::AddMasterPage (
204 SdDrawDocument& rTargetDocument,
205 SdPage* pMasterPage)
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
226 // master page.
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");
239 catch(...)
241 pClonedMasterPage = NULL;
242 OSL_TRACE ("caught general exception");
246 return pClonedMasterPage;
249 void DocumentHelper::ProvideStyles (
250 SdDrawDocument& rSourceDocument,
251 SdDrawDocument& rTargetDocument,
252 SdPage* pPage)
254 // Get the layout name of the given page.
255 OUString sLayoutName (pPage->GetLayoutName());
256 sal_Int32 nIndex = sLayoutName.indexOf(SD_LT_SEPARATOR);
257 if( nIndex != -1 )
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 (
267 sLayoutName,
268 *pSourceStyleSheetPool,
269 aCreatedStyles);
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 (
279 &rTargetDocument,
280 aCreatedStyles,
281 true);
282 pUndoManager->AddUndoAction (pMovStyles);
287 void DocumentHelper::AssignMasterPageToPageList (
288 SdDrawDocument& rTargetDocument,
289 SdPage* pMasterPage,
290 const ::boost::shared_ptr<std::vector<SdPage*> >& rpPageList)
292 if (pMasterPage == NULL || !pMasterPage->IsMasterPage())
293 return;
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);
300 if( nIndex != -1 )
301 sBaseLayoutName = sBaseLayoutName.copy(0, nIndex);
303 if (rpPageList->empty())
304 return;
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() )
319 return;
321 ::svl::IUndoManager* pUndoMgr = rTargetDocument.GetDocSh()->GetUndoManager();
322 if( pUndoMgr )
323 pUndoMgr->EnterListAction(SD_RESSTR(STR_UNDO_SET_PRESLAYOUT), OUString());
325 SdPage* pMasterPageInDocument = ProvideMasterPage(rTargetDocument,pMasterPage,rpPageList);
326 if (pMasterPageInDocument == NULL)
327 return;
329 // Assign the master pages to the given list of pages.
330 for (iPage=aCleanedList.begin();
331 iPage!=aCleanedList.end();
332 ++iPage)
334 AssignMasterPageToPage (
335 pMasterPageInDocument,
336 sBaseLayoutName,
337 *iPage);
340 if( pUndoMgr )
341 pUndoMgr->LeaveListAction();
344 SdPage* DocumentHelper::AddMasterPage (
345 SdDrawDocument& rTargetDocument,
346 SdPage* pMasterPage,
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
367 // master page.
368 rTargetDocument.InsertMasterPage (pClonedMasterPage, nInsertionIndex);
370 // Adapt the size of the new master page to that of the pages in
371 // the document.
372 Size aNewSize (rTargetDocument.GetSdPage(0, pMasterPage->GetPageKind())->GetSize());
373 Rectangle aBorders (
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
389 master pages to it.
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
394 instead.
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 (
401 SdPage* pMasterPage,
402 const OUString& rsBaseLayoutName,
403 SdPage* pPage)
405 // Leave early when the parameters are invalid.
406 if (pPage == NULL || pMasterPage == NULL)
407 return;
408 SdDrawDocument* pDocument = dynamic_cast<SdDrawDocument*>(pPage->GetModel());
409 if (pDocument == NULL)
410 return;
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()),
420 true);
421 pPage->getSdrPageProperties().PutItem(XFillStyleItem(drawing::FillStyle_NONE));
423 pDocument->SetMasterPage (
424 (pPage->GetPageNum()-1)/2,
425 rsBaseLayoutName,
426 pDocument,
427 false,
428 false);
430 else
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);
446 if (pSlide != NULL)
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,
452 rsBaseLayoutName,
453 pDocument,
454 false,
455 false);
457 else
459 // 3. Replace the master page A by a copy of the given master
460 // page B.
461 pDocument->RemoveUnnecessaryMasterPages (
462 pPage, false);
467 SdPage* DocumentHelper::ProvideMasterPage (
468 SdDrawDocument& rTargetDocument,
469 SdPage* pMasterPage,
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);
479 return NULL;
481 SdDrawDocument* pSourceDocument = static_cast<SdDrawDocument*>(pMasterPage->GetModel());
482 if (pSourceDocument == NULL)
483 return 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
490 // any changes.
491 return NULL;
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.
505 return pCandidate;
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
511 // targer document.
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));
530 else
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: */