bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / ui / sidebar / DocumentHelper.cxx
blob215793b9548923f4c2b414b506ea4d218f2c0728
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 <ViewShell.hxx>
31 #include <ViewShellBase.hxx>
32 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
33 #include <com/sun/star/drawing/XDrawPages.hpp>
34 #include <com/sun/star/container/XIndexAccess.hpp>
35 #include <stlpool.hxx>
36 #include <svx/xfillit0.hxx>
37 #include <svx/svdundo.hxx>
38 #include <tools/diagnose_ex.h>
39 #include <xmloff/autolayout.hxx>
40 #include <sal/log.hxx>
42 using namespace ::com::sun::star;
44 namespace sd { namespace sidebar {
46 SdPage* DocumentHelper::CopyMasterPageToLocalDocument (
47 SdDrawDocument& rTargetDocument,
48 SdPage* pMasterPage)
50 SdPage* pNewMasterPage = nullptr;
54 if (pMasterPage == nullptr)
55 break;
57 // Check the presence of the source document.
58 SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
60 // When the given master page already belongs to the target document
61 // then there is nothing more to do.
62 if (&rSourceDocument == &rTargetDocument)
64 pNewMasterPage = pMasterPage;
65 break;
68 // Test if the master pages of both the slide and its notes page are
69 // present. This is not the case when we are called during the
70 // creation of the slide master page because then the notes master
71 // page is not there.
72 sal_uInt16 nSourceMasterPageCount = rSourceDocument.GetMasterPageCount();
73 if (nSourceMasterPageCount%2 == 0)
74 // There should be 1 handout page + n slide masters + n notes
75 // masters = 2*n+1. An even value indicates that a new slide
76 // master but not yet the notes master has been inserted.
77 break;
78 sal_uInt16 nIndex = pMasterPage->GetPageNum();
79 if (nSourceMasterPageCount <= nIndex+1)
80 break;
81 // Get the slide master page.
82 if (pMasterPage != static_cast<SdPage*>(
83 rSourceDocument.GetMasterPage(nIndex)))
84 break;
85 // Get the notes master page.
86 SdPage* pNotesMasterPage = static_cast<SdPage*>(
87 rSourceDocument.GetMasterPage(nIndex+1));
88 if (pNotesMasterPage == nullptr)
89 break;
91 // Check if a master page with the same name as that of the given
92 // master page already exists.
93 bool bPageExists (false);
94 sal_uInt16 nMasterPageCount(rTargetDocument.GetMasterSdPageCount(PageKind::Standard));
95 for (sal_uInt16 nMaster=0; nMaster<nMasterPageCount; nMaster++)
97 SdPage* pCandidate = rTargetDocument.GetMasterSdPage (nMaster, PageKind::Standard);
98 if (pCandidate->GetName() == pMasterPage->GetName())
100 bPageExists = true;
101 pNewMasterPage = pCandidate;
102 break;
105 if (bPageExists)
106 break;
108 // Create a new slide (and its notes page.)
109 uno::Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
110 rTargetDocument.getUnoModel(), uno::UNO_QUERY);
111 if ( ! xSlideSupplier.is())
112 break;
113 uno::Reference<drawing::XDrawPages> xSlides (
114 xSlideSupplier->getDrawPages(), uno::UNO_QUERY);
115 if ( ! xSlides.is())
116 break;
117 xSlides->insertNewByIndex (xSlides->getCount());
119 // Set a layout.
120 SdPage* pSlide = rTargetDocument.GetSdPage(
121 rTargetDocument.GetSdPageCount(PageKind::Standard)-1,
122 PageKind::Standard);
123 if (pSlide == nullptr)
124 break;
125 pSlide->SetAutoLayout(AUTOLAYOUT_TITLE, true);
127 // Create a copy of the master page and the associated notes
128 // master page and insert them into our document.
129 pNewMasterPage = AddMasterPage(rTargetDocument, pMasterPage);
130 if (pNewMasterPage==nullptr)
131 break;
132 SdPage* pNewNotesMasterPage
133 = AddMasterPage(rTargetDocument, pNotesMasterPage);
134 if (pNewNotesMasterPage==nullptr)
135 break;
137 // Make the connection from the new slide to the master page
138 // (and do the same for the notes page.)
139 rTargetDocument.SetMasterPage (
140 rTargetDocument.GetSdPageCount(PageKind::Standard)-1,
141 pNewMasterPage->GetName(),
142 &rTargetDocument,
143 false, // Connect the new master page with the new slide but
144 // do not modify other (master) pages.
145 true);
147 while (false);
149 // We are not interested in any automatisms for our modified internal
150 // document.
151 rTargetDocument.SetChanged(false);
153 return pNewMasterPage;
156 SdPage* DocumentHelper::GetSlideForMasterPage (SdPage const * pMasterPage)
158 SdPage* pCandidate = nullptr;
160 SdDrawDocument* pDocument = nullptr;
161 if (pMasterPage != nullptr)
162 pDocument = dynamic_cast< SdDrawDocument* >(&pMasterPage->getSdrModelFromSdrPage());
164 // Iterate over all pages and check if it references the given master
165 // page.
166 if (pDocument!=nullptr && pDocument->GetSdPageCount(PageKind::Standard) > 0)
168 // In most cases a new slide has just been inserted so start with
169 // the last page.
170 sal_uInt16 nPageIndex (pDocument->GetSdPageCount(PageKind::Standard)-1);
171 bool bFound (false);
172 while ( ! bFound)
174 pCandidate = pDocument->GetSdPage(
175 nPageIndex,
176 PageKind::Standard);
177 if (pCandidate != nullptr)
179 if (static_cast<SdPage*>(&pCandidate->TRG_GetMasterPage())
180 == pMasterPage)
182 bFound = true;
183 break;
187 if (nPageIndex == 0)
188 break;
189 else
190 nPageIndex --;
193 // If no page was found, that referenced the given master page, reset
194 // the pointer that is returned.
195 if ( ! bFound)
196 pCandidate = nullptr;
199 return pCandidate;
202 SdPage* DocumentHelper::AddMasterPage (
203 SdDrawDocument& rTargetDocument,
204 SdPage const * pMasterPage)
206 SdPage* pClonedMasterPage = nullptr;
208 if (pMasterPage!=nullptr)
212 // Duplicate the master page.
213 pClonedMasterPage = static_cast<SdPage*>(pMasterPage->CloneSdrPage(rTargetDocument));
215 // Copy the necessary styles.
216 SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
217 ProvideStyles(rSourceDocument, rTargetDocument, pClonedMasterPage);
219 // Copy the precious flag.
220 pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious());
222 // Now that the styles are available we can insert the cloned
223 // master page.
224 rTargetDocument.InsertMasterPage (pClonedMasterPage);
226 catch(const uno::Exception&)
228 DBG_UNHANDLED_EXCEPTION("sd");
229 pClonedMasterPage = nullptr;
231 catch(const ::std::exception& e)
233 pClonedMasterPage = nullptr;
234 SAL_WARN("sd", "caught general exception " << e.what());
236 catch(...)
238 pClonedMasterPage = nullptr;
239 SAL_WARN("sd", "caught general exception");
243 return pClonedMasterPage;
246 void DocumentHelper::ProvideStyles (
247 SdDrawDocument const & rSourceDocument,
248 SdDrawDocument& rTargetDocument,
249 SdPage const * pPage)
251 // Get the layout name of the given page.
252 OUString sLayoutName (pPage->GetLayoutName());
253 sal_Int32 nIndex = sLayoutName.indexOf(SD_LT_SEPARATOR);
254 if( nIndex != -1 )
255 sLayoutName = sLayoutName.copy(0, nIndex);
257 // Copy the style sheet from source to target document.
258 SdStyleSheetPool* pSourceStyleSheetPool =
259 static_cast<SdStyleSheetPool*>(rSourceDocument.GetStyleSheetPool());
260 SdStyleSheetPool* pTargetStyleSheetPool =
261 static_cast<SdStyleSheetPool*>(rTargetDocument.GetStyleSheetPool());
262 StyleSheetCopyResultVector aCreatedStyles;
263 pTargetStyleSheetPool->CopyLayoutSheets (
264 sLayoutName,
265 *pSourceStyleSheetPool,
266 aCreatedStyles);
268 // Add an undo action for the copied style sheets.
269 if( !aCreatedStyles.empty() )
271 SfxUndoManager* pUndoManager = rTargetDocument.GetDocSh()->GetUndoManager();
272 if (pUndoManager != nullptr)
274 pUndoManager->AddUndoAction (
275 std::make_unique<SdMoveStyleSheetsUndoAction>(
276 &rTargetDocument,
277 aCreatedStyles,
278 true));
283 void DocumentHelper::AssignMasterPageToPageList (
284 SdDrawDocument& rTargetDocument,
285 SdPage* pMasterPage,
286 const std::shared_ptr<std::vector<SdPage*> >& rpPageList)
288 if (pMasterPage == nullptr || !pMasterPage->IsMasterPage())
289 return;
291 // Make the layout name by stripping ouf the layout postfix from the
292 // layout name of the given master page.
293 OUString sFullLayoutName(pMasterPage->GetLayoutName());
294 OUString sBaseLayoutName (sFullLayoutName);
295 sal_Int32 nIndex = sBaseLayoutName.indexOf(SD_LT_SEPARATOR);
296 if( nIndex != -1 )
297 sBaseLayoutName = sBaseLayoutName.copy(0, nIndex);
299 if (rpPageList->empty())
300 return;
302 // Create a second list that contains only the valid pointers to
303 // pages for which an assignment is necessary.
304 ::std::vector<SdPage*> aCleanedList;
305 for (const auto& rpPage : *rpPageList)
307 OSL_ASSERT(rpPage!=nullptr && &rpPage->getSdrModelFromSdrPage() == &rTargetDocument);
308 if (rpPage != nullptr && rpPage->GetLayoutName() != sFullLayoutName)
310 aCleanedList.push_back(rpPage);
313 if (aCleanedList.empty() )
314 return;
316 SfxUndoManager* pUndoMgr = rTargetDocument.GetDocSh()->GetUndoManager();
317 if( pUndoMgr )
318 pUndoMgr->EnterListAction(SdResId(STR_UNDO_SET_PRESLAYOUT), OUString(), 0, rTargetDocument.GetDocSh()->GetViewShell()->GetViewShellBase().GetViewShellId());
320 SdPage* pMasterPageInDocument = ProvideMasterPage(rTargetDocument,pMasterPage,rpPageList);
321 if (pMasterPageInDocument == nullptr)
322 return;
324 // Assign the master pages to the given list of pages.
325 for (const auto& rpPage : aCleanedList)
327 AssignMasterPageToPage (
328 pMasterPageInDocument,
329 sBaseLayoutName,
330 rpPage);
333 if( pUndoMgr )
334 pUndoMgr->LeaveListAction();
337 SdPage* DocumentHelper::AddMasterPage (
338 SdDrawDocument& rTargetDocument,
339 SdPage const * pMasterPage,
340 sal_uInt16 nInsertionIndex)
342 SdPage* pClonedMasterPage = nullptr;
344 if (pMasterPage!=nullptr)
346 // Duplicate the master page.
347 pClonedMasterPage = static_cast<SdPage*>(pMasterPage->CloneSdrPage(rTargetDocument));
349 // Copy the precious flag.
350 pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious());
352 // Copy the necessary styles.
353 SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
354 ProvideStyles(rSourceDocument, rTargetDocument, pClonedMasterPage);
356 // Now that the styles are available we can insert the cloned
357 // master page.
358 rTargetDocument.InsertMasterPage (pClonedMasterPage, nInsertionIndex);
360 // Adapt the size of the new master page to that of the pages in
361 // the document.
362 Size aNewSize (rTargetDocument.GetSdPage(0, pMasterPage->GetPageKind())->GetSize());
363 ::tools::Rectangle aBorders (
364 pClonedMasterPage->GetLeftBorder(),
365 pClonedMasterPage->GetUpperBorder(),
366 pClonedMasterPage->GetRightBorder(),
367 pClonedMasterPage->GetLowerBorder());
368 pClonedMasterPage->ScaleObjects(aNewSize, aBorders, true);
369 pClonedMasterPage->SetSize(aNewSize);
370 pClonedMasterPage->CreateTitleAndLayout(true);
373 return pClonedMasterPage;
376 /** In here we have to handle three cases:
377 1. pPage is a normal slide. We can use SetMasterPage to assign the
378 master pages to it.
379 2. pPage is a master page that is used by at least one slide. We can
380 assign the master page to these slides.
381 3. pPage is a master page that is currently not used by any slide.
382 We can delete that page and add copies of the given master pages
383 instead.
385 For points 2 and 3 where one master page A is assigned to another B we have
386 to keep in mind that the master page that page A has already been
387 inserted into the target document.
389 void DocumentHelper::AssignMasterPageToPage (
390 SdPage const * pMasterPage,
391 const OUString& rsBaseLayoutName,
392 SdPage* pPage)
394 // Leave early when the parameters are invalid.
395 if (pPage == nullptr || pMasterPage == nullptr)
396 return;
398 SdDrawDocument& rDocument(dynamic_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
400 if ( ! pPage->IsMasterPage())
402 // 1. Remove the background object (so that, if it exists, does
403 // not override the new master page) and assign the master page to
404 // the regular slide.
405 rDocument.GetDocSh()->GetUndoManager()->AddUndoAction(
406 std::make_unique<SdBackgroundObjUndoAction>(
407 rDocument, *pPage, pPage->getSdrPageProperties().GetItemSet()),
408 true);
409 pPage->getSdrPageProperties().PutItem(XFillStyleItem(drawing::FillStyle_NONE));
411 rDocument.SetMasterPage (
412 (pPage->GetPageNum()-1)/2,
413 rsBaseLayoutName,
414 &rDocument,
415 false,
416 false);
418 else
420 // Find first slide that uses the master page.
421 SdPage* pSlide = nullptr;
422 sal_uInt16 nPageCount = rDocument.GetSdPageCount(PageKind::Standard);
423 for (sal_uInt16 nPage=0; nPage<nPageCount&&pSlide==nullptr; nPage++)
425 SdrPage* pCandidate = rDocument.GetSdPage(nPage,PageKind::Standard);
426 if (pCandidate != nullptr
427 && pCandidate->TRG_HasMasterPage()
428 && &(pCandidate->TRG_GetMasterPage()) == pPage)
430 pSlide = static_cast<SdPage*>(pCandidate);
434 if (pSlide != nullptr)
436 // 2. Assign the given master pages to the first slide that was
437 // found above that uses the master page.
438 rDocument.SetMasterPage (
439 (pSlide->GetPageNum()-1)/2,
440 rsBaseLayoutName,
441 &rDocument,
442 false,
443 false);
445 else
447 // 3. Replace the master page A by a copy of the given master
448 // page B.
449 rDocument.RemoveUnnecessaryMasterPages (
450 pPage);
455 SdPage* DocumentHelper::ProvideMasterPage (
456 SdDrawDocument& rTargetDocument,
457 SdPage* pMasterPage,
458 const std::shared_ptr<std::vector<SdPage*> >& rpPageList)
460 // Make sure that both the master page and its notes master exist
461 // in the source document. If one is missing then return without
462 // making any changes.
463 if (pMasterPage == nullptr)
465 // The caller should make sure that the master page is valid.
466 OSL_ASSERT(pMasterPage != nullptr);
467 return nullptr;
469 SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
470 SdPage* pNotesMasterPage = static_cast<SdPage*>(
471 rSourceDocument.GetMasterPage(pMasterPage->GetPageNum()+1));
472 if (pNotesMasterPage == nullptr)
474 // The model is not in a valid state. Maybe a new master page
475 // is being (not finished yet) created? Return without making
476 // any changes.
477 return nullptr;
480 SdPage* pMasterPageInDocument = nullptr;
481 // Search for a master page with the same name as the given one in
482 // the target document.
483 const OUString sMasterPageLayoutName (pMasterPage->GetLayoutName());
484 for (sal_uInt16 nIndex=0,nCount=rTargetDocument.GetMasterPageCount(); nIndex<nCount; ++nIndex)
486 SdPage* pCandidate = static_cast<SdPage*>(rTargetDocument.GetMasterPage(nIndex));
487 if (pCandidate && sMasterPageLayoutName == pCandidate->GetLayoutName())
489 // The requested master page does already exist in the
490 // target document, return it.
491 return pCandidate;
495 // The given master page does not already belong to the target
496 // document so we have to create copies and insert them into the
497 // target document.
499 // Determine the position where the new master pages are inserted.
500 // By default they are inserted at the end. When we assign to a
501 // master page then insert after the last of the (selected) pages.
502 sal_uInt16 nInsertionIndex = rTargetDocument.GetMasterPageCount();
503 if (rpPageList->front()->IsMasterPage())
505 nInsertionIndex = rpPageList->back()->GetPageNum();
508 // Clone the master page.
509 if (&pMasterPage->getSdrModelFromSdrPage() != &rTargetDocument)
511 pMasterPageInDocument = AddMasterPage (rTargetDocument, pMasterPage, nInsertionIndex);
512 if( rTargetDocument.IsUndoEnabled() )
513 rTargetDocument.AddUndo(
514 rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pMasterPageInDocument));
516 else
517 pMasterPageInDocument = pMasterPage;
519 // Clone the notes master.
520 if (&pNotesMasterPage->getSdrModelFromSdrPage() != &rTargetDocument)
522 SdPage* pClonedNotesMasterPage
523 = AddMasterPage (rTargetDocument, pNotesMasterPage, nInsertionIndex+1);
524 if( rTargetDocument.IsUndoEnabled() )
525 rTargetDocument.AddUndo(
526 rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pClonedNotesMasterPage));
529 return pMasterPageInDocument;
532 } } // end of namespace sd::sidebar
534 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */