LibreOffice Module sd (master) 1
DocumentHelper.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include "DocumentHelper.hxx"
21
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 <stlpool.hxx>
35#include <svx/xfillit0.hxx>
36#include <svx/svdundo.hxx>
38#include <xmloff/autolayout.hxx>
39#include <sal/log.hxx>
40
41using namespace ::com::sun::star;
42
43namespace sd::sidebar {
44
46 SdDrawDocument& rTargetDocument,
47 SdPage* pMasterPage)
48{
49 SdPage* pNewMasterPage = nullptr;
50
51 do
52 {
53 if (pMasterPage == nullptr)
54 break;
55
56 // Check the presence of the source document.
57 SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
58
59 // When the given master page already belongs to the target document
60 // then there is nothing more to do.
61 if (&rSourceDocument == &rTargetDocument)
62 {
63 pNewMasterPage = pMasterPage;
64 break;
65 }
66
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 = rSourceDocument.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 rSourceDocument.GetMasterPage(nIndex)))
83 break;
84 // Get the notes master page.
85 SdPage* pNotesMasterPage = static_cast<SdPage*>(
86 rSourceDocument.GetMasterPage(nIndex+1));
87 if (pNotesMasterPage == nullptr)
88 break;
89
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(PageKind::Standard));
94 for (sal_uInt16 nMaster=0; nMaster<nMasterPageCount; nMaster++)
95 {
96 SdPage* pCandidate = rTargetDocument.GetMasterSdPage (nMaster, PageKind::Standard);
97 if (pCandidate->GetName() == pMasterPage->GetName())
98 {
99 bPageExists = true;
100 pNewMasterPage = pCandidate;
101 break;
102 }
103 }
104 if (bPageExists)
105 break;
106
107 // Create a new slide (and its notes page.)
108 uno::Reference<drawing::XDrawPagesSupplier> xSlideSupplier (
109 rTargetDocument.getUnoModel(), uno::UNO_QUERY);
110 if ( ! xSlideSupplier.is())
111 break;
112 uno::Reference<drawing::XDrawPages> xSlides =
113 xSlideSupplier->getDrawPages();
114 if ( ! xSlides.is())
115 break;
116 xSlides->insertNewByIndex (xSlides->getCount());
117
118 // Set a layout.
119 SdPage* pSlide = rTargetDocument.GetSdPage(
120 rTargetDocument.GetSdPageCount(PageKind::Standard)-1,
122 if (pSlide == nullptr)
123 break;
124 pSlide->SetAutoLayout(AUTOLAYOUT_TITLE, true);
125
126 // Create a copy of the master page and the associated notes
127 // master page and insert them into our document.
128 pNewMasterPage = AddMasterPage(rTargetDocument, pMasterPage);
129 if (pNewMasterPage==nullptr)
130 break;
131 SdPage* pNewNotesMasterPage
132 = AddMasterPage(rTargetDocument, pNotesMasterPage);
133 if (pNewNotesMasterPage==nullptr)
134 break;
135
136 // Make the connection from the new slide to the master page
137 // (and do the same for the notes page.)
138 rTargetDocument.SetMasterPage (
139 rTargetDocument.GetSdPageCount(PageKind::Standard)-1,
140 pNewMasterPage->GetName(),
141 &rTargetDocument,
142 false, // Connect the new master page with the new slide but
143 // do not modify other (master) pages.
144 true);
145 }
146 while (false);
147
148 // We are not interested in any automatisms for our modified internal
149 // document.
150 rTargetDocument.SetChanged(false);
151
152 return pNewMasterPage;
153}
154
156{
157 SdPage* pCandidate = nullptr;
158
159 SdDrawDocument* pDocument = nullptr;
160 if (pMasterPage != nullptr)
161 pDocument = dynamic_cast< SdDrawDocument* >(&pMasterPage->getSdrModelFromSdrPage());
162
163 // Iterate over all pages and check if it references the given master
164 // page.
165 if (pDocument!=nullptr && pDocument->GetSdPageCount(PageKind::Standard) > 0)
166 {
167 // In most cases a new slide has just been inserted so start with
168 // the last page.
169 sal_uInt16 nPageIndex (pDocument->GetSdPageCount(PageKind::Standard)-1);
170 bool bFound (false);
171 while ( ! bFound)
172 {
173 pCandidate = pDocument->GetSdPage(
174 nPageIndex,
176 if (pCandidate != nullptr)
177 {
178 if (static_cast<SdPage*>(&pCandidate->TRG_GetMasterPage())
179 == pMasterPage)
180 {
181 bFound = true;
182 break;
183 }
184 }
185
186 if (nPageIndex == 0)
187 break;
188 else
189 nPageIndex --;
190 }
191
192 // If no page was found, that referenced the given master page, reset
193 // the pointer that is returned.
194 if ( ! bFound)
195 pCandidate = nullptr;
196 }
197
198 return pCandidate;
199}
200
202 SdDrawDocument& rTargetDocument,
203 SdPage const * pMasterPage)
204{
205 rtl::Reference<SdPage> pClonedMasterPage;
206
207 if (pMasterPage!=nullptr)
208 {
209 try
210 {
211 // Duplicate the master page.
212 pClonedMasterPage = static_cast<SdPage*>(pMasterPage->CloneSdrPage(rTargetDocument).get());
213
214 // Copy the necessary styles.
215 SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
216 ProvideStyles(rSourceDocument, rTargetDocument, pClonedMasterPage.get());
217
218 // Copy the precious flag.
219 pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious());
220
221 // Now that the styles are available we can insert the cloned
222 // master page.
223 rTargetDocument.InsertMasterPage (pClonedMasterPage.get());
224 }
225 catch(const uno::Exception&)
226 {
228 pClonedMasterPage = nullptr;
229 }
230 catch(const ::std::exception& e)
231 {
232 pClonedMasterPage = nullptr;
233 SAL_WARN("sd", "caught general exception " << e.what());
234 }
235 catch(...)
236 {
237 pClonedMasterPage = nullptr;
238 SAL_WARN("sd", "caught general exception");
239 }
240 }
241
242 return pClonedMasterPage.get();
243}
244
246 SdDrawDocument const & rSourceDocument,
247 SdDrawDocument& rTargetDocument,
248 SdPage const * pPage)
249{
250 // Get the layout name of the given page.
251 OUString sLayoutName (pPage->GetLayoutName());
252 sal_Int32 nIndex = sLayoutName.indexOf(SD_LT_SEPARATOR);
253 if( nIndex != -1 )
254 sLayoutName = sLayoutName.copy(0, nIndex);
255
256 // Copy the style sheet from source to target document.
257 SdStyleSheetPool* pSourceStyleSheetPool =
258 static_cast<SdStyleSheetPool*>(rSourceDocument.GetStyleSheetPool());
259 SdStyleSheetPool* pTargetStyleSheetPool =
260 static_cast<SdStyleSheetPool*>(rTargetDocument.GetStyleSheetPool());
261 StyleSheetCopyResultVector aCreatedStyles;
262 pTargetStyleSheetPool->CopyLayoutSheets (
263 sLayoutName,
264 *pSourceStyleSheetPool,
265 aCreatedStyles);
266
267 // Add an undo action for the copied style sheets.
268 if( !aCreatedStyles.empty() )
269 {
270 SfxUndoManager* pUndoManager = rTargetDocument.GetDocSh()->GetUndoManager();
271 if (pUndoManager != nullptr)
272 {
273 pUndoManager->AddUndoAction (
274 std::make_unique<SdMoveStyleSheetsUndoAction>(
275 &rTargetDocument,
276 aCreatedStyles,
277 true));
278 }
279 }
280}
281
283 SdDrawDocument& rTargetDocument,
284 SdPage* pMasterPage,
285 const std::shared_ptr<std::vector<SdPage*> >& rpPageList)
286{
287 if (pMasterPage == nullptr || !pMasterPage->IsMasterPage())
288 return;
289
290 // Make the layout name by stripping out the layout postfix from the
291 // layout name of the given master page.
292 OUString sFullLayoutName(pMasterPage->GetLayoutName());
293 OUString sBaseLayoutName (sFullLayoutName);
294 sal_Int32 nIndex = sBaseLayoutName.indexOf(SD_LT_SEPARATOR);
295 if( nIndex != -1 )
296 sBaseLayoutName = sBaseLayoutName.copy(0, nIndex);
297
298 if (rpPageList->empty())
299 return;
300
301 // Create a second list that contains only the valid pointers to
302 // pages for which an assignment is necessary.
303 ::std::vector<SdPage*> aCleanedList;
304 for (const auto& rpPage : *rpPageList)
305 {
306 OSL_ASSERT(rpPage!=nullptr && &rpPage->getSdrModelFromSdrPage() == &rTargetDocument);
307 if (rpPage != nullptr && rpPage->GetLayoutName() != sFullLayoutName)
308 {
309 aCleanedList.push_back(rpPage);
310 }
311 }
312 if (aCleanedList.empty() )
313 return;
314
315 ViewShellId nViewShellId(-1);
316 if (sd::ViewShell* pViewShell = rTargetDocument.GetDocSh()->GetViewShell())
317 nViewShellId = pViewShell->GetViewShellBase().GetViewShellId();
318 SfxUndoManager* pUndoMgr = rTargetDocument.GetDocSh()->GetUndoManager();
319 if( pUndoMgr )
320 pUndoMgr->EnterListAction(SdResId(STR_UNDO_SET_PRESLAYOUT), OUString(), 0, nViewShellId);
321
322 SdPage* pMasterPageInDocument = ProvideMasterPage(rTargetDocument,pMasterPage,rpPageList);
323 if (pMasterPageInDocument == nullptr)
324 return;
325
326 // Assign the master pages to the given list of pages.
327 for (const auto& rpPage : aCleanedList)
328 {
330 pMasterPageInDocument,
331 sBaseLayoutName,
332 rpPage);
333 }
334
335 if( pUndoMgr )
336 pUndoMgr->LeaveListAction();
337}
338
340 SdDrawDocument& rTargetDocument,
341 SdPage const * pMasterPage,
342 sal_uInt16 nInsertionIndex)
343{
344 rtl::Reference<SdPage> pClonedMasterPage;
345
346 if (pMasterPage!=nullptr)
347 {
348 // Duplicate the master page.
349 pClonedMasterPage = static_cast<SdPage*>(pMasterPage->CloneSdrPage(rTargetDocument).get());
350
351 // Copy the precious flag.
352 pClonedMasterPage->SetPrecious(pMasterPage->IsPrecious());
353
354 // Copy the necessary styles.
355 SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
356 ProvideStyles(rSourceDocument, rTargetDocument, pClonedMasterPage.get());
357
358 // Now that the styles are available we can insert the cloned
359 // master page.
360 rTargetDocument.InsertMasterPage (pClonedMasterPage.get(), nInsertionIndex);
361
362 // Adapt the size of the new master page to that of the pages in
363 // the document.
364 Size aNewSize (rTargetDocument.GetSdPage(0, pMasterPage->GetPageKind())->GetSize());
365 ::tools::Rectangle aBorders (
366 pClonedMasterPage->GetLeftBorder(),
367 pClonedMasterPage->GetUpperBorder(),
368 pClonedMasterPage->GetRightBorder(),
369 pClonedMasterPage->GetLowerBorder());
370 pClonedMasterPage->ScaleObjects(aNewSize, aBorders, true);
371 pClonedMasterPage->SetSize(aNewSize);
372 pClonedMasterPage->CreateTitleAndLayout(true);
373 }
374
375 return pClonedMasterPage.get();
376}
377
392 SdPage const * pMasterPage,
393 std::u16string_view rsBaseLayoutName,
394 SdPage* pPage)
395{
396 // Leave early when the parameters are invalid.
397 if (pPage == nullptr || pMasterPage == nullptr)
398 return;
399
400 SdDrawDocument& rDocument(dynamic_cast< SdDrawDocument& >(pPage->getSdrModelFromSdrPage()));
401
402 if ( ! pPage->IsMasterPage())
403 {
404 // 1. Remove the background object (so that, if it exists, does
405 // not override the new master page) and assign the master page to
406 // the regular slide.
407 rDocument.GetDocSh()->GetUndoManager()->AddUndoAction(
408 std::make_unique<SdBackgroundObjUndoAction>(
409 rDocument, *pPage, pPage->getSdrPageProperties().GetItemSet()),
410 true);
411 pPage->getSdrPageProperties().PutItem(XFillStyleItem(drawing::FillStyle_NONE));
412
413 rDocument.SetMasterPage (
414 (pPage->GetPageNum()-1)/2,
415 rsBaseLayoutName,
416 &rDocument,
417 false,
418 false);
419 }
420 else
421 {
422 // Find first slide that uses the master page.
423 SdPage* pSlide = nullptr;
424 sal_uInt16 nPageCount = rDocument.GetSdPageCount(PageKind::Standard);
425 for (sal_uInt16 nPage=0; nPage<nPageCount&&pSlide==nullptr; nPage++)
426 {
427 SdrPage* pCandidate = rDocument.GetSdPage(nPage,PageKind::Standard);
428 if (pCandidate != nullptr
429 && pCandidate->TRG_HasMasterPage()
430 && &(pCandidate->TRG_GetMasterPage()) == pPage)
431 {
432 pSlide = static_cast<SdPage*>(pCandidate);
433 }
434 }
435
436 if (pSlide != nullptr)
437 {
438 // 2. Assign the given master pages to the first slide that was
439 // found above that uses the master page.
440 rDocument.SetMasterPage (
441 (pSlide->GetPageNum()-1)/2,
442 rsBaseLayoutName,
443 &rDocument,
444 false,
445 false);
446 }
447 else
448 {
449 // 3. Replace the master page A by a copy of the given master
450 // page B.
452 pPage);
453 }
454 }
455}
456
458 SdDrawDocument& rTargetDocument,
459 SdPage* pMasterPage,
460 const std::shared_ptr<std::vector<SdPage*> >& rpPageList)
461{
462 // Make sure that both the master page and its notes master exist
463 // in the source document. If one is missing then return without
464 // making any changes.
465 if (pMasterPage == nullptr)
466 {
467 // The caller should make sure that the master page is valid.
468 OSL_ASSERT(pMasterPage != nullptr);
469 return nullptr;
470 }
471 SdDrawDocument& rSourceDocument(static_cast< SdDrawDocument& >(pMasterPage->getSdrModelFromSdrPage()));
472 SdPage* pNotesMasterPage = static_cast<SdPage*>(
473 rSourceDocument.GetMasterPage(pMasterPage->GetPageNum()+1));
474 if (pNotesMasterPage == nullptr)
475 {
476 // The model is not in a valid state. Maybe a new master page
477 // is being (not finished yet) created? Return without making
478 // any changes.
479 return nullptr;
480 }
481
482 SdPage* pMasterPageInDocument = nullptr;
483 // Search for a master page with the same name as the given one in
484 // the target document.
485 const OUString sMasterPageLayoutName (pMasterPage->GetLayoutName());
486 for (sal_uInt16 nIndex=0,nCount=rTargetDocument.GetMasterPageCount(); nIndex<nCount; ++nIndex)
487 {
488 SdPage* pCandidate = static_cast<SdPage*>(rTargetDocument.GetMasterPage(nIndex));
489 if (pCandidate && sMasterPageLayoutName == pCandidate->GetLayoutName())
490 {
491 // The requested master page does already exist in the
492 // target document, return it.
493 return pCandidate;
494 }
495 }
496
497 // The given master page does not already belong to the target
498 // document so we have to create copies and insert them into the
499 // target document.
500
501 // Determine the position where the new master pages are inserted.
502 // By default they are inserted at the end. When we assign to a
503 // master page then insert after the last of the (selected) pages.
504 sal_uInt16 nInsertionIndex = rTargetDocument.GetMasterPageCount();
505 if (rpPageList->front()->IsMasterPage())
506 {
507 nInsertionIndex = rpPageList->back()->GetPageNum();
508 }
509
510 // Clone the master page.
511 if (&pMasterPage->getSdrModelFromSdrPage() != &rTargetDocument)
512 {
513 pMasterPageInDocument = AddMasterPage (rTargetDocument, pMasterPage, nInsertionIndex);
514 if( rTargetDocument.IsUndoEnabled() )
515 rTargetDocument.AddUndo(
516 rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pMasterPageInDocument));
517 }
518 else
519 pMasterPageInDocument = pMasterPage;
520
521 // Clone the notes master.
522 if (&pNotesMasterPage->getSdrModelFromSdrPage() != &rTargetDocument)
523 {
524 SdPage* pClonedNotesMasterPage
525 = AddMasterPage (rTargetDocument, pNotesMasterPage, nInsertionIndex+1);
526 if( rTargetDocument.IsUndoEnabled() )
527 rTargetDocument.AddUndo(
528 rTargetDocument.GetSdrUndoFactory().CreateUndoNewPage(*pClonedNotesMasterPage));
529 }
530
531 return pMasterPageInDocument;
532}
533
534} // end of namespace sd::sidebar
535
536/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
AUTOLAYOUT_TITLE
sal_uInt16 GetMasterSdPageCount(PageKind ePgKind) const
Definition: drawdoc2.cxx:222
virtual SAL_DLLPRIVATE void InsertMasterPage(SdrPage *pPage, sal_uInt16 nPos=0xFFFF) override
Definition: drawdoc2.cxx:434
SdPage * GetSdPage(sal_uInt16 nPgNum, PageKind ePgKind) const
Definition: drawdoc2.cxx:207
SdPage * GetMasterSdPage(sal_uInt16 nPgNum, PageKind ePgKind)
Definition: drawdoc2.cxx:217
void SetMasterPage(sal_uInt16 nSdPageNum, std::u16string_view rLayoutName, SdDrawDocument *pSourceDoc, bool bMaster, bool bCheckMasters)
Definition: drawdoc3.cxx:1370
SAL_DLLPRIVATE void RemoveUnnecessaryMasterPages(SdPage *pMaster=nullptr, bool bOnlyDuplicatePages=false, bool bUndo=true)
Definition: drawdoc3.cxx:1172
virtual SAL_DLLPRIVATE void SetChanged(bool bFlag=true) override
Definition: drawdoc.cxx:658
SAL_DLLPRIVATE::sd::DrawDocShell * GetDocSh() const
Definition: drawdoc.hxx:242
sal_uInt16 GetSdPageCount(PageKind ePgKind) const
Definition: drawdoc2.cxx:212
PageKind GetPageKind() const
Definition: sdpage.hxx:205
bool IsPrecious() const
The "precious" flag is used for master pages to prevent some unused master pages from being deleted a...
Definition: sdpage.hxx:368
void SetAutoLayout(AutoLayout eLayout, bool bInit=false, bool bCreate=false)
Definition: sdpage.cxx:1610
virtual OUString GetLayoutName() const override
Definition: sdpage.hxx:255
const OUString & GetName() const
Definition: sdpage.cxx:2505
virtual rtl::Reference< SdrPage > CloneSdrPage(SdrModel &rTargetModel) const override
Definition: sdpage2.cxx:420
void CopyLayoutSheets(std::u16string_view rLayoutName, SdStyleSheetPool &rSourcePool, StyleSheetCopyResultVector &rCreatedSheets)
Definition: stlpool.cxx:718
const SdrPage * GetMasterPage(sal_uInt16 nPgNum) const
void AddUndo(std::unique_ptr< SdrUndoAction > pUndo)
sal_uInt16 GetMasterPageCount() const
SfxStyleSheetBasePool * GetStyleSheetPool() const
SdrUndoFactory & GetSdrUndoFactory() const
css::uno::Reference< css::uno::XInterface > const & getUnoModel()
bool IsUndoEnabled() const
const SfxItemSet & GetItemSet() const
void PutItem(const SfxPoolItem &rItem)
SdrPage & TRG_GetMasterPage() const
sal_uInt16 GetPageNum() const
bool IsMasterPage() const
Size GetSize() const
bool TRG_HasMasterPage() const
SdrPageProperties & getSdrPageProperties()
SdrModel & getSdrModelFromSdrPage() const
virtual std::unique_ptr< SdrUndoAction > CreateUndoNewPage(SdrPage &rPage)
size_t LeaveListAction()
virtual void EnterListAction(const OUString &rComment, const OUString &rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId)
virtual void AddUndoAction(std::unique_ptr< SfxUndoAction > pAction, bool bTryMerg=false)
Base class of the stacked shell hierarchy.
Definition: ViewShell.hxx:92
static void AssignMasterPageToPage(SdPage const *pMasterPage, std::u16string_view rsBaseLayoutName, SdPage *pPage)
Assign the given master page to the given page.
static SdPage * CopyMasterPageToLocalDocument(SdDrawDocument &rTargetDocument, SdPage *pMasterPage)
Return a copy of the given master page in the given document.
static SdPage * AddMasterPage(SdDrawDocument &rTargetDocument, SdPage const *pMasterPage)
static void ProvideStyles(SdDrawDocument const &rSourceDocument, SdDrawDocument &rTargetDocument, SdPage const *pPage)
Copy the styles used by the given page from the source document to the target document.
static SdPage * GetSlideForMasterPage(SdPage const *pMasterPage)
Return and, when not yet present, create a slide that uses the given master page.
static SdPage * ProvideMasterPage(SdDrawDocument &rTargetDocument, SdPage *pMasterPage, const std::shared_ptr< std::vector< SdPage * > > &rpPageList)
static void AssignMasterPageToPageList(SdDrawDocument &rTargetDocument, SdPage *pMasterPage, const std::shared_ptr< std::vector< SdPage * > > &rPageList)
Assign the given master page to the list of pages.
int nCount
#define DBG_UNHANDLED_EXCEPTION(...)
constexpr OUStringLiteral SD_LT_SEPARATOR
Definition: glob.hxx:49
sal_Int32 nIndex
#define SAL_WARN(area, stream)
OUString SdResId(TranslateId aId)
Definition: sdmod.cxx:83
std::vector< StyleSheetCopyResult > StyleSheetCopyResultVector
Definition: stlsheet.hxx:184