sd/inc/drawdoc.hxx | 484 ++++- sd/qa/unit/misc-tests.cxx | 6 sd/qa/unit/uiimpress.cxx | 38 sd/source/core/drawdoc3.cxx | 1380 ++++++++++----- sd/source/core/pglink.cxx | 3 sd/source/ui/app/sdxfer.cxx | 3 sd/source/ui/func/fuinsfil.cxx | 5 sd/source/ui/slidesorter/controller/SlsClipboard.cxx | 18 sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx | 3 sd/source/ui/view/ViewClipboard.cxx | 30 10 files changed, 1451 insertions(+), 519 deletions(-)
New commits: commit 4db90da301cff5b4bcedbe492d12bfa10e7577b7 Author: Mohamed Ali <mohmedali1462...@gmail.com> AuthorDate: Tue Jan 14 21:22:04 2025 +0200 Commit: Hossein <hoss...@libreoffice.org> CommitDate: Thu Mar 27 14:40:32 2025 +0100 tdf#45617 Refactor the member function SdDrawDocument::InsertBookmarkAsPage Break down the monolithic InsertBookmarkAsPage function into smaller, more specialized methods with clearer responsibilities: - Extract separate methods for inserting all/selected pages - Create specialized variants for different insertion scenarios (paste, file insert, drag-drop, page links, internal document operations, document import) - Introduce parameter structures to better organize function arguments - Add dedicated methods for style transfer and master page management - Improve code organization with clearer function boundaries - Enhance maintainability through smaller, focused functions Change-Id: If2b8bda0c2e88f25478d534af3f8fa0394017dbf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179832 Reviewed-by: Hossein <hoss...@libreoffice.org> Tested-by: Jenkins diff --git a/sd/inc/drawdoc.hxx b/sd/inc/drawdoc.hxx index d4dad173b7fb..393729f70c97 100644 --- a/sd/inc/drawdoc.hxx +++ b/sd/inc/drawdoc.hxx @@ -30,9 +30,12 @@ #include <memory> #include <optional> #include <string_view> +#include <map> +#include <utility> #include "sddllapi.h" #include "pres.hxx" +#include "stlpool.hxx" namespace com::sun::star::xml::dom { class XNode; } namespace com::sun::star::uno { class XInterface; } @@ -118,6 +121,230 @@ namespace sd }; } +/** + * Type aliases for commonly used data structures + */ +typedef std::vector<OUString> PageNameList; // List of page/bookmark names +typedef std::vector<OUString> SlideLayoutNameList; // List of slide layout names +typedef std::map<OUString, sal_Int32> SlideLayoutMap; // Map of slide layout names to indices +typedef std::map<OUString, std::shared_ptr<model::Theme>> ThemeMap; // Map of theme names to theme objects + +/** + * Context for style sheet transfers during page operations + * + * This structure contains all data required for transferring styles (graphic, cell, table) + * between documents or pages. It maintains collections of styles that need to be + * transferred and manages pointers to source and destination style sheet pools. + */ +struct StyleTransferContext +{ + // Style collections to be transferred + StyleSheetCopyResultVector aGraphicStyles; // Graphic styles to be transferred + StyleSheetCopyResultVector aCellStyles; // Cell styles to be transferred + XStyleVector aTableStyles; // Table styles to be transferred + OUString aRenameString; // String for style renaming operations + + // Layout information + SlideLayoutMap aSlideLayouts; // Layouts to be transferred + ThemeMap aThemes; // Themes to be transferred + + // Style sheet pools (optional, set by the caller) + SdStyleSheetPool* pSourceStyleSheetPool; // Source style sheet pool + SdStyleSheetPool* pDestStyleSheetPool; // Destination style sheet pool + + StyleTransferContext() + : pSourceStyleSheetPool(nullptr) + , pDestStyleSheetPool(nullptr) + {} + + // Constructor with style sheet pools + StyleTransferContext(SdStyleSheetPool* pSource, SdStyleSheetPool* pDest) + : pSourceStyleSheetPool(pSource) + , pDestStyleSheetPool(pDest) + {} + + // Set style sheet pools + void setStyleSheetPools(SdStyleSheetPool* pSource, SdStyleSheetPool* pDest) { + pSourceStyleSheetPool = pSource; + pDestStyleSheetPool = pDest; + } + + // Reset/clear all collections + void clear() { + aGraphicStyles.clear(); + aCellStyles.clear(); + aTableStyles.clear(); + aRenameString.clear(); + aSlideLayouts.clear(); + aThemes.clear(); + // Don't clear pointers to style sheet pools + } +}; + +/** + * Options for inserting bookmarks as pages + * + * This structure defines all parameters for controlling how pages/bookmarks + * are inserted into documents. It covers operations like linking, replacing, + * and various flags to control the behavior during page insertion. + */ +struct InsertBookmarkOptions +{ + bool bLink; // Insert bookmarks as links + bool bReplace; // Replace pages instead of inserting + bool bNoDialogs; // No dialogs allowed + bool bCopy; // Copy source document + bool bMergeMasterPages; // Merge master pages + bool bPreservePageNames; // Preserve page names + bool bIsClipboardOperation; // Operation triggered by clipboard + bool bIsDragAndDropOperation; // Operation triggered by drag and drop + bool bIsSameDocumentOperation; // Operation within the same document + bool bIsFileDocument; // Operation involves a file document + + InsertBookmarkOptions() + : bLink(false), bReplace(false), bNoDialogs(false), + bCopy(true), bMergeMasterPages(true), bPreservePageNames(false), + bIsClipboardOperation(false), bIsDragAndDropOperation(false), + bIsSameDocumentOperation(false), bIsFileDocument(false) + {} + + // Preset for paste operation + static InsertBookmarkOptions ForPaste(bool bMergeMasterPages) { + InsertBookmarkOptions options; + options.bIsClipboardOperation = true; + options.bMergeMasterPages = bMergeMasterPages; + // All defaults are fine for paste + return options; + } + + // Preset for file insert operation + static InsertBookmarkOptions ForFileInsert(bool bLinkPages) { + InsertBookmarkOptions options; + options.bLink = bLinkPages; + options.bIsFileDocument = true; + return options; + } + + // Preset for drag and drop operation + static InsertBookmarkOptions ForDragDrop(bool bMergeMasterPages) { + InsertBookmarkOptions options; + options.bIsDragAndDropOperation = true; + options.bNoDialogs = true; + options.bMergeMasterPages = bMergeMasterPages; + return options; + } + + // Preset for page link resolution + static InsertBookmarkOptions ForPageLinks(bool bCopySource, bool bNoDialogs) { + InsertBookmarkOptions options; + options.bLink = true; + options.bReplace = true; + options.bPreservePageNames = true; + options.bCopy = bCopySource; + options.bNoDialogs = bNoDialogs; + return options; + } + + // Preset for internal document operations + static InsertBookmarkOptions ForInternalOps(bool bPreserveNames) { + InsertBookmarkOptions options; + options.bNoDialogs = true; + options.bMergeMasterPages = false; + options.bPreservePageNames = bPreserveNames; + options.bIsSameDocumentOperation = true; + return options; + } + + // Preset for document import operations + static InsertBookmarkOptions ForDocumentImport() { + InsertBookmarkOptions options; + options.bLink = false; // No linking for document import + options.bReplace = true; // Replace pages when importing document + options.bNoDialogs = true; // No dialogs for document import + options.bCopy = true; // Always copy when importing document + options.bMergeMasterPages = true; // Always merge master pages + options.bPreservePageNames = false; // Don't preserve page names + options.bIsFileDocument = true; // This is a file document operation + return options; + } +}; + +/** + * Properties of a document page, used for page insertion and scaling operations + * + * This structure stores the geometric properties of a page including size, margins, + * orientation, and a pointer to the page object itself. Used primarily during + * page insertion and scaling operations. + */ +struct PageProperties +{ + Size size; // Page size dimensions + sal_Int32 left; // Left margin + sal_Int32 right; // Right margin + sal_Int32 upper; // Upper (top) margin + sal_Int32 lower; // Lower (bottom) margin + Orientation orientation; // Page orientation (portrait/landscape) + SdPage* pPage; // Pointer to the page object +}; + +/** + * Document page count information + * + * Tracks counts of different page types during document operations, + * particularly useful during page insertion and master page handling. + */ +struct DocumentPageCounts +{ + sal_uInt16 nDestPageCount; // Count of standard pages in destination document + sal_uInt16 nSourcePageCount; // Count of standard pages in source document + sal_uInt16 nMasterPageCount; // Count of master pages in destination document + sal_uInt16 nNewMPageCount; // Count of new master pages after processing + + DocumentPageCounts(sal_uInt16 destCount, sal_uInt16 sourceCount, sal_uInt16 masterCount) + : nDestPageCount(destCount) + , nSourcePageCount(sourceCount) + , nMasterPageCount(masterCount) + , nNewMPageCount(0) + {} + + // Check if all counts are valid (non-zero) + bool areValid() const { + return !(nDestPageCount == 0 || nSourcePageCount == 0 || nMasterPageCount == 0); + } +}; + +/** + * Parameters related to page insertion operations + * + * Collects all parameters needed for page insertion operations including + * insertion position, bookmark name, replacement count, undo status, scaling options, + * and property information for both main and notes pages. + */ +struct PageInsertionParams +{ + sal_uInt16 nInsertPos; // Position where to insert pages + OUString aBookmarkName; // Name of the bookmark for insertion + sal_uInt16 nReplacedStandardPages; // Number of replaced standard pages + bool bUndo; // Whether undo is enabled + bool bScaleObjects; // Whether to scale objects + PageNameList* pExchangeList; // List of pages for exchange operations + SdDrawDocument* pBookmarkDoc; // Source document for page insertion + PageProperties mainProps; // Properties of main pages (size, borders, etc.) + PageProperties notesProps; // Properties of notes pages (size, borders, etc.) + + PageInsertionParams(sal_uInt16 a_nInsertPos, PageNameList* a_pExchangeList = nullptr, SdDrawDocument* a_pBookmarkDoc = nullptr) + : nInsertPos(a_nInsertPos) + , aBookmarkName(OUString()) + , nReplacedStandardPages(0) + , bUndo(true) + , bScaleObjects(false) + , pExchangeList(a_pExchangeList) + , pBookmarkDoc(a_pBookmarkDoc) + // mainProps and notesProps are default-initialized + {} +}; + + // SdDrawDocument class SD_DLLPUBLIC SdDrawDocument final : public FmFormModel { @@ -197,6 +424,97 @@ private: public: + /** + * Initialize the bookmark document for page/object operations + */ + bool initBookmarkDoc(::sd::DrawDocShell* pBookmarkDocSh, SdDrawDocument*& pBookmarkDoc, OUString& aBookmarkName); + + /** + * Get page properties from the first standard and notes pages + */ + void getPageProperties(PageProperties& mainProps, PageProperties& notesProps, sal_uInt16 nSdPageCount); + + // --- Page insertion and document handling operations --- + + /** + * Insert specific pages selected from the bookmark list + */ + void insertSelectedPages(const PageNameList& rBookmarkList, + PageInsertionParams& rParams, + InsertBookmarkOptions rOptions); + + /** + * Insert all pages from the source document + */ + void insertAllPages(PageInsertionParams& rParams, + const InsertBookmarkOptions& rOptions, + const sal_uInt16& nBMSdPageCount); + + /** + * Determine whether objects should be scaled during insertion + */ + bool determineScaleObjects(bool bNoDialogs, + const PageNameList& rBookmarkList, + PageInsertionParams& rParams); + + /** + * Collect layouts that need to be transferred from source document + */ + void collectLayoutsToTransfer(const PageNameList& rBookmarkList, + SdDrawDocument* pBookmarkDoc, + SlideLayoutNameList& rLayoutsToTransfer, + const sal_uInt16& nBMSdPageCount); + + /** + * Transfer layout styles from source document to destination + */ + void transferLayoutStyles(const SlideLayoutNameList& layoutsToTransfer, + SdDrawDocument* pBookmarkDoc, + SfxUndoManager* pUndoMgr, + StyleTransferContext& rStyleContext); + + /** + * Copy styles between documents with options for replacement and dialog suppression + */ + static void copyStyles(bool bReplace, bool bNoDialogs, + StyleTransferContext& rStyleContext); + + /** + * Remove duplicate master pages after insertion + */ + void removeDuplicateMasterPages(PageInsertionParams& rParams, + DocumentPageCounts& rPageCounts); + + /** + * Update pages after insertion with proper styles and properties + */ + void updateInsertedPages(PageInsertionParams& rParams, + const InsertBookmarkOptions& rOptions, + DocumentPageCounts& rPageCounts, + StyleTransferContext& rStyleContext); + + /** + * Rename object styles if needed after page insertion + */ + void renameObjectStylesIfNeeded(sal_uInt32 nInsertPos, + StyleTransferContext& rStyleContext, + sal_uInt32 nBMSdPageCount); + + /** + * Clean up unused styles after page insertion + */ + void cleanupStyles(SfxUndoManager* pUndoMgr, + StyleTransferContext& rStyleContext); + + /** + * Begin an undoable action for page operations + */ + SfxUndoManager* beginUndoAction(); + + /** + * End an undoable action for page operations + */ + void endUndoAction(bool bUndo, SfxUndoManager* pUndoMgr); SAL_DLLPRIVATE SdDrawDocument(DocumentType eType, SfxObjectShell* pDocSh); SAL_DLLPRIVATE virtual ~SdDrawDocument() override; @@ -305,61 +623,125 @@ public: SAL_DLLPRIVATE void InitObjectVector(); /// return reference to vector of master presentation object definitions SAL_DLLPRIVATE const std::vector<css::uno::Reference<css::xml::dom::XNode> >& GetObjectVector() const { return maPresObjectInfo; } - /** Insert pages into this document - - This method inserts whole pages into this document, either - selected ones (specified via pBookmarkList/pExchangeList), or - all from the source document. - - @attention Beware! This method in its current state does not - handle all combinations of their input parameters - correctly. For example, for pBookmarkList=NULL, bReplace=true - is ignored (no replace happens). - - @param pBookmarkList - A list of strings, denoting the names of the pages to be copied - - @param pExchangeList - A list of strings, denoting the names of the pages to be renamed - - @param bLink - Whether the inserted pages should be linked to the bookmark document - - @param bReplace - Whether the pages should not be inserted, but replace the pages in - the destination document - - @param nPgPos - Insertion point/start of replacement - @param bNoDialogs - Whether query dialogs are allowed (e.g. for page scaling) - @param pBookmarkDocSh - DocShell of the source document (used e.g. to extract the filename - for linked pages) - - @param bCopy - Whether the source document should be treated as immutable (i.e. - inserted pages are not removed from it, but cloned) - - @param bMergeMasterPages - Whether the source document's master pages should be copied, too. - - @param bPreservePageNames - Whether the replace operation should take the name from the new - page, or preserve the old name + /** + * Paste pages from clipboard - handles regular paste operations + * + * This method is called when the user performs a paste operation from the clipboard. + * It handles the insertion of pages that were previously copied or cut to the clipboard. + * + * @param rBookmarkList List of page names to be pasted + * @param pExchangeList Optional list of names to use for the pasted pages + * @param nInsertPos Position where pages should be inserted + * @param pBookmarkDocSh Source document shell + * @param bMergeMasterPages Whether to merge master pages from source + * @return true if operation was successful */ + bool PasteBookmarkAsPage( + const PageNameList &rBookmarkList, + PageNameList *pExchangeList, + sal_uInt16 nInsertPos, + ::sd::DrawDocShell* pBookmarkDocSh, + bool bMergeMasterPages); + + /** + * Insert pages from external files + * + * This method is called when inserting pages from external files, either through + * the Insert > Page from File menu command or when handling file links. + * It manages the transfer of pages from an external document to the current one. + * + * @param rBookmarkList List of page names to be inserted + * @param pExchangeList Optional list of names to use for the inserted pages + * @param bLink Whether to link to the source pages instead of copying + * @param nInsertPos Position where pages should be inserted + * @param pBookmarkDocSh Source document shell + * @return true if operation was successful + */ + bool InsertFileAsPage( + const PageNameList &rBookmarkList, + PageNameList *pExchangeList, + bool bLink, + sal_uInt16 nInsertPos, + ::sd::DrawDocShell* pBookmarkDocSh); + + /** + * Handle drag and drop operations + * + * This method is called when pages are dragged and dropped, either within + * the same document or from another document. It processes the dropped pages + * and inserts them at the specified position. + * + * @param rBookmarkList List of page names to be dropped + * @param nInsertPos Position where pages should be inserted + * @param pBookmarkDocSh Source document shell + * @param bMergeMasterPages Whether to merge master pages from source + * @return true if operation was successful + */ + bool DropBookmarkAsPage( + const PageNameList &rBookmarkList, + sal_uInt16 nInsertPos, + ::sd::DrawDocShell* pBookmarkDocSh, + bool bMergeMasterPages); + + /** + * Resolve page links + * + * This method is called when linked pages need to be resolved, typically + * when a document with linked pages is opened or when the user chooses + * to update or break links to external pages. + * + * @param rBookmarkList List of page names to resolve links for + * @param nInsertPos Position where resolved pages should be inserted + * @param bNoDialogs Whether to suppress dialogs during operation + * @param bCopy Whether to copy the linked pages + * @return true if operation was successful + */ + bool ResolvePageLinks( + const PageNameList &rBookmarkList, + sal_uInt16 nInsertPos, + bool bNoDialogs, + bool bCopy); + + /** + * Copy or move pages within the same document + * + * This method is called for internal page operations such as duplicating pages + * or moving pages within the same document. It handles the copying or moving + * of pages while maintaining proper references and styles. + * + * @param rBookmarkList List of page names to be copied or moved + * @param pExchangeList Optional list of names to use for the destination pages + * @param nInsertPos Position where pages should be inserted + * @param bPreservePageNames Whether to preserve original page names + * @return true if operation was successful + */ + bool CopyOrMovePagesWithinDocument( + const PageNameList &rBookmarkList, + PageNameList *pExchangeList, + sal_uInt16 nInsertPos, + bool bPreservePageNames); + + /** + * Import a whole document + * + * This method is called when importing an entire document, such as when + * using Insert > Document or when merging presentations. It handles the + * transfer of all pages and associated resources from the source document. + * + * @param rBookmarkList List of page names to be imported (empty for all pages) + * @param nInsertPos Position where imported pages should be inserted + * @param pBookmarkDocSh Source document shell + * @return true if operation was successful + */ + bool ImportDocumentPages( + const PageNameList &rBookmarkList, + sal_uInt16 nInsertPos, + ::sd::DrawDocShell* pBookmarkDocSh); - bool InsertBookmarkAsPage(const std::vector<OUString> &rBookmarkList, - std::vector<OUString> *pExchangeList, - bool bLink, bool bReplace, sal_uInt16 nPgPos, - bool bNoDialogs, ::sd::DrawDocShell* pBookmarkDocSh, - bool bCopy, bool bMergeMasterPages, - bool bPreservePageNames); - - SAL_DLLPRIVATE bool InsertBookmarkAsObject(const std::vector<OUString> &rBookmarkList, - const std::vector<OUString> &rExchangeList, + SAL_DLLPRIVATE bool InsertBookmarkAsObject(const PageNameList &rBookmarkList, + const PageNameList &rExchangeList, ::sd::DrawDocShell* pBookmarkDocSh, Point const * pObjPos, bool bCalcObjCount); diff --git a/sd/qa/unit/misc-tests.cxx b/sd/qa/unit/misc-tests.cxx index 59628256fcce..5c1693b85f96 100644 --- a/sd/qa/unit/misc-tests.cxx +++ b/sd/qa/unit/misc-tests.cxx @@ -902,8 +902,7 @@ void SdMiscTest::testTdf39519() // Insert a bookmark as a new page using the same name std::vector<OUString> aBookmarkList = { u"Test"_ustr }; - pDoc->InsertBookmarkAsPage(aBookmarkList, nullptr, false, false, 2, true, pDoc->GetDocSh(), - true, false, false); + pDoc->CopyOrMovePagesWithinDocument(aBookmarkList, nullptr, 2, false); // Check if the copied page has a different name SdPage* pCopiedPage = static_cast<SdPage*>(pDoc->GetPage(2)); @@ -925,8 +924,7 @@ void SdMiscTest::testTdf164284() // Move a bookmark as a page using the same name pDoc->DoMakePageObjectsNamesUnique(false); std::vector<OUString> aBookmarkList = { u"Test"_ustr }; - pDoc->InsertBookmarkAsPage(aBookmarkList, nullptr, false, false, 2, true, pDoc->GetDocSh(), - true, false, false); + pDoc->CopyOrMovePagesWithinDocument(aBookmarkList, nullptr, 2, true); // Check if the moved page has the same name SdPage* pMovedPage = static_cast<SdPage*>(pDoc->GetPage(2)); diff --git a/sd/qa/unit/uiimpress.cxx b/sd/qa/unit/uiimpress.cxx index 45f9bf0815d7..e0f0b7db26ff 100644 --- a/sd/qa/unit/uiimpress.cxx +++ b/sd/qa/unit/uiimpress.cxx @@ -542,6 +542,44 @@ CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf96206) CPPUNIT_ASSERT_EQUAL(nMasterPageCnt1, nMasterPageCnt2); } +CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testDocumentCut) +{ + // Test cutting slides and verifying the document state afterwards + createSdImpressDoc("odp/tdf96206.odp"); + + // Get the slide sorter and controller + sd::slidesorter::SlideSorterViewShell* pSSVS = getSlideSorterViewShell(); + auto& rSSController = pSSVS->GetSlideSorter().GetController(); + + // Get document and initial page count + SdXImpressDocument* pXImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get()); + SdDrawDocument* pDoc = pXImpressDocument->GetDoc(); + + // Get initial page count + const sal_uInt16 nInitialPageCount = pDoc->GetSdPageCount(PageKind::Standard); + CPPUNIT_ASSERT(nInitialPageCount > 0); + + // Select all slides + rSSController.GetPageSelector().SelectAllPages(); + + // Check that slides are selected + CPPUNIT_ASSERT(rSSController.GetPageSelector().GetSelectedPageCount() > 0); + + // Cut the selected slides + rSSController.GetClipboard().DoCut(); + + // Paste the cut slides + rSSController.GetClipboard().DoPaste(); + + // After pasting, we should have at least the initial number of pages + const sal_uInt16 nPageCountAfterPaste = pDoc->GetSdPageCount(PageKind::Standard); + CPPUNIT_ASSERT(nPageCountAfterPaste >= nInitialPageCount); + + // Verify that master page count remains unchanged throughout the operation + const sal_uInt16 nMasterPageCount = pDoc->GetMasterSdPageCount(PageKind::Standard); + CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), nMasterPageCount); +} + CPPUNIT_TEST_FIXTURE(SdUiImpressTest, testTdf96708) { createSdImpressDoc("odp/tdf96708.odp"); diff --git a/sd/source/core/drawdoc3.cxx b/sd/source/core/drawdoc3.cxx index 3e8c088e1067..fa5173cefe2b 100644 --- a/sd/source/core/drawdoc3.cxx +++ b/sd/source/core/drawdoc3.cxx @@ -314,8 +314,8 @@ void SdDrawDocument::InsertBookmark( if ( bOK && bInsertPages ) { // Insert all page bookmarks - bOK = InsertBookmarkAsPage(rBookmarkList, &rExchangeList, bLink, false/*bReplace*/, - nInsertPos, false/*bNoDialogs*/, pBookmarkDocSh, true/*bCopy*/, true, false); + bOK = InsertFileAsPage(rBookmarkList, &rExchangeList, + bLink, nInsertPos, pBookmarkDocSh); } if ( bOK && !rBookmarkList.empty() ) @@ -371,25 +371,11 @@ SfxStyleSheet *lcl_findStyle(StyleSheetCopyResultVector& rStyles, std::u16string } -bool SdDrawDocument::InsertBookmarkAsPage( - const std::vector<OUString> &rBookmarkList, - std::vector<OUString> *pExchangeList, // List of names to be used - bool bLink, - bool bReplace, - sal_uInt16 nInsertPos, - bool bNoDialogs, +bool SdDrawDocument::initBookmarkDoc( ::sd::DrawDocShell* pBookmarkDocSh, - bool bCopy, - bool bMergeMasterPages, - bool bPreservePageNames) + SdDrawDocument*& pBookmarkDoc, + OUString& aBookmarkName) { - bool bContinue = true; - bool bScaleObjects = false; - sal_uInt16 nReplacedStandardPages = 0; - - SdDrawDocument* pBookmarkDoc = nullptr; - OUString aBookmarkName; - if (pBookmarkDocSh) { pBookmarkDoc = pBookmarkDocSh->GetDoc(); @@ -408,40 +394,39 @@ bool SdDrawDocument::InsertBookmarkAsPage( { return false; } + return true; +} - const sal_uInt16 nSdPageCount = GetSdPageCount(PageKind::Standard); - const sal_uInt16 nBMSdPageCount = pBookmarkDoc->GetSdPageCount(PageKind::Standard); - const sal_uInt16 nMPageCount = GetMasterPageCount(); - - if (nSdPageCount==0 || nBMSdPageCount==0 || nMPageCount==0) - { - return false; - } - - // Store the size and some other properties of the first page and notes - // page so that inserted pages can be properly scaled even when inserted - // before the first page. - // Note that the pointers are used later on as general page pointers. - SdPage* pRefPage = GetSdPage(0, PageKind::Standard); - Size aSize(pRefPage->GetSize()); - sal_Int32 nLeft = pRefPage->GetLeftBorder(); - sal_Int32 nRight = pRefPage->GetRightBorder(); - sal_Int32 nUpper = pRefPage->GetUpperBorder(); - sal_Int32 nLower = pRefPage->GetLowerBorder(); - Orientation eOrient = pRefPage->GetOrientation(); - - SdPage* pNPage = GetSdPage(0, PageKind::Notes); - Size aNSize(pNPage->GetSize()); - sal_Int32 nNLeft = pNPage->GetLeftBorder(); - sal_Int32 nNRight = pNPage->GetRightBorder(); - sal_Int32 nNUpper = pNPage->GetUpperBorder(); - sal_Int32 nNLower = pNPage->GetLowerBorder(); - Orientation eNOrient = pNPage->GetOrientation(); - - // Adapt page size and margins to those of the later pages? - pRefPage = GetSdPage(nSdPageCount - 1, PageKind::Standard); +void SdDrawDocument::getPageProperties(PageProperties& mainProps, PageProperties& notesProps , sal_uInt16 nSdPageCount) +{ + // Get the properties from the first Standard page. + mainProps.pPage = GetSdPage(0, PageKind::Standard); + mainProps.size = mainProps.pPage->GetSize(); + mainProps.left = mainProps.pPage->GetLeftBorder(); + mainProps.right = mainProps.pPage->GetRightBorder(); + mainProps.upper = mainProps.pPage->GetUpperBorder(); + mainProps.lower = mainProps.pPage->GetLowerBorder(); + mainProps.orientation = mainProps.pPage->GetOrientation(); + + // Similarly for the first Notes page. + notesProps.pPage = GetSdPage(0, PageKind::Notes); + notesProps.size = notesProps.pPage->GetSize(); + notesProps.left = notesProps.pPage->GetLeftBorder(); + notesProps.right = notesProps.pPage->GetRightBorder(); + notesProps.upper = notesProps.pPage->GetUpperBorder(); + notesProps.lower = notesProps.pPage->GetLowerBorder(); + notesProps.orientation = notesProps.pPage->GetOrientation(); + + // Adapt the main page properties using the last standard page. + mainProps.pPage = GetSdPage(nSdPageCount - 1, PageKind::Standard); +} - if( bNoDialogs ) +bool SdDrawDocument::determineScaleObjects(bool bNoDialogs, + const PageNameList& rBookmarkList, + PageInsertionParams& rParams) +{ + // In dialog-less mode, decide based on transfer container and page settings. + if (bNoDialogs) { SdModule* mod = SdModule::get(); // If this is clipboard, then no need to scale objects: @@ -449,46 +434,44 @@ bool SdDrawDocument::InsertBookmarkAsPage( // and thus InsertBookmarkAsPage_FindDuplicateLayouts will // duplicate masters on insert to same document m_bTransportContainer = (mod->pTransferClip && - mod->pTransferClip->GetWorkDocument() == this); + mod->pTransferClip->GetWorkDocument() == this); if (!m_bTransportContainer) { if (rBookmarkList.empty()) - bScaleObjects = pRefPage->IsScaleObjects(); + rParams.bScaleObjects = rParams.mainProps.pPage->IsScaleObjects(); else - bScaleObjects = true; + rParams.bScaleObjects = true; } } else { - SdPage* pBMPage = pBookmarkDoc->GetSdPage(0,PageKind::Standard); - - if (pBMPage->GetSize() != pRefPage->GetSize() || - pBMPage->GetLeftBorder() != pRefPage->GetLeftBorder() || - pBMPage->GetRightBorder() != pRefPage->GetRightBorder() || - pBMPage->GetUpperBorder() != pRefPage->GetUpperBorder() || - pBMPage->GetLowerBorder() != pRefPage->GetLowerBorder()) + // If not dialog-less, compare the first bookmark page with our reference page. + SdPage* pBMPage = rParams.pBookmarkDoc->GetSdPage(0, PageKind::Standard); + if (pBMPage->GetSize() != rParams.mainProps.pPage->GetSize() || + pBMPage->GetLeftBorder() != rParams.mainProps.pPage->GetLeftBorder() || + pBMPage->GetRightBorder() != rParams.mainProps.pPage->GetRightBorder() || + pBMPage->GetUpperBorder() != rParams.mainProps.pPage->GetUpperBorder() || + pBMPage->GetLowerBorder() != rParams.mainProps.pPage->GetLowerBorder()) { OUString aStr(SdResId(STR_SCALE_OBJECTS)); std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr, - VclMessageType::Question, VclButtonsType::YesNo, - aStr)); + VclMessageType::Question, VclButtonsType::YesNo, + aStr)); xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); sal_uInt16 nBut = xQueryBox->run(); - - bScaleObjects = nBut == RET_YES; - bContinue = nBut != RET_CANCEL; - + rParams.bScaleObjects = (nBut == RET_YES); + bool bContinue = (nBut != RET_CANCEL); if (!bContinue) - { return bContinue; - } } } + return true; +} - // Get the necessary presentation stylesheets and transfer them before - // the pages, else, the text objects won't reference their styles anymore. +SfxUndoManager* SdDrawDocument::beginUndoAction() +{ SfxUndoManager* pUndoMgr = nullptr; - if( mpDocSh ) + if ( mpDocSh ) { pUndoMgr = mpDocSh->GetUndoManager(); ViewShellId nViewShellId(-1); @@ -496,28 +479,33 @@ bool SdDrawDocument::InsertBookmarkAsPage( nViewShellId = pViewShell->GetViewShellBase().GetViewShellId(); pUndoMgr->EnterListAction(SdResId(STR_UNDO_INSERTPAGES), u""_ustr, 0, nViewShellId); } + return pUndoMgr; +} - // Refactored copy'n'pasted layout name collection into IterateBookmarkPages - - std::vector<OUString> aLayoutsToTransfer; - InsertBookmarkAsPage_FindDuplicateLayouts aSearchFunctor( aLayoutsToTransfer ); +void SdDrawDocument::collectLayoutsToTransfer(const PageNameList& rBookmarkList, + SdDrawDocument* pBookmarkDoc, + SlideLayoutNameList& aLayoutsToTransfer, + const sal_uInt16& nBMSdPageCount) +{ + InsertBookmarkAsPage_FindDuplicateLayouts aSearchFunctor(aLayoutsToTransfer); lcl_IterateBookmarkPages( *this, pBookmarkDoc, rBookmarkList, nBMSdPageCount, aSearchFunctor, ( rBookmarkList.empty() && pBookmarkDoc != this ) ); +} - // Copy the style that we actually need. - SdStyleSheetPool& rBookmarkStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*pBookmarkDoc->GetStyleSheetPool()); - SdStyleSheetPool& rStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*GetStyleSheetPool()); - - // When copying styles, also copy the master pages! - if( !aLayoutsToTransfer.empty() ) - bMergeMasterPages = true; +void SdDrawDocument::transferLayoutStyles(const SlideLayoutNameList& aLayoutsToTransfer, + SdDrawDocument* pBookmarkDoc, + SfxUndoManager* pUndoMgr, + StyleTransferContext& rStyleContext) +{ + // For each layout in the list, copy the layout styles and, if the layout + // is from a master page, also copy theme and layout ID. - std::map<OUString, sal_Int32> aSlideLayoutsToTransfer; - std::map<OUString, std::shared_ptr<model::Theme>> aThemesToTransfer; + // Use the style sheet pools from the context + SdStyleSheetPool& rBookmarkStyleSheetPool = *rStyleContext.pSourceStyleSheetPool; + SdStyleSheetPool& rStyleSheetPool = *rStyleContext.pDestStyleSheetPool; - for ( const OUString& layoutName : aLayoutsToTransfer ) + for (const OUString& layoutName : aLayoutsToTransfer) { StyleSheetCopyResultVector aCreatedStyles; - rStyleSheetPool.CopyLayoutSheets(layoutName, rBookmarkStyleSheetPool, aCreatedStyles); if(!aCreatedStyles.empty()) @@ -529,6 +517,7 @@ bool SdDrawDocument::InsertBookmarkAsPage( } // copy SlideLayout and Theme of the master slide + // If the layout belongs to a master page, extract its theme and layout ID. sal_Int32 nLayout = 20; // blank page - master slide layout ID bool bIsMasterPage = false; sal_uInt16 nBMPage = pBookmarkDoc->GetPageByName(layoutName, bIsMasterPage); @@ -538,7 +527,9 @@ bool SdDrawDocument::InsertBookmarkAsPage( SdrPage* pMasterPage = SdPage::getImplementation(xOldPage); if (pMasterPage) { - aThemesToTransfer.insert({ layoutName, pMasterPage->getSdrPageProperties().getTheme() }); + rStyleContext.aThemes.insert({ layoutName, pMasterPage->getSdrPageProperties().getTheme() }); + + // Retrieve the SlideLayout property via the property set. uno::Reference<beans::XPropertySet> xPropSet(xOldPage, uno::UNO_QUERY_THROW); if (xPropSet.is()) { @@ -548,449 +539,435 @@ bool SdDrawDocument::InsertBookmarkAsPage( } } } - aSlideLayoutsToTransfer.insert({ layoutName, nLayout }); + rStyleContext.aSlideLayouts.insert({ layoutName, nLayout }); } } +} - // Copy styles. This unconditionally copies all styles, even those - // that are not used in any of the inserted pages. The unused styles - // are then removed at the end of the function, where we also create - // undo records for the inserted styles. - StyleSheetCopyResultVector aNewGraphicStyles; - OUString aRenameStr; - if(!bReplace && !bNoDialogs) - aRenameStr = "_"; - rStyleSheetPool.RenameAndCopyGraphicSheets(rBookmarkStyleSheetPool, aNewGraphicStyles, aRenameStr); - StyleSheetCopyResultVector aNewCellStyles; - rStyleSheetPool.CopyCellSheets(rBookmarkStyleSheetPool, aNewCellStyles); - +void SdDrawDocument::copyStyles(bool bReplace, bool bNoDialogs, + StyleTransferContext& rStyleContext) +{ + // Use the style sheet pools from the context + SdStyleSheetPool& rBookmarkStyleSheetPool = *rStyleContext.pSourceStyleSheetPool; + SdStyleSheetPool& rStyleSheetPool = *rStyleContext.pDestStyleSheetPool; + + // Depending on whether pages are being replaced and dialog mode, + // decide on a renaming string and then copy graphic, cell, and table styles. + if (!bReplace && !bNoDialogs) + rStyleContext.aRenameString = "_"; + rStyleSheetPool.RenameAndCopyGraphicSheets(rBookmarkStyleSheetPool, rStyleContext.aGraphicStyles, rStyleContext.aRenameString); + rStyleSheetPool.CopyCellSheets(rBookmarkStyleSheetPool, rStyleContext.aCellStyles); // TODO handle undo of table styles too - XStyleVector aNewTableStyles; - rStyleSheetPool.CopyTableStyles(rBookmarkStyleSheetPool, aNewTableStyles); + rStyleSheetPool.CopyTableStyles(rBookmarkStyleSheetPool, rStyleContext.aTableStyles); +} - // Insert document +void SdDrawDocument::insertAllPages(PageInsertionParams& rParams, + const InsertBookmarkOptions& rOptions, + const sal_uInt16& nBMSdPageCount) +{ + // Adjust insertion position if needed. + if (rParams.nInsertPos >= GetPageCount()) + rParams.nInsertPos = GetPageCount(); - const bool bUndo = IsUndoEnabled(); + sal_uInt16 nActualInsertPos = rParams.nInsertPos; - if( bUndo ) - BegUndo(SdResId(STR_UNDO_INSERTPAGES)); + sal_uInt16 nBMSdPage; + // Build a name map and a set for pages that need renaming. + std::set<sal_uInt16> aRenameSet; + std::map<sal_uInt16, OUString> aNameMap; - if (rBookmarkList.empty()) + for (nBMSdPage = 0; nBMSdPage < nBMSdPageCount; nBMSdPage++) { - if (nInsertPos >= GetPageCount()) + SdPage* pBMPage = rParams.pBookmarkDoc->GetSdPage(nBMSdPage, PageKind::Standard); + OUString sName(pBMPage->GetName()); + bool bIsMasterPage; + + if (rOptions.bLink) { - // Add pages to the end - nInsertPos = GetPageCount(); + // Remember the names of all pages + aNameMap.insert(std::make_pair(nBMSdPage,sName)); } - sal_uInt16 nActualInsertPos = nInsertPos; - - sal_uInt16 nBMSdPage; - std::set<sal_uInt16> aRenameSet; - std::map<sal_uInt16,OUString> aNameMap; - - for (nBMSdPage=0; nBMSdPage < nBMSdPageCount; nBMSdPage++) + // Have to check for duplicate names here, too + // don't change name if source and dest model are the same! + if( rParams.pBookmarkDoc != this && + GetPageByName(sName, bIsMasterPage ) != SDRPAGE_NOTFOUND ) { - SdPage* pBMPage = pBookmarkDoc->GetSdPage(nBMSdPage, PageKind::Standard); - OUString sName(pBMPage->GetName()); - bool bIsMasterPage; - - if (bLink) - { - // Remember the names of all pages - aNameMap.insert(std::make_pair(nBMSdPage,sName)); - } - - // Have to check for duplicate names here, too - // don't change name if source and dest model are the same! - if( pBookmarkDoc != this && - GetPageByName(sName, bIsMasterPage ) != SDRPAGE_NOTFOUND ) - { - // delay renaming *after* pages are copied (might destroy source otherwise) - aRenameSet.insert(nBMSdPage); - } + // delay renaming *after* pages are copied (might destroy source otherwise) + aRenameSet.insert(nBMSdPage); } + } - Merge(*pBookmarkDoc, - 1, // Not the handout page - 0xFFFF, // But all others - nActualInsertPos, // Insert at position ... - bMergeMasterPages, // Move master pages? - false, // But only the master pages used - true, // Create an undo action - bCopy); // Copy (or merge) pages? + // Merge the pages from the bookmark document. + Merge(*rParams.pBookmarkDoc, + 1, // Not the handout page + SDRPAGE_NOTFOUND, // But all others + nActualInsertPos, // Insert at position ... + rOptions.bMergeMasterPages, // Move master pages? + false, // But only the master pages used + true, // Create an undo action + rOptions.bCopy); // Copy (or merge) pages? + + // After merging, fix names and set link info if needed. + for ( nBMSdPage = 0; nBMSdPage < nBMSdPageCount; nBMSdPage++) + { + SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) ); + SdPage* pNotesPage = static_cast<SdPage*>( GetPage(nActualInsertPos + 1) ); - for (nBMSdPage=0; nBMSdPage < nBMSdPageCount; nBMSdPage++) + // delay renaming *after* pages are copied (might destroy source otherwise) + if ( aRenameSet.find(nBMSdPage) != aRenameSet.end() ) { - SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) ); - SdPage* pNotesPage = static_cast<SdPage*>( GetPage(nActualInsertPos+1) ); - - // delay renaming *after* pages are copied (might destroy source otherwise) - if( aRenameSet.find(nBMSdPage) != aRenameSet.end() ) - { - // Page name already in use -> Use default name for default and - // notes page - pPage->SetName(OUString()); - pNotesPage->SetName(OUString()); - } + // Page name already in use -> Use default name for default and + // notes page + pPage->SetName(OUString()); + pNotesPage->SetName(OUString()); + } + if (rOptions.bLink) + { + // Assemble all link names + pPage->SetFileName(rParams.aBookmarkName); + pPage->SetBookmarkName(aNameMap[nBMSdPage]); + } + nActualInsertPos += 2; + } +} - if (bLink) - { - OUString aName(aNameMap[nBMSdPage]); +void SdDrawDocument::insertSelectedPages(const PageNameList& rBookmarkList, + PageInsertionParams& rParams, + InsertBookmarkOptions rOptions) +{ + // Adjust insertion position if necessary. + if (rParams.nInsertPos >= GetPageCount()) + { + // Add pages to the end + rOptions.bReplace = false; + rParams.nInsertPos = GetPageCount(); + } - // Assemble all link names - pPage->SetFileName(aBookmarkName); - pPage->SetBookmarkName(aName); - } + sal_uInt16 nActualInsertPos = rParams.nInsertPos; - nActualInsertPos += 2; - } - } - else + // Build a vector of pointers to bookmarked pages. + std::vector<SdPage*> aBookmarkedPages(rBookmarkList.size(), nullptr); + for (size_t nPos = 0; nPos < rBookmarkList.size(); ++nPos) { - // Insert selected pages - SdPage* pBMPage; + const OUString& aPgName(rBookmarkList[nPos]); + bool bIsMasterPage = false; + sal_uInt16 nBMPage = rParams.pBookmarkDoc->GetPageByName( aPgName, bIsMasterPage); - if (nInsertPos >= GetPageCount()) + if (nBMPage != SDRPAGE_NOTFOUND) { - // Add pages to the end - bReplace = false; - nInsertPos = GetPageCount(); + aBookmarkedPages[nPos] = dynamic_cast<SdPage*>(rParams.pBookmarkDoc->GetPage(nBMPage)); } + } - sal_uInt16 nActualInsertPos = nInsertPos; + // Process each bookmarked page. + for ( size_t nPos = 0; nPos < rBookmarkList.size(); ++nPos) + { + SdPage* pBMPage = aBookmarkedPages[nPos]; + sal_uInt16 nBMPage = pBMPage!=nullptr ? pBMPage->GetPageNum() : SDRPAGE_NOTFOUND; - // Collect the bookmarked pages - ::std::vector<SdPage*> aBookmarkedPages (rBookmarkList.size(), nullptr); - for ( size_t nPos = 0, n = rBookmarkList.size(); nPos < n; ++nPos) + if (pBMPage && pBMPage->GetPageKind() == PageKind::Standard && !pBMPage->IsMasterPage()) { + // It has to be a default page + bool bMustRename = false; + // delay renaming *after* pages are copied (might destroy source otherwise) + // don't change name if source and dest model are the same! + // avoid renaming if replacing the same page const OUString& aPgName(rBookmarkList[nPos]); - bool bIsMasterPage; - sal_uInt16 nBMPage = pBookmarkDoc->GetPageByName( aPgName, bIsMasterPage ); - - if (nBMPage != SDRPAGE_NOTFOUND) + bool bIsMasterPage; + sal_uInt16 nPageSameName = GetPageByName(aPgName, bIsMasterPage); + if ( rParams.pBookmarkDoc != this && + nPageSameName != SDRPAGE_NOTFOUND && + ( !rOptions.bReplace || nPageSameName != nActualInsertPos)) { - aBookmarkedPages[nPos] = dynamic_cast<SdPage*>(pBookmarkDoc->GetPage(nBMPage)); + bMustRename = true; } - } - for ( size_t nPos = 0, n = rBookmarkList.size(); nPos < n; ++nPos) - { - pBMPage = aBookmarkedPages[nPos]; - sal_uInt16 nBMPage = pBMPage!=nullptr ? pBMPage->GetPageNum() : SDRPAGE_NOTFOUND; + SdPage* pBookmarkPage = pBMPage; + if (rOptions.bReplace) + ReplacePageInCustomShows(dynamic_cast<SdPage*>(GetPage(nActualInsertPos)), pBMPage); - if (pBMPage && pBMPage->GetPageKind()==PageKind::Standard && !pBMPage->IsMasterPage()) + Merge(*rParams.pBookmarkDoc, + nBMPage, // From page (default page) + nBMPage+1, // To page (notes page) + nActualInsertPos, // Insert at position + rOptions.bMergeMasterPages, // Move master pages? + false, // But only the master pages used + true, // Create undo action + rOptions.bCopy); // Copy (or merge) pages? + + if (rOptions.bReplace && GetPage(nActualInsertPos) != pBookmarkPage) + { + // bookmark page was not moved but cloned, so update custom shows again + ReplacePageInCustomShows(pBMPage, dynamic_cast<SdPage*>(GetPage(nActualInsertPos))); + } + // tdf#39519 - rename page if its name is not unique, e.g., if a slide is copied by + // ctrl + drag and drop (DND_ACTION_COPY) + if (bMustRename + // tdf#164284 - prevent page name change during page move + || (rParams.pBookmarkDoc->DoesMakePageObjectsNamesUnique() + && !mpDocSh->IsPageNameUnique(aPgName))) { - // It has to be a default page - bool bMustRename = false; + // Page name already in use -> use default name for default and + // notes page + SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) ); + pPage->SetName(OUString()); + SdPage* pNotesPage = static_cast<SdPage*>( GetPage(nActualInsertPos+1) ); + pNotesPage->SetName(OUString()); + } - // delay renaming *after* pages are copied (might destroy source otherwise) - // don't change name if source and dest model are the same! - // avoid renaming if replacing the same page - const OUString& aPgName(rBookmarkList[nPos]); - bool bIsMasterPage; - sal_uInt16 nPageSameName = GetPageByName(aPgName, bIsMasterPage); - if( pBookmarkDoc != this && - nPageSameName != SDRPAGE_NOTFOUND && - ( !bReplace || - nPageSameName != nActualInsertPos ) ) - { - bMustRename = true; - } + if (rOptions.bLink) + { + SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) ); + pPage->SetFileName(rParams.aBookmarkName); + pPage->SetBookmarkName(aPgName); + } - SdPage* pBookmarkPage = pBMPage; - if (bReplace ) + if (rOptions.bReplace) + { + // Remove the replaced page(s) + const sal_uInt16 nDestPageNum(nActualInsertPos + 2); + SdPage* pStandardPage = nullptr; + + if (nDestPageNum < GetPageCount()) { - ReplacePageInCustomShows( dynamic_cast< SdPage* >( GetPage( nActualInsertPos ) ), pBookmarkPage ); + pStandardPage = static_cast<SdPage*>(GetPage(nDestPageNum)); } - Merge(*pBookmarkDoc, - nBMPage, // From page (default page) - nBMPage+1, // To page (notes page) - nActualInsertPos, // Insert at position - bMergeMasterPages, // Move master pages? - false, // But only the master pages used - true, // Create undo action - bCopy); // Copy (or merge) pages? - - if( bReplace ) + if (pStandardPage) { - if( GetPage( nActualInsertPos ) != pBookmarkPage ) + if( rOptions.bPreservePageNames ) { - // bookmark page was not moved but cloned, so update custom shows again - ReplacePageInCustomShows( pBookmarkPage, dynamic_cast< SdPage* >( GetPage( nActualInsertPos ) ) ); + // Take old slide names for inserted pages + SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) ); + pPage->SetName( pStandardPage->GetRealName() ); } - } - // tdf#39519 - rename page if its name is not unique, e.g., if a slide is copied by - // ctrl + drag and drop (DND_ACTION_COPY) - if (bMustRename - // tdf#164284 - prevent page name change during page move - || (pBookmarkDoc->DoesMakePageObjectsNamesUnique() - && !mpDocSh->IsPageNameUnique(aPgName))) - { - // Page name already in use -> use default name for default and - // notes page - SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) ); - pPage->SetName(OUString()); - SdPage* pNotesPage = static_cast<SdPage*>( GetPage(nActualInsertPos+1) ); - pNotesPage->SetName(OUString()); + if( rParams.bUndo ) + AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*pStandardPage)); + + RemovePage(nDestPageNum); } - if (bLink) + SdPage* pNotesPage = nullptr; + if (nDestPageNum < GetPageCount()) { - SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) ); - pPage->SetFileName(aBookmarkName); - pPage->SetBookmarkName(aPgName); + pNotesPage = static_cast<SdPage*>(GetPage(nDestPageNum)); } - if (bReplace) + if (pNotesPage) { - // Remove page and notes page. - const sal_uInt16 nDestPageNum(nActualInsertPos + 2); - SdPage* pStandardPage = nullptr; - - if(nDestPageNum < GetPageCount()) - { - pStandardPage = static_cast<SdPage*>(GetPage(nDestPageNum)); - } - - if (pStandardPage) + if (rOptions.bPreservePageNames) { - if( bPreservePageNames ) - { - // Take old slide names for inserted pages - SdPage* pPage = static_cast<SdPage*>( GetPage(nActualInsertPos) ); - pPage->SetName( pStandardPage->GetRealName() ); - } - - if( bUndo ) - AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*pStandardPage)); - - RemovePage(nDestPageNum); - } - - SdPage* pNotesPage = nullptr; + // Take old slide names for inserted pages + SdPage* pNewNotesPage = static_cast<SdPage*>( GetPage(nActualInsertPos+1)); - if(nDestPageNum < GetPageCount()) - { - pNotesPage = static_cast<SdPage*>(GetPage(nDestPageNum)); + if (pNewNotesPage) + pNewNotesPage->SetName(pStandardPage->GetRealName()); } - if (pNotesPage) - { - if( bPreservePageNames ) - { - // Take old slide names for inserted pages - SdPage* pNewNotesPage = static_cast<SdPage*>( GetPage(nActualInsertPos+1)); - if( pNewNotesPage ) - pNewNotesPage->SetName( pStandardPage->GetRealName() ); - } - - if( bUndo ) - AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*pNotesPage)); - - RemovePage(nDestPageNum); - } + if( rParams.bUndo ) + AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*pNotesPage)); - nReplacedStandardPages++; + RemovePage(nDestPageNum); } - - nActualInsertPos += 2; + rParams.nReplacedStandardPages++; } + + nActualInsertPos += 2; } } +} +void SdDrawDocument::removeDuplicateMasterPages(PageInsertionParams& rParams, + DocumentPageCounts& rPageCounts) +{ + // Remove duplicate master pages created during the merge. // We might have duplicate master pages now, as the drawing engine does not // recognize duplicates. Remove these now. - sal_uInt16 nNewMPageCount = GetMasterPageCount(); + rPageCounts.nNewMPageCount = GetMasterPageCount(); // Go backwards, so the numbers don't become messed up - for (sal_uInt16 nPage = nNewMPageCount - 1; nPage >= nMPageCount; nPage--) + for (sal_uInt16 nPage = rPageCounts.nNewMPageCount - 1; nPage >= rPageCounts.nMasterPageCount; nPage--) { - pRefPage = static_cast<SdPage*>( GetMasterPage(nPage) ); - OUString aMPLayout(pRefPage->GetLayoutName()); - PageKind eKind = pRefPage->GetPageKind(); - - // Does this already exist? - for (sal_uInt16 nTest = 0; nTest < nMPageCount; nTest++) + rParams.mainProps.pPage = static_cast<SdPage*>(GetMasterPage(nPage)); + OUString aMPLayout (rParams.mainProps.pPage->GetLayoutName()); + PageKind eKind = rParams.mainProps.pPage->GetPageKind(); + // Check against the original set of master pages. + for (sal_uInt16 nTest = 0; nTest < rPageCounts.nMasterPageCount; nTest++) { - SdPage* pTest = static_cast<SdPage*>( GetMasterPage(nTest) ); + SdPage* pTest = static_cast<SdPage*>( GetMasterPage(nTest)); OUString aTest(pTest->GetLayoutName()); - // nInsertPos > 2 is always true when inserting into non-empty models - if ( nInsertPos > 2 && - aTest == aMPLayout && - eKind == pTest->GetPageKind() ) + if (aTest == aMPLayout && eKind == pTest->GetPageKind() && rParams.nInsertPos > 2) { - if( bUndo ) - AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*pRefPage)); - + if(rParams.bUndo) + AddUndo(GetSdrUndoFactory().CreateUndoDeletePage(*rParams.mainProps.pPage)); RemoveMasterPage(nPage); - - nNewMPageCount--; + rPageCounts.nNewMPageCount--; break; } } } + // Optionally, update remaining master pages with new themes/layout IDs. +} - // nInsertPos > 2 is always true when inserting into non-empty models - if (nInsertPos > 0) - { - sal_uInt16 nSdPageStart = (nInsertPos - 1) / 2; - sal_uInt16 nSdPageEnd = bReplace - ? nSdPageStart + nReplacedStandardPages - 1 - : GetSdPageCount(PageKind::Standard) - nSdPageCount + nSdPageStart - 1; - const bool bRemoveEmptyPresObj = - (pBookmarkDoc->GetDocumentType() == DocumentType::Impress) && - (GetDocumentType() == DocumentType::Draw); +void SdDrawDocument::updateInsertedPages(PageInsertionParams& rParams, + const InsertBookmarkOptions& rOptions, + DocumentPageCounts& rPageCounts, + StyleTransferContext& rStyleContext) +{ + // Update page names (from pExchangeList), layouts, scaling, etc. + sal_uInt16 nSdPageStart = (rParams.nInsertPos - 1) / 2; + sal_uInt16 nSdPageEnd = rOptions.bReplace + ? nSdPageStart + rParams.nReplacedStandardPages - 1 // if replacing, update only the replaced pages + : GetSdPageCount(PageKind::Standard) - rPageCounts.nDestPageCount + nSdPageStart - 1; - std::vector<OUString>::iterator pExchangeIter; + const bool bRemoveEmptyPresObj = + (rParams.pBookmarkDoc->GetDocumentType() == DocumentType::Impress) && + (GetDocumentType() == DocumentType::Draw); - if (pExchangeList) - pExchangeIter = pExchangeList->begin(); + std::vector<OUString>::iterator pExchangeIter; + if (rParams.pExchangeList) + pExchangeIter = rParams.pExchangeList->begin(); - for (sal_uInt16 nSdPage = nSdPageStart; nSdPage <= nSdPageEnd; nSdPage++) + for (sal_uInt16 nSdPage = nSdPageStart; nSdPage <= nSdPageEnd; ++nSdPage) + { + rParams.mainProps.pPage = GetSdPage(nSdPage, PageKind::Standard); + if (rParams.pExchangeList && pExchangeIter != rParams.pExchangeList->end()) { - pRefPage = GetSdPage(nSdPage, PageKind::Standard); - - if (pExchangeList && pExchangeIter != pExchangeList->end()) - { - // Get the name to use from Exchange list - OUString aExchangeName(*pExchangeIter); - pRefPage->SetName(aExchangeName); - Broadcast(SdrHint(SdrHintKind::PageOrderChange, pRefPage)); - - SdPage* pNewNotesPage = GetSdPage(nSdPage, PageKind::Notes); - pNewNotesPage->SetName(aExchangeName); - Broadcast(SdrHint(SdrHintKind::PageOrderChange, pNewNotesPage)); - - ++pExchangeIter; - } + OUString aExchangeName(*pExchangeIter); + rParams.mainProps.pPage->SetName(aExchangeName); + Broadcast(SdrHint(SdrHintKind::PageOrderChange, rParams.mainProps.pPage)); - OUString aLayout(pRefPage->GetLayoutName()); - sal_Int32 nIndex = aLayout.indexOf( SD_LT_SEPARATOR ); - if( nIndex != -1 ) - aLayout = aLayout.copy(0, nIndex); + SdPage* pNotesPage = GetSdPage(nSdPage, PageKind::Notes); + pNotesPage->SetName(aExchangeName); + Broadcast(SdrHint(SdrHintKind::PageOrderChange, pNotesPage)); - // update layout and referred master page - pRefPage->SetPresentationLayout(aLayout); - if( bUndo ) - AddUndo( GetSdrUndoFactory().CreateUndoPageChangeMasterPage( *pRefPage ) ); - - if (bScaleObjects) - { - ::tools::Rectangle aBorderRect(nLeft, nUpper, nRight, nLower); - pRefPage->ScaleObjects(aSize, aBorderRect, true); - } - pRefPage->SetSize(aSize); - pRefPage->SetBorder(nLeft, nUpper, nRight, nLower); - pRefPage->SetOrientation( eOrient ); + ++pExchangeIter; + } + OUString aLayout(rParams.mainProps.pPage->GetLayoutName()); + sal_Int32 nIndex = aLayout.indexOf(SD_LT_SEPARATOR); + if (nIndex != -1) + aLayout = aLayout.copy(0, nIndex); - if( bRemoveEmptyPresObj ) - pRefPage->RemoveEmptyPresentationObjects(); + // update layout and referred master page + rParams.mainProps.pPage->SetPresentationLayout(aLayout); + if (rParams.bUndo) + AddUndo(GetSdrUndoFactory().CreateUndoPageChangeMasterPage(*rParams.mainProps.pPage)); - pRefPage = GetSdPage(nSdPage, PageKind::Notes); + if (rParams.bScaleObjects) + { + ::tools::Rectangle aBorderRect(rParams.mainProps.left, rParams.mainProps.upper, rParams.mainProps.right, rParams.mainProps.lower); + rParams.mainProps.pPage->ScaleObjects(rParams.mainProps.size, aBorderRect, true); + } + rParams.mainProps.pPage->SetSize(rParams.mainProps.size); + rParams.mainProps.pPage->SetBorder(rParams.mainProps.left, rParams.mainProps.upper, rParams.mainProps.right, rParams.mainProps.lower); + rParams.mainProps.pPage->SetOrientation(rParams.mainProps.orientation); - // update layout and referred master page - pRefPage->SetPresentationLayout(aLayout); - if( bUndo ) - AddUndo( GetSdrUndoFactory().CreateUndoPageChangeMasterPage( *pRefPage ) ); + if (bRemoveEmptyPresObj) + rParams.mainProps.pPage->RemoveEmptyPresentationObjects(); - if (bScaleObjects) - { - ::tools::Rectangle aBorderRect(nNLeft, nNUpper, nNRight, nNLower); - pRefPage->ScaleObjects(aNSize, aBorderRect, true); - } + rParams.mainProps.pPage = GetSdPage(nSdPage, PageKind::Notes); - pRefPage->SetSize(aNSize); - pRefPage->SetBorder(nNLeft, nNUpper, nNRight, nNLower); - pRefPage->SetOrientation( eNOrient ); + // update layout and referred master page + rParams.mainProps.pPage->SetPresentationLayout(aLayout); + if (rParams.bUndo) + AddUndo(GetSdrUndoFactory().CreateUndoPageChangeMasterPage(*rParams.mainProps.pPage)); - if( bRemoveEmptyPresObj ) - pRefPage->RemoveEmptyPresentationObjects(); + if (rParams.bScaleObjects) + { + ::tools::Rectangle aBorderRect(rParams.notesProps.left, rParams.notesProps.upper, rParams.notesProps.right, rParams.notesProps.lower); + rParams.mainProps.pPage->ScaleObjects(rParams.notesProps.size, aBorderRect, true); } - ///Remove processed elements, to avoid doing hacks in InsertBookmarkAsObject - if ( pExchangeList ) - pExchangeList->erase(pExchangeList->begin(),pExchangeIter); + rParams.mainProps.pPage->SetSize(rParams.notesProps.size); + rParams.mainProps.pPage->SetBorder(rParams.notesProps.left, rParams.notesProps.upper, rParams.notesProps.right, rParams.notesProps.lower); + rParams.mainProps.pPage->SetOrientation(rParams.notesProps.orientation); + + if (bRemoveEmptyPresObj) + rParams.mainProps.pPage->RemoveEmptyPresentationObjects(); + } + ///Remove processed elements, to avoid doing hacks in InsertBookmarkAsObject + if (rParams.pExchangeList) + rParams.pExchangeList->erase(rParams.pExchangeList->begin(), pExchangeIter); - for (sal_uInt16 nPage = nMPageCount; nPage < nNewMPageCount; nPage++) + for (sal_uInt16 nPage = rPageCounts.nMasterPageCount; nPage < rPageCounts.nNewMPageCount; nPage++) + { + rParams.mainProps.pPage = static_cast<SdPage*>(GetMasterPage(nPage)); + if (rParams.mainProps.pPage->GetPageKind() == PageKind::Standard) { - pRefPage = static_cast<SdPage*>( GetMasterPage(nPage) ); - if (pRefPage->GetPageKind() == PageKind::Standard) + if (rParams.bScaleObjects) { - if (bScaleObjects) - { - ::tools::Rectangle aBorderRect(nLeft, nUpper, nRight, nLower); - pRefPage->ScaleObjects(aSize, aBorderRect, true); - } - pRefPage->SetSize(aSize); - pRefPage->SetBorder(nLeft, nUpper, nRight, nLower); - pRefPage->SetOrientation( eOrient ); + ::tools::Rectangle aBorderRect(rParams.mainProps.left, rParams.mainProps.upper, rParams.mainProps.right, rParams.mainProps.lower); + rParams.mainProps.pPage->ScaleObjects(rParams.mainProps.size, aBorderRect, true); + } + rParams.mainProps.pPage->SetSize(rParams.mainProps.size); + rParams.mainProps.pPage->SetBorder(rParams.mainProps.left, rParams.mainProps.upper, rParams.mainProps.right, rParams.mainProps.lower); + rParams.mainProps.pPage->SetOrientation(rParams.mainProps.orientation); - uno::Reference< drawing::XDrawPage > xNewPage(GetMasterPage(nPage)->getUnoPage(), uno::UNO_QUERY_THROW); + uno::Reference<drawing::XDrawPage> xNewPage(GetMasterPage(nPage)->getUnoPage(), uno::UNO_QUERY_THROW); - SdrPage* pMasterPage = SdPage::getImplementation(xNewPage); - if (pMasterPage) + SdrPage* pMasterPage = SdPage::getImplementation(xNewPage); + if (pMasterPage) + { + OUString aLayout(rParams.mainProps.pPage->GetName()); + if (auto it{ rStyleContext.aThemes.find(aLayout) }; it != std::end(rStyleContext.aThemes)) { - OUString aLayout(pRefPage->GetName()); - if (auto it{ aThemesToTransfer.find(aLayout) }; it != std::end(aThemesToTransfer)) - { - pMasterPage->getSdrPageProperties().setTheme(it->second); - } + pMasterPage->getSdrPageProperties().setTheme(it->second); } + } - uno::Reference<beans::XPropertySet> xNewPropSet(xNewPage, uno::UNO_QUERY_THROW); - if (xNewPropSet.is()) + uno::Reference<beans::XPropertySet> xNewPropSet(xNewPage, uno::UNO_QUERY_THROW); + if (xNewPropSet.is()) + { + OUString aLayout(rParams.mainProps.pPage->GetName()); + sal_Int32 nLayout = 20; // blank page - master slide layout ID + if (auto it{ rStyleContext.aSlideLayouts.find(aLayout) }; it != std::end(rStyleContext.aSlideLayouts)) { - OUString aLayout(pRefPage->GetName()); - sal_Int32 nLayout = 20; // blank page - master slide layout ID - if (auto it{ aSlideLayoutsToTransfer.find(aLayout) }; it != std::end(aSlideLayoutsToTransfer)) - { - nLayout = it->second; - } - xNewPropSet->setPropertyValue(u"SlideLayout"_ustr, uno::Any(nLayout)); + nLayout = it->second; } + xNewPropSet->setPropertyValue(u"SlideLayout"_ustr, uno::Any(nLayout)); } - else // Can only be notes + } + else // Can only be notes + { + if (rParams.bScaleObjects) { - if (bScaleObjects) - { - ::tools::Rectangle aBorderRect(nNLeft, nNUpper, nNRight, nNLower); - pRefPage->ScaleObjects(aNSize, aBorderRect, true); - } - pRefPage->SetSize(aNSize); - pRefPage->SetBorder(nNLeft, nNUpper, nNRight, nNLower); - pRefPage->SetOrientation( eNOrient ); + ::tools::Rectangle aBorderRect(rParams.notesProps.left, rParams.notesProps.upper, rParams.notesProps.right, rParams.notesProps.lower); + rParams.notesProps.pPage->ScaleObjects(rParams.notesProps.size, aBorderRect, true); } - - if( bRemoveEmptyPresObj ) - pRefPage->RemoveEmptyPresentationObjects(); + rParams.notesProps.pPage->SetSize(rParams.notesProps.size); + rParams.notesProps.pPage->SetBorder(rParams.notesProps.left, rParams.notesProps.upper, rParams.notesProps.right, rParams.notesProps.lower); + rParams.notesProps.pPage->SetOrientation(rParams.notesProps.orientation); } - } - // Make absolutely sure no double masterpages are there - RemoveUnnecessaryMasterPages(nullptr, true); + if (bRemoveEmptyPresObj) + rParams.mainProps.pPage->RemoveEmptyPresentationObjects(); + } +} - // Rename object styles if necessary - if(!aRenameStr.isEmpty()) +void SdDrawDocument::renameObjectStylesIfNeeded(sal_uInt32 nInsertPos, + StyleTransferContext& rStyleContext, + sal_uInt32 nBMSdPageCount) +{ + if (!rStyleContext.aRenameString.isEmpty()) { - try - { - for(sal_uInt32 p = nInsertPos; p < sal_uInt32(nInsertPos) + sal_uInt32(nBMSdPageCount); p++) + try { + for (sal_uInt32 p = nInsertPos; p < nInsertPos + nBMSdPageCount ; p++) { - if (SdPage *pPg = static_cast<SdPage *>( GetPage(p) )) - for (const rtl::Reference<SdrObject>& pObj : *pPg) + if (SdPage* pPage = static_cast<SdPage*>(GetPage(p))) { + for (const rtl::Reference<SdrObject>& pObj : *pPage) { - if(pObj->GetStyleSheet()) + if (pObj->GetStyleSheet()) { OUString aStyleName = pObj->GetStyleSheet()->GetName(); - SfxStyleSheet *pSheet = lcl_findStyle(aNewGraphicStyles, Concat2View(aStyleName + aRenameStr)); - if(pSheet != nullptr) + SfxStyleSheet* pSheet = lcl_findStyle(rStyleContext.aGraphicStyles, Concat2View(aStyleName + rStyleContext.aRenameString)); + if (pSheet) pObj->SetStyleSheet(pSheet, true); } } + } } } catch(...) @@ -998,23 +975,25 @@ bool SdDrawDocument::InsertBookmarkAsPage( TOOLS_WARN_EXCEPTION( "sd", "Exception while renaming styles @ SdDrawDocument::InsertBookmarkAsPage"); } } - // remove copied styles not used on any inserted page and create - // undo records - // WARNING: SdMoveStyleSheetsUndoAction clears the passed list of - // styles, so it cannot be used after this point - lcl_removeUnusedStyles(GetStyleSheetPool(), aNewGraphicStyles); - if (!aNewGraphicStyles.empty() && pUndoMgr) - pUndoMgr->AddUndoAction(std::make_unique<SdMoveStyleSheetsUndoAction>(this, aNewGraphicStyles, true)); - lcl_removeUnusedTableStyles(static_cast<SdStyleSheetPool*>(GetStyleSheetPool()), aNewTableStyles); - lcl_removeUnusedStyles(GetStyleSheetPool(), aNewCellStyles); +} +void SdDrawDocument::cleanupStyles(SfxUndoManager* pUndoMgr, + StyleTransferContext& rStyleContext) +{ + lcl_removeUnusedStyles(GetStyleSheetPool(), rStyleContext.aGraphicStyles); + if (!rStyleContext.aGraphicStyles.empty() && pUndoMgr) + pUndoMgr->AddUndoAction(std::make_unique<SdMoveStyleSheetsUndoAction>(this, rStyleContext.aGraphicStyles, true)); + lcl_removeUnusedTableStyles(static_cast<SdStyleSheetPool*>(GetStyleSheetPool()), rStyleContext.aTableStyles); + lcl_removeUnusedStyles(GetStyleSheetPool(), rStyleContext.aCellStyles); +} + +void SdDrawDocument::endUndoAction(bool bUndo,SfxUndoManager* pUndoMgr) +{ if( bUndo ) EndUndo(); if (pUndoMgr) pUndoMgr->LeaveListAction(); - - return bContinue; } // Inserts a bookmark as an object @@ -1940,4 +1919,543 @@ void SdDrawDocument::Merge(SdrModel& rSourceModel, } } +// Paste pages from clipboard - handles regular paste operations +bool SdDrawDocument::PasteBookmarkAsPage( + const PageNameList &rBookmarkList, + PageNameList *pExchangeList, + sal_uInt16 nInsertPos, + ::sd::DrawDocShell* pBookmarkDocSh, + bool bMergeMasterPages) +{ + // Use predefined options for clipboard paste operation + InsertBookmarkOptions options = InsertBookmarkOptions::ForPaste(bMergeMasterPages); + + // Create insertion parameters + PageInsertionParams aInsertParams(nInsertPos, pExchangeList); + + // Get the bookmark document first so we can use it for scale object determination + if (!initBookmarkDoc(pBookmarkDocSh, aInsertParams.pBookmarkDoc, aInsertParams.aBookmarkName)) + return false; + + DocumentPageCounts pageCounts(GetSdPageCount(PageKind::Standard), + aInsertParams.pBookmarkDoc->GetSdPageCount(PageKind::Standard), + GetMasterPageCount()); + + if (!pageCounts.areValid()) + { + return false; + } + + // Retrieve page properties (size, borders, orientation) for main and notes pages. + getPageProperties(aInsertParams.mainProps, aInsertParams.notesProps, pageCounts.nDestPageCount); + + // Determine if objects need to be scaled + if (!determineScaleObjects(options.bNoDialogs, rBookmarkList, aInsertParams)) + return false; + + // Get the necessary presentation stylesheets and transfer them before + // the pages, else, the text objects won't reference their styles anymore. + SfxUndoManager* pUndoMgr = beginUndoAction(); + + // Collect layout names that need to be transferred + SlideLayoutNameList aLayoutsToTransfer; + collectLayoutsToTransfer(rBookmarkList, aInsertParams.pBookmarkDoc, aLayoutsToTransfer, pageCounts.nSourcePageCount); + + // Copy the style that we actually need. + SdStyleSheetPool& rBookmarkStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*aInsertParams.pBookmarkDoc->GetStyleSheetPool()); + SdStyleSheetPool& rStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*GetStyleSheetPool()); + + // When copying styles, also copy the master pages! + if (!aLayoutsToTransfer.empty()) + bMergeMasterPages = true; + + // Create a StyleTransferContext with the style sheet pools + StyleTransferContext aStyleContext(&rBookmarkStyleSheetPool, &rStyleSheetPool); + + // Transfer layout styles + transferLayoutStyles(aLayoutsToTransfer, aInsertParams.pBookmarkDoc, pUndoMgr, aStyleContext); + + // Copy styles. This unconditionally copies all styles, even those + // that are not used in any of the inserted pages. The unused styles + // are then removed at the end of the function, where we also create + // undo records for the inserted styles. + copyStyles(options.bReplace, options.bNoDialogs, aStyleContext); + + aInsertParams.bUndo = IsUndoEnabled(); + + // Insert document + if (aInsertParams.bUndo) + BegUndo(SdResId(STR_UNDO_INSERTPAGES)); + + // Insert pages based on whether all or selected pages are bookmarked. + if (rBookmarkList.empty()) + { + insertAllPages(aInsertParams, options, pageCounts.nSourcePageCount); + } + else + { + // Insert selected pages + insertSelectedPages(rBookmarkList, aInsertParams, options); + } + + // Remove duplicate master pages that may have been created. + removeDuplicateMasterPages(aInsertParams, pageCounts); + + // nInsertPos > 2 is always true when inserting into non-empty models + if (nInsertPos > 0) { + updateInsertedPages(aInsertParams, options, pageCounts, aStyleContext); + } + + // Make absolutely sure no double masterpages are there + RemoveUnnecessaryMasterPages(nullptr, true); + + // Rename object styles if necessary + renameObjectStylesIfNeeded(nInsertPos, aStyleContext, pageCounts.nSourcePageCount); + + // Clean up any copied styles not used and record undo actions. + // remove copied styles not used on any inserted page and create + // undo records + // WARNING: SdMoveStyleSheetsUndoAction clears the passed list of + // styles, so it cannot be used after this point + cleanupStyles(pUndoMgr, aStyleContext); + + // End undo action + endUndoAction(aInsertParams.bUndo, pUndoMgr); + + return true; +} + +// Resolve page links +bool SdDrawDocument::ResolvePageLinks( + const PageNameList &rBookmarkList, + sal_uInt16 nInsertPos, + bool bNoDialogs, + bool bCopy) +{ + // Use predefined options for page link resolution + InsertBookmarkOptions options = InsertBookmarkOptions::ForPageLinks(bCopy, bNoDialogs); + + // Create insertion parameters + PageInsertionParams aInsertParams(nInsertPos); + + // Get the bookmark document first so we can use it for scale object determination + if (!initBookmarkDoc(nullptr, aInsertParams.pBookmarkDoc, aInsertParams.aBookmarkName)) + return false; + + DocumentPageCounts pageCounts(GetSdPageCount(PageKind::Standard), aInsertParams.pBookmarkDoc->GetSdPageCount(PageKind::Standard), GetMasterPageCount()); + + if (!pageCounts.areValid()) + { + return false; + } + + // Retrieve page properties (size, borders, orientation) for main and notes pages + getPageProperties(aInsertParams.mainProps, aInsertParams.notesProps, pageCounts.nDestPageCount); + + if (!determineScaleObjects(options.bNoDialogs, rBookmarkList, aInsertParams)) + return false; + + // Get the necessary presentation stylesheets and transfer them before + // the pages, else, the text objects won't reference their styles anymore. + SfxUndoManager* pUndoMgr = beginUndoAction(); + + // Collect layout names that need to be transferred + SlideLayoutNameList aLayoutsToTransfer; + collectLayoutsToTransfer(rBookmarkList, aInsertParams.pBookmarkDoc, aLayoutsToTransfer, pageCounts.nSourcePageCount); + + // Copy the style that we actually need. + SdStyleSheetPool& rBookmarkStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*aInsertParams.pBookmarkDoc->GetStyleSheetPool()); + SdStyleSheetPool& rStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*GetStyleSheetPool()); + + // Create a StyleTransferContext with the style sheet pools + StyleTransferContext aStyleContext(&rBookmarkStyleSheetPool, &rStyleSheetPool); + + // Transfer layout styles + transferLayoutStyles(aLayoutsToTransfer, aInsertParams.pBookmarkDoc, pUndoMgr, aStyleContext); + + // Copy styles. This unconditionally copies all styles, even those + // that are not used in any of the inserted pages. The unused styles + // are then removed at the end of the function, where we also create + // undo records for the inserted styles. + copyStyles(options.bReplace, options.bNoDialogs, aStyleContext); + + aInsertParams.bUndo = IsUndoEnabled(); + + // Insert document + if (aInsertParams.bUndo) + BegUndo(SdResId(STR_UNDO_INSERTPAGES)); + + if (rBookmarkList.empty()) + { + insertAllPages(aInsertParams, options, pageCounts.nSourcePageCount); + } + else + { + // Insert selected pages + insertSelectedPages(rBookmarkList, aInsertParams, options); + } + + // Remove duplicate master pages that may have been created. + removeDuplicateMasterPages(aInsertParams, pageCounts); + + // Update inserted pages (scaling objects if needed, etc) + updateInsertedPages(aInsertParams, options, pageCounts, aStyleContext); + + // Make absolutely sure no double masterpages are there + RemoveUnnecessaryMasterPages(nullptr, true); + + // Rename object styles if necessary + renameObjectStylesIfNeeded(nInsertPos, aStyleContext, pageCounts.nSourcePageCount); + + // Clean up any copied styles not used and record undo actions. + // remove copied styles not used on any inserted page and create + // undo records + // WARNING: SdMoveStyleSheetsUndoAction clears the passed list of + // styles, so it cannot be used after this point + cleanupStyles(pUndoMgr, aStyleContext); + + // End undo action + endUndoAction(aInsertParams.bUndo, pUndoMgr); + + return true; +} + +// Import a whole document +bool SdDrawDocument::ImportDocumentPages( + const PageNameList &rBookmarkList, + sal_uInt16 nInsertPos, + ::sd::DrawDocShell* pBookmarkDocSh) +{ + // Use predefined options for document import + InsertBookmarkOptions options = InsertBookmarkOptions::ForDocumentImport(); + + // Create parameter object for page insertion + PageInsertionParams aInsertParams(nInsertPos); + + + // Initialize bookmark document + if (!initBookmarkDoc(pBookmarkDocSh, aInsertParams.pBookmarkDoc, aInsertParams.aBookmarkName)) + return false; + + DocumentPageCounts pageCounts(GetSdPageCount(PageKind::Standard), aInsertParams.pBookmarkDoc->GetSdPageCount(PageKind::Standard), GetMasterPageCount()); + + if (!pageCounts.areValid()) + { + return false; + } + + // Retrieve page properties (size, borders, orientation) for main and notes pages. + getPageProperties(aInsertParams.mainProps, aInsertParams.notesProps, pageCounts.nDestPageCount); + + // Determine if objects need to be scaled + if (!determineScaleObjects(options.bNoDialogs, rBookmarkList, aInsertParams)) + return false; + + // Start undo action + SfxUndoManager* pUndoMgr = beginUndoAction(); + + // Collect layout names that need to be transferred + SlideLayoutNameList aLayoutsToTransfer; + collectLayoutsToTransfer(rBookmarkList, aInsertParams.pBookmarkDoc, aLayoutsToTransfer, pageCounts.nSourcePageCount); + + // Copy the style that we actually need. + SdStyleSheetPool& rBookmarkStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*aInsertParams.pBookmarkDoc->GetStyleSheetPool()); + SdStyleSheetPool& rStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*GetStyleSheetPool()); + + + // Create a StyleTransferContext with the style sheet pools + StyleTransferContext aStyleContext(&rBookmarkStyleSheetPool, &rStyleSheetPool); + + // Transfer layout styles + transferLayoutStyles(aLayoutsToTransfer, aInsertParams.pBookmarkDoc, pUndoMgr, aStyleContext); + + // Copy styles. This unconditionally copies all styles, even those + // that are not used in any of the inserted pages. The unused styles + // are then removed at the end of the function, where we also create + // undo records for the inserted styles. + copyStyles(options.bReplace, options.bNoDialogs, aStyleContext); + + aInsertParams.bUndo = IsUndoEnabled(); + + if (aInsertParams.bUndo) + BegUndo(SdResId(STR_UNDO_INSERTPAGES)); + + // For document import, we typically import all pages + if (rBookmarkList.empty()) + { + insertAllPages(aInsertParams, options, pageCounts.nSourcePageCount); + } + else + { + // If specific pages were selected, import only those + insertSelectedPages(rBookmarkList, aInsertParams, options); + } + + // Remove duplicate master pages that may have been created. + removeDuplicateMasterPages(aInsertParams, pageCounts); + + // nInsertPos > 2 is always true when inserting into non-empty models + if (nInsertPos > 0) { + updateInsertedPages(aInsertParams, options, pageCounts, aStyleContext); + } + + // Make absolutely sure no double masterpages are there + RemoveUnnecessaryMasterPages(nullptr, true); + + // Rename object styles if necessary + renameObjectStylesIfNeeded(nInsertPos, aStyleContext, pageCounts.nSourcePageCount); + + // Clean up any copied styles not used and record undo actions. + cleanupStyles(pUndoMgr, aStyleContext); + + // End undo action + endUndoAction(aInsertParams.bUndo, pUndoMgr); + + return true; +} + +// Insert pages from external files +bool SdDrawDocument::InsertFileAsPage( + const PageNameList &rBookmarkList, + PageNameList *pExchangeList, + bool bLink, + sal_uInt16 nInsertPos, + ::sd::DrawDocShell* pBookmarkDocSh) +{ + // Use predefined options for file insert operation + InsertBookmarkOptions options = InsertBookmarkOptions::ForFileInsert(bLink); + + // Create parameter object for page insertion + PageInsertionParams aInsertParams(nInsertPos, pExchangeList); + + // Initialize bookmark document + if (!initBookmarkDoc(pBookmarkDocSh, aInsertParams.pBookmarkDoc, aInsertParams.aBookmarkName)) + return false; + + DocumentPageCounts pageCounts(GetSdPageCount(PageKind::Standard), aInsertParams.pBookmarkDoc->GetSdPageCount(PageKind::Standard), GetMasterPageCount()); + + if (!pageCounts.areValid()) + { + return false; + } + + // Retrieve page properties (size, borders, orientation) for main and notes pages. + getPageProperties(aInsertParams.mainProps, aInsertParams.notesProps, pageCounts.nDestPageCount); + + // Determine if objects need to be scaled + if (!determineScaleObjects(options.bNoDialogs, rBookmarkList, aInsertParams)) + return false; + + // Get the necessary presentation stylesheets and transfer them before + // the pages, else, the text objects won't reference their styles anymore. + SfxUndoManager* pUndoMgr = beginUndoAction(); + + // Collect layout names that need to be transferred + SlideLayoutNameList aLayoutsToTransfer; + collectLayoutsToTransfer(rBookmarkList, aInsertParams.pBookmarkDoc, aLayoutsToTransfer, pageCounts.nSourcePageCount); + + // Copy the style that we actually need. + SdStyleSheetPool& rBookmarkStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*aInsertParams.pBookmarkDoc->GetStyleSheetPool()); + SdStyleSheetPool& rStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*GetStyleSheetPool()); + + // Create a StyleTransferContext with the style sheet pools + StyleTransferContext aStyleContext(&rBookmarkStyleSheetPool, &rStyleSheetPool); + + // Transfer layout styles + transferLayoutStyles(aLayoutsToTransfer, aInsertParams.pBookmarkDoc, pUndoMgr, aStyleContext); + + // Copy styles. This unconditionally copies all styles, even those + // that are not used in any of the inserted pages. The unused styles + // are then removed at the end of the function, where we also create + // undo records for the inserted styles. + copyStyles(options.bReplace, options.bNoDialogs, aStyleContext); + + aInsertParams.bUndo = IsUndoEnabled(); + + if (aInsertParams.bUndo) + BegUndo(SdResId(STR_UNDO_INSERTPAGES)); + + if (rBookmarkList.empty()) + { + insertAllPages(aInsertParams, options, pageCounts.nSourcePageCount); + } + else + { + // Insert selected pages + insertSelectedPages(rBookmarkList, aInsertParams, options); + } + + // Remove duplicate master pages that may have been created. + removeDuplicateMasterPages(aInsertParams, pageCounts); + + // nInsertPos > 2 is always true when inserting into non-empty models + if (nInsertPos > 0) { + updateInsertedPages(aInsertParams, options, pageCounts, aStyleContext); + } + + // Make absolutely sure no double masterpages are there + RemoveUnnecessaryMasterPages(nullptr, true); + + // Rename object styles if necessary + renameObjectStylesIfNeeded(nInsertPos, aStyleContext, pageCounts.nSourcePageCount); + + // Clean up any copied styles not used and record undo actions. + cleanupStyles(pUndoMgr, aStyleContext); + + // End undo action + endUndoAction(aInsertParams.bUndo, pUndoMgr); + + return true; +} + +// Handle drag and drop operations +bool SdDrawDocument::DropBookmarkAsPage( + const PageNameList &rBookmarkList, + sal_uInt16 nInsertPos, + ::sd::DrawDocShell* pBookmarkDocSh, + bool bMergeMasterPages) +{ + // Use predefined options for drag and drop operation + InsertBookmarkOptions options = InsertBookmarkOptions::ForDragDrop(bMergeMasterPages); + + // Create parameter object for page insertion + PageInsertionParams aInsertParams(nInsertPos); + + // Initialize bookmark document + if (!initBookmarkDoc(pBookmarkDocSh, aInsertParams.pBookmarkDoc, aInsertParams.aBookmarkName)) + return false; + + DocumentPageCounts pageCounts(GetSdPageCount(PageKind::Standard), aInsertParams.pBookmarkDoc->GetSdPageCount(PageKind::Standard), GetMasterPageCount()); + + if (!pageCounts.areValid()) + { + return false; + } + + // Retrieve page properties (size, borders, orientation) for main and notes pages. + getPageProperties(aInsertParams.mainProps, aInsertParams.notesProps, pageCounts.nDestPageCount); + + // Determine if objects need to be scaled + if (!determineScaleObjects(options.bNoDialogs, rBookmarkList, aInsertParams)) + return false; + + // Get the necessary presentation stylesheets and transfer them before + // the pages, else, the text objects won't reference their styles anymore. + SfxUndoManager* pUndoMgr = beginUndoAction(); + + // Collect layout names that need to be transferred + SlideLayoutNameList aLayoutsToTransfer; + collectLayoutsToTransfer(rBookmarkList, aInsertParams.pBookmarkDoc, aLayoutsToTransfer, pageCounts.nSourcePageCount); + + // Copy the style that we actually need. + SdStyleSheetPool& rBookmarkStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*aInsertParams.pBookmarkDoc->GetStyleSheetPool()); + SdStyleSheetPool& rStyleSheetPool = dynamic_cast<SdStyleSheetPool&>(*GetStyleSheetPool()); + + // Create a StyleTransferContext with the style sheet pools + StyleTransferContext aStyleContext(&rBookmarkStyleSheetPool, &rStyleSheetPool); + + // Transfer layout styles + transferLayoutStyles(aLayoutsToTransfer, aInsertParams.pBookmarkDoc, pUndoMgr, aStyleContext); + + // Copy styles. This unconditionally copies all styles, even those + // that are not used in any of the inserted pages. The unused styles + // are then removed at the end of the function, where we also create + // undo records for the inserted styles. + copyStyles(options.bReplace, options.bNoDialogs, aStyleContext); + + aInsertParams.bUndo = IsUndoEnabled(); + + if (aInsertParams.bUndo) + BegUndo(SdResId(STR_UNDO_INSERTPAGES)); + + // Insert pages based on whether all or selected pages are bookmarked. + if (rBookmarkList.empty()) + { + insertAllPages(aInsertParams, options, pageCounts.nSourcePageCount); + } + else + { + // Insert selected pages + insertSelectedPages(rBookmarkList, aInsertParams, options); + } + + // Remove duplicate master pages that may have been created. + removeDuplicateMasterPages(aInsertParams, pageCounts); + + // nInsertPos > 2 is always true when inserting into non-empty models + if (nInsertPos > 0) { + updateInsertedPages(aInsertParams, options, pageCounts, aStyleContext); + } + + // Make absolutely sure no double masterpages are there + RemoveUnnecessaryMasterPages(nullptr, true); + + // Rename object styles if necessary + renameObjectStylesIfNeeded(nInsertPos, aStyleContext, pageCounts.nSourcePageCount); + + // Clean up any copied styles not used and record undo actions. + cleanupStyles(pUndoMgr, aStyleContext); + + // End undo action + endUndoAction(aInsertParams.bUndo, pUndoMgr); + + return true; +} + +// Copy or move pages within the same document +bool SdDrawDocument::CopyOrMovePagesWithinDocument( + const PageNameList &rBookmarkList, + PageNameList *pExchangeList, + sal_uInt16 nInsertPos, + bool bPreservePageNames) +{ + // Use predefined options for internal document operations + InsertBookmarkOptions options = InsertBookmarkOptions::ForInternalOps(bPreservePageNames); + + // Create parameter object for page insertion + // When copying within document, source and target are the same + PageInsertionParams aInsertParams(nInsertPos, pExchangeList, this); + + DocumentPageCounts pageCounts(GetSdPageCount(PageKind::Standard), aInsertParams.pBookmarkDoc->GetSdPageCount(PageKind::Standard), GetMasterPageCount()); + + if (!pageCounts.areValid()) + { + return false; + } + + getPageProperties(aInsertParams.mainProps, aInsertParams.notesProps, pageCounts.nDestPageCount); + + if (!determineScaleObjects(options.bNoDialogs, rBookmarkList, aInsertParams)) + return false; + + // Get the necessary presentation stylesheets and transfer them before + // the pages, else, the text objects won't reference their styles anymore. + SfxUndoManager* pUndoMgr = beginUndoAction(); + aInsertParams.bUndo = IsUndoEnabled(); + + if (aInsertParams.bUndo) + BegUndo(SdResId(STR_UNDO_INSERTPAGES)); + + // Insert selected pages + insertSelectedPages(rBookmarkList, aInsertParams, options); + + // Remove duplicate master pages that may have been created. + removeDuplicateMasterPages(aInsertParams, pageCounts); + + // nInsertPos > 2 is always true when inserting into non-empty models + StyleTransferContext aStyleContext; + if (nInsertPos > 0) { + updateInsertedPages(aInsertParams, options, pageCounts, aStyleContext); + } + + // No need to remove unnecessary master pages when copying within the same document + // No need to rename object styles when copying within the same document + // No need to clean up styles when copying within the same document + + // End undo action + endUndoAction(aInsertParams.bUndo, pUndoMgr); + + return true; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/core/pglink.cxx b/sd/source/core/pglink.cxx index 358012df94f3..18e9b3c5b1e9 100644 --- a/sd/source/core/pglink.cxx +++ b/sd/source/core/pglink.cxx @@ -100,8 +100,7 @@ SdPageLink::~SdPageLink() bCopy = true; } - pDoc->InsertBookmarkAsPage(aBookmarkList, nullptr, true/*bLink*/, true/*bReplace*/, - nInsertPos, bNoDialogs, nullptr, bCopy, true, true); + pDoc->ResolvePageLinks(aBookmarkList, nInsertPos, bNoDialogs, bCopy); if (!SdDrawDocument::s_pDocLockedInsertingLinks) pDoc->CloseBookmarkDoc(); diff --git a/sd/source/ui/app/sdxfer.cxx b/sd/source/ui/app/sdxfer.cxx index 17ed6280b13a..348322d47334 100644 --- a/sd/source/ui/app/sdxfer.cxx +++ b/sd/source/ui/app/sdxfer.cxx @@ -673,8 +673,7 @@ void SdTransferable::SetPageBookmarks( std::vector<OUString> && rPageBookmarks, if( bPersistent ) { mpSdDrawDocument->CreateFirstPages(mpSourceDoc); - mpSdDrawDocument->InsertBookmarkAsPage( rPageBookmarks, nullptr, false, true, 1, true, - mpSourceDoc->GetDocSh(), true, true, false ); + mpSdDrawDocument->ImportDocumentPages(rPageBookmarks, 1, mpSourceDoc->GetDocSh()); } else { diff --git a/sd/source/ui/func/fuinsfil.cxx b/sd/source/ui/func/fuinsfil.cxx index 630ea14ae3aa..9eb004066084 100644 --- a/sd/source/ui/func/fuinsfil.cxx +++ b/sd/source/ui/func/fuinsfil.cxx @@ -373,9 +373,8 @@ bool FuInsertFile::InsSDDinDrMode(SfxMedium* pMedium) bNameOK = mpView->GetExchangeList( aExchangeList, aBookmarkList, 0 ); if( bNameOK ) - bOK = mpDoc->InsertBookmarkAsPage( aBookmarkList, &aExchangeList, - bLink, false/*bReplace*/, nPos, - false, nullptr, true, true, false ); + bOK = mpDoc->InsertFileAsPage( aBookmarkList, &aExchangeList, + bLink, nPos, nullptr ); aBookmarkList.clear(); aExchangeList.clear(); diff --git a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx index 2c0b81bde2b2..c404cb0b8561 100644 --- a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx +++ b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx @@ -299,17 +299,12 @@ sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) const SolarMutexGuard aGuard; nInsertPageCount = static_cast<sal_uInt16>(rBookmarkList.size()); - rModel.GetDocument()->InsertBookmarkAsPage( + rModel.GetDocument()->PasteBookmarkAsPage( rBookmarkList, nullptr, - false, - false, nInsertIndex, - false, pClipTransferable->GetPageDocShell(), - true, - bMergeMasterPages, - false); + bMergeMasterPages); } else { @@ -324,17 +319,12 @@ sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) bMergeMasterPages = (pDataDoc != rModel.GetDocument()); nInsertPageCount = pDataDoc->GetSdPageCount( PageKind::Standard ); - rModel.GetDocument()->InsertBookmarkAsPage( + rModel.GetDocument()->PasteBookmarkAsPage( -e ... etc. - the rest is truncated