diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sd/source/ui/view | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sd/source/ui/view')
65 files changed, 46188 insertions, 0 deletions
diff --git a/sd/source/ui/view/DocumentRenderer.cxx b/sd/source/ui/view/DocumentRenderer.cxx new file mode 100644 index 0000000000..c9bed876e7 --- /dev/null +++ b/sd/source/ui/view/DocumentRenderer.cxx @@ -0,0 +1,2253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <DocumentRenderer.hxx> +#include <DocumentRenderer.hrc> +#include <ViewShellBase.hxx> + +#include <drawdoc.hxx> +#include <sdpage.hxx> +#include <sdresid.hxx> +#include <strings.hrc> +#include <drawview.hxx> +#include <DrawViewShell.hxx> +#include <FrameView.hxx> +#include <Outliner.hxx> +#include <OutlineViewShell.hxx> +#include <SlideSorterViewShell.hxx> +#include <DrawDocShell.hxx> + +#include <tools/multisel.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> +#include <rtl/ustrbuf.hxx> +#include <editeng/editstat.hxx> +#include <editeng/outlobj.hxx> +#include <svx/svdetc.hxx> +#include <svx/svditer.hxx> +#include <svx/svdopage.hxx> +#include <svx/svdopath.hxx> +#include <svx/svdpagv.hxx> +#include <svx/xlineit0.hxx> +#include <svx/xlnclit.hxx> +#include <toolkit/awt/vclxdevice.hxx> +#include <unotools/localedatawrapper.hxx> +#include <utility> +#include <vcl/print.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <unotools/moduleoptions.hxx> +#include <xmloff/autolayout.hxx> +#include <sfx2/objsh.hxx> + +#include <officecfg/Office/Draw.hxx> +#include <officecfg/Office/Impress.hxx> + +#include <algorithm> +#include <memory> +#include <vector> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd { + +namespace { + + /** Convenience class to extract values from the sequence of properties + given to one of the XRenderable methods. + */ + class PrintOptions + { + public: + PrintOptions ( + const vcl::PrinterOptionsHelper& rHelper, + std::vector<sal_Int32>&& rSlidesPerPage) + : mrProperties(rHelper), + maSlidesPerPage(std::move(rSlidesPerPage)) + { + } + + bool IsWarningOrientation() const + { + return GetBoolValue(nullptr, true); + } + + bool IsPrintPageName() const + { + return GetBoolValue("IsPrintName", false); + } + + bool IsDate() const + { + return GetBoolValue("IsPrintDateTime", false); + } + + bool IsTime() const + { + return GetBoolValue("IsPrintDateTime", false); + } + + bool IsHiddenPages() const + { + return GetBoolValue("IsPrintHidden", false); + } + + bool IsHandoutHorizontal() const + { + return GetBoolValue("SlidesPerPageOrder", sal_Int32(0)); + } + + sal_Int32 GetHandoutPageCount() const + { + sal_uInt32 nIndex = static_cast<sal_Int32>(mrProperties.getIntValue("SlidesPerPage", sal_Int32(0))); + if (nIndex<maSlidesPerPage.size()) + return maSlidesPerPage[nIndex]; + else if ( ! maSlidesPerPage.empty()) + return maSlidesPerPage[0]; + else + return 0; + } + + bool IsDraw() const + { + return GetBoolValue("PageContentType", sal_Int32(0)); + } + + bool IsHandout() const + { + return GetBoolValue("PageContentType", sal_Int32(1)); + } + + bool IsNotes() const + { + return GetBoolValue("PageContentType", sal_Int32(2)); + } + + bool IsOutline() const + { + return GetBoolValue("PageContentType", sal_Int32(3)); + } + + sal_uLong GetOutputQuality() const + { + sal_Int32 nQuality = static_cast<sal_Int32>(mrProperties.getIntValue( "Quality", sal_Int32(0) )); + return nQuality; + } + + bool IsPageSize() const + { + return GetBoolValue("PageOptions", sal_Int32(1)); + } + + bool IsTilePage() const + { + return GetBoolValue("PageOptions", sal_Int32(2)) || GetBoolValue("PageOptions", sal_Int32(3)); + } + + bool IsCutPage() const + { + return GetBoolValue("PageOptions", sal_Int32(0)); + } + + bool IsBooklet() const + { + return GetBoolValue("PrintProspect", false); + } + + bool IsPrinterPreferred(DocumentType eDocType) const + { + bool bIsDraw = eDocType == DocumentType::Draw; + return IsTilePage() || IsPageSize() || IsBooklet() || (!bIsDraw && !IsNotes()); + } + + bool IsPrintExcluded() const + { + return (IsNotes() || IsDraw() || IsHandout()) && IsHiddenPages(); + } + + bool IsPrintFrontPage() const + { + sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 )); + return nInclude != 2; + } + + bool IsPrintBackPage() const + { + sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 )); + return nInclude != 1; + } + + bool IsPaperBin() const + { + return GetBoolValue("PrintPaperFromSetup", false); + } + + bool IsPrintMarkedOnly() const + { + return GetBoolValue("PrintContent", sal_Int32(4)); + } + + OUString GetPrinterSelection (sal_Int32 nPageCount, sal_Int32 nCurrentPageIndex) const + { + sal_Int32 nContent = static_cast<sal_Int32>(mrProperties.getIntValue( "PrintContent", 0 )); + OUString sFullRange = "1-" + OUString::number(nPageCount); + + if (nContent == 0) // all pages/slides + { + return sFullRange; + } + + if (nContent == 1) // range + { + OUString sValue = mrProperties.getStringValue("PageRange"); + return sValue.isEmpty() ? sFullRange : sValue; + } + + if (nContent == 2 && // selection + nCurrentPageIndex >= 0) + { + return OUString::number(nCurrentPageIndex + 1); + } + + return OUString(); + } + + private: + const vcl::PrinterOptionsHelper& mrProperties; + const std::vector<sal_Int32> maSlidesPerPage; + + /** When the value of the property with name pName is a boolean then + return its value. When the property is unknown then + bDefaultValue is returned. Otherwise <FALSE/> is returned. + */ + bool GetBoolValue ( + const char* pName, + const bool bDefaultValue) const + { + bool bValue = mrProperties.getBoolValue( pName, bDefaultValue ); + return bValue; + } + + /** Return <TRUE/> when the value of the property with name pName is + an integer and its value is nTriggerValue. Otherwise <FALSE/> is + returned. + */ + bool GetBoolValue ( + const char* pName, + const sal_Int32 nTriggerValue) const + { + sal_Int32 nValue = static_cast<sal_Int32>(mrProperties.getIntValue( pName, 0 )); + return nValue == nTriggerValue; + } + }; + + /** A collection of values that helps to reduce the number of arguments + given to some functions. Note that not all values are set at the + same time. + */ + class PrintInfo + { + public: + PrintInfo ( + Printer* pPrinter, + const bool bPrintMarkedOnly) + : mpPrinter(pPrinter), + mnDrawMode(DrawModeFlags::Default), + maPrintSize(0,0), + maPageSize(0,0), + meOrientation(Orientation::Portrait), + mbPrintMarkedOnly(bPrintMarkedOnly) + {} + + const VclPtr<Printer> mpPrinter; + DrawModeFlags mnDrawMode; + OUString msTimeDate; + OUString msPageString; + Size maPrintSize; + Size maPageSize; + Orientation meOrientation; + MapMode maMap; + const bool mbPrintMarkedOnly; + }; + + /** Output one page of the document to the given printer. Note that + more than one document page may be output to one printer page. + */ + void PrintPage ( + Printer& rPrinter, + ::sd::View& rPrintView, + SdPage& rPage, + View const * pView, + const bool bPrintMarkedOnly, + const SdrLayerIDSet& rVisibleLayers, + const SdrLayerIDSet& rPrintableLayers) + { + rPrintView.ShowSdrPage(&rPage); + + const MapMode aOriginalMapMode (rPrinter.GetMapMode()); + + // Set the visible layers + SdrPageView* pPageView = rPrintView.GetSdrPageView(); + OSL_ASSERT(pPageView!=nullptr); + pPageView->SetVisibleLayers(rVisibleLayers); + pPageView->SetPrintableLayers(rPrintableLayers); + + if (pView!=nullptr && bPrintMarkedOnly) + pView->DrawMarkedObj(rPrinter); + else + rPrintView.CompleteRedraw(&rPrinter, + vcl::Region(::tools::Rectangle(Point(0,0), rPage.GetSize()))); + + rPrinter.SetMapMode(aOriginalMapMode); + + rPrintView.HideSdrPage(); + } + + /** Output a string (that typically is not part of a document page) to + the given printer. + */ + void PrintMessage ( + Printer& rPrinter, + const OUString& rsPageString, + const Point& rPageStringOffset) + { + const vcl::Font aOriginalFont (rPrinter.OutputDevice::GetFont()); + rPrinter.SetFont(vcl::Font(FAMILY_SWISS, Size(0, 423))); + rPrinter.DrawText(rPageStringOffset, rsPageString); + rPrinter.SetFont(aOriginalFont); + } + + /** Read the resources and process then into a sequence of properties + that can be passed to the printing dialog. + */ + class DialogCreator + { + public: + DialogCreator (ViewShellBase &rBase, bool bImpress, sal_Int32 nCurPage) + : mrBase(rBase) + , mbImpress(bImpress) + , mnCurPage(nCurPage) + { + ProcessResource(); + } + + const std::vector< beans::PropertyValue >& GetDialogControls() const + { + return maProperties; + } + + const std::vector<sal_Int32>& GetSlidesPerPage() const + { + return maSlidesPerPage; + } + + private: + ViewShellBase &mrBase; + std::vector<beans::PropertyValue> maProperties; + std::vector<sal_Int32> maSlidesPerPage; + bool mbImpress; + sal_Int32 mnCurPage; + + void ProcessResource() + { + // load the writer PrinterOptions into the custom tab + beans::PropertyValue aOptionsUIFile; + aOptionsUIFile.Name = "OptionsUIFile"; + if( mbImpress ) + aOptionsUIFile.Value <<= OUString("modules/simpress/ui/impressprinteroptions.ui"); + else + aOptionsUIFile.Value <<= OUString("modules/sdraw/ui/drawprinteroptions.ui"); + maProperties.push_back(aOptionsUIFile); + + SvtModuleOptions aOpt; + OUString aAppGroupname(SdResId(STR_IMPRESS_PRINT_UI_GROUP_NAME)); + aAppGroupname = aAppGroupname.replaceFirst("%s", aOpt.GetModuleName( + mbImpress ? SvtModuleOptions::EModule::IMPRESS : SvtModuleOptions::EModule::DRAW)); + AddDialogControl(vcl::PrinterOptionsHelper::setGroupControlOpt("tabcontrol-page2", aAppGroupname, ".HelpID:vcl:PrintDialog:TabPage:AppPage")); + + uno::Sequence< OUString > aHelpIds, aWidgetIds; + if( mbImpress ) + { + aHelpIds = { ".HelpID:vcl:PrintDialog:PageContentType:ListBox" }; + AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( + "impressdocument", + SdResId(STR_IMPRESS_PRINT_UI_CONTENT), + aHelpIds, + "PageContentType" , + CreateChoice(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES)), + 0) + ); + + aHelpIds = { ".HelpID:vcl:PrintDialog:SlidesPerPage:ListBox" }; + vcl::PrinterOptionsHelper::UIControlOptions aContentOpt( "PageContentType" , 1 ); + AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( + "slidesperpage", + SdResId(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE), + aHelpIds, + "SlidesPerPage" , + GetSlidesPerPageSequence(), + 0, + Sequence< sal_Bool >(), + aContentOpt + ) + ); + + aHelpIds = { ".HelpID:vcl:PrintDialog:SlidesPerPageOrder:ListBox" }; + vcl::PrinterOptionsHelper::UIControlOptions aSlidesPerPageOpt( "SlidesPerPage" , -1, true ); + AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( + "slidesperpageorder", + SdResId(STR_IMPRESS_PRINT_UI_ORDER), + aHelpIds, + "SlidesPerPageOrder" , + CreateChoice(STR_IMPRESS_PRINT_UI_ORDER_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_ORDER_CHOICES)), + 0, + Sequence< sal_Bool >(), + aSlidesPerPageOpt ) + ); + } + + AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("contents", + SdResId(STR_IMPRESS_PRINT_UI_INCLUDE_CONTENT), "" ) ); + + if( mbImpress ) + { + AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printname", + SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_NAME), + ".HelpID:vcl:PrintDialog:IsPrintName:CheckBox" , + "IsPrintName" , + officecfg::Office::Impress::Print::Other::PageName::get() + ) + ); + } + else + { + AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printname", + SdResId(STR_DRAW_PRINT_UI_IS_PRINT_NAME), + ".HelpID:vcl:PrintDialog:IsPrintName:CheckBox" , + "IsPrintName" , + officecfg::Office::Draw::Print::Other::PageName::get() + ) + ); + } + + AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printdatetime", + SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_DATE), + ".HelpID:vcl:PrintDialog:IsPrintDateTime:CheckBox" , + "IsPrintDateTime" , + // Separate settings for time and date in Impress/Draw -> Print page, check that both are set + mbImpress ? + officecfg::Office::Impress::Print::Other::Date::get() && + officecfg::Office::Impress::Print::Other::Time::get() : + officecfg::Office::Draw::Print::Other::Date::get() && + officecfg::Office::Draw::Print::Other::Time::get() + ) + ); + + if( mbImpress ) + { + AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printhidden", + SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_HIDDEN), + ".HelpID:vcl:PrintDialog:IsPrintHidden:CheckBox" , + "IsPrintHidden" , + officecfg::Office::Impress::Print::Other::HiddenPage::get() + ) + ); + } + + AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("color", + SdResId(STR_IMPRESS_PRINT_UI_QUALITY), "" ) ); + + aHelpIds = { ".HelpID:vcl:PrintDialog:Quality:RadioButton:0", + ".HelpID:vcl:PrintDialog:Quality:RadioButton:1", + ".HelpID:vcl:PrintDialog:Quality:RadioButton:2" }; + aWidgetIds = { "originalcolors", "grayscale", "blackandwhite" }; + AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt( + aWidgetIds, + "", + aHelpIds, + "Quality" , + CreateChoice(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES)), + mbImpress ? officecfg::Office::Impress::Print::Other::Quality::get() : + officecfg::Office::Draw::Print::Other::Quality::get() ) + + ); + + AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("pagesizes", + SdResId(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS), "" ) ); + + aHelpIds = { ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:0", + ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:1", + ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:2", + ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:3" }; + aWidgetIds = { "originalsize", "fittoprintable", "distributeonmultiple", "tilesheet" }; + + // Mutually exclusive page options settings are stored in separate config keys... + // TODO: There is no config key to set the distributeonmultiple option as default + sal_Int32 nDefaultChoice = 0; + if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageSize::get() : + officecfg::Office::Draw::Print::Page::PageSize::get() ) + { + nDefaultChoice = 1; + } + else if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageTile::get() : + officecfg::Office::Draw::Print::Page::PageTile::get() ) + { + nDefaultChoice = 3; + } + vcl::PrinterOptionsHelper::UIControlOptions aPageOptionsOpt("PrintProspect", 0); + AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt( + aWidgetIds, + "", + aHelpIds, + "PageOptions" , + mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES)) : + CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW)), + nDefaultChoice, + Sequence< sal_Bool >(), + aPageOptionsOpt + ) + ); + + vcl::PrinterOptionsHelper::UIControlOptions aBrochureOpt; + aBrochureOpt.maGroupHint = "LayoutPage" ; + AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("pagesides", + SdResId(STR_IMPRESS_PRINT_UI_PAGE_SIDES), "", + aBrochureOpt ) ); + + // brochure printing + AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("brochure", + SdResId(STR_IMPRESS_PRINT_UI_BROCHURE), + ".HelpID:vcl:PrintDialog:PrintProspect:CheckBox" , + "PrintProspect" , + mbImpress ? officecfg::Office::Impress::Print::Page::Booklet::get() : + officecfg::Office::Draw::Print::Page::Booklet::get(), + aBrochureOpt + ) + ); + + vcl::PrinterOptionsHelper::UIControlOptions + aIncludeOpt( "PrintProspect" , -1, false ); + aIncludeOpt.maGroupHint = "LayoutPage" ; + aHelpIds = { ".HelpID:vcl:PrintDialog:PrintProspectInclude:ListBox" }; + AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( + "brochureinclude", + SdResId(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE), + aHelpIds, + "PrintProspectInclude" , + CreateChoice(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST)), + 0, + Sequence< sal_Bool >(), + aIncludeOpt + ) + ); + + // paper tray (on options page) + vcl::PrinterOptionsHelper::UIControlOptions aPaperTrayOpt; + aPaperTrayOpt.maGroupHint = "OptionsPageOptGroup" ; + AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printpaperfromsetup", + SdResId(STR_IMPRESS_PRINT_UI_PAPER_TRAY), + ".HelpID:vcl:PrintDialog:PrintPaperFromSetup:CheckBox" , + "PrintPaperFromSetup" , + false, + aPaperTrayOpt + ) + ); + // print range selection + vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt; + aPrintRangeOpt.mbInternalOnly = true; + aPrintRangeOpt.maGroupHint = "PrintRange" ; + AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("printrange", + mbImpress ? SdResId(STR_IMPRESS_PRINT_UI_SLIDE_RANGE) : SdResId(STR_IMPRESS_PRINT_UI_PAGE_RANGE), + "", + aPrintRangeOpt ) + ); + + // check if there is a selection of slides + OUString aPageRange(OUString::number(mnCurPage + 1)); + int nPrintRange(0); + using sd::slidesorter::SlideSorterViewShell; + SlideSorterViewShell* const pSSViewSh(SlideSorterViewShell::GetSlideSorter(mrBase)); + if (pSSViewSh) + { + const std::shared_ptr<SlideSorterViewShell::PageSelection> pPageSelection(pSSViewSh->GetPageSelection()); + if (bool(pPageSelection) && pPageSelection->size() > 1) + { + OUStringBuffer aBuf; + // TODO: this could be improved by writing ranges instead of consecutive page + // numbers if appropriate. Do we have a helper function for that somewhere? + bool bFirst(true); + for (auto pPage: *pPageSelection) + { + if (bFirst) + bFirst = false; + else + aBuf.append(','); + aBuf.append(static_cast<sal_Int32>(pPage->GetPageNum() / 2 + 1)); + } + aPageRange = aBuf.makeStringAndClear(); + nPrintRange = 1; + } + } +/* + OUString aPrintRangeName( "PrintContent" ); + aHelpIds.realloc( 1 ); + aHelpIds[0] = ".HelpID:vcl:PrintDialog:PageContentType:ListBox"; + AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( "printpagesbox", OUString(), + aHelpIds, aPrintRangeName, + mbImpress ? CreateChoice( STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE ) ) : + CreateChoice( STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE ) ), + nPrintRange ) ); +*/ + OUString aPrintRangeName( "PrintContent" ); + aHelpIds = { ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:0", + ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:1", + ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:2" }; + aWidgetIds = { "rbAllPages", "rbRangePages", "rbRangeSelection" }; + + AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(aWidgetIds, OUString(), + aHelpIds, aPrintRangeName, + mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE)) : + CreateChoice(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE)), + nPrintRange ) + ); + // create an Edit dependent on "Pages" selected + vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true ); + AddDialogControl(vcl::PrinterOptionsHelper::setEditControlOpt("pagerange", "", + ".HelpID:vcl:PrintDialog:PageRange:Edit", "PageRange", + aPageRange, aPageRangeOpt)); + vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, -1, true); + AddDialogControl(vcl::PrinterOptionsHelper::setChoiceListControlOpt("evenoddbox", "", + uno::Sequence<OUString>(), "EvenOdd", uno::Sequence<OUString>(), + 0, uno::Sequence<sal_Bool>(), aEvenOddOpt)); + } + + void AddDialogControl( const Any& i_rCtrl ) + { + beans::PropertyValue aVal; + aVal.Value = i_rCtrl; + maProperties.push_back( aVal ); + } + + static Sequence<OUString> CreateChoice(const TranslateId* pResourceId, size_t nCount) + { + Sequence<OUString> aChoices (nCount); + std::transform(pResourceId, pResourceId + nCount, aChoices.getArray(), + [](const auto& id) { return SdResId(id); }); + return aChoices; + } + + Sequence<OUString> GetSlidesPerPageSequence() + { + const Sequence<OUString> aChoice ( + CreateChoice(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES))); + maSlidesPerPage.clear(); + maSlidesPerPage.push_back(0); // first is using the default + std::transform(std::next(aChoice.begin()), aChoice.end(), std::back_inserter(maSlidesPerPage), + [](const OUString& rChoice) -> sal_Int32 { return rChoice.toInt32(); }); + return aChoice; + } + }; + + /** The Prepare... methods of the DocumentRenderer::Implementation class + create a set of PrinterPage objects that contain all necessary + information to do the actual printing. There is one PrinterPage + object per printed page. Derived classes implement the actual, mode + specific printing. + + This and all derived classes support the asynchronous printing + process by not storing pointers to any data with lifetime shorter + than the PrinterPage objects, i.e. slides, shapes, (one of) the + outliner (of the document). + */ + class PrinterPage + { + public: + PrinterPage ( + const PageKind ePageKind, + const MapMode& rMapMode, + const bool bPrintMarkedOnly, + OUString sPageString, + const Point& rPageStringOffset, + const DrawModeFlags nDrawMode, + const Orientation eOrientation, + const sal_uInt16 nPaperTray) + : mePageKind(ePageKind), + maMap(rMapMode), + mbPrintMarkedOnly(bPrintMarkedOnly), + msPageString(std::move(sPageString)), + maPageStringOffset(rPageStringOffset), + mnDrawMode(nDrawMode), + meOrientation(eOrientation), + mnPaperTray(nPaperTray) + { + } + + virtual ~PrinterPage() {} + + virtual void Print ( + Printer& rPrinter, + SdDrawDocument& rDocument, + ViewShell& rViewShell, + View* pView, + DrawView& rPrintView, + const SdrLayerIDSet& rVisibleLayers, + const SdrLayerIDSet& rPrintableLayers) const = 0; + + DrawModeFlags GetDrawMode() const { return mnDrawMode; } + Orientation GetOrientation() const { return meOrientation; } + sal_uInt16 GetPaperTray() const { return mnPaperTray; } + + protected: + const PageKind mePageKind; + const MapMode maMap; + const bool mbPrintMarkedOnly; + const OUString msPageString; + const Point maPageStringOffset; + const DrawModeFlags mnDrawMode; + const Orientation meOrientation; + const sal_uInt16 mnPaperTray; + }; + + /** The RegularPrinterPage is used for printing one regular slide (no + notes, handout, or outline) to one printer page. + */ + class RegularPrinterPage : public PrinterPage + { + public: + RegularPrinterPage ( + const sal_uInt16 nPageIndex, + const PageKind ePageKind, + const MapMode& rMapMode, + const bool bPrintMarkedOnly, + const OUString& rsPageString, + const Point& rPageStringOffset, + const DrawModeFlags nDrawMode, + const Orientation eOrientation, + const sal_uInt16 nPaperTray) + : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, rsPageString, + rPageStringOffset, nDrawMode, eOrientation, nPaperTray), + mnPageIndex(nPageIndex) + { + } + + virtual void Print ( + Printer& rPrinter, + SdDrawDocument& rDocument, + ViewShell&, + View* pView, + DrawView& rPrintView, + const SdrLayerIDSet& rVisibleLayers, + const SdrLayerIDSet& rPrintableLayers) const override + { + SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind); + rPrinter.SetMapMode(maMap); + PrintPage( + rPrinter, + rPrintView, + *pPageToPrint, + pView, + mbPrintMarkedOnly, + rVisibleLayers, + rPrintableLayers); + PrintMessage( + rPrinter, + msPageString, + maPageStringOffset); + } + + private: + const sal_uInt16 mnPageIndex; + }; + + /** Print one slide multiple times on a printer page so that the whole + printer page is covered. + */ + class TiledPrinterPage : public PrinterPage + { + public: + TiledPrinterPage ( + const sal_uInt16 nPageIndex, + const PageKind ePageKind, + const bool bPrintMarkedOnly, + const OUString& rsPageString, + const Point& rPageStringOffset, + const DrawModeFlags nDrawMode, + const Orientation eOrientation, + const sal_uInt16 nPaperTray) + : PrinterPage(ePageKind, MapMode(), bPrintMarkedOnly, rsPageString, + rPageStringOffset, nDrawMode, eOrientation, nPaperTray), + mnPageIndex(nPageIndex) + { + } + + virtual void Print ( + Printer& rPrinter, + SdDrawDocument& rDocument, + ViewShell&, + View* pView, + DrawView& rPrintView, + const SdrLayerIDSet& rVisibleLayers, + const SdrLayerIDSet& rPrintableLayers) const override + { + SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind); + if (pPageToPrint==nullptr) + return; + MapMode aMap (rPrinter.GetMapMode()); + + const Size aPageSize (pPageToPrint->GetSize()); + const Size aPrintSize (rPrinter.GetOutputSize()); + + const sal_Int32 nPageWidth (aPageSize.Width() + mnGap + - pPageToPrint->GetLeftBorder() - pPageToPrint->GetRightBorder()); + const sal_Int32 nPageHeight (aPageSize.Height() + mnGap + - pPageToPrint->GetUpperBorder() - pPageToPrint->GetLowerBorder()); + if (nPageWidth<=0 || nPageHeight<=0) + return; + + // Print at least two rows and columns. More if the document + // page fits completely onto the printer page. + const sal_Int32 nColumnCount (std::max(sal_Int32(2), + sal_Int32(aPrintSize.Width() / nPageWidth))); + const sal_Int32 nRowCount (std::max(sal_Int32(2), + sal_Int32(aPrintSize.Height() / nPageHeight))); + for (sal_Int32 nRow=0; nRow<nRowCount; ++nRow) + for (sal_Int32 nColumn=0; nColumn<nColumnCount; ++nColumn) + { + aMap.SetOrigin(Point(nColumn*nPageWidth,nRow*nPageHeight)); + rPrinter.SetMapMode(aMap); + PrintPage( + rPrinter, + rPrintView, + *pPageToPrint, + pView, + mbPrintMarkedOnly, + rVisibleLayers, + rPrintableLayers); + } + + PrintMessage( + rPrinter, + msPageString, + maPageStringOffset); + } + + private: + const sal_uInt16 mnPageIndex; + static const sal_Int32 mnGap = 500; + }; + + /** Print two slides to one printer page so that the resulting pages + form a booklet. + */ + class BookletPrinterPage : public PrinterPage + { + public: + BookletPrinterPage ( + const sal_uInt16 nFirstPageIndex, + const sal_uInt16 nSecondPageIndex, + const Point& rFirstOffset, + const Point& rSecondOffset, + const PageKind ePageKind, + const MapMode& rMapMode, + const bool bPrintMarkedOnly, + const DrawModeFlags nDrawMode, + const Orientation eOrientation, + const sal_uInt16 nPaperTray) + : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, "", + Point(), nDrawMode, eOrientation, nPaperTray), + mnFirstPageIndex(nFirstPageIndex), + mnSecondPageIndex(nSecondPageIndex), + maFirstOffset(rFirstOffset), + maSecondOffset(rSecondOffset) + { + } + + virtual void Print ( + Printer& rPrinter, + SdDrawDocument& rDocument, + ViewShell&, + View* pView, + DrawView& rPrintView, + const SdrLayerIDSet& rVisibleLayers, + const SdrLayerIDSet& rPrintableLayers) const override + { + MapMode aMap (maMap); + SdPage* pPageToPrint = rDocument.GetSdPage(mnFirstPageIndex, mePageKind); + if (pPageToPrint) + { + aMap.SetOrigin(maFirstOffset); + rPrinter.SetMapMode(aMap); + PrintPage( + rPrinter, + rPrintView, + *pPageToPrint, + pView, + mbPrintMarkedOnly, + rVisibleLayers, + rPrintableLayers); + } + + pPageToPrint = rDocument.GetSdPage(mnSecondPageIndex, mePageKind); + if( !pPageToPrint ) + return; + + aMap.SetOrigin(maSecondOffset); + rPrinter.SetMapMode(aMap); + PrintPage( + rPrinter, + rPrintView, + *pPageToPrint, + pView, + mbPrintMarkedOnly, + rVisibleLayers, + rPrintableLayers); + } + + private: + const sal_uInt16 mnFirstPageIndex; + const sal_uInt16 mnSecondPageIndex; + const Point maFirstOffset; + const Point maSecondOffset; + }; + + /** One handout page displays one to nine slides. + */ + class HandoutPrinterPage : public PrinterPage + { + public: + HandoutPrinterPage ( + const sal_uInt16 nHandoutPageIndex, + std::vector<sal_uInt16>&& rPageIndices, + const MapMode& rMapMode, + const OUString& rsPageString, + const Point& rPageStringOffset, + const DrawModeFlags nDrawMode, + const Orientation eOrientation, + const sal_uInt16 nPaperTray) + : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString, + rPageStringOffset, nDrawMode, eOrientation, nPaperTray), + mnHandoutPageIndex(nHandoutPageIndex), + maPageIndices(std::move(rPageIndices)) + { + } + + virtual void Print ( + Printer& rPrinter, + SdDrawDocument& rDocument, + ViewShell& rViewShell, + View* pView, + DrawView& rPrintView, + const SdrLayerIDSet& rVisibleLayers, + const SdrLayerIDSet& rPrintableLayers) const override + { + SdPage& rHandoutPage (*rDocument.GetSdPage(0, PageKind::Handout)); + + Reference< css::beans::XPropertySet > xHandoutPage( rHandoutPage.getUnoPage(), UNO_QUERY ); + static constexpr OUString sPageNumber( u"Number"_ustr ); + + // Collect the page objects of the handout master. + std::vector<SdrPageObj*> aHandoutPageObjects; + SdrObjListIter aShapeIter (&rHandoutPage); + while (aShapeIter.IsMore()) + { + SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next()); + if (pPageObj) + aHandoutPageObjects.push_back(pPageObj); + } + if (aHandoutPageObjects.empty()) + return; + + // Connect page objects with pages. + std::vector<SdrPageObj*>::iterator aPageObjIter (aHandoutPageObjects.begin()); + for (std::vector<sal_uInt16>::const_iterator + iPageIndex(maPageIndices.begin()), + iEnd(maPageIndices.end()); + iPageIndex!=iEnd && aPageObjIter!=aHandoutPageObjects.end(); + ++iPageIndex) + { + // Check if the page still exists. + if (*iPageIndex >= rDocument.GetSdPageCount(PageKind::Standard)) + continue; + + SdrPageObj* pPageObj = *aPageObjIter++; + pPageObj->SetReferencedPage(rDocument.GetSdPage(*iPageIndex, PageKind::Standard)); + } + + // if there are more page objects than pages left, set the rest to invisible + int nHangoverCount = 0; + while (aPageObjIter != aHandoutPageObjects.end()) + { + (*aPageObjIter++)->SetReferencedPage(nullptr); + nHangoverCount++; + } + + // Hide outlines for objects that have pages attached. + if (nHangoverCount > 0) + { + int nSkip = aHandoutPageObjects.size() - nHangoverCount; + aShapeIter.Reset(); + while (aShapeIter.IsMore()) + { + SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next()); + if (pPathObj) + { + if (nSkip > 0) + --nSkip; + else + pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE)); + } + } + } + + if( xHandoutPage.is() ) try + { + xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(mnHandoutPageIndex) ) ); + } + catch( Exception& ) + { + } + rViewShell.SetPrintedHandoutPageNum( mnHandoutPageIndex + 1 ); + + rPrinter.SetMapMode(maMap); + + PrintPage( + rPrinter, + rPrintView, + rHandoutPage, + pView, + false, + rVisibleLayers, + rPrintableLayers); + PrintMessage( + rPrinter, + msPageString, + maPageStringOffset); + + if( xHandoutPage.is() ) try + { + xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(0) ) ); + } + catch( Exception& ) + { + } + rViewShell.SetPrintedHandoutPageNum(1); + + // Restore outlines. + if (nHangoverCount > 0) + { + aShapeIter.Reset(); + while (aShapeIter.IsMore()) + { + SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next()); + if (pPathObj != nullptr) + pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID)); + } + } + + } + + private: + const sal_uInt16 mnHandoutPageIndex; + const std::vector<sal_uInt16> maPageIndices; + }; + + /** The outline information (title, subtitle, outline objects) of the + document. There is no fixed mapping of slides to printer pages. + */ + class OutlinerPrinterPage : public PrinterPage + { + public: + OutlinerPrinterPage ( + std::optional<OutlinerParaObject> pParaObject, + const MapMode& rMapMode, + const OUString& rsPageString, + const Point& rPageStringOffset, + const DrawModeFlags nDrawMode, + const Orientation eOrientation, + const sal_uInt16 nPaperTray) + : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString, + rPageStringOffset, nDrawMode, eOrientation, nPaperTray), + mpParaObject(std::move(pParaObject)) + { + } + + virtual void Print ( + Printer& rPrinter, + SdDrawDocument& rDocument, + ViewShell&, + View*, + DrawView&, + const SdrLayerIDSet&, + const SdrLayerIDSet&) const override + { + // Set up the printer. + rPrinter.SetMapMode(maMap); + + // Get and set up the outliner. + const ::tools::Rectangle aOutRect (rPrinter.GetPageOffset(), rPrinter.GetOutputSize()); + Outliner* pOutliner = rDocument.GetInternalOutliner(); + const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode()); + const bool bSavedUpdateMode (pOutliner->IsUpdateLayout()); + const Size aSavedPaperSize (pOutliner->GetPaperSize()); + + pOutliner->Init(OutlinerMode::OutlineView); + pOutliner->SetPaperSize(aOutRect.GetSize()); + pOutliner->SetUpdateLayout(true); + pOutliner->Clear(); + pOutliner->SetText(*mpParaObject); + + pOutliner->Draw(rPrinter, aOutRect); + + PrintMessage( + rPrinter, + msPageString, + maPageStringOffset); + + // Restore outliner and printer. + pOutliner->Clear(); + pOutliner->SetUpdateLayout(bSavedUpdateMode); + pOutliner->SetPaperSize(aSavedPaperSize); + pOutliner->Init(nSavedOutlMode); + } + + private: + std::optional<OutlinerParaObject> mpParaObject; + }; +} + +//===== DocumentRenderer::Implementation ====================================== + +class DocumentRenderer::Implementation + : public SfxListener, + public vcl::PrinterOptionsHelper +{ +public: + explicit Implementation (ViewShellBase& rBase) + : mxObjectShell(rBase.GetDocShell()) + , mrBase(rBase) + , mbIsDisposed(false) + , mpPrinter(nullptr) + , mbHasOrientationWarningBeenShown(false) + { + DialogCreator aCreator( mrBase, mrBase.GetDocShell()->GetDocumentType() == DocumentType::Impress, GetCurrentPageIndex() ); + m_aUIProperties = aCreator.GetDialogControls(); + maSlidesPerPage = aCreator.GetSlidesPerPage(); + + StartListening(mrBase); + } + + virtual ~Implementation() override + { + EndListening(mrBase); + } + + virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override + { + if (&rBroadcaster != &static_cast<SfxBroadcaster&>(mrBase)) + return; + + if (rHint.GetId() == SfxHintId::Dying) + { + mbIsDisposed = true; + } + } + + /** Process the sequence of properties given to one of the XRenderable + methods. + */ + void ProcessProperties (const css::uno::Sequence<css::beans::PropertyValue >& rOptions) + { + OSL_ASSERT(!mbIsDisposed); + if (mbIsDisposed) + return; + + bool bIsValueChanged = processProperties( rOptions ); + bool bIsPaperChanged = false; + + // The RenderDevice property is handled specially: its value is + // stored in mpPrinter instead of being retrieved on demand. + Any aDev( getValue( "RenderDevice" ) ); + Reference<awt::XDevice> xRenderDevice; + + if (aDev >>= xRenderDevice) + { + VCLXDevice* pDevice = dynamic_cast<VCLXDevice*>(xRenderDevice.get()); + VclPtr< OutputDevice > pOut = pDevice ? pDevice->GetOutputDevice() + : VclPtr< OutputDevice >(); + mpPrinter = dynamic_cast<Printer*>(pOut.get()); + Size aPageSizePixel = mpPrinter ? mpPrinter->GetPaperSizePixel() : Size(); + if( aPageSizePixel != maPrinterPageSizePixel ) + { + bIsPaperChanged = true; + maPrinterPageSizePixel = aPageSizePixel; + } + } + + if (bIsValueChanged && ! mpOptions ) + mpOptions.reset(new PrintOptions(*this, std::vector(maSlidesPerPage))); + if( bIsValueChanged || bIsPaperChanged ) + PreparePages(); + } + + /** Return the number of pages that are to be printed. + */ + sal_Int32 GetPrintPageCount() const + { + OSL_ASSERT(!mbIsDisposed); + if (mbIsDisposed) + return 0; + else + return maPrinterPages.size(); + } + + /** Return a sequence of properties that can be returned by the + XRenderable::getRenderer() method. + */ + css::uno::Sequence<css::beans::PropertyValue> GetProperties () const + { + css::uno::Sequence<css::beans::PropertyValue> aProperties{ + comphelper::makePropertyValue("ExtraPrintUIOptions", + comphelper::containerToSequence(m_aUIProperties)), + comphelper::makePropertyValue("PageSize", maPrintSize), + // FIXME: is this always true ? + comphelper::makePropertyValue("PageIncludesNonprintableArea", true) + }; + + return aProperties; + } + + /** Print one of the prepared pages. + */ + void PrintPage (const sal_Int32 nIndex) + { + OSL_ASSERT(!mbIsDisposed); + if (mbIsDisposed) + return; + + Printer& rPrinter (*mpPrinter); + + std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell()); + if ( ! pViewShell) + return; + + SdDrawDocument* pDocument = pViewShell->GetDoc(); + OSL_ASSERT(pDocument!=nullptr); + + std::shared_ptr<DrawViewShell> pDrawViewShell( + std::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell())); + + if (!mpPrintView) + mpPrintView.reset(new DrawView(mrBase.GetDocShell(), &rPrinter, nullptr)); + + if (nIndex<0 || sal::static_int_cast<sal_uInt32>(nIndex)>=maPrinterPages.size()) + return; + + const std::shared_ptr<PrinterPage> pPage (maPrinterPages[nIndex]); + OSL_ASSERT(pPage); + if ( ! pPage) + return; + + const Orientation eSavedOrientation (rPrinter.GetOrientation()); + const DrawModeFlags nSavedDrawMode (rPrinter.GetDrawMode()); + const MapMode aSavedMapMode (rPrinter.GetMapMode()); + const sal_uInt16 nSavedPaperBin (rPrinter.GetPaperBin()); + + // Set page orientation. + if ( ! rPrinter.SetOrientation(pPage->GetOrientation())) + { + if ( ! mbHasOrientationWarningBeenShown + && mpOptions->IsWarningOrientation()) + { + mbHasOrientationWarningBeenShown = true; + // Show warning that the orientation could not be set. + std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog( + pViewShell->GetFrameWeld(), VclMessageType::Warning, VclButtonsType::OkCancel, + SdResId(STR_WARN_PRINTFORMAT_FAILURE))); + xWarn->set_default_response(RET_CANCEL); + if (xWarn->run() != RET_OK) + return; + } + } + + // Set the draw mode. + rPrinter.SetDrawMode(pPage->GetDrawMode()); + + // Set paper tray. + rPrinter.SetPaperBin(pPage->GetPaperTray()); + + // Print the actual page. + pPage->Print( + rPrinter, + *pDocument, + *pViewShell, + pDrawViewShell ? pDrawViewShell->GetView() : nullptr, + *mpPrintView, + pViewShell->GetFrameView()->GetVisibleLayers(), + pViewShell->GetFrameView()->GetPrintableLayers()); + + rPrinter.SetOrientation(eSavedOrientation); + rPrinter.SetDrawMode(nSavedDrawMode); + rPrinter.SetMapMode(aSavedMapMode); + rPrinter.SetPaperBin(nSavedPaperBin); + } + +private: + // rhbz#657394: keep the document alive: prevents crash when + SfxObjectShellRef mxObjectShell; // destroying mpPrintView + ViewShellBase& mrBase; + bool mbIsDisposed; + VclPtr<Printer> mpPrinter; + Size maPrinterPageSizePixel; + std::unique_ptr<PrintOptions> mpOptions; + std::vector< std::shared_ptr< ::sd::PrinterPage> > maPrinterPages; + std::unique_ptr<DrawView> mpPrintView; + bool mbHasOrientationWarningBeenShown; + std::vector<sal_Int32> maSlidesPerPage; + awt::Size maPrintSize; + + sal_Int32 GetCurrentPageIndex() const + { + const ViewShell *pShell = mrBase.GetMainViewShell().get(); + const SdPage *pCurrentPage = pShell ? pShell->getCurrentPage() : nullptr; + return pCurrentPage ? (pCurrentPage->GetPageNum()-1)/2 : -1; + } + + /** Determine and set the paper orientation. + */ + void SetupPaperOrientation ( + const PageKind ePageKind, + PrintInfo& rInfo) + { + SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc(); + rInfo.meOrientation = Orientation::Portrait; + + if( ! mpOptions->IsBooklet()) + { + rInfo.meOrientation = pDocument->GetSdPage(0, ePageKind)->GetOrientation(); + } + else if (rInfo.maPageSize.Width() < rInfo.maPageSize.Height()) + rInfo.meOrientation = Orientation::Landscape; + + // Draw and Notes should usually abide by their specified paper size + Size aPaperSize; + if (!mpOptions->IsPrinterPreferred(pDocument->GetDocumentType())) + { + aPaperSize.setWidth(rInfo.maPageSize.Width()); + aPaperSize.setHeight(rInfo.maPageSize.Height()); + } + else + { + aPaperSize.setWidth(rInfo.mpPrinter->GetPaperSize().Width()); + aPaperSize.setHeight(rInfo.mpPrinter->GetPaperSize().Height()); + } + + maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height()); + + if (mpOptions->IsPrinterPreferred(pDocument->GetDocumentType())) + { + if( (rInfo.meOrientation == Orientation::Landscape && + (aPaperSize.Width() < aPaperSize.Height())) + || + (rInfo.meOrientation == Orientation::Portrait && + (aPaperSize.Width() > aPaperSize.Height())) + ) + { + maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width()); + } + } + } + + /** Top most method for preparing printer pages. In this and the other + Prepare... methods the various special cases are detected and + handled. + For every page that is to be printed (that may contain several + slides) one PrinterPage object is created and inserted into + maPrinterPages. + */ + void PreparePages() + { + mpPrintView.reset(); + maPrinterPages.clear(); + mbHasOrientationWarningBeenShown = false; + + ViewShell* pShell = mrBase.GetMainViewShell().get(); + + PrintInfo aInfo (mpPrinter, mpOptions->IsPrintMarkedOnly()); + + if (aInfo.mpPrinter==nullptr || pShell==nullptr) + return; + + MapMode aMap (aInfo.mpPrinter->GetMapMode()); + aMap.SetMapUnit(MapUnit::Map100thMM); + aInfo.maMap = aMap; + mpPrinter->SetMapMode(aMap); + + ::Outliner& rOutliner = mrBase.GetDocument()->GetDrawOutliner(); + const EEControlBits nSavedControlWord (rOutliner.GetControlWord()); + EEControlBits nCntrl = nSavedControlWord; + nCntrl &= ~EEControlBits::MARKFIELDS; + nCntrl &= ~EEControlBits::ONLINESPELLING; + rOutliner.SetControlWord( nCntrl ); + + // When in outline view then apply all pending changes to the model. + if( auto pOutlineViewShell = dynamic_cast< OutlineViewShell *>( pShell ) ) + pOutlineViewShell->PrepareClose (false); + + // Collect some frequently used data. + if (mpOptions->IsDate()) + { + aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData().getDate( Date( Date::SYSTEM ) ); + aInfo.msTimeDate += " "; + } + + if (mpOptions->IsTime()) + aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData().getTime( ::tools::Time( ::tools::Time::SYSTEM ), false ); + + // Draw and Notes should usually use specified paper size when printing + if (!mpOptions->IsPrinterPreferred(mrBase.GetDocShell()->GetDocumentType())) + { + aInfo.maPrintSize = mrBase.GetDocument()->GetSdPage(0, PageKind::Standard)->GetSize(); + maPrintSize = awt::Size(aInfo.maPrintSize.Width(), + aInfo.maPrintSize.Height()); + } + else + { + aInfo.maPrintSize = aInfo.mpPrinter->GetOutputSize(); + maPrintSize = awt::Size( + aInfo.mpPrinter->GetPaperSize().Width(), + aInfo.mpPrinter->GetPaperSize().Height()); + } + + switch (mpOptions->GetOutputQuality()) + { + case 1: // Grayscale + aInfo.mnDrawMode = DrawModeFlags::GrayLine | DrawModeFlags::GrayFill + | DrawModeFlags::GrayText | DrawModeFlags::GrayBitmap + | DrawModeFlags::GrayGradient; + break; + + case 2: // Black & White + aInfo.mnDrawMode = DrawModeFlags::BlackLine | DrawModeFlags::WhiteFill + | DrawModeFlags::BlackText | DrawModeFlags::GrayBitmap + | DrawModeFlags::WhiteGradient; + break; + + default: + aInfo.mnDrawMode = DrawModeFlags::Default; + } + + if (mpOptions->IsDraw()) + PrepareStdOrNotes(PageKind::Standard, aInfo); + if (mpOptions->IsNotes()) + PrepareStdOrNotes(PageKind::Notes, aInfo); + if (mpOptions->IsHandout()) + { + InitHandoutTemplate(); + PrepareHandout(aInfo); + } + if (mpOptions->IsOutline()) + PrepareOutline(aInfo); + + rOutliner.SetControlWord(nSavedControlWord); + } + + /** Create the page objects of the handout template. When the actual + printing takes place then the page objects are assigned different + sets of slides for each printed page (see HandoutPrinterPage::Print). + */ + void InitHandoutTemplate() + { + const sal_Int32 nSlidesPerHandout (mpOptions->GetHandoutPageCount()); + const bool bHandoutHorizontal (mpOptions->IsHandoutHorizontal()); + + AutoLayout eLayout = AUTOLAYOUT_HANDOUT6; + switch (nSlidesPerHandout) + { + case 0: eLayout = AUTOLAYOUT_NONE; break; // AUTOLAYOUT_HANDOUT1; break; + case 1: eLayout = AUTOLAYOUT_HANDOUT1; break; + case 2: eLayout = AUTOLAYOUT_HANDOUT2; break; + case 3: eLayout = AUTOLAYOUT_HANDOUT3; break; + case 4: eLayout = AUTOLAYOUT_HANDOUT4; break; + default: + case 6: eLayout = AUTOLAYOUT_HANDOUT6; break; + case 9: eLayout = AUTOLAYOUT_HANDOUT9; break; + } + + if( !mrBase.GetDocument() ) + return; + + SdDrawDocument& rModel = *mrBase.GetDocument(); + + // first, prepare handout page (not handout master) + + SdPage* pHandout = rModel.GetSdPage(0, PageKind::Handout); + if( !pHandout ) + return; + + // delete all previous shapes from handout page + while( pHandout->GetObjCount() ) + pHandout->NbcRemoveObject(0); + + const bool bDrawLines (eLayout == AUTOLAYOUT_HANDOUT3); + + std::vector< ::tools::Rectangle > aAreas; + SdPage::CalculateHandoutAreas( rModel, eLayout, bHandoutHorizontal, aAreas ); + + std::vector< ::tools::Rectangle >::iterator iter( aAreas.begin() ); + while( iter != aAreas.end() ) + { + pHandout->NbcInsertObject( + new SdrPageObj( + rModel, + (*iter++))); + + if( bDrawLines && (iter != aAreas.end()) ) + { + ::tools::Rectangle aRect( *iter++ ); + + basegfx::B2DPolygon aPoly; + aPoly.insert(0, basegfx::B2DPoint( aRect.Left(), aRect.Top() ) ); + aPoly.insert(1, basegfx::B2DPoint( aRect.Right(), aRect.Top() ) ); + + basegfx::B2DHomMatrix aMatrix; + aMatrix.translate( 0.0, static_cast< double >( aRect.GetHeight() / 7 ) ); + + basegfx::B2DPolyPolygon aPathPoly; + for( sal_uInt16 nLine = 0; nLine < 7; nLine++ ) + { + aPoly.transform( aMatrix ); + aPathPoly.append( aPoly ); + } + + rtl::Reference<SdrPathObj> pPathObj = new SdrPathObj( + rModel, + SdrObjKind::PathLine, + std::move(aPathPoly)); + pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID)); + pPathObj->SetMergedItem(XLineColorItem(OUString(), COL_BLACK)); + + pHandout->NbcInsertObject( pPathObj.get() ); + } + } + } + + /** Detect whether the specified slide is to be printed. + @return + When the slide is not to be printed then <NULL/> is returned. + Otherwise a pointer to the slide is returned. + */ + SdPage* GetFilteredPage ( + const sal_Int32 nPageIndex, + const PageKind ePageKind) const + { + OSL_ASSERT(mrBase.GetDocument() != nullptr); + OSL_ASSERT(nPageIndex>=0); + SdPage* pPage = mrBase.GetDocument()->GetSdPage( + sal::static_int_cast<sal_uInt16>(nPageIndex), + ePageKind); + if (pPage == nullptr) + return nullptr; + if ( ! pPage->IsExcluded() || mpOptions->IsPrintExcluded()) + return pPage; + else + return nullptr; + } + + /** Prepare the outline of the document for printing. There is no fixed + number of slides whose outline data is put onto one printer page. + If the current printer page has enough room for the outline of the + current slide then that is added. Otherwise a new printer page is + started. + */ + void PrepareOutline (PrintInfo const & rInfo) + { + MapMode aMap (rInfo.maMap); + Point aPageOfs (rInfo.mpPrinter->GetPageOffset() ); + aMap.SetScaleX(Fraction(1,2)); + aMap.SetScaleY(Fraction(1,2)); + mpPrinter->SetMapMode(aMap); + + ::tools::Rectangle aOutRect(aPageOfs, rInfo.mpPrinter->GetOutputSize()); + if( aOutRect.GetWidth() > aOutRect.GetHeight() ) + { + Size aPaperSize( rInfo.mpPrinter->PixelToLogic( rInfo.mpPrinter->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ) ); + maPrintSize.Width = aPaperSize.Height(); + maPrintSize.Height = aPaperSize.Width(); + const auto nRotatedWidth = aOutRect.GetHeight(); + const auto nRotatedHeight = aOutRect.GetWidth(); + const auto nRotatedX = aPageOfs.Y(); + const auto nRotatedY = aPageOfs.X(); + aOutRect = ::tools::Rectangle(Point( nRotatedX, nRotatedY), + Size(nRotatedWidth, nRotatedHeight)); + } + + Outliner* pOutliner = mrBase.GetDocument()->GetInternalOutliner(); + pOutliner->Init(OutlinerMode::OutlineView); + const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode()); + const bool bSavedUpdateMode (pOutliner->IsUpdateLayout()); + const Size aSavedPaperSize (pOutliner->GetPaperSize()); + const MapMode aSavedMapMode (pOutliner->GetRefMapMode()); + pOutliner->SetPaperSize(aOutRect.GetSize()); + pOutliner->SetUpdateLayout(true); + + ::tools::Long nPageH = aOutRect.GetHeight(); + + std::vector< sal_Int32 > aPages; + sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard); + StringRangeEnumerator::getRangesFromString( + mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()), + aPages, 0, nPageCount-1); + + for (size_t nIndex = 0, nCount = aPages.size(); nIndex < nCount;) + { + pOutliner->Clear(); + + Paragraph* pPara = nullptr; + ::tools::Long nH (0); + while (nH < nPageH && nIndex<nCount) + { + SdPage* pPage = GetFilteredPage(aPages[nIndex], PageKind::Standard); + ++nIndex; + if (pPage == nullptr) + continue; + + SdrTextObj* pTextObj = nullptr; + + for (const rtl::Reference<SdrObject>& pObj : *pPage) + { + if (pObj->GetObjInventor() == SdrInventor::Default + && pObj->GetObjIdentifier() == SdrObjKind::TitleText) + { + pTextObj = DynCastSdrTextObj(pObj.get()); + if (pTextObj) + break; + } + } + + pPara = pOutliner->GetParagraph(pOutliner->GetParagraphCount() - 1); + + if (pTextObj!=nullptr + && !pTextObj->IsEmptyPresObj() + && pTextObj->GetOutlinerParaObject()) + { + pOutliner->AddText(*(pTextObj->GetOutlinerParaObject())); + } + else + pOutliner->Insert(OUString()); + + pTextObj = nullptr; + + for (const rtl::Reference<SdrObject>& pObj : *pPage) + { + if (pObj->GetObjInventor() == SdrInventor::Default + && pObj->GetObjIdentifier() == SdrObjKind::OutlineText) + { + pTextObj = DynCastSdrTextObj(pObj.get()); + if (pTextObj) + break; + } + } + + bool bSubTitle (false); + if (!pTextObj) + { + bSubTitle = true; + pTextObj = DynCastSdrTextObj(pPage->GetPresObj(PresObjKind::Text)); // is there a subtitle? + } + + sal_Int32 nParaCount1 = pOutliner->GetParagraphCount(); + + if (pTextObj!=nullptr + && !pTextObj->IsEmptyPresObj() + && pTextObj->GetOutlinerParaObject()) + { + pOutliner->AddText(*(pTextObj->GetOutlinerParaObject())); + } + + if (bSubTitle ) + { + const sal_Int32 nParaCount2 (pOutliner->GetParagraphCount()); + for (sal_Int32 nPara=nParaCount1; nPara<nParaCount2; ++nPara) + { + Paragraph* pP = pOutliner->GetParagraph(nPara); + if (pP!=nullptr && pOutliner->GetDepth(nPara) > 0) + pOutliner->SetDepth(pP, 0); + } + } + + nH = pOutliner->GetTextHeight(); + } + + // Remove the last paragraph when that does not fit completely on + // the current page. + if (nH > nPageH && pPara!=nullptr) + { + sal_Int32 nCnt = pOutliner->GetAbsPos( + pOutliner->GetParagraph( pOutliner->GetParagraphCount() - 1 ) ); + sal_Int32 nParaPos = pOutliner->GetAbsPos( pPara ); + nCnt -= nParaPos; + pPara = pOutliner->GetParagraph( ++nParaPos ); + if ( nCnt && pPara ) + { + pOutliner->Remove(pPara, nCnt); + --nIndex; + } + } + + if ( CheckForFrontBackPages( nIndex ) ) + { + maPrinterPages.push_back( + std::make_shared<OutlinerPrinterPage>( + pOutliner->CreateParaObject(), + aMap, + rInfo.msTimeDate, + aPageOfs, + rInfo.mnDrawMode, + rInfo.meOrientation, + rInfo.mpPrinter->GetPaperBin())); + } + } + + pOutliner->SetRefMapMode(aSavedMapMode); + pOutliner->SetUpdateLayout(bSavedUpdateMode); + pOutliner->SetPaperSize(aSavedPaperSize); + pOutliner->Init(nSavedOutlMode); + } + + /** Prepare handout pages for slides that are to be printed. + */ + void PrepareHandout (PrintInfo& rInfo) + { + SdDrawDocument* pDocument = mrBase.GetDocument(); + OSL_ASSERT(pDocument != nullptr); + SdPage& rHandoutPage (*pDocument->GetSdPage(0, PageKind::Handout)); + + const bool bScalePage (mpOptions->IsPageSize()); + + sal_uInt16 nPaperBin; + if ( ! mpOptions->IsPaperBin()) + nPaperBin = rHandoutPage.GetPaperBin(); + else + nPaperBin = rInfo.mpPrinter->GetPaperBin(); + + // Change orientation? + SdPage& rMaster (dynamic_cast<SdPage&>(rHandoutPage.TRG_GetMasterPage())); + rInfo.meOrientation = rMaster.GetOrientation(); + + const Size aPaperSize (rInfo.mpPrinter->GetPaperSize()); + if( (rInfo.meOrientation == Orientation::Landscape && + (aPaperSize.Width() < aPaperSize.Height())) + || + (rInfo.meOrientation == Orientation::Portrait && + (aPaperSize.Width() > aPaperSize.Height())) + ) + { + maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width()); + } + else + { + maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height()); + } + + MapMode aMap (rInfo.maMap); + const Point aPageOfs (rInfo.mpPrinter->GetPageOffset()); + + if ( bScalePage ) + { + const Size aPageSize (rHandoutPage.GetSize()); + const Size aPrintSize (rInfo.mpPrinter->GetOutputSize()); + + const double fHorz = static_cast<double>(aPrintSize.Width()) / aPageSize.Width(); + const double fVert = static_cast<double>(aPrintSize.Height()) / aPageSize.Height(); + + Fraction aFract; + if ( fHorz < fVert ) + aFract = Fraction(aPrintSize.Width(), aPageSize.Width()); + else + aFract = Fraction(aPrintSize.Height(), aPageSize.Height()); + + aMap.SetScaleX(aFract); + aMap.SetScaleY(aFract); + aMap.SetOrigin(Point()); + } + + std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell()); + pViewShell->WriteFrameViewData(); + + // Count page shapes. + sal_uInt32 nShapeCount (0); + SdrObjListIter aShapeIter (&rHandoutPage); + while (aShapeIter.IsMore()) + { + SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next()); + if (pPageObj) + ++nShapeCount; + } + + const sal_uInt16 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard); + const sal_uInt16 nHandoutPageCount = nShapeCount ? (nPageCount + nShapeCount - 1) / nShapeCount : 0; + pViewShell->SetPrintedHandoutPageCount( nHandoutPageCount ); + mrBase.GetDocument()->setHandoutPageCount( nHandoutPageCount ); + + // Distribute pages to handout pages. + StringRangeEnumerator aRangeEnum( + mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()), + 0, nPageCount-1); + std::vector<sal_uInt16> aPageIndices; + sal_uInt16 nPrinterPageIndex = 0; + StringRangeEnumerator::Iterator it = aRangeEnum.begin(), itEnd = aRangeEnum.end(); + bool bLastLoop = (it == itEnd); + while (!bLastLoop) + { + sal_Int32 nPageIndex = *it; + ++it; + bLastLoop = (it == itEnd); + + if (GetFilteredPage(nPageIndex, PageKind::Standard)) + aPageIndices.push_back(nPageIndex); + else if (!bLastLoop) + continue; + + // Create a printer page when we have found one page for each + // placeholder or when this is the last (and special) loop. + if ( !aPageIndices.empty() && CheckForFrontBackPages( nPageIndex ) + && (aPageIndices.size() == nShapeCount || bLastLoop) ) + { + maPrinterPages.push_back( + std::make_shared<HandoutPrinterPage>( + nPrinterPageIndex++, + std::move(aPageIndices), + aMap, + rInfo.msTimeDate, + aPageOfs, + rInfo.mnDrawMode, + rInfo.meOrientation, + nPaperBin)); + aPageIndices.clear(); + } + } + } + + /** Prepare the notes pages or regular slides. + */ + void PrepareStdOrNotes ( + const PageKind ePageKind, + PrintInfo& rInfo) + { + OSL_ASSERT(rInfo.mpPrinter != nullptr); + + // Fill in page kind specific data. + SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc(); + if (pDocument->GetSdPageCount(ePageKind) == 0) + return; + SdPage* pRefPage = pDocument->GetSdPage(0, ePageKind); + rInfo.maPageSize = pRefPage->GetSize(); + + SetupPaperOrientation(ePageKind, rInfo); + + MapMode aMap (rInfo.maMap); + rInfo.maMap = aMap; + + if (mpOptions->IsBooklet()) + PrepareBooklet(ePageKind, rInfo); + else + PrepareRegularPages(ePageKind, rInfo); + } + + /** Prepare slides in a non-booklet way: one slide per one to many + printer pages. + */ + void PrepareRegularPages ( + const PageKind ePageKind, + PrintInfo& rInfo) + { + std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell()); + pViewShell->WriteFrameViewData(); + + sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard); + StringRangeEnumerator aRangeEnum( + mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()), + 0, nPageCount-1); + for (StringRangeEnumerator::Iterator + it = aRangeEnum.begin(), + itEnd = aRangeEnum.end(); + it != itEnd; + ++it) + { + SdPage* pPage = GetFilteredPage(*it, ePageKind); + if (pPage == nullptr) + continue; + + MapMode aMap (rInfo.maMap); + // is it possible that the page size changed? + const Size aPageSize = pPage->GetSize(); + + if (mpOptions->IsPageSize()) + { + const double fHorz (static_cast<double>(rInfo.maPrintSize.Width()) / aPageSize.Width()); + const double fVert (static_cast<double>(rInfo.maPrintSize.Height()) / aPageSize.Height()); + + Fraction aFract; + if (fHorz < fVert) + aFract = Fraction(rInfo.maPrintSize.Width(), aPageSize.Width()); + else + aFract = Fraction(rInfo.maPrintSize.Height(), aPageSize.Height()); + + aMap.SetScaleX(aFract); + aMap.SetScaleY(aFract); + aMap.SetOrigin(Point()); + } + + if (mpOptions->IsPrintPageName()) + { + rInfo.msPageString = pPage->GetName() + " "; + } + else + rInfo.msPageString.clear(); + rInfo.msPageString += rInfo.msTimeDate; + + ::tools::Long aPageWidth = aPageSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder(); + ::tools::Long aPageHeight = aPageSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder(); + // Bugfix for 44530: + // if it was implicitly changed (Landscape/Portrait), + // this is considered for tiling, respectively for the splitting up + // (Poster) + if( ( rInfo.maPrintSize.Width() > rInfo.maPrintSize.Height() + && aPageWidth < aPageHeight ) + || ( rInfo.maPrintSize.Width() < rInfo.maPrintSize.Height() + && aPageWidth > aPageHeight ) ) + { + const sal_Int32 nTmp (rInfo.maPrintSize.Width()); + rInfo.maPrintSize.setWidth( rInfo.maPrintSize.Height() ); + rInfo.maPrintSize.setHeight( nTmp ); + } + + if (mpOptions->IsTilePage() + && aPageWidth < rInfo.maPrintSize.Width() + && aPageHeight < rInfo.maPrintSize.Height()) + { + // Put multiple slides on one printer page. + PrepareTiledPage(*it, *pPage, ePageKind, rInfo); + } + else + { + rInfo.maMap = aMap; + PrepareScaledPage(*it, *pPage, ePageKind, rInfo); + } + } + } + + /** Put two slides on one printer page. + */ + void PrepareBooklet ( + const PageKind ePageKind, + const PrintInfo& rInfo) + { + MapMode aStdMap (rInfo.maMap); + Point aOffset; + Size aPrintSize_2 (rInfo.maPrintSize); + Size aPageSize_2 (rInfo.maPageSize); + + if (rInfo.meOrientation == Orientation::Landscape) + aPrintSize_2.setWidth( aPrintSize_2.Width() >> 1 ); + else + aPrintSize_2.setHeight( aPrintSize_2.Height() >> 1 ); + + const double fPageWH = static_cast<double>(aPageSize_2.Width()) / aPageSize_2.Height(); + const double fPrintWH = static_cast<double>(aPrintSize_2.Width()) / aPrintSize_2.Height(); + + if( fPageWH < fPrintWH ) + { + aPageSize_2.setWidth( static_cast<::tools::Long>( aPrintSize_2.Height() * fPageWH ) ); + aPageSize_2.setHeight( aPrintSize_2.Height() ); + } + else + { + aPageSize_2.setWidth( aPrintSize_2.Width() ); + aPageSize_2.setHeight( static_cast<::tools::Long>( aPrintSize_2.Width() / fPageWH ) ); + } + + MapMode aMap (rInfo.maMap); + aMap.SetScaleX( Fraction( aPageSize_2.Width(), rInfo.maPageSize.Width() ) ); + aMap.SetScaleY( Fraction( aPageSize_2.Height(), rInfo.maPageSize.Height() ) ); + + // calculate adjusted print size + const Size aAdjustedPrintSize (OutputDevice::LogicToLogic( + rInfo.maPrintSize, + aStdMap, + aMap)); + + if (rInfo.meOrientation == Orientation::Landscape) + { + aOffset.setX( ( ( aAdjustedPrintSize.Width() >> 1 ) - rInfo.maPageSize.Width() ) >> 1 ); + aOffset.setY( ( aAdjustedPrintSize.Height() - rInfo.maPageSize.Height() ) >> 1 ); + } + else + { + aOffset.setX( ( aAdjustedPrintSize.Width() - rInfo.maPageSize.Width() ) >> 1 ); + aOffset.setY( ( ( aAdjustedPrintSize.Height() >> 1 ) - rInfo.maPageSize.Height() ) >> 1 ); + } + + // create vector of pages to print + sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(ePageKind); + StringRangeEnumerator aRangeEnum( + mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()), + 0, nPageCount-1); + std::vector< sal_uInt16 > aPageVector; + for (StringRangeEnumerator::Iterator + it = aRangeEnum.begin(), + itEnd = aRangeEnum.end(); + it != itEnd; + ++it) + { + SdPage* pPage = GetFilteredPage(*it, ePageKind); + if (pPage != nullptr) + aPageVector.push_back(*it); + } + + // create pairs of pages to print on each page + std::vector< std::pair< sal_uInt16, sal_uInt16 > > aPairVector; + if ( ! aPageVector.empty()) + { + sal_uInt32 nFirstIndex = 0, nLastIndex = aPageVector.size() - 1; + + if( aPageVector.size() & 1 ) + aPairVector.emplace_back( sal_uInt16(65535), aPageVector[ nFirstIndex++ ] ); + else + aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] ); + + while( nFirstIndex < nLastIndex ) + { + if( nFirstIndex & 1 ) + aPairVector.emplace_back( aPageVector[ nFirstIndex++ ], aPageVector[ nLastIndex-- ] ); + else + aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] ); + } + } + + for (sal_uInt32 + nIndex=0, + nCount=aPairVector.size(); + nIndex < nCount; + ++nIndex) + { + if ( CheckForFrontBackPages( nIndex ) ) + { + const std::pair<sal_uInt16, sal_uInt16> aPair (aPairVector[nIndex]); + Point aSecondOffset (aOffset); + if (rInfo.meOrientation == Orientation::Landscape) + aSecondOffset.AdjustX( aAdjustedPrintSize.Width() / 2 ); + else + aSecondOffset.AdjustY( aAdjustedPrintSize.Height() / 2 ); + maPrinterPages.push_back( + std::make_shared<BookletPrinterPage>( + aPair.first, + aPair.second, + aOffset, + aSecondOffset, + ePageKind, + aMap, + rInfo.mbPrintMarkedOnly, + rInfo.mnDrawMode, + rInfo.meOrientation, + rInfo.mpPrinter->GetPaperBin())); + + } + } + } + + /** Print one slide multiple times on one printer page so that the whole + printer page is covered. + */ + void PrepareTiledPage ( + const sal_Int32 nPageIndex, + const SdPage& rPage, + const PageKind ePageKind, + const PrintInfo& rInfo) + { + sal_uInt16 nPaperBin; + if ( ! mpOptions->IsPaperBin()) + nPaperBin = rPage.GetPaperBin(); + else + nPaperBin = rInfo.mpPrinter->GetPaperBin(); + + if ( !CheckForFrontBackPages( nPageIndex ) ) + return; + + maPrinterPages.push_back( + std::make_shared<TiledPrinterPage>( + sal::static_int_cast<sal_uInt16>(nPageIndex), + ePageKind, + rInfo.mbPrintMarkedOnly, + rInfo.msPageString, + rInfo.mpPrinter->GetPageOffset(), + rInfo.mnDrawMode, + rInfo.meOrientation, + nPaperBin)); + } + + /** Print one standard slide or notes page on one to many printer + pages. More than on printer page is used when the slide is larger + than the printable area. + */ + void PrepareScaledPage ( + const sal_Int32 nPageIndex, + const SdPage& rPage, + const PageKind ePageKind, + const PrintInfo& rInfo) + { + const Point aPageOffset (rInfo.mpPrinter->GetPageOffset()); + + sal_uInt16 nPaperBin; + if ( ! mpOptions->IsPaperBin()) + nPaperBin = rPage.GetPaperBin(); + else + nPaperBin = rInfo.mpPrinter->GetPaperBin(); + + // For pages larger then the printable area there + // are three options: + // 1. Scale down to the page to the printable area. + // 2. Print only the upper left part of the page + // (without the unprintable borders). + // 3. Split the page into parts of the size of the + // printable area. + const bool bScalePage (mpOptions->IsPageSize()); + const bool bCutPage (mpOptions->IsCutPage()); + MapMode aMap (rInfo.maMap); + if ( (bScalePage || bCutPage) && CheckForFrontBackPages( nPageIndex ) ) + { + // Handle 1 and 2. + + // if CutPage is set then do not move it, otherwise move the + // scaled page to printable area + maPrinterPages.push_back( + std::make_shared<RegularPrinterPage>( + sal::static_int_cast<sal_uInt16>(nPageIndex), + ePageKind, + aMap, + rInfo.mbPrintMarkedOnly, + rInfo.msPageString, + aPageOffset, + rInfo.mnDrawMode, + rInfo.meOrientation, + nPaperBin)); + } + else + { + // Handle 3. Print parts of the page in the size of the + // printable area until the whole page is covered. + + // keep the page content at its position if it fits, otherwise + // move it to the printable area + const ::tools::Long nPageWidth ( + rInfo.maPageSize.Width() - rPage.GetLeftBorder() - rPage.GetRightBorder()); + const ::tools::Long nPageHeight ( + rInfo.maPageSize.Height() - rPage.GetUpperBorder() - rPage.GetLowerBorder()); + + Point aOrigin ( 0, 0 ); + + for (Point aPageOrigin = aOrigin; + -aPageOrigin.Y()<nPageHeight; + aPageOrigin.AdjustY( -rInfo.maPrintSize.Height() )) + { + for (aPageOrigin.setX(aOrigin.X()); + -aPageOrigin.X()<nPageWidth; + aPageOrigin.AdjustX(-rInfo.maPrintSize.Width())) + { + if ( CheckForFrontBackPages( nPageIndex ) ) + { + aMap.SetOrigin(aPageOrigin); + maPrinterPages.push_back( + std::make_shared<RegularPrinterPage>( + sal::static_int_cast<sal_uInt16>(nPageIndex), + ePageKind, + aMap, + rInfo.mbPrintMarkedOnly, + rInfo.msPageString, + aPageOffset, + rInfo.mnDrawMode, + rInfo.meOrientation, + nPaperBin)); + } + } + } + } + } + +bool CheckForFrontBackPages( sal_Int32 nPage ) +{ + const bool bIsIndexOdd(nPage & 1); + if ((!bIsIndexOdd && mpOptions->IsPrintFrontPage()) + || (bIsIndexOdd && mpOptions->IsPrintBackPage())) + { + return true; + } + else + return false; +} +}; + +//===== DocumentRenderer ====================================================== + +DocumentRenderer::DocumentRenderer (ViewShellBase& rBase) + : mpImpl(new Implementation(rBase)) +{ +} + +DocumentRenderer::~DocumentRenderer() +{ +} + +//----- XRenderable ----------------------------------------------------------- + +sal_Int32 SAL_CALL DocumentRenderer::getRendererCount ( + const css::uno::Any&, + const css::uno::Sequence<css::beans::PropertyValue >& rOptions) +{ + mpImpl->ProcessProperties(rOptions); + return mpImpl->GetPrintPageCount(); +} + +Sequence<beans::PropertyValue> SAL_CALL DocumentRenderer::getRenderer ( + sal_Int32, + const css::uno::Any&, + const css::uno::Sequence<css::beans::PropertyValue>& rOptions) +{ + mpImpl->ProcessProperties(rOptions); + return mpImpl->GetProperties(); +} + +void SAL_CALL DocumentRenderer::render ( + sal_Int32 nRenderer, + const css::uno::Any&, + const css::uno::Sequence<css::beans::PropertyValue>& rOptions) +{ + mpImpl->ProcessProperties(rOptions); + mpImpl->PrintPage(nRenderer); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/FormShellManager.cxx b/sd/source/ui/view/FormShellManager.cxx new file mode 100644 index 0000000000..d2cb6ebfee --- /dev/null +++ b/sd/source/ui/view/FormShellManager.cxx @@ -0,0 +1,324 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <FormShellManager.hxx> + +#include <EventMultiplexer.hxx> +#include <ViewShell.hxx> +#include <ViewShellBase.hxx> +#include <ViewShellManager.hxx> +#include <Window.hxx> +#include <vcl/vclevent.hxx> +#include <svx/fmshell.hxx> +#include <osl/diagnose.h> + +namespace sd { + +namespace { + +/** This factory is responsible for creating and deleting the FmFormShell. +*/ +class FormShellManagerFactory + : public ::sd::ShellFactory<SfxShell> +{ +public: + FormShellManagerFactory (ViewShell& rViewShell, FormShellManager& rManager); + virtual FmFormShell* CreateShell (ShellId nId) override; + virtual void ReleaseShell (SfxShell* pShell) override; + +private: + ::sd::ViewShell& mrViewShell; + FormShellManager& mrFormShellManager; +}; + +} // end of anonymous namespace + +FormShellManager::FormShellManager (ViewShellBase& rBase) + : mrBase(rBase), + mpFormShell(nullptr), + mbFormShellAboveViewShell(false), + mbIsMainViewChangePending(false), + mpMainViewShellWindow(nullptr) +{ + // Register at the EventMultiplexer to be informed about changes in the + // center pane. + Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler)); + mrBase.GetEventMultiplexer()->AddEventListener(aLink); + + RegisterAtCenterPane(); +} + +void FormShellManager::ImplDestroy() +{ + SetFormShell(nullptr); + UnregisterAtCenterPane(); + + // Unregister from the EventMultiplexer. + Link<sd::tools::EventMultiplexerEvent&,void> aLink (LINK(this, FormShellManager, ConfigurationUpdateHandler)); + mrBase.GetEventMultiplexer()->RemoveEventListener(aLink); + + if (mpSubShellFactory) + { + ViewShell* pShell = mrBase.GetMainViewShell().get(); + if (pShell != nullptr) + mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell,mpSubShellFactory); + } +} + +FormShellManager::~FormShellManager() +{ + suppress_fun_call_w_exception(ImplDestroy()); +} + +void FormShellManager::SetFormShell (FmFormShell* pFormShell) +{ + if (mpFormShell == pFormShell) + return; + + // Disconnect from the old form shell. + if (mpFormShell != nullptr) + { + mpFormShell->SetControlActivationHandler(Link<LinkParamNone*,void>()); + EndListening(*mpFormShell); + mpFormShell->SetView(nullptr); + } + + mpFormShell = pFormShell; + + // Connect to the new form shell. + if (mpFormShell != nullptr) + { + mpFormShell->SetControlActivationHandler( + LINK( + this, + FormShellManager, + FormControlActivated)); + StartListening(*mpFormShell); + + ViewShell* pMainViewShell = mrBase.GetMainViewShell().get(); + if (pMainViewShell != nullptr) + { + // Prevent setting the view twice at the FmFormShell. + FmFormView* pFormView = pMainViewShell->GetView(); + if (mpFormShell->GetFormView() != pFormView) + mpFormShell->SetView(pFormView); + } + } + + // Tell the ViewShellManager where on the stack to place the form shell. + mrBase.GetViewShellManager()->SetFormShell( + mrBase.GetMainViewShell().get(), + mpFormShell, + mbFormShellAboveViewShell); +} + +void FormShellManager::RegisterAtCenterPane() +{ + ViewShell* pShell = mrBase.GetMainViewShell().get(); + if (pShell == nullptr) + return; + + // No form shell for the slide sorter. Besides that it is not + // necessary, using both together results in crashes. + if (pShell->GetShellType() == ViewShell::ST_SLIDE_SORTER) + return; + + mpMainViewShellWindow = pShell->GetActiveWindow(); + if (mpMainViewShellWindow == nullptr) + return; + + // Register at the window to get informed when to move the form + // shell to the bottom of the shell stack. + mpMainViewShellWindow->AddEventListener( + LINK( + this, + FormShellManager, + WindowEventHandler)); + + // Create a shell factory and with it activate the form shell. + OSL_ASSERT(!mpSubShellFactory); + mpSubShellFactory = std::make_shared<FormShellManagerFactory>(*pShell, *this); + mrBase.GetViewShellManager()->AddSubShellFactory(pShell,mpSubShellFactory); + mrBase.GetViewShellManager()->ActivateSubShell(*pShell, ToolbarId::FormLayer_Toolbox); +} + +void FormShellManager::UnregisterAtCenterPane() +{ + if (mpMainViewShellWindow != nullptr) + { + // Unregister from the window. + mpMainViewShellWindow->RemoveEventListener( + LINK( + this, + FormShellManager, + WindowEventHandler)); + mpMainViewShellWindow = nullptr; + } + + // Unregister form at the form shell. + SetFormShell(nullptr); + + // Deactivate the form shell and destroy the shell factory. + ViewShell* pShell = mrBase.GetMainViewShell().get(); + if (pShell != nullptr) + { + mrBase.GetViewShellManager()->DeactivateSubShell(*pShell, ToolbarId::FormLayer_Toolbox); + mrBase.GetViewShellManager()->RemoveSubShellFactory(pShell, mpSubShellFactory); + } + + mpSubShellFactory.reset(); +} + +IMPL_LINK_NOARG(FormShellManager, FormControlActivated, LinkParamNone*, void) +{ + // The form shell has been activated. To give it priority in reacting to + // slot calls the form shell is moved to the top of the object bar shell + // stack. + ViewShell* pShell = mrBase.GetMainViewShell().get(); + if (pShell!=nullptr && !mbFormShellAboveViewShell) + { + mbFormShellAboveViewShell = true; + + ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager()); + mrBase.GetViewShellManager()->SetFormShell(pShell,mpFormShell,mbFormShellAboveViewShell); + } +} + +IMPL_LINK(FormShellManager, ConfigurationUpdateHandler, sd::tools::EventMultiplexerEvent&, rEvent, void) +{ + switch (rEvent.meEventId) + { + case EventMultiplexerEventId::MainViewRemoved: + UnregisterAtCenterPane(); + break; + + case EventMultiplexerEventId::MainViewAdded: + mbIsMainViewChangePending = true; + break; + + case EventMultiplexerEventId::ConfigurationUpdated: + if (mbIsMainViewChangePending) + { + mbIsMainViewChangePending = false; + RegisterAtCenterPane(); + } + break; + + default: + break; + } +} + +IMPL_LINK(FormShellManager, WindowEventHandler, VclWindowEvent&, rEvent, void) +{ + switch (rEvent.GetId()) + { + case VclEventId::WindowGetFocus: + { + // The window of the center pane got the focus. Therefore + // the form shell is moved to the bottom of the object bar + // stack. + ViewShell* pShell = mrBase.GetMainViewShell().get(); + if (pShell!=nullptr && mbFormShellAboveViewShell) + { + mbFormShellAboveViewShell = false; + ViewShellManager::UpdateLock aLock (mrBase.GetViewShellManager()); + mrBase.GetViewShellManager()->SetFormShell( + pShell, + mpFormShell, + mbFormShellAboveViewShell); + } + } + break; + + case VclEventId::WindowLoseFocus: + // We follow the sloppy focus policy. Losing the focus is + // ignored. We wait for the focus to be placed either in + // the window or the form shell. The later, however, is + // notified over the FormControlActivated handler, not this + // one. + break; + + case VclEventId::ObjectDying: + mpMainViewShellWindow = nullptr; + break; + + default: break; + } +} + +void FormShellManager::Notify(SfxBroadcaster&, const SfxHint& rHint) +{ + if (rHint.GetId()!=SfxHintId::Dying) + return; + + // If all goes well this listener is called after the + // FormShellManager was notified about the dying form shell by the + // FormShellManagerFactory. + OSL_ASSERT(mpFormShell==nullptr); + if (mpFormShell != nullptr) + { + mpFormShell = nullptr; + mrBase.GetViewShellManager()->SetFormShell( + mrBase.GetMainViewShell().get(), + nullptr, + false); + } +} + +//===== FormShellManagerFactory =============================================== + +namespace { + +FormShellManagerFactory::FormShellManagerFactory ( + ::sd::ViewShell& rViewShell, + FormShellManager& rManager) + : mrViewShell(rViewShell), + mrFormShellManager(rManager) +{ +} + +FmFormShell* FormShellManagerFactory::CreateShell( ::sd::ShellId nId ) +{ + FmFormShell* pShell = nullptr; + + ::sd::View* pView = mrViewShell.GetView(); + if (nId == ToolbarId::FormLayer_Toolbox) + { + pShell = new FmFormShell(&mrViewShell.GetViewShellBase(), pView); + mrFormShellManager.SetFormShell(pShell); + } + + return pShell; +} + +void FormShellManagerFactory::ReleaseShell (SfxShell* pShell) +{ + if (pShell != nullptr) + { + mrFormShellManager.SetFormShell(nullptr); + delete pShell; + } +} + +} // end of anonymous namespace + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/GraphicObjectBar.cxx b/sd/source/ui/view/GraphicObjectBar.cxx new file mode 100644 index 0000000000..b1e94f7219 --- /dev/null +++ b/sd/source/ui/view/GraphicObjectBar.cxx @@ -0,0 +1,141 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <GraphicObjectBar.hxx> + +#include <sfx2/shell.hxx> +#include <svx/svxids.hrc> +#include <sfx2/request.hxx> +#include <svx/svdograf.hxx> +#include <svx/grfflt.hxx> +#include <svx/grafctrl.hxx> + +#include <sfx2/objface.hxx> + +#include <strings.hrc> +#include <DrawDocShell.hxx> +#include <ViewShell.hxx> +#include <sdresid.hxx> + +using namespace sd; +#define ShellClass_GraphicObjectBar +#include <sdslots.hxx> + +namespace sd { + + +SFX_IMPL_INTERFACE(GraphicObjectBar, SfxShell) + +void GraphicObjectBar::InitInterface_Impl() +{ +} + + +GraphicObjectBar::GraphicObjectBar ( + const ViewShell* pSdViewShell, + ::sd::View* pSdView ) + : SfxShell (pSdViewShell->GetViewShell()), + mpView ( pSdView ) +{ + DrawDocShell* pDocShell = pSdViewShell->GetDocSh(); + + SetPool( &pDocShell->GetPool() ); + SetUndoManager( pDocShell->GetUndoManager() ); + SetRepeatTarget( mpView ); + SetName( "Graphic objectbar"); +} + +GraphicObjectBar::~GraphicObjectBar() +{ + SetRepeatTarget( nullptr ); +} + +void GraphicObjectBar::GetAttrState( SfxItemSet& rSet ) +{ + if( mpView ) + SvxGrafAttrHelper::GetGrafAttrState( rSet, *mpView ); +} + +void GraphicObjectBar::Execute( SfxRequest& rReq ) +{ + if( mpView ) + { + SvxGrafAttrHelper::ExecuteGrafAttr( rReq, *mpView ); + Invalidate(); + } +} + +void GraphicObjectBar::GetFilterState( SfxItemSet& rSet ) +{ + const SdrMarkList& rMarkList = mpView->GetMarkedObjectList(); + bool bEnable = false; + + if( rMarkList.GetMarkCount() == 1 ) + { + SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); + + if( auto pGrafObj = dynamic_cast< SdrGrafObj *>( pObj ) ) + if( pGrafObj->GetGraphicType() == GraphicType::Bitmap ) + bEnable = true; + } + + if( !bEnable ) + SvxGraphicFilter::DisableGraphicFilterSlots( rSet ); +} + +void GraphicObjectBar::ExecuteFilter( SfxRequest const & rReq ) +{ + const SdrMarkList& rMarkList = mpView->GetMarkedObjectList(); + + if( rMarkList.GetMarkCount() == 1 ) + { + SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); + + if( auto pGrafObj = dynamic_cast< SdrGrafObj *>( pObj ) ) + if( pGrafObj->GetGraphicType() == GraphicType::Bitmap ) + { + GraphicObject aFilterObj( pGrafObj->GetGraphicObject() ); + + if( SvxGraphicFilterResult::NONE == + SvxGraphicFilter::ExecuteGrfFilterSlot( rReq, aFilterObj ) ) + { + SdrPageView* pPageView = mpView->GetSdrPageView(); + + if( pPageView ) + { + rtl::Reference<SdrGrafObj> pFilteredObj = SdrObject::Clone(static_cast<SdrGrafObj&>(*pObj), pObj->getSdrModelFromSdrObject()); + OUString aStr = mpView->GetDescriptionOfMarkedObjects() + + " " + SdResId(STR_UNDO_GRAFFILTER); + mpView->BegUndo( aStr ); + pFilteredObj->SetGraphicObject( aFilterObj ); + ::sd::View* const pView = mpView; + pView->ReplaceObjectAtView( pObj, *pPageView, pFilteredObj.get() ); + pView->EndUndo(); + return; + } + } + } + } + + Invalidate(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/GraphicViewShellBase.cxx b/sd/source/ui/view/GraphicViewShellBase.cxx new file mode 100644 index 0000000000..a3f8ece26c --- /dev/null +++ b/sd/source/ui/view/GraphicViewShellBase.cxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <GraphicViewShellBase.hxx> + +#include <GraphicDocShell.hxx> +#include <DrawController.hxx> +#include <app.hrc> +#include <framework/DrawModule.hxx> +#include <framework/FrameworkHelper.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfac.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> + +namespace sd +{ +// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a +// new GraphicViewShellBase object has been constructed. + +SfxViewFactory* GraphicViewShellBase::s_pFactory; +SfxViewShell* GraphicViewShellBase::CreateInstance(SfxViewFrame& rFrame, SfxViewShell* pOldView) +{ + GraphicViewShellBase* pBase = new GraphicViewShellBase(rFrame, pOldView); + pBase->LateInit(framework::FrameworkHelper::msDrawViewURL); + return pBase; +} +void GraphicViewShellBase::RegisterFactory(SfxInterfaceId nPrio) +{ + s_pFactory = new SfxViewFactory(&CreateInstance, nPrio, "Default"); + InitFactory(); +} +void GraphicViewShellBase::InitFactory() { SFX_VIEW_REGISTRATION(GraphicDocShell); } + +GraphicViewShellBase::GraphicViewShellBase(SfxViewFrame& _rFrame, SfxViewShell* pOldShell) + : ViewShellBase(_rFrame, pOldShell) +{ +} + +GraphicViewShellBase::~GraphicViewShellBase() {} + +void GraphicViewShellBase::Execute(SfxRequest& rRequest) +{ + sal_uInt16 nSlotId = rRequest.GetSlot(); + + switch (nSlotId) + { + case SID_NOTES_WINDOW: + case SID_SLIDE_SORTER_MULTI_PANE_GUI: + case SID_SLIDE_SORTER_MODE: + case SID_SLIDE_MASTER_MODE: + case SID_OUTLINE_MODE: + case SID_NOTES_MODE: + case SID_NOTES_MASTER_MODE: + case SID_HANDOUT_MASTER_MODE: + // Prevent some Impress-only slots from being executed. + rRequest.Cancel(); + break; + + case SID_SWITCH_SHELL: + case SID_LEFT_PANE_DRAW: + case SID_LEFT_PANE_IMPRESS: + default: + // The remaining requests are forwarded to our base class. + ViewShellBase::Execute(rRequest); + break; + } +} + +void GraphicViewShellBase::InitializeFramework() +{ + rtl::Reference<sd::DrawController> xController(GetDrawController()); + sd::framework::DrawModule::Initialize(xController); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/ImpressViewShellBase.cxx b/sd/source/ui/view/ImpressViewShellBase.cxx new file mode 100644 index 0000000000..929b607dbb --- /dev/null +++ b/sd/source/ui/view/ImpressViewShellBase.cxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ImpressViewShellBase.hxx> + +#include <DrawDocShell.hxx> +#include <DrawController.hxx> +#include <app.hrc> +#include <framework/FrameworkHelper.hxx> +#include <framework/ImpressModule.hxx> +#include <MasterPageObserver.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfac.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> +#include <comphelper/lok.hxx> + +namespace sd { + + +// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a +// new ImpressViewShellBase object has been constructed. + +SfxViewFactory* ImpressViewShellBase::s_pFactory; +SfxViewShell* ImpressViewShellBase::CreateInstance ( + SfxViewFrame& rFrame, SfxViewShell *pOldView) +{ + ImpressViewShellBase* pBase = new ImpressViewShellBase(rFrame, pOldView); + pBase->LateInit(comphelper::LibreOfficeKit::isActive() ? framework::FrameworkHelper::msImpressViewURL : ""); + return pBase; +} +void ImpressViewShellBase::RegisterFactory( SfxInterfaceId nPrio ) +{ + s_pFactory = new SfxViewFactory(&CreateInstance,nPrio,"Default"); + InitFactory(); +} +void ImpressViewShellBase::InitFactory() +{ + SFX_VIEW_REGISTRATION(DrawDocShell); +} + +ImpressViewShellBase::ImpressViewShellBase ( + SfxViewFrame& _rFrame, + SfxViewShell* pOldShell) + : ViewShellBase (_rFrame, pOldShell) +{ + MasterPageObserver::Instance().RegisterDocument (*GetDocShell()->GetDoc()); +} + +ImpressViewShellBase::~ImpressViewShellBase() +{ + MasterPageObserver::Instance().UnregisterDocument (*GetDocShell()->GetDoc()); +} + +void ImpressViewShellBase::Execute (SfxRequest& rRequest) +{ + sal_uInt16 nSlotId = rRequest.GetSlot(); + + switch (nSlotId) + { + case SID_LEFT_PANE_DRAW: + // Prevent a Draw-only slots from being executed. + rRequest.Cancel(); + break; + + default: + // The remaining requests are forwarded to our base class. + ViewShellBase::Execute(rRequest); + break; + } +} + +void ImpressViewShellBase::InitializeFramework() +{ + rtl::Reference<sd::DrawController> xController(GetDrawController()); + sd::framework::ImpressModule::Initialize(xController); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/MediaObjectBar.cxx b/sd/source/ui/view/MediaObjectBar.cxx new file mode 100644 index 0000000000..232535240e --- /dev/null +++ b/sd/source/ui/view/MediaObjectBar.cxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <MediaObjectBar.hxx> +#include <avmedia/mediaitem.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/objface.hxx> +#include <svx/MediaShellHelpers.hxx> + +#include <strings.hrc> +#include <DrawDocShell.hxx> +#include <ViewShell.hxx> +#include <sdresid.hxx> +#include <drawdoc.hxx> + +using namespace sd; +using namespace svx; + +#define ShellClass_MediaObjectBar +#include <sdslots.hxx> + +namespace sd +{ +SFX_IMPL_INTERFACE(MediaObjectBar, SfxShell) + +void MediaObjectBar::InitInterface_Impl() {} + +MediaObjectBar::MediaObjectBar(const ViewShell* pSdViewShell, ::sd::View* pSdView) + : SfxShell(pSdViewShell->GetViewShell()) + , mpView(pSdView) +{ + DrawDocShell* pDocShell = pSdViewShell->GetDocSh(); + + SetPool(&pDocShell->GetPool()); + SetUndoManager(pDocShell->GetUndoManager()); + SetRepeatTarget(mpView); + SetName(SdResId(RID_DRAW_MEDIA_TOOLBOX)); +} + +MediaObjectBar::~MediaObjectBar() { SetRepeatTarget(nullptr); } + +void MediaObjectBar::GetState(SfxItemSet& rSet) { MediaShellHelpers::GetState(mpView, rSet); } + +void MediaObjectBar::Execute(SfxRequest const& rReq) +{ + const ::avmedia::MediaItem* pMediaItem = MediaShellHelpers::Execute(mpView, rReq); + if (!pMediaItem) + return; + + //if only changing state then don't set modified flag (e.g. playing a video) + if (!(pMediaItem->getMaskSet() & AVMediaSetMask::STATE)) + { + //fdo #32598: after changing playback opts, set document's modified flag + SdDrawDocument& rDoc = mpView->GetDoc(); + rDoc.SetChanged(); + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/OutlineViewShellBase.cxx b/sd/source/ui/view/OutlineViewShellBase.cxx new file mode 100644 index 0000000000..e3efb3ed59 --- /dev/null +++ b/sd/source/ui/view/OutlineViewShellBase.cxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <OutlineViewShellBase.hxx> +#include <DrawDocShell.hxx> +#include <framework/FrameworkHelper.hxx> +#include <sfx2/viewfac.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> + +namespace sd { + +class DrawDocShell; + + +// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a +// new OutlineViewShellBase object has been constructed. + +SfxViewFactory* OutlineViewShellBase::s_pFactory; +SfxViewShell* OutlineViewShellBase::CreateInstance ( + SfxViewFrame& rFrame, SfxViewShell *pOldView) +{ + OutlineViewShellBase* pBase = new OutlineViewShellBase(rFrame, pOldView); + pBase->LateInit(framework::FrameworkHelper::msOutlineViewURL); + return pBase; +} +void OutlineViewShellBase::RegisterFactory( SfxInterfaceId nPrio ) +{ + s_pFactory = new SfxViewFactory(&CreateInstance,nPrio,"Outline"); + InitFactory(); +} +void OutlineViewShellBase::InitFactory() +{ + SFX_VIEW_REGISTRATION(DrawDocShell); +} + +OutlineViewShellBase::OutlineViewShellBase ( + SfxViewFrame& _rFrame, + SfxViewShell* pOldShell) + : ImpressViewShellBase (_rFrame, pOldShell) +{ +} + +OutlineViewShellBase::~OutlineViewShellBase() +{ +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx new file mode 100644 index 0000000000..aaf4cc6a81 --- /dev/null +++ b/sd/source/ui/view/Outliner.cxx @@ -0,0 +1,2066 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <Outliner.hxx> +#include <boost/property_tree/json_parser.hpp> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +#include <svl/srchitem.hxx> +#include <svl/intitem.hxx> +#include <editeng/editstat.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/outdev.hxx> +#include <vcl/weld.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svdotext.hxx> +#include <svx/svdograf.hxx> +#include <editeng/unolingu.hxx> +#include <com/sun/star/linguistic2/XSpellChecker1.hpp> +#include <svx/srchdlg.hxx> +#include <unotools/linguprops.hxx> +#include <unotools/lingucfg.hxx> +#include <editeng/editeng.hxx> +#include <sfx2/viewfrm.hxx> +#include <tools/debug.hxx> +#include <comphelper/diagnose_ex.hxx> + +#include <strings.hrc> +#include <editeng/outliner.hxx> +#include <sdmod.hxx> +#include <Window.hxx> +#include <sdresid.hxx> +#include <DrawViewShell.hxx> +#include <OutlineView.hxx> +#include <OutlineViewShell.hxx> +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <drawview.hxx> +#include <ViewShellBase.hxx> +#include <SpellDialogChildWindow.hxx> +#include <framework/FrameworkHelper.hxx> +#include <svx/svxids.hrc> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <comphelper/string.hxx> +#include <comphelper/lok.hxx> +#include <comphelper/scopeguard.hxx> +#include <VectorGraphicSearchContext.hxx> +#include <fusearch.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::linguistic2; + +class SfxStyleSheetPool; + +class SdOutliner::Implementation +{ +public: + /** The original edit mode directly after switching to a different view + mode. Used for restoring the edit mode when leaving that view mode + again. + */ + EditMode meOriginalEditMode; + + Implementation(); + ~Implementation(); + + /** Return the OutlinerView that was provided by the last call to + ProvideOutlinerView() (or NULL when there was no such call.) + */ + OutlinerView* GetOutlinerView() { return mpOutlineView;} + + /** Provide in the member mpOutlineView an instance of OutlinerView that + is either taken from the ViewShell, when it is an OutlineViewShell, + or is created. When an OutlinerView already exists it is initialized. + */ + void ProvideOutlinerView ( + Outliner& rOutliner, + const std::shared_ptr<sd::ViewShell>& rpViewShell, + vcl::Window* pWindow); + + /** This method is called when the OutlinerView is no longer used. + */ + void ReleaseOutlinerView(); + + sd::VectorGraphicSearchContext& getVectorGraphicSearchContext() { return maVectorGraphicSearchContext; } + +private: + /** Flag that specifies whether we own the outline view pointed to by + <member>mpOutlineView</member> and thus have to + delete it in <member>EndSpelling()</member>. + */ + bool mbOwnOutlineView; + + /** The outline view used for searching and spelling. If searching or + spell checking an outline view this data member points to that view. + For all other views an instance is created. The + <member>mbOwnOutlineView</member> distinguishes between both cases. + */ + OutlinerView* mpOutlineView; + + sd::VectorGraphicSearchContext maVectorGraphicSearchContext; +}; + +namespace +{ + +sd::ViewShellBase* getViewShellBase() +{ + return dynamic_cast<sd::ViewShellBase*>(SfxViewShell::Current()); +} + +} // end anonymous namespace + +SdOutliner::SdOutliner( SdDrawDocument* pDoc, OutlinerMode nMode ) + : SdrOutliner( &pDoc->GetItemPool(), nMode ), + mpImpl(new Implementation()), + meMode(SEARCH), + mpView(nullptr), + mpWindow(nullptr), + mpDrawDocument(pDoc), + mnConversionLanguage(LANGUAGE_NONE), + mnIgnoreCurrentPageChangesLevel(0), + mbStringFound(false), + mbMatchMayExist(false), + mnPageCount(0), + mbEndOfSearch(false), + mbFoundObject(false), + mbDirectionIsForward(true), + mbRestrictSearchToSelection(false), + mpObj(nullptr), + mpFirstObj(nullptr), + mpSearchSpellTextObj(nullptr), + mnText(0), + mpParaObj(nullptr), + meStartViewMode(PageKind::Standard), + meStartEditMode(EditMode::Page), + mnStartPageIndex(sal_uInt16(-1)), + mpStartEditedObject(nullptr), + mbPrepareSpellingPending(true) +{ + SetStyleSheetPool(static_cast<SfxStyleSheetPool*>( mpDrawDocument->GetStyleSheetPool() )); + SetEditTextObjectPool( &pDoc->GetItemPool() ); + SetCalcFieldValueHdl(LINK(SD_MOD(), SdModule, CalcFieldValueHdl)); + SetForbiddenCharsTable( pDoc->GetForbiddenCharsTable() ); + + EEControlBits nCntrl = GetControlWord(); + nCntrl |= EEControlBits::ALLOWBIGOBJS; + nCntrl |= EEControlBits::MARKFIELDS; + nCntrl |= EEControlBits::AUTOCORRECT; + + bool bOnlineSpell = false; + + sd::DrawDocShell* pDocSh = mpDrawDocument->GetDocSh(); + + if (pDocSh) + { + bOnlineSpell = mpDrawDocument->GetOnlineSpell(); + } + else + { + bOnlineSpell = false; + + try + { + const SvtLinguConfig aLinguConfig; + Any aAny = aLinguConfig.GetProperty( UPN_IS_SPELL_AUTO ); + aAny >>= bOnlineSpell; + } + catch( ... ) + { + OSL_FAIL( "Ill. type in linguistic property" ); + } + } + + if (bOnlineSpell) + nCntrl |= EEControlBits::ONLINESPELLING; + else + nCntrl &= ~EEControlBits::ONLINESPELLING; + + SetControlWord(nCntrl); + + Reference< XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() ); + if ( xSpellChecker.is() ) + SetSpeller( xSpellChecker ); + + Reference< XHyphenator > xHyphenator( LinguMgr::GetHyphenator() ); + if( xHyphenator.is() ) + SetHyphenator( xHyphenator ); + + SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ); +} + +/// Nothing spectacular in the destructor. +SdOutliner::~SdOutliner() +{ +} + +OutlinerView* SdOutliner::getOutlinerView() +{ + return mpImpl->GetOutlinerView(); +} + +/** Prepare find&replace or spellchecking. This distinguishes between three + cases: + <ol> + <li>The current shell is a <type>DrawViewShell</type>: Create a + <type>OutlinerView</type> object and search all objects of (i) the + current mark list, (ii) of the current view, or (iii) of all the view + combinations: + <ol> + <li>Draw view, slide view</li> + <li>Draw view, background view</li> + <li>Notes view, slide view</li> + <li>Notes view, background view</li> + <li>Handout view, slide view</li> + <li>Handout view, background view</li> + </ol> + + <li>When the current shell is a <type>SdOutlineViewShell</type> then + directly operate on it. No switching into other views takes place.</li> + </ol> +*/ +void SdOutliner::PrepareSpelling() +{ + mbPrepareSpellingPending = false; + + sd::ViewShellBase* pBase = getViewShellBase(); + if (pBase != nullptr) + SetViewShell (pBase->GetMainViewShell()); + SetRefDevice( SD_MOD()->GetVirtualRefDevice() ); + + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if (pViewShell) + { + mbStringFound = false; + + // Supposed that we are not located at the very beginning/end of + // the document then there may be a match in the document + // prior/after the current position. + mbMatchMayExist = true; + + maObjectIterator = sd::outliner::Iterator(); + maSearchStartPosition = sd::outliner::Iterator(); + RememberStartPosition(); + + mpImpl->ProvideOutlinerView(*this, pViewShell, mpWindow); + + HandleChangedSelection (); + } + ClearModifyFlag(); +} + +void SdOutliner::StartSpelling() +{ + meMode = SPELL; + mbDirectionIsForward = true; + mpSearchItem.reset(); +} + +/** Free all resources acquired during the search/spell check. After a + spell check the start position is restored here. +*/ +void SdOutliner::EndSpelling() +{ + // Keep old view shell alive until we release the outliner view. + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + std::shared_ptr<sd::ViewShell> pOldViewShell (pViewShell); + + sd::ViewShellBase* pBase = getViewShellBase(); + if (pBase != nullptr) + pViewShell = pBase->GetMainViewShell(); + else + pViewShell.reset(); + mpWeakViewShell = pViewShell; + + // When in <member>PrepareSpelling()</member> a new outline view has + // been created then delete it here. + bool bViewIsDrawViewShell(dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() )); + if (bViewIsDrawViewShell) + { + SetStatusEventHdl(Link<EditStatus&,void>()); + mpView = pViewShell->GetView(); + mpView->UnmarkAllObj (mpView->GetSdrPageView()); + mpView->SdrEndTextEdit(); + // Make FuSelection the current function. + pViewShell->GetDispatcher()->Execute( + SID_OBJECT_SELECT, + SfxCallMode::SYNCHRON | SfxCallMode::RECORD); + + // Remove and, if previously created by us, delete the outline + // view. + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView != nullptr) + { + RemoveView(pOutlinerView); + mpImpl->ReleaseOutlinerView(); + } + + SetUpdateLayout(true); + } + + // Before clearing the modify flag use it as a hint that + // changes were done at SpellCheck + if(IsModified()) + { + if(auto pOutlineView = dynamic_cast<sd::OutlineView *>( mpView )) + pOutlineView->PrepareClose(); + if(mpDrawDocument && !mpDrawDocument->IsChanged()) + mpDrawDocument->SetChanged(); + } + + // Now clear the modify flag to have a specified state of + // Outliner + ClearModifyFlag(); + + // When spell checking then restore the start position. + if (meMode==SPELL || meMode==TEXT_CONVERSION) + RestoreStartPosition (); + + mpWeakViewShell.reset(); + mpView = nullptr; + mpWindow = nullptr; + mnStartPageIndex = sal_uInt16(-1); +} + +bool SdOutliner::SpellNextDocument() +{ + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() )) + { + // When doing a spell check in the outline view then there is + // only one document. + mbEndOfSearch = true; + EndOfSearch (); + } + else + { + if( auto pOutlineView = dynamic_cast<sd::OutlineView *>( mpView )) + pOutlineView->PrepareClose(); + mpDrawDocument->GetDocSh()->SetWaitCursor( true ); + + Initialize (true); + + mpWindow = pViewShell->GetActiveWindow(); + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView != nullptr) + pOutlinerView->SetWindow(mpWindow); + ProvideNextTextObject (); + + mpDrawDocument->GetDocSh()->SetWaitCursor( false ); + ClearModifyFlag(); + } + + return !mbEndOfSearch; +} + +/** + * check next text object + */ +svx::SpellPortions SdOutliner::GetNextSpellSentence() +{ + svx::SpellPortions aResult; + + DetectChange(); + // Iterate over sentences and text shapes until a sentence with a + // spelling error has been found. If no such sentence can be + // found the loop is left through a break. + // It is the responsibility of the sd outliner object to correctly + // iterate over all text shapes, i.e. switch between views, wrap + // around at the end of the document, stop when all text shapes + // have been examined exactly once. + bool bFoundNextSentence = false; + while ( ! bFoundNextSentence) + { + OutlinerView* pOutlinerView = GetView(0); + if (pOutlinerView != nullptr) + { + ESelection aCurrentSelection (pOutlinerView->GetSelection()); + if ( ! mbMatchMayExist + && maStartSelection < aCurrentSelection) + EndOfSearch(); + + // Advance to the next sentence. + bFoundNextSentence = SpellSentence( pOutlinerView->GetEditView(), aResult); + } + + // When no sentence with spelling errors has been found in the + // currently selected text shape or there is no selected text + // shape then advance to the next text shape. + if ( ! bFoundNextSentence) + if ( ! SpellNextDocument()) + // All text objects have been processed so exit the + // loop and return an empty portions list. + break; + } + + return aResult; +} + +/** Go to next match. +*/ +bool SdOutliner::StartSearchAndReplace (const SvxSearchItem* pSearchItem) +{ + bool bEndOfSearch = true; + + // clear the search toolbar entry + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty); + + mpDrawDocument->GetDocSh()->SetWaitCursor( true ); + + // Since REPLACE is really a replaceAndSearchNext instead of a searchAndReplace, + // make sure that the search portion has not changed since the last FIND. + if (!mbPrepareSpellingPending && mpSearchItem + && pSearchItem->GetCommand() == SvxSearchCmd::REPLACE + && !mpSearchItem->equalsIgnoring(*pSearchItem, /*bIgnoreReplace=*/true, + /*bIgnoreCommand=*/true)) + { + EndSpelling(); + mbPrepareSpellingPending = true; + } + + if (mbPrepareSpellingPending) + PrepareSpelling(); + sd::ViewShellBase* pBase = getViewShellBase(); + // Determine whether we have to abort the search. This is necessary + // when the main view shell does not support searching. + bool bAbort = false; + if (pBase != nullptr) + { + std::shared_ptr<sd::ViewShell> pShell (pBase->GetMainViewShell()); + SetViewShell(pShell); + if (pShell == nullptr) + bAbort = true; + else + switch (pShell->GetShellType()) + { + case sd::ViewShell::ST_DRAW: + case sd::ViewShell::ST_IMPRESS: + case sd::ViewShell::ST_NOTES: + case sd::ViewShell::ST_HANDOUT: + case sd::ViewShell::ST_OUTLINE: + bAbort = false; + break; + default: + bAbort = true; + break; + } + } + + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if ( ! pViewShell) + { + OSL_ASSERT(pViewShell); + return true; + } + + if ( ! bAbort) + { + meMode = SEARCH; + mpSearchItem.reset(pSearchItem->Clone()); + + mbFoundObject = false; + + Initialize ( ! mpSearchItem->GetBackward()); + + const SvxSearchCmd nCommand (mpSearchItem->GetCommand()); + if (nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL) + { + bEndOfSearch = SearchAndReplaceAll (); + } + else + { + RememberStartPosition (); + bEndOfSearch = SearchAndReplaceOnce (); + // restore start position if nothing was found + if(!mbStringFound) + { + RestoreStartPosition (); + // Nothing was changed, no need to restart the spellchecker. + if (nCommand == SvxSearchCmd::FIND) + bEndOfSearch = false; + } + mnStartPageIndex = sal_uInt16(-1); + } + } + + mpDrawDocument->GetDocSh()->SetWaitCursor( false ); + + return bEndOfSearch; +} + +void SdOutliner::Initialize (bool bDirectionIsForward) +{ + const bool bIsAtEnd (maObjectIterator == sd::outliner::OutlinerContainer(this).end()); + const bool bOldDirectionIsForward = mbDirectionIsForward; + mbDirectionIsForward = bDirectionIsForward; + + if (maObjectIterator == sd::outliner::Iterator()) + { + // Initialize a new search. + maObjectIterator = sd::outliner::OutlinerContainer(this).current(); + maCurrentPosition = *maObjectIterator; + + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if ( ! pViewShell) + { + OSL_ASSERT(pViewShell); + return; + } + + // In case we are searching in an outline view then first remove the + // current selection and place cursor at its start or end. + if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() )) + { + ESelection aSelection = getOutlinerView()->GetSelection (); + if (mbDirectionIsForward) + { + aSelection.nEndPara = aSelection.nStartPara; + aSelection.nEndPos = aSelection.nStartPos; + } + else + { + aSelection.nStartPara = aSelection.nEndPara; + aSelection.nStartPos = aSelection.nEndPos; + } + getOutlinerView()->SetSelection (aSelection); + } + + // When not beginning the search at the beginning of the search area + // then there may be matches before the current position. + mbMatchMayExist = (maObjectIterator!=sd::outliner::OutlinerContainer(this).begin()); + } + else if (bOldDirectionIsForward != mbDirectionIsForward) + { + // Requested iteration direction has changed. Turn around the iterator. + maObjectIterator.Reverse(); + if (bIsAtEnd) + { + // The iterator has pointed to end(), which after the search + // direction is reversed, becomes begin(). + maObjectIterator = sd::outliner::OutlinerContainer(this).begin(); + } + else + { + // The iterator has pointed to the object one ahead/before the current + // one. Now move it to the one before/ahead the current one. + ++maObjectIterator; + if (maObjectIterator != sd::outliner::OutlinerContainer(this).end()) + { + ++maObjectIterator; + } + } + + mbMatchMayExist = true; + } + + // Initialize the last valid position with where the search starts so + // that it always points to a valid position. + maLastValidPosition = *sd::outliner::OutlinerContainer(this).current(); +} + +bool SdOutliner::SearchAndReplaceAll() +{ + bool bRet = true; + + // Save the current position to be restored after having replaced all + // matches. + RememberStartPosition (); + + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if ( ! pViewShell) + { + OSL_ASSERT(pViewShell); + return true; + } + + std::vector<sd::SearchSelection> aSelections; + if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() )) + { + // Put the cursor to the beginning/end of the outliner. + getOutlinerView()->SetSelection (GetSearchStartPosition ()); + + // The outliner does all the work for us when we are in this mode. + SearchAndReplaceOnce(); + } + else if( nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() )) + { + // Disable selection change notifications during search all. + SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase(); + rSfxViewShell.setTiledSearching(true); + comphelper::ScopeGuard aGuard([&rSfxViewShell]() + { + rSfxViewShell.setTiledSearching(false); + }); + + // Go to beginning/end of document. + maObjectIterator = sd::outliner::OutlinerContainer(this).begin(); + // Switch to the first object which contains the search string. + ProvideNextTextObject(); + if( !mbStringFound ) + { + RestoreStartPosition (); + mnStartPageIndex = sal_uInt16(-1); + return true; + } + // Reset the iterator back to the beginning + maObjectIterator = sd::outliner::OutlinerContainer(this).begin(); + + // Search/replace until the end of the document is reached. + bool bFoundMatch; + do + { + bFoundMatch = ! SearchAndReplaceOnce(&aSelections); + if (mpSearchItem->GetCommand() == SvxSearchCmd::FIND_ALL && comphelper::LibreOfficeKit::isActive() && bFoundMatch && aSelections.size() == 1) + { + // Without this, RememberStartPosition() will think it already has a remembered position. + mnStartPageIndex = sal_uInt16(-1); + + RememberStartPosition(); + + // So when RestoreStartPosition() restores the first match, then spellchecker doesn't kill the selection. + bRet = false; + } + } + while (bFoundMatch); + + if (mpSearchItem->GetCommand() == SvxSearchCmd::FIND_ALL && comphelper::LibreOfficeKit::isActive() && !aSelections.empty()) + { + boost::property_tree::ptree aTree; + aTree.put("searchString", mpSearchItem->GetSearchString().toUtf8().getStr()); + aTree.put("highlightAll", true); + + boost::property_tree::ptree aChildren; + for (const sd::SearchSelection& rSelection : aSelections) + { + boost::property_tree::ptree aChild; + aChild.put("part", OString::number(rSelection.m_nPage).getStr()); + aChild.put("rectangles", rSelection.m_aRectangles.getStr()); + aChildren.push_back(std::make_pair("", aChild)); + } + aTree.add_child("searchResultSelection", aChildren); + + std::stringstream aStream; + boost::property_tree::write_json(aStream, aTree); + OString aPayload( aStream.str() ); + rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload); + } + } + + RestoreStartPosition (); + + if (mpSearchItem->GetCommand() == SvxSearchCmd::FIND_ALL && comphelper::LibreOfficeKit::isActive() && !bRet) + { + // Find-all, tiled rendering and we have at least one match. + OString aPayload = OString::number(mnStartPageIndex); + SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase(); + rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload); + + // Emit a selection callback here: + // 1) The original one is no longer valid, as we there was a SET_PART in between + // 2) The underlying editeng will only talk about the first match till + // it doesn't support multi-selection. + std::vector<OString> aRectangles; + for (const sd::SearchSelection& rSelection : aSelections) + { + if (rSelection.m_nPage == mnStartPageIndex) + aRectangles.push_back(rSelection.m_aRectangles); + } + OString sRectangles = comphelper::string::join("; ", aRectangles); + rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRectangles); + } + + mnStartPageIndex = sal_uInt16(-1); + + return bRet; +} + +namespace +{ + +basegfx::B2DRectangle getPDFSelection(const std::unique_ptr<VectorGraphicSearch> & rVectorGraphicSearch, + const SdrObject* pObject) +{ + basegfx::B2DRectangle aSelection; + + auto const & rTextRectangles = rVectorGraphicSearch->getTextRectangles(); + if (rTextRectangles.empty()) + return aSelection; + + basegfx::B2DSize aPdfPageSizeHMM = rVectorGraphicSearch->pageSize(); + + basegfx::B2DRectangle aObjectB2DRectHMM(vcl::unotools::b2DRectangleFromRectangle(pObject->GetLogicRect())); + + // Setup coordinate conversion matrix to convert the inner PDF + // coordinates to the page relative coordinates + basegfx::B2DHomMatrix aB2DMatrix; + + aB2DMatrix.scale(aObjectB2DRectHMM.getWidth() / aPdfPageSizeHMM.getWidth(), + aObjectB2DRectHMM.getHeight() / aPdfPageSizeHMM.getHeight()); + + aB2DMatrix.translate(aObjectB2DRectHMM.getMinX(), aObjectB2DRectHMM.getMinY()); + + + for (auto const & rRectangle : rVectorGraphicSearch->getTextRectangles()) + { + basegfx::B2DRectangle aRectangle(rRectangle); + aRectangle *= aB2DMatrix; + + if (aSelection.isEmpty()) + aSelection = aRectangle; + else + aSelection.expand(aRectangle); + } + + return aSelection; +} + +} // end namespace + +void SdOutliner::sendLOKSearchResultCallback(const std::shared_ptr<sd::ViewShell> & pViewShell, + const OutlinerView* pOutlinerView, + std::vector<sd::SearchSelection>* pSelections) +{ + std::vector<::tools::Rectangle> aLogicRects; + auto& rVectorGraphicSearchContext = mpImpl->getVectorGraphicSearchContext(); + if (rVectorGraphicSearchContext.mbCurrentIsVectorGraphic) + { + basegfx::B2DRectangle aSelectionHMM = getPDFSelection(rVectorGraphicSearchContext.mpVectorGraphicSearch, mpObj); + + tools::Rectangle aSelection(Point(aSelectionHMM.getMinX(), aSelectionHMM.getMinY()), + Size(aSelectionHMM.getWidth(), aSelectionHMM.getHeight())); + aSelection = o3tl::convert(aSelection, o3tl::Length::mm100, o3tl::Length::twip); + aLogicRects.push_back(aSelection); + } + else + { + pOutlinerView->GetSelectionRectangles(aLogicRects); + + // convert to twips if in 100thmm (seems as if LibreOfficeKit is based on twips?). Do this + // here where we have the only place needing this, *not* in ImpEditView::GetSelectionRectangles + // which makes that method unusable for others + if (pOutlinerView->GetWindow() && MapUnit::Map100thMM == pOutlinerView->GetWindow()->GetMapMode().GetMapUnit()) + { + for (tools::Rectangle& rRectangle : aLogicRects) + { + rRectangle = o3tl::convert(rRectangle, o3tl::Length::mm100, o3tl::Length::twip); + } + } + } + + std::vector<OString> aLogicRectStrings; + std::transform(aLogicRects.begin(), aLogicRects.end(), std::back_inserter(aLogicRectStrings), + [](const ::tools::Rectangle& rRectangle) + { + return rRectangle.toString(); + }); + + OString sRectangles = comphelper::string::join("; ", aLogicRectStrings); + + if (!pSelections) + { + // notify LibreOfficeKit about changed page + OString aPayload = OString::number(maCurrentPosition.mnPageIndex); + SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase(); + rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload); + + // also about search result selections + boost::property_tree::ptree aTree; + aTree.put("searchString", mpSearchItem->GetSearchString().toUtf8().getStr()); + aTree.put("highlightAll", false); + + boost::property_tree::ptree aChildren; + boost::property_tree::ptree aChild; + aChild.put("part", OString::number(maCurrentPosition.mnPageIndex).getStr()); + aChild.put("rectangles", sRectangles.getStr()); + aChildren.push_back(std::make_pair("", aChild)); + aTree.add_child("searchResultSelection", aChildren); + + std::stringstream aStream; + boost::property_tree::write_json(aStream, aTree); + aPayload = OString(aStream.str()); + rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload); + + if (rVectorGraphicSearchContext.mbCurrentIsVectorGraphic) + { + rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRectangles); + } + } + else + { + sd::SearchSelection aSelection(maCurrentPosition.mnPageIndex, sRectangles); + bool bDuplicate = !pSelections->empty() && pSelections->back() == aSelection; + if (!bDuplicate) + pSelections->push_back(aSelection); + } +} + +bool SdOutliner::SearchAndReplaceOnce(std::vector<sd::SearchSelection>* pSelections) +{ + DetectChange (); + + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + + if (!getOutlinerView() || !GetEditEngine().HasView(&getOutlinerView()->GetEditView())) + { + std::shared_ptr<sd::DrawViewShell> pDrawViewShell ( + std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell)); + + // Perhaps the user switched to a different page/slide between searches. + // If so, reset the starting search position to the current slide like DetectChange does + if (pDrawViewShell && pDrawViewShell->GetCurPagePos() != maCurrentPosition.mnPageIndex) + maObjectIterator = sd::outliner::OutlinerContainer(this).current(); + + mpImpl->ProvideOutlinerView(*this, pViewShell, mpWindow); + } + + if (pViewShell) + { + mpView = pViewShell->GetView(); + mpWindow = pViewShell->GetActiveWindow(); + getOutlinerView()->SetWindow(mpWindow); + auto& rVectorGraphicSearchContext = mpImpl->getVectorGraphicSearchContext(); + if (nullptr != dynamic_cast<const sd::DrawViewShell*>(pViewShell.get())) + { + sal_uLong nMatchCount = 0; + + if (rVectorGraphicSearchContext.mbCurrentIsVectorGraphic) + { + OUString const & rString = mpSearchItem->GetSearchString(); + bool bBackwards = mpSearchItem->GetBackward(); + + VectorGraphicSearchOptions aOptions; + aOptions.meStartPosition = bBackwards ? SearchStartPosition::End : SearchStartPosition::Begin; + aOptions.mbMatchCase = mpSearchItem->GetExact(); + aOptions.mbMatchWholeWord = mpSearchItem->GetWordOnly(); + + bool bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->search(rString, aOptions); + + if (bResult) + { + if (bBackwards) + bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->previous(); + else + bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->next(); + } + + if (bResult) + { + nMatchCount = 1; + + SdrPageView* pPageView = mpView->GetSdrPageView(); + mpView->UnmarkAllObj(pPageView); + + std::vector<basegfx::B2DRectangle> aSubSelections; + basegfx::B2DRectangle aSubSelection = getPDFSelection(rVectorGraphicSearchContext.mpVectorGraphicSearch, mpObj); + if (!aSubSelection.isEmpty()) + aSubSelections.push_back(aSubSelection); + mpView->MarkObj(mpObj, pPageView, false, false, std::move(aSubSelections)); + } + else + { + rVectorGraphicSearchContext.reset(); + } + } + else + { + // When replacing we first check if there is a selection + // indicating a match. If there is then replace it. The + // following call to StartSearchAndReplace will then search for + // the next match. + if (meMode == SEARCH && mpSearchItem->GetCommand() == SvxSearchCmd::REPLACE) + { + if (getOutlinerView()->GetSelection().HasRange()) + getOutlinerView()->StartSearchAndReplace(*mpSearchItem); + } + + // Search for the next match. + if (mpSearchItem->GetCommand() != SvxSearchCmd::REPLACE_ALL) + { + nMatchCount = getOutlinerView()->StartSearchAndReplace(*mpSearchItem); + } + } + + // Go to the next text object when there have been no matches in + // the current object or the whole object has already been + // processed. + if (nMatchCount==0 || mpSearchItem->GetCommand()==SvxSearchCmd::REPLACE_ALL) + { + ProvideNextTextObject (); + + if (!mbEndOfSearch && !rVectorGraphicSearchContext.mbCurrentIsVectorGraphic) + { + // Remember the current position as the last one with a + // text object. + maLastValidPosition = maCurrentPosition; + + // Now that the mbEndOfSearch flag guards this block the + // following assertion and return should not be + // necessary anymore. + DBG_ASSERT(GetEditEngine().HasView(&getOutlinerView()->GetEditView() ), + "SearchAndReplace without valid view!" ); + if ( ! GetEditEngine().HasView( &getOutlinerView()->GetEditView() ) ) + { + mpDrawDocument->GetDocSh()->SetWaitCursor( false ); + return true; + } + + if (meMode == SEARCH) + getOutlinerView()->StartSearchAndReplace(*mpSearchItem); + } + } + } + else if (nullptr != dynamic_cast<const sd::OutlineViewShell*>(pViewShell.get())) + { + mpDrawDocument->GetDocSh()->SetWaitCursor(false); + // The following loop is executed more than once only when a + // wrap around search is done. + while (true) + { + int nResult = getOutlinerView()->StartSearchAndReplace(*mpSearchItem); + if (nResult == 0) + { + if (HandleFailedSearch ()) + { + getOutlinerView()->SetSelection (GetSearchStartPosition ()); + continue; + } + } + else + mbStringFound = true; + break; + } + } + } + + mpDrawDocument->GetDocSh()->SetWaitCursor( false ); + + if (pViewShell && comphelper::LibreOfficeKit::isActive() && mbStringFound) + { + sendLOKSearchResultCallback(pViewShell, getOutlinerView(), pSelections); + } + + return mbEndOfSearch; +} + +/** Try to detect whether the document or the view (shell) has changed since + the last time <member>StartSearchAndReplace()</member> has been called. +*/ +void SdOutliner::DetectChange() +{ + sd::outliner::IteratorPosition aPosition (maCurrentPosition); + + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + std::shared_ptr<sd::DrawViewShell> pDrawViewShell ( + std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell)); + + // Detect whether the view has been switched from the outside. + if (pDrawViewShell != nullptr + && (aPosition.meEditMode != pDrawViewShell->GetEditMode() + || aPosition.mePageKind != pDrawViewShell->GetPageKind())) + { + // Either the edit mode or the page kind has changed. + SetStatusEventHdl(Link<EditStatus&,void>()); + + SdrPageView* pPageView = mpView->GetSdrPageView(); + if (pPageView != nullptr) + mpView->UnmarkAllObj (pPageView); + mpView->SdrEndTextEdit(); + SetUpdateLayout(false); + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView != nullptr) + pOutlinerView->SetOutputArea( ::tools::Rectangle( Point(), Size(1, 1) ) ); + if (meMode == SPELL) + SetPaperSize( Size(1, 1) ); + SetText(OUString(), GetParagraph(0)); + + RememberStartPosition (); + + mnPageCount = mpDrawDocument->GetSdPageCount(pDrawViewShell->GetPageKind()); + maObjectIterator = sd::outliner::OutlinerContainer(this).current(); + } + + // Detect change of the set of selected objects. If their number has + // changed start again with the first selected object. + else if (DetectSelectionChange()) + { + HandleChangedSelection (); + maObjectIterator = sd::outliner::OutlinerContainer(this).current(); + } + + // Detect change of page count. Restart search at first/last page in + // that case. + else if (aPosition.meEditMode == EditMode::Page + && mpDrawDocument->GetSdPageCount(aPosition.mePageKind) != mnPageCount) + { + // The number of pages has changed. + mnPageCount = mpDrawDocument->GetSdPageCount(aPosition.mePageKind); + maObjectIterator = sd::outliner::OutlinerContainer(this).current(); + } + else if (aPosition.meEditMode == EditMode::MasterPage + && mpDrawDocument->GetSdPageCount(aPosition.mePageKind) != mnPageCount) + { + // The number of master pages has changed. + mnPageCount = mpDrawDocument->GetSdPageCount(aPosition.mePageKind); + maObjectIterator = sd::outliner::OutlinerContainer(this).current(); + } +} + +bool SdOutliner::DetectSelectionChange() +{ + bool bSelectionHasChanged = false; + + // If mpObj is NULL then we have not yet found our first match. + // Detecting a change makes no sense. + if (mpObj != nullptr) + { + const size_t nMarkCount = mpView ? mpView->GetMarkedObjectList().GetMarkCount() : 0; + switch (nMarkCount) + { + case 0: + // The selection has changed when previously there have been + // selected objects. + bSelectionHasChanged = mbRestrictSearchToSelection; + break; + case 1: + // Check if the only selected object is not the one that we + // had selected. + if (mpView != nullptr) + { + SdrMark* pMark = mpView->GetMarkedObjectList().GetMark(0); + if (pMark != nullptr) + bSelectionHasChanged = (mpObj != pMark->GetMarkedSdrObj ()); + } + break; + default: + // We had selected exactly one object. + bSelectionHasChanged = true; + break; + } + } + + return bSelectionHasChanged; +} + +void SdOutliner::RememberStartPosition() +{ + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if ( ! pViewShell) + { + OSL_ASSERT(pViewShell); + return; + } + + if ( mnStartPageIndex != sal_uInt16(-1) ) + return; + + if( nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() )) + { + std::shared_ptr<sd::DrawViewShell> pDrawViewShell ( + std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell)); + if (pDrawViewShell != nullptr) + { + meStartViewMode = pDrawViewShell->GetPageKind(); + meStartEditMode = pDrawViewShell->GetEditMode(); + mnStartPageIndex = pDrawViewShell->GetCurPagePos(); + } + + if (mpView != nullptr) + { + mpStartEditedObject = mpView->GetTextEditObject(); + if (mpStartEditedObject != nullptr) + { + // Try to retrieve current caret position only when there is an + // edited object. + ::Outliner* pOutliner = + static_cast<sd::DrawView*>(mpView)->GetTextEditOutliner(); + if (pOutliner!=nullptr && pOutliner->GetViewCount()>0) + { + OutlinerView* pOutlinerView = pOutliner->GetView(0); + maStartSelection = pOutlinerView->GetSelection(); + } + } + } + } + else if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() )) + { + // Remember the current cursor position. + OutlinerView* pView = GetView(0); + if (pView != nullptr) + pView->GetSelection(); + } + else + { + mnStartPageIndex = sal_uInt16(-1); + } +} + +void SdOutliner::RestoreStartPosition() +{ + bool bRestore = true; + // Take a negative start page index as indicator that restoring the + // start position is not requested. + if (mnStartPageIndex == sal_uInt16(-1) ) + bRestore = false; + // Don't restore when the view shell is not valid. + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if (pViewShell == nullptr) + bRestore = false; + + if (!bRestore) + return; + + if( nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() )) + { + std::shared_ptr<sd::DrawViewShell> pDrawViewShell ( + std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell)); + SetViewMode (meStartViewMode); + if (pDrawViewShell != nullptr) + { + SetPage (meStartEditMode, mnStartPageIndex); + mpObj = mpStartEditedObject; + if (mpObj) + { + PutTextIntoOutliner(); + EnterEditMode(false); + if (getOutlinerView()) + getOutlinerView()->SetSelection(maStartSelection); + } + } + } + else if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() )) + { + // Set cursor to its old position. + OutlinerView* pView = GetView(0); + if (pView != nullptr) + pView->SetSelection (maStartSelection); + } +} + +namespace +{ + +bool lclIsValidTextObject(const sd::outliner::IteratorPosition& rPosition) +{ + auto* pObject = DynCastSdrTextObj( rPosition.mxObject.get().get() ); + return (pObject != nullptr) && pObject->HasText() && ! pObject->IsEmptyPresObj(); +} + +bool isValidVectorGraphicObject(const sd::outliner::IteratorPosition& rPosition) +{ + rtl::Reference<SdrGrafObj> pGraphicObject = dynamic_cast<SdrGrafObj*>(rPosition.mxObject.get().get()); + if (pGraphicObject) + { + auto const& pVectorGraphicData = pGraphicObject->GetGraphic().getVectorGraphicData(); + if (pVectorGraphicData && VectorGraphicDataType::Pdf == pVectorGraphicData->getType()) + { + return true; + } + } + return false; +} + +} // end anonymous namespace + + +/** The main purpose of this method is to iterate over all shape objects of + the search area (current selection, current view, or whole document) + until a text object has been found that contains at least one match or + until no such object can be found anymore. These two conditions are + expressed by setting one of the flags <member>mbFoundObject</member> or + <member>mbEndOfSearch</member> to <TRUE/>. +*/ +void SdOutliner::ProvideNextTextObject() +{ + mbEndOfSearch = false; + mbFoundObject = false; + + // reset the vector search + auto& rVectorGraphicSearchContext = mpImpl->getVectorGraphicSearchContext(); + rVectorGraphicSearchContext.reset(); + + mpView->UnmarkAllObj (mpView->GetSdrPageView()); + try + { + mpView->SdrEndTextEdit(); + } + catch (const css::uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("sd.view"); + } + SetUpdateLayout(false); + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView != nullptr) + pOutlinerView->SetOutputArea( ::tools::Rectangle( Point(), Size(1, 1) ) ); + if (meMode == SPELL) + SetPaperSize( Size(1, 1) ); + SetText(OUString(), GetParagraph(0)); + + mpSearchSpellTextObj = nullptr; + + // Iterate until a valid text object has been found or the search ends. + do + { + mpObj = nullptr; + mpParaObj = nullptr; + + if (maObjectIterator != sd::outliner::OutlinerContainer(this).end()) + { + maCurrentPosition = *maObjectIterator; + + // LOK: do not descent to notes or master pages when searching + bool bForbiddenPage = comphelper::LibreOfficeKit::isActive() && (maCurrentPosition.mePageKind != PageKind::Standard || maCurrentPosition.meEditMode != EditMode::Page); + + rVectorGraphicSearchContext.reset(); + + if (!bForbiddenPage) + { + // Switch to the current object only if it is a valid text object. + if (lclIsValidTextObject(maCurrentPosition)) + { + // Don't set yet in case of searching: the text object may not match. + if (meMode != SEARCH) + mpObj = SetObject(maCurrentPosition); + else + mpObj = maCurrentPosition.mxObject.get().get(); + } + // Or if the object is a valid graphic object which contains vector graphic + else if (meMode == SEARCH && isValidVectorGraphicObject(maCurrentPosition)) + { + mpObj = maCurrentPosition.mxObject.get().get(); + rVectorGraphicSearchContext.mbCurrentIsVectorGraphic = true; + } + } + + // Advance to the next object + ++maObjectIterator; + + if (mpObj) + { + if (rVectorGraphicSearchContext.mbCurrentIsVectorGraphic) + { + // We know here the object is a SdrGrafObj and that it + // contains a vector graphic + auto* pGraphicObject = static_cast<SdrGrafObj*>(mpObj); + OUString const & rString = mpSearchItem->GetSearchString(); + bool bBackwards = mpSearchItem->GetBackward(); + + VectorGraphicSearchOptions aOptions; + aOptions.meStartPosition = bBackwards ? SearchStartPosition::End : SearchStartPosition::Begin; + aOptions.mbMatchCase = mpSearchItem->GetExact(); + aOptions.mbMatchWholeWord = mpSearchItem->GetWordOnly(); + + rVectorGraphicSearchContext.mpVectorGraphicSearch = std::make_unique<VectorGraphicSearch>(pGraphicObject->GetGraphic()); + + bool bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->search(rString, aOptions); + if (bResult) + { + if (bBackwards) + bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->previous(); + else + bResult = rVectorGraphicSearchContext.mpVectorGraphicSearch->next(); + } + + if (bResult) + { + mpObj = SetObject(maCurrentPosition); + + mbStringFound = true; + mbMatchMayExist = true; + mbFoundObject = true; + + SdrPageView* pPageView = mpView->GetSdrPageView(); + mpView->UnmarkAllObj(pPageView); + + std::vector<basegfx::B2DRectangle> aSubSelections; + basegfx::B2DRectangle aSubSelection = getPDFSelection(rVectorGraphicSearchContext.mpVectorGraphicSearch, mpObj); + if (!aSubSelection.isEmpty()) + aSubSelections.push_back(aSubSelection); + + mpView->MarkObj(mpObj, pPageView, false, false, std::move(aSubSelections)); + + mpDrawDocument->GetDocSh()->SetWaitCursor( false ); + } + else + { + rVectorGraphicSearchContext.reset(); + } + } + else + { + PutTextIntoOutliner(); + + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if (pViewShell != nullptr) + { + switch (meMode) + { + case SEARCH: + PrepareSearchAndReplace (); + break; + case SPELL: + PrepareSpellCheck (); + break; + case TEXT_CONVERSION: + PrepareConversion(); + break; + } + } + } + } + } + else + { + rVectorGraphicSearchContext.reset(); + + if (meMode == SEARCH) + // Instead of doing a full-blown SetObject(), which would do the same -- but would also possibly switch pages. + mbStringFound = false; + + mbEndOfSearch = true; + EndOfSearch (); + } + } + while ( ! (mbFoundObject || mbEndOfSearch)); +} + +void SdOutliner::EndOfSearch() +{ + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if ( ! pViewShell) + { + OSL_ASSERT(pViewShell); + return; + } + + // Before we display a dialog we first jump to where the last valid text + // object was found. All page and view mode switching since then was + // temporary and should not be visible to the user. + if( nullptr == dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() )) + SetObject (maLastValidPosition); + + if (mbRestrictSearchToSelection) + ShowEndOfSearchDialog (); + else + { + // When no match has been found so far then terminate the search. + if ( ! mbMatchMayExist) + { + ShowEndOfSearchDialog (); + mbEndOfSearch = true; + } + // Ask the user whether to wrap around and continue the search or + // to terminate. + else if (meMode==TEXT_CONVERSION || ShowWrapAroundDialog ()) + { + mbMatchMayExist = false; + // Everything back to beginning (or end?) of the document. + maObjectIterator = sd::outliner::OutlinerContainer(this).begin(); + if( nullptr != dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() )) + { + // Set cursor to first character of the document. + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView != nullptr) + pOutlinerView->SetSelection (GetSearchStartPosition ()); + } + + mbEndOfSearch = false; + } + else + { + // No wrap around. + mbEndOfSearch = true; + } + } +} + +void SdOutliner::ShowEndOfSearchDialog() +{ + if (meMode == SEARCH) + { + if (!mbStringFound) + { + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); + std::shared_ptr<sd::ViewShell> pViewShell(mpWeakViewShell.lock()); + if (pViewShell) + { + SfxViewShell& rSfxViewShell = pViewShell->GetViewShellBase(); + rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, mpSearchItem->GetSearchString().toUtf8()); + } + } + + // don't do anything else for search + return; + } + + OUString aString; + if (mpView->AreObjectsMarked()) + aString = SdResId(STR_END_SPELLING_OBJ); + else + aString = SdResId(STR_END_SPELLING); + + // Show the message in an info box that is modal with respect to the whole application. + weld::Window* pParent = GetMessageBoxParent(); + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent, + VclMessageType::Info, VclButtonsType::Ok, aString)); + xInfoBox->run(); +} + +bool SdOutliner::ShowWrapAroundDialog() +{ + // Determine whether to show the dialog. + if (mpSearchItem) + { + // When searching display the dialog only for single find&replace. + const SvxSearchCmd nCommand(mpSearchItem->GetCommand()); + if (nCommand == SvxSearchCmd::REPLACE || nCommand == SvxSearchCmd::FIND) + { + if (mbDirectionIsForward) + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End); + else + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Start); + + return true; + } + else + return false; + } + + // show dialog only for spelling + if (meMode != SPELL) + return false; + + // The question text depends on the search direction. + bool bImpress = mpDrawDocument && mpDrawDocument->GetDocumentType() == DocumentType::Impress; + + TranslateId pStringId; + if (mbDirectionIsForward) + pStringId = bImpress ? STR_SAR_WRAP_FORWARD : STR_SAR_WRAP_FORWARD_DRAW; + else + pStringId = bImpress ? STR_SAR_WRAP_BACKWARD : STR_SAR_WRAP_BACKWARD_DRAW; + + // Pop up question box that asks the user whether to wrap around. + // The dialog is made modal with respect to the whole application. + weld::Window* pParent = GetMessageBoxParent(); + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pParent, + VclMessageType::Question, VclButtonsType::YesNo, SdResId(pStringId))); + sal_uInt16 nBoxResult = xQueryBox->run(); + + return (nBoxResult == RET_YES); +} + +void SdOutliner::PutTextIntoOutliner() +{ + mpSearchSpellTextObj = DynCastSdrTextObj( mpObj ); + if ( mpSearchSpellTextObj && mpSearchSpellTextObj->HasText() && !mpSearchSpellTextObj->IsEmptyPresObj() ) + { + SdrText* pText = mpSearchSpellTextObj->getText( maCurrentPosition.mnText ); + mpParaObj = pText ? pText->GetOutlinerParaObject() : nullptr; + + if (mpParaObj != nullptr) + { + SetText(*mpParaObj); + + ClearModifyFlag(); + } + } + else + { + mpSearchSpellTextObj = nullptr; + } +} + +void SdOutliner::PrepareSpellCheck() +{ + EESpellState eState = HasSpellErrors(); + DBG_ASSERT(eState != EESpellState::NoSpeller, "No SpellChecker"); + + if (eState == EESpellState::Ok) + return; + + // When spell checking we have to test whether we have processed the + // whole document and have reached the start page again. + if (meMode == SPELL) + { + if (maSearchStartPosition == sd::outliner::Iterator()) + // Remember the position of the first text object so that we + // know when we have processed the whole document. + maSearchStartPosition = maObjectIterator; + else if (maSearchStartPosition == maObjectIterator) + { + mbEndOfSearch = true; + } + } + + EnterEditMode( false ); +} + +void SdOutliner::PrepareSearchAndReplace() +{ + if (!HasText( *mpSearchItem )) + return; + + // Set the object now that we know it matches. + mpObj = SetObject(maCurrentPosition); + + mbStringFound = true; + mbMatchMayExist = true; + + EnterEditMode(false); + + mpDrawDocument->GetDocSh()->SetWaitCursor( false ); + // Start search at the right end of the current object's text + // depending on the search direction. + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView != nullptr) + pOutlinerView->SetSelection (GetSearchStartPosition ()); +} + +void SdOutliner::SetViewMode (PageKind ePageKind) +{ + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + std::shared_ptr<sd::DrawViewShell> pDrawViewShell( + std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell)); + if (pDrawViewShell == nullptr || ePageKind == pDrawViewShell->GetPageKind()) + return; + + // Restore old edit mode. + pDrawViewShell->ChangeEditMode(mpImpl->meOriginalEditMode, false); + + SetStatusEventHdl(Link<EditStatus&,void>()); + OUString sViewURL; + switch (ePageKind) + { + case PageKind::Standard: + default: + sViewURL = sd::framework::FrameworkHelper::msImpressViewURL; + break; + case PageKind::Notes: + sViewURL = sd::framework::FrameworkHelper::msNotesViewURL; + break; + case PageKind::Handout: + sViewURL = sd::framework::FrameworkHelper::msHandoutViewURL; + break; + } + // The text object iterator is destroyed when the shells are + // switched but we need it so save it and restore it afterwards. + sd::outliner::Iterator aIterator (maObjectIterator); + bool bMatchMayExist = mbMatchMayExist; + + sd::ViewShellBase& rBase = pViewShell->GetViewShellBase(); + + rtl::Reference<sd::FuSearch> xFuSearch; + if (pViewShell->GetView()) + xFuSearch = pViewShell->GetView()->getSearchContext().getFunctionSearch(); + + SetViewShell(std::shared_ptr<sd::ViewShell>()); + sd::framework::FrameworkHelper::Instance(rBase)->RequestView( + sViewURL, + sd::framework::FrameworkHelper::msCenterPaneURL); + + // Force (well, request) a synchronous update of the configuration. + // In a better world we would handle the asynchronous view update + // instead. But that would involve major restructuring of the + // Outliner code. + sd::framework::FrameworkHelper::Instance(rBase)->RequestSynchronousUpdate(); + + auto pNewViewShell = rBase.GetMainViewShell(); + SetViewShell(pNewViewShell); + if (xFuSearch.is() && pNewViewShell->GetView()) + pNewViewShell->GetView()->getSearchContext().setSearchFunction(xFuSearch); + + // Switching to another view shell has intermediatly called + // EndSpelling(). A PrepareSpelling() is pending, so call that now. + PrepareSpelling(); + + // Update the number of pages so that + // <member>DetectChange()</member> has the correct value to compare + // to. + mnPageCount = mpDrawDocument->GetSdPageCount(ePageKind); + + maObjectIterator = aIterator; + mbMatchMayExist = bMatchMayExist; + + // Save edit mode so that it can be restored when switching the view + // shell again. + pDrawViewShell = std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell); + OSL_ASSERT(pDrawViewShell != nullptr); + if (pDrawViewShell != nullptr) + mpImpl->meOriginalEditMode = pDrawViewShell->GetEditMode(); +} + +void SdOutliner::SetPage (EditMode eEditMode, sal_uInt16 nPageIndex) +{ + if ( ! mbRestrictSearchToSelection) + { + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + std::shared_ptr<sd::DrawViewShell> pDrawViewShell( + std::dynamic_pointer_cast<sd::DrawViewShell>(pViewShell)); + OSL_ASSERT(pDrawViewShell != nullptr); + if (pDrawViewShell != nullptr) + { + pDrawViewShell->ChangeEditMode(eEditMode, false); + pDrawViewShell->SwitchPage(nPageIndex); + } + } +} + +void SdOutliner::EnterEditMode (bool bGrabFocus) +{ + OutlinerView* pOutlinerView = getOutlinerView(); + if (!(pOutlinerView && mpSearchSpellTextObj)) + return; + + pOutlinerView->SetOutputArea( ::tools::Rectangle( Point(), Size(1, 1))); + SetPaperSize( mpSearchSpellTextObj->GetLogicRect().GetSize() ); + SdrPageView* pPV = mpView->GetSdrPageView(); + + // Make FuText the current function. + SfxUInt16Item aItem (SID_TEXTEDIT, 1); + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if (!(pViewShell && pViewShell->GetDispatcher())) + return; + + pViewShell->GetDispatcher()->ExecuteList( + SID_TEXTEDIT, SfxCallMode::SYNCHRON | SfxCallMode::RECORD, {&aItem}); + + if (mpView->IsTextEdit()) + { + // end text edition before starting it again + mpView->SdrEndTextEdit(); + } + + // To be consistent with the usual behaviour in the Office the text + // object that is put into edit mode would have also to be selected. + // Starting the text edit mode is not enough so we do it here by + // hand. + mpView->UnmarkAllObj(pPV); + mpView->MarkObj(mpSearchSpellTextObj, pPV); + + mpSearchSpellTextObj->setActiveText(mnText); + + // Turn on the edit mode for the text object. + SetUpdateLayout(true); + mpView->SdrBeginTextEdit(mpSearchSpellTextObj, pPV, mpWindow, true, this, + pOutlinerView, true, true, bGrabFocus); + + mbFoundObject = true; +} + +ESelection SdOutliner::GetSearchStartPosition() const +{ + ESelection aPosition; + if (mbDirectionIsForward) + { + // The default constructor uses the beginning of the text as default. + aPosition = ESelection (); + } + else + { + // Retrieve the position after the last character in the last + // paragraph. + sal_Int32 nParagraphCount = GetParagraphCount(); + if (nParagraphCount == 0) + aPosition = ESelection(); + else + { + sal_Int32 nLastParagraphLength = GetEditEngine().GetTextLen ( + nParagraphCount-1); + aPosition = ESelection (nParagraphCount-1, nLastParagraphLength); + } + } + + return aPosition; +} + +bool SdOutliner::HasNoPreviousMatch() +{ + OutlinerView* pOutlinerView = getOutlinerView(); + + DBG_ASSERT (pOutlinerView!=nullptr, "outline view in SdOutliner::HasNoPreviousMatch is NULL"); + + // Detect whether the cursor stands at the beginning + // resp. at the end of the text. + return pOutlinerView->GetSelection() == GetSearchStartPosition(); +} + +bool SdOutliner::HandleFailedSearch() +{ + bool bContinueSearch = false; + + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView && mpSearchItem) + { + // Detect whether there is/may be a prior match. If there is then + // ask the user whether to wrap around. Otherwise tell the user + // that there is no match. + if (HasNoPreviousMatch ()) + { + // No match found in the whole presentation. + SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound); + } + + else + { + // No further matches found. Ask the user whether to wrap + // around and start again. + bContinueSearch = ShowWrapAroundDialog(); + } + } + + return bContinueSearch; +} + +SdrObject* SdOutliner::SetObject ( + const sd::outliner::IteratorPosition& rPosition) +{ + SetViewMode (rPosition.mePageKind); + SetPage (rPosition.meEditMode, static_cast<sal_uInt16>(rPosition.mnPageIndex)); + mnText = rPosition.mnText; + return rPosition.mxObject.get().get(); +} + +void SdOutliner::SetViewShell (const std::shared_ptr<sd::ViewShell>& rpViewShell) +{ + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if (pViewShell == rpViewShell) + return; + + // Set the new view shell. + mpWeakViewShell = rpViewShell; + // When the outline view is not owned by us then we have to clear + // that pointer so that the current one for the new view shell will + // be used (in ProvideOutlinerView). + if (rpViewShell) + { + mpView = rpViewShell->GetView(); + + mpWindow = rpViewShell->GetActiveWindow(); + + mpImpl->ProvideOutlinerView(*this, rpViewShell, mpWindow); + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView != nullptr) + pOutlinerView->SetWindow(mpWindow); + } + else + { + mpView = nullptr; + mpWindow = nullptr; + } +} + +void SdOutliner::HandleChangedSelection() +{ + maMarkListCopy.clear(); + mbRestrictSearchToSelection = mpView->AreObjectsMarked(); + if (!mbRestrictSearchToSelection) + return; + + // Make a copy of the current mark list. + const SdrMarkList& rMarkList = mpView->GetMarkedObjectList(); + const size_t nCount = rMarkList.GetMarkCount(); + if (nCount > 0) + { + maMarkListCopy.clear(); + maMarkListCopy.reserve (nCount); + for (size_t i=0; i<nCount; ++i) + maMarkListCopy.emplace_back(rMarkList.GetMark(i)->GetMarkedSdrObj ()); + } + else + // No marked object. Is this case possible? + mbRestrictSearchToSelection = false; +} + +void SdOutliner::StartConversion( LanguageType nSourceLanguage, LanguageType nTargetLanguage, + const vcl::Font *pTargetFont, sal_Int32 nOptions, bool bIsInteractive ) +{ + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + bool bMultiDoc = nullptr != dynamic_cast< const sd::DrawViewShell *>( pViewShell.get() ); + + meMode = TEXT_CONVERSION; + mbDirectionIsForward = true; + mpSearchItem.reset(); + mnConversionLanguage = nSourceLanguage; + + BeginConversion(); + + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView != nullptr) + { + pOutlinerView->StartTextConversion( + GetMessageBoxParent(), + nSourceLanguage, + nTargetLanguage, + pTargetFont, + nOptions, + bIsInteractive, + bMultiDoc); + } + + EndConversion(); +} + +/** Prepare to do a text conversion on the current text object. This + includes putting it into edit mode. +*/ +void SdOutliner::PrepareConversion() +{ + SetUpdateLayout(true); + if( HasConvertibleTextPortion( mnConversionLanguage ) ) + { + SetUpdateLayout(false); + mbStringFound = true; + mbMatchMayExist = true; + + EnterEditMode(true); + + mpDrawDocument->GetDocSh()->SetWaitCursor( false ); + // Start search at the right end of the current object's text + // depending on the search direction. + } + else + { + SetUpdateLayout(false); + } +} + +void SdOutliner::BeginConversion() +{ + SetRefDevice( SD_MOD()->GetVirtualRefDevice() ); + + sd::ViewShellBase* pBase = getViewShellBase(); + if (pBase != nullptr) + SetViewShell (pBase->GetMainViewShell()); + + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if (pViewShell) + { + mbStringFound = false; + + // Supposed that we are not located at the very beginning/end of the + // document then there may be a match in the document prior/after + // the current position. + mbMatchMayExist = true; + + maObjectIterator = sd::outliner::Iterator(); + maSearchStartPosition = sd::outliner::Iterator(); + RememberStartPosition(); + + mpImpl->ProvideOutlinerView(*this, pViewShell, mpWindow); + + HandleChangedSelection (); + } + ClearModifyFlag(); +} + +void SdOutliner::EndConversion() +{ + EndSpelling(); +} + +bool SdOutliner::ConvertNextDocument() +{ + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if (dynamic_cast< const sd::OutlineViewShell *>( pViewShell.get() ) ) + return false; + + mpDrawDocument->GetDocSh()->SetWaitCursor( true ); + + Initialize ( true ); + + OutlinerView* pOutlinerView = getOutlinerView(); + if (pOutlinerView != nullptr) + { + mpWindow = pViewShell->GetActiveWindow(); + pOutlinerView->SetWindow(mpWindow); + } + ProvideNextTextObject (); + + mpDrawDocument->GetDocSh()->SetWaitCursor( false ); + ClearModifyFlag(); + + // for text conversion we automatically wrap around one + // time and stop at the start shape + if( mpFirstObj ) + { + if( (mnText == 0) && (mpFirstObj == mpObj) ) + return false; + } + else + { + mpFirstObj = mpObj; + } + + return !mbEndOfSearch; +} + +weld::Window* SdOutliner::GetMessageBoxParent() +{ + // We assume that the parent of the given message box is NULL, i.e. it is + // modal with respect to the top application window. However, this + // does not affect the search dialog. Therefore we have to lock it here + // while the message box is being shown. We also have to take into + // account that we are called during a spell check and the search dialog + // is not available. + weld::Window* pSearchDialog = nullptr; + SfxChildWindow* pChildWindow = nullptr; + switch (meMode) + { + case SEARCH: + if (SfxViewFrame* pViewFrm = SfxViewFrame::Current()) + pChildWindow = pViewFrm->GetChildWindow( + SvxSearchDialogWrapper::GetChildWindowId()); + break; + + case SPELL: + if (SfxViewFrame* pViewFrm = SfxViewFrame::Current()) + pChildWindow = pViewFrm->GetChildWindow( + sd::SpellDialogChildWindow::GetChildWindowId()); + break; + + case TEXT_CONVERSION: + // There should no messages boxes be displayed while doing the + // hangul hanja conversion. + break; + } + + if (pChildWindow != nullptr) + { + auto xController = pChildWindow->GetController(); + pSearchDialog = xController ? xController->getDialog() : nullptr; + } + + if (pSearchDialog) + return pSearchDialog; + + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + auto pWin = pViewShell->GetActiveWindow(); + return pWin ? pWin->GetFrameWeld() : nullptr; +} + +//===== SdOutliner::Implementation ============================================== + +SdOutliner::Implementation::Implementation() + : meOriginalEditMode(EditMode::Page), + mbOwnOutlineView(false), + mpOutlineView(nullptr) +{ +} + +SdOutliner::Implementation::~Implementation() +{ + if (mbOwnOutlineView && mpOutlineView!=nullptr) + { + mpOutlineView->SetWindow(nullptr); + delete mpOutlineView; + mpOutlineView = nullptr; + } +} + +/** We try to create a new OutlinerView only when there is none available, + either from an OutlinerViewShell or a previous call to + ProvideOutlinerView(). This is necessary to support the spell checker + which can not cope with exchanging the OutlinerView. +*/ +void SdOutliner::Implementation::ProvideOutlinerView ( + Outliner& rOutliner, + const std::shared_ptr<sd::ViewShell>& rpViewShell, + vcl::Window* pWindow) +{ + if (rpViewShell == nullptr) + return; + + switch (rpViewShell->GetShellType()) + { + case sd::ViewShell::ST_DRAW: + case sd::ViewShell::ST_IMPRESS: + case sd::ViewShell::ST_NOTES: + case sd::ViewShell::ST_HANDOUT: + { + // Create a new outline view to do the search on. + bool bInsert = false; + if (mpOutlineView != nullptr && !mbOwnOutlineView) + mpOutlineView = nullptr; + + if (mpOutlineView == nullptr || !rOutliner.GetEditEngine().HasView(&mpOutlineView->GetEditView())) + { + delete mpOutlineView; + mpOutlineView = new OutlinerView(&rOutliner, pWindow); + mbOwnOutlineView = true; + bInsert = true; + } + else + mpOutlineView->SetWindow(pWindow); + + EVControlBits nStat = mpOutlineView->GetControlWord(); + nStat &= ~EVControlBits::AUTOSCROLL; + mpOutlineView->SetControlWord(nStat); + + if (bInsert) + rOutliner.InsertView( mpOutlineView ); + + rOutliner.SetUpdateLayout(false); + mpOutlineView->SetOutputArea (::tools::Rectangle (Point(), Size(1, 1))); + rOutliner.SetPaperSize( Size(1, 1) ); + rOutliner.SetText(OUString(), rOutliner.GetParagraph(0)); + + meOriginalEditMode = + std::static_pointer_cast<sd::DrawViewShell>(rpViewShell)->GetEditMode(); + } + break; + + case sd::ViewShell::ST_OUTLINE: + { + if (mpOutlineView!=nullptr && mbOwnOutlineView) + delete mpOutlineView; + mpOutlineView = rOutliner.GetView(0); + mbOwnOutlineView = false; + } + break; + + default: + case sd::ViewShell::ST_NONE: + case sd::ViewShell::ST_PRESENTATION: + // Ignored + break; + } +} + +void SdOutliner::Implementation::ReleaseOutlinerView() +{ + if (mbOwnOutlineView) + { + OutlinerView* pView = mpOutlineView; + mpOutlineView = nullptr; + mbOwnOutlineView = false; + if (pView != nullptr) + { + pView->SetWindow(nullptr); + delete pView; + } + } + else + { + mpOutlineView = nullptr; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/OutlinerIterator.cxx b/sd/source/ui/view/OutlinerIterator.cxx new file mode 100644 index 0000000000..a7cd6cf66b --- /dev/null +++ b/sd/source/ui/view/OutlinerIterator.cxx @@ -0,0 +1,800 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <OutlinerIterator.hxx> +#include <OutlinerIteratorImpl.hxx> +#include <svx/svditer.hxx> +#include <tools/debug.hxx> +#include <osl/diagnose.h> +#include <Outliner.hxx> + +#include <drawdoc.hxx> +#include <DrawViewShell.hxx> +#include <sdpage.hxx> +#include <utility> + +namespace sd::outliner { + +//===== IteratorPosition ====================================================== + +IteratorPosition::IteratorPosition() +: mnText(0) +, mnPageIndex(-1) +, mePageKind(PageKind::Standard) +, meEditMode(EditMode::Page) +{ +} + +bool IteratorPosition::operator== (const IteratorPosition& aPosition) const +{ + return mxObject.get() == aPosition.mxObject.get() + && mnText == aPosition.mnText + && mnPageIndex == aPosition.mnPageIndex + && mePageKind == aPosition.mePageKind + && meEditMode == aPosition.meEditMode; +} + +//===== Iterator ============================================================== + +Iterator::Iterator() +{ +} + +Iterator::Iterator (const Iterator& rIterator) + : mxIterator(rIterator.mxIterator ? rIterator.mxIterator->Clone() : nullptr) +{ +} + +Iterator::Iterator(Iterator&& rIterator) noexcept + : mxIterator(std::move(rIterator.mxIterator)) +{ +} + +Iterator::Iterator (std::unique_ptr<IteratorImplBase> pObject) + : mxIterator(std::move(pObject)) +{ +} + +Iterator::~Iterator() +{ +} + +Iterator& Iterator::operator= (const Iterator& rIterator) +{ + if (this != &rIterator) + { + if (rIterator.mxIterator) + mxIterator.reset(rIterator.mxIterator->Clone()); + else + mxIterator.reset(); + } + return *this; +} + +Iterator& Iterator::operator=(Iterator&& rIterator) noexcept +{ + mxIterator = std::move(rIterator.mxIterator); + return *this; +} + +const IteratorPosition& Iterator::operator* () const +{ + DBG_ASSERT (mxIterator, "::sd::outliner::Iterator::operator* : missing implementation object"); + return mxIterator->GetPosition(); +} + +Iterator& Iterator::operator++ () +{ + if (mxIterator) + mxIterator->GotoNextText(); + return *this; +} + +bool Iterator::operator== (const Iterator& rIterator) const +{ + if (!mxIterator || !rIterator.mxIterator) + return mxIterator.get() == rIterator.mxIterator.get(); + else + return *mxIterator == *rIterator.mxIterator; +} + +bool Iterator::operator!= (const Iterator& rIterator) const +{ + return ! operator==(rIterator); +} + +void Iterator::Reverse() +{ + if (mxIterator) + mxIterator->Reverse(); +} + +//===== IteratorFactory ======================================================= + +OutlinerContainer::OutlinerContainer (SdOutliner* pOutliner) +: mpOutliner(pOutliner) +{ +} + +Iterator OutlinerContainer::begin() +{ + return CreateIterator (BEGIN); +} + +Iterator OutlinerContainer::end() +{ + return CreateIterator (END); +} + +Iterator OutlinerContainer::current() +{ + return CreateIterator (CURRENT); +} + +Iterator OutlinerContainer::CreateIterator (IteratorLocation aLocation) +{ + // Decide on certain features of the outliner which kind of iterator to + // use. + if (mpOutliner->mbRestrictSearchToSelection) + // There is a selection. Search only in this. + return CreateSelectionIterator ( + mpOutliner->maMarkListCopy, + mpOutliner->mpDrawDocument, + mpOutliner->mpWeakViewShell.lock(), + mpOutliner->mbDirectionIsForward, + aLocation); + else + // Search in the whole document. + return CreateDocumentIterator ( + mpOutliner->mpDrawDocument, + mpOutliner->mpWeakViewShell.lock(), + mpOutliner->mbDirectionIsForward, + aLocation); +} + +Iterator OutlinerContainer::CreateSelectionIterator ( + const ::std::vector<::unotools::WeakReference<SdrObject>>& rObjectList, + SdDrawDocument* pDocument, + const std::shared_ptr<ViewShell>& rpViewShell, + bool bDirectionIsForward, + IteratorLocation aLocation) +{ + OSL_ASSERT(rpViewShell); + + sal_Int32 nObjectIndex; + + if (bDirectionIsForward) + switch (aLocation) + { + case CURRENT: + case BEGIN: + default: + nObjectIndex = 0; + break; + case END: + nObjectIndex = rObjectList.size(); + break; + } + else + switch (aLocation) + { + case CURRENT: + case BEGIN: + default: + nObjectIndex = rObjectList.size()-1; + break; + case END: + nObjectIndex = -1; + break; + } + + return Iterator (std::make_unique<SelectionIteratorImpl> ( + rObjectList, nObjectIndex, pDocument, rpViewShell, bDirectionIsForward)); +} + +Iterator OutlinerContainer::CreateDocumentIterator ( + SdDrawDocument* pDocument, + const std::shared_ptr<ViewShell>& rpViewShell, + bool bDirectionIsForward, + IteratorLocation aLocation) +{ + OSL_ASSERT(rpViewShell); + + PageKind ePageKind; + EditMode eEditMode; + + switch (aLocation) + { + case BEGIN: + default: + if (bDirectionIsForward) + { + ePageKind = PageKind::Standard; + eEditMode = EditMode::Page; + } + else + { + ePageKind = PageKind::Handout; + eEditMode = EditMode::MasterPage; + } + break; + + case END: + if (bDirectionIsForward) + { + ePageKind = PageKind::Handout; + eEditMode = EditMode::MasterPage; + } + else + { + ePageKind = PageKind::Standard; + eEditMode = EditMode::Page; + } + break; + + case CURRENT: + const std::shared_ptr<DrawViewShell> pDrawViewShell( + std::dynamic_pointer_cast<DrawViewShell>(rpViewShell)); + if (pDrawViewShell) + { + ePageKind = pDrawViewShell->GetPageKind(); + eEditMode = pDrawViewShell->GetEditMode(); + } + else + { + ePageKind = PageKind::Standard; + eEditMode = EditMode::Page; + } + break; + } + + sal_Int32 nPageIndex = GetPageIndex (pDocument, rpViewShell, + ePageKind, eEditMode, bDirectionIsForward, aLocation); + + return Iterator ( + std::make_unique<DocumentIteratorImpl> (nPageIndex, ePageKind, eEditMode, + pDocument, rpViewShell, bDirectionIsForward)); +} + +sal_Int32 OutlinerContainer::GetPageIndex ( + SdDrawDocument const * pDocument, + const std::shared_ptr<ViewShell>& rpViewShell, + PageKind ePageKind, + EditMode eEditMode, + bool bDirectionIsForward, + IteratorLocation aLocation) +{ + OSL_ASSERT(rpViewShell); + + sal_Int32 nPageIndex; + sal_Int32 nPageCount; + + const std::shared_ptr<DrawViewShell> pDrawViewShell( + std::dynamic_pointer_cast<DrawViewShell>(rpViewShell)); + + switch (eEditMode) + { + case EditMode::Page: + nPageCount = pDocument->GetSdPageCount (ePageKind); + break; + case EditMode::MasterPage: + nPageCount = pDocument->GetMasterSdPageCount(ePageKind); + break; + default: + nPageCount = 0; + } + + switch (aLocation) + { + case CURRENT: + if (pDrawViewShell) + nPageIndex = pDrawViewShell->GetCurPagePos(); + else + { + const SdPage* pPage = rpViewShell->GetActualPage(); + if (pPage != nullptr) + nPageIndex = (pPage->GetPageNum()-1)/2; + else + nPageIndex = 0; + } + break; + + case BEGIN: + default: + if (bDirectionIsForward) + nPageIndex = 0; + else + nPageIndex = nPageCount-1; + break; + + case END: + if (bDirectionIsForward) + nPageIndex = nPageCount; + else + nPageIndex = -1; + break; + } + + return nPageIndex; +} + +//===== IteratorImplBase ==================================================== + +IteratorImplBase::IteratorImplBase(SdDrawDocument* pDocument, + const std::weak_ptr<ViewShell>& rpViewShellWeak, + bool bDirectionIsForward) +: mpDocument (pDocument) +, mpViewShellWeak (rpViewShellWeak) +, mbDirectionIsForward (bDirectionIsForward) +{ + std::shared_ptr<DrawViewShell> pDrawViewShell; + if ( ! mpViewShellWeak.expired()) + pDrawViewShell = std::dynamic_pointer_cast<DrawViewShell>(rpViewShellWeak.lock()); + + if (pDrawViewShell) + { + maPosition.mePageKind = pDrawViewShell->GetPageKind(); + maPosition.meEditMode = pDrawViewShell->GetEditMode(); + } + else + { + maPosition.mePageKind = PageKind::Standard; + maPosition.meEditMode = EditMode::Page; + } +} + +IteratorImplBase::IteratorImplBase( SdDrawDocument* pDocument, + std::weak_ptr<ViewShell> pViewShellWeak, + bool bDirectionIsForward, PageKind ePageKind, EditMode eEditMode) +: mpDocument (pDocument) +, mpViewShellWeak (std::move(pViewShellWeak)) +, mbDirectionIsForward (bDirectionIsForward) +{ + maPosition.mePageKind = ePageKind; + maPosition.meEditMode = eEditMode; +} + +IteratorImplBase::~IteratorImplBase() +{} + +bool IteratorImplBase::operator== (const IteratorImplBase& rIterator) const +{ + return maPosition == rIterator.maPosition; +} + +bool IteratorImplBase::IsEqualSelection(const IteratorImplBase& rIterator) const +{ + // When this method is executed instead of the ones from derived classes + // then the argument is of another type then the object itself. In this + // just compare the position objects. + return maPosition == rIterator.maPosition; +} + +const IteratorPosition& IteratorImplBase::GetPosition() +{ + return maPosition; +} + +IteratorImplBase* IteratorImplBase::Clone (IteratorImplBase* pObject) const +{ + if (pObject != nullptr) + { + pObject->maPosition = maPosition; + pObject->mpDocument = mpDocument; + pObject->mpViewShellWeak = mpViewShellWeak; + pObject->mbDirectionIsForward = mbDirectionIsForward; + } + return pObject; +} + +void IteratorImplBase::Reverse() +{ + mbDirectionIsForward = ! mbDirectionIsForward; +} + +//===== SelectionIteratorImpl =========================================== + +SelectionIteratorImpl::SelectionIteratorImpl ( + const ::std::vector<::unotools::WeakReference<SdrObject>>& rObjectList, + sal_Int32 nObjectIndex, + SdDrawDocument* pDocument, + const std::weak_ptr<ViewShell>& rpViewShellWeak, + bool bDirectionIsForward) + : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward), + mrObjectList(rObjectList), + mnObjectIndex(nObjectIndex) +{ +} + +SelectionIteratorImpl::~SelectionIteratorImpl() +{} + +IteratorImplBase* SelectionIteratorImpl::Clone (IteratorImplBase* pObject) const +{ + SelectionIteratorImpl* pIterator = static_cast<SelectionIteratorImpl*>(pObject); + if (pIterator == nullptr) + pIterator = new SelectionIteratorImpl ( + mrObjectList, mnObjectIndex, mpDocument, mpViewShellWeak, mbDirectionIsForward); + return pIterator; +} + +void SelectionIteratorImpl::GotoNextText() +{ + SdrTextObj* pTextObj = DynCastSdrTextObj( mrObjectList.at(mnObjectIndex).get().get() ); + if (mbDirectionIsForward) + { + if( pTextObj ) + { + ++maPosition.mnText; + if( maPosition.mnText >= pTextObj->getTextCount() ) + { + maPosition.mnText = 0; + ++mnObjectIndex; + } + } + else + { + ++mnObjectIndex; + } + } + else + { + if( pTextObj ) + { + --maPosition.mnText; + if( maPosition.mnText < 0 ) + { + maPosition.mnText = -1; + --mnObjectIndex; + } + } + else + { + --mnObjectIndex; + maPosition.mnText = -1; + } + + if( (maPosition.mnText == -1) && (mnObjectIndex >= 0) ) + { + pTextObj = DynCastSdrTextObj( mrObjectList.at(mnObjectIndex).get().get() ); + if( pTextObj ) + maPosition.mnText = pTextObj->getTextCount() - 1; + } + + if( maPosition.mnText == -1 ) + maPosition.mnText = 0; + } +} + +const IteratorPosition& SelectionIteratorImpl::GetPosition() +{ + maPosition.mxObject = mrObjectList.at(mnObjectIndex); + + return maPosition; +} + +bool SelectionIteratorImpl::operator== (const IteratorImplBase& rIterator) const +{ + return rIterator.IsEqualSelection(*this); +} + +bool SelectionIteratorImpl::IsEqualSelection(const IteratorImplBase& rIterator) const +{ + const SelectionIteratorImpl* pSelectionIterator = + static_cast<const SelectionIteratorImpl*>(&rIterator); + return mpDocument == pSelectionIterator->mpDocument + && mnObjectIndex == pSelectionIterator->mnObjectIndex; +} + +//===== ViewIteratorImpl ================================================ + +ViewIteratorImpl::ViewIteratorImpl ( + sal_Int32 nPageIndex, + SdDrawDocument* pDocument, + const std::weak_ptr<ViewShell>& rpViewShellWeak, + bool bDirectionIsForward) + : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward), + mbPageChangeOccurred(false), + mpPage(nullptr) +{ + SetPage (nPageIndex); +} + +ViewIteratorImpl::ViewIteratorImpl ( + sal_Int32 nPageIndex, + SdDrawDocument* pDocument, + const std::weak_ptr<ViewShell>& rpViewShellWeak, + bool bDirectionIsForward, + PageKind ePageKind, + EditMode eEditMode) + : IteratorImplBase (pDocument, rpViewShellWeak, bDirectionIsForward, ePageKind, eEditMode), + mbPageChangeOccurred(false), + mpPage(nullptr) +{ + SetPage (nPageIndex); +} + +ViewIteratorImpl::~ViewIteratorImpl() +{ +} + +IteratorImplBase* ViewIteratorImpl::Clone (IteratorImplBase* pObject) const +{ + + ViewIteratorImpl* pIterator = static_cast<ViewIteratorImpl*>(pObject); + if (pIterator == nullptr) + pIterator = new ViewIteratorImpl ( + maPosition.mnPageIndex, mpDocument, mpViewShellWeak, mbDirectionIsForward); + + IteratorImplBase::Clone (pObject); + + if (moObjectIterator) + { + pIterator->moObjectIterator.emplace(mpPage, SdrIterMode::DeepNoGroups, !mbDirectionIsForward); + + // No direct way to set the object iterator to the current object. + pIterator->maPosition.mxObject = nullptr; + while (pIterator->moObjectIterator->IsMore() && pIterator->maPosition.mxObject.get()!=maPosition.mxObject.get()) + pIterator->maPosition.mxObject = pIterator->moObjectIterator->Next(); + } + else + pIterator->moObjectIterator.reset(); + + return pIterator; +} + +void ViewIteratorImpl::GotoNextText() +{ + SdrTextObj* pTextObj = DynCastSdrTextObj( maPosition.mxObject.get().get() ); + if( pTextObj ) + { + if (mbDirectionIsForward) + { + ++maPosition.mnText; + if( maPosition.mnText < pTextObj->getTextCount() ) + return; + } + else + { + --maPosition.mnText; + if( maPosition.mnText >= 0 ) + return; + } + } + + if (moObjectIterator && moObjectIterator->IsMore()) + maPosition.mxObject = moObjectIterator->Next(); + else + maPosition.mxObject = nullptr; + + if (!maPosition.mxObject.get().is() ) + { + if (mbDirectionIsForward) + SetPage (maPosition.mnPageIndex+1); + else + SetPage (maPosition.mnPageIndex-1); + + if (mpPage != nullptr) + moObjectIterator.emplace( mpPage, SdrIterMode::DeepNoGroups, !mbDirectionIsForward ); + if (moObjectIterator && moObjectIterator->IsMore()) + maPosition.mxObject = moObjectIterator->Next(); + else + maPosition.mxObject = nullptr; + } + + maPosition.mnText = 0; + if( !mbDirectionIsForward && maPosition.mxObject.get().is() ) + { + pTextObj = DynCastSdrTextObj( maPosition.mxObject.get().get() ); + if( pTextObj ) + maPosition.mnText = pTextObj->getTextCount() - 1; + } +} + +void ViewIteratorImpl::SetPage (sal_Int32 nPageIndex) +{ + mbPageChangeOccurred = (maPosition.mnPageIndex!=nPageIndex); + if (mbPageChangeOccurred) + { + maPosition.mnPageIndex = nPageIndex; + + sal_Int32 nPageCount; + if (maPosition.meEditMode == EditMode::Page) + nPageCount = mpDocument->GetSdPageCount(maPosition.mePageKind); + else + nPageCount = mpDocument->GetMasterSdPageCount( + maPosition.mePageKind); + + // Get page pointer. Here we have three cases: regular pages, + // master pages and invalid page indices. The later ones are not + // errors but the effect of the iterator advancing to the next page + // and going past the last one. This dropping of the rim at the far + // side is detected here and has to be reacted to by the caller. + if (nPageIndex>=0 && nPageIndex < nPageCount) + { + if (maPosition.meEditMode == EditMode::Page) + mpPage = mpDocument->GetSdPage ( + static_cast<sal_uInt16>(nPageIndex), + maPosition.mePageKind); + else + mpPage = mpDocument->GetMasterSdPage ( + static_cast<sal_uInt16>(nPageIndex), + maPosition.mePageKind); + } + else + mpPage = nullptr; + } + + // Set up object list iterator. + if (mpPage != nullptr) + moObjectIterator.emplace(mpPage, SdrIterMode::DeepNoGroups, ! mbDirectionIsForward); + else + moObjectIterator.reset(); + + // Get object pointer. + if (moObjectIterator && moObjectIterator->IsMore()) + maPosition.mxObject = moObjectIterator->Next(); + else + maPosition.mxObject = nullptr; + + maPosition.mnText = 0; + if( !mbDirectionIsForward && maPosition.mxObject.get().is() ) + { + SdrTextObj* pTextObj = DynCastSdrTextObj( maPosition.mxObject.get().get() ); + if( pTextObj ) + maPosition.mnText = pTextObj->getTextCount() - 1; + } + +} + +void ViewIteratorImpl::Reverse() +{ + IteratorImplBase::Reverse (); + + // Create reversed object list iterator. + if (mpPage != nullptr) + moObjectIterator.emplace(mpPage, SdrIterMode::DeepNoGroups, ! mbDirectionIsForward); + else + moObjectIterator.reset(); + + // Move iterator to the current object. + ::unotools::WeakReference<SdrObject> xObject = std::move(maPosition.mxObject); + maPosition.mxObject = nullptr; + + if (!moObjectIterator) + return; + + while (moObjectIterator->IsMore() && maPosition.mxObject.get() != xObject.get()) + maPosition.mxObject = moObjectIterator->Next(); +} + +//===== DocumentIteratorImpl ============================================ + +DocumentIteratorImpl::DocumentIteratorImpl ( + sal_Int32 nPageIndex, + PageKind ePageKind, EditMode eEditMode, + SdDrawDocument* pDocument, + const std::weak_ptr<ViewShell>& rpViewShellWeak, + bool bDirectionIsForward) + : ViewIteratorImpl (nPageIndex, pDocument, rpViewShellWeak, bDirectionIsForward, + ePageKind, eEditMode) +{ + if (eEditMode == EditMode::Page) + mnPageCount = pDocument->GetSdPageCount (ePageKind); + else + mnPageCount = pDocument->GetMasterSdPageCount(ePageKind); +} + +DocumentIteratorImpl::~DocumentIteratorImpl() +{} + +IteratorImplBase* DocumentIteratorImpl::Clone (IteratorImplBase* pObject) const +{ + DocumentIteratorImpl* pIterator = static_cast<DocumentIteratorImpl*>(pObject); + if (pIterator == nullptr) + pIterator = new DocumentIteratorImpl ( + maPosition.mnPageIndex, maPosition.mePageKind, maPosition.meEditMode, + mpDocument, mpViewShellWeak, mbDirectionIsForward); + // Finish the cloning. + return ViewIteratorImpl::Clone (pIterator); +} + +void DocumentIteratorImpl::GotoNextText() +{ + bool bSetToOnePastLastPage = false; + bool bViewChanged = false; + + ViewIteratorImpl::GotoNextText(); + + if (mbDirectionIsForward) + { + if (maPosition.mnPageIndex >= mnPageCount) + { + // Switch to master page. + if (maPosition.meEditMode == EditMode::Page) + { + maPosition.meEditMode = EditMode::MasterPage; + SetPage (0); + } + + // Switch to next view mode. + else + { + if (maPosition.mePageKind == PageKind::Handout) + // Not really necessary but makes things more clear. + bSetToOnePastLastPage = true; + else + { + maPosition.meEditMode = EditMode::Page; + if (maPosition.mePageKind == PageKind::Standard) + maPosition.mePageKind = PageKind::Notes; + else if (maPosition.mePageKind == PageKind::Notes) + maPosition.mePageKind = PageKind::Handout; + SetPage (0); + } + } + bViewChanged = true; + } + } + else + if (maPosition.mnPageIndex < 0) + { + // Switch from master pages to draw pages. + if (maPosition.meEditMode == EditMode::MasterPage) + { + maPosition.meEditMode = EditMode::Page; + bSetToOnePastLastPage = true; + } + + // Switch to previous view mode. + else + { + if (maPosition.mePageKind == PageKind::Standard) + SetPage (-1); + else + { + maPosition.meEditMode = EditMode::MasterPage; + if (maPosition.mePageKind == PageKind::Handout) + maPosition.mePageKind = PageKind::Notes; + else if (maPosition.mePageKind == PageKind::Notes) + maPosition.mePageKind = PageKind::Standard; + bSetToOnePastLastPage = true; + } + } + bViewChanged = true; + } + + if (!bViewChanged) + return; + + // Get new page count; + sal_Int32 nPageCount; + if (maPosition.meEditMode == EditMode::Page) + nPageCount = mpDocument->GetSdPageCount (maPosition.mePageKind); + else + nPageCount = mpDocument->GetMasterSdPageCount(maPosition.mePageKind); + + // Now that we know the number of pages we can set the current page index. + if (bSetToOnePastLastPage) + SetPage (nPageCount); +} + +} // end of namespace ::sd::outliner + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/PresentationViewShellBase.cxx b/sd/source/ui/view/PresentationViewShellBase.cxx new file mode 100644 index 0000000000..525c0813d9 --- /dev/null +++ b/sd/source/ui/view/PresentationViewShellBase.cxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <PresentationViewShellBase.hxx> +#include <DrawDocShell.hxx> +#include <DrawController.hxx> +#include <framework/FrameworkHelper.hxx> +#include <framework/PresentationModule.hxx> + +#include <sfx2/viewfac.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XFrame.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd { + +class DrawDocShell; + + +// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a +// new PresentationViewShellBase object has been constructed. + +SfxViewFactory* PresentationViewShellBase::s_pFactory; +SfxViewShell* PresentationViewShellBase::CreateInstance ( + SfxViewFrame& _rFrame, SfxViewShell *pOldView) +{ + PresentationViewShellBase* pBase = + new PresentationViewShellBase(_rFrame, pOldView); + pBase->LateInit(framework::FrameworkHelper::msPresentationViewURL); + return pBase; +} +void PresentationViewShellBase::RegisterFactory( SfxInterfaceId nPrio ) +{ + s_pFactory = new SfxViewFactory( + &CreateInstance,nPrio,"FullScreenPresentation"); + InitFactory(); +} +void PresentationViewShellBase::InitFactory() +{ + SFX_VIEW_REGISTRATION(DrawDocShell); +} + +PresentationViewShellBase::PresentationViewShellBase ( + SfxViewFrame& _rFrame, + SfxViewShell* pOldShell) + : ViewShellBase (_rFrame, pOldShell) +{ + // Hide the automatic (non-context sensitive) tool bars. + Reference<beans::XPropertySet> xFrameSet ( + _rFrame.GetFrame().GetFrameInterface(), + UNO_QUERY); + if (xFrameSet.is()) + { + Reference<beans::XPropertySet> xLayouterSet(xFrameSet->getPropertyValue("LayoutManager"), UNO_QUERY); + if (xLayouterSet.is()) + { + xLayouterSet->setPropertyValue("AutomaticToolbars", Any(false)); + } + } +} + +PresentationViewShellBase::~PresentationViewShellBase() +{ +} + +void PresentationViewShellBase::InitializeFramework() +{ + rtl::Reference<sd::DrawController> xController (GetDrawController()); + sd::framework::PresentationModule::Initialize(xController); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/SlideSorterViewShellBase.cxx b/sd/source/ui/view/SlideSorterViewShellBase.cxx new file mode 100644 index 0000000000..3c5578e8a1 --- /dev/null +++ b/sd/source/ui/view/SlideSorterViewShellBase.cxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <SlideSorterViewShellBase.hxx> +#include <DrawDocShell.hxx> +#include <framework/FrameworkHelper.hxx> +#include <sfx2/viewfac.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> + +namespace sd { + +class DrawDocShell; + + +// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a +// new SlideSorterViewShellBase object has been constructed. + +SfxViewFactory* SlideSorterViewShellBase::s_pFactory; +SfxViewShell* SlideSorterViewShellBase::CreateInstance ( + SfxViewFrame& rFrame, SfxViewShell *pOldView) +{ + SlideSorterViewShellBase* pBase = new SlideSorterViewShellBase(rFrame, pOldView); + pBase->LateInit(framework::FrameworkHelper::msSlideSorterURL); + return pBase; +} + +void SlideSorterViewShellBase::RegisterFactory( SfxInterfaceId nPrio ) +{ + s_pFactory = new SfxViewFactory(&CreateInstance,nPrio,"SlideSorter"); + InitFactory(); +} + +void SlideSorterViewShellBase::InitFactory() +{ + SFX_VIEW_REGISTRATION(DrawDocShell); +} + +SlideSorterViewShellBase::SlideSorterViewShellBase ( + SfxViewFrame& _rFrame, + SfxViewShell* pOldShell) + : ImpressViewShellBase (_rFrame, pOldShell) +{ +} + +SlideSorterViewShellBase::~SlideSorterViewShellBase() +{ +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/ToolBarManager.cxx b/sd/source/ui/view/ToolBarManager.cxx new file mode 100644 index 0000000000..4be073bac6 --- /dev/null +++ b/sd/source/ui/view/ToolBarManager.cxx @@ -0,0 +1,1381 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ToolBarManager.hxx> + +#include <DrawViewShell.hxx> +#include <EventMultiplexer.hxx> +#include <ViewShellBase.hxx> +#include <ViewShellManager.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> + +#include <sal/log.hxx> +#include <osl/mutex.hxx> +#include <o3tl/deleter.hxx> +#include <o3tl/enumrange.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/notebookbar/SfxNotebookBar.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/toolbarids.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/eitem.hxx> +#include <svx/svxids.hrc> +#include <svx/extrusionbar.hxx> +#include <svx/fontworkbar.hxx> +#include <tools/debug.hxx> +#include <tools/link.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <osl/diagnose.h> + +#include <map> +#include <memory> +#include <string_view> +#include <vector> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace { + +using namespace sd; + +class ToolBarRules; + +/** Lock of the frame::XLayoutManager. +*/ +class LayouterLock +{ + Reference<frame::XLayoutManager> mxLayouter; +public: + explicit LayouterLock (const Reference<frame::XLayoutManager>& rxLayouter); + ~LayouterLock(); + bool is() const { return mxLayouter.is(); } +}; + +/** Store a list of tool bars for each of the tool bar groups. From + this the list of requested tool bars is built. +*/ +class ToolBarList +{ +public: + ToolBarList(); + + void ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup); + void AddToolBar (sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName); + bool RemoveToolBar (sd::ToolBarManager::ToolBarGroup eGroup, const OUString& rsName); + + void GetToolBarsToActivate (std::vector<OUString>& rToolBars) const; + void GetToolBarsToDeactivate (std::vector<OUString>& rToolBars) const; + + void MarkToolBarAsActive (const OUString& rsName); + void MarkToolBarAsNotActive (const OUString& rsName); + void MarkAllToolBarsAsNotActive(); + +private: + typedef ::std::map<sd::ToolBarManager::ToolBarGroup, std::vector<OUString> > Groups; + Groups maGroups; + std::vector<OUString> maActiveToolBars; + + void MakeRequestedToolBarList (std::vector<OUString>& rToolBars) const; +}; + +/** Manage tool bars that are implemented as sub shells of a view shell. + The typical procedure of updating the sub shells of a view shell is to + rebuild a list of sub shells that the caller would like to have active. + The methods ClearGroup() and AddShellId() allow the caller to do that. A + final call to UpdateShells() activates the requested shells that are not + active and deactivates the active shells that are not requested . + + This is done by maintaining two lists. One (the current list) + reflects the current state. The other (the requested list) contains the + currently requested shells. UpdateShells() makes the requested + list the current list and clears the current list. + + Each shell belongs to one group. Different groups can be modified + separately. +*/ +class ToolBarShellList +{ +public: + /** Create a new object with an empty current list and an empty + requested list. + */ + ToolBarShellList(); + + /** Remove all shells from a group. Calling this method should normally + not be necessary because after the construction or after a call to + UpdateShells() the requested list is empty. + @param eGroup + The group to clear. Shells in other groups are not modified. + */ + void ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup); + + /** Add a shell. When the specified shell has already been requested + for another group then it is moved to this group. + @param eGroup + The group to which to add the shell. + @param nId + The id of the shell to add. + */ + void AddShellId (sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nId); + + /** Releasing all shells means that the given ToolBarRules object is + informed that every shell managed by the called ToolBarShellList is + about to be removed and that the associated framework tool bars can + be removed as well. The caller still has to call UpdateShells(). + */ + void ReleaseAllShells (ToolBarRules& rRules); + + /** The requested list is made the current list by activating all + shells in the requested list and by deactivating the shells in the + current list that are not in the requested list. + @param pMainViewShell + The shells that are activated or deactivated are sub shells of + this view shell. + @param rManager + This ViewShellManager is used to activate or deactivate shells. + */ + void UpdateShells ( + const std::shared_ptr<ViewShell>& rpMainViewShell, + const std::shared_ptr<ViewShellManager>& rpManager); + +private: + class ShellDescriptor + {public: + ShellDescriptor (ShellId nId,sd::ToolBarManager::ToolBarGroup eGroup); + ShellId mnId; + sd::ToolBarManager::ToolBarGroup meGroup; + friend bool operator<(const ShellDescriptor& r1, const ShellDescriptor& r2) + { return r1.mnId < r2.mnId; } + }; + + /** The requested list of tool bar shells that will be active after the + next call to UpdateShells(). + */ + typedef ::std::set<ShellDescriptor> GroupedShellList; + GroupedShellList maNewList; + + /** The list of tool bar shells that are currently on the shell stack. + Using a GroupedShellList is not strictly necessary but it makes + things easier and does not waste too much memory. + */ + GroupedShellList maCurrentList; +}; + +/** This class concentrates the knowledge about when to show what tool bars + in one place. +*/ +class ToolBarRules +{ +public: + ToolBarRules ( + std::shared_ptr<ToolBarManager> pToolBarManager, + std::shared_ptr<ViewShellManager> pViewShellManager); + + /** This method calls MainViewShellChanged() and SelectionHasChanged() + for the current main view shell and its view. + */ + void Update (ViewShellBase const & rBase); + + /** Reset all tool bars in all groups and add tool bars and tool bar + shells to the ToolBarGroup::Permanent group for the specified ViewShell type. + */ + void MainViewShellChanged (ViewShell::ShellType nShellType); + + /** Reset all tool bars in all groups and add tool bars and tool bar + shells to the ToolBarGroup::Permanent group for the specified ViewShell. + */ + void MainViewShellChanged (const ViewShell& rMainViewShell); + + /** Reset all tool bars in the ToolBarGroup::Function group and add tool bars and tool bar + shells to this group for the current selection. + */ + void SelectionHasChanged ( + const ::sd::ViewShell& rViewShell, + const SdrView& rView); + + /** Add a tool bar for the specified tool bar shell. + */ + void SubShellAdded ( + ::sd::ToolBarManager::ToolBarGroup eGroup, + sd::ShellId nShellId); + + /** Remove a tool bar for the specified tool bar shell. + */ + void SubShellRemoved ( + ::sd::ToolBarManager::ToolBarGroup eGroup, + sd::ShellId nShellId); + +private: + std::shared_ptr<ToolBarManager> mpToolBarManager; + std::shared_ptr<ViewShellManager> mpViewShellManager; +}; + +} // end of anonymous namespace + +namespace sd { + +//===== ToolBarManager::Implementation ======================================== + +class ToolBarManager::Implementation +{ +public: + /** This constructor takes three arguments even though the + ToolBarManager could be taken from the ViewShellBase. This is so to + state explicitly which information has to be present when this + constructor is called. The ViewShellBase may not have been fully + initialized at this point and must not be asked for this values. + */ + Implementation ( + ViewShellBase& rBase, + std::shared_ptr<sd::tools::EventMultiplexer> pMultiplexer, + const std::shared_ptr<ViewShellManager>& rpViewShellManager, + const std::shared_ptr<ToolBarManager>& rpToolBarManager); + ~Implementation(); + + void SetValid (bool bValid); + + void ResetToolBars (ToolBarGroup eGroup); + void ResetAllToolBars(); + void AddToolBar (ToolBarGroup eGroup, const OUString& rsToolBarName); + void AddToolBarShell (ToolBarGroup eGroup, ShellId nToolBarId); + void RemoveToolBar (ToolBarGroup eGroup, const OUString& rsToolBarName); + + /** Release all tool bar shells and the associated framework tool bars. + Typically called when the main view shell is being replaced by + another, all tool bar shells are released. In that process the + shells are destroyed anyway and without calling this method they + would still be referenced. + */ + void ReleaseAllToolBarShells(); + + void ToolBarsDestroyed(); + + void RequestUpdate(); + + void PreUpdate(); + void PostUpdate(); + /** Tell the XLayoutManager about the tool bars that we would like to be + shown. + @param rpLayouterLock + This typically is the mpSynchronousLayouterLock that is used in + this method and that is either released at its end or assigned + to mpAsynchronousLock in order to be unlocked later. + */ + void Update (::std::unique_ptr<LayouterLock> pLayouterLock); + + class UpdateLockImplementation + { + public: + explicit UpdateLockImplementation (Implementation& rImplementation) + : mrImplementation(rImplementation) { mrImplementation.LockUpdate(); } + ~UpdateLockImplementation() { mrImplementation.UnlockUpdate(); } + private: + Implementation& mrImplementation; + }; + + void LockViewShellManager(); + void LockUpdate(); + void UnlockUpdate(); + + ToolBarRules& GetToolBarRules() { return maToolBarRules;} + +private: + mutable ::osl::Mutex maMutex; + ViewShellBase& mrBase; + std::shared_ptr<sd::tools::EventMultiplexer> mpEventMultiplexer; + bool mbIsValid; + ToolBarList maToolBarList; + ToolBarShellList maToolBarShellList; + Reference<frame::XLayoutManager> mxLayouter; + sal_Int32 mnLockCount; + bool mbPreUpdatePending; + bool mbPostUpdatePending; + /** The layouter locks manage the locking of the XLayoutManager. The + lock() and unlock() functions are not called directly because the + (final) unlocking is usually done asynchronously *after* the + list of requested toolbars is updated. + */ + ::std::unique_ptr<LayouterLock> mpSynchronousLayouterLock; + ::std::unique_ptr<LayouterLock> mpAsynchronousLayouterLock; + ::std::unique_ptr<ViewShellManager::UpdateLock, o3tl::default_delete<ViewShellManager::UpdateLock>> mpViewShellManagerLock; + ImplSVEvent * mnPendingUpdateCall; + ImplSVEvent * mnPendingSetValidCall; + ToolBarRules maToolBarRules; + + static OUString GetToolBarResourceName (std::u16string_view rsBaseName); + bool CheckPlugInMode (std::u16string_view rsName) const; + + DECL_LINK(UpdateCallback, void *, void); + DECL_LINK(EventMultiplexerCallback, sd::tools::EventMultiplexerEvent&, void); + DECL_LINK(SetValidCallback, void*, void); +}; + +//===== ToolBarManager ======================================================== + +std::shared_ptr<ToolBarManager> ToolBarManager::Create ( + ViewShellBase& rBase, + const std::shared_ptr<sd::tools::EventMultiplexer>& rpMultiplexer, + const std::shared_ptr<ViewShellManager>& rpViewShellManager) +{ + std::shared_ptr<ToolBarManager> pManager (new ToolBarManager()); + pManager->mpImpl.reset( + new Implementation(rBase,rpMultiplexer,rpViewShellManager,pManager)); + return pManager; +} + +ToolBarManager::ToolBarManager() +{ +} + +ToolBarManager::~ToolBarManager() +{ +} + +void ToolBarManager::Shutdown() +{ + if (mpImpl != nullptr) + mpImpl.reset(); +} + +void ToolBarManager::ResetToolBars (ToolBarGroup eGroup) +{ + if (mpImpl != nullptr) + { + UpdateLock aLock (shared_from_this()); + mpImpl->ResetToolBars(eGroup); + } +} + +void ToolBarManager::ResetAllToolBars() +{ + if (mpImpl != nullptr) + { + UpdateLock aLock (shared_from_this()); + mpImpl->ResetAllToolBars(); + } +} + +void ToolBarManager::AddToolBar ( + ToolBarGroup eGroup, + const OUString& rsToolBarName) +{ + if (mpImpl != nullptr) + { + UpdateLock aLock (shared_from_this()); + mpImpl->AddToolBar(eGroup,rsToolBarName); + } +} + +void ToolBarManager::AddToolBarShell ( + ToolBarGroup eGroup, + ShellId nToolBarId) +{ + if (mpImpl != nullptr) + { + UpdateLock aLock (shared_from_this()); + mpImpl->AddToolBarShell(eGroup,nToolBarId); + } +} + +void ToolBarManager::RemoveToolBar ( + ToolBarGroup eGroup, + const OUString& rsToolBarName) +{ + if (mpImpl != nullptr) + { + UpdateLock aLock (shared_from_this()); + mpImpl->RemoveToolBar(eGroup,rsToolBarName); + } +} + +void ToolBarManager::SetToolBar ( + ToolBarGroup eGroup, + const OUString& rsToolBarName) +{ + if (mpImpl != nullptr) + { + UpdateLock aLock (shared_from_this()); + mpImpl->ResetToolBars(eGroup); + mpImpl->AddToolBar(eGroup,rsToolBarName); + } +} + +void ToolBarManager::SetToolBarShell ( + ToolBarGroup eGroup, + ShellId nToolBarId) +{ + if (mpImpl != nullptr) + { + UpdateLock aLock (shared_from_this()); + mpImpl->ResetToolBars(eGroup); + mpImpl->AddToolBarShell(eGroup,nToolBarId); + } +} + +void ToolBarManager::PreUpdate() +{ + if (mpImpl != nullptr) + mpImpl->PreUpdate(); +} + +void ToolBarManager::RequestUpdate() +{ + if (mpImpl != nullptr) + mpImpl->RequestUpdate(); +} + +void ToolBarManager::LockViewShellManager() +{ + if (mpImpl != nullptr) + mpImpl->LockViewShellManager(); +} + +void ToolBarManager::LockUpdate() +{ + if (mpImpl != nullptr) + mpImpl->LockUpdate(); +} + +void ToolBarManager::UnlockUpdate() +{ + if (mpImpl != nullptr) + mpImpl->UnlockUpdate(); +} + +void ToolBarManager::MainViewShellChanged () +{ + if (mpImpl != nullptr) + { + mpImpl->ReleaseAllToolBarShells(); + mpImpl->GetToolBarRules().MainViewShellChanged(ViewShell::ST_NONE); + } +} + +void ToolBarManager::MainViewShellChanged (const ViewShell& rMainViewShell) +{ + if (mpImpl != nullptr) + { + mpImpl->ReleaseAllToolBarShells(); + mpImpl->GetToolBarRules().MainViewShellChanged(rMainViewShell); + } +} + +void ToolBarManager::SelectionHasChanged ( + const ViewShell& rViewShell, + const SdrView& rView) +{ + if (mpImpl != nullptr) + mpImpl->GetToolBarRules().SelectionHasChanged(rViewShell,rView); +} + +void ToolBarManager::ToolBarsDestroyed() +{ + if (mpImpl != nullptr) + mpImpl->ToolBarsDestroyed(); +} + +//===== ToolBarManager::Implementation ======================================= + +ToolBarManager::Implementation::Implementation ( + ViewShellBase& rBase, + std::shared_ptr<sd::tools::EventMultiplexer> pMultiplexer, + const std::shared_ptr<ViewShellManager>& rpViewShellManager, + const std::shared_ptr<ToolBarManager>& rpToolBarManager) + : mrBase(rBase), + mpEventMultiplexer(std::move(pMultiplexer)), + mbIsValid(false), + mnLockCount(0), + mbPreUpdatePending(false), + mbPostUpdatePending(false), + mnPendingUpdateCall(nullptr), + mnPendingSetValidCall(nullptr), + maToolBarRules(rpToolBarManager,rpViewShellManager) +{ + Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this,ToolBarManager::Implementation,EventMultiplexerCallback)); + mpEventMultiplexer->AddEventListener( aLink ); +} + +/** The order of statements is important. + First unregister listeners, which may post user events. + Then remove pending user events. +*/ +ToolBarManager::Implementation::~Implementation() +{ + // Unregister at broadcasters. + Link<tools::EventMultiplexerEvent&,void> aLink (LINK(this,ToolBarManager::Implementation,EventMultiplexerCallback)); + mpEventMultiplexer->RemoveEventListener(aLink); + + // Abort pending user calls. + if (mnPendingUpdateCall != nullptr) + Application::RemoveUserEvent(mnPendingUpdateCall); + if (mnPendingSetValidCall != nullptr) + Application::RemoveUserEvent(mnPendingSetValidCall); +} + +void ToolBarManager::Implementation::ToolBarsDestroyed() +{ + maToolBarList.MarkAllToolBarsAsNotActive(); +} + +void ToolBarManager::Implementation::SetValid (bool bValid) +{ + ::osl::MutexGuard aGuard(maMutex); + + if (mbIsValid == bValid) + return; + + UpdateLockImplementation aUpdateLock (*this); + + mbIsValid = bValid; + if (mbIsValid) + { + Reference<frame::XFrame> xFrame = mrBase.GetViewFrame().GetFrame().GetFrameInterface(); + try + { + Reference<beans::XPropertySet> xFrameProperties (xFrame, UNO_QUERY_THROW); + Any aValue (xFrameProperties->getPropertyValue("LayoutManager")); + aValue >>= mxLayouter; + // tdf#119997 if mpSynchronousLayouterLock was created before mxLayouter was + // set then update it now that its available + if (mpSynchronousLayouterLock && !mpSynchronousLayouterLock->is()) + mpSynchronousLayouterLock.reset(new LayouterLock(mxLayouter)); + } + catch (const RuntimeException&) + { + } + + GetToolBarRules().Update(mrBase); + } + else + { + ResetAllToolBars(); + mxLayouter = nullptr; + } +} + +void ToolBarManager::Implementation::ResetToolBars (ToolBarGroup eGroup) +{ + ::osl::MutexGuard aGuard(maMutex); + + maToolBarList.ClearGroup(eGroup); + maToolBarShellList.ClearGroup(eGroup); + + mbPreUpdatePending = true; +} + +void ToolBarManager::Implementation::ResetAllToolBars() +{ + SAL_INFO("sd.view", __func__ << ": resetting all tool bars"); + for (auto i : o3tl::enumrange<ToolBarGroup>()) + ResetToolBars(i); +} + +void ToolBarManager::Implementation::AddToolBar ( + ToolBarGroup eGroup, + const OUString& rsToolBarName) +{ + ::osl::MutexGuard aGuard(maMutex); + + if (CheckPlugInMode(rsToolBarName)) + { + maToolBarList.AddToolBar(eGroup,rsToolBarName); + + mbPostUpdatePending = true; + if (mnLockCount == 0) + PostUpdate(); + } +} + +void ToolBarManager::Implementation::RemoveToolBar ( + ToolBarGroup eGroup, + const OUString& rsToolBarName) +{ + ::osl::MutexGuard aGuard(maMutex); + + if (maToolBarList.RemoveToolBar(eGroup,rsToolBarName)) + { + mbPreUpdatePending = true; + if (mnLockCount == 0) + PreUpdate(); + } +} + +void ToolBarManager::Implementation::AddToolBarShell ( + ToolBarGroup eGroup, + ShellId nToolBarId) +{ + ViewShell* pMainViewShell = mrBase.GetMainViewShell().get(); + if (pMainViewShell != nullptr) + { + maToolBarShellList.AddShellId(eGroup,nToolBarId); + GetToolBarRules().SubShellAdded(eGroup, nToolBarId); + } +} + +void ToolBarManager::Implementation::ReleaseAllToolBarShells() +{ + maToolBarShellList.ReleaseAllShells(GetToolBarRules()); + maToolBarShellList.UpdateShells(mrBase.GetMainViewShell(), mrBase.GetViewShellManager()); +} + +void ToolBarManager::Implementation::RequestUpdate() +{ + if (mnPendingUpdateCall == nullptr) + { + mnPendingUpdateCall = Application::PostUserEvent( + LINK(this,ToolBarManager::Implementation,UpdateCallback)); + } +} + +void ToolBarManager::Implementation::PreUpdate() +{ + ::osl::MutexGuard aGuard(maMutex); + + if (!(mbIsValid + && mbPreUpdatePending + && mxLayouter.is())) + return; + + mbPreUpdatePending = false; + + SAL_INFO("sd.view", __func__ << ": ToolBarManager::PreUpdate ["); + + // Get the list of tool bars that are not used anymore and are to be + // deactivated. + std::vector<OUString> aToolBars; + maToolBarList.GetToolBarsToDeactivate(aToolBars); + + // Turn off the tool bars. + for (const auto& aToolBar : aToolBars) + { + OUString sFullName (GetToolBarResourceName(aToolBar)); + SAL_INFO("sd.view", __func__ << ": turning off tool bar " << sFullName); + mxLayouter->destroyElement(sFullName); + maToolBarList.MarkToolBarAsNotActive(aToolBar); + } + + SAL_INFO("sd.view", __func__ << ": ToolBarManager::PreUpdate ]"); +} + +void ToolBarManager::Implementation::PostUpdate() +{ + ::osl::MutexGuard aGuard(maMutex); + + if (!(mbIsValid + && mbPostUpdatePending + && mxLayouter.is())) + return; + + mbPostUpdatePending = false; + + // Create the list of requested tool bars. + std::vector<OUString> aToolBars; + maToolBarList.GetToolBarsToActivate(aToolBars); + + SAL_INFO("sd.view", __func__ << ": ToolBarManager::PostUpdate ["); + + // Turn on the tool bars that are visible in the new context. + for (const auto& aToolBar : aToolBars) + { + OUString sFullName (GetToolBarResourceName(aToolBar)); + SAL_INFO("sd.view", __func__ << ": turning on tool bar " << sFullName); + mxLayouter->requestElement(sFullName); + maToolBarList.MarkToolBarAsActive(aToolBar); + } + + SAL_INFO("sd.view", __func__ << ": ToolBarManager::PostUpdate ]"); +} + +void ToolBarManager::Implementation::LockViewShellManager() +{ + if (mpViewShellManagerLock == nullptr) + mpViewShellManagerLock.reset( + new ViewShellManager::UpdateLock(mrBase.GetViewShellManager())); +} + +void ToolBarManager::Implementation::LockUpdate() +{ + SAL_INFO("sd.view", __func__ << ": LockUpdate " << mnLockCount); + ::osl::MutexGuard aGuard(maMutex); + + DBG_ASSERT(mnLockCount<100, "ToolBarManager lock count unusually high"); + if (mnLockCount == 0) + { + OSL_ASSERT(mpSynchronousLayouterLock == nullptr); + + mpSynchronousLayouterLock.reset(new LayouterLock(mxLayouter)); + } + ++mnLockCount; +} + +void ToolBarManager::Implementation::UnlockUpdate() +{ + SAL_INFO("sd.view", __func__ << ": UnlockUpdate " << mnLockCount); + ::osl::MutexGuard aGuard(maMutex); + + OSL_ASSERT(mnLockCount>0); + --mnLockCount; + if (mnLockCount == 0) + { + Update(std::move(mpSynchronousLayouterLock)); + } +} + +void ToolBarManager::Implementation::Update ( + ::std::unique_ptr<LayouterLock> pLocalLayouterLock) +{ + // When the lock is released and there are pending changes to the set of + // tool bars then update this set now. + if (mnLockCount != 0) + return; + + // During creation of ViewShellBase we may have the situation that + // the controller has already been created and attached to the frame + // but that the ToolBarManager has not yet completed its + // initialization (by initializing the mxLayouter member.) We do + // this here so that we do not have to wait for the next Update() + // call to show the tool bars. + if (mnPendingSetValidCall != nullptr) + { + Application::RemoveUserEvent(mnPendingSetValidCall); + mnPendingSetValidCall = nullptr; + SetValid(true); + } + + if (mbIsValid && mxLayouter.is() && (mbPreUpdatePending || mbPostUpdatePending)) + { + // 1) Release UNO tool bars that are no longer used. Do this + // now so that they are not updated when the SFX shell stack is + // modified. + if (mbPreUpdatePending) + PreUpdate(); + + // 2) Update the requested shells that represent tool bar + // functionality. Those that are not used anymore are + // deactivated now. Those that are missing are activated in the + // next step together with the view shells. + if (mpViewShellManagerLock == nullptr) + mpViewShellManagerLock.reset( + new ViewShellManager::UpdateLock(mrBase.GetViewShellManager())); + maToolBarShellList.UpdateShells( + mrBase.GetMainViewShell(), + mrBase.GetViewShellManager()); + + // 3) Unlock the ViewShellManager::UpdateLock. This updates the + // shell stack. + mpViewShellManagerLock.reset(); + + // 4) Make the UNO tool bars visible. The outstanding call to + // PostUpdate() is done via PostUserEvent() so that it is + // guaranteed to be executed when the SFX shell stack has been + // updated (under the assumption that our lock to the + // ViewShellManager was the only one open. If that is not the + // case then all should still be well but not as fast.) + + // Note that the lock count may have been increased since + // entering this method. In that case one of the next + // UnlockUpdate() calls will post the UpdateCallback. + if (mnLockCount==0) + { + mpAsynchronousLayouterLock = std::move(pLocalLayouterLock); + if (mnPendingUpdateCall==nullptr) + { + mnPendingUpdateCall = Application::PostUserEvent( + LINK(this,ToolBarManager::Implementation,UpdateCallback)); + } + } + } + else + { + mpViewShellManagerLock.reset(); + pLocalLayouterLock.reset(); + } +} + +IMPL_LINK_NOARG(ToolBarManager::Implementation, UpdateCallback, void*, void) +{ + mnPendingUpdateCall = nullptr; + if (mnLockCount == 0) + { + if (mbPreUpdatePending) + PreUpdate(); + if (mbPostUpdatePending) + PostUpdate(); + if (mbIsValid && mxLayouter.is()) + mpAsynchronousLayouterLock.reset(); + } +} + +IMPL_LINK(ToolBarManager::Implementation,EventMultiplexerCallback, + sd::tools::EventMultiplexerEvent&, rEvent, void) +{ + SolarMutexGuard g; + switch (rEvent.meEventId) + { + case EventMultiplexerEventId::ControllerAttached: + if (mnPendingSetValidCall == nullptr) + mnPendingSetValidCall + = Application::PostUserEvent(LINK(this,Implementation,SetValidCallback)); + break; + + case EventMultiplexerEventId::ControllerDetached: + SetValid(false); + break; + + default: break; + } +} + +IMPL_LINK_NOARG(ToolBarManager::Implementation, SetValidCallback, void*, void) +{ + mnPendingSetValidCall = nullptr; + SetValid(true); +} + +OUString ToolBarManager::Implementation::GetToolBarResourceName ( + std::u16string_view rsBaseName) +{ + return OUString::Concat("private:resource/toolbar/") + rsBaseName; +} + +bool ToolBarManager::Implementation::CheckPlugInMode (std::u16string_view rsName) const +{ + bool bValid (false); + + // Determine the plug in mode. + bool bIsPlugInMode (false); + do + { + SfxObjectShell* pObjectShell = mrBase.GetObjectShell(); + if (pObjectShell == nullptr) + break; + + SfxMedium* pMedium = pObjectShell->GetMedium(); + if (pMedium == nullptr) + break; + + const SfxBoolItem* pViewOnlyItem = pMedium->GetItemSet().GetItem(SID_VIEWONLY, false); + if (pViewOnlyItem == nullptr) + break; + + bIsPlugInMode = pViewOnlyItem->GetValue(); + } + while (false); + + if (rsName == msViewerToolBar) + bValid = bIsPlugInMode; + else + bValid = ! bIsPlugInMode; + + return bValid; +} + +} // end of namespace sd + +namespace { + +using namespace ::sd; + +//===== LayouterLock ========================================================== + +LayouterLock::LayouterLock (const Reference<frame::XLayoutManager>& rxLayouter) + : mxLayouter(rxLayouter) +{ + SAL_INFO("sd.view", __func__ << ": LayouterLock " << (mxLayouter.is() ? 1 :0)); + if (mxLayouter.is()) + mxLayouter->lock(); +} + +LayouterLock::~LayouterLock() +{ + SAL_INFO("sd.view", __func__ << ": ~LayouterLock " << (mxLayouter.is() ? 1 :0)); + if (mxLayouter.is()) + mxLayouter->unlock(); +} + +//===== ToolBarRules ========================================================== + +ToolBarRules::ToolBarRules ( + std::shared_ptr<sd::ToolBarManager> pToolBarManager, + std::shared_ptr<sd::ViewShellManager> pViewShellManager) + : mpToolBarManager(std::move(pToolBarManager)), + mpViewShellManager(std::move(pViewShellManager)) +{ +} + +void ToolBarRules::Update (ViewShellBase const & rBase) +{ + ViewShell* pMainViewShell = rBase.GetMainViewShell().get(); + if (pMainViewShell != nullptr) + { + MainViewShellChanged(pMainViewShell->GetShellType()); + if (pMainViewShell->GetView()) + SelectionHasChanged (*pMainViewShell, *pMainViewShell->GetView()); + } + else + MainViewShellChanged(ViewShell::ST_NONE); +} + +void ToolBarRules::MainViewShellChanged (ViewShell::ShellType nShellType) +{ + ::sd::ToolBarManager::UpdateLock aToolBarManagerLock (mpToolBarManager); + ::sd::ViewShellManager::UpdateLock aViewShellManagerLock (mpViewShellManager); + + mpToolBarManager->ResetAllToolBars(); + + switch(nShellType) + { + case ::sd::ViewShell::ST_IMPRESS: + case ::sd::ViewShell::ST_NOTES: + case ::sd::ViewShell::ST_HANDOUT: + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msToolBar); + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msOptionsToolBar); + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msViewerToolBar); + break; + + case ::sd::ViewShell::ST_DRAW: + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msToolBar); + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msOptionsToolBar); + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msViewerToolBar); + break; + + case ViewShell::ST_OUTLINE: + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msOutlineToolBar); + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msViewerToolBar); + mpToolBarManager->AddToolBarShell( + ToolBarManager::ToolBarGroup::Permanent, ToolbarId::Draw_Text_Toolbox_Sd); + break; + + case ViewShell::ST_SLIDE_SORTER: + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msViewerToolBar); + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msSlideSorterToolBar); + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::Permanent, + ToolBarManager::msSlideSorterObjectBar); + break; + + case ViewShell::ST_NONE: + case ViewShell::ST_PRESENTATION: + case ViewShell::ST_SIDEBAR: + default: + break; + } +} + +void ToolBarRules::MainViewShellChanged (const ViewShell& rMainViewShell) +{ + ::sd::ToolBarManager::UpdateLock aToolBarManagerLock (mpToolBarManager); + ::sd::ViewShellManager::UpdateLock aViewShellManagerLock (mpViewShellManager); + + MainViewShellChanged(rMainViewShell.GetShellType()); + switch(rMainViewShell.GetShellType()) + { + case ::sd::ViewShell::ST_IMPRESS: + case ::sd::ViewShell::ST_DRAW: + case ::sd::ViewShell::ST_NOTES: + { + const DrawViewShell* pDrawViewShell + = dynamic_cast<const DrawViewShell*>(&rMainViewShell); + if (pDrawViewShell != nullptr) + { + if (pDrawViewShell->GetEditMode() == EditMode::MasterPage) + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::MasterMode, + ToolBarManager::msMasterViewToolBar); + else if ( rMainViewShell.GetShellType() != ::sd::ViewShell::ST_DRAW ) + mpToolBarManager->AddToolBar( + ToolBarManager::ToolBarGroup::CommonTask, + ToolBarManager::msCommonTaskToolBar); + } + break; + } + + default: + break; + } +} + +void ToolBarRules::SelectionHasChanged ( + const ::sd::ViewShell& rViewShell, + const SdrView& rView) +{ + ::sd::ToolBarManager::UpdateLock aLock (mpToolBarManager); + mpToolBarManager->LockViewShellManager(); + bool bTextEdit = rView.IsTextEdit(); + + mpToolBarManager->ResetToolBars(ToolBarManager::ToolBarGroup::Function); + + if (!sfx2::SfxNotebookBar::IsActive()) + { + switch (rView.GetContext()) + { + case SdrViewContext::Graphic: + if (!bTextEdit) + mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function, + ToolbarId::Draw_Graf_Toolbox); + break; + + case SdrViewContext::Media: + if (!bTextEdit) + mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function, + ToolbarId::Draw_Media_Toolbox); + break; + + case SdrViewContext::Table: + mpToolBarManager->SetToolBarShell(ToolBarManager::ToolBarGroup::Function, + ToolbarId::Draw_Table_Toolbox); + bTextEdit = true; + break; + + case SdrViewContext::Standard: + default: + if (!bTextEdit) + { + switch(rViewShell.GetShellType()) + { + case ::sd::ViewShell::ST_IMPRESS: + case ::sd::ViewShell::ST_DRAW: + case ::sd::ViewShell::ST_NOTES: + case ::sd::ViewShell::ST_HANDOUT: + mpToolBarManager->SetToolBar(ToolBarManager::ToolBarGroup::Function, + ToolBarManager::msDrawingObjectToolBar); + break; + default: + break; + } + break; + } + } + } + + if( bTextEdit ) + mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Draw_Text_Toolbox_Sd); + + SdrView* pView = &const_cast<SdrView&>(rView); + // Check if the extrusion tool bar and the fontwork tool bar have to + // be activated. + if (svx::checkForSelectedCustomShapes(pView, true /* bOnlyExtruded */ )) + mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Svx_Extrusion_Bar); + + if (svx::checkForSelectedFontWork(pView)) + mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Svx_Fontwork_Bar); + + // Switch on additional context-sensitive tool bars. + if (rView.GetContext() == SdrViewContext::PointEdit) + mpToolBarManager->AddToolBarShell(ToolBarManager::ToolBarGroup::Function, ToolbarId::Bezier_Toolbox_Sd); +} + +void ToolBarRules::SubShellAdded ( + ::sd::ToolBarManager::ToolBarGroup eGroup, + sd::ShellId nShellId) +{ + // For some tool bar shells (those defined in sd) we have to add the + // actual tool bar here. + switch (nShellId) + { + case ToolbarId::Draw_Graf_Toolbox: + mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msGraphicObjectBar); + break; + + case ToolbarId::Draw_Media_Toolbox: + mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msMediaObjectBar); + break; + + case ToolbarId::Draw_Text_Toolbox_Sd: + mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msTextObjectBar); + break; + + case ToolbarId::Bezier_Toolbox_Sd: + mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msBezierObjectBar); + break; + + case ToolbarId::Draw_Table_Toolbox: + // tdf#142489 Do not show the table toolbar when the Notebookbar UI is active + if (!sfx2::SfxNotebookBar::IsActive(true)) + mpToolBarManager->AddToolBar(eGroup, ToolBarManager::msTableObjectBar); + break; + + default: + break; + } +} + +void ToolBarRules::SubShellRemoved ( + ::sd::ToolBarManager::ToolBarGroup eGroup, + sd::ShellId nShellId) +{ + // For some tool bar shells (those defined in sd) we have to add the + // actual tool bar here. + switch (nShellId) + { + case ToolbarId::Draw_Graf_Toolbox: + mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msGraphicObjectBar); + break; + + case ToolbarId::Draw_Media_Toolbox: + mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msMediaObjectBar); + break; + + case ToolbarId::Draw_Text_Toolbox_Sd: + mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msTextObjectBar); + break; + + case ToolbarId::Bezier_Toolbox_Sd: + mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msBezierObjectBar); + break; + + case ToolbarId::Draw_Table_Toolbox: + mpToolBarManager->RemoveToolBar(eGroup, ToolBarManager::msTableObjectBar); + break; + + default: + break; + } +} + +//===== ToolBarList =========================================================== + +ToolBarList::ToolBarList() +{ +} + +void ToolBarList::ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup) +{ + Groups::iterator iGroup (maGroups.find(eGroup)); + if (iGroup != maGroups.end()) + { + iGroup->second.clear(); + } +} + +void ToolBarList::AddToolBar ( + sd::ToolBarManager::ToolBarGroup eGroup, + const OUString& rsName) +{ + Groups::iterator iGroup (maGroups.find(eGroup)); + if (iGroup == maGroups.end()) + iGroup = maGroups.emplace(eGroup,std::vector<OUString>()).first; + + if (iGroup != maGroups.end()) + { + auto iBar (std::find(iGroup->second.cbegin(),iGroup->second.cend(),rsName)); + if (iBar == iGroup->second.cend()) + { + iGroup->second.push_back(rsName); + } + } +} + +bool ToolBarList::RemoveToolBar ( + sd::ToolBarManager::ToolBarGroup eGroup, + const OUString& rsName) +{ + Groups::iterator iGroup (maGroups.find(eGroup)); + if (iGroup != maGroups.end()) + { + auto iBar (std::find(iGroup->second.begin(),iGroup->second.end(),rsName)); + if (iBar != iGroup->second.end()) + { + iGroup->second.erase(iBar); + return true; + } + } + return false; +} + +void ToolBarList::MakeRequestedToolBarList (std::vector<OUString>& rRequestedToolBars) const +{ + for (auto eGroup : o3tl::enumrange<sd::ToolBarManager::ToolBarGroup>()) + { + Groups::const_iterator iGroup (maGroups.find(eGroup)); + if (iGroup != maGroups.end()) + rRequestedToolBars.insert( rRequestedToolBars.end(), + iGroup->second.begin(), + iGroup->second.end() ); + } +} + +void ToolBarList::GetToolBarsToActivate (std::vector<OUString>& rToolBars) const +{ + std::vector<OUString> aRequestedToolBars; + MakeRequestedToolBarList(aRequestedToolBars); + + for (const auto& aToolBar : aRequestedToolBars) + { + if (::std::find(maActiveToolBars.begin(),maActiveToolBars.end(),aToolBar) + == maActiveToolBars.end()) + { + rToolBars.push_back(aToolBar); + } + } +} + +void ToolBarList::GetToolBarsToDeactivate (std::vector<OUString>& rToolBars) const +{ + std::vector<OUString> aRequestedToolBars; + MakeRequestedToolBarList(aRequestedToolBars); + + for (auto& aToolBar : maActiveToolBars) + { + if (::std::find(aRequestedToolBars.begin(),aRequestedToolBars.end(),aToolBar) + == aRequestedToolBars.end()) + { + rToolBars.push_back(aToolBar); + } + } +} + +void ToolBarList::MarkToolBarAsActive (const OUString& rsName) +{ + maActiveToolBars.push_back(rsName); +} + +void ToolBarList::MarkToolBarAsNotActive (const OUString& rsName) +{ + maActiveToolBars.erase( + ::std::find(maActiveToolBars.begin(),maActiveToolBars.end(), rsName)); +} + +void ToolBarList::MarkAllToolBarsAsNotActive() +{ + maActiveToolBars.clear(); +} + +//===== ToolBarShellList ====================================================== + +ToolBarShellList::ShellDescriptor::ShellDescriptor ( + ShellId nId, + sd::ToolBarManager::ToolBarGroup eGroup) + : mnId(nId), + meGroup(eGroup) +{ +} + +ToolBarShellList::ToolBarShellList() +{ +} + +void ToolBarShellList::ClearGroup (sd::ToolBarManager::ToolBarGroup eGroup) +{ + for (GroupedShellList::iterator iDescriptor = maNewList.begin(); iDescriptor != maNewList.end(); ) + if (iDescriptor->meGroup == eGroup) + iDescriptor = maNewList.erase(iDescriptor); + else + ++iDescriptor; +} + +void ToolBarShellList::AddShellId (sd::ToolBarManager::ToolBarGroup eGroup, sd::ShellId nId) +{ + // Make sure that the shell is not added twice (and possibly in + // different groups.) + ShellDescriptor aDescriptor (nId,eGroup); + GroupedShellList::iterator iDescriptor (maNewList.find(aDescriptor)); + if (iDescriptor != maNewList.end()) + { + // The shell is already requested. + if (iDescriptor->meGroup != eGroup) + { + // It is now being requested for another group. + // (Is this an error?) + // Move it to that group. + maNewList.erase(iDescriptor); + maNewList.insert(aDescriptor); + } + // else nothing to do. + } + else + maNewList.insert(aDescriptor); +} + +void ToolBarShellList::ReleaseAllShells (ToolBarRules& rRules) +{ + // Release the currently active tool bars. + GroupedShellList aList (maCurrentList); + for (const auto& rDescriptor : aList) + { + rRules.SubShellRemoved(rDescriptor.meGroup, rDescriptor.mnId); + } + + // Clear the list of requested tool bars. + maNewList.clear(); +} + +void ToolBarShellList::UpdateShells ( + const std::shared_ptr<ViewShell>& rpMainViewShell, + const std::shared_ptr<ViewShellManager>& rpManager) +{ + if (rpMainViewShell == nullptr) + return; + + GroupedShellList aList; + + // Deactivate shells that are in maCurrentList, but not in + // maNewList. + ::std::set_difference(maCurrentList.begin(), maCurrentList.end(), + maNewList.begin(), maNewList.end(), + std::insert_iterator<GroupedShellList>(aList,aList.begin())); + for (const auto& rShell : aList) + { + SAL_INFO("sd.view", __func__ << ": deactivating tool bar shell " << static_cast<sal_uInt32>(rShell.mnId)); + rpManager->DeactivateSubShell(*rpMainViewShell, rShell.mnId); + } + + // Activate shells that are in maNewList, but not in + // maCurrentList. + aList.clear(); + ::std::set_difference(maNewList.begin(), maNewList.end(), + maCurrentList.begin(), maCurrentList.end(), + std::insert_iterator<GroupedShellList>(aList,aList.begin())); + for (const auto& rShell : aList) + { + SAL_INFO("sd.view", __func__ << ": activating tool bar shell " << static_cast<sal_uInt32>(rShell.mnId)); + rpManager->ActivateSubShell(*rpMainViewShell, rShell.mnId); + } + + // The maNewList now reflects the current state and thus is made + // maCurrentList. + maCurrentList = maNewList; +} + +} // end of anonymous namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/ViewClipboard.cxx b/sd/source/ui/view/ViewClipboard.cxx new file mode 100644 index 0000000000..c17bf7de1f --- /dev/null +++ b/sd/source/ui/view/ViewClipboard.cxx @@ -0,0 +1,240 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ViewClipboard.hxx> + +#include <DrawDocShell.hxx> +#include <DrawViewShell.hxx> +#include <View.hxx> +#include <ViewShell.hxx> +#include <Window.hxx> + +#include <drawdoc.hxx> +#include <sdmod.hxx> +#include <sdpage.hxx> +#include <sdxfer.hxx> +#include <strings.hxx> + +#include <svx/svdpagv.hxx> +#include <vcl/svapp.hxx> + +namespace sd { + +ViewClipboard::ViewClipboard (::sd::View& rView) + : mrView(rView) +{ +} + +ViewClipboard::~ViewClipboard() +{ +} + +void ViewClipboard::HandlePageDrop (const SdTransferable& rTransferable) +{ + // Determine whether to insert the given set of slides or to assign a + // given master page. + // tdf#113405 only assign master pages to normal pages, don't attempt to assign a master + // page to a master page + sd::DrawViewShell* pDrawViewShell = dynamic_cast<::sd::DrawViewShell*>(mrView.GetViewShell()); + SdPage* pMasterPage = (pDrawViewShell && pDrawViewShell->GetEditMode() == EditMode::Page) ? GetFirstMasterPage(rTransferable) : nullptr; + if (pMasterPage) + AssignMasterPage (rTransferable, pMasterPage); + else + InsertSlides (rTransferable, DetermineInsertPosition ()); +} + +SdPage* ViewClipboard::GetFirstMasterPage (const SdTransferable& rTransferable) +{ + SdPage* pFirstMasterPage = nullptr; + + if (rTransferable.HasPageBookmarks()) + { + do + { + const std::vector<OUString> &rBookmarks = rTransferable.GetPageBookmarks(); + + if (rBookmarks.empty()) + break; + + DrawDocShell* pDocShell = rTransferable.GetPageDocShell(); + if (pDocShell == nullptr) + break; + + SdDrawDocument* pDocument = pDocShell->GetDoc(); + if (pDocument == nullptr) + break; + + for (const OUString& sName : rBookmarks) + { + bool bIsMasterPage; + + // SdPage* GetMasterSdPage(sal_uInt16 nPgNum, PageKind ePgKind); + // sal_uInt16 GetMasterSdPageCount(PageKind ePgKind) const; + + sal_uInt16 nBMPage = pDocument->GetPageByName ( + sName, bIsMasterPage); + if ( ! bIsMasterPage) + { + // At least one regular slide: return NULL to indicate + // that not all bookmarks point to master pages. + pFirstMasterPage = nullptr; + break; + } + else if (pFirstMasterPage == nullptr) + { + // Remember the first master page for later. + if (nBMPage != SDRPAGE_NOTFOUND) + pFirstMasterPage = static_cast<SdPage*>( + pDocument->GetMasterPage(nBMPage)); + } + } + } + while (false); + } + + return pFirstMasterPage; +} + +void ViewClipboard::AssignMasterPage ( + const SdTransferable& rTransferable, + SdPage const * pMasterPage) +{ + if (pMasterPage == nullptr) + return; + + // Get the target page to which the master page is assigned. + SdrPageView* pPageView = mrView.GetSdrPageView(); + if (pPageView == nullptr) + return; + + SdPage* pPage = static_cast<SdPage*>(pPageView->GetPage()); + if (pPage == nullptr) + return; + + SdDrawDocument& rDocument = mrView.GetDoc(); + + if ( ! rTransferable.HasPageBookmarks()) + return; + + DrawDocShell* pDataDocShell = rTransferable.GetPageDocShell(); + if (pDataDocShell == nullptr) + return; + + SdDrawDocument* pSourceDocument = pDataDocShell->GetDoc(); + if (pSourceDocument == nullptr) + return; + + // We have to remove the layout suffix from the layout name which is + // appended again by SetMasterPage() to the given name. Don't ask. + OUString sLayoutSuffix = SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE; + sal_Int32 nLength = sLayoutSuffix.getLength(); + OUString sLayoutName = pMasterPage->GetLayoutName(); + if (sLayoutName.endsWith(sLayoutSuffix)) + sLayoutName = sLayoutName.copy(0, sLayoutName.getLength() - nLength); + + rDocument.SetMasterPage ( + pPage->GetPageNum() / 2, + sLayoutName, + pSourceDocument, + false, // Exchange the master page of only the target page. + false // Keep unused master pages. + ); +} + +sal_uInt16 ViewClipboard::DetermineInsertPosition () +{ + SdDrawDocument& rDoc = mrView.GetDoc(); + sal_uInt16 nPgCnt = rDoc.GetSdPageCount( PageKind::Standard ); + + // Insert position is the behind the last selected page or behind the + // last page when the selection is empty. + sal_uInt16 nInsertPos = rDoc.GetSdPageCount( PageKind::Standard ) * 2 + 1; + for( sal_uInt16 nPage = 0; nPage < nPgCnt; nPage++ ) + { + SdPage* pPage = rDoc.GetSdPage( nPage, PageKind::Standard ); + + if( pPage->IsSelected() ) + nInsertPos = nPage * 2 + 3; + } + + return nInsertPos; +} + +sal_uInt16 ViewClipboard::InsertSlides ( + const SdTransferable& rTransferable, + sal_uInt16 nInsertPosition) +{ + SdDrawDocument& rDoc = mrView.GetDoc(); + + sal_uInt16 nInsertPgCnt = 0; + bool bMergeMasterPages = !rTransferable.HasSourceDoc( &rDoc ); + + // Prepare the insertion. + const std::vector<OUString> *pBookmarkList = nullptr; + DrawDocShell* pDataDocSh; + if (rTransferable.HasPageBookmarks()) + { + // When the transferable contains page bookmarks then the referenced + // pages are inserted. + pBookmarkList = &rTransferable.GetPageBookmarks(); + pDataDocSh = rTransferable.GetPageDocShell(); + nInsertPgCnt = static_cast<sal_uInt16>(pBookmarkList->size()); + } + else + { + // Otherwise all pages of the document of the transferable are + // inserted. + SfxObjectShell* pShell = rTransferable.GetDocShell().get(); + pDataDocSh = static_cast<DrawDocShell*>(pShell); + SdDrawDocument* pDataDoc = pDataDocSh->GetDoc(); + + if (pDataDoc!=nullptr && pDataDoc->GetSdPageCount(PageKind::Standard)) + nInsertPgCnt = pDataDoc->GetSdPageCount(PageKind::Standard); + } + if (nInsertPgCnt > 0) + { + const SolarMutexGuard aGuard; + ::sd::Window* pWin = mrView.GetViewShell()->GetActiveWindow(); + const bool bWait = pWin && pWin->IsWait(); + + if( bWait ) + pWin->LeaveWait(); + + rDoc.InsertBookmarkAsPage( + pBookmarkList ? *pBookmarkList : std::vector<OUString>(), + nullptr, + false, + false, + nInsertPosition, + (&rTransferable == SD_MOD()->pTransferDrag), + pDataDocSh, + true, + bMergeMasterPages, + false); + + if( bWait ) + pWin->EnterWait(); + } + + return nInsertPgCnt; +} + +} // end of namespace ::sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/ViewShellBase.cxx b/sd/source/ui/view/ViewShellBase.cxx new file mode 100644 index 0000000000..9e8e7b1aa5 --- /dev/null +++ b/sd/source/ui/view/ViewShellBase.cxx @@ -0,0 +1,1515 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <comphelper/processfactory.hxx> + +#include <ViewShellBase.hxx> +#include <algorithm> +#include <EventMultiplexer.hxx> +#include <cache/SlsPageCacheManager.hxx> +#include <app.hrc> +#include <slideshow.hxx> +#include <unokywds.hxx> +#include <svx/svxids.hrc> +#include <DrawDocShell.hxx> +#include <ViewShellManager.hxx> +#include <DrawController.hxx> +#include <FrameView.hxx> +#include <ViewTabBar.hxx> +#include <sfx2/event.hxx> +#include <drawdoc.hxx> +#include <sdpage.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/request.hxx> +#include <sfx2/printer.hxx> +#include <DrawViewShell.hxx> +#include <FormShellManager.hxx> +#include <ToolBarManager.hxx> +#include <Window.hxx> +#include <framework/ConfigurationController.hxx> +#include <DocumentRenderer.hxx> +#include <optsitem.hxx> +#include <sdmod.hxx> + +#include <com/sun/star/document/XViewDataSupplier.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XMasterPagesSupplier.hpp> +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/drawing/framework/XConfigurationController.hpp> +#include <com/sun/star/drawing/framework/ResourceId.hpp> +#include <framework/FrameworkHelper.hxx> + +#include <sal/log.hxx> +#include <rtl/ref.hxx> +#include <sfx2/msg.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/whiter.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +#include <sfx2/notebookbar/SfxNotebookBar.hxx> + +#include <comphelper/diagnose_ex.hxx> +#include <sfx2/lokhelper.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <editeng/editview.hxx> +#include <tools/svborder.hxx> +#include <o3tl/unreachable.hxx> + +#include <fubullet.hxx> +#include <drawview.hxx> + +using namespace sd; +#define ShellClass_ViewShellBase +#include <sdslots.hxx> + +using ::sd::framework::FrameworkHelper; + +using namespace com::sun::star; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::drawing::framework; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; + +namespace { + +class CurrentPageSetter +{ +public: + explicit CurrentPageSetter (ViewShellBase& rBase); + void operator () (bool); +private: + ViewShellBase& mrBase; +}; + +} // end of anonymous namespace + +namespace sd { + +class ViewShellBase::Implementation +{ +public: + /** Main controller of the view shell. During the switching from one + stacked shell to another this pointer may be NULL. + */ + ::rtl::Reference<DrawController> mpController; + + /** The view tab bar is the control for switching between different + views in one pane. + */ + ::rtl::Reference<ViewTabBar> mpViewTabBar; + + // contains the complete area of the current view relative to the frame window + ::tools::Rectangle maClientArea; + + // This is set to true when PrepareClose() is called. + bool mbIsClosing; + + /** The view window is the parent of all UI elements that belong to the + view or ViewShell. This comprises the rulers, the scroll bars, and + the content window. + It does not include the ViewTabBar. + */ + VclPtr<vcl::Window> mpViewWindow; + std::shared_ptr<ToolBarManager> mpToolBarManager; + std::shared_ptr<ViewShellManager> mpViewShellManager; + std::shared_ptr<tools::EventMultiplexer> mpEventMultiplexer; + std::shared_ptr<FormShellManager> mpFormShellManager; + + explicit Implementation (ViewShellBase& rBase); + ~Implementation(); + + void LateInit(); + + /** Show or hide the ViewTabBar. + @param bShow + When <TRUE/> then the ViewTabBar is shown, otherwise it is hidden. + */ + void ShowViewTabBar (bool bShow); + + void SetUserWantsTabBar(bool inValue); + bool GetUserWantsTabBar() const { return mbUserWantsTabBar; } + + /** Common code of ViewShellBase::OuterResizePixel() and + ViewShellBase::InnerResizePixel(). + */ + void ResizePixel ( + const Point& rOrigin, + const Size& rSize, + bool bOuterResize); + + /** Show or hide the specified pane. The visibility state is taken + from the given request. + @param rRequest + The request determines the new visibility state. The state can + either be toggled or be set to a given value. + @param rsPaneURL + This URL specifies the pane whose visibility state to set. + @param rsViewURL + When the pane becomes visible then this view URL specifies which + type of view to show in it. + */ + void SetPaneVisibility ( + const SfxRequest& rRequest, + const OUString& rsPaneURL, + const OUString& rsViewURL); + + void GetSlotState (SfxItemSet& rSet); + + void ProcessRestoreEditingViewSlot(); + +private: + ViewShellBase& mrBase; + bool mbUserWantsTabBar; + bool mbTabBarShouldBeVisible; + /** Hold a reference to the page cache manager of the slide sorter in + order to ensure that it stays alive while the ViewShellBase is + alive. + */ + std::shared_ptr<slidesorter::cache::PageCacheManager> mpPageCacheManager; +}; + +namespace { +/** The only task of this window is to forward key presses to the content + window of the main view shell. With the key press it forwards the focus + so that it is not called very often. +*/ +class FocusForwardingWindow : public vcl::Window +{ +public: + FocusForwardingWindow (vcl::Window& rParentWindow, ViewShellBase& rBase); + virtual ~FocusForwardingWindow() override; + virtual void dispose() override; + virtual void KeyInput (const KeyEvent& rEvent) override; + virtual void Command (const CommandEvent& rEvent) override; + +private: + ViewShellBase& mrBase; +}; +} // end of anonymous namespace + +//===== ViewShellBase ========================================================= + + +// We have to expand the SFX_IMPL_VIEWFACTORY macro to call LateInit() after a +// new ViewShellBase object has been constructed. + +SFX_IMPL_SUPERCLASS_INTERFACE(ViewShellBase, SfxViewShell) + +void ViewShellBase::InitInterface_Impl() +{ +} + +ViewShellBase::ViewShellBase ( + SfxViewFrame& _rFrame, + SfxViewShell*) + : SfxViewShell(_rFrame, SfxViewShellFlags::HAS_PRINTOPTIONS), + mpDocShell (nullptr), + mpDocument (nullptr) +{ + mpImpl.reset(new Implementation(*this)); + mpImpl->mpViewWindow = VclPtr<FocusForwardingWindow>::Create(_rFrame.GetWindow(),*this); + mpImpl->mpViewWindow->SetBackground(Wallpaper()); + + _rFrame.GetWindow().SetBackground(Application::GetSettings().GetStyleSettings().GetLightColor()); + + // Set up the members in the correct order. + if (auto pDrawDocShell = dynamic_cast< DrawDocShell *>( GetViewFrame().GetObjectShell() )) + mpDocShell = pDrawDocShell; + if (mpDocShell != nullptr) + mpDocument = mpDocShell->GetDoc(); + mpImpl->mpViewShellManager = std::make_shared<ViewShellManager>(*this); + + SetWindow(mpImpl->mpViewWindow.get()); + + // Hide the window to avoid complaints from Sfx...SwitchViewShell... + _rFrame.GetWindow().Hide(); +} + +/** In this destructor the order in which some of the members are destroyed + (and/or being prepared to being destroyed) is important. Change it only + when you know what you are doing. +*/ +ViewShellBase::~ViewShellBase() +{ + // Notify other LOK views that we are going away. + SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_VIEW_CURSOR_VISIBLE, "visible", "false"_ostr); + SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", ""_ostr); + SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY"_ostr); + + sfx2::SfxNotebookBar::CloseMethod(GetFrame()->GetBindings()); + + rtl::Reference<SlideShow> xSlideShow(SlideShow::GetSlideShow(*this)); + if (xSlideShow.is() && xSlideShow->dependsOn(this)) + SlideShow::Stop(*this); + xSlideShow.clear(); + + // Tell the controller that the ViewShellBase is not available anymore. + if (mpImpl->mpController) + mpImpl->mpController->ReleaseViewShellBase(); + + // We have to hide the main window to prevent SFX complaining after a + // reload about it being already visible. + ViewShell* pShell = GetMainViewShell().get(); + if (pShell!=nullptr + && pShell->GetActiveWindow()!=nullptr + && pShell->GetActiveWindow()->GetParent()!=nullptr) + { + pShell->GetActiveWindow()->GetParent()->Hide(); + } + + mpImpl->mpToolBarManager->Shutdown(); + mpImpl->mpViewShellManager->Shutdown(); + + EndListening(GetViewFrame()); + EndListening(*GetDocShell()); + + SetWindow(nullptr); + + mpImpl->mpFormShellManager.reset(); +} + +void ViewShellBase::LateInit (const OUString& rsDefaultView) +{ + StartListening(GetViewFrame(), DuplicateHandling::Prevent); + StartListening(*GetDocShell(), DuplicateHandling::Prevent); + mpImpl->LateInit(); + InitializeFramework(); + + mpImpl->mpEventMultiplexer = std::make_shared<tools::EventMultiplexer>(*this); + + mpImpl->mpFormShellManager = std::make_shared<FormShellManager>(*this); + + mpImpl->mpToolBarManager = ToolBarManager::Create( + *this, + mpImpl->mpEventMultiplexer, + mpImpl->mpViewShellManager); + + try + { + rtl::Reference<::sd::DrawController> xControllerManager (GetDrawController()); + Reference<XConfigurationController> xConfigurationController; + if (xControllerManager) + xConfigurationController = xControllerManager->getConfigurationController(); + if (xConfigurationController.is()) + { + OUString sView (rsDefaultView); + if (sView.isEmpty()) + sView = GetInitialViewShellType(); + + FrameworkHelper::Instance(*this); + + // Create the resource ids for the center pane and view. + const Reference<drawing::framework::XResourceId> xCenterPaneId ( + FrameworkHelper::CreateResourceId(FrameworkHelper::msCenterPaneURL)); + const Reference<drawing::framework::XResourceId> xCenterViewId ( + FrameworkHelper::CreateResourceId(sView, xCenterPaneId)); + + // Request center pane and view. + xConfigurationController->requestResourceActivation(xCenterPaneId, ResourceActivationMode_ADD); + xConfigurationController->requestResourceActivation(xCenterViewId, ResourceActivationMode_REPLACE); + + // Process configuration events synchronously until the center view + // has been created. + sd::framework::ConfigurationController* pConfigurationController + = dynamic_cast<sd::framework::ConfigurationController*>(xConfigurationController.get()); + if (pConfigurationController != nullptr) + { + while ( + ! pConfigurationController->getResource(xCenterViewId).is() + && pConfigurationController->hasPendingRequests()) + { + pConfigurationController->ProcessEvent(); + } + } + } + } + catch (const RuntimeException&) + { + } + + // AutoLayouts have to be ready. + GetDocument()->StopWorkStartupDelay(); + + UpdateBorder(); + + // Remember the type of the current main view shell in the frame view. + ViewShell* pViewShell = GetMainViewShell().get(); + if (pViewShell != nullptr) + { + FrameView* pFrameView = pViewShell->GetFrameView(); + if (pFrameView != nullptr) + pFrameView->SetViewShellTypeOnLoad(pViewShell->GetShellType()); + } + // Show/Hide the TabBar + SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDocument()->GetDocumentType()); + bool bIsTabBarVisible = pOptions->IsTabBarVisible(); + mpImpl->SetUserWantsTabBar( bIsTabBarVisible ); +} + +std::shared_ptr<ViewShellManager> const & ViewShellBase::GetViewShellManager() const +{ + return mpImpl->mpViewShellManager; +} + +std::shared_ptr<ViewShell> ViewShellBase::GetMainViewShell() const +{ + std::shared_ptr<ViewShell> pMainViewShell ( + framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this)) + ->GetViewShell(framework::FrameworkHelper::msCenterPaneURL)); + if (pMainViewShell == nullptr) + pMainViewShell = framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this)) + ->GetViewShell(framework::FrameworkHelper::msFullScreenPaneURL); + return pMainViewShell; +} + +ViewShellBase* ViewShellBase::GetViewShellBase (SfxViewFrame const * pViewFrame) +{ + ViewShellBase* pBase = nullptr; + + if (pViewFrame != nullptr) + { + // Get the view shell for the frame and cast it to + // sd::ViewShellBase. + SfxViewShell* pSfxViewShell = pViewFrame->GetViewShell(); + pBase = dynamic_cast< ::sd::ViewShellBase *>( pSfxViewShell ); + } + + return pBase; +} + +void ViewShellBase::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) +{ + SfxViewShell::Notify(rBC, rHint); + + const SfxHintId nHintId = rHint.GetId(); + + if (nHintId == SfxHintId::ThisIsAnSfxEventHint) + { + switch (static_cast<const SfxEventHint&>(rHint).GetEventId()) + { + case SfxEventHintId::OpenDoc: + if( GetDocument() && GetDocument()->IsStartWithPresentation() ) + { + GetViewFrame().GetDispatcher()->Execute( + SID_PRESENTATION, SfxCallMode::ASYNCHRON ); + } + break; + + default: + break; + } + } + else + { + switch (nHintId) + { + case SfxHintId::LanguageChanged: + { + GetViewFrame().GetBindings().Invalidate(SID_LANGUAGE_STATUS); + } + break; + + default: + break; + } + } +} + +void ViewShellBase::InitializeFramework() +{ +} + +OUString ViewShellBase::GetSelectionText(bool bCompleteWords, bool /*bOnlyASample*/) +{ + std::shared_ptr<ViewShell> const pMainShell(GetMainViewShell()); + DrawViewShell *const pDrawViewShell( + dynamic_cast<DrawViewShell*>(pMainShell.get())); + return pDrawViewShell + ? pDrawViewShell->GetSelectionText(bCompleteWords) + : SfxViewShell::GetSelectionText(bCompleteWords); +} + +bool ViewShellBase::HasSelection(bool bText) const +{ + std::shared_ptr<ViewShell> const pMainShell(GetMainViewShell()); + DrawViewShell *const pDrawViewShell( + dynamic_cast<DrawViewShell*>(pMainShell.get())); + return pDrawViewShell + ? pDrawViewShell->HasSelection(bText) + : SfxViewShell::HasSelection(bText); +} + +void ViewShellBase::InnerResizePixel (const Point& rOrigin, const Size &rSize, bool) +{ + Size aObjSize = GetObjectShell()->GetVisArea().GetSize(); + if ( !aObjSize.IsEmpty() ) + { + SvBorder aBorder( GetBorderPixel() ); + Size aSize( rSize ); + aSize.AdjustWidth( -(aBorder.Left() + aBorder.Right()) ); + aSize.AdjustHeight( -(aBorder.Top() + aBorder.Bottom()) ); + Size aObjSizePixel = mpImpl->mpViewWindow->LogicToPixel(aObjSize, MapMode(MapUnit::Map100thMM)); + SfxViewShell::SetZoomFactor( + Fraction( aSize.Width(), std::max( aObjSizePixel.Width(), static_cast<::tools::Long>(1) ) ), + Fraction( aSize.Height(), std::max( aObjSizePixel.Height(), static_cast<::tools::Long>(1)) ) ); + } + + mpImpl->ResizePixel(rOrigin, rSize, false); +} + +void ViewShellBase::OuterResizePixel (const Point& rOrigin, const Size &rSize) +{ + mpImpl->ResizePixel (rOrigin, rSize, true); +} + +void ViewShellBase::Rearrange() +{ + // There is a bug in the communication between embedded objects and the + // framework::LayoutManager that leads to missing resize updates. The + // following workaround enforces such an update by cycling the border to + // zero and back to the current value. + if (GetWindow() != nullptr) + { + SetBorderPixel(SvBorder()); + UpdateBorder(true); + } + else + { + SAL_WARN("sd.view", "Rearrange: window missing"); + } + + GetViewFrame().Resize(true); +} + +ErrCode ViewShellBase::DoVerb(sal_Int32 nVerb) +{ + ErrCode aResult = ERRCODE_NONE; + + ::sd::ViewShell* pShell = GetMainViewShell().get(); + if (pShell != nullptr) + aResult = pShell->DoVerb(nVerb); + + return aResult; +} + +Reference<view::XRenderable> ViewShellBase::GetRenderable() +{ + // Create a new DocumentRenderer on every call. It observes the life + // time of this ViewShellBase object. + return Reference<view::XRenderable>(new DocumentRenderer(*this)); +} + +SfxPrinter* ViewShellBase::GetPrinter (bool bCreate) +{ + OSL_ASSERT(mpImpl != nullptr); + + return GetDocShell()->GetPrinter (bCreate); +} + +sal_uInt16 ViewShellBase::SetPrinter ( + SfxPrinter* pNewPrinter, + SfxPrinterChangeFlags nDiffFlags) +{ + OSL_ASSERT(mpImpl != nullptr); + + GetDocShell()->SetPrinter(pNewPrinter); + + if ( (nDiffFlags & SfxPrinterChangeFlags::CHG_ORIENTATION || + nDiffFlags & SfxPrinterChangeFlags::CHG_SIZE) && pNewPrinter ) + { + MapMode aMap = pNewPrinter->GetMapMode(); + aMap.SetMapUnit(MapUnit::Map100thMM); + MapMode aOldMap = pNewPrinter->GetMapMode(); + pNewPrinter->SetMapMode(aMap); + Size aNewSize = pNewPrinter->GetOutputSize(); + + std::shared_ptr<DrawViewShell> pDrawViewShell ( + std::dynamic_pointer_cast<DrawViewShell>(GetMainViewShell())); + if (pDrawViewShell) + { + SdPage* pPage = GetDocument()->GetSdPage( + 0, PageKind::Standard ); + pDrawViewShell->SetPageSizeAndBorder ( + pDrawViewShell->GetPageKind(), + aNewSize, + -1,-1,-1,-1, + false/*bScaleAll*/, + pNewPrinter->GetOrientation(), + pPage->GetPaperBin(), + pPage->IsBackgroundFullSize()); + } + + pNewPrinter->SetMapMode(aOldMap); + } + + return 0; +} + +void ViewShellBase::UIActivating( SfxInPlaceClient* pClient ) +{ + mpImpl->ShowViewTabBar(false); + + ViewShell* pViewShell = GetMainViewShell().get(); + if ( pViewShell ) + pViewShell->UIActivating( pClient ); + + SfxViewShell::UIActivating( pClient ); +} + +void ViewShellBase::UIDeactivated( SfxInPlaceClient* pClient ) +{ + SfxViewShell::UIDeactivated( pClient ); + + mpImpl->ShowViewTabBar(true); + + ViewShell* pViewShell = GetMainViewShell().get(); + if ( pViewShell ) + pViewShell->UIDeactivated( pClient ); +} + +SvBorder ViewShellBase::GetBorder (bool ) +{ + int nTop = 0; + if (mpImpl->mpViewTabBar.is() && mpImpl->mpViewTabBar->GetTabControl()->IsVisible()) + nTop = mpImpl->mpViewTabBar->GetHeight(); + return SvBorder(0,nTop,0,0); +} + +void ViewShellBase::Execute (SfxRequest& rRequest) +{ + sal_uInt16 nSlotId = rRequest.GetSlot(); + + switch (nSlotId) + { + case SID_SWITCH_SHELL: + { + Reference<XControllerManager> xControllerManager (GetController(), UNO_QUERY); + if (xControllerManager.is()) + { + Reference<XConfigurationController> xConfigurationController ( + xControllerManager->getConfigurationController()); + if (xConfigurationController.is()) + xConfigurationController->update(); + } + } + break; + + case SID_LEFT_PANE_DRAW: + mpImpl->SetPaneVisibility( + rRequest, + framework::FrameworkHelper::msLeftDrawPaneURL, + framework::FrameworkHelper::msSlideSorterURL); + break; + + case SID_LEFT_PANE_IMPRESS: + mpImpl->SetPaneVisibility( + rRequest, + framework::FrameworkHelper::msLeftImpressPaneURL, + framework::FrameworkHelper::msSlideSorterURL); + break; + + case SID_TOGGLE_TABBAR_VISIBILITY: + { + SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDocument()->GetDocumentType()); + bool bIsTabBarVisible = pOptions->IsTabBarVisible(); + pOptions->SetTabBarVisible( !bIsTabBarVisible ); + mpImpl->SetUserWantsTabBar( !bIsTabBarVisible ); + rRequest.Done(); + } + break; + + // draw + case SID_DRAWINGMODE: + // impress normal + case SID_NORMAL_MULTI_PANE_GUI: + case SID_NOTES_MODE: + case SID_OUTLINE_MODE: + case SID_SLIDE_SORTER_MULTI_PANE_GUI: + case SID_SLIDE_SORTER_MODE: + // impress master + case SID_SLIDE_MASTER_MODE: + case SID_NOTES_MASTER_MODE: + case SID_HANDOUT_MASTER_MODE: + framework::FrameworkHelper::Instance(*this)->HandleModeChangeSlot(nSlotId, rRequest); + break; + + case SID_WIN_FULLSCREEN: + // The full screen mode is not supported. Ignore the request. + break; + + case SID_RESTORE_EDITING_VIEW: + mpImpl->ProcessRestoreEditingViewSlot(); + break; + + default: + // Ignore any other slot. + rRequest.Ignore (); + break; + } +} + +void ViewShellBase::GetState (SfxItemSet& rSet) +{ + mpImpl->GetSlotState(rSet); + + FuBullet::GetSlotState( rSet, nullptr, &GetViewFrame() ); +} + +void ViewShellBase::WriteUserDataSequence ( + css::uno::Sequence< css::beans::PropertyValue >& rSequence) +{ + // Forward call to main sub shell. + ViewShell* pShell = GetMainViewShell().get(); + if (pShell != nullptr) + pShell->WriteUserDataSequence (rSequence); +} + +void ViewShellBase::ReadUserDataSequence ( + const css::uno::Sequence< css::beans::PropertyValue >& rSequence) +{ + // Forward call to main sub shell. + ViewShell* pShell = GetMainViewShell().get(); + if (pShell == nullptr) + return; + + pShell->ReadUserDataSequence (rSequence); + + // For certain shell types ReadUserDataSequence may have changed the + // type to another one. Make sure that the center pane shows the + // right view shell. + switch (pShell->GetShellType()) + { + case ViewShell::ST_IMPRESS: + case ViewShell::ST_NOTES: + case ViewShell::ST_HANDOUT: + { + OUString sViewURL; + switch (dynamic_cast<DrawViewShell&>(*pShell).GetPageKind()) + { + default: + case PageKind::Standard: + sViewURL = framework::FrameworkHelper::msImpressViewURL; + break; + case PageKind::Notes: + sViewURL = framework::FrameworkHelper::msNotesViewURL; + break; + case PageKind::Handout: + sViewURL = framework::FrameworkHelper::msHandoutViewURL; + break; + } + if (!sViewURL.isEmpty()) + framework::FrameworkHelper::Instance(*this)->RequestView( + sViewURL, + framework::FrameworkHelper::msCenterPaneURL); + } + break; + + default: + break; + } +} + +void ViewShellBase::Activate (bool bIsMDIActivate) +{ + SfxViewShell::Activate(bIsMDIActivate); + + Reference<XControllerManager> xControllerManager (GetController(), UNO_QUERY); + if (xControllerManager.is()) + { + Reference<XConfigurationController> xConfigurationController ( + xControllerManager->getConfigurationController()); + if (xConfigurationController.is()) + xConfigurationController->update(); + } + GetToolBarManager()->RequestUpdate(); +} + +void ViewShellBase::SetZoomFactor ( + const Fraction &rZoomX, + const Fraction &rZoomY) +{ + SfxViewShell::SetZoomFactor (rZoomX, rZoomY); + // Forward call to main sub shell. + ViewShell* pShell = GetMainViewShell().get(); + if (pShell != nullptr) + pShell->SetZoomFactor (rZoomX, rZoomY); +} + +bool ViewShellBase::PrepareClose (bool bUI) +{ + bool bResult = SfxViewShell::PrepareClose (bUI); + + if (bResult) + { + mpImpl->mbIsClosing = true; + + // Forward call to main sub shell. + ViewShell* pShell = GetMainViewShell().get(); + if (pShell != nullptr) + bResult = pShell->PrepareClose (bUI); + } + + return bResult; +} + +void ViewShellBase::WriteUserData (OUString& rString, bool bBrowse) +{ + SfxViewShell::WriteUserData (rString, bBrowse); + + // Forward call to main sub shell. + ViewShell* pShell = GetMainViewShell().get(); + if (pShell != nullptr) + pShell->WriteUserData(); +} + +void ViewShellBase::ReadUserData (const OUString& rString, bool bBrowse) +{ + SfxViewShell::ReadUserData (rString, bBrowse); + + // Forward call to main sub shell. + ViewShell* pShell = GetMainViewShell().get(); + if (pShell != nullptr) + pShell->ReadUserData(); +} + +SdrView* ViewShellBase::GetDrawView() const +{ + // Forward call to main sub shell. + ViewShell* pShell = GetMainViewShell().get(); + if (pShell != nullptr) + return pShell->GetDrawView (); + else + return SfxViewShell::GetDrawView(); +} + +void ViewShellBase::SetBusyState (bool bBusy) +{ + if (GetDocShell() != nullptr) + GetDocShell()->SetWaitCursor (bBusy); +} + +void ViewShellBase::UpdateBorder ( bool bForce /* = false */ ) +{ + // The following calls to SetBorderPixel() and InvalidateBorder() are + // made only for the main view shell. This not only avoids unnecessary + // calls for the views in side panes but prevents calling an already + // dying SfxViewShell base class. + // We have to check the existence of the window, too. + // The SfxViewFrame accesses the window without checking it. + ViewShell* pMainViewShell = GetMainViewShell().get(); + if (pMainViewShell == nullptr || GetWindow()==nullptr) + return; + + SvBorder aCurrentBorder (GetBorderPixel()); + bool bOuterResize ( ! GetDocShell()->IsInPlaceActive()); + SvBorder aBorder (GetBorder(bOuterResize)); + aBorder += pMainViewShell->GetBorder(); + + if (bForce || (aBorder != aCurrentBorder)) + { + SetBorderPixel (aBorder); + InvalidateBorder(); + } +} + +void ViewShellBase::ShowUIControls (bool bVisible) +{ + mpImpl->ShowViewTabBar(bVisible); + + ViewShell* pMainViewShell = GetMainViewShell().get(); + if (pMainViewShell != nullptr) + pMainViewShell->ShowUIControls (bVisible); + + UpdateBorder(); + if (bVisible) + Rearrange(); +} + +OUString ViewShellBase::GetInitialViewShellType() const +{ + OUString sRequestedView (FrameworkHelper::msImpressViewURL); + + do + { + Reference<document::XViewDataSupplier> xViewDataSupplier ( + GetDocShell()->GetModel(), UNO_QUERY); + if ( ! xViewDataSupplier.is()) + break; + + Reference<container::XIndexAccess> xViewData (xViewDataSupplier->getViewData()); + if ( ! xViewData.is()) + break; + if (xViewData->getCount() == 0) + break; + + css::uno::Any aAny = xViewData->getByIndex(0); + Sequence<beans::PropertyValue> aProperties; + if ( ! (aAny >>= aProperties)) + break; + + // Search the properties for the one that tells us what page kind to + // use. + auto pProperty = std::find_if(std::cbegin(aProperties), std::cend(aProperties), + [](const beans::PropertyValue& rProperty) { return rProperty.Name == sUNO_View_PageKind; }); + if (pProperty != std::cend(aProperties)) + { + sal_Int16 nPageKind = 0; + pProperty->Value >>= nPageKind; + switch (static_cast<PageKind>(nPageKind)) + { + case PageKind::Standard: + sRequestedView = FrameworkHelper::msImpressViewURL; + break; + + case PageKind::Handout: + sRequestedView = FrameworkHelper::msHandoutViewURL; + break; + + case PageKind::Notes: + sRequestedView = FrameworkHelper::msNotesViewURL; + break; + + default: + // The page kind is invalid. This is probably an + // error by the caller. We use the standard type to + // keep things going. + SAL_WARN( "sd.view", "ViewShellBase::GetInitialViewShellType: invalid page kind"); + sRequestedView = FrameworkHelper::msImpressViewURL; + break; + } + } + } + while (false); + + return sRequestedView; +} + +std::shared_ptr<tools::EventMultiplexer> const & ViewShellBase::GetEventMultiplexer() const +{ + OSL_ASSERT(mpImpl != nullptr); + OSL_ASSERT(mpImpl->mpEventMultiplexer != nullptr); + + return mpImpl->mpEventMultiplexer; +} + +const ::tools::Rectangle& ViewShellBase::getClientRectangle() const +{ + return mpImpl->maClientArea; +} + +std::shared_ptr<ToolBarManager> const & ViewShellBase::GetToolBarManager() const +{ + OSL_ASSERT(mpImpl != nullptr); + OSL_ASSERT(mpImpl->mpToolBarManager != nullptr); + + return mpImpl->mpToolBarManager; +} + +std::shared_ptr<FormShellManager> const & ViewShellBase::GetFormShellManager() const +{ + OSL_ASSERT(mpImpl != nullptr); + OSL_ASSERT(mpImpl->mpFormShellManager != nullptr); + + return mpImpl->mpFormShellManager; +} + +DrawController* ViewShellBase::GetDrawController() const +{ + OSL_ASSERT(mpImpl != nullptr); + + return mpImpl->mpController.get(); +} + +void ViewShellBase::SetViewTabBar (const ::rtl::Reference<ViewTabBar>& rViewTabBar) +{ + OSL_ASSERT(mpImpl != nullptr); + + mpImpl->mpViewTabBar = rViewTabBar; +} + +vcl::Window* ViewShellBase::GetViewWindow() +{ + OSL_ASSERT(mpImpl != nullptr); + + return mpImpl->mpViewWindow.get(); +} + +OUString ViewShellBase::RetrieveLabelFromCommand( const OUString& aCmdURL ) const +{ + OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(GetMainViewShell()->GetViewFrame()->GetFrame().GetFrameInterface())); + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCmdURL, aModuleName); + return vcl::CommandInfoProvider::GetLabelForCommand(aProperties); +} + +int ViewShellBase::getPart() const +{ + ViewShell* pViewShell = framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this))->GetViewShell(FrameworkHelper::msCenterPaneURL).get(); + + if (DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pViewShell)) + { + return pDrawViewShell->GetCurPagePos(); + } + + return 0; +} + +int ViewShellBase::getEditMode() const +{ + ViewShell* pViewShell = framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this))->GetViewShell(FrameworkHelper::msCenterPaneURL).get(); + + if (DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pViewShell)) + { + switch ( pDrawViewShell->GetEditMode() ) + { + case EditMode::Page: + return 0; + case EditMode::MasterPage: + return 1; + } + } + + return 0; +} + +void ViewShellBase::setEditMode(int nMode) +{ + ViewShell* pViewShell = framework::FrameworkHelper::Instance(*this)->GetViewShell(FrameworkHelper::msCenterPaneURL).get(); + + if (DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pViewShell)) + { + switch ( nMode ) + { + case 0: + pDrawViewShell->ChangeEditMode(EditMode::Page, false); + break; + case 1: + pDrawViewShell->ChangeEditMode(EditMode::MasterPage, false); + break; + } + } +} + +void ViewShellBase::NotifyCursor(SfxViewShell* pOtherShell) const +{ + ViewShell* pThisShell = framework::FrameworkHelper::Instance(*const_cast<ViewShellBase*>(this))->GetViewShell(FrameworkHelper::msCenterPaneURL).get(); + + DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(pThisShell); + if (!pDrawViewShell) + return; + + if (this == pOtherShell) + return; + + DrawView* pDrawView = pDrawViewShell->GetDrawView(); + if (!pDrawView) + return; + + if (pDrawView->GetTextEditObject()) + { + // Blinking cursor. + EditView& rEditView = pDrawView->GetTextEditOutlinerView()->GetEditView(); + rEditView.RegisterOtherShell(pOtherShell); + rEditView.ShowCursor(); + rEditView.RegisterOtherShell(nullptr); + // Text selection, if any. + rEditView.DrawSelectionXOR(pOtherShell); + + // Shape text lock. + if (OutlinerView* pOutlinerView = pDrawView->GetTextEditOutlinerView()) + { + ::tools::Rectangle aRectangle = pOutlinerView->GetOutputArea(); + vcl::Window* pWin = pThisShell->GetActiveWindow(); + if (pWin && pWin->GetMapMode().GetMapUnit() == MapUnit::Map100thMM) + aRectangle = o3tl::toTwips(aRectangle, o3tl::Length::mm100); + OString sRectangle = aRectangle.toString(); + SfxLokHelper::notifyOtherView(&pDrawViewShell->GetViewShellBase(), pOtherShell, LOK_CALLBACK_VIEW_LOCK, "rectangle", sRectangle); + } + } + else + { + // Graphic selection. + pDrawView->AdjustMarkHdl(pOtherShell); + } +} + +::Color ViewShellBase::GetColorConfigColor(svtools::ColorConfigEntry nColorType) const +{ + if (DrawViewShell* pCurrentDrawShell = dynamic_cast<DrawViewShell*>(GetMainViewShell().get())) + { + const SdViewOptions& rViewOptions = pCurrentDrawShell->GetViewOptions(); + switch (nColorType) + { + case svtools::ColorConfigEntry::DOCCOLOR: + { + return rViewOptions.mnDocBackgroundColor; + } + // Should never be called for an unimplemented color type + default: + { + O3TL_UNREACHABLE; + } + } + } + else + { + SAL_WARN("sd", "dynamic_cast to DrawViewShell failed"); + } + + return {}; +} + +//===== ViewShellBase::Implementation ========================================= + +ViewShellBase::Implementation::Implementation (ViewShellBase& rBase) + : mbIsClosing(false), + mrBase(rBase), + mbUserWantsTabBar(false), + mbTabBarShouldBeVisible(true), + mpPageCacheManager(slidesorter::cache::PageCacheManager::Instance()) +{ +} + +ViewShellBase::Implementation::~Implementation() +{ + mpController = nullptr; + mpViewTabBar = nullptr; + mpViewWindow.disposeAndClear(); + mpToolBarManager.reset(); +} + +void ViewShellBase::Implementation::LateInit() +{ + mpController = new DrawController(mrBase); +} + +void ViewShellBase::Implementation::ProcessRestoreEditingViewSlot() +{ + ViewShell* pViewShell = mrBase.GetMainViewShell().get(); + if (pViewShell == nullptr) + return; + + FrameView* pFrameView = pViewShell->GetFrameView(); + if (pFrameView == nullptr) + return; + + // Set view shell, edit mode, and page kind. + // pFrameView->SetViewShEditMode( + // pFrameView->GetViewShEditModeOnLoad(), + // pFrameView->GetPageKindOnLoad()); + pFrameView->SetViewShEditMode( + pFrameView->GetViewShEditModeOnLoad() ); + pFrameView->SetPageKind( + pFrameView->GetPageKindOnLoad()); + std::shared_ptr<FrameworkHelper> pHelper (FrameworkHelper::Instance(mrBase)); + pHelper->RequestView( + FrameworkHelper::GetViewURL(pFrameView->GetViewShellTypeOnLoad()), + FrameworkHelper::msCenterPaneURL); + pHelper->RunOnConfigurationEvent("ConfigurationUpdateEnd", CurrentPageSetter(mrBase)); +} + +void ViewShellBase::Implementation::SetUserWantsTabBar(bool inValue) +{ + mbUserWantsTabBar = inValue; + // Call ShowViewTabBar to refresh the TabBar visibility + ShowViewTabBar(mbTabBarShouldBeVisible); +} + +void ViewShellBase::Implementation::ShowViewTabBar (bool bShow) +{ + mbTabBarShouldBeVisible = bShow; + bShow = bShow && mbUserWantsTabBar; + + if (mpViewTabBar.is() + && mpViewTabBar->GetTabControl()->IsVisible() != bShow) + { + mpViewTabBar->GetTabControl()->Show(bShow); + mrBase.Rearrange(); + } +} + +void ViewShellBase::Implementation::ResizePixel ( + const Point& rOrigin, + const Size &rSize, + bool bOuterResize) +{ + if (mbIsClosing) + return; + + // Forward the call to both the base class and the main stacked sub + // shell only when main sub shell exists. + ViewShell* pMainViewShell = mrBase.GetMainViewShell().get(); + + // Set the ViewTabBar temporarily to full size so that, when asked + // later, it can return its true height. + mrBase.SetWindow (mpViewWindow.get()); + if (mpViewTabBar.is() && mpViewTabBar->GetTabControl()->IsVisible()) + mpViewTabBar->GetTabControl()->SetPosSizePixel (rOrigin, rSize); + + // Calculate and set the border before the controls are placed. + SvBorder aBorder; + if (pMainViewShell != nullptr) + aBorder = pMainViewShell->GetBorder(); + aBorder += mrBase.GetBorder(bOuterResize); + if (mrBase.GetBorderPixel() != aBorder) + mrBase.SetBorderPixel(aBorder); + + // Place the ViewTabBar at the top. It is part of the border. + SvBorder aBaseBorder; + if (mpViewTabBar.is() && mpViewTabBar->GetTabControl()->IsVisible()) + { + aBaseBorder.Top() = mpViewTabBar->GetHeight(); + mpViewTabBar->GetTabControl()->SetPosSizePixel( + rOrigin, Size(rSize.Width(),aBaseBorder.Top())); + } + + // The view window gets the remaining space. + Point aViewWindowPosition ( + rOrigin.X()+aBaseBorder.Left(), + rOrigin.Y()+aBaseBorder.Top()); + + Size aViewWindowSize ( + rSize.Width() - aBaseBorder.Left() - aBaseBorder.Right(), + rSize.Height() - aBaseBorder.Top() - aBaseBorder.Bottom()); + mpViewWindow->SetPosSizePixel(aViewWindowPosition, aViewWindowSize); + + maClientArea = ::tools::Rectangle(Point(0,0), aViewWindowSize); +} + +void ViewShellBase::Implementation::SetPaneVisibility ( + const SfxRequest& rRequest, + const OUString& rsPaneURL, + const OUString& rsViewURL) +{ + try + { + Reference<XControllerManager> xControllerManager (mrBase.GetController(), UNO_QUERY_THROW); + + const Reference< XComponentContext > xContext( + ::comphelper::getProcessComponentContext() ); + Reference<XResourceId> xPaneId (ResourceId::create( + xContext, rsPaneURL)); + Reference<XResourceId> xViewId (ResourceId::createWithAnchorURL( + xContext, rsViewURL, rsPaneURL)); + + // Determine the new visibility state. + const SfxItemSet* pArguments = rRequest.GetArgs(); + bool bShowChildWindow; + sal_uInt16 nSlotId = rRequest.GetSlot(); + if (pArguments != nullptr) + bShowChildWindow = static_cast<const SfxBoolItem&>( + pArguments->Get(nSlotId)).GetValue(); + else + { + Reference<XConfigurationController> xConfigurationController ( + xControllerManager->getConfigurationController()); + if ( ! xConfigurationController.is()) + throw RuntimeException(); + Reference<XConfiguration> xConfiguration ( + xConfigurationController->getRequestedConfiguration()); + if ( ! xConfiguration.is()) + throw RuntimeException(); + + bShowChildWindow = ! xConfiguration->hasResource(xPaneId); + } + + // Set the desired visibility state at the current configuration + // and update it accordingly. + Reference<XConfigurationController> xConfigurationController ( + xControllerManager->getConfigurationController()); + if ( ! xConfigurationController.is()) + throw RuntimeException(); + if (bShowChildWindow) + { + xConfigurationController->requestResourceActivation( + xPaneId, + ResourceActivationMode_ADD); + xConfigurationController->requestResourceActivation( + xViewId, + ResourceActivationMode_REPLACE); + } + else + xConfigurationController->requestResourceDeactivation( + xPaneId); + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("sd.view"); + } +} + +void ViewShellBase::Implementation::GetSlotState (SfxItemSet& rSet) +{ + try + { + // Get some frequently used values. + Reference<XControllerManager> xControllerManager (mrBase.GetController(), UNO_QUERY_THROW); + Reference<XConfigurationController> xConfigurationController ( + xControllerManager->getConfigurationController()); + if ( ! xConfigurationController.is()) + throw RuntimeException(); + Reference<XConfiguration> xConfiguration ( + xConfigurationController->getRequestedConfiguration()); + if ( ! xConfiguration.is()) + throw RuntimeException(); + + const Reference< XComponentContext > xContext( + ::comphelper::getProcessComponentContext() ); + SfxWhichIter aSetIterator (rSet); + sal_uInt16 nItemId (aSetIterator.FirstWhich()); + + while (nItemId > 0) + { + bool bState (false); + Reference<XResourceId> xResourceId; + try + { + // Check if the right view is active + switch (nItemId) + { + case SID_LEFT_PANE_IMPRESS: + xResourceId = ResourceId::create( + xContext, FrameworkHelper::msLeftImpressPaneURL); + bState = xConfiguration->hasResource(xResourceId); + break; + + case SID_LEFT_PANE_DRAW: + xResourceId = ResourceId::create( + xContext, FrameworkHelper::msLeftDrawPaneURL); + bState = xConfiguration->hasResource(xResourceId); + break; + + case SID_DRAWINGMODE: + case SID_NORMAL_MULTI_PANE_GUI: + case SID_SLIDE_MASTER_MODE: + xResourceId = ResourceId::createWithAnchorURL( + xContext, FrameworkHelper::msImpressViewURL, + FrameworkHelper::msCenterPaneURL); + bState = xConfiguration->hasResource(xResourceId); + break; + + case SID_SLIDE_SORTER_MULTI_PANE_GUI: + case SID_SLIDE_SORTER_MODE: + xResourceId = ResourceId::createWithAnchorURL( + xContext, + FrameworkHelper::msSlideSorterURL, + FrameworkHelper::msCenterPaneURL); + bState = xConfiguration->hasResource(xResourceId); + break; + + case SID_OUTLINE_MODE: + xResourceId = ResourceId::createWithAnchorURL( + xContext, + FrameworkHelper::msOutlineViewURL, + FrameworkHelper::msCenterPaneURL); + bState = xConfiguration->hasResource(xResourceId); + break; + + case SID_HANDOUT_MASTER_MODE: + xResourceId = ResourceId::createWithAnchorURL( + xContext, FrameworkHelper::msHandoutViewURL, + FrameworkHelper::msCenterPaneURL); + bState = xConfiguration->hasResource(xResourceId); + break; + + case SID_NOTES_MODE: + case SID_NOTES_MASTER_MODE: + xResourceId = ResourceId::createWithAnchorURL( + xContext, FrameworkHelper::msNotesViewURL, + FrameworkHelper::msCenterPaneURL); + bState = xConfiguration->hasResource(xResourceId); + break; + + case SID_TOGGLE_TABBAR_VISIBILITY: + bState = GetUserWantsTabBar(); + break; + + default: + // Ignore all other items. They are not meant to be + // handled by us. + break; + } + } + catch (const DeploymentException&) + { + } + + // Check if edit mode fits too + if (bState) + { + ViewShell* const pCenterViewShell = FrameworkHelper::Instance(mrBase)->GetViewShell( + FrameworkHelper::msCenterPaneURL).get(); + DrawViewShell* const pShell = dynamic_cast<DrawViewShell*>(pCenterViewShell); + if (pShell) + { + switch (nItemId) + { + case SID_DRAWINGMODE: + case SID_NORMAL_MULTI_PANE_GUI: + case SID_NOTES_MODE: + bState = pShell->GetEditMode() == EditMode::Page; + break; + case SID_SLIDE_MASTER_MODE: + case SID_NOTES_MASTER_MODE: + bState = pShell->GetEditMode() == EditMode::MasterPage; + break; + } + } + } + + // And finally set the state. + rSet.Put(SfxBoolItem(nItemId, bState)); + + nItemId = aSetIterator.NextWhich(); + } + } + catch (const RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("sd.view"); + } + +} + +} // end of namespace sd + +//===== CurrentPageSetter =========================================== + +namespace { + +CurrentPageSetter::CurrentPageSetter (ViewShellBase& rBase) + : mrBase(rBase) +{ +} + +void CurrentPageSetter::operator() (bool) +{ + FrameView* pFrameView = nullptr; + + if (mrBase.GetMainViewShell() != nullptr) + { + pFrameView = mrBase.GetMainViewShell()->GetFrameView(); + } + + if (pFrameView==nullptr) + return; + + try + { + // Get the current page either from the DrawPagesSupplier or the + // MasterPagesSupplier. + Any aPage; + if (pFrameView->GetViewShEditModeOnLoad() == EditMode::Page) + { + Reference<drawing::XDrawPagesSupplier> xPagesSupplier ( + mrBase.GetController()->getModel(), UNO_QUERY_THROW); + Reference<container::XIndexAccess> xPages ( + xPagesSupplier->getDrawPages(), UNO_QUERY_THROW); + aPage = xPages->getByIndex(pFrameView->GetSelectedPageOnLoad()); + } + else + { + Reference<drawing::XMasterPagesSupplier> xPagesSupplier ( + mrBase.GetController()->getModel(), UNO_QUERY_THROW); + Reference<container::XIndexAccess> xPages ( + xPagesSupplier->getMasterPages(), UNO_QUERY_THROW); + aPage = xPages->getByIndex(pFrameView->GetSelectedPageOnLoad()); + } + // Switch to the page last edited by setting the CurrentPage + // property. + Reference<beans::XPropertySet> xSet (mrBase.GetController(), UNO_QUERY_THROW); + xSet->setPropertyValue ("CurrentPage", aPage); + } + catch (const RuntimeException&) + { + // We have not been able to set the current page at the main view. + // This is sad but still leaves us in a valid state. Therefore, + // this exception is silently ignored. + } + catch (const beans::UnknownPropertyException&) + { + SAL_WARN("sd.view", "CurrentPage property unknown"); + } +} + +} // end of anonymous namespace + +//===== FocusForwardingWindow ================================================= + +namespace sd { +namespace { + +FocusForwardingWindow::FocusForwardingWindow ( + vcl::Window& rParentWindow, + ViewShellBase& rBase) + : vcl::Window(&rParentWindow, WinBits(WB_CLIPCHILDREN | WB_DIALOGCONTROL)), + mrBase(rBase) +{ + SAL_INFO("sd.view", "created FocusForwardingWindow at " << this); +} + +FocusForwardingWindow::~FocusForwardingWindow() +{ + disposeOnce(); +} + +void FocusForwardingWindow::dispose() +{ + SAL_INFO("sd.view", "destroyed FocusForwardingWindow at " << this); + vcl::Window::dispose(); +} + +void FocusForwardingWindow::KeyInput (const KeyEvent& rKEvt) +{ + std::shared_ptr<ViewShell> pViewShell = mrBase.GetMainViewShell(); + if (pViewShell != nullptr) + { + vcl::Window* pWindow = pViewShell->GetActiveWindow(); + if (pWindow != nullptr) + { + // Forward the focus so that the window is called directly the + // next time. + pWindow->GrabFocus(); + // Forward the key press as well. + pWindow->KeyInput(rKEvt); + } + } +} + +void FocusForwardingWindow::Command (const CommandEvent& rEvent) +{ + std::shared_ptr<ViewShell> pViewShell = mrBase.GetMainViewShell(); + if (pViewShell != nullptr) + { + vcl::Window* pWindow = pViewShell->GetActiveWindow(); + if (pWindow != nullptr) + { + pWindow->Command(rEvent); + } + } +} + +} // end of anonymous namespace + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/ViewShellHint.cxx b/sd/source/ui/view/ViewShellHint.cxx new file mode 100644 index 0000000000..b86cbaa325 --- /dev/null +++ b/sd/source/ui/view/ViewShellHint.cxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ViewShellHint.hxx> + +namespace sd +{ +ViewShellHint::ViewShellHint(HintId eHintId) + : meHintId(eHintId) +{ +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/ViewShellImplementation.cxx b/sd/source/ui/view/ViewShellImplementation.cxx new file mode 100644 index 0000000000..c76de5a513 --- /dev/null +++ b/sd/source/ui/view/ViewShellImplementation.cxx @@ -0,0 +1,380 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <ViewShellImplementation.hxx> + +#include <sdpage.hxx> +#include <drawdoc.hxx> +#include <sdresid.hxx> +#include <unokywds.hxx> +#include <strings.hrc> +#include <app.hrc> +#include <unmodpg.hxx> +#include <DrawDocShell.hxx> +#include <FactoryIds.hxx> +#include <ViewShellBase.hxx> + +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/request.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/viewfrm.hxx> +#include <sfx2/sidebar/Sidebar.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <svx/imapdlg.hxx> +#include <basic/sbstar.hxx> +#include <basic/sberrors.hxx> +#include <xmloff/autolayout.hxx> +#include <vcl/svapp.hxx> + +#include <undo/undoobjects.hxx> + +#include <com/sun/star/drawing/framework/XControllerManager.hpp> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +namespace sd { + +ViewShell::Implementation::Implementation (ViewShell& rViewShell) + : mbIsMainViewShell(false), + mbIsInitialized(false), + mbArrangeActive(false), + mrViewShell(rViewShell) +{ +} + +ViewShell::Implementation::~Implementation() COVERITY_NOEXCEPT_FALSE +{ + if ( ! mpUpdateLockForMouse.expired()) + { + std::shared_ptr<ToolBarManagerLock> pLock(mpUpdateLockForMouse); + if (pLock != nullptr) + { + // Force the ToolBarManagerLock to be released even when the + // IsUICaptured() returns <TRUE/>. + pLock->Release(true); + } + } +} + +void ViewShell::Implementation::ProcessModifyPageSlot ( + SfxRequest& rRequest, + SdPage* pCurrentPage, + PageKind ePageKind) +{ + SdDrawDocument* pDocument = mrViewShell.GetDoc(); + SdrLayerAdmin& rLayerAdmin = pDocument->GetLayerAdmin(); + SdrLayerIDSet aVisibleLayers; + bool bHandoutMode = false; + SdPage* pHandoutMPage = nullptr; + OUString aNewName; + + AutoLayout aNewAutoLayout; + + bool bBVisible; + bool bBObjsVisible; + const SfxItemSet* pArgs = rRequest.GetArgs(); + + if (pCurrentPage != nullptr && pCurrentPage->TRG_HasMasterPage()) + aVisibleLayers = pCurrentPage->TRG_GetMasterPageVisibleLayers(); + else + aVisibleLayers.SetAll(); + + do + { + if (pCurrentPage == nullptr) + break; + + if (!pArgs || pArgs->Count() == 1 || pArgs->Count() == 2 ) + { + // First make sure that the sidebar is visible + mrViewShell.GetDrawView()->SdrEndTextEdit(); + mrViewShell.GetDrawView()->UnmarkAll(); + mrViewShell.GetViewFrame()->ShowChildWindow(SID_SIDEBAR); + sfx2::sidebar::Sidebar::TogglePanel( + u"SdLayoutsPanel", + mrViewShell.GetViewFrame()->GetFrame().GetFrameInterface()); + break; + } + else if (pArgs->Count() == 4) + { + const SfxStringItem* pNewName = rRequest.GetArg<SfxStringItem>(ID_VAL_PAGENAME); + const SfxUInt32Item* pNewAutoLayout = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYOUT); + const SfxBoolItem* pBVisible = rRequest.GetArg<SfxBoolItem>(ID_VAL_ISPAGEBACK); + const SfxBoolItem* pBObjsVisible = rRequest.GetArg<SfxBoolItem>(ID_VAL_ISPAGEOBJ); + assert(pNewName && pNewAutoLayout && pBVisible && pBObjsVisible && "must be present"); + AutoLayout aLayout (static_cast<AutoLayout>(pNewAutoLayout->GetValue ())); + if (aLayout >= AUTOLAYOUT_START + && aLayout < AUTOLAYOUT_END) + { + aNewName = pNewName->GetValue (); + aNewAutoLayout = static_cast<AutoLayout>(pNewAutoLayout->GetValue ()); + bBVisible = pBVisible->GetValue (); + bBObjsVisible = pBObjsVisible->GetValue (); + } + else + { +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE); +#endif + rRequest.Ignore (); + break; + } + if (ePageKind == PageKind::Handout) + { + bHandoutMode = true; + pHandoutMPage = pDocument->GetMasterSdPage(0, PageKind::Handout); + } + } + else + { +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + rRequest.Ignore (); + break; + } + + SdPage* pUndoPage = + bHandoutMode ? pHandoutMPage : pCurrentPage; + + SfxUndoManager* pUndoManager = mrViewShell.GetDocSh()->GetUndoManager(); + DBG_ASSERT(pUndoManager, "No UNDO MANAGER ?!?"); + + if( pUndoManager ) + { + OUString aComment( SdResId(STR_UNDO_MODIFY_PAGE) ); + pUndoManager->EnterListAction(aComment, aComment, 0, mrViewShell.GetViewShellBase().GetViewShellId()); + pUndoManager->AddUndoAction( + std::make_unique<ModifyPageUndoAction>( + pDocument, pUndoPage, aNewName, aNewAutoLayout, bBVisible, bBObjsVisible)); + + // Clear the selection because the selected object may be removed as + // a result of the assignment of the layout. + mrViewShell.GetDrawView()->UnmarkAll(); + + if (!bHandoutMode) + { + if (pCurrentPage->GetName() != aNewName) + { + pCurrentPage->SetName(aNewName); + + if (ePageKind == PageKind::Standard) + { + sal_uInt16 nPage = (pCurrentPage->GetPageNum()-1) / 2; + SdPage* pNotesPage = pDocument->GetSdPage(nPage, PageKind::Notes); + if (pNotesPage != nullptr) + pNotesPage->SetName(aNewName); + } + } + + pCurrentPage->SetAutoLayout(aNewAutoLayout, true); + + SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background); + SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects); + aVisibleLayers.Set(aBckgrnd, bBVisible); + aVisibleLayers.Set(aBckgrndObj, bBObjsVisible); + pCurrentPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers); + } + else + { + pHandoutMPage->SetAutoLayout(aNewAutoLayout, true); + } + + mrViewShell.GetViewFrame()->GetDispatcher()->Execute(SID_SWITCHPAGE, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); + + bool bSetModified = true; + + if (pArgs->Count() == 1) + { + bSetModified = static_cast<const SfxBoolItem&>(pArgs->Get(SID_MODIFYPAGE)).GetValue(); + } + + pUndoManager->AddUndoAction( std::make_unique<UndoAutoLayoutPosAndSize>( *pUndoPage ) ); + pUndoManager->LeaveListAction(); + + pDocument->SetChanged(bSetModified); + } + } + while (false); + + mrViewShell.Cancel(); + rRequest.Done (); +} + +void ViewShell::Implementation::AssignLayout ( SfxRequest const & rRequest, PageKind ePageKind ) +{ + const SfxUInt32Item* pWhatPage = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATPAGE); + const SfxUInt32Item* pWhatLayout = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYOUT); + + SdDrawDocument* pDocument = mrViewShell.GetDoc(); + if( !pDocument ) + return; + + SdPage* pPage = nullptr; + if( pWhatPage ) + { + pPage = pDocument->GetSdPage(static_cast<sal_uInt16>(pWhatPage->GetValue()), ePageKind); + } + + if( pPage == nullptr ) + pPage = mrViewShell.getCurrentPage(); + + if( !pPage ) + return; + + AutoLayout eLayout = pPage->GetAutoLayout(); + + if( pWhatLayout ) + eLayout = static_cast< AutoLayout >( pWhatLayout->GetValue() ); + + // Transform the given request into the four argument form that is + // understood by ProcessModifyPageSlot(). + SdrLayerAdmin& rLayerAdmin (mrViewShell.GetViewShellBase().GetDocument()->GetLayerAdmin()); + SdrLayerID aBackground (rLayerAdmin.GetLayerID(sUNO_LayerName_background)); + SdrLayerID aBackgroundObject (rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects)); + + SdrLayerIDSet aVisibleLayers; + + if( pPage->GetPageKind() == PageKind::Handout ) + aVisibleLayers.SetAll(); + else + aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers(); + + SfxRequest aRequest(mrViewShell.GetViewShellBase().GetViewFrame(), SID_MODIFYPAGE); + aRequest.AppendItem(SfxStringItem (ID_VAL_PAGENAME, pPage->GetName())); + aRequest.AppendItem(SfxUInt32Item (ID_VAL_WHATLAYOUT, eLayout)); + aRequest.AppendItem(SfxBoolItem(ID_VAL_ISPAGEBACK, aVisibleLayers.IsSet(aBackground))); + aRequest.AppendItem(SfxBoolItem(ID_VAL_ISPAGEOBJ, aVisibleLayers.IsSet(aBackgroundObject))); + + // Forward the call with the new arguments. + ProcessModifyPageSlot( aRequest, pPage, pPage->GetPageKind()); +} + +SfxInterfaceId ViewShell::Implementation::GetViewId() const +{ + switch (mrViewShell.GetShellType()) + { + case ViewShell::ST_IMPRESS: + case ViewShell::ST_NOTES: + case ViewShell::ST_HANDOUT: + return IMPRESS_FACTORY_ID; + + case ViewShell::ST_DRAW: + return DRAW_FACTORY_ID; + + case ViewShell::ST_OUTLINE: + return OUTLINE_FACTORY_ID; + + case ViewShell::ST_SLIDE_SORTER: + return SLIDE_SORTER_FACTORY_ID; + + case ViewShell::ST_PRESENTATION: + return PRESENTATION_FACTORY_ID; + + // Since we have to return a view id for every possible shell type + // and there is not (yet) a proper ViewShellBase sub class for the + // remaining types we chose the Impress factory as a fall back. + case ViewShell::ST_SIDEBAR: + case ViewShell::ST_NONE: + default: + return IMPRESS_FACTORY_ID; + } +} + +SvxIMapDlg* ViewShell::Implementation::GetImageMapDialog() +{ + SfxViewFrame* pViewFrm = SfxViewFrame::Current(); + if (!pViewFrm) + return nullptr; + + SfxChildWindow* pChildWindow = pViewFrm->GetChildWindow( + SvxIMapDlgChildWindow::GetChildWindowId()); + if (pChildWindow == nullptr) + return nullptr; + + return dynamic_cast<SvxIMapDlg*>(pChildWindow->GetController().get()); +} + +//===== ToolBarManagerLock ==================================================== + +class ViewShell::Implementation::ToolBarManagerLock::Deleter { public: + void operator() (ToolBarManagerLock* pObject) { delete pObject; } +}; + +std::shared_ptr<ViewShell::Implementation::ToolBarManagerLock> + ViewShell::Implementation::ToolBarManagerLock::Create ( + const std::shared_ptr<ToolBarManager>& rpManager) +{ + std::shared_ptr<ToolBarManagerLock> pLock ( + new ViewShell::Implementation::ToolBarManagerLock(rpManager), + ViewShell::Implementation::ToolBarManagerLock::Deleter()); + pLock->mpSelf = pLock; + return pLock; +} + +ViewShell::Implementation::ToolBarManagerLock::ToolBarManagerLock ( + const std::shared_ptr<ToolBarManager>& rpManager) + : mpLock(new ToolBarManager::UpdateLock(rpManager)), + maTimer("sd ToolBarManagerLock maTimer") +{ + // Start a timer that will unlock the ToolBarManager update lock when + // that is not done explicitly by calling Release(). + maTimer.SetInvokeHandler(LINK(this,ToolBarManagerLock,TimeoutCallback)); + maTimer.SetTimeout(100); + maTimer.Start(); +} + +IMPL_LINK_NOARG(ViewShell::Implementation::ToolBarManagerLock, TimeoutCallback, Timer *, void) +{ + // If possible then release the lock now. Otherwise start the timer + // and try again later. + if (Application::IsUICaptured()) + { + maTimer.Start(); + } + else + { + mpSelf.reset(); + } +} + +void ViewShell::Implementation::ToolBarManagerLock::Release (bool bForce) +{ + // If possible then release the lock now. Otherwise try again when the + // timer expires. + if (bForce || ! Application::IsUICaptured()) + { + mpSelf.reset(); + } +} + +ViewShell::Implementation::ToolBarManagerLock::~ToolBarManagerLock() +{ + mpLock.reset(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/ViewShellManager.cxx b/sd/source/ui/view/ViewShellManager.cxx new file mode 100644 index 0000000000..db2ee5f8f1 --- /dev/null +++ b/sd/source/ui/view/ViewShellManager.cxx @@ -0,0 +1,1168 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ViewShellManager.hxx> +#include <ViewShell.hxx> +#include <ViewShellBase.hxx> +#include <Window.hxx> +#include <DrawDocShell.hxx> + +#include <sal/log.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/svxids.hrc> +#include <svx/fmshell.hxx> +#include <vcl/vclevent.hxx> +#include <osl/diagnose.h> + +#include <iterator> +#include <list> +#include <unordered_map> + +namespace sd { + +namespace { + +/** The ShellDescriptor class is used to shells together with their ids and + the factory that was used to create the shell. + + The shell pointer may be NULL. In that case the shell is created on + demand by a factory. + + The factory pointer may be NULL. In that case the shell pointer is + given to the ViewShellManager. + + Shell pointer and factory pointer can but should not be NULL at the same + time. +*/ +class ShellDescriptor { +public: + SfxShell* mpShell; + ShellId mnId; + ViewShellManager::SharedShellFactory mpFactory; + bool mbIsListenerAddedToWindow; + + ShellDescriptor (); + explicit ShellDescriptor (ShellId nId); + vcl::Window* GetWindow() const; +}; + +/** This functor can be used to search for a shell in an STL container when the + shell pointer is given. +*/ +class IsShell +{ +public: + explicit IsShell (const SfxShell* pShell) : mpShell(pShell) {} + bool operator() (const ShellDescriptor& rDescriptor) + { return rDescriptor.mpShell == mpShell; } +private: + const SfxShell* mpShell; +}; + +/** This functor can be used to search for a shell in an STL container when the + id of the shell is given. +*/ +class IsId +{ +public: + explicit IsId (ShellId nId) : mnId(nId) {} + bool operator() (const ShellDescriptor& rDescriptor) + { return rDescriptor.mnId == mnId; } +private: + ShellId mnId; +}; + +} // end of anonymous namespace + +class ViewShellManager::Implementation +{ +public: + Implementation ( + ViewShellBase& rBase); + ~Implementation() COVERITY_NOEXCEPT_FALSE; + + void AddShellFactory ( + const SfxShell* pViewShell, + const SharedShellFactory& rpFactory); + void RemoveShellFactory ( + const SfxShell* pViewShell, + const SharedShellFactory& rpFactory); + void ActivateViewShell ( + ViewShell* pViewShell); + void DeactivateViewShell (const ViewShell& rShell); + void ActivateShell (SfxShell& rShell); + void DeactivateShell (const SfxShell& rShell); + void ActivateShell (const ShellDescriptor& rDescriptor); + void SetFormShell (const ViewShell* pViewShell, FmFormShell* pFormShell, bool bAbove); + void ActivateSubShell (const SfxShell& rParentShell, ShellId nId); + void DeactivateSubShell (const SfxShell& rParentShell, ShellId nId); + void MoveToTop (const SfxShell& rParentShell); + SfxShell* GetShell (ShellId nId) const; + SfxShell* GetTopShell() const; + SfxShell* GetTopViewShell() const; + void Shutdown(); + void InvalidateAllSubShells (const SfxShell* pParentShell); + + /** Remove all shells from the SFX stack above and including the given + shell. + */ + void TakeShellsFromStack (const SfxShell* pShell); + + class UpdateLock + { + public: + explicit UpdateLock (Implementation& rImpl) : mrImpl(rImpl) {mrImpl.LockUpdate();} + ~UpdateLock() COVERITY_NOEXCEPT_FALSE {mrImpl.UnlockUpdate();} + private: + Implementation& mrImpl; + }; + + /** Prevent updates of the shell stack. While the sub shell manager is + locked it will update its internal data structures but not alter the + shell stack. Use this method when there are several modifications + to the shell stack to prevent multiple rebuilds of the shell stack + and resulting broadcasts. + */ + void LockUpdate(); + + /** Allow updates of the shell stack. This method has to be called the + same number of times as LockUpdate() to really allow a rebuild of + the shell stack. + */ + void UnlockUpdate(); + +private: + ViewShellBase& mrBase; + mutable ::osl::Mutex maMutex; + + class ShellHash { public: size_t operator()(const SfxShell* p) const { return reinterpret_cast<size_t>(p);} }; + typedef std::unordered_multimap<const SfxShell*,SharedShellFactory,ShellHash> + FactoryList; + FactoryList maShellFactories; + + /** List of the active view shells. In order to create gather all shells + to put on the shell stack each view shell in this list is asked for + its sub-shells (typically toolbars). + */ + typedef std::list<ShellDescriptor> ActiveShellList; + ActiveShellList maActiveViewShells; + + typedef std::list<ShellDescriptor> SubShellSubList; + typedef std::unordered_map<const SfxShell*,SubShellSubList,ShellHash> SubShellList; + SubShellList maActiveSubShells; + + /** In this member we remember what shells we have pushed on the shell + stack. + */ + typedef ::std::vector<SfxShell*> ShellStack; + + int mnUpdateLockCount; + + /** The UpdateShellStack() method can be called recursively. This flag + is used to communicate between different levels of invocation: if + the stack has been updated in an inner call the outer call can (has + to) stop and return immediately. + */ + bool mbShellStackIsUpToDate; + + SfxShell* mpFormShell; + const ViewShell* mpFormShellParent; + bool mbFormShellAboveParent; + + SfxShell* mpTopShell; + SfxShell* mpTopViewShell; + + + void UpdateShellStack(); + + void CreateShells(); + + /** This method rebuilds the stack of shells that are stacked upon the + view shell base. + */ + void CreateTargetStack (ShellStack& rStack) const; + + DECL_LINK(WindowEventHandler, VclWindowEvent&, void); + +#if OSL_DEBUG_LEVEL >= 2 + void DumpShellStack (const ShellStack& rStack); + void DumpSfxShellStack(); +#endif + + /** To be called before a shell is taken from the SFX shell stack. This + method deactivates an active text editing to avoid problems with + undo managers. + Afterwards the Deactivate() of the shell is called. + */ + static void Deactivate (SfxShell* pShell); + + ShellDescriptor CreateSubShell ( + SfxShell const * pShell, + ShellId nShellId); + void DestroyViewShell (ShellDescriptor& rDescriptor); + static void DestroySubShell (const ShellDescriptor& rDescriptor); +}; + +//===== ViewShellManager ====================================================== + +ViewShellManager::ViewShellManager (ViewShellBase& rBase) + : mpImpl(new Implementation(rBase)), + mbValid(true) +{ +} + +ViewShellManager::~ViewShellManager() +{ +} + +void ViewShellManager::AddSubShellFactory ( + ViewShell const * pViewShell, + const SharedShellFactory& rpFactory) +{ + if (mbValid) + mpImpl->AddShellFactory(pViewShell, rpFactory); +} + +void ViewShellManager::RemoveSubShellFactory ( + ViewShell const * pViewShell, + const SharedShellFactory& rpFactory) +{ + if (mbValid) + mpImpl->RemoveShellFactory(pViewShell, rpFactory); +} + +void ViewShellManager::ActivateViewShell (ViewShell* pViewShell) +{ + if (mbValid) + return mpImpl->ActivateViewShell(pViewShell); +} + +void ViewShellManager::DeactivateViewShell (const ViewShell* pShell) +{ + if (mbValid && pShell!=nullptr) + mpImpl->DeactivateViewShell(*pShell); +} + +void ViewShellManager::SetFormShell ( + const ViewShell* pParentShell, + FmFormShell* pFormShell, + bool bAbove) +{ + if (mbValid) + mpImpl->SetFormShell(pParentShell,pFormShell,bAbove); +} + +void ViewShellManager::ActivateSubShell (const ViewShell& rViewShell, ShellId nId) +{ + if (mbValid) + mpImpl->ActivateSubShell(rViewShell,nId); +} + +void ViewShellManager::DeactivateSubShell (const ViewShell& rViewShell, ShellId nId) +{ + if (mbValid) + mpImpl->DeactivateSubShell(rViewShell,nId); +} + +void ViewShellManager::InvalidateAllSubShells (ViewShell const * pViewShell) +{ + if (mbValid) + mpImpl->InvalidateAllSubShells(pViewShell); +} + +void ViewShellManager::ActivateShell (SfxShell* pShell) +{ + if (mbValid && pShell!=nullptr) + mpImpl->ActivateShell(*pShell); +} + +void ViewShellManager::DeactivateShell (const SfxShell* pShell) +{ + if (mbValid && pShell!=nullptr) + mpImpl->DeactivateShell(*pShell); +} + +void ViewShellManager::MoveToTop (const ViewShell& rParentShell) +{ + if (mbValid) + mpImpl->MoveToTop(rParentShell); +} + +SfxShell* ViewShellManager::GetShell (ShellId nId) const +{ + if (mbValid) + return mpImpl->GetShell(nId); + else + return nullptr; +} + +SfxShell* ViewShellManager::GetTopShell() const +{ + if (mbValid) + return mpImpl->GetTopShell(); + else + return nullptr; +} + +SfxShell* ViewShellManager::GetTopViewShell() const +{ + if (mbValid) + return mpImpl->GetTopViewShell(); + else + return nullptr; +} + +void ViewShellManager::Shutdown() +{ + if (mbValid) + { + mpImpl->Shutdown(); + mbValid = false; + } +} + +void ViewShellManager::LockUpdate() +{ + mpImpl->LockUpdate(); +} + +void ViewShellManager::UnlockUpdate() +{ + mpImpl->UnlockUpdate(); +} + +//===== ViewShellManager::Implementation ====================================== + +ViewShellManager::Implementation::Implementation ( + ViewShellBase& rBase) + : mrBase(rBase), + mnUpdateLockCount(0), + mbShellStackIsUpToDate(true), + mpFormShell(nullptr), + mpFormShellParent(nullptr), + mbFormShellAboveParent(true), + mpTopShell(nullptr), + mpTopViewShell(nullptr) +{} + +ViewShellManager::Implementation::~Implementation() COVERITY_NOEXCEPT_FALSE +{ + Shutdown(); +} + +void ViewShellManager::Implementation::AddShellFactory ( + const SfxShell* pViewShell, + const SharedShellFactory& rpFactory) +{ + bool bAlreadyAdded (false); + + // Check that the given factory has not already been added. + ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( + maShellFactories.equal_range(pViewShell)); + for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory) + if (iFactory->second == rpFactory) + { + bAlreadyAdded = true; + break; + } + + // Add the factory if it is not already present. + if ( ! bAlreadyAdded) + maShellFactories.emplace(pViewShell, rpFactory); +} + +void ViewShellManager::Implementation::RemoveShellFactory ( + const SfxShell* pViewShell, + const SharedShellFactory& rpFactory) +{ + ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( + maShellFactories.equal_range(pViewShell)); + for (FactoryList::iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory) + if (iFactory->second == rpFactory) + { + maShellFactories.erase(iFactory); + break; + } +} + +void ViewShellManager::Implementation::ActivateViewShell (ViewShell* pViewShell) +{ + ::osl::MutexGuard aGuard (maMutex); + + ShellDescriptor aResult; + aResult.mpShell = pViewShell; + + // Register as window listener so that the shells of the current + // window can be moved to the top of the shell stack. + if (aResult.mpShell != nullptr) + { + vcl::Window* pWindow = aResult.GetWindow(); + if (pWindow != nullptr) + { + pWindow->AddEventListener( + LINK(this, ViewShellManager::Implementation, WindowEventHandler)); + aResult.mbIsListenerAddedToWindow = true; + } + else + { + SAL_WARN("sd.view", + "ViewShellManager::ActivateViewShell: " + "new view shell has no active window"); + } + } + + ActivateShell(aResult); +} + +void ViewShellManager::Implementation::DeactivateViewShell (const ViewShell& rShell) +{ + ::osl::MutexGuard aGuard (maMutex); + + ActiveShellList::iterator iShell (::std::find_if ( + maActiveViewShells.begin(), + maActiveViewShells.end(), + IsShell(&rShell))); + if (iShell == maActiveViewShells.end()) + return; + + UpdateLock aLocker (*this); + + ShellDescriptor aDescriptor(*iShell); + mrBase.GetDocShell()->Disconnect(dynamic_cast<ViewShell*>(aDescriptor.mpShell)); + maActiveViewShells.erase(iShell); + TakeShellsFromStack(aDescriptor.mpShell); + + // Deactivate sub shells. + SubShellList::iterator iList (maActiveSubShells.find(&rShell)); + if (iList != maActiveSubShells.end()) + { + SubShellSubList& rList (iList->second); + while ( ! rList.empty()) + DeactivateSubShell(rShell, rList.front().mnId); + } + + DestroyViewShell(aDescriptor); +} + +void ViewShellManager::Implementation::ActivateShell (SfxShell& rShell) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Create a new shell or recycle on in the cache. + ShellDescriptor aDescriptor; + aDescriptor.mpShell = &rShell; + + ActivateShell(aDescriptor); +} + +void ViewShellManager::Implementation::ActivateShell (const ShellDescriptor& rDescriptor) +{ + // Put shell on top of the active view shells. + if (rDescriptor.mpShell != nullptr) + { + maActiveViewShells.insert( maActiveViewShells.begin(), rDescriptor); + } +} + +void ViewShellManager::Implementation::DeactivateShell (const SfxShell& rShell) +{ + ::osl::MutexGuard aGuard (maMutex); + + ActiveShellList::iterator iShell (::std::find_if ( + maActiveViewShells.begin(), + maActiveViewShells.end(), + IsShell(&rShell))); + if (iShell == maActiveViewShells.end()) + return; + + UpdateLock aLocker (*this); + + ShellDescriptor aDescriptor(*iShell); + mrBase.GetDocShell()->Disconnect(dynamic_cast<ViewShell*>(aDescriptor.mpShell)); + maActiveViewShells.erase(iShell); + TakeShellsFromStack(aDescriptor.mpShell); + + // Deactivate sub shells. + SubShellList::iterator iList (maActiveSubShells.find(&rShell)); + if (iList != maActiveSubShells.end()) + { + SubShellSubList& rList (iList->second); + while ( ! rList.empty()) + DeactivateSubShell(rShell, rList.front().mnId); + } + + DestroyViewShell(aDescriptor); +} + +void ViewShellManager::Implementation::ActivateSubShell ( + const SfxShell& rParentShell, + ShellId nId) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Check that the given view shell is active. + if (std::none_of (maActiveViewShells.begin(), maActiveViewShells.end(), IsShell(&rParentShell))) + return; + + // Create the sub shell list if it does not yet exist. + SubShellList::iterator iList (maActiveSubShells.find(&rParentShell)); + if (iList == maActiveSubShells.end()) + iList = maActiveSubShells.emplace(&rParentShell,SubShellSubList()).first; + + // Do not activate an object bar that is already active. Requesting + // this is not exactly an error but may be an indication of one. + SubShellSubList& rList (iList->second); + if (std::any_of(rList.begin(),rList.end(), IsId(nId))) + return; + + // Add just the id of the sub shell. The actual shell is created + // later in CreateShells(). + UpdateLock aLock (*this); + rList.emplace_back(nId); +} + +void ViewShellManager::Implementation::DeactivateSubShell ( + const SfxShell& rParentShell, + ShellId nId) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Check that the given view shell is active. + SubShellList::iterator iList (maActiveSubShells.find(&rParentShell)); + if (iList == maActiveSubShells.end()) + return; + + // Look up the sub shell. + SubShellSubList& rList (iList->second); + SubShellSubList::iterator iShell ( + ::std::find_if(rList.begin(),rList.end(), IsId(nId))); + if (iShell == rList.end()) + return; + SfxShell* pShell = iShell->mpShell; + if (pShell == nullptr) + return; + + UpdateLock aLock (*this); + + ShellDescriptor aDescriptor(*iShell); + // Remove the sub shell from both the internal structure as well as the + // SFX shell stack above and including the sub shell. + rList.erase(iShell); + TakeShellsFromStack(pShell); + + DestroySubShell(aDescriptor); +} + +void ViewShellManager::Implementation::MoveToTop (const SfxShell& rShell) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Check that we have access to a dispatcher. If not, then we are + // (probably) called while the view shell is still being created or + // initialized. Without dispatcher we can not rebuild the shell stack + // to move the requested shell to the top. So return right away instead + // of making a mess without being able to clean up afterwards. + if (mrBase.GetDispatcher() == nullptr) + return; + + ActiveShellList::iterator iShell (::std::find_if ( + maActiveViewShells.begin(), + maActiveViewShells.end(), + IsShell(&rShell))); + bool bMove = true; + if (iShell != maActiveViewShells.end()) + { + // Is the shell already at the top of the stack? We have to keep + // the case in mind that mbKeepMainViewShellOnTop is true. Shells + // that are not the main view shell are placed on the second-to-top + // position in this case. + if (iShell == maActiveViewShells.begin()) + { + // The shell is at the top position and is either a) the main + // view shell or b) another shell but the main view shell is not + // kept at the top position. We do not have to move the shell. + bMove = false; + } + } + else + { + // The shell is not on the stack. Therefore it can not be moved. + // We could insert it but we don't. Use ActivateViewShell() for + // that. + bMove = false; + } + + // When the shell is not at the right position it is removed from the + // internal list of shells and inserted at the correct position. + if (bMove) + { + UpdateLock aLock (*this); + + ShellDescriptor aDescriptor(*iShell); + + TakeShellsFromStack(&rShell); + maActiveViewShells.erase(iShell); + + maActiveViewShells.insert(maActiveViewShells.begin(), aDescriptor); + } +} + +SfxShell* ViewShellManager::Implementation::GetShell (ShellId nId) const +{ + ::osl::MutexGuard aGuard (maMutex); + + SfxShell* pShell = nullptr; + + // First search the active view shells. + ActiveShellList::const_iterator iShell ( + ::std::find_if ( + maActiveViewShells.begin(), + maActiveViewShells.end(), + IsId(nId))); + if (iShell != maActiveViewShells.end()) + pShell = iShell->mpShell; + else + { + // Now search the active sub shells of every active view shell. + for (auto const& activeSubShell : maActiveSubShells) + { + const SubShellSubList& rList (activeSubShell.second); + SubShellSubList::const_iterator iSubShell( + ::std::find_if(rList.begin(),rList.end(), IsId(nId))); + if (iSubShell != rList.end()) + { + pShell = iSubShell->mpShell; + break; + } + } + } + + return pShell; +} + +SfxShell* ViewShellManager::Implementation::GetTopShell() const +{ + OSL_ASSERT(mpTopShell == mrBase.GetSubShell(0)); + return mpTopShell; +} + +SfxShell* ViewShellManager::Implementation::GetTopViewShell() const +{ + return mpTopViewShell; +} + +void ViewShellManager::Implementation::LockUpdate() +{ + mnUpdateLockCount++; +} + +void ViewShellManager::Implementation::UnlockUpdate() +{ + ::osl::MutexGuard aGuard (maMutex); + + mnUpdateLockCount--; + if (mnUpdateLockCount < 0) + { + // This should not happen. + OSL_ASSERT (mnUpdateLockCount>=0); + mnUpdateLockCount = 0; + } + if (mnUpdateLockCount == 0) + UpdateShellStack(); +} + +/** Update the SFX shell stack (the portion that is visible to us) so that + it matches the internal shell stack. This is done in six steps: + 1. Create the missing view shells and sub shells. + 2. Set up the internal shell stack. + 3. Get the SFX shell stack. + 4. Find the lowest shell in which the two stacks differ. + 5. Remove all shells above and including that shell from the SFX stack. + 6. Push all shells of the internal stack on the SFX shell stack that are + not already present on the later. +*/ +void ViewShellManager::Implementation::UpdateShellStack() +{ + ::osl::MutexGuard aGuard (maMutex); + + // Remember the undo manager from the top-most shell on the stack. + SfxShell* pTopMostShell = mrBase.GetSubShell(0); + SfxUndoManager* pUndoManager = (pTopMostShell!=nullptr) + ? pTopMostShell->GetUndoManager() + : nullptr; + + // 1. Create the missing shells. + CreateShells(); + + // Update the pointer to the top-most active view shell. + mpTopViewShell = (maActiveViewShells.empty()) + ? nullptr : maActiveViewShells.begin()->mpShell; + + + // 2. Create the internal target stack. + ShellStack aTargetStack; + CreateTargetStack(aTargetStack); + + // 3. Get SFX shell stack. + ShellStack aSfxShellStack; + sal_uInt16 nIndex (0); + while (mrBase.GetSubShell(nIndex)!=nullptr) + ++nIndex; + aSfxShellStack.reserve(nIndex); + while (nIndex-- > 0) + aSfxShellStack.push_back(mrBase.GetSubShell(nIndex)); + +#if OSL_DEBUG_LEVEL >= 2 + SAL_INFO("sd.view", __func__ << ": Current SFX Stack"); + DumpShellStack(aSfxShellStack); + SAL_INFO("sd.view", __func__ << ": Target Stack"); + DumpShellStack(aTargetStack); +#endif + + // 4. Find the lowest shell in which the two stacks differ. + auto mismatchIters = std::mismatch(aSfxShellStack.begin(), aSfxShellStack.end(), + aTargetStack.begin(), aTargetStack.end()); + ShellStack::iterator iSfxShell (mismatchIters.first); + ShellStack::iterator iTargetShell (mismatchIters.second); + + // 5. Remove all shells above and including the differing shell from the + // SFX stack starting with the shell on top of the stack. + for (std::reverse_iterator<ShellStack::const_iterator> i(aSfxShellStack.end()), iLast(iSfxShell); + i != iLast; ++i) + { + SfxShell* const pShell = *i; + SAL_INFO("sd.view", __func__ << ": removing shell " << pShell << " from stack"); + mrBase.RemoveSubShell(pShell); + } + aSfxShellStack.erase(iSfxShell, aSfxShellStack.end()); + + // 6. Push shells from the given stack onto the SFX stack. + mbShellStackIsUpToDate = false; + while (iTargetShell != aTargetStack.end()) + { + SAL_INFO("sd.view", __func__ << ": pushing shell " << *iTargetShell << " on stack"); + mrBase.AddSubShell(**iTargetShell); + ++iTargetShell; + + // The pushing of the shell on to the shell stack may have lead to + // another invocation of this method. In this case we have to abort + // pushing shells on the stack and return immediately. + if (mbShellStackIsUpToDate) + break; + } + if (mrBase.GetDispatcher() != nullptr) + mrBase.GetDispatcher()->Flush(); + + // Update the pointer to the top-most shell and set its undo manager + // to the one of the previous top-most shell. + mpTopShell = mrBase.GetSubShell(0); + if (mpTopShell!=nullptr && pUndoManager!=nullptr && mpTopShell->GetUndoManager()==nullptr) + mpTopShell->SetUndoManager(pUndoManager); + + // Finally tell an invocation of this method on a higher level that it can (has + // to) abort and return immediately. + mbShellStackIsUpToDate = true; + +#if OSL_DEBUG_LEVEL >= 2 + SAL_INFO("sd.view", __func__ << ": New current stack"); + DumpSfxShellStack(); +#endif +} + +void ViewShellManager::Implementation::TakeShellsFromStack (const SfxShell* pShell) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Remember the undo manager from the top-most shell on the stack. + SfxShell* pTopMostShell = mrBase.GetSubShell(0); + SfxUndoManager* pUndoManager = (pTopMostShell!=nullptr) + ? pTopMostShell->GetUndoManager() + : nullptr; + +#if OSL_DEBUG_LEVEL >= 2 + SAL_INFO("sd.view", __func__ << "TakeShellsFromStack( " << pShell << ")"); + DumpSfxShellStack(); +#endif + + // 0.Make sure that the given shell is on the stack. This is a + // preparation for the following assertion. + for (sal_uInt16 nIndex=0; true; nIndex++) + { + SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex); + if (pShellOnStack == nullptr) + { + // Set pShell to NULL to indicate the following code that the + // shell is not on the stack. + pShell = nullptr; + break; + } + else if (pShellOnStack == pShell) + break; + } + + if (pShell == nullptr) + return; + + // 1. Deactivate our shells on the stack before they are removed so + // that during the Deactivation() calls the stack is still intact. + for (sal_uInt16 nIndex=0; true; nIndex++) + { + SfxShell* pShellOnStack = mrBase.GetSubShell(nIndex); + Deactivate(pShellOnStack); + if (pShellOnStack == pShell) + break; + } + + // 2. Remove the shells from the stack. + while (true) + { + SfxShell* pShellOnStack = mrBase.GetSubShell(0); + SAL_INFO("sd.view", __func__ << "removing shell " << pShellOnStack << " from stack"); + mrBase.RemoveSubShell(pShellOnStack); + if (pShellOnStack == pShell) + break; + } + + // 3. Update the stack. + if (mrBase.GetDispatcher() != nullptr) + mrBase.GetDispatcher()->Flush(); + + // Update the pointer to the top-most shell and set its undo manager + // to the one of the previous top-most shell. + mpTopShell = mrBase.GetSubShell(0); + if (mpTopShell!=nullptr && pUndoManager!=nullptr && mpTopShell->GetUndoManager()==nullptr) + mpTopShell->SetUndoManager(pUndoManager); + +#if OSL_DEBUG_LEVEL >= 2 + SAL_INFO("sd.view", __func__ << "Sfx shell stack is:"); + DumpSfxShellStack(); +#endif +} + +void ViewShellManager::Implementation::CreateShells() +{ + ::osl::MutexGuard aGuard (maMutex); + + // Iterate over all view shells. + ActiveShellList::reverse_iterator iShell; + for (iShell=maActiveViewShells.rbegin(); iShell!=maActiveViewShells.rend(); ++iShell) + { + // Get the list of associated sub shells. + SubShellList::iterator iList (maActiveSubShells.find(iShell->mpShell)); + if (iList != maActiveSubShells.end()) + { + SubShellSubList& rList (iList->second); + + // Iterate over all sub shells of the current view shell. + for (auto & subShell : rList) + { + if (subShell.mpShell == nullptr) + { + subShell = CreateSubShell(iShell->mpShell,subShell.mnId); + } + } + } + } +} + +void ViewShellManager::Implementation::CreateTargetStack (ShellStack& rStack) const +{ + // Create a local stack of the shells that are to push on the shell + // stack. We can thus safely create the required shells while still + // having a valid shell stack. + for (ActiveShellList::const_reverse_iterator iViewShell (maActiveViewShells.rbegin()); + iViewShell != maActiveViewShells.rend(); + ++iViewShell) + { + // Possibly place the form shell below the current view shell. + if ( ! mbFormShellAboveParent + && mpFormShell!=nullptr + && iViewShell->mpShell==mpFormShellParent) + { + rStack.push_back(mpFormShell); + } + + // Put the view shell itself on the local stack. + rStack.push_back (iViewShell->mpShell); + + // Possibly place the form shell above the current view shell. + if (mbFormShellAboveParent + && mpFormShell!=nullptr + && iViewShell->mpShell==mpFormShellParent) + { + rStack.push_back(mpFormShell); + } + + // Add all other sub shells. + SubShellList::const_iterator iList (maActiveSubShells.find(iViewShell->mpShell)); + if (iList != maActiveSubShells.end()) + { + const SubShellSubList& rList (iList->second); + SubShellSubList::const_reverse_iterator iSubShell; + for (iSubShell=rList.rbegin(); iSubShell!=rList.rend(); ++iSubShell) + if (iSubShell->mpShell != mpFormShell) + rStack.push_back(iSubShell->mpShell); + } + } +} + +IMPL_LINK(ViewShellManager::Implementation, WindowEventHandler, VclWindowEvent&, rEvent, void) +{ + vcl::Window* pEventWindow = rEvent.GetWindow(); + + switch (rEvent.GetId()) + { + case VclEventId::WindowGetFocus: + { + for (auto const& activeShell : maActiveViewShells) + { + if (pEventWindow == activeShell.GetWindow()) + { + MoveToTop(*activeShell.mpShell); + break; + } + } + } + break; + + case VclEventId::WindowLoseFocus: + break; + + case VclEventId::ObjectDying: + // Remember that we do not have to remove the window + // listener for this window. + for (auto & activeViewShell : maActiveViewShells) + { + if (activeViewShell.GetWindow() == pEventWindow) + { + activeViewShell.mbIsListenerAddedToWindow = false; + break; + } + } + break; + + default: break; + } +} + +ShellDescriptor ViewShellManager::Implementation::CreateSubShell ( + SfxShell const * pParentShell, + ShellId nShellId) +{ + ::osl::MutexGuard aGuard (maMutex); + ShellDescriptor aResult; + + // Look up the factories for the parent shell. + ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( + maShellFactories.equal_range(pParentShell)); + + // Try all factories to create the shell. + for (FactoryList::const_iterator iFactory=aRange.first; iFactory!=aRange.second; ++iFactory) + { + SharedShellFactory pFactory = iFactory->second; + if (pFactory != nullptr) + aResult.mpShell = pFactory->CreateShell(nShellId); + + // Exit the loop when the shell has been successfully created. + if (aResult.mpShell != nullptr) + { + aResult.mpFactory = pFactory; + aResult.mnId = nShellId; + break; + } + } + + return aResult; +} + +void ViewShellManager::Implementation::DestroyViewShell ( + ShellDescriptor& rDescriptor) +{ + OSL_ASSERT(rDescriptor.mpShell != nullptr); + + if (rDescriptor.mbIsListenerAddedToWindow) + { + rDescriptor.mbIsListenerAddedToWindow = false; + vcl::Window* pWindow = rDescriptor.GetWindow(); + if (pWindow != nullptr) + { + pWindow->RemoveEventListener( + LINK(this, ViewShellManager::Implementation, WindowEventHandler)); + } + } + + // Destroy the sub shell factories. + ::std::pair<FactoryList::iterator,FactoryList::iterator> aRange( + maShellFactories.equal_range(rDescriptor.mpShell)); + if (aRange.first != maShellFactories.end()) + maShellFactories.erase(aRange.first, aRange.second); + + // Release the shell. + if (rDescriptor.mpFactory) + rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell); +} + +void ViewShellManager::Implementation::DestroySubShell ( + const ShellDescriptor& rDescriptor) +{ + OSL_ASSERT(rDescriptor.mpFactory); + rDescriptor.mpFactory->ReleaseShell(rDescriptor.mpShell); +} + +void ViewShellManager::Implementation::InvalidateAllSubShells (const SfxShell* pParentShell) +{ + ::osl::MutexGuard aGuard (maMutex); + + SubShellList::iterator iList (maActiveSubShells.find(pParentShell)); + if (iList != maActiveSubShells.end()) + { + SubShellSubList& rList (iList->second); + for (auto const& shell : rList) + if (shell.mpShell != nullptr) + shell.mpShell->Invalidate(); + } +} + +void ViewShellManager::Implementation::Shutdown() +{ + ::osl::MutexGuard aGuard (maMutex); + + // Take stacked shells from stack. + if ( ! maActiveViewShells.empty()) + { + UpdateLock aLock (*this); + + while ( ! maActiveViewShells.empty()) + { + SfxShell* pShell = maActiveViewShells.front().mpShell; + if (pShell != nullptr) + { + ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell); + if (pViewShell != nullptr) + DeactivateViewShell(*pViewShell); + else + DeactivateShell(*pShell); + } + else + { + SAL_WARN("sd.view", + "ViewShellManager::Implementation::Shutdown(): empty active shell descriptor"); + maActiveViewShells.pop_front(); + } + } + } + mrBase.RemoveSubShell (); + + maShellFactories.clear(); +} + +#if OSL_DEBUG_LEVEL >= 2 +void ViewShellManager::Implementation::DumpShellStack (const ShellStack& rStack) +{ + ShellStack::const_reverse_iterator iEntry; + for (iEntry=rStack.rbegin(); iEntry!=rStack.rend(); ++iEntry) + if (*iEntry != NULL) + SAL_INFO("sd.view", __func__ << ": " << + *iEntry << " : " << + (*iEntry)->GetName()); + else + SAL_INFO("sd.view", __func__ << " null"); +} + +void ViewShellManager::Implementation::DumpSfxShellStack() +{ + ShellStack aSfxShellStack; + sal_uInt16 nIndex (0); + while (mrBase.GetSubShell(nIndex)!=NULL) + ++nIndex; + aSfxShellStack.reserve(nIndex); + while (nIndex-- > 0) + aSfxShellStack.push_back(mrBase.GetSubShell(nIndex)); + DumpShellStack(aSfxShellStack); +} +#endif + +void ViewShellManager::Implementation::Deactivate (SfxShell* pShell) +{ + OSL_ASSERT(pShell!=nullptr); + + // We have to end a text edit for view shells that are to be taken from + // the shell stack. + ViewShell* pViewShell = dynamic_cast<ViewShell*>(pShell); + if (pViewShell != nullptr) + { + sd::View* pView = pViewShell->GetView(); + if (pView!=nullptr && pView->IsTextEdit()) + { + pView->SdrEndTextEdit(); + pView->UnmarkAll(); + pViewShell->GetViewFrame()->GetDispatcher()->Execute( + SID_OBJECT_SELECT, + SfxCallMode::ASYNCHRON); + } + } + + // Now we can deactivate the shell. + pShell->Deactivate(true); +} + +void ViewShellManager::Implementation::SetFormShell ( + const ViewShell* pFormShellParent, + FmFormShell* pFormShell, + bool bFormShellAboveParent) +{ + ::osl::MutexGuard aGuard (maMutex); + + mpFormShellParent = pFormShellParent; + mpFormShell = pFormShell; + mbFormShellAboveParent = bFormShellAboveParent; +} + +namespace { + +ShellDescriptor::ShellDescriptor() + : mpShell(nullptr), + mnId(ToolbarId::None), + mbIsListenerAddedToWindow(false) +{ +} + +ShellDescriptor::ShellDescriptor ( + ShellId nId) + : mpShell(nullptr), + mnId(nId), + mbIsListenerAddedToWindow(false) +{ +} + +vcl::Window* ShellDescriptor::GetWindow() const +{ + ViewShell* pViewShell = dynamic_cast<ViewShell*>(mpShell); + if (pViewShell != nullptr) + return pViewShell->GetActiveWindow(); + else + return nullptr; +} + +} // end of anonymous namespace + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/ViewTabBar.cxx b/sd/source/ui/view/ViewTabBar.cxx new file mode 100644 index 0000000000..099a333ae5 --- /dev/null +++ b/sd/source/ui/view/ViewTabBar.cxx @@ -0,0 +1,536 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ViewTabBar.hxx> + +#include <ViewShellBase.hxx> +#include <framework/FrameworkHelper.hxx> +#include <framework/Pane.hxx> +#include <DrawController.hxx> + +#include <Client.hxx> +#include <utility> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> + +#include <sfx2/viewfrm.hxx> +#include <com/sun/star/drawing/framework/ResourceId.hpp> +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/drawing/framework/XView.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/diagnose_ex.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using ::sd::framework::FrameworkHelper; + +namespace sd { + +namespace { +bool IsEqual (const TabBarButton& rButton1, const TabBarButton& rButton2) +{ + return ((rButton1.ResourceId.is() + && rButton2.ResourceId.is() + && rButton1.ResourceId->compareTo(rButton2.ResourceId) == 0) + || rButton1.ButtonLabel == rButton2.ButtonLabel); +} + +} // end of anonymous namespace + +ViewTabBar::ViewTabBar ( + const Reference<XResourceId>& rxViewTabBarId, + const rtl::Reference<::sd::DrawController>& rxController) + : mpTabControl(VclPtr<TabBarControl>::Create(GetAnchorWindow(rxViewTabBarId,rxController), this)), + mxController(rxController), + mxViewTabBarId(rxViewTabBarId), + mpViewShellBase(nullptr), + mnNoteBookWidthPadding(0) +{ + // Do this manually instead of via uno::Reference, so we don't delete ourselves. + osl_atomic_increment(&m_refCount); + + // Tunnel through the controller and use the ViewShellBase to obtain the + // view frame. + if (mxController) + mpViewShellBase = mxController->GetViewShellBase(); + + // Register as listener at XConfigurationController. + if (mxController.is()) + { + mxConfigurationController = mxController->getConfigurationController(); + if (mxConfigurationController.is()) + { + mxConfigurationController->addConfigurationChangeListener( + this, + FrameworkHelper::msResourceActivationEvent, + Any()); + } + } + + mpTabControl->Show(); + + if (mpViewShellBase != nullptr + && rxViewTabBarId->isBoundToURL( + FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) + { + mpViewShellBase->SetViewTabBar(this); + } + + osl_atomic_decrement(&m_refCount); +} + +ViewTabBar::~ViewTabBar() +{ +} + +void ViewTabBar::disposing(std::unique_lock<std::mutex>&) +{ + if (mpViewShellBase != nullptr + && mxViewTabBarId->isBoundToURL( + FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) + { + mpViewShellBase->SetViewTabBar(nullptr); + } + + if (mxConfigurationController.is()) + { + // Unregister listener from XConfigurationController. + try + { + mxConfigurationController->removeConfigurationChangeListener(this); + } + catch (const lang::DisposedException&) + { + // Receiving a disposed exception is the normal case. Is there + // a way to avoid it? + } + mxConfigurationController = nullptr; + } + + { + const SolarMutexGuard aSolarGuard; + mpTabControl.disposeAndClear(); + } + + mxController = nullptr; +} + +vcl::Window* ViewTabBar::GetAnchorWindow( + const Reference<XResourceId>& rxViewTabBarId, + const rtl::Reference<::sd::DrawController>& rxController) +{ + vcl::Window* pWindow = nullptr; + ViewShellBase* pBase = nullptr; + + // Tunnel through the controller and use the ViewShellBase to obtain the + // view frame. + if (rxController) + pBase = rxController->GetViewShellBase(); + + // The ViewTabBar supports at the moment only the center pane. + if (rxViewTabBarId.is() + && rxViewTabBarId->isBoundToURL( + FrameworkHelper::msCenterPaneURL, AnchorBindingMode_DIRECT)) + { + if (pBase != nullptr) + pWindow = &pBase->GetViewFrame().GetWindow(); + } + + // The rest is (at the moment) just for the emergency case. + if (pWindow == nullptr) + { + Reference<XPane> xPane; + try + { + Reference<XConfigurationController> xCC ( + rxController->getConfigurationController()); + if (xCC.is()) + xPane.set(xCC->getResource(rxViewTabBarId->getAnchor()), UNO_QUERY); + } + catch (const RuntimeException&) + { + } + + // Tunnel through the XWindow to the VCL side. + try + { + if (auto pPane = dynamic_cast<framework::Pane*>(xPane.get())) + pWindow = pPane->GetWindow()->GetParent(); + } + catch (const RuntimeException&) + { + } + } + + return pWindow; +} + +//----- XConfigurationChangeListener ------------------------------------------ + +void SAL_CALL ViewTabBar::notifyConfigurationChange ( + const ConfigurationChangeEvent& rEvent) +{ + if (rEvent.Type == FrameworkHelper::msResourceActivationEvent + && rEvent.ResourceId->getResourceURL().match(FrameworkHelper::msViewURLPrefix) + && rEvent.ResourceId->isBoundTo(mxViewTabBarId->getAnchor(), AnchorBindingMode_DIRECT)) + { + UpdateActiveButton(); + } +} + +//----- XEventListener -------------------------------------------------------- + +void SAL_CALL ViewTabBar::disposing( + const lang::EventObject& rEvent) +{ + if (rEvent.Source == mxConfigurationController) + { + mxConfigurationController = nullptr; + mxController = nullptr; + } +} + +//----- XTabBar --------------------------------------------------------------- + +void SAL_CALL ViewTabBar::addTabBarButtonAfter ( + const TabBarButton& rButton, + const TabBarButton& rAnchor) +{ + const SolarMutexGuard aSolarGuard; + AddTabBarButton(rButton, rAnchor); +} + +void SAL_CALL ViewTabBar::appendTabBarButton (const TabBarButton& rButton) +{ + const SolarMutexGuard aSolarGuard; + AddTabBarButton(rButton); +} + +void SAL_CALL ViewTabBar::removeTabBarButton (const TabBarButton& rButton) +{ + const SolarMutexGuard aSolarGuard; + RemoveTabBarButton(rButton); +} + +sal_Bool SAL_CALL ViewTabBar::hasTabBarButton (const TabBarButton& rButton) +{ + const SolarMutexGuard aSolarGuard; + return HasTabBarButton(rButton); +} + +Sequence<TabBarButton> SAL_CALL ViewTabBar::getTabBarButtons() +{ + const SolarMutexGuard aSolarGuard; + return GetTabBarButtons(); +} + +//----- XResource ------------------------------------------------------------- + +Reference<XResourceId> SAL_CALL ViewTabBar::getResourceId() +{ + return mxViewTabBarId; +} + +sal_Bool SAL_CALL ViewTabBar::isAnchorOnly() +{ + return false; +} + +bool ViewTabBar::ActivatePage(size_t nIndex) +{ + try + { + Reference<XConfigurationController> xConfigurationController ( + mxController->getConfigurationController()); + if ( ! xConfigurationController.is()) + throw RuntimeException(); + Reference<XView> xView; + try + { + xView.set(xConfigurationController->getResource( + ResourceId::create( + ::comphelper::getProcessComponentContext(), + FrameworkHelper::msCenterPaneURL)), + UNO_QUERY); + } + catch (const DeploymentException&) + { + } + + Client* pIPClient = nullptr; + if (mpViewShellBase != nullptr) + pIPClient = dynamic_cast<Client*>(mpViewShellBase->GetIPClient()); + if (pIPClient==nullptr || ! pIPClient->IsObjectInPlaceActive()) + { + if (nIndex < maTabBarButtons.size()) + { + xConfigurationController->requestResourceActivation( + maTabBarButtons[nIndex].ResourceId, + ResourceActivationMode_REPLACE); + } + + return true; + } + } + catch (const RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("sd.view"); + } + + return false; +} + +int ViewTabBar::GetHeight() const +{ + int nHeight (0); + + if (!maTabBarButtons.empty()) + { + if (mpTabControl->IsReallyVisible()) + { + weld::Notebook& rNotebook = mpTabControl->GetNotebook(); + int nAllocatedWidth = mpTabControl->GetAllocatedWidth(); + int nPageWidth = nAllocatedWidth - mnNoteBookWidthPadding; + + // set each page width-request to the size it takes to fit the notebook allocation + for (int nIndex = 1, nPageCount = rNotebook.get_n_pages(); nIndex <= nPageCount; ++nIndex) + { + OUString sIdent(OUString::number(nIndex)); + weld::Container* pContainer = rNotebook.get_page(sIdent); + pContainer->set_size_request(nPageWidth, -1); + } + + // get the height-for-width for this allocation + nHeight = mpTabControl->get_preferred_size().Height(); + } + + if (nHeight <= 0) + { + // Using a default when the real height can not be determined. + // To get correct height this method should be called when the + // control is visible. + nHeight = 21; + } + } + + return nHeight; +} + +void ViewTabBar::AddTabBarButton ( + const css::drawing::framework::TabBarButton& rButton, + const css::drawing::framework::TabBarButton& rAnchor) +{ + TabBarButtonList::size_type nIndex; + + if ( ! rAnchor.ResourceId.is() + || (rAnchor.ResourceId->getResourceURL().isEmpty() + && rAnchor.ButtonLabel.isEmpty())) + { + nIndex = 0; + } + else + { + for (nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) + { + if (IsEqual(maTabBarButtons[nIndex], rAnchor)) + { + ++nIndex; + break; + } + } + } + + AddTabBarButton(rButton,nIndex); +} + +void ViewTabBar::AddTabBarButton ( + const css::drawing::framework::TabBarButton& rButton) +{ + AddTabBarButton(rButton, maTabBarButtons.size()); +} + +void ViewTabBar::AddTabBarButton ( + const css::drawing::framework::TabBarButton& rButton, + sal_Int32 nPosition) +{ + if (nPosition >= 0 && + nPosition <= mpTabControl->GetNotebook().get_n_pages()) + { + // Insert the button into our local array. + maTabBarButtons.insert(maTabBarButtons.begin() + nPosition, rButton); + UpdateTabBarButtons(); + UpdateActiveButton(); + } +} + +void ViewTabBar::RemoveTabBarButton ( + const css::drawing::framework::TabBarButton& rButton) +{ + for (TabBarButtonList::size_type nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) + { + if (IsEqual(maTabBarButtons[nIndex], rButton)) + { + maTabBarButtons.erase(maTabBarButtons.begin()+nIndex); + UpdateTabBarButtons(); + UpdateActiveButton(); + break; + } + } +} + +bool ViewTabBar::HasTabBarButton ( + const css::drawing::framework::TabBarButton& rButton) +{ + bool bResult (false); + + for (const css::drawing::framework::TabBarButton & r : maTabBarButtons) + { + if (IsEqual(r, rButton)) + { + bResult = true; + break; + } + } + + return bResult; +} + +css::uno::Sequence<css::drawing::framework::TabBarButton> + ViewTabBar::GetTabBarButtons() +{ + return comphelper::containerToSequence(maTabBarButtons); +} + +void ViewTabBar::UpdateActiveButton() +{ + Reference<XView> xView; + if (mpViewShellBase != nullptr) + xView = FrameworkHelper::Instance(*mpViewShellBase)->GetView( + mxViewTabBarId->getAnchor()); + if (!xView.is()) + return; + + Reference<XResourceId> xViewId (xView->getResourceId()); + for (size_t nIndex=0; nIndex<maTabBarButtons.size(); ++nIndex) + { + if (maTabBarButtons[nIndex].ResourceId->compareTo(xViewId) == 0) + { + mpTabControl->GetNotebook().set_current_page(nIndex); + break; + } + } +} + +void ViewTabBar::UpdateTabBarButtons() +{ + int nMaxPageWidthReq(0); + + weld::Notebook& rNotebook = mpTabControl->GetNotebook(); + int nPageCount(rNotebook.get_n_pages()); + int nIndex = 1; + for (const auto& rTab : maTabBarButtons) + { + OUString sIdent(OUString::number(nIndex)); + // Create a new tab when there are not enough. + if (nPageCount < nIndex) + rNotebook.append_page(sIdent, rTab.ButtonLabel); + else + { + // Update the tab. + rNotebook.set_tab_label_text(sIdent, rTab.ButtonLabel); + } + + // Set a fairly arbitrary initial width request for the pages so we can + // measure what extra width the notebook itself uses + weld::Container* pContainer = rNotebook.get_page(sIdent); + int nTextWidth = pContainer->get_pixel_size(rTab.ButtonLabel).Width(); + pContainer->set_size_request(nTextWidth, -1); + nMaxPageWidthReq = std::max(nMaxPageWidthReq, nTextWidth); + + ++nIndex; + } + + // Delete tabs that are no longer used. + for (; nIndex<=nPageCount; ++nIndex) + rNotebook.remove_page(OUString::number(nIndex)); + + int nWidthReq = rNotebook.get_preferred_size().Width(); + // The excess width over the page request that the notebook uses we will + // use this later to help measure the best height-for-width given the + // eventual allocated width of the notebook + mnNoteBookWidthPadding = nWidthReq - nMaxPageWidthReq; +} + +//===== TabBarControl ========================================================= + +TabBarControl::TabBarControl ( + vcl::Window* pParentWindow, + ::rtl::Reference<ViewTabBar> pViewTabBar) + : InterimItemWindow(pParentWindow, "modules/simpress/ui/tabviewbar.ui", "TabViewBar") + , mxTabControl(m_xBuilder->weld_notebook("tabcontrol")) + , mpViewTabBar(std::move(pViewTabBar)) + , mnAllocatedWidth(0) +{ + // Because the actual window background is transparent--to avoid + // flickering due to multiple background paintings by this and by child + // windows--we have to paint the background for this control explicitly: + // the actual control is not painted over its whole bounding box. + SetPaintTransparent(false); + SetBackground(Application::GetSettings().GetStyleSettings().GetDialogColor()); + + InitControlBase(mxTabControl.get()); + + mxTabControl->connect_enter_page(LINK(this, TabBarControl, ActivatePageHdl)); + mxTabControl->connect_size_allocate(LINK(this, TabBarControl, NotebookSizeAllocHdl)); +} + +void TabBarControl::dispose() +{ + mxTabControl.reset(); + InterimItemWindow::dispose(); +} + +TabBarControl::~TabBarControl() +{ + disposeOnce(); +} + +IMPL_LINK(TabBarControl, NotebookSizeAllocHdl, const Size&, rSize, void) +{ + mnAllocatedWidth = rSize.Width(); +} + +IMPL_LINK(TabBarControl, ActivatePageHdl, const OUString&, rPage, void) +{ + if (!mpViewTabBar->ActivatePage(mxTabControl->get_page_index(rPage))) + { + // When we run into this else branch then we have an active OLE + // object. We ignore the request to switch views. Additionally + // we put the active tab back to the one for the current view. + mpViewTabBar->UpdateActiveButton(); + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/WindowUpdater.cxx b/sd/source/ui/view/WindowUpdater.cxx new file mode 100644 index 0000000000..3aa53fe0d2 --- /dev/null +++ b/sd/source/ui/view/WindowUpdater.cxx @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <WindowUpdater.hxx> +#include <drawdoc.hxx> + +#include <vcl/outdev.hxx> +#include <vcl/vclptr.hxx> +#include <vcl/window.hxx> + +#include <algorithm> + +namespace sd { + +WindowUpdater::WindowUpdater() + : mpDocument (nullptr) +{ + maCTLOptions.AddListener(this); +} + +WindowUpdater::~WindowUpdater() noexcept +{ + maCTLOptions.RemoveListener(this); +} + +void WindowUpdater::RegisterWindow (vcl::Window* pWindow) +{ + if (pWindow != nullptr) + { + tWindowList::iterator aWindowIterator ( + ::std::find ( + maWindowList.begin(), maWindowList.end(), pWindow)); + if (aWindowIterator == maWindowList.end()) + { + // Update the device once right now and add it to the list. + Update (pWindow->GetOutDev()); + maWindowList.emplace_back(pWindow); + } + } +} + +void WindowUpdater::UnregisterWindow (vcl::Window* pWindow) +{ + tWindowList::iterator aWindowIterator ( + ::std::find ( + maWindowList.begin(), maWindowList.end(), pWindow)); + if (aWindowIterator != maWindowList.end()) + { + maWindowList.erase (aWindowIterator); + } +} + +void WindowUpdater::SetDocument (SdDrawDocument* pDocument) +{ + mpDocument = pDocument; +} + +/*static*/ void WindowUpdater::Update (OutputDevice* pDevice) +{ + if (pDevice != nullptr) + { + UpdateWindow (pDevice); + } +} + +/*static*/ void WindowUpdater::UpdateWindow (OutputDevice* pDevice) +{ + if (pDevice == nullptr) + return; + + SvtCTLOptions::TextNumerals aNumeralMode (SvtCTLOptions::GetCTLTextNumerals()); + + LanguageType aLanguage; + // Now this is a bit confusing. The numerals in arabic languages + // are Hindi numerals and what the western world generally uses are + // arabic numerals. The digits used in the Hindi language are not + // used at all. + switch (aNumeralMode) + { + case SvtCTLOptions::NUMERALS_HINDI: + aLanguage = LANGUAGE_ARABIC_SAUDI_ARABIA; + break; + + case SvtCTLOptions::NUMERALS_SYSTEM: + aLanguage = LANGUAGE_SYSTEM; + break; + + case SvtCTLOptions::NUMERALS_ARABIC: + default: + aLanguage = LANGUAGE_ENGLISH; + break; + } + + pDevice->SetDigitLanguage (aLanguage); +} + +void WindowUpdater::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints ) +{ + // Set the current state at all registered output devices. + for (auto& rxWindow : maWindowList) + Update (rxWindow->GetOutDev()); + + // Reformat the document for the modified state to take effect. + if (mpDocument != nullptr) + mpDocument->ReformatAllTextObjects(); + + // Invalidate the windows to make the modified state visible. + for (auto& rxWindow : maWindowList) + rxWindow->Invalidate(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/clview.cxx b/sd/source/ui/view/clview.cxx new file mode 100644 index 0000000000..9f11839da2 --- /dev/null +++ b/sd/source/ui/view/clview.cxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ClientView.hxx> +#include <drawview.hxx> + +namespace sd +{ +class DrawDocShell; +class DrawViewShell; + +/** + * ClientView is used for DrawDocShell::Draw() + */ + +ClientView::ClientView(DrawDocShell* pDocSh, OutputDevice* pOutDev) + : DrawView(pDocSh, pOutDev, nullptr) +{ +} + +ClientView::~ClientView() {} + +/** + * If View should not Invalidate() the windows, this method has + * to be overridden and properly handled. + */ + +void ClientView::InvalidateOneWin(OutputDevice& rWin) +{ + vcl::Region aRegion; + CompleteRedraw(&rWin, aRegion); +} + +/** + * If View should not Invalidate() the windows, this method has + * to be overridden and properly handled. + */ + +void ClientView::InvalidateOneWin(OutputDevice& rWin, const ::tools::Rectangle& rRect) +{ + CompleteRedraw(&rWin, vcl::Region(rRect)); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drawview.cxx b/sd/source/ui/view/drawview.cxx new file mode 100644 index 0000000000..69555bb741 --- /dev/null +++ b/sd/source/ui/view/drawview.cxx @@ -0,0 +1,621 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svl/style.hxx> +#include <editeng/outliner.hxx> +#include <svx/svdotext.hxx> +#include <svl/poolitem.hxx> +#include <editeng/eeitem.hxx> +#include <svl/whiter.hxx> +#include <sal/log.hxx> +#include <tools/debug.hxx> + +#include <svx/svdundo.hxx> +#include <svx/strings.hrc> +#include <svx/dialmgr.hxx> + +#include <strings.hrc> +#include <View.hxx> +#include <drawview.hxx> +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <sdpage.hxx> +#include <ViewShellBase.hxx> +#include <DrawViewShell.hxx> +#include <pres.hxx> +#include <sdresid.hxx> +#include <unchss.hxx> +#include <slideshow.hxx> + +#include <undo/undomanager.hxx> + +using namespace ::com::sun::star; + +namespace sd { + + +/** + * Shows the first page of document at position 0,0. In the case + * that there is no page a page is created. + */ + +DrawView::DrawView( + DrawDocShell* pDocSh, + OutputDevice* pOutDev, + DrawViewShell* pShell) +: ::sd::View(*pDocSh->GetDoc(), pOutDev, pShell) + ,mpDocShell(pDocSh) + ,mpDrawViewShell(pShell) + ,mnPOCHSmph(0) +{ + SetCurrentObj(SdrObjKind::Rectangle); +} + +DrawView::~DrawView() +{ +} + +/** + * Virtual method from SdrView, called at selection change. + */ + +void DrawView::MarkListHasChanged() +{ + ::sd::View::MarkListHasChanged(); + + if (mpDrawViewShell) + mpDrawViewShell->SelectionHasChanged(); +} + +/** + * Virtual method from SdrView, called at model change. + */ + +void DrawView::ModelHasChanged() +{ + ::sd::View::ModelHasChanged(); + + // force framer to rerender + SfxStyleSheetBasePool* pSSPool = mrDoc.GetStyleSheetPool(); + pSSPool->Broadcast(SfxStyleSheetPoolHint()); + + if( mpDrawViewShell ) + mpDrawViewShell->ModelHasChanged(); + +} + +/** + * Redirect attributes onto title and outline text and background + * rectangle of a masterpage into templates, otherwise pass on baseclass. + */ + +bool DrawView::SetAttributes(const SfxItemSet& rSet, + bool bReplaceAll, bool bSlide, bool bMaster) +{ + bool bOk = false; + + if (mpDrawViewShell && bMaster) + { + SfxStyleSheetBasePool* pStShPool = mrDoc.GetStyleSheetPool(); + SdPage& rPage = *mpDrawViewShell->getCurrentPage(); + SdrPage& rMasterPage = rPage.TRG_GetMasterPage(); + for (const rtl::Reference<SdrObject>& pObject : rMasterPage) + SetMasterAttributes(pObject.get(), rPage, rSet, pStShPool, bOk, bMaster, bSlide); + return bOk; + } + if (mpDrawViewShell && bSlide) + { + SfxStyleSheetBasePool* pStShPool = mrDoc.GetStyleSheetPool(); + SdPage& rPage = *mpDrawViewShell->getCurrentPage(); + for (const rtl::Reference<SdrObject>& pObject : rPage) + SetMasterAttributes(pObject.get(), rPage, rSet, pStShPool, bOk, bMaster, bSlide); + return bOk; + } + + // is there a masterpage edit? + if ( mpDrawViewShell && (mpDrawViewShell->GetEditMode() == EditMode::MasterPage) ) + { + SfxStyleSheetBasePool* pStShPool = mrDoc.GetStyleSheetPool(); + SdPage& rPage = *mpDrawViewShell->getCurrentPage(); + SdrTextObj* pEditObject = GetTextEditObject(); + + if (pEditObject) + { + // Textedit + + SdrInventor nInv = pEditObject->GetObjInventor(); + + if (nInv == SdrInventor::Default) + { + SdrObjKind eObjKind = pEditObject->GetObjIdentifier(); + PresObjKind ePresObjKind = rPage.GetPresObjKind(pEditObject); + + if ( ePresObjKind == PresObjKind::Title || + ePresObjKind == PresObjKind::Notes ) + { + // Presentation object (except outline) + SfxStyleSheet* pSheet = rPage.GetStyleSheetForPresObj( ePresObjKind ); + DBG_ASSERT(pSheet, "StyleSheet not found"); + + SfxItemSet aTempSet( pSheet->GetItemSet() ); + aTempSet.Put( rSet ); + aTempSet.ClearInvalidItems(); + + // Undo-Action + mpDocSh->GetUndoManager()->AddUndoAction( + std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet)); + + pSheet->GetItemSet().Put(aTempSet); + pSheet->Broadcast(SfxHint(SfxHintId::DataChanged)); + bOk = true; + } + else if (eObjKind == SdrObjKind::OutlineText) + { + // Presentation object outline + OutlinerView* pOV = GetTextEditOutlinerView(); + ::Outliner* pOutliner = pOV->GetOutliner(); + + pOutliner->SetUpdateLayout(false); + mpDocSh->SetWaitCursor( true ); + + // replace placeholder by template name + OUString aComment(SdResId(STR_UNDO_CHANGE_PRES_OBJECT)); + aComment = aComment.replaceFirst("$", SdResId(STR_PSEUDOSHEET_OUTLINE)); + mpDocSh->GetUndoManager()->EnterListAction( aComment, OUString(), 0, mpDrawViewShell->GetViewShellBase().GetViewShellId() ); + + std::vector<Paragraph*> aSelList; + pOV->CreateSelectionList(aSelList); + + std::vector<Paragraph*>::reverse_iterator iter = aSelList.rbegin(); + Paragraph* pPara = iter != aSelList.rend() ? *iter : nullptr; + + while (pPara) + { + sal_Int32 nParaPos = pOutliner->GetAbsPos( pPara ); + sal_Int16 nDepth = pOutliner->GetDepth( nParaPos ); + OUString aName = rPage.GetLayoutName() + " " + + OUString::number((nDepth <= 0) ? 1 : nDepth + 1); + SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>(pStShPool->Find(aName, SfxStyleFamily::Page)); + //We have no stylesheet if we access outline level 10 + //in the master preview, there is no true style backing + //that entry + SAL_WARN_IF(!pSheet, "sd", "StyleSheet " << aName << " not found"); + if (pSheet) + { + SfxItemSet aTempSet( pSheet->GetItemSet() ); + aTempSet.Put( rSet ); + aTempSet.ClearInvalidItems(); + + if( nDepth > 0 && aTempSet.GetItemState( EE_PARA_NUMBULLET ) == SfxItemState::SET ) + { + // no SvxNumBulletItem in outline level 1 to 8! + aTempSet.ClearItem( EE_PARA_NUMBULLET ); + } + + // Undo-Action + mpDocSh->GetUndoManager()->AddUndoAction( + std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet)); + + pSheet->GetItemSet().Put(aTempSet); + pSheet->Broadcast(SfxHint(SfxHintId::DataChanged)); + + // now also broadcast any child sheets + sal_Int16 nChild; + for( nChild = nDepth + 1; nChild < 9; nChild++ ) + { + OUString aSheetName = rPage.GetLayoutName() + " " + + OUString::number((nChild <= 0) ? 1 : nChild + 1); + SfxStyleSheet* pOutlSheet = static_cast< SfxStyleSheet* >(pStShPool->Find(aSheetName, SfxStyleFamily::Page)); + + if( pOutlSheet ) + pOutlSheet->Broadcast(SfxHint(SfxHintId::DataChanged)); + } + } + + ++iter; + pPara = iter != aSelList.rend() ? *iter : nullptr; + + bool bJumpToLevel1 = false; + if( !pPara && nDepth > 0 && rSet.GetItemState( EE_PARA_NUMBULLET ) == SfxItemState::SET ) + bJumpToLevel1 = true; + + if (bJumpToLevel1) + { + iter = aSelList.rend(); + --iter; + + if (pOutliner->GetDepth(pOutliner->GetAbsPos(*iter)) > 0) + pPara = pOutliner->GetParagraph( 0 ); // Put NumBulletItem in outline level 1 + } + } + + mpDocSh->SetWaitCursor( false ); + pOV->GetOutliner()->SetUpdateLayout(true); + + mpDocSh->GetUndoManager()->LeaveListAction(); + + bOk = true; + } + else + { + bOk = ::sd::View::SetAttributes(rSet, bReplaceAll); + } + } + } + else + { + // Selection + const SdrMarkList& rList = GetMarkedObjectList(); + const size_t nMarkCount = rList.GetMarkCount(); + for (size_t nMark = 0; nMark < nMarkCount; ++nMark) + { + SdrObject* pObject = rList.GetMark(nMark)->GetMarkedSdrObj(); + SetMasterAttributes(pObject, rPage, rSet, pStShPool, bOk, bMaster, bSlide); + } + + if(!bOk) + bOk = ::sd::View::SetAttributes(rSet, bReplaceAll); + } + } + else // not at masterpage + { + bOk = ::sd::View::SetAttributes(rSet, bReplaceAll); + } + + return bOk; +} + +void DrawView::SetMasterAttributes( SdrObject* pObject, const SdPage& rPage, SfxItemSet rSet, SfxStyleSheetBasePool* pStShPool, bool& bOk, bool bMaster, bool bSlide ) +{ + SdrInventor nInv = pObject->GetObjInventor(); + + if (nInv != SdrInventor::Default) + return; + + SdrObjKind eObjKind = pObject->GetObjIdentifier(); + PresObjKind ePresObjKind = rPage.GetPresObjKind(pObject); + if (bSlide && eObjKind == SdrObjKind::Text) + { + // Presentation object (except outline) + SfxStyleSheet* pSheet = rPage.GetTextStyleSheetForObject(pObject); + DBG_ASSERT(pSheet, "StyleSheet not found"); + + SfxItemSet aTempSet( pSheet->GetItemSet() ); + aTempSet.Put( rSet ); + aTempSet.ClearInvalidItems(); + + // Undo-Action + mpDocSh->GetUndoManager()->AddUndoAction( + std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet)); + + pSheet->GetItemSet().Put(aTempSet,false); + pSheet->Broadcast(SfxHint(SfxHintId::DataChanged)); + bOk = true; + } + + if (!bSlide && + (ePresObjKind == PresObjKind::Title || + ePresObjKind == PresObjKind::Notes)) + { + // Presentation object (except outline) + SfxStyleSheet* pSheet = rPage.GetStyleSheetForPresObj( ePresObjKind ); + DBG_ASSERT(pSheet, "StyleSheet not found"); + + SfxItemSet aTempSet( pSheet->GetItemSet() ); + aTempSet.Put( rSet ); + aTempSet.ClearInvalidItems(); + + // Undo-Action + mpDocSh->GetUndoManager()->AddUndoAction( + std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet)); + + pSheet->GetItemSet().Put(aTempSet,false); + pSheet->Broadcast(SfxHint(SfxHintId::DataChanged)); + bOk = true; + } + else if (eObjKind == SdrObjKind::OutlineText) + { + // tdf#127900: do not forget to apply master style to placeholders + if (!rSet.HasItem(EE_PARA_NUMBULLET) || bMaster) + { + // Presentation object outline + for (sal_uInt16 nLevel = 9; nLevel > 0; nLevel--) + { + OUString aName = rPage.GetLayoutName() + " " + + OUString::number(nLevel); + SfxStyleSheet* pSheet = static_cast<SfxStyleSheet*>(pStShPool-> + Find(aName, SfxStyleFamily::Page)); + DBG_ASSERT(pSheet, "StyleSheet not found"); + + SfxItemSet aTempSet( pSheet->GetItemSet() ); + + if( nLevel > 1 ) + { + // for all levels over 1, clear all items that will be + // hard set to level 1 + SfxWhichIter aWhichIter(rSet); + sal_uInt16 nWhich(aWhichIter.FirstWhich()); + while( nWhich ) + { + if( SfxItemState::SET == aWhichIter.GetItemState() ) + aTempSet.ClearItem( nWhich ); + nWhich = aWhichIter.NextWhich(); + } + + } + else + { + // put the items hard into level one + aTempSet.Put( rSet ); + } + + aTempSet.ClearInvalidItems(); + + // Undo-Action + mpDocSh->GetUndoManager()->AddUndoAction( + std::make_unique<StyleSheetUndoAction>(&mrDoc, pSheet, &aTempSet)); + + pSheet->GetItemSet().Set(aTempSet,false); + pSheet->Broadcast(SfxHint(SfxHintId::DataChanged)); + } + + // remove all hard set items from shape that are now set in style + SfxWhichIter aWhichIter(rSet); + sal_uInt16 nWhich(aWhichIter.FirstWhich()); + while( nWhich ) + { + if( SfxItemState::SET == aWhichIter.GetItemState() ) + pObject->ClearMergedItem( nWhich ); + nWhich = aWhichIter.NextWhich(); + } + } + else + pObject->SetMergedItemSet(rSet); + + bOk = true; + } +} + +/** + * Notify for change of site arrangement + */ + +void DrawView::Notify(SfxBroadcaster& rBC, const SfxHint& rHint) +{ + if ( mpDrawViewShell && rHint.GetId() == SfxHintId::ThisIsAnSdrHint ) + { + SdrHintKind eHintKind = static_cast<const SdrHint&>(rHint).GetKind(); + + if ( mnPOCHSmph == 0 && eHintKind == SdrHintKind::PageOrderChange ) + { + mpDrawViewShell->ResetActualPage(); + } + else if ( eHintKind == SdrHintKind::LayerChange || eHintKind == SdrHintKind::LayerOrderChange ) + { + mpDrawViewShell->ResetActualLayer(); + } + + // switch to that page when it's not a master page + if(SdrHintKind::SwitchToPage == eHintKind) + { + // We switch page only in the current view, which triggered this event + // and keep other views untouched. + SfxViewShell* pViewShell = SfxViewShell::Current(); + if(pViewShell && pViewShell != &mpDrawViewShell->GetViewShellBase()) + return; + + const SdrPage* pPage = static_cast<const SdrHint&>(rHint).GetPage(); + if(pPage && !pPage->IsMasterPage()) + { + if(mpDrawViewShell->GetActualPage() != pPage) + { + sal_uInt16 nPageNum = (pPage->GetPageNum() - 1) / 2; // Sdr --> Sd + mpDrawViewShell->SwitchPage(nPageNum); + } + } + } + } + + ::sd::View::Notify(rBC, rHint); +} + +/** + * Lock/Unlock PageOrderChangedHint + */ + +void DrawView::BlockPageOrderChangedHint(bool bBlock) +{ + if (bBlock) + mnPOCHSmph++; + else + { + DBG_ASSERT(mnPOCHSmph, "counter overflow"); + mnPOCHSmph--; + } +} + +/** + * If presentation objects are selected, intercept stylesheet-positioning at + * masterpage. + */ + +bool DrawView::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr) +{ + bool bResult = true; + + // is there a masterpage edit? + if (mpDrawViewShell && mpDrawViewShell->GetEditMode() == EditMode::MasterPage) + { + if (IsPresObjSelected(false)) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(mpDrawViewShell->GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + bResult = false; + } + else + { + bResult = ::sd::View::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr); + } + } + else + { + bResult = ::sd::View::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr); + } + return bResult; +} + +/** + * Paint-method: Redirect event to the view + */ + +void DrawView::CompleteRedraw(OutputDevice* pOutDev, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector /*=0*/) +{ + SdDrawDocument* pDoc = mpDocShell->GetDoc(); + if( pDoc && pDoc->GetDocumentType() == DocumentType::Impress) + { + rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( pDoc ) ); + if(xSlideshow.is() && xSlideshow->isRunning()) + { + OutputDevice* pShowWindow = xSlideshow->getShowWindow(); + if( (pShowWindow == pOutDev) || (xSlideshow->getAnimationMode() == ANIMATIONMODE_PREVIEW) ) + { + if( pShowWindow == pOutDev && mpViewSh ) + xSlideshow->paint(); + return; + } + } + } + + ::sd::View::CompleteRedraw(pOutDev, rReg, pRedirector); +} + +/** + * Make passed region visible (scrolling if necessary) + */ + +void DrawView::MakeVisible(const ::tools::Rectangle& rRect, vcl::Window& rWin) +{ + if (!rRect.IsEmpty() && mpDrawViewShell) + { + mpDrawViewShell->MakeVisible(rRect, rWin); + } +} + +/** + * Hide page. + */ + +void DrawView::HideSdrPage() +{ + if (mpDrawViewShell) + { + mpDrawViewShell->HidePage(); + } + + ::sd::View::HideSdrPage(); +} + +void DrawView::DeleteMarked() +{ + sd::UndoManager* pUndoManager = mrDoc.GetUndoManager(); + DBG_ASSERT( pUndoManager, "sd::DrawView::DeleteMarked(), ui action without undo manager!?" ); + + if( pUndoManager ) + { + OUString aUndo(SvxResId(STR_EditDelete)); + aUndo = aUndo.replaceFirst("%1", GetDescriptionOfMarkedObjects()); + ViewShellId nViewShellId = mpDrawViewShell ? mpDrawViewShell->GetViewShellBase().GetViewShellId() : ViewShellId(-1); + pUndoManager->EnterListAction(aUndo, aUndo, 0, nViewShellId); + } + + SdPage* pPage = nullptr; + bool bResetLayout = false; + + const size_t nMarkCount = GetMarkedObjectList().GetMarkCount(); + if( nMarkCount ) + { + SdrMarkList aList( GetMarkedObjectList() ); + for (size_t nMark = 0; nMark < nMarkCount; ++nMark) + { + SdrObject* pObj = aList.GetMark(nMark)->GetMarkedSdrObj(); + if( pObj && !pObj->IsEmptyPresObj() && pObj->GetUserCall() ) + { + pPage = static_cast< SdPage* >( pObj->getSdrPageFromSdrObject() ); + if (pPage) + { + PresObjKind ePresObjKind(pPage->GetPresObjKind(pObj)); + switch( ePresObjKind ) + { + case PresObjKind::NONE: + continue; // ignore it + case PresObjKind::Graphic: + case PresObjKind::Object: + case PresObjKind::Chart: + case PresObjKind::OrgChart: + case PresObjKind::Table: + case PresObjKind::Calc: + case PresObjKind::Media: + ePresObjKind = PresObjKind::Outline; + break; + default: + break; + } + SdrTextObj* pTextObj = DynCastSdrTextObj( pObj ); + bool bVertical = pTextObj && pTextObj->IsVerticalWriting(); + ::tools::Rectangle aRect( pObj->GetLogicRect() ); + SdrObject* pNewObj = pPage->InsertAutoLayoutShape( nullptr, ePresObjKind, bVertical, aRect, true ); + + // pUndoManager should not be NULL (see assert above) + // but since we have defensive code + // for it earlier and later in the function + // we might as well be consistent + if(pUndoManager) + { + // Move the new PresObj to the position before the + // object it will replace. + pUndoManager->AddUndoAction( + mrDoc.GetSdrUndoFactory().CreateUndoObjectOrdNum( + *pNewObj, + pNewObj->GetOrdNum(), + pObj->GetOrdNum())); + } + pPage->SetObjectOrdNum( pNewObj->GetOrdNum(), pObj->GetOrdNum() ); + + bResetLayout = true; + } + } + } + } + + ::sd::View::DeleteMarked(); + + if( pPage && bResetLayout ) + pPage->SetAutoLayout( pPage->GetAutoLayout() ); + + if( pUndoManager ) + pUndoManager->LeaveListAction(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drbezob.cxx b/sd/source/ui/view/drbezob.cxx new file mode 100644 index 0000000000..0db363aa21 --- /dev/null +++ b/sd/source/ui/view/drbezob.cxx @@ -0,0 +1,320 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <BezierObjectBar.hxx> +#include <sfx2/msg.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/objface.hxx> + +#include <svx/svxids.hrc> +#include <svl/eitem.hxx> +#include <sfx2/request.hxx> +#include <svx/svdopath.hxx> +#include <svx/svdundo.hxx> +#include <sfx2/dispatch.hxx> + +#include <sdresid.hxx> + + +#include <strings.hrc> + +#include <DrawDocShell.hxx> +#include <ViewShell.hxx> +#include <drawdoc.hxx> +#include <fusel.hxx> +#include <fuconbez.hxx> + +using namespace sd; +#define ShellClass_BezierObjectBar +#include <sdslots.hxx> + +namespace sd { + +/** + * Declare default interface (Slotmap must not be empty) + */ +SFX_IMPL_INTERFACE(BezierObjectBar, ::SfxShell) + +void BezierObjectBar::InitInterface_Impl() +{ +} + + +BezierObjectBar::BezierObjectBar( + ViewShell* pSdViewShell, + ::sd::View* pSdView) + : SfxShell(pSdViewShell->GetViewShell()), + mpView(pSdView), + mpViewSh(pSdViewShell) +{ + DrawDocShell* pDocShell = mpViewSh->GetDocSh(); + SetPool(&pDocShell->GetPool()); + SetUndoManager(pDocShell->GetUndoManager()); + SetRepeatTarget(mpView); +} + +BezierObjectBar::~BezierObjectBar() +{ + SetRepeatTarget(nullptr); +} + +/** + * Status of attribute items. + */ + +void BezierObjectBar::GetAttrState(SfxItemSet& rSet) +{ + SfxItemSet aAttrSet( mpView->GetDoc().GetPool() ); + mpView->GetAttributes( aAttrSet ); + rSet.Put(aAttrSet, false); // <- sal_False, so DontCare-Status gets acquired + + rtl::Reference<FuPoor> xFunc( mpViewSh->GetCurrentFunction() ); + + if(xFunc.is()) + { + if( auto pFuSelection = dynamic_cast< const FuSelection *>( xFunc.get() )) + { + sal_uInt16 nEditMode = pFuSelection->GetEditMode(); + rSet.Put(SfxBoolItem(nEditMode, true)); + } + else if( auto pFuPolygon = dynamic_cast< const FuConstructBezierPolygon *>( xFunc.get() )) + { + sal_uInt16 nEditMode = pFuPolygon->GetEditMode(); + rSet.Put(SfxBoolItem(nEditMode, true)); + } + } + + if(!mpView->IsMoveAllowed() || !mpView->IsResizeAllowed()) + { + // #i77187# if object is move and/or size protected, do not allow point editing at all + rSet.DisableItem(SID_BEZIER_MOVE); + rSet.DisableItem(SID_BEZIER_INSERT); + + rSet.DisableItem(SID_BEZIER_DELETE); + rSet.DisableItem(SID_BEZIER_CUTLINE); + rSet.DisableItem(SID_BEZIER_CONVERT); + + rSet.DisableItem(SID_BEZIER_EDGE); + rSet.DisableItem(SID_BEZIER_SMOOTH); + rSet.DisableItem(SID_BEZIER_SYMMTR); + + rSet.DisableItem(SID_BEZIER_CLOSE); + + rSet.DisableItem(SID_BEZIER_ELIMINATE_POINTS); + } + else + { + IPolyPolygonEditorController* pIPPEC = nullptr; + if( mpView->GetMarkedObjectList().GetMarkCount() ) + pIPPEC = mpView; + else + pIPPEC = dynamic_cast< IPolyPolygonEditorController* >( mpView->getSmartTags().getSelected().get() ); + + if ( !pIPPEC || !pIPPEC->IsRipUpAtMarkedPointsPossible()) + { + rSet.DisableItem(SID_BEZIER_CUTLINE); + } + if (!pIPPEC || !pIPPEC->IsDeleteMarkedPointsPossible()) + { + rSet.DisableItem(SID_BEZIER_DELETE); + } + if (!pIPPEC || !pIPPEC->IsSetMarkedSegmentsKindPossible()) + { + rSet.DisableItem(SID_BEZIER_CONVERT); + } + else + { + SdrPathSegmentKind eSegm = pIPPEC->GetMarkedSegmentsKind(); + switch (eSegm) + { + case SdrPathSegmentKind::DontCare: rSet.InvalidateItem(SID_BEZIER_CONVERT); break; + case SdrPathSegmentKind::Line : rSet.Put(SfxBoolItem(SID_BEZIER_CONVERT,false)); break; // Button down = curve + case SdrPathSegmentKind::Curve : rSet.Put(SfxBoolItem(SID_BEZIER_CONVERT,true)); break; + default: break; + } + } + if (!pIPPEC || !pIPPEC->IsSetMarkedPointsSmoothPossible()) + { + rSet.DisableItem(SID_BEZIER_EDGE); + rSet.DisableItem(SID_BEZIER_SMOOTH); + rSet.DisableItem(SID_BEZIER_SYMMTR); + } + else + { + SdrPathSmoothKind eSmooth = pIPPEC->GetMarkedPointsSmooth(); + switch (eSmooth) + { + case SdrPathSmoothKind::DontCare : break; + case SdrPathSmoothKind::Angular : rSet.Put(SfxBoolItem(SID_BEZIER_EDGE, true)); break; + case SdrPathSmoothKind::Asymmetric: rSet.Put(SfxBoolItem(SID_BEZIER_SMOOTH,true)); break; + case SdrPathSmoothKind::Symmetric : rSet.Put(SfxBoolItem(SID_BEZIER_SYMMTR,true)); break; + } + } + if (!pIPPEC || !pIPPEC->IsOpenCloseMarkedObjectsPossible()) + { + rSet.DisableItem(SID_BEZIER_CLOSE); + } + else + { + SdrObjClosedKind eClose = pIPPEC->GetMarkedObjectsClosedState(); + switch (eClose) + { + case SdrObjClosedKind::DontCare: rSet.InvalidateItem(SID_BEZIER_CLOSE); break; + case SdrObjClosedKind::Open : rSet.Put(SfxBoolItem(SID_BEZIER_CLOSE,false)); break; + case SdrObjClosedKind::Closed : rSet.Put(SfxBoolItem(SID_BEZIER_CLOSE,true)); break; + default: break; + } + } + + if(pIPPEC == mpView) + rSet.Put(SfxBoolItem(SID_BEZIER_ELIMINATE_POINTS, mpView->IsEliminatePolyPoints())); + else + rSet.DisableItem( SID_BEZIER_ELIMINATE_POINTS ); // only works for views + } +} + +/** + * Process SfxRequests + */ + +void BezierObjectBar::Execute(SfxRequest& rReq) +{ + sal_uInt16 nSId = rReq.GetSlot(); + + switch (nSId) + { + case SID_BEZIER_CUTLINE: + case SID_BEZIER_CONVERT: + case SID_BEZIER_DELETE: + case SID_BEZIER_EDGE: + case SID_BEZIER_SMOOTH: + case SID_BEZIER_SYMMTR: + case SID_BEZIER_CLOSE: + { + const SdrMarkList& rMarkList = mpView->GetMarkedObjectList(); + + IPolyPolygonEditorController* pIPPEC = nullptr; + if( rMarkList.GetMarkCount() ) + pIPPEC = mpView; + else + pIPPEC = dynamic_cast< IPolyPolygonEditorController* >( mpView->getSmartTags().getSelected().get() ); + + if( pIPPEC && !mpView->IsAction()) + { + switch (nSId) + { + case SID_BEZIER_DELETE: + pIPPEC->DeleteMarkedPoints(); + break; + + case SID_BEZIER_CUTLINE: + pIPPEC->RipUpAtMarkedPoints(); + break; + + case SID_BEZIER_CONVERT: + { + pIPPEC->SetMarkedSegmentsKind(SdrPathSegmentKind::Toggle); + break; + } + + case SID_BEZIER_EDGE: + case SID_BEZIER_SMOOTH: + case SID_BEZIER_SYMMTR: + { + SdrPathSmoothKind eKind; + + switch (nSId) + { + default: + case SID_BEZIER_EDGE: eKind = SdrPathSmoothKind::Angular; break; + case SID_BEZIER_SMOOTH: eKind = SdrPathSmoothKind::Asymmetric; break; + case SID_BEZIER_SYMMTR: eKind = SdrPathSmoothKind::Symmetric; break; + } + + pIPPEC->SetMarkedPointsSmooth(eKind); + break; + } + + case SID_BEZIER_CLOSE: + { + SdrPathObj* pPathObj = static_cast<SdrPathObj*>( rMarkList.GetMark(0)->GetMarkedSdrObj() ); + const bool bUndo = mpView->IsUndoEnabled(); + if( bUndo ) + mpView->BegUndo(SdResId(STR_UNDO_BEZCLOSE)); + + mpView->UnmarkAllPoints(); + + if( bUndo ) + mpView->AddUndo(mpView->GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pPathObj)); + + pPathObj->ToggleClosed(); + + if( bUndo ) + mpView->EndUndo(); + break; + } + } + } + + if( (pIPPEC == mpView) && !mpView->AreObjectsMarked() ) + mpViewSh->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + + rReq.Ignore(); + } + break; + + case SID_BEZIER_ELIMINATE_POINTS: + { + mpView->SetEliminatePolyPoints(!mpView->IsEliminatePolyPoints()); + Invalidate(SID_BEZIER_ELIMINATE_POINTS); + rReq.Done(); + } + break; + + case SID_BEZIER_MOVE: + case SID_BEZIER_INSERT: + { + rtl::Reference<FuPoor> xFunc( mpViewSh->GetCurrentFunction() ); + + if(xFunc.is()) + { + if( auto pFuSelection = dynamic_cast<FuSelection *>( xFunc.get() )) + { + pFuSelection->SetEditMode(rReq.GetSlot()); + } + else if( auto pFuPolygon = dynamic_cast<FuConstructBezierPolygon *>( xFunc.get() )) + { + pFuPolygon->SetEditMode(rReq.GetSlot()); + } + } + + rReq.Ignore (); + } + break; + + default: + break; + } + + Invalidate(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drtxtob.cxx b/sd/source/ui/view/drtxtob.cxx new file mode 100644 index 0000000000..710518185d --- /dev/null +++ b/sd/source/ui/view/drtxtob.cxx @@ -0,0 +1,627 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <TextObjectBar.hxx> + +#include <svx/svxids.hrc> + +#include <com/sun/star/linguistic2/XThesaurus.hpp> + +#include <editeng/eeitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjustitem.hxx> +#include <editeng/editview.hxx> +#include <editeng/outliner.hxx> +#include <editeng/unolingu.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/editund2.hxx> +#include <svl/whiter.hxx> +#include <svl/itempool.hxx> +#include <svl/stritem.hxx> +#include <svl/style.hxx> +#include <svl/languageoptions.hxx> +#include <svl/cjkoptions.hxx> +#include <svl/ctloptions.hxx> +#include <sfx2/tplpitem.hxx> +#include <editeng/escapementitem.hxx> +#include <svx/svdoutl.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/writingmodeitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/fhgtitem.hxx> +#include <o3tl/temporary.hxx> + +#include <sfx2/objface.hxx> + +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <DrawViewShell.hxx> +#include <OutlineViewShell.hxx> +#include <Window.hxx> +#include <OutlineView.hxx> +#include <Outliner.hxx> + +#define ShellClass_TextObjectBar +using namespace sd; +#include <sdslots.hxx> + +using namespace ::com::sun::star; + +namespace sd { + +/** + * Declare default interface (Slotmap must not be empty, therefore enter + * something that (hopefully) never occurs. + */ +SFX_IMPL_INTERFACE(TextObjectBar, SfxShell) + +void TextObjectBar::InitInterface_Impl() +{ +} + + +TextObjectBar::TextObjectBar ( + ViewShell* pSdViewSh, + SfxItemPool& rItemPool, + ::sd::View* pSdView ) + : SfxShell(pSdViewSh->GetViewShell()), + mpViewShell( pSdViewSh ), + mpView( pSdView ) +{ + SetPool(&rItemPool); + + if( mpView ) + { + OutlineView* pOutlinerView = dynamic_cast< OutlineView* >( mpView ); + if( pOutlinerView ) + { + SetUndoManager(&pOutlinerView->GetOutliner().GetUndoManager()); + } + else + { + DrawDocShell* pDocShell = mpView->GetDoc().GetDocSh(); + if( pDocShell ) + { + SetUndoManager(pDocShell->GetUndoManager()); + DrawViewShell* pDrawViewShell = dynamic_cast< DrawViewShell* >( pSdViewSh ); + if ( pDrawViewShell ) + SetRepeatTarget(pSdView); + } + } + } + + SetName( "TextObjectBar"); + + // SetHelpId( SD_IF_SDDRAWTEXTOBJECTBAR ); +} + +TextObjectBar::~TextObjectBar() +{ + SetRepeatTarget(nullptr); +} + +void TextObjectBar::GetCharState( SfxItemSet& rSet ) +{ + SfxItemSet aCharAttrSet( mpView->GetDoc().GetPool() ); + mpView->GetAttributes( aCharAttrSet ); + + SfxItemSetFixed<EE_ITEMS_START,EE_ITEMS_END> aNewAttr( mpViewShell->GetPool() ); + + aNewAttr.Put(aCharAttrSet, false); + rSet.Put(aNewAttr, false); + + SvxKerningItem aKern = aCharAttrSet.Get( EE_CHAR_KERNING ); + //aKern.SetWhich(SID_ATTR_CHAR_KERNING); + rSet.Put(aKern); + + SfxItemState eState = aCharAttrSet.GetItemState( EE_CHAR_KERNING ); + if ( eState == SfxItemState::DONTCARE ) + { + rSet.InvalidateItem(EE_CHAR_KERNING); + } +} + +/** + * Status of attribute items. + */ +void TextObjectBar::GetAttrState( SfxItemSet& rSet ) +{ + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + SfxItemSet aAttrSet( mpView->GetDoc().GetPool() ); + bool bDisableParagraphTextDirection = !SvtCTLOptions::IsCTLFontEnabled(); + bool bDisableVerticalText = !SvtCJKOptions::IsVerticalTextEnabled(); + + mpView->GetAttributes( aAttrSet ); + + while ( nWhich ) + { + sal_uInt16 nSlotId = SfxItemPool::IsWhich(nWhich) + ? GetPool().GetSlotId(nWhich) + : nWhich; + + switch ( nSlotId ) + { + case SID_ATTR_CHAR_FONT: + case SID_ATTR_CHAR_FONTHEIGHT: + case SID_ATTR_CHAR_WEIGHT: + case SID_ATTR_CHAR_POSTURE: + case SID_ATTR_CHAR_SHADOWED: + case SID_ATTR_CHAR_STRIKEOUT: + case SID_ATTR_CHAR_CASEMAP: + { + double stretchY = 100.0; + SvxScriptSetItem aSetItem( nSlotId, GetPool() ); + aSetItem.GetItemSet().Put( aAttrSet, false ); + + SvtScriptType nScriptType = mpView->GetScriptType(); + + if( (nSlotId == SID_ATTR_CHAR_FONT) || (nSlotId == SID_ATTR_CHAR_FONTHEIGHT) ) + { + // input language should be preferred over + // current cursor position to detect script type + OutlinerView* pOLV = mpView->GetTextEditOutlinerView(); + SdrOutliner *pOutliner = mpView->GetTextEditOutliner(); + + assert(mpViewShell); + + if (OutlineView* pOView = dynamic_cast<OutlineView*>(mpView)) + pOLV = pOView->GetViewByWindow(mpViewShell->GetActiveWindow()); + + if (pOutliner) + pOutliner->getGlobalScale(o3tl::temporary(double()), stretchY, o3tl::temporary(double()), o3tl::temporary(double())); + + if(pOLV && !pOLV->GetSelection().HasRange()) + { + if (mpViewShell->GetViewShell() && mpViewShell->GetViewShell()->GetWindow()) + { + LanguageType nInputLang = mpViewShell->GetViewShell()->GetWindow()->GetInputLanguage(); + if(nInputLang != LANGUAGE_DONTKNOW && nInputLang != LANGUAGE_SYSTEM) + nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nInputLang ); + } + } + } + + const SfxPoolItem* pI = aSetItem.GetItemOfScript( nScriptType ); + if( pI ) + { + if( nSlotId == SID_ATTR_CHAR_FONTHEIGHT ) + { + SvxFontHeightItem aFontItem = dynamic_cast<const SvxFontHeightItem&>(*pI); + aFontItem.SetHeight(aFontItem.GetHeight() * (stretchY / 100.0), 100, aFontItem.GetPropUnit()); + aFontItem.SetWhich(nWhich); + aAttrSet.Put( aFontItem ); + } + else + { + aAttrSet.Put( pI->CloneSetWhich(nWhich) ); + } + } + else + { + aAttrSet.InvalidateItem( nWhich ); + } + } + break; + + case SID_STYLE_APPLY: + case SID_STYLE_FAMILY2: + { + SfxStyleSheet* pStyleSheet = mpView->GetStyleSheetFromMarked(); + if( pStyleSheet ) + rSet.Put( SfxTemplateItem( nWhich, pStyleSheet->GetName() ) ); + else + { + rSet.Put( SfxTemplateItem( nWhich, OUString() ) ); + } + } + break; + + case SID_OUTLINE_LEFT: + case SID_OUTLINE_RIGHT: + case SID_OUTLINE_UP: + case SID_OUTLINE_DOWN: + { + bool bDisableLeft = true; + bool bDisableRight = true; + bool bDisableUp = true; + bool bDisableDown = true; + + //fdo#78151 it doesn't make sense to promote or demote outline levels in master view. + const DrawViewShell* pDrawViewShell = dynamic_cast< DrawViewShell* >(mpViewShell); + const bool bInMasterView = pDrawViewShell && pDrawViewShell->GetEditMode() == EditMode::MasterPage; + + if (!bInMasterView) + { + OutlinerView* pOLV = mpView->GetTextEditOutlinerView(); + + if (OutlineView* pOView = dynamic_cast<OutlineView*>(mpView)) + pOLV = pOView->GetViewByWindow(mpViewShell->GetActiveWindow()); + + bool bOutlineViewSh = dynamic_cast< const OutlineViewShell *>( mpViewShell ) != nullptr; + + if (pOLV) + { + // Outliner at outline-mode + ::Outliner* pOutl = pOLV->GetOutliner(); + + std::vector<Paragraph*> aSelList; + pOLV->CreateSelectionList(aSelList); + Paragraph* pPara = aSelList.empty() ? nullptr : *(aSelList.begin()); + + // find out if we are an OutlineView + bool bIsOutlineView(OutlinerMode::OutlineView == pOLV->GetOutliner()->GetOutlinerMode()); + + // This is ONLY for OutlineViews + if(bIsOutlineView) + { + // allow move up if position is 2 or greater OR it + // is a title object (and thus depth==1) + if(pOutl->GetAbsPos(pPara) > 1 || ( ::Outliner::HasParaFlag(pPara,ParaFlag::ISPAGE) && pOutl->GetAbsPos(pPara) > 0 ) ) + { + // not at top + bDisableUp = false; + } + } + else + { + // old behaviour for OutlinerMode::OutlineObject + if(pOutl->GetAbsPos(pPara) > 0) + { + // not at top + bDisableUp = false; + } + } + + for (const auto& rpItem : aSelList) + { + pPara = rpItem; + + sal_Int16 nDepth = pOutl->GetDepth( pOutl->GetAbsPos( pPara ) ); + + if (nDepth > 0 || (bOutlineViewSh && (nDepth <= 0) && !::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE )) ) + { + // not minimum depth + bDisableLeft = false; + } + + if( (nDepth < pOLV->GetOutliner()->GetMaxDepth() && ( !bOutlineViewSh || pOutl->GetAbsPos(pPara) != 0 )) || + (bOutlineViewSh && (nDepth <= 0) && ::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) && pOutl->GetAbsPos(pPara) != 0) ) + { + // not maximum depth and not at top + bDisableRight = false; + } + } + + if ( ( pOutl->GetAbsPos(pPara) < pOutl->GetParagraphCount() - 1 ) && + ( pOutl->GetParagraphCount() > 1 || !bOutlineViewSh) ) + { + // not last paragraph + bDisableDown = false; + } + + // disable when first para and 2nd is not a title + pPara = aSelList.empty() ? nullptr : *(aSelList.begin()); + + if(!bDisableDown && bIsOutlineView + && pPara + && 0 == pOutl->GetAbsPos(pPara) + && pOutl->GetParagraphCount() > 1 + && !::Outliner::HasParaFlag( pOutl->GetParagraph(1), ParaFlag::ISPAGE ) ) + { + // Needs to be disabled + bDisableDown = true; + } + } + } + + if (bDisableLeft) + rSet.DisableItem(SID_OUTLINE_LEFT); + if (bDisableRight) + rSet.DisableItem(SID_OUTLINE_RIGHT); + if (bDisableUp) + rSet.DisableItem(SID_OUTLINE_UP); + if (bDisableDown) + rSet.DisableItem(SID_OUTLINE_DOWN); + } + break; + + case SID_TEXTDIRECTION_LEFT_TO_RIGHT: + case SID_TEXTDIRECTION_TOP_TO_BOTTOM: + { + if ( bDisableVerticalText ) + { + rSet.DisableItem( SID_TEXTDIRECTION_LEFT_TO_RIGHT ); + rSet.DisableItem( SID_TEXTDIRECTION_TOP_TO_BOTTOM ); + } + else + { + bool bLeftToRight = true; + + SdrOutliner* pOutl = mpView->GetTextEditOutliner(); + if( pOutl ) + { + if( pOutl->IsVertical() ) + bLeftToRight = false; + } + else + bLeftToRight = aAttrSet.Get( SDRATTR_TEXTDIRECTION ).GetValue() == css::text::WritingMode_LR_TB; + + rSet.Put( SfxBoolItem( SID_TEXTDIRECTION_LEFT_TO_RIGHT, bLeftToRight ) ); + rSet.Put( SfxBoolItem( SID_TEXTDIRECTION_TOP_TO_BOTTOM, !bLeftToRight ) ); + + if( !bLeftToRight ) + bDisableParagraphTextDirection = true; + } + } + break; + + case SID_ULINE_VAL_NONE: + case SID_ULINE_VAL_SINGLE: + case SID_ULINE_VAL_DOUBLE: + case SID_ULINE_VAL_DOTTED: + { + if( aAttrSet.GetItemState( EE_CHAR_UNDERLINE ) >= SfxItemState::DEFAULT ) + { + FontLineStyle eLineStyle = aAttrSet.Get(EE_CHAR_UNDERLINE).GetLineStyle(); + + switch (nSlotId) + { + case SID_ULINE_VAL_NONE: + rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_NONE)); + break; + case SID_ULINE_VAL_SINGLE: + rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_SINGLE)); + break; + case SID_ULINE_VAL_DOUBLE: + rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_DOUBLE)); + break; + case SID_ULINE_VAL_DOTTED: + rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_DOTTED)); + break; + } + } + } + break; + + case SID_GROW_FONT_SIZE: + case SID_SHRINK_FONT_SIZE: + { + // todo + } + break; + + case SID_THES: + { + if (mpView->GetTextEditOutlinerView()) + { + EditView & rEditView = mpView->GetTextEditOutlinerView()->GetEditView(); + OUString aStatusVal; + LanguageType nLang = LANGUAGE_NONE; + bool bIsLookUpWord = GetStatusValueForThesaurusFromContext( aStatusVal, nLang, rEditView ); + rSet.Put( SfxStringItem( SID_THES, aStatusVal ) ); + + // disable "Thesaurus" context menu entry if there is nothing to look up + uno::Reference< linguistic2::XThesaurus > xThes( LinguMgr::GetThesaurus() ); + if (!bIsLookUpWord || + !xThes.is() || nLang == LANGUAGE_NONE || !xThes->hasLocale( LanguageTag( nLang). getLocale() )) + rSet.DisableItem( SID_THES ); + } + else + { + rSet.DisableItem( SID_THES ); + } + } + break; + + default: + break; + } + + nWhich = aIter.NextWhich(); + } + + rSet.Put( aAttrSet, false ); // <- sal_False, so DontCare-Status gets acquired + + // these are disabled in outline-mode + if (!mpViewShell || dynamic_cast< const DrawViewShell *>( mpViewShell ) == nullptr) + { + rSet.DisableItem( SID_ATTR_PARA_ADJUST_LEFT ); + rSet.DisableItem( SID_ATTR_PARA_ADJUST_RIGHT ); + rSet.DisableItem( SID_ATTR_PARA_ADJUST_CENTER ); + rSet.DisableItem( SID_ATTR_PARA_ADJUST_BLOCK ); + rSet.DisableItem( SID_ATTR_PARA_LINESPACE_10 ); + rSet.DisableItem( SID_ATTR_PARA_LINESPACE_15 ); + rSet.DisableItem( SID_ATTR_PARA_LINESPACE_20 ); + rSet.DisableItem( SID_DEC_INDENT ); + rSet.DisableItem( SID_INC_INDENT ); + rSet.DisableItem( SID_PARASPACE_INCREASE ); + rSet.DisableItem( SID_PARASPACE_DECREASE ); + rSet.DisableItem( SID_TEXTDIRECTION_TOP_TO_BOTTOM ); + rSet.DisableItem( SID_TEXTDIRECTION_LEFT_TO_RIGHT ); + rSet.DisableItem( SID_ATTR_PARA_LEFT_TO_RIGHT ); + rSet.DisableItem( SID_ATTR_PARA_RIGHT_TO_LEFT ); + } + else + { + // paragraph spacing + OutlinerView* pOLV = mpView->GetTextEditOutlinerView(); + if( pOLV ) + { + ESelection aSel = pOLV->GetSelection(); + aSel.Adjust(); + sal_Int32 nStartPara = aSel.nStartPara; + sal_Int32 nEndPara = aSel.nEndPara; + if( !aSel.HasRange() ) + { + nStartPara = 0; + nEndPara = pOLV->GetOutliner()->GetParagraphCount() - 1; + } + ::tools::Long nUpper = 0; + + for( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + const SfxItemSet& rItems = pOLV->GetOutliner()->GetParaAttribs( nPara ); + const SvxULSpaceItem& rItem = rItems.Get( EE_PARA_ULSPACE ); + nUpper = std::max( nUpper, static_cast<::tools::Long>(rItem.GetUpper()) ); + } + if( nUpper == 0 ) + rSet.DisableItem( SID_PARASPACE_DECREASE ); + } + else + { + // never disabled at the moment! + //rSet.DisableItem( SID_PARASPACE_INCREASE ); + //rSet.DisableItem( SID_PARASPACE_DECREASE ); + } + + // paragraph justification + const SvxLRSpaceItem& aLR = aAttrSet.Get( EE_PARA_LRSPACE ); + rSet.Put(aLR); + SvxAdjust eAdj = aAttrSet.Get( EE_PARA_JUST ).GetAdjust(); + switch( eAdj ) + { + case SvxAdjust::Left: + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, true ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, false ) ); + break; + case SvxAdjust::Center: + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, true ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, false ) ); + break; + case SvxAdjust::Right: + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, true ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, false ) ); + break; + case SvxAdjust::Block: + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, true ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, false ) ); + break; + default: + break; + } + + Invalidate(SID_ATTR_PARA_ADJUST_LEFT); + Invalidate(SID_ATTR_PARA_ADJUST_CENTER); + Invalidate(SID_ATTR_PARA_ADJUST_RIGHT); + Invalidate(SID_ATTR_PARA_ADJUST_BLOCK); + Invalidate(SID_ATTR_PARA_LINESPACE); + Invalidate(SID_ATTR_PARA_ULSPACE); + + // paragraph text direction + if( bDisableParagraphTextDirection ) + { + rSet.DisableItem( SID_ATTR_PARA_LEFT_TO_RIGHT ); + rSet.DisableItem( SID_ATTR_PARA_RIGHT_TO_LEFT ); + } + else + { + switch( aAttrSet.Get( EE_PARA_WRITINGDIR ).GetValue() ) + { + case SvxFrameDirection::Vertical_LR_TB: + case SvxFrameDirection::Vertical_RL_TB: + { + rSet.DisableItem( SID_ATTR_PARA_LEFT_TO_RIGHT ); + rSet.DisableItem( SID_ATTR_PARA_RIGHT_TO_LEFT ); + } + break; + + case SvxFrameDirection::Horizontal_LR_TB: + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LEFT_TO_RIGHT, true ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_RIGHT_TO_LEFT, false ) ); + break; + + case SvxFrameDirection::Horizontal_RL_TB: + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LEFT_TO_RIGHT, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_RIGHT_TO_LEFT, true ) ); + break; + + // The case for the superordinate object is missing. + case SvxFrameDirection::Environment: + { + SdDrawDocument& rDoc = mpView->GetDoc(); + css::text::WritingMode eMode = rDoc.GetDefaultWritingMode(); + bool bIsLeftToRight(false); + + if(css::text::WritingMode_LR_TB == eMode + || css::text::WritingMode_TB_RL == eMode) + { + bIsLeftToRight = true; + } + + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LEFT_TO_RIGHT, bIsLeftToRight ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_RIGHT_TO_LEFT, !bIsLeftToRight ) ); + } + break; + default: break; + } + } + + SvxLRSpaceItem aLRSpace = aAttrSet.Get( EE_PARA_LRSPACE ); + aLRSpace.SetWhich(SID_ATTR_PARA_LRSPACE); + rSet.Put(aLRSpace); + Invalidate(SID_ATTR_PARA_LRSPACE); + + //Added by xuxu + SfxItemState eState = aAttrSet.GetItemState( EE_PARA_LRSPACE ); + if ( eState == SfxItemState::DONTCARE ) + { + rSet.InvalidateItem(EE_PARA_LRSPACE); + rSet.InvalidateItem(SID_ATTR_PARA_LRSPACE); + } + sal_uInt16 nLineSpace = aAttrSet.Get( EE_PARA_SBL ).GetPropLineSpace(); + switch( nLineSpace ) + { + case 100: + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_10, true ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_15, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_20, false ) ); + break; + case 150: + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_15, true ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_10, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_20, false ) ); + break; + case 200: + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_20, true ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_10, false ) ); + rSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_15, false ) ); + break; + } + } + + // justification (superscript, subscript) is also needed in outline-mode + SvxEscapement eEsc = static_cast<SvxEscapement>(aAttrSet.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue()); + rSet.Put(SfxBoolItem(SID_SET_SUPER_SCRIPT, eEsc == SvxEscapement::Superscript)); + rSet.Put(SfxBoolItem(SID_SET_SUB_SCRIPT, eEsc == SvxEscapement::Subscript)); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drtxtob1.cxx b/sd/source/ui/view/drtxtob1.cxx new file mode 100644 index 0000000000..b176db5596 --- /dev/null +++ b/sd/source/ui/view/drtxtob1.cxx @@ -0,0 +1,803 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <TextObjectBar.hxx> + +#include <svx/svxids.hrc> + +#include <editeng/eeitem.hxx> +#include <editeng/editview.hxx> +#include <editeng/outliner.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjustitem.hxx> +#include <editeng/numitem.hxx> +#include <svl/itempool.hxx> +#include <svl/stritem.hxx> +#include <svl/style.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <editeng/escapementitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/contouritem.hxx> +#include <editeng/shdditem.hxx> +#include <svx/svdpagv.hxx> +#include <editeng/flstitem.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/writingmodeitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/cmapitem.hxx> + +#include <app.hrc> +#include <strings.hrc> +#include <sdresid.hxx> +#include <prlayout.hxx> +#include <ViewShell.hxx> +#include <drawdoc.hxx> +#include <sdpage.hxx> +#include <stlpool.hxx> +#include <stlsheet.hxx> +#include <OutlineView.hxx> +#include <Window.hxx> +#include <futempl.hxx> +#include <DrawDocShell.hxx> +#include <futext.hxx> +#include <editeng/colritem.hxx> + +#include <memory> + +namespace sd { + +/** + * Process SfxRequests + */ + +void TextObjectBar::Execute( SfxRequest &rReq ) +{ + const SfxItemSet* pArgs = rReq.GetArgs(); + sal_uInt16 nSlot = rReq.GetSlot(); + OutlinerView* pOLV = mpView->GetTextEditOutlinerView(); + + std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard; + + assert(mpViewShell); + + if (OutlineView* pOView = dynamic_cast<OutlineView*>(mpView)) + { + pOLV = pOView->GetViewByWindow(mpViewShell->GetActiveWindow()); + aGuard.reset( new OutlineViewModelChangeGuard( static_cast<OutlineView&>(*mpView) ) ); + } + + switch (nSlot) + { + case SID_STYLE_APPLY: + { + if( pArgs ) + { + SdDrawDocument& rDoc = mpView->GetDoc(); + assert(mpViewShell->GetViewShell()); + rtl::Reference<FuPoor> xFunc( FuTemplate::Create( mpViewShell, static_cast< ::sd::Window*>( mpViewShell->GetViewShell()->GetWindow()), mpView, &rDoc, rReq ) ); + + if(xFunc.is()) + { + xFunc->Activate(); + xFunc->Deactivate(); + + if( rReq.GetSlot() == SID_STYLE_APPLY ) + { + if (mpViewShell->GetViewFrame()) + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_STYLE_APPLY ); + } + } + } + else + { + if (mpViewShell->GetViewFrame()) + mpViewShell->GetViewFrame()->GetDispatcher()->Execute( SID_STYLE_DESIGNER, SfxCallMode::ASYNCHRON ); + } + + rReq.Done(); + } + break; + + case SID_INC_INDENT: + case SID_DEC_INDENT: + { + if( pOLV ) + { + ESelection aSel = pOLV->GetSelection(); + aSel.Adjust(); + sal_Int32 nStartPara = aSel.nStartPara; + sal_Int32 nEndPara = aSel.nEndPara; + if( !aSel.HasRange() ) + { + nStartPara = 0; + nEndPara = pOLV->GetOutliner()->GetParagraphCount() - 1; + } + + pOLV->GetOutliner()->UndoActionStart( OLUNDO_ATTR ); + for( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + SfxStyleSheet* pStyleSheet = nullptr; + if (pOLV->GetOutliner() != nullptr) + pStyleSheet = pOLV->GetOutliner()->GetStyleSheet(nPara); + if (pStyleSheet != nullptr) + { + SfxItemSet aAttr( pStyleSheet->GetItemSet() ); + SfxItemSet aTmpSet( pOLV->GetOutliner()->GetParaAttribs( nPara ) ); + aAttr.Put( aTmpSet, false ); + const SvxLRSpaceItem& rItem = aAttr.Get( EE_PARA_LRSPACE ); + std::unique_ptr<SvxLRSpaceItem> pNewItem(rItem.Clone()); + + ::tools::Long nLeft = pNewItem->GetLeft(); + if( nSlot == SID_INC_INDENT ) + nLeft += 1000; + else + { + nLeft -= 1000; + nLeft = std::max<::tools::Long>( nLeft, 0 ); + } + pNewItem->SetLeftValue( static_cast<sal_uInt16>(nLeft) ); + + SfxItemSet aNewAttrs( aAttr ); + aNewAttrs.Put( std::move(pNewItem) ); + pOLV->GetOutliner()->SetParaAttribs( nPara, aNewAttrs ); + } + } + pOLV->GetOutliner()->UndoActionEnd(); + mpViewShell->Invalidate( SID_UNDO ); + } + rReq.Done(); + + Invalidate(); + // to refresh preview (in outline mode), slot has to be invalidated: + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true ); + + } + break; + + case SID_PARASPACE_INCREASE: + case SID_PARASPACE_DECREASE: + { + if( pOLV ) + { + ESelection aSel = pOLV->GetSelection(); + aSel.Adjust(); + sal_Int32 nStartPara = aSel.nStartPara; + sal_Int32 nEndPara = aSel.nEndPara; + if( !aSel.HasRange() ) + { + nStartPara = 0; + nEndPara = pOLV->GetOutliner()->GetParagraphCount() - 1; + } + + pOLV->GetOutliner()->UndoActionStart( OLUNDO_ATTR ); + for( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + SfxStyleSheet* pStyleSheet = nullptr; + if (pOLV->GetOutliner() != nullptr) + pStyleSheet = pOLV->GetOutliner()->GetStyleSheet(nPara); + if (pStyleSheet != nullptr) + { + SfxItemSet aAttr( pStyleSheet->GetItemSet() ); + SfxItemSet aTmpSet( pOLV->GetOutliner()->GetParaAttribs( nPara ) ); + aAttr.Put( aTmpSet, false ); // sal_False= InvalidItems is not default, handle it as "holes" + const SvxULSpaceItem& rItem = aAttr.Get( EE_PARA_ULSPACE ); + std::unique_ptr<SvxULSpaceItem> pNewItem(rItem.Clone()); + + ::tools::Long nUpper = pNewItem->GetUpper(); + if( nSlot == SID_PARASPACE_INCREASE ) + nUpper += 100; + else + { + nUpper -= 100; + nUpper = std::max<::tools::Long>( nUpper, 0 ); + } + pNewItem->SetUpper( static_cast<sal_uInt16>(nUpper) ); + + ::tools::Long nLower = pNewItem->GetLower(); + if( nSlot == SID_PARASPACE_INCREASE ) + nLower += 100; + else + { + nLower -= 100; + nLower = std::max<::tools::Long>( nLower, 0 ); + } + pNewItem->SetLower( static_cast<sal_uInt16>(nLower) ); + + SfxItemSet aNewAttrs( aAttr ); + aNewAttrs.Put( std::move(pNewItem) ); + pOLV->GetOutliner()->SetParaAttribs( nPara, aNewAttrs ); + } + } + pOLV->GetOutliner()->UndoActionEnd(); + mpViewShell->Invalidate( SID_UNDO ); + } + else + { + // the following code could be enabled, if I get a correct + // DontCare status from JOE. + + // gets enabled, through it doesn't really work (see above) + SfxItemSet aEditAttr( mpView->GetDoc().GetPool() ); + mpView->GetAttributes( aEditAttr ); + if( aEditAttr.GetItemState( EE_PARA_ULSPACE ) >= SfxItemState::DEFAULT ) + { + SfxItemSet aNewAttrs(*(aEditAttr.GetPool()), aEditAttr.GetRanges()); + const SvxULSpaceItem& rItem = aEditAttr.Get( EE_PARA_ULSPACE ); + std::unique_ptr<SvxULSpaceItem> pNewItem(rItem.Clone()); + ::tools::Long nUpper = pNewItem->GetUpper(); + + if( nSlot == SID_PARASPACE_INCREASE ) + nUpper += 100; + else + { + nUpper -= 100; + nUpper = std::max<::tools::Long>( nUpper, 0 ); + } + pNewItem->SetUpper( static_cast<sal_uInt16>(nUpper) ); + + ::tools::Long nLower = pNewItem->GetLower(); + if( nSlot == SID_PARASPACE_INCREASE ) + nLower += 100; + else + { + nLower -= 100; + nLower = std::max<::tools::Long>( nLower, 0 ); + } + pNewItem->SetLower( static_cast<sal_uInt16>(nLower) ); + + aNewAttrs.Put( std::move(pNewItem) ); + + mpView->SetAttributes( aNewAttrs ); + } + } + rReq.Done(); + + Invalidate(); + // to refresh preview (in outline mode), slot has to be invalidated: + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true ); + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_PARA_ULSPACE, true ); + } + break; + + case SID_OUTLINE_LEFT: + { + if (pOLV) + { + pOLV->AdjustDepth( -1 ); + + // Ensure bold/italic etc. icon state updates + Invalidate(); + // trigger preview refresh + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true ); + } + rReq.Done(); + } + break; + + case SID_OUTLINE_RIGHT: + { + if (pOLV) + { + pOLV->AdjustDepth( 1 ); + + // Ensure bold/italic etc. icon state updates + Invalidate(); + // trigger preview refresh + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true ); + } + rReq.Done(); + } + break; + + case SID_ATTR_PARA_LRSPACE: + { + SvxLRSpaceItem aLRSpace = static_cast<const SvxLRSpaceItem&>(pArgs->Get( + SID_ATTR_PARA_LRSPACE)); + + SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aEditAttr( GetPool() ); + aLRSpace.SetWhich( EE_PARA_LRSPACE ); + + aEditAttr.Put( aLRSpace ); + mpView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_PARA_LRSPACE); + } + break; + + case SID_HANGING_INDENT: + { + SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aLRSpaceSet( GetPool() ); + mpView->GetAttributes( aLRSpaceSet ); + SvxLRSpaceItem aParaMargin( aLRSpaceSet.Get( EE_PARA_LRSPACE ) ); + + SvxLRSpaceItem aNewMargin( EE_PARA_LRSPACE ); + aNewMargin.SetTextLeft( aParaMargin.GetTextLeft() + aParaMargin.GetTextFirstLineOffset() ); + aNewMargin.SetRight( aParaMargin.GetRight() ); + aNewMargin.SetTextFirstLineOffset( ( aParaMargin.GetTextFirstLineOffset() ) * -1 ); + aLRSpaceSet.Put( aNewMargin ); + mpView->SetAttributes( aLRSpaceSet ); + + Invalidate(SID_ATTR_PARA_LRSPACE); + } + break; + + case SID_OUTLINE_UP: + { + if (pOLV) + { + pOLV->AdjustHeight( -1 ); + + // trigger preview refresh + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true ); + } + rReq.Done(); + } + break; + + case SID_OUTLINE_DOWN: + { + if (pOLV) + { + pOLV->AdjustHeight( 1 ); + + // trigger preview refresh + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true ); + } + rReq.Done(); + } + break; + + case SID_TEXTDIRECTION_LEFT_TO_RIGHT: + case SID_TEXTDIRECTION_TOP_TO_BOTTOM: + { + mpView->SdrEndTextEdit(); + // tdf#131571: SdrEndTextEdit invalidates pTextEditOutlinerView, the pointer retrieved for pOLV + // so reinitialize pOLV + pOLV=mpView->GetTextEditOutlinerView(); + SfxItemSetFixed<SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION> aAttr( mpView->GetDoc().GetPool() ); + aAttr.Put( SvxWritingModeItem( + nSlot == SID_TEXTDIRECTION_LEFT_TO_RIGHT ? + css::text::WritingMode_LR_TB : css::text::WritingMode_TB_RL, + SDRATTR_TEXTDIRECTION ) ); + rReq.Done( aAttr ); + mpView->SetAttributes( aAttr ); + Invalidate(); + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true ); + } + break; + + case FN_NUM_BULLET_ON: + { + if (pOLV) + { + bool bMasterPage = false; + SdrPageView* pPageView = mpView->GetSdrPageView(); + if (pPageView) + { + SdPage* pPage = static_cast<SdPage*>(pPageView->GetPage()); + bMasterPage = pPage && (pPage->GetPageKind() == PageKind::Standard) && pPage->IsMasterPage(); + } + + if (!bMasterPage) + pOLV->ToggleBullets(); + else + { + //Resolves: fdo#78151 in master pages if we toggle bullets on + //and off then just disable/enable the bulleting, but do not + //change the *level* of the paragraph, because the paragraph is + //effectively a preview of the equivalent style level, and + //changing the level disconnects it from the style + + ::Outliner* pOL = pOLV->GetOutliner(); + if (pOL) + { + const SvxNumBulletItem *pItem = nullptr; + SfxStyleSheetBasePool* pSSPool = mpView->GetDocSh()->GetStyleSheetPool(); + OUString sStyleName(SdResId(STR_PSEUDOSHEET_OUTLINE) + " 1"); + SfxStyleSheetBase* pFirstStyleSheet = pSSPool->Find(sStyleName, SfxStyleFamily::Pseudo); + if( pFirstStyleSheet ) + pItem = pFirstStyleSheet->GetItemSet().GetItemIfSet(EE_PARA_NUMBULLET, false); + + if (pItem ) + { + SvxNumRule aNewRule(pItem->GetNumRule()); + ESelection aSel = pOLV->GetSelection(); + aSel.Adjust(); + sal_Int32 nStartPara = aSel.nStartPara; + sal_Int32 nEndPara = aSel.nEndPara; + for (sal_Int32 nPara = nStartPara; nPara <= nEndPara; ++nPara) + { + sal_uInt16 nLevel = pOL->GetDepth(nPara); + SvxNumberFormat aFmt(aNewRule.GetLevel(nLevel)); + + if (aFmt.GetNumberingType() == SVX_NUM_NUMBER_NONE) + { + aFmt.SetNumberingType(SVX_NUM_CHAR_SPECIAL); + SdStyleSheetPool::setDefaultOutlineNumberFormatBulletAndIndent(nLevel, aFmt); + } + else + { + aFmt.SetNumberingType(SVX_NUM_NUMBER_NONE); + aFmt.SetAbsLSpace(0); + aFmt.SetFirstLineOffset(0); + } + + aNewRule.SetLevel(nLevel, aFmt); + } + + pFirstStyleSheet->GetItemSet().Put(SvxNumBulletItem(std::move(aNewRule), EE_PARA_NUMBULLET)); + + SdStyleSheet::BroadcastSdStyleSheetChange(pFirstStyleSheet, PresentationObjects::Outline_1, pSSPool); + } + } + } + } + break; + } + case SID_GROW_FONT_SIZE: + case SID_SHRINK_FONT_SIZE: + { + const SvxFontListItem* pFonts = static_cast<const SvxFontListItem*>(mpViewShell->GetDocSh()->GetItem( SID_ATTR_CHAR_FONTLIST )); + const FontList* pFontList = pFonts ? pFonts->GetFontList(): nullptr; + if( pFontList ) + { + FuText::ChangeFontSize( nSlot == SID_GROW_FONT_SIZE, pOLV, pFontList, mpView ); + if( pOLV ) + pOLV->SetAttribs( pOLV->GetEditView().GetEmptyItemSet() ); + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_CHAR_FONTHEIGHT ); + } + rReq.Done(); + } + break; + + case SID_THES: + { + OUString aReplaceText; + const SfxStringItem* pItem2 = rReq.GetArg(FN_PARAM_THES_WORD_REPLACE); + if (pItem2) + aReplaceText = pItem2->GetValue(); + if (!aReplaceText.isEmpty()) + ReplaceTextWithSynonym( pOLV->GetEditView(), aReplaceText ); + } + break; + + default: + { + SfxItemSet aEditAttr( mpView->GetDoc().GetPool() ); + mpView->GetAttributes( aEditAttr ); + SfxItemSet aNewAttr(*(aEditAttr.GetPool()), aEditAttr.GetRanges()); + + if( !pArgs ) + { + //aNewAttr.InvalidateAllItems(); <- produces problems (#35465#) + + switch ( nSlot ) + { + case SID_ATTR_CHAR_WEIGHT: + { + FontWeight eFW = aEditAttr.Get( EE_CHAR_WEIGHT ).GetWeight(); + aNewAttr.Put( SvxWeightItem( eFW == WEIGHT_NORMAL ? + WEIGHT_BOLD : WEIGHT_NORMAL, + EE_CHAR_WEIGHT ) ); + } + break; + case SID_ATTR_CHAR_POSTURE: + { + FontItalic eFI = aEditAttr.Get( EE_CHAR_ITALIC ).GetPosture(); + aNewAttr.Put( SvxPostureItem( eFI == ITALIC_NORMAL ? + ITALIC_NONE : ITALIC_NORMAL, + EE_CHAR_ITALIC ) ); + } + break; + case SID_ATTR_CHAR_UNDERLINE: + { + FontLineStyle eFU = aEditAttr.Get( EE_CHAR_UNDERLINE ).GetLineStyle(); + aNewAttr.Put( SvxUnderlineItem( eFU == LINESTYLE_SINGLE ? + LINESTYLE_NONE : LINESTYLE_SINGLE, + EE_CHAR_UNDERLINE ) ); + } + break; + + case SID_ULINE_VAL_NONE: + { + aNewAttr.Put(SvxUnderlineItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE)); + break; + } + + case SID_ULINE_VAL_SINGLE: + case SID_ULINE_VAL_DOUBLE: + case SID_ULINE_VAL_DOTTED: + { + FontLineStyle eOld = aEditAttr.Get(EE_CHAR_UNDERLINE).GetLineStyle(); + FontLineStyle eNew = eOld; + + switch (nSlot) + { + case SID_ULINE_VAL_SINGLE: + eNew = ( eOld == LINESTYLE_SINGLE ) ? LINESTYLE_NONE : LINESTYLE_SINGLE; + break; + case SID_ULINE_VAL_DOUBLE: + eNew = ( eOld == LINESTYLE_DOUBLE ) ? LINESTYLE_NONE : LINESTYLE_DOUBLE; + break; + case SID_ULINE_VAL_DOTTED: + eNew = ( eOld == LINESTYLE_DOTTED ) ? LINESTYLE_NONE : LINESTYLE_DOTTED; + break; + } + + SvxUnderlineItem aUnderline(eNew, EE_CHAR_UNDERLINE); + aNewAttr.Put(aUnderline); + } + break; + + case SID_ATTR_CHAR_OVERLINE: + { + FontLineStyle eFO = aEditAttr.Get( EE_CHAR_OVERLINE ).GetLineStyle(); + aNewAttr.Put( SvxOverlineItem( eFO == LINESTYLE_SINGLE ? + LINESTYLE_NONE : LINESTYLE_SINGLE, + EE_CHAR_OVERLINE ) ); + } + break; + case SID_ATTR_CHAR_CONTOUR: + { + aNewAttr.Put( SvxContourItem( !aEditAttr.Get( EE_CHAR_OUTLINE ).GetValue(), EE_CHAR_OUTLINE ) ); + } + break; + case SID_ATTR_CHAR_SHADOWED: + { + aNewAttr.Put( SvxShadowedItem( !aEditAttr.Get( EE_CHAR_SHADOW ).GetValue(), EE_CHAR_SHADOW ) ); + } + break; + case SID_ATTR_CHAR_CASEMAP: + { + aNewAttr.Put( aEditAttr.Get( EE_CHAR_CASEMAP ) ); + } + break; + case SID_ATTR_CHAR_STRIKEOUT: + { + FontStrikeout eFSO = aEditAttr.Get( EE_CHAR_STRIKEOUT ).GetStrikeout(); + aNewAttr.Put( SvxCrossedOutItem( eFSO == STRIKEOUT_SINGLE ? + STRIKEOUT_NONE : STRIKEOUT_SINGLE, EE_CHAR_STRIKEOUT ) ); + } + break; + + case SID_ATTR_PARA_ADJUST_LEFT: + { + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) ); + } + break; + case SID_ATTR_PARA_ADJUST_CENTER: + { + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) ); + } + break; + case SID_ATTR_PARA_ADJUST_RIGHT: + { + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) ); + } + break; + case SID_ATTR_PARA_ADJUST_BLOCK: + { + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Block, EE_PARA_JUST ) ); + } + break; + case SID_ATTR_PARA_LINESPACE_10: + { + SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL ); + aItem.SetPropLineSpace( 100 ); + aNewAttr.Put( aItem ); + } + break; + case SID_ATTR_PARA_LINESPACE_15: + { + SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL ); + aItem.SetPropLineSpace( 150 ); + aNewAttr.Put( aItem ); + } + break; + case SID_ATTR_PARA_LINESPACE_20: + { + SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL ); + aItem.SetPropLineSpace( 200 ); + aNewAttr.Put( aItem ); + } + break; + case SID_SET_SUPER_SCRIPT: + { + SvxEscapementItem aItem( EE_CHAR_ESCAPEMENT ); + SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue()); + + if( eEsc == SvxEscapement::Superscript ) + aItem.SetEscapement( SvxEscapement::Off ); + else + aItem.SetEscapement( SvxEscapement::Superscript ); + aNewAttr.Put( aItem ); + } + break; + case SID_SET_SUB_SCRIPT: + { + SvxEscapementItem aItem( EE_CHAR_ESCAPEMENT ); + SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue()); + + if( eEsc == SvxEscapement::Subscript ) + aItem.SetEscapement( SvxEscapement::Off ); + else + aItem.SetEscapement( SvxEscapement::Subscript ); + aNewAttr.Put( aItem ); + } + break; + + // attributes for TextObjectBar + case SID_ATTR_CHAR_FONT: + mpViewShell->GetViewFrame()->GetDispatcher()-> + Execute( SID_CHAR_DLG, SfxCallMode::ASYNCHRON ); + break; + case SID_ATTR_CHAR_FONTHEIGHT: + mpViewShell->GetViewFrame()->GetDispatcher()-> + Execute( SID_CHAR_DLG, SfxCallMode::ASYNCHRON ); + break; + case SID_ATTR_CHAR_COLOR: + break; +// #i35937# removed need for FN_NUM_BULLET_ON handling + } + + rReq.Done( aNewAttr ); + pArgs = rReq.GetArgs(); + } + else if ( nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT || + nSlot == SID_ATTR_PARA_RIGHT_TO_LEFT ) + { + bool bLeftToRight = nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT; + + SvxAdjust nAdjust = SvxAdjust::Left; + if( const SvxAdjustItem* pAdjustItem = aEditAttr.GetItemIfSet(EE_PARA_JUST) ) + nAdjust = pAdjustItem->GetAdjust(); + + if( bLeftToRight ) + { + aNewAttr.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) ); + if( nAdjust == SvxAdjust::Right ) + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) ); + } + else + { + aNewAttr.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) ); + if( nAdjust == SvxAdjust::Left ) + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) ); + } + + rReq.Done( aNewAttr ); + pArgs = rReq.GetArgs(); + + Invalidate( SID_RULER_TEXT_RIGHT_TO_LEFT ); + } + else if ( nSlot == SID_ATTR_CHAR_FONT || + nSlot == SID_ATTR_CHAR_FONTHEIGHT || + nSlot == SID_ATTR_CHAR_POSTURE || + nSlot == SID_ATTR_CHAR_WEIGHT ) + { + // #i78017 establish the same behaviour as in Writer + SvtScriptType nScriptType = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX; + if (nSlot == SID_ATTR_CHAR_FONT) + nScriptType = mpView->GetScriptType(); + + SfxItemPool& rPool = mpView->GetDoc().GetPool(); + SvxScriptSetItem aSvxScriptSetItem( nSlot, rPool ); + aSvxScriptSetItem.PutItemForScriptType( nScriptType, pArgs->Get( rPool.GetWhich( nSlot ) ) ); + aNewAttr.Put( aSvxScriptSetItem.GetItemSet() ); + rReq.Done( aNewAttr ); + pArgs = rReq.GetArgs(); + } + else if (nSlot == SID_ATTR_PARA_ADJUST_LEFT || + nSlot == SID_ATTR_PARA_ADJUST_CENTER || + nSlot == SID_ATTR_PARA_ADJUST_RIGHT || + nSlot == SID_ATTR_PARA_ADJUST_BLOCK) + { + switch( nSlot ) + { + case SID_ATTR_PARA_ADJUST_LEFT: + { + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) ); + } + break; + case SID_ATTR_PARA_ADJUST_CENTER: + { + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) ); + } + break; + case SID_ATTR_PARA_ADJUST_RIGHT: + { + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) ); + } + break; + case SID_ATTR_PARA_ADJUST_BLOCK: + { + aNewAttr.Put( SvxAdjustItem( SvxAdjust::Block, EE_PARA_JUST ) ); + } + break; + } + rReq.Done( aNewAttr ); + pArgs = rReq.GetArgs(); + } + else if(nSlot == SID_ATTR_CHAR_KERNING) + { + aNewAttr.Put(pArgs->Get(pArgs->GetPool()->GetWhich(nSlot))); + rReq.Done( aNewAttr ); + pArgs = rReq.GetArgs(); + } + else if(nSlot == SID_SET_SUPER_SCRIPT ) + { + SvxEscapementItem aItem(EE_CHAR_ESCAPEMENT); + SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue()); + + if( eEsc == SvxEscapement::Superscript ) + aItem.SetEscapement( SvxEscapement::Off ); + else + aItem.SetEscapement( SvxEscapement::Superscript ); + aNewAttr.Put( aItem ); + rReq.Done( aNewAttr ); + pArgs = rReq.GetArgs(); + } + else if( nSlot == SID_SET_SUB_SCRIPT ) + { + SvxEscapementItem aItem(EE_CHAR_ESCAPEMENT); + SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue()); + + if( eEsc == SvxEscapement::Subscript ) + aItem.SetEscapement( SvxEscapement::Off ); + else + aItem.SetEscapement( SvxEscapement::Subscript ); + aNewAttr.Put( aItem ); + rReq.Done( aNewAttr ); + pArgs = rReq.GetArgs(); + } + + std::unique_ptr<SfxItemSet> pNewArgs = pArgs->Clone(); + mpView->SetAttributes(*pNewArgs); + + // invalidate entire shell because of performance and + // extension reasons + Invalidate(); + + // to refresh preview (in outline mode), slot has to be invalidated: + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_PREVIEW_STATE, true ); + } + break; + } + + if ( nSlot != SID_STYLE_APPLY && pOLV ) + { + pOLV->ShowCursor(); + pOLV->GetWindow()->GrabFocus(); + } + + Invalidate( SID_OUTLINE_LEFT ); + Invalidate( SID_OUTLINE_RIGHT ); + Invalidate( SID_OUTLINE_UP ); + Invalidate( SID_OUTLINE_DOWN ); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews1.cxx b/sd/source/ui/view/drviews1.cxx new file mode 100644 index 0000000000..a48ab7a115 --- /dev/null +++ b/sd/source/ui/view/drviews1.cxx @@ -0,0 +1,1382 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> +#include <ViewShellImplementation.hxx> + +#include <DrawController.hxx> +#include <com/sun/star/embed/XEmbeddedObject.hpp> + +#include <comphelper/scopeguard.hxx> +#include <rtl/ref.hxx> + +#include <svx/svxids.hrc> +#include <svx/svdpagv.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <svx/svdoole2.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/module.hxx> +#include <sfx2/notebookbar/SfxNotebookBar.hxx> +#include <svx/svdopage.hxx> +#include <svx/fmshell.hxx> +#include <tools/debug.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <vcl/graphicfilter.hxx> + +#include <view/viewoverlaymanager.hxx> + +#include <app.hrc> + +#include <fupoor.hxx> +#include <unokywds.hxx> +#include <sdpage.hxx> +#include <FrameView.hxx> +#include <Window.hxx> +#include <drawview.hxx> +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <Ruler.hxx> +#include <Client.hxx> +#include <slideshow.hxx> +#include <AnimationChildWindow.hxx> +#include <ToolBarManager.hxx> +#include <FormShellManager.hxx> +#include <ViewShellBase.hxx> +#include <LayerTabBar.hxx> +#include <ViewShellManager.hxx> +#include <ViewShellHint.hxx> +#include <SlideSorter.hxx> +#include <SlideSorterViewShell.hxx> +#include <controller/SlideSorterController.hxx> +#include <controller/SlsPageSelector.hxx> + +#include <comphelper/lok.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <vcl/uitest/logger.hxx> +#include <vcl/uitest/eventdescription.hxx> +#include <titledockwin.hxx> +#include <strings.hrc> +#include <sdresid.hxx> + +using namespace com::sun::star; + +namespace sd { + +void DrawViewShell::Activate(bool bIsMDIActivate) +{ + ViewShell::Activate(bIsMDIActivate); + + // tdf#150773: do not grab focus on loading + if (mbFirstTimeActivation) + mbFirstTimeActivation = false; + else + { + + // When the mode is switched to normal the main view shell grabs focus. + // This is done for getting cut/copy/paste commands on slides in the left + // pane (slide sorter view shell) to work properly. + SfxShell* pTopViewShell = GetViewShellBase().GetViewShellManager()->GetTopViewShell(); + if (pTopViewShell == this) + { + GetActiveWindow()->GrabFocus(); + } + } +} + +void DrawViewShell::UIActivating( SfxInPlaceClient* pCli ) +{ + ViewShell::UIActivating(pCli); + + // Disable own controls + maTabControl->Disable(); + if (GetLayerTabControl() != nullptr) + GetLayerTabControl()->Disable(); +} + +void DrawViewShell::UIDeactivated( SfxInPlaceClient* pCli ) +{ + // Enable own controls + maTabControl->Enable(); + if (GetLayerTabControl() != nullptr) + GetLayerTabControl()->Enable(); + + ViewShell::UIDeactivated(pCli); +} + +void DrawViewShell::Deactivate(bool bIsMDIActivate) +{ + // Temporarily disable context broadcasting while the Deactivate() + // call is forwarded to our base class. + const bool bIsContextBroadcasterEnabled (SfxShell::SetContextBroadcasterEnabled(false)); + + ViewShell::Deactivate(bIsMDIActivate); + + SfxShell::SetContextBroadcasterEnabled(bIsContextBroadcasterEnabled); +} + +namespace +{ + class LockUI + { + private: + void Lock(bool bLock); + SfxViewFrame *mpFrame; + public: + explicit LockUI(SfxViewFrame *pFrame) : mpFrame(pFrame) { Lock(true); } + ~LockUI() { Lock(false); } + + }; + + void LockUI::Lock(bool bLock) + { + if (!mpFrame) + return; + mpFrame->Enable( !bLock ); + } +} + +/** + * Called, if state of selection of view is changed + */ + +void DrawViewShell::SelectionHasChanged() +{ + Invalidate(); + + //Update3DWindow(); // 3D-Controller + SfxBoolItem aItem( SID_3D_STATE, true ); + GetViewFrame()->GetDispatcher()->ExecuteList( + SID_3D_STATE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem }); + + SdrOle2Obj* pOleObj = nullptr; + + if ( mpDrawView->AreObjectsMarked() ) + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + + if (rMarkList.GetMarkCount() == 1) + { + SdrMark* pMark = rMarkList.GetMark(0); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + + SdrInventor nInv = pObj->GetObjInventor(); + SdrObjKind nSdrObjKind = pObj->GetObjIdentifier(); + + if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::OLE2) + { + pOleObj = static_cast<SdrOle2Obj*>(pObj); + UpdateIMapDlg( pObj ); + } + else if (nSdrObjKind == SdrObjKind::Graphic) + UpdateIMapDlg( pObj ); + } + } + + ViewShellBase& rBase = GetViewShellBase(); + rBase.SetVerbs( uno::Sequence< embed::VerbDescriptor >() ); + + try + { + Client* pIPClient = static_cast<Client*>(rBase.GetIPClient()); + if ( pIPClient && pIPClient->IsObjectInPlaceActive() ) + { + // as appropriate take ole-objects into account and deactivate + + // this means we recently deselected an inplace active ole object so + // we need to deselect it now + if (!pOleObj) + { + //#i47279# disable frame until after object has completed unload + LockUI aUILock(GetViewFrame()); + pIPClient->DeactivateObject(); + //HMHmpDrView->ShowMarkHdl(); + } + else + { + const uno::Reference < embed::XEmbeddedObject >& xObj = pOleObj->GetObjRef(); + if ( xObj.is() ) + { + rBase.SetVerbs( xObj->getSupportedVerbs() ); + } + else + { + rBase.SetVerbs( uno::Sequence < embed::VerbDescriptor >() ); + } + } + } + else + { + if ( pOleObj ) + { + const uno::Reference < embed::XEmbeddedObject >& xObj = pOleObj->GetObjRef(); + if ( xObj.is() ) + { + rBase.SetVerbs( xObj->getSupportedVerbs() ); + } + else + { + rBase.SetVerbs( uno::Sequence < embed::VerbDescriptor >() ); + } + } + else + { + rBase.SetVerbs( uno::Sequence < embed::VerbDescriptor >() ); + } + } + } + catch( css::uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "sd", "sd::DrawViewShell::SelectionHasChanged()" ); + } + + if( HasCurrentFunction() ) + { + GetCurrentFunction()->SelectionHasChanged(); + } + else + { + GetViewShellBase().GetToolBarManager()->SelectionHasChanged(*this,*mpDrawView); + } + + // Invalidate for every subshell + GetViewShellBase().GetViewShellManager()->InvalidateAllSubShells(this); + + mpDrawView->UpdateSelectionClipboard(); + + GetViewShellBase().GetDrawController()->FireSelectionChangeListener(); +} + +namespace { + +void collectUIInformation(const OUString& aZoom) +{ + EventDescription aDescription; + aDescription.aID = "impress_win"; + aDescription.aParameters = {{"ZOOM", aZoom}}; + aDescription.aAction = "SET"; + aDescription.aKeyWord = "ImpressWindowUIObject"; + aDescription.aParent = "MainWindow"; + + UITestLogger::getInstance().logEvent(aDescription); +} + +} + +/** + * set zoom factor + */ +void DrawViewShell::SetZoom( ::tools::Long nZoom ) +{ + // Make sure that the zoom factor will not be recalculated on + // following window resizings. + mbZoomOnPage = false; + ViewShell::SetZoom( nZoom ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER ); + mpViewOverlayManager->onZoomChanged(); + collectUIInformation(OUString::number(nZoom)); +} + +/** + * Set zoom rectangle for active window + */ + +void DrawViewShell::SetZoomRect( const ::tools::Rectangle& rZoomRect ) +{ + ViewShell::SetZoomRect( rZoomRect ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER ); + mpViewOverlayManager->onZoomChanged(); +} + +/** + * PrepareClose, as appropriate end text input, so other viewshells + * discover a refreshed text object. + */ + +bool DrawViewShell::PrepareClose( bool bUI ) +{ + if ( !ViewShell::PrepareClose(bUI) ) + return false; + + if( HasCurrentFunction() ) + { + sal_uInt16 nID = GetCurrentFunction()->GetSlotID(); + if (nID == SID_TEXTEDIT || nID == SID_ATTR_CHAR) + { + mpDrawView->SdrEndTextEdit(); + } + } + + return true; +} + + +/** + * Set status (enabled/disabled) of menu SfxSlots + */ + +void DrawViewShell::ChangeEditMode(EditMode eEMode, bool bIsLayerModeActive) +{ + if (meEditMode == eEMode && mbIsLayerModeActive == bIsLayerModeActive) + return; + + ViewShellManager::UpdateLock aLock (GetViewShellBase().GetViewShellManager()); + + sal_uInt16 nActualPageId = maTabControl->GetPageId(0); + + if (mePageKind == PageKind::Handout) + { + // at handouts only allow MasterPage + eEMode = EditMode::MasterPage; + } + + GetViewShellBase().GetDrawController()->FireChangeEditMode (eEMode == EditMode::MasterPage); + GetViewShellBase().GetDrawController()->FireChangeLayerMode (bIsLayerModeActive); + + if ( mpDrawView->IsTextEdit() ) + { + // This exits the text edit mode when going in and out of window focus, which is not needed + // Let's keep this call as comment for now as it probably just needs a better conditional. + // mpDrawView->SdrEndTextEdit(); + } + + LayerTabBar* pLayerBar = GetLayerTabControl(); + if (pLayerBar != nullptr) + pLayerBar->EndEditMode(); + maTabControl->EndEditMode(); + + GetViewShellBase().GetDrawController()->BroadcastContextChange(); + + meEditMode = eEMode; + + if(pLayerBar) + { + // #i87182# only switch activation mode of LayerTabBar when there is one, + // else it will not get initialized with the current set of Layers as needed + mbIsLayerModeActive = bIsLayerModeActive; + } + + // Determine whether to show the master view toolbar. The master + // page mode has to be active and the shell must not be a handout + // view. + bool bShowMasterViewToolbar (meEditMode == EditMode::MasterPage + && GetShellType() != ViewShell::ST_HANDOUT); + bool bShowPresentationToolbar (meEditMode != EditMode::MasterPage + && GetShellType() != ViewShell::ST_HANDOUT + && GetShellType() != ViewShell::ST_DRAW); + + // If the master view toolbar is not shown we hide it before + // switching the edit mode. + if (::sd::ViewShell::mpImpl->mbIsInitialized + && IsMainViewShell()) + { + if ( !bShowMasterViewToolbar ) + GetViewShellBase().GetToolBarManager()->ResetToolBars(ToolBarManager::ToolBarGroup::MasterMode); + if ( !bShowPresentationToolbar ) + GetViewShellBase().GetToolBarManager()->ResetToolBars(ToolBarManager::ToolBarGroup::CommonTask); + } + + ConfigureAppBackgroundColor(); + + // tdf#87638 - change slide pane title according to the edit mode + auto setLeftPaneTitleIfPaneExists + = [pViewShell = GetViewFrame()](sal_uInt16 nId, TranslateId aId) + { + if (auto* pChildWindow = pViewShell->GetChildWindow(nId)) + if (auto* pTitledDockingWindow + = static_cast<TitledDockingWindow*>(pChildWindow->GetWindow())) + pTitledDockingWindow->SetTitle(SdResId(aId)); + }; + + if (meEditMode == EditMode::Page) + { + /****************************************************************** + * PAGEMODE + ******************************************************************/ + + maTabControl->Clear(); + + // tdf#87638 - change slide pane title according to the edit mode + setLeftPaneTitleIfPaneExists(SID_LEFT_PANE_DRAW, STR_LEFT_PANE_DRAW_TITLE); + setLeftPaneTitleIfPaneExists(SID_LEFT_PANE_IMPRESS, STR_LEFT_PANE_IMPRESS_TITLE); + + SdPage* pPage; + sal_uInt16 nPageCnt = GetDoc()->GetSdPageCount(mePageKind); + + for (sal_uInt16 i = 0; i < nPageCnt; i++) + { + pPage = GetDoc()->GetSdPage(i, mePageKind); + OUString aPageName = pPage->GetName(); + maTabControl->InsertPage(pPage->getPageId(), aPageName); + + if ( !comphelper::LibreOfficeKit::isActive() && pPage->IsSelected() ) + { + nActualPageId = pPage->getPageId(); + } + } + + maTabControl->SetCurPageId(nActualPageId); + + SwitchPage(maTabControl->GetPagePos(nActualPageId)); + + //tdf#102343 re-enable common undo on switch back from master mode + mpDrawView->GetModel().SetDisableTextEditUsesCommonUndoManager(false); + } + else + { + /****************************************************************** + * MASTERPAGE + ******************************************************************/ + GetViewFrame()->SetChildWindow( + AnimationChildWindow::GetChildWindowId(), false ); + + // tdf#87638 - change slide pane title according to the edit mode + setLeftPaneTitleIfPaneExists(SID_LEFT_PANE_DRAW, STR_LEFT_PANE_DRAW_TITLE_MASTER); + setLeftPaneTitleIfPaneExists(SID_LEFT_PANE_IMPRESS, STR_LEFT_PANE_IMPRESS_TITLE_MASTER); + + if (comphelper::LibreOfficeKit::isActive()) + GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, + ".uno:SlideMasterPage=true"_ostr); + if (!mpActualPage) + { + // as long as there is no mpActualPage, take first + mpActualPage = GetDoc()->GetSdPage(0, mePageKind); + } + + maTabControl->Clear(); + sal_uInt16 nActualMasterPageId = maTabControl->GetPageId(0); + sal_uInt16 nMasterPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind); + + for (sal_uInt16 i = 0; i < nMasterPageCnt; i++) + { + SdPage* pMaster = GetDoc()->GetMasterSdPage(i, mePageKind); + OUString aLayoutName = pMaster->GetLayoutName(); + sal_Int32 nPos = aLayoutName.indexOf(SD_LT_SEPARATOR); + if (nPos != -1) + aLayoutName = aLayoutName.copy(0, nPos); + + maTabControl->InsertPage(pMaster->getPageId(), aLayoutName); + + if (&(mpActualPage->TRG_GetMasterPage()) == pMaster) + { + nActualMasterPageId = pMaster->getPageId(); + } + } + + maTabControl->SetCurPageId(nActualMasterPageId); + SwitchPage(maTabControl->GetPagePos(nActualMasterPageId)); + + //tdf#102343 changing attributes of textboxes in master typically + //changes the stylesheet they are linked to, so if the common + //undo manager is in use, those stylesheet changes are thrown + //away at present + mpDrawView->GetModel().SetDisableTextEditUsesCommonUndoManager(true); + } + + // If the master view toolbar is to be shown we turn it on after the + // edit mode has been changed. + if (::sd::ViewShell::mpImpl->mbIsInitialized && !sfx2::SfxNotebookBar::IsActive() + && IsMainViewShell()) + { + if (bShowMasterViewToolbar) + GetViewShellBase().GetToolBarManager()->SetToolBar( + ToolBarManager::ToolBarGroup::MasterMode, + ToolBarManager::msMasterViewToolBar); + if (bShowPresentationToolbar) + GetViewShellBase().GetToolBarManager()->SetToolBar( + ToolBarManager::ToolBarGroup::CommonTask, + ToolBarManager::msCommonTaskToolBar); + } + + if ( ! mbIsLayerModeActive) + { + maTabControl->Show(); + // Set the tab control only for draw pages. For master page + // this has been done already above. + if (meEditMode == EditMode::Page) + maTabControl->SetCurPageId (nActualPageId); + } + + ResetActualLayer(); + + Invalidate( SID_PAGEMODE ); + Invalidate( SID_LAYERMODE ); + Invalidate( SID_MASTERPAGE ); + Invalidate( SID_DELETE_MASTER_PAGE ); + Invalidate( SID_DELETE_PAGE ); + Invalidate( SID_SLIDE_MASTER_MODE ); + Invalidate( SID_NOTES_MASTER_MODE ); + Invalidate( SID_HANDOUT_MASTER_MODE ); + InvalidateWindows(); + + if (sfx2::SfxNotebookBar::IsActive()) + UIFeatureChanged(); + + SetContextName(GetSidebarContextName()); + +} + +/** + * Generate horizontal ruler + */ + +VclPtr<SvxRuler> DrawViewShell::CreateHRuler (::sd::Window* pWin) +{ + VclPtr<Ruler> pRuler; + WinBits aWBits; + SvxRulerSupportFlags nFlags = SvxRulerSupportFlags::OBJECT; + + aWBits = WB_HSCROLL | WB_3DLOOK | WB_BORDER | WB_EXTRAFIELD; + nFlags |= SvxRulerSupportFlags::SET_NULLOFFSET | + SvxRulerSupportFlags::TABS | + SvxRulerSupportFlags::PARAGRAPH_MARGINS; // new + + pRuler = VclPtr<Ruler>::Create(*this, GetParentWindow(), pWin, nFlags, + GetViewFrame()->GetBindings(), aWBits); + + // Metric ... + sal_uInt16 nMetric = static_cast<sal_uInt16>(GetDoc()->GetUIUnit()); + + if( nMetric == 0xffff ) + nMetric = static_cast<sal_uInt16>(GetViewShellBase().GetViewFrame().GetDispatcher()->GetModule()->GetFieldUnit()); + + pRuler->SetUnit( FieldUnit( nMetric ) ); + + // ... and also set DefTab at the ruler + pRuler->SetDefTabDist( GetDoc()->GetDefaultTabulator() ); // new + + Fraction aUIScale(pWin->GetMapMode().GetScaleX()); + aUIScale *= GetDoc()->GetUIScale(); + pRuler->SetZoom(aUIScale); + + return pRuler; +} + +/** + * Generate vertical ruler + */ + +VclPtr<SvxRuler> DrawViewShell::CreateVRuler(::sd::Window* pWin) +{ + VclPtr<SvxRuler> pRuler; + WinBits aWBits = WB_VSCROLL | WB_3DLOOK | WB_BORDER; + SvxRulerSupportFlags nFlags = SvxRulerSupportFlags::OBJECT; + + pRuler = VclPtr<Ruler>::Create(*this, GetParentWindow(), pWin, nFlags, + GetViewFrame()->GetBindings(), aWBits); + + // Metric same as HRuler, use document setting + sal_uInt16 nMetric = static_cast<sal_uInt16>(GetDoc()->GetUIUnit()); + + if( nMetric == 0xffff ) + nMetric = static_cast<sal_uInt16>(GetViewShellBase().GetViewFrame().GetDispatcher()->GetModule()->GetFieldUnit()); + + pRuler->SetUnit( FieldUnit( nMetric ) ); + + Fraction aUIScale(pWin->GetMapMode().GetScaleY()); + aUIScale *= GetDoc()->GetUIScale(); + pRuler->SetZoom(aUIScale); + + return pRuler; +} + +/** + * Refresh horizontal ruler + */ + +void DrawViewShell::UpdateHRuler() +{ + Invalidate( SID_ATTR_LONG_LRSPACE ); + Invalidate( SID_RULER_PAGE_POS ); + Invalidate( SID_RULER_OBJECT ); + Invalidate( SID_RULER_TEXT_RIGHT_TO_LEFT ); + + if (mpHorizontalRuler) + mpHorizontalRuler->ForceUpdate(); +} + +/** + * Refresh vertical ruler + */ + +void DrawViewShell::UpdateVRuler() +{ + Invalidate( SID_ATTR_LONG_LRSPACE ); + Invalidate( SID_RULER_PAGE_POS ); + Invalidate( SID_RULER_OBJECT ); + + if (mpVerticalRuler) + mpVerticalRuler->ForceUpdate(); +} + +/** + * Refresh TabControl on splitter change + */ + +IMPL_LINK( DrawViewShell, TabSplitHdl, TabBar *, pTab, void ) +{ + const ::tools::Long nMax = maViewSize.Width() - maScrBarWH.Width() + - maTabControl->GetPosPixel().X() ; + + Size aTabSize = maTabControl->GetSizePixel(); + aTabSize.setWidth( std::min(pTab->GetSplitSize(), static_cast<::tools::Long>(nMax-1)) ); + + maTabControl->SetSizePixel(aTabSize); + + if(GetLayerTabControl()) // #i87182# + { + GetLayerTabControl()->SetSizePixel(aTabSize); + } + + Point aPos = maTabControl->GetPosPixel(); + aPos.AdjustX(aTabSize.Width() ); + + Size aScrSize(nMax - aTabSize.Width(), maScrBarWH.Height()); + mpHorizontalScrollBar->SetPosSizePixel(aPos, aScrSize); +} + +/// inherited from sd::ViewShell +SdPage* DrawViewShell::getCurrentPage() const +{ + const sal_uInt16 nPageCount = (meEditMode == EditMode::Page)? + GetDoc()->GetSdPageCount(mePageKind): + GetDoc()->GetMasterSdPageCount(mePageKind); + + sal_uInt16 nCurrentPage = maTabControl->GetCurPagePos(); + DBG_ASSERT((nCurrentPage<nPageCount), "sd::DrawViewShell::getCurrentPage(), illegal page index!"); + if (nCurrentPage >= nPageCount) + nCurrentPage = 0; // play safe here + + if (meEditMode == EditMode::Page) + { + return GetDoc()->GetSdPage(nCurrentPage, mePageKind); + } + else // EditMode::MasterPage + { + return GetDoc()->GetMasterSdPage(nCurrentPage, mePageKind); + } +} + +/** + * Select new refreshed page, in case of a page order change (eg. by undo) + */ + +void DrawViewShell::ResetActualPage() +{ + if (!GetDoc()) + return; + + sal_uInt16 nCurrentPageId = maTabControl->GetCurPageId(); + sal_uInt16 nNewPageId; + sal_uInt16 nCurrentPageNum = maTabControl->GetPagePos(nCurrentPageId); + sal_uInt16 nPageCount = (meEditMode == EditMode::Page)?GetDoc()->GetSdPageCount(mePageKind):GetDoc()->GetMasterSdPageCount(mePageKind); + + if (meEditMode == EditMode::Page) + { + + // Update for TabControl + maTabControl->Clear(); + + SdPage* pPage = nullptr; + + for (sal_uInt16 i = 0; i < nPageCount; i++) + { + pPage = GetDoc()->GetSdPage(i, mePageKind); + OUString aPageName = pPage->GetName(); + maTabControl->InsertPage(pPage->getPageId(), aPageName); + + if (nCurrentPageId == pPage->getPageId()) + { + nCurrentPageNum = i; + GetDoc()->SetSelected(pPage, true); + } + else + GetDoc()->SetSelected(pPage, false); + } + + nNewPageId = maTabControl->GetPageId(nCurrentPageNum); + maTabControl->SetCurPageId(nNewPageId); + } + else // EditMode::MasterPage + { + maTabControl->Clear(); + + sal_uInt16 nMasterPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind); + for (sal_uInt16 i = 0; i < nMasterPageCnt; i++) + { + SdPage* pMaster = GetDoc()->GetMasterSdPage(i, mePageKind); + OUString aLayoutName = pMaster->GetLayoutName(); + sal_Int32 nPos = aLayoutName.indexOf(SD_LT_SEPARATOR); + if (nPos != -1) + aLayoutName = aLayoutName.copy(0, nPos); + maTabControl->InsertPage(pMaster->getPageId(), aLayoutName); + + if (pMaster->getPageId() == nCurrentPageId) + nCurrentPageNum = i; + } + + nNewPageId = maTabControl->GetPageId(nCurrentPageNum); + maTabControl->SetCurPageId(nNewPageId); + SwitchPage(nCurrentPageNum); + } + + bool bAllowChangeFocus = nNewPageId != nCurrentPageId; + SfxBoolItem aI(SID_SWITCHPAGE, bAllowChangeFocus); + GetViewFrame()->GetDispatcher()->ExecuteList(SID_SWITCHPAGE, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, + { &aI }); +} + +/** + * Apply "Verb" on OLE-object. + */ +ErrCode DrawViewShell::DoVerb(sal_Int32 nVerb) +{ + if ( mpDrawView->AreObjectsMarked() ) + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + + if (rMarkList.GetMarkCount() == 1) + { + SdrMark* pMark = rMarkList.GetMark(0); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + + SdrInventor nInv = pObj->GetObjInventor(); + SdrObjKind nSdrObjKind = pObj->GetObjIdentifier(); + + if (nInv == SdrInventor::Default && nSdrObjKind == SdrObjKind::OLE2) + { + ActivateObject( static_cast<SdrOle2Obj*>(pObj), nVerb); + } + } + } + + return ERRCODE_NONE; +} + +/** + * Activate OLE-object + */ +bool DrawViewShell::ActivateObject(SdrOle2Obj* pObj, sal_Int32 nVerb) +{ + bool bActivated = false; + + if ( !GetDocSh()->IsUIActive() ) + { + ToolBarManager::UpdateLock aLock (GetViewShellBase().GetToolBarManager()); + + bActivated = ViewShell::ActivateObject(pObj, nVerb); + } + + return bActivated; +} + +/** + * Mark the desired page as selected (1), deselected (0), toggle (2). + * nPage refers to the page in question. + */ +bool DrawViewShell::SelectPage(sal_uInt16 nPage, sal_uInt16 nSelect) +{ + SdPage* pPage = GetDoc()->GetSdPage(nPage, PageKind::Standard); + + //page selector marks pages to selected in view + auto &pageSelector = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase())->GetSlideSorter().GetController().GetPageSelector(); + + if (pPage) + { + if (nSelect == 0) + { + GetDoc()->SetSelected(pPage, false); // Deselect. + pageSelector.DeselectPage(nPage); + } + else if (nSelect == 1) + { + GetDoc()->SetSelected(pPage, true); // Select. + pageSelector.SelectPage(nPage); + } + else + { + // Toggle. + if (pPage->IsSelected()) + { + GetDoc()->SetSelected(pPage, false); + pageSelector.DeselectPage(nPage); + } + else + { + GetDoc()->SetSelected(pPage, true); + pageSelector.SelectPage(nPage); + } + } + return true; + } + + return false; +} + +bool DrawViewShell::IsSelected(sal_uInt16 nPage) +{ + slidesorter::SlideSorterViewShell* pVShell + = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase()); + if (pVShell != nullptr) + return pVShell->GetSlideSorter().GetController().GetPageSelector().IsPageSelected(nPage); + + return false; +} + +/** + * Switch to desired page. + * nSelectPage refers to the current EditMode + * bAllowChangeFocus set to false when slide is inserted before current page + * and we need to only update the current page number, + * do not disturb editing in that case + */ +bool DrawViewShell::SwitchPage(sal_uInt16 nSelectedPage, bool bAllowChangeFocus) +{ + /** Under some circumstances there are nested calls to SwitchPage() and + may crash the application (activation of form controls when the + shell of the edit view is not on top of the shell stack, see issue + 83888 for details.) Therefore the nested calls are ignored (they + would jump to the wrong page anyway.) + */ + + if (mbIsInSwitchPage) + return false; + mbIsInSwitchPage = true; + comphelper::ScopeGuard aGuard( + [this] () { this->mbIsInSwitchPage = false; } ); + + if (GetActiveWindow()->IsInPaint()) + { + // Switching the current page while a Paint is being executed is + // dangerous. So, post it for later execution and return. + maAsynchronousSwitchPageCall.Post( + [this, nSelectedPage] () { this->SwitchPage(nSelectedPage); } ); + return false; + } + + bool bOK = false; + + // With the current implementation of FuSlideShow there is a problem + // when it displays the show in a window: when the show is stopped it + // returns at one point in time SDRPAGE_NOTFOUND as current page index. + // Because FuSlideShow is currently being rewritten this bug is fixed + // here. + // This is not as bad a hack as it may look because making SwitchPage() + // more robust with respect to invalid page numbers is a good thing + // anyway. + if (nSelectedPage == SDRPAGE_NOTFOUND) + { + nSelectedPage = 0; + } + else + { + // Make sure that the given page index points to an existing page. Move + // the index into the valid range if necessary. + sal_uInt16 nPageCount = (meEditMode == EditMode::Page) + ? GetDoc()->GetSdPageCount(mePageKind) + : GetDoc()->GetMasterSdPageCount(mePageKind); + if (nSelectedPage >= nPageCount) + nSelectedPage = nPageCount-1; + } + + if (IsSwitchPageAllowed()) + { + ModifyGuard aGuard2( GetDoc() ); + + bOK = true; + + if (mpActualPage) + { + SdPage* pNewPage = nullptr; + + if (meEditMode == EditMode::MasterPage) + { + if( GetDoc()->GetMasterSdPageCount(mePageKind) > nSelectedPage ) + pNewPage = GetDoc()->GetMasterSdPage(nSelectedPage, mePageKind); + + if( pNewPage ) + { + SdrPageView* pPV = mpDrawView->GetSdrPageView(); + OUString sPageText(pNewPage->GetLayoutName()); + sal_Int32 nPos = sPageText.indexOf(SD_LT_SEPARATOR); + if (nPos != -1) + sPageText = sPageText.copy(0, nPos); + if (pPV + && pNewPage == dynamic_cast< SdPage* >( pPV->GetPage() ) + && sPageText == maTabControl->GetPageText(maTabControl->GetPageId(nSelectedPage))) + { + // this slide is already visible + return true; + } + } + } + else + { + OSL_ASSERT(mpFrameView!=nullptr); + mpFrameView->SetSelectedPage(nSelectedPage); + + if (GetDoc()->GetSdPageCount(mePageKind) > nSelectedPage) + pNewPage = GetDoc()->GetSdPage(nSelectedPage, mePageKind); + + if (mpActualPage == pNewPage) + { + SdrPageView* pPV = mpDrawView->GetSdrPageView(); + + SdPage* pCurrentPage = pPV ? dynamic_cast<SdPage*>(pPV->GetPage()) : nullptr; + if (pCurrentPage + && pNewPage == pCurrentPage + && maTabControl->GetPageText(maTabControl->GetPageId(nSelectedPage)) == pNewPage->GetName()) + { + // this slide is already visible + return true; + } + } + } + } + + if (bAllowChangeFocus) + mpDrawView->SdrEndTextEdit(); + + mpActualPage = nullptr; + + if (meEditMode == EditMode::Page) + { + mpActualPage = GetDoc()->GetSdPage(nSelectedPage, mePageKind); + } + else + { + SdPage* pMaster = GetDoc()->GetMasterSdPage(nSelectedPage, mePageKind); + + // does the selected page fit to the masterpage? + sal_uInt16 nPageCount = GetDoc()->GetSdPageCount(mePageKind); + for (sal_uInt16 i = 0; i < nPageCount; i++) + { + SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind); + if(pPage && pPage->IsSelected() && pMaster == &(pPage->TRG_GetMasterPage())) + { + mpActualPage = pPage; + break; + } + } + + if (!mpActualPage) + { + // take the first page, that fits to the masterpage + for (sal_uInt16 i = 0; i < nPageCount; i++) + { + SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind); + if(pPage && pMaster == &(pPage->TRG_GetMasterPage())) + { + mpActualPage = pPage; + break; + } + } + } + } + + for (sal_uInt16 i = 0; i < GetDoc()->GetSdPageCount(mePageKind); i++) + { + // deselect all pages + GetDoc()->SetSelected( GetDoc()->GetSdPage(i, mePageKind), false); + } + + if (!mpActualPage) + { + // as far as there is no mpActualPage, take the first + mpActualPage = GetDoc()->GetSdPage(0, mePageKind); + } + + // also select this page (mpActualPage always points at a drawing page, + // never at a masterpage) + GetDoc()->SetSelected(mpActualPage, true); + + if (comphelper::LibreOfficeKit::isActive()) + { + // notify LibreOfficeKit about changed page + OString aPayload = OString::number(nSelectedPage); + if (SfxViewShell* pViewShell = GetViewShell()) + pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload); + } + + rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetDoc() ) ); + if( !xSlideshow.is() || !xSlideshow->isRunning() || ( xSlideshow->getAnimationMode() != ANIMATIONMODE_SHOW ) ) + { + // tighten VisArea, to possibly deactivate objects + // !!! only if we are not in presentation mode (#96279) !!! + OSL_ASSERT (GetViewShell()!=nullptr); + GetViewShell()->DisconnectAllClients(); + VisAreaChanged(::tools::Rectangle(Point(), Size(1, 1))); + } + + // Try to prefetch all graphics for the active page. This will be done + // in threads to be more efficient than loading them on-demand one by one. + std::vector<Graphic*> graphics; + mpActualPage->getGraphicsForPrefetch(graphics); + if(graphics.size() > 1) // threading does not help with loading just one + GraphicFilter::GetGraphicFilter().MakeGraphicsAvailableThreaded(graphics); + + if (meEditMode == EditMode::Page) + { + /********************************************************************** + * PAGEMODE + **********************************************************************/ + GetDoc()->SetSelected(mpActualPage, true); + + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + + if (pPageView) + { + mpFrameView->SetVisibleLayers( pPageView->GetVisibleLayers() ); + mpFrameView->SetPrintableLayers( pPageView->GetPrintableLayers() ); + mpFrameView->SetLockedLayers( pPageView->GetLockedLayers() ); + + if (mePageKind == PageKind::Notes) + { + mpFrameView->SetNotesHelpLines( pPageView->GetHelpLines() ); + } + else if (mePageKind == PageKind::Handout) + { + mpFrameView->SetHandoutHelpLines( pPageView->GetHelpLines() ); + } + else + { + mpFrameView->SetStandardHelpLines( pPageView->GetHelpLines() ); + } + } + + mpDrawView->HideSdrPage(); + maTabControl->SetCurPageId(maTabControl->GetPageId(nSelectedPage)); + mpDrawView->ShowSdrPage(mpActualPage); + GetViewShellBase().GetDrawController()->FireSwitchCurrentPage(mpActualPage); + + SdrPageView* pNewPageView = mpDrawView->GetSdrPageView(); + + if (pNewPageView) + { + pNewPageView->SetVisibleLayers( mpFrameView->GetVisibleLayers() ); + pNewPageView->SetPrintableLayers( mpFrameView->GetPrintableLayers() ); + pNewPageView->SetLockedLayers( mpFrameView->GetLockedLayers() ); + + if (mePageKind == PageKind::Notes) + { + pNewPageView->SetHelpLines( mpFrameView->GetNotesHelpLines() ); + } + else if (mePageKind == PageKind::Handout) + { + pNewPageView->SetHelpLines( mpFrameView->GetHandoutHelpLines() ); + } + else + { + pNewPageView->SetHelpLines( mpFrameView->GetStandardHelpLines() ); + } + } + + OUString aPageName = mpActualPage->GetName(); + + if (maTabControl->GetPageText(maTabControl->GetPageId(nSelectedPage)) != aPageName) + { + maTabControl->SetPageText(maTabControl->GetPageId(nSelectedPage), aPageName); + } + } + else + { + /********************************************************************** + * MASTERPAGE + **********************************************************************/ + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + + if (pPageView) + { + mpFrameView->SetVisibleLayers( pPageView->GetVisibleLayers() ); + mpFrameView->SetPrintableLayers( pPageView->GetPrintableLayers() ); + mpFrameView->SetLockedLayers( pPageView->GetLockedLayers() ); + + if (mePageKind == PageKind::Notes) + { + mpFrameView->SetNotesHelpLines( pPageView->GetHelpLines() ); + } + else if (mePageKind == PageKind::Handout) + { + mpFrameView->SetHandoutHelpLines( pPageView->GetHelpLines() ); + } + else + { + mpFrameView->SetStandardHelpLines( pPageView->GetHelpLines() ); + } + } + + mpDrawView->HideSdrPage(); + maTabControl->SetCurPageId(maTabControl->GetPageId(nSelectedPage)); + + SdPage* pMaster = GetDoc()->GetMasterSdPage(nSelectedPage, mePageKind); + + if( !pMaster ) // if this page should not exist + pMaster = GetDoc()->GetMasterSdPage(0, mePageKind); + + sal_uInt16 nNum = pMaster->GetPageNum(); + mpDrawView->ShowSdrPage(mpDrawView->GetModel().GetMasterPage(nNum)); + + GetViewShellBase().GetDrawController()->FireSwitchCurrentPage(pMaster); + + SdrPageView* pNewPageView = mpDrawView->GetSdrPageView(); + + if (pNewPageView) + { + pNewPageView->SetVisibleLayers( mpFrameView->GetVisibleLayers() ); + pNewPageView->SetPrintableLayers( mpFrameView->GetPrintableLayers() ); + pNewPageView->SetLockedLayers( mpFrameView->GetLockedLayers() ); + + if (mePageKind == PageKind::Notes) + { + pNewPageView->SetHelpLines( mpFrameView->GetNotesHelpLines() ); + } + else if (mePageKind == PageKind::Handout) + { + pNewPageView->SetHelpLines( mpFrameView->GetHandoutHelpLines() ); + } + else + { + pNewPageView->SetHelpLines( mpFrameView->GetStandardHelpLines() ); + } + } + + OUString aLayoutName(pMaster->GetLayoutName()); + sal_Int32 nPos = aLayoutName.indexOf(SD_LT_SEPARATOR); + if (nPos != -1) + aLayoutName = aLayoutName.copy(0, nPos); + + if (maTabControl->GetPageText(maTabControl->GetPageId(nSelectedPage)) != aLayoutName) + { + maTabControl->SetPageText(maTabControl->GetPageId(nSelectedPage), aLayoutName); + } + + if( mePageKind == PageKind::Handout ) + { + // set pages for all available handout presentation objects + sd::ShapeList& rShapeList = pMaster->GetPresentationShapeList(); + SdrObject* pObj = nullptr; + rShapeList.seekShape(0); + + while( (pObj = rShapeList.getNextShape()) ) + { + if( pMaster->GetPresObjKind(pObj) == PresObjKind::Handout ) + { + // #i105146# We want no content to be displayed for PageKind::Handout, + // so just never set a page as content + static_cast<SdrPageObj*>(pObj)->SetReferencedPage(nullptr); + } + } + } + } + + Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel(); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); + VisAreaChanged(aVisAreaWin); + mpDrawView->VisAreaChanged(GetActiveWindow()->GetOutDev()); + + // so navigator (and effect window) notice that + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate(SID_NAVIGATOR_STATE, true); + rBindings.Invalidate(SID_NAVIGATOR_PAGENAME, true); + rBindings.Invalidate(SID_STATUS_PAGE, true); + rBindings.Invalidate(SID_DELETE_MASTER_PAGE, true); + rBindings.Invalidate(SID_DELETE_PAGE, true); + rBindings.Invalidate(SID_ASSIGN_LAYOUT, true); + rBindings.Invalidate(SID_INSERTPAGE, true); + UpdatePreview( mpActualPage ); + + mpDrawView->AdjustMarkHdl(); + } + + return bOK; +} + +/** + * Check if page change is allowed + */ + +bool DrawViewShell::IsSwitchPageAllowed() const +{ + bool bOK = true; + + FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell(); + if (pFormShell != nullptr && !pFormShell->PrepareClose(false)) + bOK = false; + + return bOK; +} + +/** + * Select new refreshed page, in case of a page order change (eg. by undo) + */ + +void DrawViewShell::ResetActualLayer() +{ + LayerTabBar* pLayerBar = GetLayerTabControl(); + if (pLayerBar == nullptr) + return; + + // remember old tab count and current tab id + // this is needed when one layer is renamed to + // restore current tab + sal_uInt16 nOldLayerCnt = pLayerBar->GetPageCount(); // actually it is tab count + sal_uInt16 nOldLayerPos = pLayerBar->GetCurPageId(); // actually it is a tab nId + + /** + * Update for LayerTab + */ + pLayerBar->Clear(); + + OUString aName; // a real layer name + OUString aActiveLayer = mpDrawView->GetActiveLayer(); + sal_uInt16 nActiveLayerPos = SDRLAYERPOS_NOTFOUND; + SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin(); + sal_uInt16 nLayerCnt = rLayerAdmin.GetLayerCount(); + + for ( sal_uInt16 nLayerPos = 0; nLayerPos < nLayerCnt; nLayerPos++ ) + { + aName = rLayerAdmin.GetLayer(nLayerPos)->GetName(); + + if ( aName == aActiveLayer ) + { + nActiveLayerPos = nLayerPos; + } + + if ( aName != sUNO_LayerName_background ) // layer "background" has never a tab + { + if (meEditMode == EditMode::MasterPage) + { + // don't show page layer onto the masterpage + if (aName != sUNO_LayerName_layout && + aName != sUNO_LayerName_controls && + aName != sUNO_LayerName_measurelines) + { + TabBarPageBits nBits = TabBarPageBits::NONE; + SdrPageView* pPV = mpDrawView->GetSdrPageView(); + if (pPV) + { + if (!pPV->IsLayerVisible(aName)) + { + nBits |= TabBarPageBits::Blue; + } + if (pPV->IsLayerLocked(aName)) + { + nBits |= TabBarPageBits::Italic; + } + if (!pPV->IsLayerPrintable(aName)) + { + nBits |= TabBarPageBits::Underline; + } + } + + pLayerBar->InsertPage(nLayerPos+1, aName, nBits); // why +1? It is a nId, not a position. Position is APPEND. + } + } + else + { + // don't show masterpage layer onto the page + if (aName != sUNO_LayerName_background_objects) + { + TabBarPageBits nBits = TabBarPageBits::NONE; + if (!mpDrawView->GetSdrPageView()->IsLayerVisible(aName)) + { + nBits = TabBarPageBits::Blue; + } + if (mpDrawView->GetSdrPageView()->IsLayerLocked(aName)) + { + nBits |= TabBarPageBits::Italic; + } + if (!mpDrawView->GetSdrPageView()->IsLayerPrintable(aName)) + { + nBits |= TabBarPageBits::Underline; + } + + pLayerBar->InsertPage(nLayerPos+1, aName, nBits);// why +1? + } + } + } + } + + if ( nActiveLayerPos == SDRLAYERPOS_NOTFOUND ) + { + if( nOldLayerCnt == pLayerBar->GetPageCount() ) + { + nActiveLayerPos = nOldLayerPos - 1; + } + else + { + nActiveLayerPos = ( meEditMode == EditMode::MasterPage ) ? 2 : 0; + } + + mpDrawView->SetActiveLayer( pLayerBar->GetLayerName(nActiveLayerPos + 1) );// why +1? + } + + pLayerBar->SetCurPageId(nActiveLayerPos + 1); + GetViewFrame()->GetBindings().Invalidate( SID_TOGGLELAYERVISIBILITY ); + GetViewFrame()->GetBindings().Invalidate( SID_MODIFYLAYER ); + GetViewFrame()->GetBindings().Invalidate( SID_DELETE_LAYER ); +} + +/** + * AcceptDrop + */ + +sal_Int8 DrawViewShell::AcceptDrop ( + const AcceptDropEvent& rEvt, + DropTargetHelper& rTargetHelper, + ::sd::Window* /*pTargetWindow*/, + sal_uInt16 /*nPage*/, + SdrLayerID nLayer ) +{ + if( SlideShow::IsRunning( GetViewShellBase() ) ) + return DND_ACTION_NONE; + + return mpDrawView->AcceptDrop( rEvt, rTargetHelper, nLayer ); +} + +/** + * ExecuteDrop + */ + +sal_Int8 DrawViewShell::ExecuteDrop ( + const ExecuteDropEvent& rEvt, + DropTargetHelper& /*rTargetHelper*/, + ::sd::Window* pTargetWindow, + sal_uInt16 nPage, + SdrLayerID nLayer) +{ + if( nPage != SDRPAGE_NOTFOUND ) + nPage = GetDoc()->GetSdPage( nPage, mePageKind )->GetPageNum(); + + if( SlideShow::IsRunning( GetViewShellBase() ) ) + return DND_ACTION_NONE; + + Broadcast(ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START)); + sal_Int8 nResult (mpDrawView->ExecuteDrop( rEvt, pTargetWindow, nPage, nLayer )); + Broadcast(ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END)); + + return nResult; +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews2.cxx b/sd/source/ui/view/drviews2.cxx new file mode 100644 index 0000000000..90cde7c792 --- /dev/null +++ b/sd/source/ui/view/drviews2.cxx @@ -0,0 +1,4018 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <avmedia/mediaplayer.hxx> + +#include <basic/sberrors.hxx> +#include <basic/sbstar.hxx> + +#include <com/sun/star/drawing/XMasterPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPages.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/util/URLTransformer.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/scanner/XScannerManager2.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> + +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/scopeguard.hxx> +#include <comphelper/lok.hxx> + +#include <editeng/contouritem.hxx> +#include <editeng/editdata.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/section.hxx> +#include <editeng/editobj.hxx> +#include <editeng/CustomPropertyField.hxx> +#include <editeng/urlfieldhelper.hxx> + +#include <sal/log.hxx> + +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/msgpool.hxx> +#include <sfx2/msg.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/zoomitem.hxx> + +#include <svx/compressgraphicdialog.hxx> +#include <svx/ClassificationDialog.hxx> +#include <svx/ClassificationCommon.hxx> +#include <svx/bmpmask.hxx> +#include <svx/extedit.hxx> +#include <svx/extrusionbar.hxx> +#include <svx/f3dchild.hxx> +#include <svx/fontwork.hxx> +#include <svx/fontworkbar.hxx> +#include <svx/graphichelper.hxx> +#include <svx/hlnkitem.hxx> +#include <svx/imapdlg.hxx> +#include <svx/sdtagitm.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdoole2.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdundo.hxx> +#include <svx/svxdlg.hxx> +#include <svx/svxids.hrc> +#include <svx/sdtfsitm.hxx> +#include <svx/sdmetitm.hxx> +#include <svx/zoomslideritem.hxx> +#include <svx/xflclit.hxx> +#include <svx/xlnwtit.hxx> +#include <svx/chrtitem.hxx> +#include <svx/xlnclit.hxx> +#include <svx/xflgrit.hxx> + +#include <comphelper/diagnose_ex.hxx> +#include <tools/UnitConversion.hxx> + +#include <unotools/useroptions.hxx> + +#include <vcl/abstdlg.hxx> +#include <vcl/graph.hxx> +#include <vcl/svapp.hxx> +#include <vcl/unohelp2.hxx> +#include <vcl/weld.hxx> + +#include <editeng/cmapitem.hxx> +#include <editeng/escapementitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/numitem.hxx> +#include <svx/svdobj.hxx> +#include <svx/SvxColorChildWindow.hxx> +#include <editeng/outlobj.hxx> +#include <editeng/flstitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/colritem.hxx> + +#include <svl/poolitem.hxx> +#include <svl/style.hxx> +#include <svl/whiter.hxx> + +#include <app.hrc> +#include <strings.hrc> + +#include <AnimationChildWindow.hxx> +#include <DrawDocShell.hxx> +#include <DrawViewShell.hxx> +#include <LayerTabBar.hxx> +#include <Outliner.hxx> +#include <ViewShellHint.hxx> +#include <ViewShellImplementation.hxx> +#include <Window.hxx> +#include <drawdoc.hxx> +#include <drawview.hxx> +#include <fuarea.hxx> +#include <fubullet.hxx> +#include <fuchar.hxx> +#include <fucushow.hxx> +#include <fuconnct.hxx> +#include <fucopy.hxx> +#include <fudspord.hxx> +#include <fuexecuteinteraction.hxx> +#include <fuexpand.hxx> +#include <fuinsert.hxx> +#include <fuinsfil.hxx> +#include <fuline.hxx> +#include <fulinend.hxx> +#include <fulink.hxx> +#include <fumeasur.hxx> +#include <fumorph.hxx> +#include <fuoaprms.hxx> +#include <fuolbull.hxx> +#include <fupage.hxx> +#include <fuparagr.hxx> +#include <fuprlout.hxx> +#include <fuscale.hxx> +#include <fusel.hxx> +#include <fusldlg.hxx> +#include <fusnapln.hxx> +#include <fusumry.hxx> +#include <futempl.hxx> +#include <futhes.hxx> +#include <futransf.hxx> +#include <futxtatt.hxx> +#include <fuvect.hxx> +#include <futext.hxx> +#include <helpids.h> +#include <sdabstdlg.hxx> +#include <sdattr.hxx> +#include <sdpage.hxx> +#include <sdresid.hxx> +#include <unokywds.hxx> +#include <slideshow.hxx> +#include <stlsheet.hxx> +#include <undolayer.hxx> +#include <sfx2/sidebar/Sidebar.hxx> +#include <sfx2/classificationhelper.hxx> +#include <sdmod.hxx> +#include <model/SlsPageDescriptor.hxx> +#include <model/SlsPageEnumerationProvider.hxx> +#include <SlideSorter.hxx> +#include <view/SlideSorterView.hxx> +#include <SlideSorterViewShell.hxx> +#include <controller/SlideSorterController.hxx> +#include <controller/SlsPageSelector.hxx> +#include <tools/GraphicSizeCheck.hxx> + +#include <theme/ThemeColorChanger.hxx> +#include <svx/dialog/ThemeDialog.hxx> +#include <svx/theme/ThemeColorPaletteManager.hxx> +#include <sfx2/lokhelper.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> + +#include <ViewShellBase.hxx> +#include <memory> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +#define MIN_ACTIONS_FOR_DIALOG 5000 ///< if there are more meta objects, we show a dialog during the break up + +namespace sd { + +namespace { + +const SvxFieldItem* findField(editeng::Section const & rSection) +{ + for (SfxPoolItem const * pPool: rSection.maAttributes) + { + if (pPool->Which() == EE_FEATURE_FIELD) + return static_cast<const SvxFieldItem*>(pPool); + } + return nullptr; +} + +bool hasCustomPropertyField(std::vector<editeng::Section> const & aSections, std::u16string_view rName) +{ + for (editeng::Section const & rSection : aSections) + { + const SvxFieldItem* pFieldItem = findField(rSection); + if (pFieldItem) + { + const editeng::CustomPropertyField* pCustomPropertyField = dynamic_cast<const editeng::CustomPropertyField*>(pFieldItem->GetField()); + if (pCustomPropertyField && pCustomPropertyField->GetName() == rName) + return true; + } + } + return false; +} + +OUString getWeightString(SfxItemSet const & rItemSet) +{ + OUString sWeightString = "NORMAL"; + + if (const SfxPoolItem* pItem = rItemSet.GetItem(EE_CHAR_WEIGHT, false)) + { + const SvxWeightItem* pWeightItem = dynamic_cast<const SvxWeightItem*>(pItem); + if (pWeightItem && pWeightItem->GetWeight() == WEIGHT_BOLD) + sWeightString = "BOLD"; + } + return sWeightString; +} + +class ClassificationCommon +{ +protected: + sd::DrawViewShell& m_rDrawViewShell; + uno::Reference<document::XDocumentProperties> m_xDocumentProperties; + uno::Reference<beans::XPropertyContainer> m_xPropertyContainer; + sfx::ClassificationKeyCreator m_aKeyCreator; +public: + ClassificationCommon(sd::DrawViewShell& rDrawViewShell, const css::uno::Reference<css::document::XDocumentProperties>& rDocProps) + : m_rDrawViewShell(rDrawViewShell) + , m_xDocumentProperties(rDocProps) + , m_xPropertyContainer(m_xDocumentProperties->getUserDefinedProperties()) + , m_aKeyCreator(SfxClassificationHelper::getPolicyType()) + {} +}; + +class ClassificationCollector : public ClassificationCommon +{ +private: + std::vector<svx::ClassificationResult> m_aResults; + + void iterateSectionsAndCollect(std::vector<editeng::Section> const & rSections, EditTextObject const & rEditText) + { + sal_Int32 nCurrentParagraph = -1; + OUString sBlank; + + for (editeng::Section const & rSection : rSections) + { + // Insert new paragraph if needed + while (nCurrentParagraph < rSection.mnParagraph) + { + nCurrentParagraph++; + // Get Weight of current paragraph + OUString sWeightProperty = getWeightString(rEditText.GetParaAttribs(nCurrentParagraph)); + // Insert new paragraph into collection + m_aResults.push_back({ svx::ClassificationType::PARAGRAPH, sWeightProperty, sBlank, sBlank }); + } + + const SvxFieldItem* pFieldItem = findField(rSection); + const editeng::CustomPropertyField* pCustomPropertyField = pFieldItem ? + dynamic_cast<const editeng::CustomPropertyField*>(pFieldItem->GetField()) : + nullptr; + if (pCustomPropertyField) + { + const OUString& aKey = pCustomPropertyField->GetName(); + if (m_aKeyCreator.isMarkingTextKey(aKey)) + { + OUString aValue = svx::classification::getProperty(m_xPropertyContainer, aKey); + m_aResults.push_back({ svx::ClassificationType::TEXT, aValue, sBlank, sBlank }); + } + else if (m_aKeyCreator.isCategoryNameKey(aKey) || m_aKeyCreator.isCategoryIdentifierKey(aKey)) + { + OUString aValue = svx::classification::getProperty(m_xPropertyContainer, aKey); + m_aResults.push_back({ svx::ClassificationType::CATEGORY, aValue, sBlank, sBlank }); + } + else if (m_aKeyCreator.isMarkingKey(aKey)) + { + OUString aValue = svx::classification::getProperty(m_xPropertyContainer, aKey); + m_aResults.push_back({ svx::ClassificationType::MARKING, aValue, sBlank, sBlank }); + } + else if (m_aKeyCreator.isIntellectualPropertyPartKey(aKey)) + { + OUString aValue = svx::classification::getProperty(m_xPropertyContainer, aKey); + m_aResults.push_back({ svx::ClassificationType::INTELLECTUAL_PROPERTY_PART, aValue, sBlank, sBlank }); + } + } + } + } + +public: + ClassificationCollector(sd::DrawViewShell & rDrawViewShell, const css::uno::Reference<css::document::XDocumentProperties>& rDocProps) + : ClassificationCommon(rDrawViewShell, rDocProps) + {} + + std::vector<svx::ClassificationResult> const & getResults() const + { + return m_aResults; + } + + void collect() + { + // Set to MASTER mode + EditMode eOldMode = m_rDrawViewShell.GetEditMode(); + if (eOldMode != EditMode::MasterPage) + m_rDrawViewShell.ChangeEditMode(EditMode::MasterPage, false); + + // Scoped guard to revert to the previous mode + comphelper::ScopeGuard const aGuard([this, eOldMode] () { + m_rDrawViewShell.ChangeEditMode(eOldMode, false); + }); + + const sal_uInt16 nCount = m_rDrawViewShell.GetDoc()->GetMasterSdPageCount(PageKind::Standard); + + for (sal_uInt16 nPageIndex = 0; nPageIndex < nCount; ++nPageIndex) + { + SdPage* pMasterPage = m_rDrawViewShell.GetDoc()->GetMasterSdPage(nPageIndex, PageKind::Standard); + for (const rtl::Reference<SdrObject>& pObject : *pMasterPage) + { + SdrRectObj* pRectObject = dynamic_cast<SdrRectObj*>(pObject.get()); + if (pRectObject && pRectObject->GetTextKind() == SdrObjKind::Text) + { + OutlinerParaObject* pOutlinerParagraphObject = pRectObject->GetOutlinerParaObject(); + if (pOutlinerParagraphObject) + { + const EditTextObject& rEditText = pOutlinerParagraphObject->GetTextObject(); + std::vector<editeng::Section> aSections; + rEditText.GetAllSections(aSections); + + // Search for a custom property field that has the classification category identifier key + if (hasCustomPropertyField(aSections, m_aKeyCreator.makeCategoryNameKey())) + { + iterateSectionsAndCollect(aSections, rEditText); + return; + } + } + } + } + } + } +}; + +class ClassificationInserter : public ClassificationCommon +{ +private: + /// Delete the previous existing classification object(s) - if they exist + void deleteExistingObjects() + { + OUString sKey = m_aKeyCreator.makeCategoryNameKey(); + + const sal_uInt16 nCount = m_rDrawViewShell.GetDoc()->GetMasterSdPageCount(PageKind::Standard); + + for (sal_uInt16 nPageIndex = 0; nPageIndex < nCount; ++nPageIndex) + { + SdPage* pMasterPage = m_rDrawViewShell.GetDoc()->GetMasterSdPage(nPageIndex, PageKind::Standard); + for (const rtl::Reference<SdrObject>& pObject : *pMasterPage) + { + SdrRectObj* pRectObject = dynamic_cast<SdrRectObj*>(pObject.get()); + if (pRectObject && pRectObject->GetTextKind() == SdrObjKind::Text) + { + OutlinerParaObject* pOutlinerParagraphObject = pRectObject->GetOutlinerParaObject(); + if (pOutlinerParagraphObject) + { + const EditTextObject& rEditText = pOutlinerParagraphObject->GetTextObject(); + std::vector<editeng::Section> aSections; + rEditText.GetAllSections(aSections); + + if (hasCustomPropertyField(aSections, sKey)) + { + pMasterPage->RemoveObject(pRectObject->GetOrdNum()); + } + } + } + } + } + } + + void fillTheOutliner(Outliner* pOutliner, std::vector<svx::ClassificationResult> const & rResults) + { + sal_Int32 nParagraph = -1; + for (svx::ClassificationResult const & rResult : rResults) + { + + ESelection aPosition(nParagraph, EE_TEXTPOS_MAX_COUNT, nParagraph, EE_TEXTPOS_MAX_COUNT); + + switch (rResult.meType) + { + case svx::ClassificationType::TEXT: + { + OUString sKey = m_aKeyCreator.makeNumberedTextKey(); + svx::classification::addOrInsertDocumentProperty(m_xPropertyContainer, sKey, rResult.msName); + pOutliner->QuickInsertField(SvxFieldItem(editeng::CustomPropertyField(sKey, rResult.msName), EE_FEATURE_FIELD), aPosition); + } + break; + + case svx::ClassificationType::CATEGORY: + { + OUString sKey = m_aKeyCreator.makeCategoryNameKey(); + pOutliner->QuickInsertField(SvxFieldItem(editeng::CustomPropertyField(sKey, rResult.msName), EE_FEATURE_FIELD), aPosition); + } + break; + + case svx::ClassificationType::MARKING: + { + OUString sKey = m_aKeyCreator.makeNumberedMarkingKey(); + svx::classification::addOrInsertDocumentProperty(m_xPropertyContainer, sKey, rResult.msName); + pOutliner->QuickInsertField(SvxFieldItem(editeng::CustomPropertyField(sKey, rResult.msName), EE_FEATURE_FIELD), aPosition); + } + break; + + case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART: + { + OUString sKey = m_aKeyCreator.makeNumberedIntellectualPropertyPartKey(); + svx::classification::addOrInsertDocumentProperty(m_xPropertyContainer, sKey, rResult.msName); + pOutliner->QuickInsertField(SvxFieldItem(editeng::CustomPropertyField(sKey, rResult.msName), EE_FEATURE_FIELD), aPosition); + } + break; + + case svx::ClassificationType::PARAGRAPH: + { + nParagraph++; + pOutliner->Insert(""); + + SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aItemSet(m_rDrawViewShell.GetDoc()->GetPool()); + + if (rResult.msName == "BOLD") + aItemSet.Put(SvxWeightItem(WEIGHT_BOLD, EE_CHAR_WEIGHT)); + else + aItemSet.Put(SvxWeightItem(WEIGHT_NORMAL, EE_CHAR_WEIGHT)); + + SvxNumRule aDefaultNumRule(SvxNumRuleFlags::NONE, 0, false); + aItemSet.Put(SvxNumBulletItem(std::move(aDefaultNumRule), EE_PARA_NUMBULLET)); + + pOutliner->SetParaAttribs(nParagraph, aItemSet); + } + break; + + default: + break; + } + } + } + +public: + ClassificationInserter(sd::DrawViewShell & rDrawViewShell, const css::uno::Reference<css::document::XDocumentProperties>& rDocProps) + : ClassificationCommon(rDrawViewShell, rDocProps) + { + } + + void insert(std::vector<svx::ClassificationResult> const & rResults) + { + // Set to MASTER mode + EditMode eOldMode = m_rDrawViewShell.GetEditMode(); + if (eOldMode != EditMode::MasterPage) + m_rDrawViewShell.ChangeEditMode(EditMode::MasterPage, false); + + // Scoped guard to revert the mode + comphelper::ScopeGuard const aGuard([this, eOldMode] () { + m_rDrawViewShell.ChangeEditMode(eOldMode, false); + }); + + // Delete the previous existing object - if exists + deleteExistingObjects(); + + // Clear properties + svx::classification::removeAllProperties(m_xPropertyContainer); + + SfxClassificationHelper aHelper(m_xDocumentProperties); + + // Apply properties from the BA policy + for (svx::ClassificationResult const & rResult : rResults) + { + if (rResult.meType == svx::ClassificationType::CATEGORY) + aHelper.SetBACName(rResult.msName, SfxClassificationHelper::getPolicyType()); + } + + // Insert full text as document property + svx::classification::insertFullTextualRepresentationAsDocumentProperty(m_xPropertyContainer, m_aKeyCreator, rResults); + + // Create the outliner from the + Outliner* pOutliner = m_rDrawViewShell.GetDoc()->GetInternalOutliner(); + OutlinerMode eOutlinerMode = pOutliner->GetOutlinerMode(); + + comphelper::ScopeGuard const aOutlinerGuard([pOutliner, eOutlinerMode] () { + pOutliner->Init(eOutlinerMode); + }); + + pOutliner->Init(OutlinerMode::TextObject); + + // Fill the outliner with the text from classification result + fillTheOutliner(pOutliner, rResults); + + // Calculate to outliner text size + pOutliner->UpdateFields(); + pOutliner->SetUpdateLayout(true); + Size aTextSize(pOutliner->CalcTextSize()); + pOutliner->SetUpdateLayout(false); + + // Create objects, apply the outliner and add them (objects) to all master pages + const sal_uInt16 nCount = m_rDrawViewShell.GetDoc()->GetMasterSdPageCount(PageKind::Standard); + + for (sal_uInt16 nPageIndex = 0; nPageIndex < nCount; ++nPageIndex) + { + SdPage* pMasterPage = m_rDrawViewShell.GetDoc()->GetMasterSdPage(nPageIndex, PageKind::Standard); + if (!pMasterPage) + continue; + + rtl::Reference<SdrRectObj> pObject = new SdrRectObj( + *m_rDrawViewShell.GetDoc(), // TTTT should be reference + SdrObjKind::Text); + pObject->SetMergedItem(makeSdrTextAutoGrowWidthItem(true)); + pObject->SetOutlinerParaObject(pOutliner->CreateParaObject()); + pMasterPage->InsertObject(pObject.get()); + + // Calculate position + ::tools::Rectangle aRectangle(Point(), pMasterPage->GetSize()); + Point aPosition(aRectangle.Center().X(), aRectangle.Bottom()); + + aPosition.AdjustX( -(aTextSize.Width() / 2) ); + aPosition.AdjustY( -(aTextSize.Height()) ); + + pObject->SetLogicRect(::tools::Rectangle(aPosition, aTextSize)); + } + } +}; + + void lcl_convertStringArguments(const std::unique_ptr<SfxItemSet>& pArgs) + { + const SfxPoolItem* pItem = nullptr; + + if (SfxItemState::SET == pArgs->GetItemState(SID_ATTR_LINE_WIDTH_ARG, false, &pItem)) + { + double fValue = static_cast<const SvxDoubleItem*>(pItem)->GetValue(); + // FIXME: different units... + int nPow = 100; + int nValue = fValue * nPow; + + XLineWidthItem aItem(nValue); + pArgs->Put(aItem); + } + if (SfxItemState::SET == pArgs->GetItemState(SID_FILL_GRADIENT_JSON, false, &pItem)) + { + const SfxStringItem* pJSON = static_cast<const SfxStringItem*>(pItem); + if (pJSON) + { + basegfx::BGradient aGradient = basegfx::BGradient::fromJSON(pJSON->GetValue()); + XFillGradientItem aItem(aGradient); + pArgs->Put(aItem); + } + } + } +} + +/** + * SfxRequests for temporary actions + */ + +void DrawViewShell::FuTemporary(SfxRequest& rReq) +{ + // during a native slide show nothing gets executed! + if(SlideShow::IsRunning( GetViewShellBase() ) && (rReq.GetSlot() != SID_NAVIGATOR)) + return; + + DBG_ASSERT( mpDrawView, "sd::DrawViewShell::FuTemporary(), no draw view!" ); + if( !mpDrawView ) + return; + + CheckLineTo (rReq); + + DeactivateCurrentFunction(); + + sal_uInt16 nSId = rReq.GetSlot(); + + switch ( nSId ) + { + case SID_OUTLINE_TEXT_AUTOFIT: + { + SfxUndoManager* pUndoManager = GetDocSh()->GetUndoManager(); + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + if( rMarkList.GetMarkCount() == 1 ) + { + pUndoManager->EnterListAction("", "", 0, GetViewShellBase().GetViewShellId()); + mpDrawView->BegUndo(); + + SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); + bool bSet = pObj->GetMergedItemSet().GetItem<SdrTextFitToSizeTypeItem>(SDRATTR_TEXT_FITTOSIZE)->GetValue() != drawing::TextFitToSizeType_NONE; + + mpDrawView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj)); + + if (!bSet) + { + //If we are turning on AutoFit we have to turn these off if already on + if (pObj->GetMergedItemSet().GetItem<SdrOnOffItem>(SDRATTR_TEXT_AUTOGROWHEIGHT)->GetValue()) + pObj->SetMergedItem(makeSdrTextAutoGrowHeightItem(false)); + if (pObj->GetMergedItemSet().GetItem<SdrOnOffItem>(SDRATTR_TEXT_AUTOGROWWIDTH)->GetValue()) + pObj->SetMergedItem(makeSdrTextAutoGrowWidthItem(false)); + } + + pObj->SetMergedItem(SdrTextFitToSizeTypeItem(bSet ? drawing::TextFitToSizeType_NONE : drawing::TextFitToSizeType_AUTOFIT)); + + mpDrawView->EndUndo(); + pUndoManager->LeaveListAction(); + } + Cancel(); + rReq.Done(); + } + break; + + // area and line attributes: shall have + // an own Execute method (like StateMethode) + case SID_ATTR_FILL_STYLE: + case SID_ATTR_FILL_COLOR: + case SID_ATTR_FILL_GRADIENT: + case SID_ATTR_FILL_HATCH: + case SID_ATTR_FILL_BITMAP: + case SID_ATTR_FILL_SHADOW: + case SID_ATTR_SHADOW_COLOR: + case SID_ATTR_SHADOW_TRANSPARENCE: + case SID_ATTR_SHADOW_BLUR: + case SID_ATTR_SHADOW_XDISTANCE: + case SID_ATTR_SHADOW_YDISTANCE: + case SID_ATTR_FILL_USE_SLIDE_BACKGROUND: + case SID_ATTR_FILL_TRANSPARENCE: + case SID_ATTR_FILL_FLOATTRANSPARENCE: + + case SID_ATTR_LINE_STYLE: + case SID_ATTR_LINE_DASH: + case SID_ATTR_LINE_WIDTH: + case SID_ATTR_LINE_COLOR: + case SID_ATTR_LINEEND_STYLE: + case SID_ATTR_LINE_START: + case SID_ATTR_LINE_END: + case SID_ATTR_LINE_TRANSPARENCE: + case SID_ATTR_LINE_JOINT: + case SID_ATTR_LINE_CAP: + + case SID_ATTR_TEXT_FITTOSIZE: + { + if( rReq.GetArgs() ) + { + std::unique_ptr<SfxItemSet> pNewArgs = rReq.GetArgs()->Clone(); + lcl_convertStringArguments(pNewArgs); + mpDrawView->SetAttributes(*pNewArgs); + rReq.Done(); + } + else + { + switch( rReq.GetSlot() ) + { + case SID_ATTR_FILL_SHADOW: + case SID_ATTR_SHADOW_COLOR: + case SID_ATTR_SHADOW_TRANSPARENCE: + case SID_ATTR_SHADOW_BLUR: + case SID_ATTR_SHADOW_XDISTANCE: + case SID_ATTR_SHADOW_YDISTANCE: + case SID_ATTR_FILL_STYLE: + case SID_ATTR_FILL_COLOR: + case SID_ATTR_FILL_GRADIENT: + case SID_ATTR_FILL_HATCH: + case SID_ATTR_FILL_BITMAP: + case SID_ATTR_FILL_USE_SLIDE_BACKGROUND: + case SID_ATTR_FILL_TRANSPARENCE: + case SID_ATTR_FILL_FLOATTRANSPARENCE: + GetViewFrame()->GetDispatcher()->Execute( SID_ATTRIBUTES_AREA, SfxCallMode::ASYNCHRON ); + break; + case SID_ATTR_LINE_STYLE: + case SID_ATTR_LINE_DASH: + case SID_ATTR_LINE_WIDTH: + case SID_ATTR_LINE_COLOR: + case SID_ATTR_LINE_TRANSPARENCE: + case SID_ATTR_LINE_JOINT: + case SID_ATTR_LINE_CAP: + GetViewFrame()->GetDispatcher()->Execute( SID_ATTRIBUTES_LINE, SfxCallMode::ASYNCHRON ); + break; + case SID_ATTR_TEXT_FITTOSIZE: + GetViewFrame()->GetDispatcher()->Execute( SID_TEXTATTR_DLG, SfxCallMode::ASYNCHRON ); + break; + } + } + Cancel(); + } + break; + + case SID_HYPHENATION: + { + const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(SID_HYPHENATION); + + if( pItem ) + { + SfxItemSetFixed<EE_PARA_HYPHENATE, EE_PARA_HYPHENATE> aSet( GetPool() ); + bool bValue = pItem->GetValue(); + aSet.Put( SfxBoolItem( EE_PARA_HYPHENATE, bValue ) ); + mpDrawView->SetAttributes( aSet ); + } + else // only for testing purpose + { + OSL_FAIL(" no value for hyphenation!"); + SfxItemSetFixed<EE_PARA_HYPHENATE, EE_PARA_HYPHENATE> aSet( GetPool() ); + aSet.Put( SfxBoolItem( EE_PARA_HYPHENATE, true ) ); + mpDrawView->SetAttributes( aSet ); + } + rReq.Done(); + Cancel(); + } + break; + + case SID_INSERTPAGE: + case SID_INSERTPAGE_QUICK: + { + SdPage* pNewPage = CreateOrDuplicatePage (rReq, mePageKind, GetActualPage()); + Cancel(); + if(HasCurrentFunction(SID_BEZIER_EDIT) ) + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + if (pNewPage != nullptr) + SwitchPage((pNewPage->GetPageNum()-1)/2); + rReq.Done (); + } + break; + + case SID_DUPLICATE_PAGE: + { + auto slideSorter = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase()); + SdPage* pNewPage = nullptr; + if(slideSorter) + DuplicateSelectedSlides(rReq); + else + pNewPage = CreateOrDuplicatePage (rReq, mePageKind, GetActualPage()); + Cancel(); + if(HasCurrentFunction(SID_BEZIER_EDIT) ) + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + if(!slideSorter && pNewPage != nullptr) + SwitchPage((pNewPage->GetPageNum()-1)/2); + rReq.Done(); + } + break; + + case SID_INSERT_MASTER_PAGE: + { + // Use the API to create a new page. + Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier ( + GetDoc()->getUnoModel(), UNO_QUERY); + if (xMasterPagesSupplier.is()) + { + Reference<drawing::XDrawPages> xMasterPages ( + xMasterPagesSupplier->getMasterPages()); + if (xMasterPages.is()) + { + sal_uInt16 nIndex = GetCurPagePos() + 1; + xMasterPages->insertNewByIndex (nIndex); + + // Create shapes for the default layout. + SdPage* pMasterPage = GetDoc()->GetMasterSdPage( + nIndex, PageKind::Standard); + pMasterPage->CreateTitleAndLayout (true,true); + } + } + + Cancel(); + if(HasCurrentFunction(SID_BEZIER_EDIT)) + GetViewFrame()->GetDispatcher()->Execute( + SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + rReq.Done (); + } + break; + + case SID_MODIFYPAGE: + { + if (mePageKind==PageKind::Standard || mePageKind==PageKind::Notes || + (mePageKind==PageKind::Handout && meEditMode==EditMode::MasterPage) ) + { + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + sal_uInt16 nPage = maTabControl->GetCurPagePos(); + mpActualPage = GetDoc()->GetSdPage(nPage, mePageKind); + ::sd::ViewShell::mpImpl->ProcessModifyPageSlot ( + rReq, + mpActualPage, + mePageKind); + } + + Cancel(); + rReq.Done (); + } + break; + + case SID_ASSIGN_LAYOUT: + { + if (mePageKind==PageKind::Standard || mePageKind==PageKind::Notes || (mePageKind==PageKind::Handout && meEditMode==EditMode::MasterPage)) + { + if ( mpDrawView->IsTextEdit() ) + mpDrawView->SdrEndTextEdit(); + + ::sd::ViewShell::mpImpl->AssignLayout(rReq, mePageKind); + } + Cancel(); + rReq.Done (); + } + break; + + case SID_RENAMEPAGE: + case SID_RENAME_MASTER_PAGE: + { + if (mePageKind==PageKind::Standard || mePageKind==PageKind::Notes ) + { + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + + sal_uInt16 nPage = maTabControl->GetCurPagePos(); + SdPage* pCurrentPage = ( GetEditMode() == EditMode::Page ) + ? GetDoc()->GetSdPage( nPage, GetPageKind() ) + : GetDoc()->GetMasterSdPage( nPage, GetPageKind() ); + + OUString aTitle = SdResId(STR_TITLE_RENAMESLIDE); + OUString aDescr = SdResId(STR_DESC_RENAMESLIDE); + const OUString& aPageName = pCurrentPage->GetName(); + + if(rReq.GetArgs()) + { + OUString aName = rReq.GetArgs()->GetItem<const SfxStringItem>(SID_RENAMEPAGE)->GetValue(); + + bool bResult = RenameSlide( maTabControl->GetPageId(nPage), aName ); + DBG_ASSERT( bResult, "Couldn't rename slide" ); + } + else + { + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractSvxNameDialog> aNameDlg(pFact->CreateSvxNameDialog(GetFrameWeld(), aPageName, aDescr)); + aNameDlg->SetText( aTitle ); + aNameDlg->SetCheckNameHdl( LINK( this, DrawViewShell, RenameSlideHdl ) ); + aNameDlg->SetEditHelpId( HID_SD_NAMEDIALOG_PAGE ); + + if( aNameDlg->Execute() == RET_OK ) + { + OUString aNewName; + aNameDlg->GetName( aNewName ); + if (aNewName != aPageName) + { + bool bResult = RenameSlide( maTabControl->GetPageId(nPage), aNewName ); + DBG_ASSERT( bResult, "Couldn't rename slide" ); + } + } + } + } + Cancel(); + rReq.Ignore(); + } + break; + + case SID_RENAMEPAGE_QUICK: + { + if (mePageKind==PageKind::Standard || mePageKind==PageKind::Notes ) + { + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + + maTabControl->StartEditMode( maTabControl->GetCurPageId() ); + } + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_PAGESIZE : // either this (no menu entries or something else!) + { + const SfxItemSet *pArgs = rReq.GetArgs (); + + if (pArgs && pArgs->Count () == 3) + { + const SfxUInt32Item* pWidth = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGEWIDTH); + const SfxUInt32Item* pHeight = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGEHEIGHT); + const SfxBoolItem* pScaleAll = rReq.GetArg<SfxBoolItem>(ID_VAL_SCALEOBJECTS); + + Size aSize (pWidth->GetValue (), pHeight->GetValue ()); + + SetupPage (aSize, 0, 0, 0, 0, true, false, pScaleAll->GetValue ()); + rReq.Ignore (); + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + rReq.Ignore (); + break; + } + + case SID_PAGEMARGIN : // or this (no menu entries or something else!) + { + const SfxItemSet *pArgs = rReq.GetArgs (); + + if (pArgs && pArgs->Count () == 5) + { + const SfxUInt32Item* pLeft = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGELEFT); + const SfxUInt32Item* pRight = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGERIGHT); + const SfxUInt32Item* pUpper = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGETOP); + const SfxUInt32Item* pLower = rReq.GetArg<SfxUInt32Item>(ID_VAL_PAGEBOTTOM); + const SfxBoolItem* pScaleAll = rReq.GetArg<SfxBoolItem>(ID_VAL_SCALEOBJECTS); + + Size aEmptySize (0, 0); + + SetupPage (aEmptySize, pLeft->GetValue (), pRight->GetValue (), + pUpper->GetValue (), pLower->GetValue (), + false, true, pScaleAll->GetValue ()); + rReq.Ignore (); + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + rReq.Ignore (); + break; + } + + case SID_ATTR_ZOOMSLIDER: + { + const SfxItemSet* pArgs = rReq.GetArgs(); + + const SfxUInt16Item* pScale = (pArgs && pArgs->Count () == 1) ? + rReq.GetArg(SID_ATTR_ZOOMSLIDER) : nullptr; + if (pScale && CHECK_RANGE (5, pScale->GetValue (), 3000)) + { + SetZoom (pScale->GetValue ()); + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_ATTR_ZOOM ); + rBindings.Invalidate( SID_ZOOM_IN ); + rBindings.Invalidate( SID_ZOOM_OUT ); + rBindings.Invalidate( SID_ATTR_ZOOMSLIDER ); + + } + + Cancel(); + rReq.Done (); + break; + } + + case SID_ATTR_ZOOM: + { + const SfxItemSet* pArgs = rReq.GetArgs(); + mbZoomOnPage = false; + + if ( pArgs ) + { + SvxZoomType eZT = pArgs->Get( SID_ATTR_ZOOM ).GetType(); + switch( eZT ) + { + case SvxZoomType::PERCENT: + SetZoom( static_cast<::tools::Long>( pArgs->Get( SID_ATTR_ZOOM ).GetValue()) ); + break; + + case SvxZoomType::OPTIMAL: + GetViewFrame()->GetDispatcher()->Execute( SID_SIZE_ALL, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD ); + break; + + case SvxZoomType::PAGEWIDTH: + GetViewFrame()->GetDispatcher()->Execute( SID_SIZE_PAGE_WIDTH, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD ); + break; + + case SvxZoomType::WHOLEPAGE: + GetViewFrame()->GetDispatcher()->Execute( SID_SIZE_PAGE, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD ); + break; + case SvxZoomType::PAGEWIDTH_NOBORDER: + OSL_FAIL("sd::DrawViewShell::FuTemporary(), SvxZoomType::PAGEWIDTH_NOBORDER not handled!" ); + break; + } + rReq.Ignore (); + } + else + { + // open zoom dialog + SetCurrentFunction( FuScale::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + } + Cancel(); + } + break; + + case SID_CHANGEBEZIER: + case SID_CHANGEPOLYGON: + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + } + + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + if( rReq.GetSlot() == SID_CHANGEBEZIER ) + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->ConvertMarkedToPathObj(false); + } + else + { + if( mpDrawView->IsVectorizeAllowed() ) + { + SetCurrentFunction( FuVectorize::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + } + else + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->ConvertMarkedToPolyObj(); + } + } + + Invalidate(SID_CHANGEBEZIER); + Invalidate(SID_CHANGEPOLYGON); + } + Cancel(); + + if( HasCurrentFunction(SID_BEZIER_EDIT) ) + { // where applicable, activate right edit action + GetViewFrame()->GetDispatcher()->Execute(SID_SWITCH_POINTEDIT, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); + } + rReq.Ignore (); + break; + + case SID_CONVERT_TO_CONTOUR: + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + } + + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->ConvertMarkedToPathObj(true); + + Invalidate(SID_CONVERT_TO_CONTOUR); + } + Cancel(); + + rReq.Ignore (); + break; + + case SID_CONVERT_TO_METAFILE: + case SID_CONVERT_TO_BITMAP: + { + // End text edit mode when it is active because the metafile or + // bitmap that will be created does not support it. + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + } + + if ( mpDrawView->IsPresObjSelected(true,true,true) ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + weld::WaitObject aWait(GetFrameWeld()); + + // create SdrGrafObj from metafile/bitmap + Graphic aGraphic; + switch (nSId) + { + case SID_CONVERT_TO_METAFILE: + { + // switch on undo for the next operations + mpDrawView->BegUndo(SdResId(STR_UNDO_CONVERT_TO_METAFILE)); + GDIMetaFile aMetaFile(mpDrawView->GetMarkedObjMetaFile()); + aGraphic = Graphic(aMetaFile); + } + break; + case SID_CONVERT_TO_BITMAP: + { + // Disable spelling during conversion + bool bOnlineSpell = GetDoc()->GetOnlineSpell(); + GetDoc()->SetOnlineSpell(false); + + // switch on undo for the next operations + mpDrawView->BegUndo(SdResId(STR_UNDO_CONVERT_TO_BITMAP)); + bool bDone(false); + + // I have to get the image here directly since GetMarkedObjBitmapEx works + // based on Bitmaps, but not on BitmapEx, thus throwing away the alpha + // channel. Argh! GetMarkedObjBitmapEx itself is too widely used to safely + // change that, e.g. in the exchange formats. For now I can only add this + // exception to get good results for Svgs. This is how the code gets more + // and more crowded, at last I made a remark for myself to change this + // as one of the next tasks. + if(1 == mpDrawView->GetMarkedObjectCount()) + { + const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(mpDrawView->GetMarkedObjectByIndex(0)); + + if(pSdrGrafObj && pSdrGrafObj->isEmbeddedVectorGraphicData()) + { + aGraphic = Graphic(pSdrGrafObj->GetGraphic().getVectorGraphicData()->getReplacement()); + bDone = true; + } + } + + if(!bDone) + { + aGraphic = Graphic(mpDrawView->GetMarkedObjBitmapEx()); + } + // Restore online spelling + GetDoc()->SetOnlineSpell(bOnlineSpell); + } + break; + } + + // create new object + rtl::Reference<SdrGrafObj> pGraphicObj = new SdrGrafObj( + *GetDoc(), + aGraphic); + + // get some necessary info and ensure it + const SdrMarkList& rMarkList(mpDrawView->GetMarkedObjectList()); + const size_t nMarkCount(rMarkList.GetMarkCount()); + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + OSL_ENSURE(nMarkCount, "DrawViewShell::FuTemporary: SID_CONVERT_TO_BITMAP with empty selection (!)"); + OSL_ENSURE(pPageView, "DrawViewShell::FuTemporary: SID_CONVERT_TO_BITMAP without SdrPageView (!)"); + + // fit rectangle of new graphic object to selection's mark rect + ::tools::Rectangle aAllMarkedRect; + rMarkList.TakeBoundRect(pPageView, aAllMarkedRect); + pGraphicObj->SetLogicRect(aAllMarkedRect); + + // #i71540# to keep the order, it is necessary to replace the lowest object + // of the selection with the new object. This also means that with multi + // selection, all other objects need to be deleted first + SdrMark* pFirstMark = rMarkList.GetMark(0); + SdrObject* pReplacementCandidate = pFirstMark->GetMarkedSdrObj(); + + if(nMarkCount > 1) + { + // take first object out of selection + mpDrawView->MarkObj(pReplacementCandidate, pPageView, true, true); + + // clear remaining selection + mpDrawView->DeleteMarkedObj(); + } + + // #i124816# copy layer from lowest object which gets replaced + pGraphicObj->SetLayer(pReplacementCandidate->GetLayer()); + + // now replace lowest object with new one + mpDrawView->ReplaceObjectAtView(pReplacementCandidate, *pPageView, pGraphicObj.get()); + + // switch off undo + mpDrawView->EndUndo(); + } + } + + Cancel(); + + rReq.Done (); + break; + + case SID_REMOVE_HYPERLINK: + { + if (mpDrawView->IsTextEdit()) + { + OutlinerView* pOutView = mpDrawView->GetTextEditOutlinerView(); + if (pOutView) + URLFieldHelper::RemoveURLField(pOutView->GetEditView()); + } + } + Cancel(); + rReq.Done (); + break; + + case SID_SET_DEFAULT: + { + std::optional<SfxItemSet> pSet; + + if (mpDrawView->IsTextEdit()) + { + pSet.emplace( GetPool(), svl::Items<EE_ITEMS_START, EE_ITEMS_END> ); + mpDrawView->SetAttributes( *pSet, true ); + } + else + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const size_t nCount = rMarkList.GetMarkCount(); + + // For every presentation object a SfxItemSet of hard attributes + // and the UserCall is stored in this list. This is because + // at the following mpDrawView->SetAttributes( *pSet, sal_True ) + // they get lost and have to be restored. + std::vector<std::pair<std::unique_ptr<SfxItemSet>,SdrObjUserCall*> > aAttrList; + SdPage* pPresPage = static_cast<SdPage*>( mpDrawView->GetSdrPageView()->GetPage() ); + + for ( size_t i = 0; i < nCount; ++i ) + { + SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj(); + + if( pPresPage->IsPresObj( pObj ) ) + { + auto pNewSet = std::make_unique<SfxItemSetFixed<SDRATTR_TEXT_MINFRAMEHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT>>( GetDoc()->GetPool() ); + pNewSet->Put(pObj->GetMergedItemSet()); + aAttrList.emplace_back(std::move(pNewSet), pObj->GetUserCall()); + } + } + + pSet.emplace( GetPool() ); + mpDrawView->SetAttributes( *pSet, true ); + + sal_uLong j = 0; + + for ( size_t i = 0; i < nCount; ++i ) + { + SfxStyleSheet* pSheet = nullptr; + SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj(); + + if (pObj->GetObjIdentifier() == SdrObjKind::TitleText) + { + pSheet = mpActualPage->GetStyleSheetForPresObj(PresObjKind::Title); + if (pSheet) + pObj->SetStyleSheet(pSheet, false); + } + else if(pObj->GetObjIdentifier() == SdrObjKind::OutlineText) + { + for (sal_uInt16 nLevel = 1; nLevel < 10; nLevel++) + { + pSheet = mpActualPage->GetStyleSheetForPresObj( PresObjKind::Outline ); + DBG_ASSERT(pSheet, "Template for outline object not found"); + if (pSheet) + { + pObj->StartListening(*pSheet); + + if( nLevel == 1 ) + // text frame listens on StyleSheet of level1 + pObj->NbcSetStyleSheet(pSheet, false); + } + } + } + + if( pPresPage->IsPresObj( pObj ) ) + { + std::pair<std::unique_ptr<SfxItemSet>,SdrObjUserCall*> &rAttr = aAttrList[j++]; + + std::unique_ptr<SfxItemSet> & pNewSet(rAttr.first); + SdrObjUserCall* pUserCall = rAttr.second; + + if ( pNewSet && pNewSet->GetItemState( SDRATTR_TEXT_MINFRAMEHEIGHT ) == SfxItemState::SET ) + { + pObj->SetMergedItem(pNewSet->Get(SDRATTR_TEXT_MINFRAMEHEIGHT)); + } + + if ( pNewSet && pNewSet->GetItemState( SDRATTR_TEXT_AUTOGROWHEIGHT ) == SfxItemState::SET ) + { + pObj->SetMergedItem(pNewSet->Get(SDRATTR_TEXT_AUTOGROWHEIGHT)); + } + + if( pUserCall ) + pObj->SetUserCall( pUserCall ); + } + } + } + + pSet.reset(); + Cancel(); + } + break; + + case SID_DELETE_SNAPITEM: + { + SdrPageView* pPV; + Point aMPos = GetActiveWindow()->PixelToLogic( maMousePos ); + sal_uInt16 nHitLog = static_cast<sal_uInt16>(GetActiveWindow()->PixelToLogic( Size( + FuPoor::HITPIX, 0 ) ).Width()); + sal_uInt16 nHelpLine; + + if( mpDrawView->PickHelpLine( aMPos, nHitLog, *GetActiveWindow()->GetOutDev(), nHelpLine, pPV) ) + { + pPV->DeleteHelpLine( nHelpLine ); + } + Cancel(); + rReq.Ignore (); + } + break; + + case SID_DELETE_PAGE: + case SID_DELETE_MASTER_PAGE: + DeleteActualPage(); + Cancel(); + rReq.Ignore (); + break; + + case SID_DELETE_LAYER: + DeleteActualLayer(); + Cancel(); + rReq.Ignore (); + break; + + case SID_ORIGINAL_SIZE: + mpDrawView->SetMarkedOriginalSize(); + Cancel(); + rReq.Done(); + break; + + case SID_DRAW_FONTWORK: + case SID_DRAW_FONTWORK_VERTICAL: + { + svx::FontworkBar::execute(*mpView, rReq, GetViewFrame()->GetBindings()); // SJ: can be removed (I think) + Cancel(); + rReq.Done(); + } + break; + + case SID_SAVE_GRAPHIC: + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + if( rMarkList.GetMarkCount() == 1 ) + { + const SdrGrafObj* pObj = dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj()); + if (pObj && pObj->GetGraphicType() == GraphicType::Bitmap) + { + weld::Window* pFrame = GetFrameWeld(); + GraphicAttr aGraphicAttr = pObj->GetGraphicAttr(); + short nState = RET_CANCEL; + if (aGraphicAttr != GraphicAttr()) // the image has been modified + { + if (pFrame) + { + nState = GraphicHelper::HasToSaveTransformedImage(pFrame); + } + } + else + { + nState = RET_NO; + } + + if (nState == RET_YES) + { + GraphicHelper::ExportGraphic(pFrame, pObj->GetTransformedGraphic(), ""); + } + else if (nState == RET_NO) + { + const GraphicObject& aGraphicObject(pObj->GetGraphicObject()); + GraphicHelper::ExportGraphic(pFrame, aGraphicObject.GetGraphic(), ""); + } + } + } + Cancel(); + rReq.Ignore(); + } + break; + + case SID_EXTERNAL_EDIT: + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + if( rMarkList.GetMarkCount() == 1 ) + { + SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); + if( auto pGraphicObj = dynamic_cast<SdrGrafObj*>( pObj ) ) + if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap ) + { + GraphicObject aGraphicObject( pGraphicObj->GetGraphicObject() ); + m_ExternalEdits.push_back( + std::make_unique<SdrExternalToolEdit>( + mpDrawView.get(), pGraphicObj)); + m_ExternalEdits.back()->Edit( &aGraphicObject ); + } + } + Cancel(); + rReq.Ignore(); + } + break; + + case SID_COMPRESS_GRAPHIC: + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + if( rMarkList.GetMarkCount() == 1 ) + { + SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); + + if( auto pGraphicObj = dynamic_cast<SdrGrafObj*>( pObj ) ) + if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap ) + { + CompressGraphicsDialog dialog(GetFrameWeld(), pGraphicObj, GetViewFrame()->GetBindings() ); + if (dialog.run() == RET_OK) + { + rtl::Reference<SdrGrafObj> pNewObject = dialog.GetCompressedSdrGrafObj(); + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + OUString aUndoString = mpDrawView->GetDescriptionOfMarkedObjects() + " Compress"; + mpDrawView->BegUndo( aUndoString ); + mpDrawView->ReplaceObjectAtView( pObj, *pPageView, pNewObject.get() ); + mpDrawView->EndUndo(); + } + } + } + Cancel(); + rReq.Ignore(); + } + break; + + case SID_GRAPHIC_SIZE_CHECK: + { + sd::GraphicSizeCheckGUIResult aResult(GetDoc()); + svx::GenericCheckDialog aDialog(GetFrameWeld(), aResult); + aDialog.run(); + + Cancel(); + rReq.Ignore(); + } + break; + + case SID_ATTRIBUTES_LINE: // BASIC + { + SetCurrentFunction( FuLine::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + if (rReq.GetArgs()) + Cancel(); + } + break; + + case SID_ATTRIBUTES_AREA: // BASIC + { + SetCurrentFunction( FuArea::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + if (rReq.GetArgs()) + Cancel(); + } + break; + + case SID_ATTR_TRANSFORM: + { + SetCurrentFunction( FuTransform::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + // tdf#138963 conditions tested for here must be the same as those + // of the early returns from FuTransform::DoExecute + if (rReq.GetArgs() || !mpDrawView->AreObjectsMarked()) + { + Invalidate(SID_RULER_OBJECT); + Cancel(); + } + } + break; + case SID_MOVE_SHAPE_HANDLE: + { + const SfxItemSet *pArgs = rReq.GetArgs (); + if (pArgs && pArgs->Count () >= 3) + { + const SfxUInt32Item* handleNumItem = rReq.GetArg<SfxUInt32Item>(FN_PARAM_1); + const SfxUInt32Item* newPosXTwips = rReq.GetArg<SfxUInt32Item>(FN_PARAM_2); + const SfxUInt32Item* newPosYTwips = rReq.GetArg<SfxUInt32Item>(FN_PARAM_3); + const SfxInt32Item* OrdNum = rReq.GetArg<SfxInt32Item>(FN_PARAM_4); + + const sal_uLong handleNum = handleNumItem->GetValue(); + const sal_uLong newPosX = convertTwipToMm100(newPosXTwips->GetValue()); + const sal_uLong newPosY = convertTwipToMm100(newPosYTwips->GetValue()); + + mpDrawView->MoveShapeHandle(handleNum, Point(newPosX, newPosY), OrdNum ? OrdNum->GetValue() : -1); + Cancel(); + } + break; + } + case SID_CHAR_DLG_EFFECT: + case SID_CHAR_DLG: // BASIC + { + SetCurrentFunction( FuChar::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_PARA_DLG: + { + SetCurrentFunction( FuParagraph::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case FN_NUM_BULLET_ON: + { + // The value (sal_uInt16)0xFFFF means set bullet on/off. + SfxUInt16Item aItem(FN_SVX_SET_BULLET, sal_uInt16(0xFFFF)); + GetViewFrame()->GetDispatcher()->ExecuteList(FN_SVX_SET_BULLET, + SfxCallMode::RECORD, { &aItem }); + } + break; + + case FN_NUM_NUMBERING_ON: + { + // The value (sal_uInt16)0xFFFF means set bullet on/off. + SfxUInt16Item aItem(FN_SVX_SET_NUMBER, sal_uInt16(0xFFFF)); + GetViewFrame()->GetDispatcher()->ExecuteList(FN_SVX_SET_NUMBER, + SfxCallMode::RECORD, { &aItem }); + } + break; + + case SID_OUTLINE_BULLET: + case FN_SVX_SET_BULLET: + case FN_SVX_SET_NUMBER: + { + SetCurrentFunction( FuBulletAndPosition::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case FN_INSERT_SOFT_HYPHEN: + case FN_INSERT_HARDHYPHEN: + case FN_INSERT_HARD_SPACE: + case FN_INSERT_NNBSP: + case SID_INSERT_RLM : + case SID_INSERT_LRM : + case SID_INSERT_WJ : + case SID_INSERT_ZWSP: + case SID_CHARMAP: + { + SetCurrentFunction( FuBullet::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_PRESENTATION_LAYOUT: + { + SetCurrentFunction( FuPresentationLayout::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + Cancel(); + } + break; + + case SID_PASTE_SPECIAL: + { + SetCurrentFunction( FuInsertClipboard::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_CHANGE_PICTURE: + case SID_INSERT_GRAPHIC: + { + SetCurrentFunction( FuInsertGraphic::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, + nSId == SID_CHANGE_PICTURE ) ); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_INSERT_AVMEDIA: + { + SetCurrentFunction( FuInsertAVMedia::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_INSERT_OBJECT: + case SID_INSERT_FLOATINGFRAME: + case SID_INSERT_MATH: + case SID_INSERT_DIAGRAM: + case SID_ATTR_TABLE: + { + SetCurrentFunction( FuInsertOLE::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + // Set the selection tool as the old one. This in particular important for the + // zoom function, in which clicking without dragging zooms as well, and that + // makes exiting the object editing mode impossible. + if (dynamic_cast<FuSelection*>( GetOldFunction().get() ) == nullptr) + SetOldFunction( FuSelection::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + rReq.Ignore (); + } + break; + case SID_CLASSIFICATION_APPLY: + { + const SfxItemSet* pArgs = rReq.GetArgs(); + const SfxPoolItem* pItem = nullptr; + if (pArgs && pArgs->GetItemState(nSId, false, &pItem) == SfxItemState::SET) + { + const OUString& rName = static_cast<const SfxStringItem*>(pItem)->GetValue(); + auto eType = SfxClassificationPolicyType::IntellectualProperty; + if (pArgs->GetItemState(SID_TYPE_NAME, false, &pItem) == SfxItemState::SET) + { + const OUString& rType = static_cast<const SfxStringItem*>(pItem)->GetValue(); + eType = SfxClassificationHelper::stringToPolicyType(rType); + } + if (SfxViewFrame* pViewFrame = GetViewFrame()) + { + if (SfxObjectShell* pObjectShell = pViewFrame->GetObjectShell()) + { + SfxClassificationHelper aHelper(pObjectShell->getDocProperties()); + aHelper.SetBACName(rName, eType); + } + } + } + else + SAL_WARN("sd.ui", "missing parameter for SID_CLASSIFICATION_APPLY"); + + Cancel(); + rReq.Ignore(); + } + break; + + case SID_CLASSIFICATION_DIALOG: + { + if (SfxObjectShell* pObjShell = SfxObjectShell::Current()) + { + css::uno::Reference<css::document::XDocumentProperties> xDocProps(pObjShell->getDocProperties()); + auto xDialog = std::make_shared<svx::ClassificationDialog>(GetFrameWeld(), xDocProps, false, [](){} ); + ClassificationCollector aCollector(*this, xDocProps); + aCollector.collect(); + + xDialog->setupValues(std::vector(aCollector.getResults())); + + if (RET_OK == xDialog->run()) + { + ClassificationInserter aInserter(*this, xDocProps); + aInserter.insert(xDialog->getResult()); + } + xDialog.reset(); + } + + Cancel(); + rReq.Ignore(); + } + break; + + case SID_COPYOBJECTS: + { + if ( mpDrawView->IsPresObjSelected(false) ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + + SetCurrentFunction( FuCopy::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + } + Cancel(); + rReq.Ignore (); + } + break; + + case SID_INSERTFILE: // BASIC + { + Broadcast (ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START)); + SetCurrentFunction( FuInsertFile::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Broadcast (ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END)); + Cancel(); + rReq.Done (); + } + break; + + case SID_SELECT_BACKGROUND: + case SID_SAVE_BACKGROUND: + case SID_ATTR_PAGE_SIZE: + case SID_ATTR_PAGE: + case SID_PAGESETUP: // BASIC ?? + { + SetCurrentFunction( FuPage::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + rReq.Ignore (); // we generate independent macros !! + } + break; + + case SID_BEFORE_OBJ: + case SID_BEHIND_OBJ: + { + SetCurrentFunction( FuDisplayOrder::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + rReq.Done(); + // finishes itself, no Cancel() needed! + } + break; + + case SID_REVERSE_ORDER: // BASIC + { + mpDrawView->ReverseOrderOfMarked(); + Cancel(); + rReq.Done (); + } + break; + + case SID_ANIMATION_EFFECTS: + { + SetCurrentFunction( FuObjectAnimationParameters::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + Cancel(); + } + break; + + case SID_EXECUTE_ANIMATION_EFFECT: + { + SetCurrentFunction(FuExecuteInteraction::Create(this, GetActiveWindow(), + mpDrawView.get(), GetDoc(), rReq)); + Cancel(); + } + break; + + case SID_LINEEND_POLYGON: + { + SetCurrentFunction( FuLineEnd::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_CAPTUREPOINT: + // negative value to signal call from menu + maMousePos = Point(-1,-1); + [[fallthrough]]; + case SID_SET_SNAPITEM: + { + SetCurrentFunction( FuSnapLine::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + Cancel(); + } + break; + + case SID_MANAGE_LINKS: + { + SetCurrentFunction( FuLink::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_THESAURUS: + { + SetCurrentFunction( FuThesaurus::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_TEXTATTR_DLG: + { + if (mpDrawView->IsTextEdit()) + mpDrawView->SdrEndTextEdit(); + SetCurrentFunction( FuTextAttrDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_MEASURE_DLG: + { + SetCurrentFunction( FuMeasureDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_CONNECTION_DLG: + { + SetCurrentFunction( FuConnectionDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + rReq.Done(); + } + break; + + case SID_CONNECTION_NEW_ROUTING: + { + SfxItemSetFixed<SDRATTR_EDGELINE1DELTA, SDRATTR_EDGELINE3DELTA> aDefAttr( GetPool() ); + GetView()->SetAttributes( aDefAttr, true ); // (ReplaceAll) + + Cancel(); + rReq.Done(); + } + break; + + case SID_TWAIN_SELECT: + { + if( mxScannerManager.is() ) + { + try + { + const css::uno::Sequence< css::scanner::ScannerContext > + aContexts( mxScannerManager->getAvailableScanners() ); + + if( aContexts.hasElements() ) + { + css::scanner::ScannerContext aContext( aContexts.getConstArray()[ 0 ] ); + + Reference<lang::XInitialization> xInit(mxScannerManager, UNO_QUERY); + if (xInit.is()) + { + // initialize dialog + weld::Window* pWindow = rReq.GetFrameWeld(); + uno::Sequence<uno::Any> aSeq(comphelper::InitAnyPropertySequence( + { + {"ParentWindow", pWindow ? uno::Any(pWindow->GetXWindow()) : uno::Any(Reference<awt::XWindow>())} + })); + xInit->initialize( aSeq ); + } + + mxScannerManager->configureScannerAndScan( aContext, mxScannerListener ); + } + } + catch(...) + { + } + } + + Cancel(); + rReq.Done(); + } + break; + + case SID_TWAIN_TRANSFER: + { + bool bDone = false; + + if( mxScannerManager.is() ) + { + try + { + const css::uno::Sequence< css::scanner::ScannerContext > aContexts( mxScannerManager->getAvailableScanners() ); + + if( aContexts.hasElements() ) + { + mxScannerManager->startScan( aContexts.getConstArray()[ 0 ], mxScannerListener ); + bDone = true; + } + } + catch( ... ) + { + } + } + + if( !bDone ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, +#ifndef UNX + SdResId(STR_TWAIN_NO_SOURCE) +#else + SdResId(STR_TWAIN_NO_SOURCE_UNX) +#endif + )); + xInfoBox->run(); + + } + else + { + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_TWAIN_SELECT ); + rBindings.Invalidate( SID_TWAIN_TRANSFER ); + } + + Cancel(); + rReq.Done(); + } + break; + + case SID_POLYGON_MORPHING: + { + SetCurrentFunction( FuMorph::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_INSERTLAYER: + { + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + + SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin(); + sal_uInt16 nLayerCnt = rLayerAdmin.GetLayerCount(); + sal_uInt16 nLayer = nLayerCnt - 2 + 1; + OUString aLayerName = SdResId(STR_LAYER) + OUString::number(nLayer); + OUString aLayerTitle, aLayerDesc; + bool bIsVisible = false; + bool bIsLocked = false; + bool bIsPrintable = false; + + const SfxItemSet* pArgs = rReq.GetArgs(); + + if (! pArgs) + { + SfxItemSetFixed<ATTR_LAYER_START, ATTR_LAYER_END> aNewAttr( GetDoc()->GetPool() ); + + aNewAttr.Put( makeSdAttrLayerName( aLayerName ) ); + aNewAttr.Put( makeSdAttrLayerTitle() ); + aNewAttr.Put( makeSdAttrLayerDesc() ); + aNewAttr.Put( makeSdAttrLayerVisible() ); + aNewAttr.Put( makeSdAttrLayerPrintable() ); + aNewAttr.Put( makeSdAttrLayerLocked() ); + aNewAttr.Put( makeSdAttrLayerThisPage() ); + + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + vcl::Window* pWin = GetActiveWindow(); + ScopedVclPtr<AbstractSdInsertLayerDlg> pDlg( pFact->CreateSdInsertLayerDlg(pWin ? pWin->GetFrameWeld() : nullptr, aNewAttr, true, SdResId(STR_INSERTLAYER)) ); + pDlg->SetHelpId( SD_MOD()->GetSlotPool()->GetSlot( SID_INSERTLAYER )->GetCommand() ); + + // test for already existing names + bool bLoop = true; + while( bLoop && pDlg->Execute() == RET_OK ) + { + pDlg->GetAttr( aNewAttr ); + aLayerName = aNewAttr.Get(ATTR_LAYER_NAME).GetValue (); + + if( rLayerAdmin.GetLayer( aLayerName ) + || aLayerName.isEmpty() + || LayerTabBar::IsLocalizedNameOfStandardLayer( aLayerName) ) + { + // name already exists + std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + SdResId(STR_WARN_NAME_DUPLICATE))); + xWarn->run(); + } + else + bLoop = false; + } + if( bLoop ) // was canceled + { + pDlg.disposeAndClear(); + Cancel(); + rReq.Ignore (); + break; + } + else + { + aLayerTitle = aNewAttr.Get(ATTR_LAYER_TITLE).GetValue(); + aLayerDesc = aNewAttr.Get(ATTR_LAYER_DESC).GetValue (); + bIsVisible = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_VISIBLE)).GetValue (); + bIsLocked = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_LOCKED)).GetValue () ; + bIsPrintable = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_PRINTABLE)).GetValue () ; + } + } + else if (pArgs->Count () != 4) + { +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + Cancel(); + rReq.Ignore (); + break; + } + else + { + const SfxStringItem* pLayerName = rReq.GetArg<SfxStringItem>(ID_VAL_LAYERNAME); + const SfxBoolItem* pIsVisible = rReq.GetArg<SfxBoolItem>(ID_VAL_ISVISIBLE); + const SfxBoolItem* pIsLocked = rReq.GetArg<SfxBoolItem>(ID_VAL_ISLOCKED); + const SfxBoolItem* pIsPrintable = rReq.GetArg<SfxBoolItem>(ID_VAL_ISPRINTABLE); + + aLayerName = pLayerName->GetValue (); + bIsVisible = pIsVisible->GetValue (); + bIsLocked = pIsLocked->GetValue (); + bIsPrintable = pIsPrintable->GetValue (); + } + + OUString aPrevLayer = mpDrawView->GetActiveLayer(); + SdrLayer* pLayer; + sal_uInt16 nPrevLayer = 0; + nLayerCnt = rLayerAdmin.GetLayerCount(); + + for ( nLayer = 0; nLayer < nLayerCnt; nLayer++ ) + { + pLayer = rLayerAdmin.GetLayer(nLayer); + OUString aName = pLayer->GetName(); + + if ( aPrevLayer == aName ) + { + nPrevLayer = std::max(nLayer, sal_uInt16(4)); + } + } + + mpDrawView->InsertNewLayer(aLayerName, nPrevLayer + 1); + pLayer = rLayerAdmin.GetLayer(aLayerName); + if( pLayer ) + { + pLayer->SetTitle( aLayerTitle ); + pLayer->SetDescription( aLayerDesc ); + } + + mpDrawView->SetLayerVisible( aLayerName, bIsVisible ); + mpDrawView->SetLayerLocked( aLayerName, bIsLocked); + mpDrawView->SetLayerPrintable(aLayerName, bIsPrintable); + + mpDrawView->SetActiveLayer(aLayerName); + + ResetActualLayer(); + + GetDoc()->SetChanged(); + + GetViewFrame()->GetDispatcher()->Execute(SID_SWITCHLAYER, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); + + Cancel(); + rReq.Done (); + } + break; + + case SID_MODIFYLAYER: + { + if(!GetLayerTabControl()) // #i87182# + { + OSL_ENSURE(false, "No LayerTabBar (!)"); + Cancel(); + rReq.Ignore(); + break; + } + + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + + SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin(); + sal_uInt16 nCurPage = GetLayerTabControl()->GetCurPageId(); + OUString aLayerName = GetLayerTabControl()->GetLayerName(nCurPage); + SdrLayer* pLayer = rLayerAdmin.GetLayer(aLayerName); + + OUString aLayerTitle = pLayer->GetTitle(); + OUString aLayerDesc = pLayer->GetDescription(); + + OUString aOldLayerName(aLayerName); + OUString aOldLayerTitle(aLayerTitle); + OUString aOldLayerDesc(aLayerDesc); + + bool bIsVisible, bIsLocked, bIsPrintable; + bool bOldIsVisible = bIsVisible = mpDrawView->IsLayerVisible(aLayerName); + bool bOldIsLocked = bIsLocked = mpDrawView->IsLayerLocked(aLayerName); + bool bOldIsPrintable = bIsPrintable = mpDrawView->IsLayerPrintable(aLayerName); + + const SfxItemSet* pArgs = rReq.GetArgs(); + // is it allowed to delete the layer? + bool bDelete = !( LayerTabBar::IsRealNameOfStandardLayer(aLayerName) ); + + if (! pArgs) + { + SfxItemSetFixed<ATTR_LAYER_START, ATTR_LAYER_END> aNewAttr( GetDoc()->GetPool() ); + + aNewAttr.Put( makeSdAttrLayerName( aLayerName ) ); + aNewAttr.Put( makeSdAttrLayerTitle( aLayerTitle ) ); + aNewAttr.Put( makeSdAttrLayerDesc( aLayerDesc ) ); + aNewAttr.Put( makeSdAttrLayerVisible( bIsVisible ) ); + aNewAttr.Put( makeSdAttrLayerLocked( bIsLocked ) ); + aNewAttr.Put( makeSdAttrLayerPrintable( bIsPrintable ) ); + aNewAttr.Put( makeSdAttrLayerThisPage() ); + + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + vcl::Window* pWin = GetActiveWindow(); + ScopedVclPtr<AbstractSdInsertLayerDlg> pDlg( pFact->CreateSdInsertLayerDlg(pWin ? pWin->GetFrameWeld() : nullptr, aNewAttr, bDelete, SdResId(STR_MODIFYLAYER)) ); + pDlg->SetHelpId( SD_MOD()->GetSlotPool()->GetSlot( SID_MODIFYLAYER )->GetCommand() ); + + // test for already existing names + bool bLoop = true; + sal_uInt16 nRet = 0; + while( bLoop ) + { + nRet = pDlg->Execute(); + if (nRet != RET_OK) + break; + pDlg->GetAttr( aNewAttr ); + aLayerName = aNewAttr.Get(ATTR_LAYER_NAME).GetValue (); + if (bDelete) + { + if( (rLayerAdmin.GetLayer( aLayerName ) && aLayerName != aOldLayerName) + || LayerTabBar::IsRealNameOfStandardLayer(aLayerName) + || LayerTabBar::IsLocalizedNameOfStandardLayer(aLayerName) + || aLayerName.isEmpty() ) + { + // name already exists + std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + SdResId(STR_WARN_NAME_DUPLICATE))); + xWarn->run(); + } + else + bLoop = false; + } + else + bLoop = false; // altering name is already disabled in the dialog itself + } + switch (nRet) + { + case RET_OK : + aLayerTitle = aNewAttr.Get(ATTR_LAYER_TITLE).GetValue (); + aLayerDesc = aNewAttr.Get(ATTR_LAYER_DESC).GetValue (); + bIsVisible = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_VISIBLE)).GetValue (); + bIsLocked = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_LOCKED)).GetValue (); + bIsPrintable = static_cast<const SfxBoolItem &>( aNewAttr.Get (ATTR_LAYER_PRINTABLE)).GetValue (); + break; + + default : + pDlg.disposeAndClear(); + rReq.Ignore (); + Cancel (); + return; + } + } + else if (pArgs->Count () == 4) + { + const SfxStringItem* pLayerName = rReq.GetArg<SfxStringItem>(ID_VAL_LAYERNAME); + const SfxBoolItem* pIsVisible = rReq.GetArg<SfxBoolItem>(ID_VAL_ISVISIBLE); + const SfxBoolItem* pIsLocked = rReq.GetArg<SfxBoolItem>(ID_VAL_ISLOCKED); + const SfxBoolItem* pIsPrintable = rReq.GetArg<SfxBoolItem>(ID_VAL_ISPRINTABLE); + + aLayerName = pLayerName->GetValue (); + bIsVisible = pIsVisible->GetValue (); + bIsLocked = pIsLocked->GetValue (); + bIsPrintable = pIsPrintable->GetValue (); + } + else + { +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + Cancel (); + rReq.Ignore (); + break; + } + + SfxUndoManager* pManager = GetDoc()->GetDocSh()->GetUndoManager(); + std::unique_ptr<SdLayerModifyUndoAction> pAction( new SdLayerModifyUndoAction( + GetDoc(), + pLayer, + // old values + aOldLayerName, + aOldLayerTitle, + aOldLayerDesc, + bOldIsVisible, + bOldIsLocked, + bOldIsPrintable, + // new values + aLayerName, + aLayerTitle, + aLayerDesc, + bIsVisible, + bIsLocked, + bIsPrintable + ) ); + pManager->AddUndoAction( std::move(pAction) ); + + ModifyLayer( pLayer, aLayerName, aLayerTitle, aLayerDesc, bIsVisible, bIsLocked, bIsPrintable ); + + Cancel(); + rReq.Done (); + } + break; + + case SID_TOGGLELAYERVISIBILITY: + { + // tdf#113439; duplicates LayerTabBar::MouseButtonDown() + sal_uInt16 aTabId = GetLayerTabControl()->GetCurPageId(); + OUString aName( GetLayerTabControl()->GetLayerName(aTabId) ); + + SdrPageView* pPV = mpDrawView->GetSdrPageView(); + bool bVisible = !pPV->IsLayerVisible(aName); + + pPV->SetLayerVisible(aName, bVisible); + + ResetActualLayer(); + GetDoc()->SetChanged(); + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_RENAMELAYER: + { + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + + if(GetLayerTabControl()) // #i87182# + { + GetLayerTabControl()->StartEditMode(GetLayerTabControl()->GetCurPageId()); + } + else + { + OSL_ENSURE(false, "No LayerTabBar (!)"); + } + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_EDIT_HYPERLINK : + { + // Ensure the field is selected first + OutlinerView* pOutView = mpDrawView->GetTextEditOutlinerView(); + if (pOutView) + pOutView->SelectFieldAtCursor(); + + GetViewFrame()->GetDispatcher()->Execute( SID_HYPERLINK_DIALOG ); + + Cancel(); + rReq.Done (); + } + break; + + case SID_OPEN_HYPERLINK: + { + OutlinerView* pOutView = mpDrawView->GetTextEditOutlinerView(); + if ( pOutView ) + { + const SvxFieldItem* pFieldItem + = pOutView->GetFieldAtSelection(/*AlsoCheckBeforeCursor=*/true); + const SvxFieldData* pField = pFieldItem ? pFieldItem->GetField() : nullptr; + if( auto pURLField = dynamic_cast< const SvxURLField *>( pField ) ) + { + SfxStringItem aUrl( SID_FILE_NAME, pURLField->GetURL() ); + SfxStringItem aTarget( SID_TARGETNAME, pURLField->GetTargetFrame() ); + + OUString aReferName; + SfxViewFrame* pFrame = GetViewFrame(); + SfxMedium* pMed = pFrame->GetObjectShell()->GetMedium(); + if (pMed) + aReferName = pMed->GetName(); + + SfxFrameItem aFrm( SID_DOCFRAME, pFrame ); + SfxStringItem aReferer( SID_REFERER, aReferName ); + + SfxBoolItem aNewView( SID_OPEN_NEW_VIEW, false ); + SfxBoolItem aBrowsing( SID_BROWSE, true ); + + if (SfxViewFrame* pViewFrm = SfxViewFrame::Current()) + { + pViewFrm->GetDispatcher()->ExecuteList(SID_OPENDOC, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, + { &aUrl, &aTarget, &aFrm, &aReferer, + &aNewView, &aBrowsing }); + } + } + } + Cancel(); + rReq.Done (); + } + break; + + case SID_COPY_HYPERLINK_LOCATION: + { + OutlinerView* pOutView = mpDrawView->GetTextEditOutlinerView(); + if ( pOutView ) + { + const SvxFieldItem* pFieldItem + = pOutView->GetFieldAtSelection(/*AlsoCheckBeforeCursor=*/true); + const SvxFieldData* pField = pFieldItem ? pFieldItem->GetField() : nullptr; + if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField)) + { + uno::Reference<datatransfer::clipboard::XClipboard> xClipboard + = pOutView->GetWindow()->GetClipboard(); + + vcl::unohelper::TextDataObject::CopyStringTo(pURLField->GetURL(), xClipboard, SfxViewShell::Current()); + } + } + + Cancel(); + rReq.Done (); + } + break; + + case SID_HYPERLINK_SETLINK: + { + const SfxItemSet* pReqArgs = rReq.GetArgs(); + + if (pReqArgs) + { + const SvxHyperlinkItem* pHLItem = + &pReqArgs->Get(SID_HYPERLINK_SETLINK); + + if (pHLItem->GetInsertMode() == HLINK_FIELD) + { + InsertURLField(pHLItem->GetURL(), pHLItem->GetName(), + pHLItem->GetTargetFrame()); + } + else if (pHLItem->GetInsertMode() == HLINK_BUTTON) + { + InsertURLButton(pHLItem->GetURL(), pHLItem->GetName(), + pHLItem->GetTargetFrame(), nullptr); + } + else if (pHLItem->GetInsertMode() == HLINK_DEFAULT) + { + OutlinerView* pOlView = mpDrawView->GetTextEditOutlinerView(); + + if (pOlView || comphelper::LibreOfficeKit::isActive()) + { + InsertURLField(pHLItem->GetURL(), pHLItem->GetName(), + pHLItem->GetTargetFrame()); + } + else + { + InsertURLButton(pHLItem->GetURL(), pHLItem->GetName(), + pHLItem->GetTargetFrame(), nullptr); + } + } + } + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_HIDE_LAST_LEVEL: + { + ESelection aSel; + // fdo#78151 editing a PresObjKind::Outline in a master page ? + ::Outliner* pOL = GetOutlinerForMasterPageOutlineTextObj(aSel); + if (pOL) + { + //we are on the last paragraph + aSel.Adjust(); + if (aSel.nEndPara == pOL->GetParagraphCount() - 1) + { + sal_uInt16 nDepth = pOL->GetDepth(aSel.nEndPara); + //there exists a previous numbering level + if (nDepth != sal_uInt16(-1) && nDepth > 0) + { + Paragraph* pPara = pOL->GetParagraph(aSel.nEndPara); + pOL->Remove(pPara, 1); + } + } + } + Cancel(); + rReq.Done (); + } + break; + + case SID_SHOW_NEXT_LEVEL: + { + const TranslateId STR_PRESOBJ_MPOUTLINE_ARY[] + { + STR_PRESOBJ_MPOUTLINE, + STR_PRESOBJ_MPOUTLLAYER2, + STR_PRESOBJ_MPOUTLLAYER3, + STR_PRESOBJ_MPOUTLLAYER4, + STR_PRESOBJ_MPOUTLLAYER5, + STR_PRESOBJ_MPOUTLLAYER6, + STR_PRESOBJ_MPOUTLLAYER7, + STR_PRESOBJ_MPNOTESTITLE, + STR_PRESOBJ_MPNOTESTEXT, + STR_PRESOBJ_NOTESTEXT + }; + + ESelection aSel; + // fdo#78151 editing a PresObjKind::Outline in a master page ? + ::Outliner* pOL = GetOutlinerForMasterPageOutlineTextObj(aSel); + if (pOL) + { + //we are on the last paragraph + aSel.Adjust(); + if (aSel.nEndPara == pOL->GetParagraphCount() - 1) + { + sal_uInt16 nDepth = pOL->GetDepth(aSel.nEndPara); + //there exists a previous numbering level + if (nDepth < 8) + { + sal_uInt16 nNewDepth = nDepth+1; + pOL->Insert(SdResId(STR_PRESOBJ_MPOUTLINE_ARY[nNewDepth]), EE_PARA_APPEND, nNewDepth); + } + } + } + Cancel(); + rReq.Done (); + } + break; + + case SID_INSERT_FLD_DATE_FIX: + case SID_INSERT_FLD_DATE_VAR: + case SID_INSERT_FLD_TIME_FIX: + case SID_INSERT_FLD_TIME_VAR: + case SID_INSERT_FLD_AUTHOR: + case SID_INSERT_FLD_PAGE: + case SID_INSERT_FLD_PAGE_TITLE: + case SID_INSERT_FLD_PAGES: + case SID_INSERT_FLD_FILE: + { + sal_uInt16 nMul = 1; + std::unique_ptr<SvxFieldItem> pFieldItem; + + switch( nSId ) + { + case SID_INSERT_FLD_DATE_FIX: + pFieldItem.reset(new SvxFieldItem( + SvxDateField( Date( Date::SYSTEM ), SvxDateType::Fix ), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_DATE_VAR: + pFieldItem.reset(new SvxFieldItem( SvxDateField(), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_TIME_FIX: + pFieldItem.reset(new SvxFieldItem( + SvxExtTimeField( ::tools::Time( ::tools::Time::SYSTEM ), SvxTimeType::Fix ), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_TIME_VAR: + pFieldItem.reset(new SvxFieldItem( SvxExtTimeField(), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_AUTHOR: + { + SvtUserOptions aUserOptions; + pFieldItem.reset(new SvxFieldItem( + SvxAuthorField( + aUserOptions.GetFirstName(), aUserOptions.GetLastName(), aUserOptions.GetID() ), EE_FEATURE_FIELD )); + } + break; + + case SID_INSERT_FLD_PAGE: + { + pFieldItem.reset(new SvxFieldItem( SvxPageField(), EE_FEATURE_FIELD )); + nMul = 3; + } + break; + + case SID_INSERT_FLD_PAGE_TITLE: + { + pFieldItem.reset(new SvxFieldItem( SvxPageTitleField(), EE_FEATURE_FIELD)); + nMul = 3; + } + break; + + case SID_INSERT_FLD_PAGES: + { + pFieldItem.reset(new SvxFieldItem( SvxPagesField(), EE_FEATURE_FIELD )); + nMul = 3; + } + break; + + case SID_INSERT_FLD_FILE: + { + OUString aName; + if( GetDocSh()->HasName() ) + aName = GetDocSh()->GetMedium()->GetName(); + pFieldItem.reset(new SvxFieldItem( SvxExtFileField( aName ), EE_FEATURE_FIELD )); + } + break; + } + + OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView(); + + if( pOLV ) + { + const SvxFieldItem* pOldFldItem = pOLV->GetFieldAtSelection(); + + if( pOldFldItem && ( nullptr != dynamic_cast< const SvxURLField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxDateField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxTimeField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtTimeField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtFileField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxAuthorField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxPageField *>( pOldFldItem->GetField() ) ) ) + { + // select field, then it will be deleted when inserting + ESelection aSel = pOLV->GetSelection(); + if( aSel.nStartPos == aSel.nEndPos ) + aSel.nEndPos++; + pOLV->SetSelection( aSel ); + } + + if( pFieldItem ) + pOLV->InsertField( *pFieldItem ); + } + else + { + Outliner* pOutl = GetDoc()->GetInternalOutliner(); + pOutl->Init( OutlinerMode::TextObject ); + OutlinerMode nOutlMode = pOutl->GetOutlinerMode(); + pOutl->SetStyleSheet( 0, nullptr ); + pOutl->QuickInsertField( *pFieldItem, ESelection() ); + std::optional<OutlinerParaObject> pOutlParaObject = pOutl->CreateParaObject(); + + rtl::Reference<SdrRectObj> pRectObj = new SdrRectObj( + *GetDoc(), + SdrObjKind::Text); + pRectObj->SetMergedItem(makeSdrTextAutoGrowWidthItem(true)); + + pOutl->UpdateFields(); + pOutl->SetUpdateLayout( true ); + Size aSize( pOutl->CalcTextSize() ); + aSize.setWidth( aSize.Width() * nMul ); + pOutl->SetUpdateLayout( false ); + + Point aPos; + ::tools::Rectangle aRect( aPos, GetActiveWindow()->GetOutputSizePixel() ); + aPos = aRect.Center(); + aPos = GetActiveWindow()->PixelToLogic(aPos); + aPos.AdjustX( -(aSize.Width() / 2) ); + aPos.AdjustY( -(aSize.Height() / 2) ); + + ::tools::Rectangle aLogicRect(aPos, aSize); + pRectObj->SetLogicRect(aLogicRect); + pRectObj->SetOutlinerParaObject( std::move(pOutlParaObject) ); + mpDrawView->InsertObjectAtView(pRectObj.get(), *mpDrawView->GetSdrPageView()); + pOutl->Init( nOutlMode ); + } + + pFieldItem.reset(); + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_MODIFY_FIELD: + { + OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView(); + + if( pOLV ) + { + const SvxFieldItem* pFldItem = pOLV->GetFieldAtSelection(); + + if( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) ) ) + { + // Dialog... + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + vcl::Window* pWin = GetActiveWindow(); + ScopedVclPtr<AbstractSdModifyFieldDlg> pDlg( pFact->CreateSdModifyFieldDlg(pWin ? pWin->GetFrameWeld() : nullptr, pFldItem->GetField(), pOLV->GetAttribs() ) ); + if( pDlg->Execute() == RET_OK ) + { + // To make a correct SetAttribs() call at the utlinerView + // it is necessary to split the actions here + std::unique_ptr<SvxFieldData> pField(pDlg->GetField()); + ESelection aSel = pOLV->GetSelection(); + bool bSelectionWasModified(false); + + if( pField ) + { + SvxFieldItem aFieldItem( *pField, EE_FEATURE_FIELD ); + + if( aSel.nStartPos == aSel.nEndPos ) + { + bSelectionWasModified = true; + aSel.nEndPos++; + pOLV->SetSelection( aSel ); + } + + pOLV->InsertField( aFieldItem ); + + // select again for eventual SetAttribs call + pOLV->SetSelection( aSel ); + } + + SfxItemSet aSet( pDlg->GetItemSet() ); + + if( aSet.Count() ) + { + pOLV->SetAttribs( aSet ); + + ::Outliner* pOutliner = pOLV->GetOutliner(); + if( pOutliner ) + pOutliner->UpdateFields(); + } + + if(pField) + { + // restore selection to original + if(bSelectionWasModified) + { + aSel.nEndPos--; + pOLV->SetSelection( aSel ); + } + } + } + } + } + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_OPEN_XML_FILTERSETTINGS: + { + try + { + css::uno::Reference < css::ui::dialogs::XExecutableDialog > xDialog = css::ui::dialogs::XSLTFilterDialog::create( ::comphelper::getProcessComponentContext() ); + xDialog->execute(); + } + catch( css::uno::RuntimeException& ) + { + DBG_UNHANDLED_EXCEPTION("sd.view"); + } + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_GROUP: // BASIC + { + if ( mpDrawView->IsPresObjSelected( true, true, true ) ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + mpDrawView->GroupMarked(); + } + Cancel(); + rReq.Done (); + } + break; + + case SID_UNGROUP: // BASIC + { + mpDrawView->UnGroupMarked(); + Cancel(); + rReq.Done (); + } + break; + + case SID_NAME_GROUP: + { + // only allow for single object selection since the name of an object needs + // to be unique + if(1 == mpDrawView->GetMarkedObjectCount()) + { + // #i68101# + SdrObject* pSelected = mpDrawView->GetMarkedObjectByIndex(0); + OSL_ENSURE(pSelected, "DrawViewShell::FuTemp03: nMarkCount, but no object (!)"); + OUString aName(pSelected->GetName()); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractSvxObjectNameDialog> pDlg(pFact->CreateSvxObjectNameDialog(GetFrameWeld(), aName)); + + pDlg->SetCheckNameHdl(LINK(this, DrawViewShell, NameObjectHdl)); + + if(RET_OK == pDlg->Execute()) + { + pDlg->GetName(aName); + pSelected->SetName(aName); + + SdPage* pPage = GetActualPage(); + if (pPage) + pPage->notifyObjectRenamed(pSelected); + } + } + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_NAVIGATOR_STATE, true ); + rBindings.Invalidate( SID_CONTEXT ); + + Cancel(); + rReq.Ignore(); + break; + } + + // #i68101# + case SID_OBJECT_TITLE_DESCRIPTION: + { + if(1 == mpDrawView->GetMarkedObjectCount()) + { + SdrObject* pSelected = mpDrawView->GetMarkedObjectByIndex(0); + OSL_ENSURE(pSelected, "DrawViewShell::FuTemp03: nMarkCount, but no object (!)"); + OUString aTitle(pSelected->GetTitle()); + OUString aDescription(pSelected->GetDescription()); + bool isDecorative(pSelected->IsDecorative()); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractSvxObjectTitleDescDialog> pDlg(pFact->CreateSvxObjectTitleDescDialog( + GetFrameWeld(), aTitle, aDescription, isDecorative)); + + if(RET_OK == pDlg->Execute()) + { + pDlg->GetTitle(aTitle); + pDlg->GetDescription(aDescription); + pDlg->IsDecorative(isDecorative); + pSelected->SetTitle(aTitle); + pSelected->SetDescription(aDescription); + pSelected->SetDecorative(isDecorative); + } + } + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_NAVIGATOR_STATE, true ); + rBindings.Invalidate( SID_CONTEXT ); + + Cancel(); + rReq.Ignore(); + break; + } + + case SID_ENTER_GROUP: // BASIC + { + mpDrawView->EnterMarkedGroup(); + Cancel(); + rReq.Done (); + } + break; + + case SID_LEAVE_GROUP: // BASIC + { + mpDrawView->LeaveOneGroup(); + Cancel(); + rReq.Done (); + } + break; + + case SID_LEAVE_ALL_GROUPS: // BASIC + { + mpDrawView->LeaveAllGroup(); + Cancel(); + rReq.Done (); + } + break; + + case SID_TEXT_COMBINE: // BASIC + { + // End text edit to avoid conflicts + if(mpDrawView->IsTextEdit()) + mpDrawView->SdrEndTextEdit(); + + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->CombineMarkedTextObjects(); + } + Cancel(); + rReq.Done (); + } + break; + + case SID_COMBINE: // BASIC + { + // End text edit to avoid conflicts + if(mpDrawView->IsTextEdit()) + mpDrawView->SdrEndTextEdit(); + + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->CombineMarkedObjects(false); + } + Cancel(); + rReq.Done (); + } + break; + + case SID_DISTRIBUTE_HLEFT: + case SID_DISTRIBUTE_HCENTER: + case SID_DISTRIBUTE_HDISTANCE: + case SID_DISTRIBUTE_HRIGHT: + case SID_DISTRIBUTE_VTOP: + case SID_DISTRIBUTE_VCENTER: + case SID_DISTRIBUTE_VDISTANCE: + case SID_DISTRIBUTE_VBOTTOM: + { + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + mpDrawView->DistributeMarkedObjects(nSId); + } + Cancel(); + rReq.Done (); + } + break; + case SID_POLY_MERGE: + { + // End text edit to avoid conflicts + if(mpDrawView->IsTextEdit()) + mpDrawView->SdrEndTextEdit(); + + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->MergeMarkedObjects(SdrMergeMode::Merge); + } + Cancel(); + rReq.Done (); + } + break; + + case SID_POLY_SUBSTRACT: + { + // End text edit to avoid conflicts + if(mpDrawView->IsTextEdit()) + mpDrawView->SdrEndTextEdit(); + + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->MergeMarkedObjects(SdrMergeMode::Subtract); + } + Cancel(); + rReq.Done (); + } + break; + + case SID_POLY_INTERSECT: + { + // End text edit to avoid conflicts + if(mpDrawView->IsTextEdit()) + mpDrawView->SdrEndTextEdit(); + + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->MergeMarkedObjects(SdrMergeMode::Intersect); + } + Cancel(); + rReq.Done (); + } + break; + + case SID_EQUALIZEWIDTH: + case SID_EQUALIZEHEIGHT: + { + // End text edit to avoid conflicts + if(mpDrawView->IsTextEdit()) + mpDrawView->SdrEndTextEdit(); + + mpDrawView->EqualizeMarkedObjects(nSId == SID_EQUALIZEWIDTH); + Cancel(); + rReq.Done (); + } + break; + + case SID_DISMANTLE: // BASIC + { + if ( mpDrawView->IsDismantlePossible() ) + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->DismantleMarkedObjects(); + } + Cancel(); + rReq.Done (); + } + break; + + case SID_CONNECT: // BASIC + { + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->CombineMarkedObjects(); + } + Cancel(); + rReq.Done (); + } + break; + + case SID_BREAK: // BASIC + { + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + + if ( mpDrawView->IsBreak3DObjPossible() ) + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->Break3DObj(); + } + else if ( mpDrawView->IsDismantlePossible(true) ) + { + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->DismantleMarkedObjects(true); + } + else if ( mpDrawView->IsImportMtfPossible() ) + { + weld::WaitObject aWait(GetFrameWeld()); + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const size_t nCnt=rMarkList.GetMarkCount(); + + // determine the sum of meta objects of all selected meta files + sal_uLong nCount = 0; + for(size_t nm=0; nm<nCnt; ++nm) + { + SdrMark* pM=rMarkList.GetMark(nm); + SdrObject* pObj=pM->GetMarkedSdrObj(); + SdrGrafObj* pGraf= dynamic_cast< SdrGrafObj *>( pObj ); + SdrOle2Obj* pOle2= dynamic_cast< SdrOle2Obj *>( pObj ); + + if (pGraf != nullptr) + { + if (pGraf->HasGDIMetaFile()) + { + nCount += pGraf->GetGraphic().GetGDIMetaFile().GetActionSize(); + } + else if (pGraf->isEmbeddedVectorGraphicData()) + { + nCount += pGraf->getMetafileFromEmbeddedVectorGraphicData().GetActionSize(); + } + } + + if(pOle2 && pOle2->GetGraphic()) + { + nCount += pOle2->GetGraphic()->GetGDIMetaFile().GetActionSize(); + } + } + + // decide with the sum of all meta objects if we should show a dialog + if(nCount < MIN_ACTIONS_FOR_DIALOG) + { + // nope, no dialog + mpDrawView->DoImportMarkedMtf(); + } + else + { + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateBreakDlg(GetFrameWeld(), mpDrawView.get(), GetDocSh(), nCount, static_cast<sal_uLong>(nCnt) )); + pDlg->Execute(); + } + } + + Cancel(); + rReq.Done (); + } + break; + + case SID_CONVERT_TO_3D: + { + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + if (mpDrawView->IsConvertTo3DObjPossible()) + { + if (mpDrawView->IsTextEdit()) + { + mpDrawView->SdrEndTextEdit(); + } + + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->ConvertMarkedObjTo3D(); + } + } + + Cancel(); + rReq.Done(); + } + break; + + case SID_FRAME_TO_TOP: // BASIC + { + mpDrawView->PutMarkedToTop(); + Cancel(); + rReq.Done (); + } + break; + + case SID_MOREFRONT: // BASIC + case SID_FRAME_UP: // BASIC + { + mpDrawView->MovMarkedToTop(); + Cancel(); + rReq.Done (); + } + break; + + case SID_MOREBACK: // BASIC + case SID_FRAME_DOWN: // BASIC + { + mpDrawView->MovMarkedToBtm(); + Cancel(); + rReq.Done (); + } + break; + + case SID_FRAME_TO_BOTTOM: // BASIC + { + mpDrawView->PutMarkedToBtm(); + Cancel(); + rReq.Done (); + } + break; + + case SID_HORIZONTAL: // BASIC + case SID_FLIP_HORIZONTAL: + { + mpDrawView->MirrorAllMarkedHorizontal(); + Cancel(); + rReq.Done (); + } + break; + + case SID_VERTICAL: // BASIC + case SID_FLIP_VERTICAL: + { + mpDrawView->MirrorAllMarkedVertical(); + Cancel(); + rReq.Done (); + } + break; + + case SID_OBJECT_ALIGN_LEFT: // BASIC + { + mpDrawView->AlignMarkedObjects(SdrHorAlign::Left, SdrVertAlign::NONE); + Cancel(); + rReq.Done (); + } + break; + + case SID_OBJECT_ALIGN_CENTER: // BASIC + { + mpDrawView->AlignMarkedObjects(SdrHorAlign::Center, SdrVertAlign::NONE); + Cancel(); + rReq.Done (); + } + break; + + case SID_OBJECT_ALIGN_RIGHT: // BASIC + { + mpDrawView->AlignMarkedObjects(SdrHorAlign::Right, SdrVertAlign::NONE); + Cancel(); + rReq.Done (); + } + break; + + case SID_OBJECT_ALIGN_UP: // BASIC + { + mpDrawView->AlignMarkedObjects(SdrHorAlign::NONE, SdrVertAlign::Top); + Cancel(); + rReq.Done (); + } + break; + + case SID_OBJECT_ALIGN_MIDDLE: // BASIC + { + mpDrawView->AlignMarkedObjects(SdrHorAlign::NONE, SdrVertAlign::Center); + Cancel(); + rReq.Done (); + } + break; + + case SID_OBJECT_ALIGN_DOWN: // BASIC + { + mpDrawView->AlignMarkedObjects(SdrHorAlign::NONE, SdrVertAlign::Bottom); + Cancel(); + rReq.Done (); + } + break; + + case SID_SELECTALL: // BASIC + { + if( (dynamic_cast<FuSelection*>( GetOldFunction().get() ) != nullptr) && + !GetView()->IsFrameDragSingles() && GetView()->HasMarkablePoints()) + { + if ( !mpDrawView->IsAction() ) + mpDrawView->MarkAllPoints(); + } + else + mpDrawView->SelectAll(); + + FreshNavigatrTree(); + + Cancel(); + rReq.Done (); + } + break; + + case SID_STYLE_NEW: // BASIC ??? + case SID_STYLE_APPLY: + case SID_STYLE_EDIT: + case SID_STYLE_DELETE: + case SID_STYLE_HIDE: + case SID_STYLE_SHOW: + case SID_STYLE_FAMILY: + case SID_STYLE_WATERCAN: + case SID_STYLE_UPDATE_BY_EXAMPLE: + case SID_STYLE_NEW_BY_EXAMPLE: + { + if( rReq.GetSlot() == SID_STYLE_EDIT && !rReq.GetArgs() ) + { + SfxStyleSheet* pStyleSheet = mpDrawView->GetStyleSheet(); + if( pStyleSheet && pStyleSheet->GetFamily() == SfxStyleFamily::Page) + pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet(); + + if( (pStyleSheet == nullptr) && GetView()->IsTextEdit() ) + { + GetView()->SdrEndTextEdit(); + + pStyleSheet = mpDrawView->GetStyleSheet(); + if(pStyleSheet && pStyleSheet->GetFamily() == SfxStyleFamily::Page) + pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet(); + } + + if( pStyleSheet == nullptr ) + { + rReq.Ignore(); + break; + } + + SfxAllItemSet aSet(GetDoc()->GetPool()); + + SfxStringItem aStyleNameItem( SID_STYLE_EDIT, pStyleSheet->GetName() ); + aSet.Put(aStyleNameItem); + + SfxUInt16Item aStyleFamilyItem( SID_STYLE_FAMILY, static_cast<sal_uInt16>(pStyleSheet->GetFamily()) ); + aSet.Put(aStyleFamilyItem); + + rReq.SetArgs(aSet); + } + + if( rReq.GetArgs() ) + { + SetCurrentFunction( FuTemplate::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + if( rReq.GetSlot() == SID_STYLE_APPLY ) + GetViewFrame()->GetBindings().Invalidate( SID_STYLE_APPLY ); + Cancel(); + } + else if( rReq.GetSlot() == SID_STYLE_APPLY ) + GetViewFrame()->GetDispatcher()->Execute( SID_STYLE_DESIGNER, SfxCallMode::ASYNCHRON ); + rReq.Ignore (); + } + break; + + case SID_IMAP: + { + sal_uInt16 nId = SvxIMapDlgChildWindow::GetChildWindowId(); + + GetViewFrame()->ToggleChildWindow( nId ); + GetViewFrame()->GetBindings().Invalidate( SID_IMAP ); + + if ( GetViewFrame()->HasChildWindow( nId ) + && ( ( ViewShell::Implementation::GetImageMapDialog() ) != nullptr ) ) + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + + if ( rMarkList.GetMarkCount() == 1 ) + UpdateIMapDlg( rMarkList.GetMark( 0 )->GetMarkedSdrObj() ); + } + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_GRID_FRONT: + { + mpDrawView->SetGridFront( !mpDrawView->IsGridFront() ); + Cancel(); + rReq.Done (); + } + break; + + case SID_HELPLINES_FRONT: + { + mpDrawView->SetHlplFront( !mpDrawView->IsHlplFront() ); + Cancel(); + rReq.Done (); + } + break; + + case SID_FONTWORK: + { + if ( rReq.GetArgs() ) + { + GetViewFrame()->SetChildWindow(SvxFontWorkChildWindow::GetChildWindowId(), + static_cast<const SfxBoolItem&>(rReq.GetArgs()-> + Get(SID_FONTWORK)).GetValue()); + } + else + { + GetViewFrame()->ToggleChildWindow( SvxFontWorkChildWindow::GetChildWindowId() ); + } + + GetViewFrame()->GetBindings().Invalidate(SID_FONTWORK); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_COLOR_CONTROL: + { + if ( rReq.GetArgs() ) + GetViewFrame()->SetChildWindow(SvxColorChildWindow::GetChildWindowId(), + rReq.GetArgs()->Get(SID_COLOR_CONTROL).GetValue()); + else + GetViewFrame()->ToggleChildWindow(SvxColorChildWindow::GetChildWindowId() ); + + GetViewFrame()->GetBindings().Invalidate(SID_COLOR_CONTROL); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_EXTRUSION_TOGGLE: + case SID_EXTRUSION_TILT_DOWN: + case SID_EXTRUSION_TILT_UP: + case SID_EXTRUSION_TILT_LEFT: + case SID_EXTRUSION_TILT_RIGHT: + case SID_EXTRUSION_3D_COLOR: + case SID_EXTRUSION_DEPTH: + case SID_EXTRUSION_DIRECTION: + case SID_EXTRUSION_PROJECTION: + case SID_EXTRUSION_LIGHTING_DIRECTION: + case SID_EXTRUSION_LIGHTING_INTENSITY: + case SID_EXTRUSION_SURFACE: + case SID_EXTRUSION_DEPTH_FLOATER: + case SID_EXTRUSION_DIRECTION_FLOATER: + case SID_EXTRUSION_LIGHTING_FLOATER: + case SID_EXTRUSION_SURFACE_FLOATER: + case SID_EXTRUSION_DEPTH_DIALOG: + svx::ExtrusionBar::execute( mpDrawView.get(), rReq, GetViewFrame()->GetBindings() ); + Cancel(); + rReq.Ignore (); + break; + + case SID_FONTWORK_SHAPE: + case SID_FONTWORK_SHAPE_TYPE: + case SID_FONTWORK_ALIGNMENT: + case SID_FONTWORK_SAME_LETTER_HEIGHTS: + case SID_FONTWORK_CHARACTER_SPACING: + case SID_FONTWORK_KERN_CHARACTER_PAIRS: + case SID_FONTWORK_GALLERY_FLOATER: + case SID_FONTWORK_CHARACTER_SPACING_FLOATER: + case SID_FONTWORK_ALIGNMENT_FLOATER: + case SID_FONTWORK_CHARACTER_SPACING_DIALOG: + svx::FontworkBar::execute(*mpDrawView, rReq, GetViewFrame()->GetBindings()); + Cancel(); + rReq.Ignore (); + break; + + case SID_BMPMASK: + { + GetViewFrame()->ToggleChildWindow( SvxBmpMaskChildWindow::GetChildWindowId() ); + GetViewFrame()->GetBindings().Invalidate( SID_BMPMASK ); + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_NAVIGATOR: + { + if (comphelper::LibreOfficeKit::isActive()) + { + GetViewFrame()->ShowChildWindow(SID_SIDEBAR); + OUString panelId = "SdNavigatorPanel"; + ::sfx2::sidebar::Sidebar::TogglePanel( + panelId, GetViewFrame()->GetFrame().GetFrameInterface()); + + Cancel(); + rReq.Done(); + } else { + if ( rReq.GetArgs() ) + GetViewFrame()->SetChildWindow(SID_NAVIGATOR, + static_cast<const SfxBoolItem&>(rReq.GetArgs()-> + Get(SID_NAVIGATOR)).GetValue()); + else + GetViewFrame()->ToggleChildWindow( SID_NAVIGATOR ); + + GetViewFrame()->GetBindings().Invalidate(SID_NAVIGATOR); + Cancel(); + rReq.Ignore (); + } + } + break; + + case SID_SLIDE_TRANSITIONS_PANEL: + case SID_MASTER_SLIDES_PANEL: + case SID_CUSTOM_ANIMATION_PANEL: + case SID_GALLERY: + { + // First make sure that the sidebar is visible + GetViewFrame()->ShowChildWindow(SID_SIDEBAR); + + OUString panelId; + if (nSId == SID_CUSTOM_ANIMATION_PANEL) + panelId = "SdCustomAnimationPanel"; + else if (nSId == SID_GALLERY) + panelId = "GalleryPanel"; + else if (nSId == SID_SLIDE_TRANSITIONS_PANEL) + panelId = "SdSlideTransitionPanel"; + else if (nSId == SID_MASTER_SLIDES_PANEL) + panelId = "SdAllMasterPagesPanel"; + + ::sfx2::sidebar::Sidebar::TogglePanel( + panelId, + GetViewFrame()->GetFrame().GetFrameInterface()); + + Cancel(); + rReq.Done(); + } + break; + + case SID_ANIMATION_OBJECTS: + { + if ( rReq.GetArgs() ) + GetViewFrame()->SetChildWindow( + AnimationChildWindow::GetChildWindowId(), + static_cast<const SfxBoolItem&>(rReq.GetArgs()-> + Get(SID_ANIMATION_OBJECTS)).GetValue()); + else + GetViewFrame()->ToggleChildWindow( + AnimationChildWindow::GetChildWindowId() ); + + GetViewFrame()->GetBindings().Invalidate(SID_ANIMATION_OBJECTS); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_3D_WIN: + { + if ( rReq.GetArgs() ) + GetViewFrame()->SetChildWindow( Svx3DChildWindow::GetChildWindowId(), + static_cast<const SfxBoolItem&>(rReq.GetArgs()-> + Get( SID_3D_WIN )).GetValue()); + else + GetViewFrame()->ToggleChildWindow( Svx3DChildWindow::GetChildWindowId() ); + + GetViewFrame()->GetBindings().Invalidate( SID_3D_WIN ); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_CONVERT_TO_3D_LATHE_FAST: + { + /* The call is enough. The initialization via Start3DCreation and + CreateMirrorPolygons is no longer needed if the parameter + sal_True is provided. Then a tilted rotary body with an axis left + besides the bounding rectangle of the selected objects is drawn + immediately and without user interaction. */ + mpDrawView->SdrEndTextEdit(); + if(GetActiveWindow()) + GetActiveWindow()->EnterWait(); + mpDrawView->End3DCreation(true); + Cancel(); + rReq.Ignore(); + if(GetActiveWindow()) + GetActiveWindow()->LeaveWait(); + } + break; + + case SID_PRESENTATION_DLG: + { + SetCurrentFunction( FuSlideShowDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_REMOTE_DLG: + { +#ifdef ENABLE_SDREMOTE + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateRemoteDialog(GetFrameWeld())); + pDlg->Execute(); +#endif + } + break; + + case SID_CUSTOMSHOW_DLG: + { + SetCurrentFunction( FuCustomShowDlg::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_EXPAND_PAGE: + { + SetCurrentFunction( FuExpandPage::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_SUMMARY_PAGE: + { + mpDrawView->SdrEndTextEdit(); + SetCurrentFunction( FuSummaryPage::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + +#if HAVE_FEATURE_AVMEDIA + case SID_AVMEDIA_PLAYER: + { + GetViewFrame()->ToggleChildWindow( ::avmedia::MediaPlayer::GetChildWindowId() ); + GetViewFrame()->GetBindings().Invalidate( SID_AVMEDIA_PLAYER ); + Cancel(); + rReq.Ignore (); + } + break; +#endif + + case SID_PRESENTATION_MINIMIZER: + { + Reference<XComponentContext> xContext(::comphelper::getProcessComponentContext()); + Reference<util::XURLTransformer> xParser(util::URLTransformer::create(xContext)); + Reference<frame::XDispatchProvider> xProvider(GetViewShellBase().GetController()->getFrame(), UNO_QUERY); + if (xProvider.is()) + { + util::URL aURL; + aURL.Complete = "vnd.com.sun.star.comp.PresentationMinimizer:execute"; + xParser->parseStrict(aURL); + uno::Reference<frame::XDispatch> xDispatch(xProvider->queryDispatch(aURL, OUString(), 0)); + if (xDispatch.is()) + { + xDispatch->dispatch(aURL, uno::Sequence< beans::PropertyValue >()); + } + } + Cancel(); + rReq.Ignore(); + } + break; + + case SID_DISPLAY_MASTER_BACKGROUND: + case SID_DISPLAY_MASTER_OBJECTS: + { + // Determine current page and toggle visibility of layers + // associated with master page background or master page shapes. + // FIXME: This solution is wrong, because shapes of master pages need + // not be on layer "background" or "backgroundobjects". + // See tdf#118613 + SdPage* pPage = GetActualPage(); + if (pPage != nullptr + && GetDoc() != nullptr) + { + SdrLayerIDSet aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers(); + SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin(); + SdrLayerID aLayerId; + if (nSId == SID_DISPLAY_MASTER_BACKGROUND) + aLayerId = rLayerAdmin.GetLayerID(sUNO_LayerName_background); + else + aLayerId = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects); + aVisibleLayers.Set(aLayerId, !aVisibleLayers.IsSet(aLayerId)); + pPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers); + } + Cancel(); + rReq.Done(); // Mark task as done to auto-update the state of each buttons tdf#132816 + } + break; + + case SID_PHOTOALBUM: + { + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + vcl::Window* pWin = GetActiveWindow(); + ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSdPhotoAlbumDialog( + pWin ? pWin->GetFrameWeld() : nullptr, + GetDoc())); + + pDlg->Execute(); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_INSERT_QRCODE: + case SID_EDIT_QRCODE: + { + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + const uno::Reference<frame::XModel> xModel = GetViewShellBase().GetController()->getModel(); + ScopedVclPtr<AbstractQrCodeGenDialog> pDlg(pFact->CreateQrCodeGenDialog( + GetFrameWeld(), xModel, rReq.GetSlot() == SID_EDIT_QRCODE)); + pDlg->Execute(); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_THEME_DIALOG: + { + SdrPage* pMasterPage = &GetActualPage()->TRG_GetMasterPage(); + auto pTheme = pMasterPage->getSdrPageProperties().getTheme(); + auto pDialog = std::make_shared<svx::ThemeDialog>(GetFrameWeld(), pTheme.get()); + auto* pDocShell = GetDocSh(); + weld::DialogController::runAsync(pDialog, [pDialog, pMasterPage, pDocShell](sal_uInt32 nResult) + { + if (RET_OK != nResult) + return; + + auto pColorSet = pDialog->getCurrentColorSet(); + if (pColorSet) + { + sd::ThemeColorChanger aChanger(pMasterPage, pDocShell); + aChanger.apply(pColorSet); + + if (comphelper::LibreOfficeKit::isActive()) + { + svx::ThemeColorPaletteManager aManager(pColorSet); + SfxLokHelper::notifyAllViews(LOK_CALLBACK_COLOR_PALETTES, aManager.generateJSON()); + } + } + }); + + Cancel(); + rReq.Ignore(); + } + break; + + case SID_ADDITIONS_DIALOG: + { + OUString sAdditionsTag = ""; + + const SfxStringItem* pStringArg = rReq.GetArg<SfxStringItem>(FN_PARAM_ADDITIONS_TAG); + if (pStringArg) + sAdditionsTag = pStringArg->GetValue(); + + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractAdditionsDialog> pDlg( + pFact->CreateAdditionsDialog(GetFrameWeld(), sAdditionsTag)); + pDlg->Execute(); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_ATTR_GLOW_COLOR: + case SID_ATTR_GLOW_RADIUS: + case SID_ATTR_GLOW_TRANSPARENCY: + case SID_ATTR_SOFTEDGE_RADIUS: + case SID_ATTR_TEXTCOLUMNS_NUMBER: + case SID_ATTR_TEXTCOLUMNS_SPACING: + if (const SfxItemSet* pNewArgs = rReq.GetArgs()) + mpDrawView->SetAttributes(*pNewArgs); + rReq.Done(); + Cancel(); + break; + + default: + { + SAL_WARN( "sd.ui", "Slot without function" ); + Cancel(); + rReq.Ignore (); + } + break; + } + + if(HasCurrentFunction()) + { + GetCurrentFunction()->Activate(); + } +} + +void DrawViewShell::ExecChar( SfxRequest &rReq ) +{ + SdDrawDocument* pDoc = GetDoc(); + if (!pDoc || !mpDrawView) + return; + + SfxItemSet aEditAttr( pDoc->GetPool() ); + mpDrawView->GetAttributes( aEditAttr ); + + //modified by wj for sym2_1580, if put old itemset into new set, + //when mpDrawView->SetAttributes(aNewAttr) it will invalidate all the item + // and use old attr to update all the attributes +// SfxItemSet aNewAttr( GetPool(), +// EE_ITEMS_START, EE_ITEMS_END ); +// aNewAttr.Put( aEditAttr, sal_False ); + SfxItemSet aNewAttr( pDoc->GetPool() ); + //modified end + + sal_uInt16 nSId = rReq.GetSlot(); + + switch ( nSId ) + { + case SID_ATTR_CHAR_FONT: + if( rReq.GetArgs() ) + { + const SvxFontItem* pItem = rReq.GetArg<SvxFontItem>(SID_ATTR_CHAR_FONT); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + case SID_ATTR_CHAR_FONTHEIGHT: + if( rReq.GetArgs() ) + { + const SvxFontHeightItem* pItem = rReq.GetArg<SvxFontHeightItem>(SID_ATTR_CHAR_FONTHEIGHT); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + case SID_ATTR_CHAR_WEIGHT: + if( rReq.GetArgs() ) + { + const SvxWeightItem* pItem = rReq.GetArg<SvxWeightItem>(SID_ATTR_CHAR_WEIGHT); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + case SID_ATTR_CHAR_POSTURE: + if( rReq.GetArgs() ) + { + const SvxPostureItem* pItem = rReq.GetArg<SvxPostureItem>(SID_ATTR_CHAR_POSTURE); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + case SID_ATTR_CHAR_UNDERLINE: + if( rReq.GetArgs() ) + { + const SvxUnderlineItem* pItem = rReq.GetArg<SvxUnderlineItem>(SID_ATTR_CHAR_UNDERLINE); + if (pItem) + { + aNewAttr.Put(*pItem); + } + else + { + FontLineStyle eFU = aEditAttr.Get( EE_CHAR_UNDERLINE ).GetLineStyle(); + aNewAttr.Put( SvxUnderlineItem( eFU != LINESTYLE_NONE ?LINESTYLE_NONE : LINESTYLE_SINGLE, EE_CHAR_UNDERLINE ) ); + } + } + break; + case SID_ATTR_CHAR_OVERLINE: + if( rReq.GetArgs() ) + { + const SvxOverlineItem* pItem = rReq.GetArg<SvxOverlineItem>(SID_ATTR_CHAR_OVERLINE); + if (pItem) + { + aNewAttr.Put(*pItem); + } + else + { + FontLineStyle eFU = aEditAttr.Get( EE_CHAR_OVERLINE ).GetLineStyle(); + aNewAttr.Put( SvxOverlineItem( eFU != LINESTYLE_NONE ?LINESTYLE_NONE : LINESTYLE_SINGLE, EE_CHAR_OVERLINE ) ); + } + } + break; + + case SID_ULINE_VAL_NONE: + { + aNewAttr.Put(SvxUnderlineItem(LINESTYLE_NONE, EE_CHAR_UNDERLINE)); + break; + } + + case SID_ULINE_VAL_SINGLE: + case SID_ULINE_VAL_DOUBLE: + case SID_ULINE_VAL_DOTTED: + { + FontLineStyle eOld = aEditAttr.Get(EE_CHAR_UNDERLINE).GetLineStyle(); + FontLineStyle eNew = eOld; + + switch (nSId) + { + case SID_ULINE_VAL_SINGLE: + eNew = ( eOld == LINESTYLE_SINGLE ) ? LINESTYLE_NONE : LINESTYLE_SINGLE; + break; + case SID_ULINE_VAL_DOUBLE: + eNew = ( eOld == LINESTYLE_DOUBLE ) ? LINESTYLE_NONE : LINESTYLE_DOUBLE; + break; + case SID_ULINE_VAL_DOTTED: + eNew = ( eOld == LINESTYLE_DOTTED ) ? LINESTYLE_NONE : LINESTYLE_DOTTED; + break; + } + + SvxUnderlineItem aUnderline(eNew, EE_CHAR_UNDERLINE); + aNewAttr.Put(aUnderline); + } + break; + + case SID_ATTR_CHAR_SHADOWED: + if( rReq.GetArgs() ) + { + const SvxShadowedItem* pItem = rReq.GetArg<SvxShadowedItem>(SID_ATTR_CHAR_SHADOWED); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + case SID_ATTR_CHAR_CONTOUR: + if( rReq.GetArgs() ) + { + const SvxContourItem* pItem = rReq.GetArg<SvxContourItem>(SID_ATTR_CHAR_CONTOUR); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + + case SID_ATTR_CHAR_STRIKEOUT: + if( rReq.GetArgs() ) + { + const SvxCrossedOutItem* pItem = rReq.GetArg<SvxCrossedOutItem>(SID_ATTR_CHAR_STRIKEOUT); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + case SID_ATTR_CHAR_COLOR: + if( rReq.GetArgs() ) + { + const SvxColorItem* pItem = rReq.GetArg<SvxColorItem>(SID_ATTR_CHAR_COLOR); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + case SID_ATTR_CHAR_KERNING: + if( rReq.GetArgs() ) + { + const SvxKerningItem* pItem = rReq.GetArg<SvxKerningItem>(SID_ATTR_CHAR_KERNING); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + case SID_ATTR_CHAR_CASEMAP: + if( rReq.GetArgs() ) + { + const SvxCaseMapItem* pItem = rReq.GetArg<SvxCaseMapItem>(SID_ATTR_CHAR_CASEMAP); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + case SID_SET_SUB_SCRIPT: + { + SvxEscapementItem aItem( EE_CHAR_ESCAPEMENT ); + SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue()); + if( eEsc == SvxEscapement::Subscript ) + aItem.SetEscapement( SvxEscapement::Off ); + else + aItem.SetEscapement( SvxEscapement::Subscript ); + aNewAttr.Put( aItem ); + } + break; + case SID_SET_SUPER_SCRIPT: + { + SvxEscapementItem aItem( EE_CHAR_ESCAPEMENT ); + SvxEscapement eEsc = static_cast<SvxEscapement>(aEditAttr.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue()); + if( eEsc == SvxEscapement::Superscript ) + aItem.SetEscapement( SvxEscapement::Off ); + else + aItem.SetEscapement( SvxEscapement::Superscript ); + aNewAttr.Put( aItem ); + } + break; + case SID_SHRINK_FONT_SIZE: + case SID_GROW_FONT_SIZE: + { + const SvxFontListItem* pFonts = dynamic_cast<const SvxFontListItem*>(GetDocSh()->GetItem( SID_ATTR_CHAR_FONTLIST ) ); + const FontList* pFontList = pFonts ? pFonts->GetFontList() : nullptr; + if( pFontList ) + { + FuText::ChangeFontSize( nSId == SID_GROW_FONT_SIZE, nullptr, pFontList, mpView ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_CHAR_FONTHEIGHT ); + } + break; + } + case SID_ATTR_CHAR_BACK_COLOR: + if( rReq.GetArgs() ) + { + const SvxColorItem* pItem = rReq.GetArg<SvxColorItem>(SID_ATTR_CHAR_BACK_COLOR); + if (pItem) + { + aNewAttr.Put(*pItem); + } + } + break; + default: + break; + } + + mpDrawView->SetAttributes(aNewAttr); + rReq.Done(); + Cancel(); +} + +/** This method consists basically of three parts: + 1. Process the arguments of the SFX request. + 2. Use the model to create a new page or duplicate an existing one. + 3. Update the tab control and switch to the new page. +*/ +SdPage* DrawViewShell::CreateOrDuplicatePage ( + SfxRequest& rRequest, + PageKind ePageKind, + SdPage* pPage, + const sal_Int32 nInsertPosition) +{ + SdPage* pNewPage = nullptr; + if (ePageKind == PageKind::Standard && meEditMode != EditMode::MasterPage) + { + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + pNewPage = ViewShell::CreateOrDuplicatePage (rRequest, ePageKind, pPage, nInsertPosition); + } + return pNewPage; +} + +void DrawViewShell::DuplicateSelectedSlides (SfxRequest& rRequest) +{ + // Create a list of the pages that are to be duplicated. The process of + // duplication alters the selection. + sal_Int32 nInsertPosition (0); + ::std::vector<SdPage*> aPagesToDuplicate; + sd::slidesorter::SlideSorter &mrSlideSorter = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase())->GetSlideSorter(); + sd::slidesorter::model::PageEnumeration aSelectedPages ( + sd::slidesorter::model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + sd::slidesorter::model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if (pDescriptor && pDescriptor->GetPage()) + { + aPagesToDuplicate.push_back(pDescriptor->GetPage()); + nInsertPosition = pDescriptor->GetPage()->GetPageNum()+2; + } + } + + // Duplicate the pages in aPagesToDuplicate and collect the newly + // created pages in aPagesToSelect. + const bool bUndo (aPagesToDuplicate.size()>1 && mrSlideSorter.GetView().IsUndoEnabled()); + if (bUndo) + mrSlideSorter.GetView().BegUndo(SdResId(STR_INSERTPAGE)); + + ::std::vector<SdPage*> aPagesToSelect; + for(::std::vector<SdPage*>::const_iterator + iPage(aPagesToDuplicate.begin()), + iEnd(aPagesToDuplicate.end()); + iPage!=iEnd; + ++iPage, nInsertPosition+=2) + { + aPagesToSelect.push_back( + mrSlideSorter.GetViewShell()->CreateOrDuplicatePage( + rRequest, PageKind::Standard, *iPage, nInsertPosition)); + } + aPagesToDuplicate.clear(); + + if (bUndo) + mrSlideSorter.GetView().EndUndo(); + + // Set the selection to the pages in aPagesToSelect. + sd::slidesorter::controller::PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + rSelector.DeselectAllPages(); + for (auto const& it: aPagesToSelect) + { + rSelector.SelectPage(it); + } +} + +void DrawViewShell::ExecutePropPanelAttr (SfxRequest const & rReq) +{ + if(SlideShow::IsRunning( GetViewShellBase() )) + return; + + SdDrawDocument* pDoc = GetDoc(); + if (!pDoc || !mpDrawView) + return; + + sal_uInt16 nSId = rReq.GetSlot(); + SfxItemSet aAttrs( pDoc->GetPool() ); + + switch ( nSId ) + { + case SID_TABLE_VERT_NONE: + case SID_TABLE_VERT_CENTER: + case SID_TABLE_VERT_BOTTOM: + SdrTextVertAdjust eTVA = SDRTEXTVERTADJUST_TOP; + if (nSId == SID_TABLE_VERT_CENTER) + eTVA = SDRTEXTVERTADJUST_CENTER; + else if (nSId == SID_TABLE_VERT_BOTTOM) + eTVA = SDRTEXTVERTADJUST_BOTTOM; + + aAttrs.Put( SdrTextVertAdjustItem(eTVA) ); + mpDrawView->SetAttributes(aAttrs); + + break; + } +} + +void DrawViewShell::GetStatePropPanelAttr(SfxItemSet& rSet) +{ + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + + SdDrawDocument* pDoc = GetDoc(); + if (!pDoc || !mpDrawView) + return; + + SfxItemSet aAttrs( pDoc->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + + while ( nWhich ) + { + sal_uInt16 nSlotId = SfxItemPool::IsWhich(nWhich) + ? GetPool().GetSlotId(nWhich) + : nWhich; + switch ( nSlotId ) + { + case SID_TABLE_VERT_NONE: + case SID_TABLE_VERT_CENTER: + case SID_TABLE_VERT_BOTTOM: + bool bContour = false; + SfxItemState eConState = aAttrs.GetItemState( SDRATTR_TEXT_CONTOURFRAME ); + if( eConState != SfxItemState::DONTCARE ) + { + bContour = aAttrs.Get( SDRATTR_TEXT_CONTOURFRAME ).GetValue(); + } + if (bContour) break; + + SfxItemState eVState = aAttrs.GetItemState( SDRATTR_TEXT_VERTADJUST ); + //SfxItemState eHState = aAttrs.GetItemState( SDRATTR_TEXT_HORZADJUST ); + + //if(SfxItemState::DONTCARE != eVState && SfxItemState::DONTCARE != eHState) + if(SfxItemState::DONTCARE != eVState) + { + SdrTextVertAdjust eTVA = aAttrs.Get(SDRATTR_TEXT_VERTADJUST).GetValue(); + bool bSet = (nSlotId == SID_TABLE_VERT_NONE && eTVA == SDRTEXTVERTADJUST_TOP) || + (nSlotId == SID_TABLE_VERT_CENTER && eTVA == SDRTEXTVERTADJUST_CENTER) || + (nSlotId == SID_TABLE_VERT_BOTTOM && eTVA == SDRTEXTVERTADJUST_BOTTOM); + rSet.Put(SfxBoolItem(nSlotId, bSet)); + } + else + { + rSet.Put(SfxBoolItem(nSlotId, false)); + } + break; + } + nWhich = aIter.NextWhich(); + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews3.cxx b/sd/source/ui/view/drviews3.cxx new file mode 100644 index 0000000000..2a3b778531 --- /dev/null +++ b/sd/source/ui/view/drviews3.cxx @@ -0,0 +1,1106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <DrawViewShell.hxx> + +#include <sfx2/viewfrm.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/adjustitem.hxx> +#include <svx/svdotable.hxx> +#include <editeng/numitem.hxx> +#include <svx/rulritem.hxx> +#include <svx/svxids.hrc> +#include <svx/svdpagv.hxx> +#include <sfx2/request.hxx> +#include <sfx2/dispatch.hxx> +#include <tools/urlobj.hxx> +#include <svl/eitem.hxx> +#include <svl/rectitem.hxx> +#include <svl/stritem.hxx> +#include <svx/svdoole2.hxx> +#include <svl/itempool.hxx> +#include <svl/ptitem.hxx> +#include <basic/sbstar.hxx> +#include <basic/sberrors.hxx> +#include <svx/fmshell.hxx> +#include <svx/f3dchild.hxx> +#include <svx/float3d.hxx> +#include <svx/sdmetitm.hxx> +#include <svx/svdogrp.hxx> +#include <svx/diagram/IDiagramHelper.hxx> + +#include <app.hrc> +#include <strings.hrc> + +#include <sdundogr.hxx> +#include <undopage.hxx> +#include <fupoor.hxx> +#include <slideshow.hxx> +#include <sdpage.hxx> +#include <Window.hxx> +#include <sdresid.hxx> +#include <unokywds.hxx> +#include <drawview.hxx> +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <sdabstdlg.hxx> +#include <sfx2/ipclient.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <ViewShellBase.hxx> +#include <FormShellManager.hxx> +#include <LayerTabBar.hxx> +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/drawing/framework/XConfigurationController.hpp> +#include <com/sun/star/drawing/framework/XConfiguration.hpp> +#include <com/sun/star/drawing/XShape.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <editeng/lspcitem.hxx> +#include <editeng/ulspitem.hxx> +#include <memory> +#include <comphelper/processfactory.hxx> +#include <oox/drawingml/diagram/diagram.hxx> +#include <oox/export/drawingml.hxx> +#include <oox/shape/ShapeFilterBase.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using ::com::sun::star::frame::XFrame; +using ::com::sun::star::frame::XController; + +namespace sd { + +/** + * handle SfxRequests for controller + */ +void DrawViewShell::ExecCtrl(SfxRequest& rReq) +{ + // except a page switch and jumps to bookmarks, nothing is executed during + // a slide show + if( HasCurrentFunction(SID_PRESENTATION) && + rReq.GetSlot() != SID_SWITCHPAGE && + rReq.GetSlot() != SID_JUMPTOMARK) + return; + + CheckLineTo (rReq); + + // End text edit mode for some requests. + sal_uInt16 nSlot = rReq.GetSlot(); + bool bAllowFocusChange = true; + switch (nSlot) + { + case SID_OUTPUT_QUALITY_COLOR: + case SID_OUTPUT_QUALITY_GRAYSCALE: + case SID_OUTPUT_QUALITY_BLACKWHITE: + case SID_OUTPUT_QUALITY_CONTRAST: + // Do nothing. + break; + case SID_SWITCHPAGE: + if (rReq.GetArgs() && rReq.GetArgs()->Count () == 1) + { + const SfxBoolItem* pAllowFocusChange = rReq.GetArg<SfxBoolItem>(SID_SWITCHPAGE); + bAllowFocusChange = pAllowFocusChange->GetValue(); + if (!bAllowFocusChange) + break; + } + [[fallthrough]]; + default: + if ( mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + } + + // sal_uInt16 nSlot = rReq.GetSlot(); + switch (nSlot) + { + case SID_SWITCHPAGE: // BASIC + { + // switch page in running slide show + if(SlideShow::IsRunning(GetViewShellBase()) && rReq.GetArgs()) + { + if (const SfxUInt32Item* pWhatPage = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATPAGE)) + SlideShow::GetSlideShow(GetViewShellBase())->jumpToPageNumber(static_cast<sal_Int32>((pWhatPage->GetValue()-1)>>1)); + } + else + { + const SfxItemSet *pArgs = rReq.GetArgs (); + sal_uInt16 nSelectedPage = 0; + + if (! pArgs || pArgs->Count () == 1) + { + nSelectedPage = maTabControl->GetCurPagePos(); + } + else if (pArgs->Count () == 2) + { + const SfxUInt32Item* pWhatPage = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATPAGE); + const SfxUInt32Item* pWhatKind = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATKIND); + + sal_Int32 nWhatPage = static_cast<sal_Int32>(pWhatPage->GetValue ()); + PageKind nWhatKind = static_cast<PageKind>(pWhatKind->GetValue ()); + if (nWhatKind < PageKind::Standard || nWhatKind > PageKind::Handout) + { +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE); +#endif + rReq.Ignore (); + break; + } + else if (meEditMode != EditMode::MasterPage) + { + if (! CHECK_RANGE (0, nWhatPage, GetDoc()->GetSdPageCount(nWhatKind))) + { +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE); +#endif + rReq.Ignore (); + break; + } + + nSelectedPage = static_cast<short>(nWhatPage); + mePageKind = nWhatKind; + } + } + else + { +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + rReq.Ignore (); + break; + } + + if( GetDocSh() && (GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED)) + GetDocSh()->SetModified(); + + SwitchPage(nSelectedPage, bAllowFocusChange); + + if(HasCurrentFunction(SID_BEZIER_EDIT)) + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + + Invalidate(); + InvalidateWindows(); + rReq.Done (); + } + break; + } + + case SID_SWITCHLAYER: // BASIC + { + const SfxItemSet *pArgs = rReq.GetArgs (); + + // #i87182# + bool bCurPageValid(false); + sal_uInt16 nCurPage(0); + + if(GetLayerTabControl()) + { + nCurPage = GetLayerTabControl()->GetCurPageId(); + bCurPageValid = true; + } + + if(pArgs && 1 == pArgs->Count()) + { + const SfxUInt32Item* pWhatLayer = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYER); + + if(pWhatLayer) + { + nCurPage = static_cast<short>(pWhatLayer->GetValue()); + bCurPageValid = true; + } + } + + if(bCurPageValid) + { + OUString aLayerName( GetLayerTabControl()->GetLayerName(nCurPage)); + if (!aLayerName.isEmpty()) + { + mpDrawView->SetActiveLayer(aLayerName); + } + Invalidate(); + } + + rReq.Done (); + + break; + } + + case SID_PAGEMODE: // BASIC + { + + const SfxItemSet *pArgs = rReq.GetArgs(); + + if (pArgs && pArgs->Count () == 2) + { + const SfxBoolItem* pIsActive = rReq.GetArg<SfxBoolItem>(ID_VAL_ISACTIVE); + const SfxUInt32Item* pWhatKind = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATKIND); + + PageKind nWhatKind = static_cast<PageKind>(pWhatKind->GetValue()); + if ( nWhatKind >= PageKind::Standard && nWhatKind <= PageKind::Handout) + { + mbIsLayerModeActive = pIsActive->GetValue(); + mePageKind = nWhatKind; + } + } + + // turn on default layer of page + mpDrawView->SetActiveLayer(sUNO_LayerName_layout); + + ChangeEditMode(EditMode::Page, mbIsLayerModeActive); + + Invalidate(); + rReq.Done (); + + break; + } + + case SID_LAYERMODE: // BASIC + { + const SfxItemSet *pArgs = rReq.GetArgs(); + + if (pArgs && pArgs->Count() == 2) + { + const SfxUInt32Item* pWhatLayer = rReq.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYER); + EditMode nWhatLayer = static_cast<EditMode>(pWhatLayer->GetValue()); + if (nWhatLayer == EditMode::Page || nWhatLayer == EditMode::MasterPage) + { + mbIsLayerModeActive = rReq.GetArg<SfxBoolItem>(ID_VAL_ISACTIVE)->GetValue(); + meEditMode = nWhatLayer; + } + } + + ChangeEditMode(meEditMode, !mbIsLayerModeActive); + + Invalidate(); + rReq.Done(); + + break; + } + + case SID_HEADER_AND_FOOTER: + case SID_INSERT_PAGE_NUMBER: + case SID_INSERT_DATE_TIME: + { + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + vcl::Window* pWin = GetActiveWindow(); + VclPtr<AbstractHeaderFooterDialog> pDlg(pFact->CreateHeaderFooterDialog(this, pWin ? pWin->GetFrameWeld() : nullptr, GetDoc(), mpActualPage)); + auto xRequest = std::make_shared<SfxRequest>(rReq); + rReq.Ignore(); // the 'old' request is not relevant any more + pDlg->StartExecuteAsync([this, pDlg, xRequest](sal_Int32 /*nResult*/){ + GetActiveWindow()->Invalidate(); + UpdatePreview( mpActualPage ); + + Invalidate(); + xRequest->Done(); + + pDlg->disposeOnce(); + }); + break; + } + + case SID_MASTER_LAYOUTS: + { + SdPage* pPage = GetActualPage(); + if (meEditMode == EditMode::MasterPage) + // Use the master page of the current page. + pPage = static_cast<SdPage*>(&pPage->TRG_GetMasterPage()); + + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + vcl::Window* pWin = GetActiveWindow(); + ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateMasterLayoutDialog(pWin ? pWin->GetFrameWeld() : nullptr, GetDoc(), pPage)); + pDlg->Execute(); + Invalidate(); + rReq.Done (); + break; + } + case SID_OBJECTRESIZE: + { + // The server likes to change the client size + OSL_ASSERT (GetViewShell()!=nullptr); + SfxInPlaceClient* pIPClient = GetViewShell()->GetIPClient(); + + if ( pIPClient && pIPClient->IsObjectInPlaceActive() ) + { + const SfxRectangleItem& rRect = + rReq.GetArgs()->Get(SID_OBJECTRESIZE); + ::tools::Rectangle aRect( GetActiveWindow()->PixelToLogic( rRect.GetValue() ) ); + + if ( mpDrawView->AreObjectsMarked() ) + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + + if (rMarkList.GetMarkCount() == 1) + { + SdrMark* pMark = rMarkList.GetMark(0); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + + SdrOle2Obj* pOle2Obj = dynamic_cast< SdrOle2Obj* >( pObj ); + if(pOle2Obj) + { + if( pOle2Obj->GetObjRef().is() ) + { + pOle2Obj->SetLogicRect(aRect); + } + } + } + } + } + rReq.Ignore (); + break; + } + + case SID_RELOAD: + { + sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId(); + SfxViewFrame* pFrame = GetViewFrame(); + + try + { + Reference< XFrame > xFrame( pFrame->GetFrame().GetFrameInterface(), UNO_SET_THROW ); + + // Save the current configuration of panes and views. + Reference<XControllerManager> xControllerManager ( + GetViewShellBase().GetController(), UNO_QUERY_THROW); + Reference<XConfigurationController> xConfigurationController ( + xControllerManager->getConfigurationController(), UNO_SET_THROW ); + Reference<XConfiguration> xConfiguration ( + xConfigurationController->getRequestedConfiguration(), UNO_SET_THROW ); + + SfxChildWindow* pWindow = pFrame->GetChildWindow(nId); + if(pWindow) + { + Svx3DWin* p3DWin = static_cast<Svx3DWin*>(pWindow->GetWindow()); + if(p3DWin) + p3DWin->DocumentReload(); + } + + // normal forwarding to ViewFrame for execution + GetViewFrame()->ExecuteSlot(rReq); + + // From here on we must cope with this object and the frame already being + // deleted. Do not call any methods or use data members. + Reference<XController> xController( xFrame->getController(), UNO_SET_THROW ); + + // Restore the configuration. + xControllerManager.set( xController, UNO_QUERY_THROW ); + xConfigurationController.set( xControllerManager->getConfigurationController() ); + if ( ! xConfigurationController.is()) + throw RuntimeException(); + xConfigurationController->restoreConfiguration(xConfiguration); + } + catch (RuntimeException&) + { + DBG_UNHANDLED_EXCEPTION("sd.view"); + } + + // We have to return immediately to avoid accessing this object. + return; + } + + case SID_JUMPTOMARK: + { + if( rReq.GetArgs() ) + { + const SfxStringItem* pBookmark = rReq.GetArg<SfxStringItem>(SID_JUMPTOMARK); + + if (pBookmark) + { + OUString sBookmark(INetURLObject::decode(pBookmark->GetValue(), INetURLObject::DecodeMechanism::WithCharset)); + + rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if(xSlideshow.is() && xSlideshow->isRunning()) + { + xSlideshow->jumpToBookmark(sBookmark); + } + else + { + GotoBookmark(sBookmark); + } + } + } + rReq.Done(); + break; + } + + case SID_OUTPUT_QUALITY_COLOR: + case SID_OUTPUT_QUALITY_GRAYSCALE: + case SID_OUTPUT_QUALITY_BLACKWHITE: + case SID_OUTPUT_QUALITY_CONTRAST: + { + ExecReq( rReq ); + break; + } + + case SID_MAIL_SCROLLBODY_PAGEDOWN: + { + ExecReq( rReq ); + break; + } + + case SID_ATTR_YEAR2000: + { + FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell(); + if (pFormShell != nullptr) + { + const SfxPoolItem* pItem; + if (rReq.GetArgs()->GetItemState( + SID_ATTR_YEAR2000, true, &pItem) == SfxItemState::SET) + pFormShell->SetY2KState ( + static_cast<const SfxUInt16Item*>(pItem)->GetValue()); + } + + rReq.Done(); + } + break; + + case SID_OPT_LOCALE_CHANGED: + { + GetActiveWindow()->Invalidate(); + UpdatePreview( mpActualPage ); + rReq.Done(); + } + break; + + case SID_REGENERATE_DIAGRAM: + case SID_EDIT_DIAGRAM: + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + + if (1 == rMarkList.GetMarkCount()) + { + SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); + + // Support advanced DiagramHelper + if(nullptr != pObj && pObj->isDiagram()) + { + if(SID_REGENERATE_DIAGRAM == nSlot) + { + mpDrawView->UnmarkAll(); + pObj->getDiagramHelper()->reLayout(*static_cast<SdrObjGroup*>(pObj)); + mpDrawView->MarkObj(pObj, mpDrawView->GetSdrPageView()); + } + else // SID_EDIT_DIAGRAM + { + VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> pDlg = pFact->CreateDiagramDialog( + GetFrameWeld(), + *static_cast<SdrObjGroup*>(pObj)); + pDlg->Execute(); + } + } + } + + rReq.Done(); + } + break; + + default: + break; + } +} + +void DrawViewShell::ExecRuler(SfxRequest& rReq) +{ + // nothing is executed during a slide show! + if(HasCurrentFunction(SID_PRESENTATION)) + return; + + CheckLineTo (rReq); + + const SfxItemSet* pArgs = rReq.GetArgs(); + const Point aPagePos( GetActiveWindow()->GetViewOrigin() ); + Size aPageSize = mpActualPage->GetSize(); + Size aViewSize = GetActiveWindow()->GetViewSize(); + + switch ( rReq.GetSlot() ) + { + case SID_ATTR_LONG_LRSPACE: + if (pArgs) + { + std::unique_ptr<SdUndoGroup> pUndoGroup(new SdUndoGroup(GetDoc())); + pUndoGroup->SetComment(SdResId(STR_UNDO_CHANGE_PAGEBORDER)); + + const SvxLongLRSpaceItem& rLRSpace = + pArgs->Get(SID_ATTR_LONG_LRSPACE); + + if( mpDrawView->IsTextEdit() ) + { + ::tools::Rectangle aRect = maMarkRect; + aRect.SetPos(aRect.TopLeft() + aPagePos); + aRect.SetLeft( rLRSpace.GetLeft() ); + aRect.SetRight( aViewSize.Width() - rLRSpace.GetRight() ); + aRect.SetPos(aRect.TopLeft() - aPagePos); + if ( aRect != maMarkRect) + { + mpDrawView->SetAllMarkedRect(aRect); + maMarkRect = mpDrawView->GetAllMarkedRect(); + Invalidate( SID_RULER_OBJECT ); + } + } + else + { + ::tools::Long nLeft = std::max(::tools::Long(0), rLRSpace.GetLeft() - aPagePos.X()); + ::tools::Long nRight = std::max(::tools::Long(0), rLRSpace.GetRight() + aPagePos.X() + + aPageSize.Width() - aViewSize.Width()); + + sal_uInt16 nPageCnt = GetDoc()->GetSdPageCount(mePageKind); + sal_uInt16 i; + for ( i = 0; i < nPageCnt; i++) + { + SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind); + SdUndoAction* pUndo = new SdPageLRUndoAction(GetDoc(), + pPage, + pPage->GetLeftBorder(), + pPage->GetRightBorder(), + nLeft, nRight); + pUndoGroup->AddAction(pUndo); + pPage->SetLeftBorder(nLeft); + pPage->SetRightBorder(nRight); + } + nPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind); + + for (i = 0; i < nPageCnt; i++) + { + SdPage* pPage = GetDoc()->GetMasterSdPage(i, mePageKind); + SdUndoAction* pUndo = new SdPageLRUndoAction(GetDoc(), + pPage, + pPage->GetLeftBorder(), + pPage->GetRightBorder(), + nLeft, nRight); + pUndoGroup->AddAction(pUndo); + pPage->SetLeftBorder(nLeft); + pPage->SetRightBorder(nRight); + } + InvalidateWindows(); + } + + // give the undo group to the undo manager + GetViewFrame()->GetObjectShell()->GetUndoManager()-> + AddUndoAction(std::move(pUndoGroup)); + } + break; + case SID_ATTR_LONG_ULSPACE: + if (pArgs) + { + std::unique_ptr<SdUndoGroup> pUndoGroup(new SdUndoGroup(GetDoc())); + pUndoGroup->SetComment(SdResId(STR_UNDO_CHANGE_PAGEBORDER)); + + const SvxLongULSpaceItem& rULSpace = + pArgs->Get(SID_ATTR_LONG_ULSPACE); + + if( mpDrawView->IsTextEdit() ) + { + ::tools::Rectangle aRect = maMarkRect; + aRect.SetPos(aRect.TopLeft() + aPagePos); + aRect.SetTop( rULSpace.GetUpper() ); + aRect.SetBottom( aViewSize.Height() - rULSpace.GetLower() ); + aRect.SetPos(aRect.TopLeft() - aPagePos); + + if ( aRect != maMarkRect) + { + mpDrawView->SetAllMarkedRect(aRect); + maMarkRect = mpDrawView->GetAllMarkedRect(); + Invalidate( SID_RULER_OBJECT ); + } + } + else + { + ::tools::Long nUpper = std::max(::tools::Long(0), rULSpace.GetUpper() - aPagePos.Y()); + ::tools::Long nLower = std::max(::tools::Long(0), rULSpace.GetLower() + aPagePos.Y() + + aPageSize.Height() - aViewSize.Height()); + + sal_uInt16 nPageCnt = GetDoc()->GetSdPageCount(mePageKind); + sal_uInt16 i; + for ( i = 0; i < nPageCnt; i++) + { + SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind); + SdUndoAction* pUndo = new SdPageULUndoAction(GetDoc(), + pPage, + pPage->GetUpperBorder(), + pPage->GetLowerBorder(), + nUpper, nLower); + pUndoGroup->AddAction(pUndo); + pPage->SetUpperBorder(nUpper); + pPage->SetLowerBorder(nLower); + } + nPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind); + + for (i = 0; i < nPageCnt; i++) + { + SdPage* pPage = GetDoc()->GetMasterSdPage(i, mePageKind); + SdUndoAction* pUndo = new SdPageULUndoAction(GetDoc(), + pPage, + pPage->GetUpperBorder(), + pPage->GetLowerBorder(), + nUpper, nLower); + pUndoGroup->AddAction(pUndo); + pPage->SetUpperBorder(nUpper); + pPage->SetLowerBorder(nLower); + } + InvalidateWindows(); + } + + // give the undo group to the undo manager + GetViewFrame()->GetObjectShell()->GetUndoManager()-> + AddUndoAction(std::move(pUndoGroup)); + } + break; + case SID_RULER_OBJECT: + if (pArgs) + { + ::tools::Rectangle aRect = maMarkRect; + aRect.SetPos(aRect.TopLeft() + aPagePos); + + const SvxObjectItem& rOI = pArgs->Get(SID_RULER_OBJECT); + + if ( rOI.GetStartX() != rOI.GetEndX() ) + { + aRect.SetLeft( rOI.GetStartX() ); + aRect.SetRight( rOI.GetEndX() ); + } + if ( rOI.GetStartY() != rOI.GetEndY() ) + { + aRect.SetTop( rOI.GetStartY() ); + aRect.SetBottom( rOI.GetEndY() ); + } + aRect.SetPos(aRect.TopLeft() - aPagePos); + if ( aRect != maMarkRect) + { + mpDrawView->SetAllMarkedRect(aRect); + maMarkRect = mpDrawView->GetAllMarkedRect(); + Invalidate( SID_RULER_OBJECT ); + } + } + break; + case SID_ATTR_TABSTOP: + if (pArgs && mpDrawView->IsTextEdit()) + { + const SvxTabStopItem& rItem = pArgs->Get( EE_PARA_TABS ); + + SfxItemSetFixed<EE_PARA_TABS, EE_PARA_TABS> aEditAttr( GetPool() ); + + aEditAttr.Put( rItem ); + mpDrawView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_TABSTOP); + } + break; + case SID_ATTR_PARA_LINESPACE: + if (pArgs) + { + SvxLineSpacingItem aParaLineSP = pArgs->Get( + GetPool().GetWhich(SID_ATTR_PARA_LINESPACE)); + + SfxItemSetFixed<EE_PARA_SBL, EE_PARA_SBL> aEditAttr( GetPool() ); + aParaLineSP.SetWhich( EE_PARA_SBL ); + + aEditAttr.Put( aParaLineSP ); + mpDrawView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_PARA_LINESPACE); + } + break; + case SID_ATTR_PARA_ADJUST_LEFT: + { + SvxAdjustItem aItem( SvxAdjust::Left, EE_PARA_JUST ); + SfxItemSetFixed<EE_PARA_JUST, EE_PARA_JUST> aEditAttr( GetPool() ); + + aEditAttr.Put( aItem ); + mpDrawView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_PARA_ADJUST_LEFT); + break; + } + case SID_ATTR_PARA_ADJUST_CENTER: + { + SvxAdjustItem aItem( SvxAdjust::Center, EE_PARA_JUST ); + SfxItemSetFixed<EE_PARA_JUST, EE_PARA_JUST> aEditAttr( GetPool() ); + + aEditAttr.Put( aItem ); + mpDrawView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_PARA_ADJUST_CENTER); + break; + } + case SID_ATTR_PARA_ADJUST_RIGHT: + { + SvxAdjustItem aItem( SvxAdjust::Right, EE_PARA_JUST ); + SfxItemSetFixed<EE_PARA_JUST, EE_PARA_JUST> aEditAttr( GetPool() ); + + aEditAttr.Put( aItem ); + mpDrawView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_PARA_ADJUST_RIGHT); + break; + } + case SID_ATTR_PARA_ADJUST_BLOCK: + { + SvxAdjustItem aItem( SvxAdjust::Block, EE_PARA_JUST ); + SfxItemSetFixed<EE_PARA_JUST, EE_PARA_JUST> aEditAttr( GetPool() ); + + aEditAttr.Put( aItem ); + mpDrawView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_PARA_ADJUST_BLOCK); + break; + } + case SID_ATTR_PARA_ULSPACE: + if (pArgs) + { + SvxULSpaceItem aULSP = static_cast<const SvxULSpaceItem&>(pArgs->Get( + SID_ATTR_PARA_ULSPACE)); + SfxItemSetFixed<EE_PARA_ULSPACE, EE_PARA_ULSPACE> aEditAttr( GetPool() ); + aULSP.SetWhich( EE_PARA_ULSPACE ); + + aEditAttr.Put( aULSP ); + mpDrawView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_PARA_ULSPACE); + } + break; + case SID_ATTR_PARA_LRSPACE: + if (pArgs) + { + SvxLRSpaceItem aLRSpace = static_cast<const SvxLRSpaceItem&>(pArgs->Get( + SID_ATTR_PARA_LRSPACE)); + + SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aEditAttr( GetPool() ); + aLRSpace.SetWhich( EE_PARA_LRSPACE ); + + aEditAttr.Put( aLRSpace ); + mpDrawView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_PARA_LRSPACE); + } + break; + case SID_ATTR_LRSPACE: + if (pArgs && mpDrawView->IsTextEdit()) + { + sal_uInt16 nId = SID_ATTR_PARA_LRSPACE; + const SvxLRSpaceItem& rItem = static_cast<const SvxLRSpaceItem&>( + pArgs->Get( nId )); + + SfxItemSetFixed< + EE_PARA_NUMBULLET, EE_PARA_NUMBULLET, + EE_PARA_OUTLLEVEL, EE_PARA_OUTLLEVEL, + EE_PARA_LRSPACE, EE_PARA_LRSPACE> aEditAttr( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aEditAttr ); + + nId = EE_PARA_LRSPACE; + SvxLRSpaceItem aLRSpaceItem( rItem.GetLeft(), + rItem.GetRight(), + rItem.GetTextFirstLineOffset(), nId ); + + const sal_Int16 nOutlineLevel = aEditAttr.Get( EE_PARA_OUTLLEVEL ).GetValue(); + const SvxLRSpaceItem& rOrigLRSpaceItem = aEditAttr.Get( EE_PARA_LRSPACE ); + const SvxNumBulletItem& rNumBulletItem = aEditAttr.Get( EE_PARA_NUMBULLET ); + if( nOutlineLevel != -1 && + rNumBulletItem.GetNumRule().GetLevelCount() > nOutlineLevel ) + { + const SvxNumberFormat& rFormat = rNumBulletItem.GetNumRule().GetLevel(nOutlineLevel); + SvxNumberFormat aFormat(rFormat); + + // left margin gets distributed onto LRSpace item + // and number format AbsLSpace - this fixes + // n#707779 (previously, LRSpace left indent could + // become negative - EditEngine really does not + // like that. + const auto nAbsLSpace=aFormat.GetAbsLSpace(); + const ::tools::Long nTxtLeft=rItem.GetTextLeft(); + const ::tools::Long nLeftIndent=std::max(::tools::Long(0),nTxtLeft - nAbsLSpace); + aLRSpaceItem.SetTextLeft(nLeftIndent); + // control for clipped left indent - remainder + // reduces number format first line indent + aFormat.SetAbsLSpace(nTxtLeft - nLeftIndent); + + // negative first line indent goes to the number + // format, positive to the lrSpace item + if( rItem.GetTextFirstLineOffset() < 0 ) + { + aFormat.SetFirstLineOffset( + rItem.GetTextFirstLineOffset() + - rOrigLRSpaceItem.GetTextFirstLineOffset() + + aFormat.GetCharTextDistance()); + aLRSpaceItem.SetTextFirstLineOffset(0); + } + else + { + aFormat.SetFirstLineOffset(0); + aLRSpaceItem.SetTextFirstLineOffset( + rItem.GetTextFirstLineOffset() + - aFormat.GetFirstLineOffset() //TODO: overflow + + aFormat.GetCharTextDistance()); + } + + if( rFormat != aFormat ) + { + // put all items + const_cast<SvxNumRule&>(rNumBulletItem.GetNumRule()).SetLevel(nOutlineLevel,aFormat); + aEditAttr.Put( rNumBulletItem ); + aEditAttr.Put( aLRSpaceItem ); + mpDrawView->SetAttributes( aEditAttr ); + + Invalidate(SID_ATTR_PARA_LRSPACE); + break; + } + } + + // only put lrSpace item + SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aEditAttrReduced( GetDoc()->GetPool() ); + aEditAttrReduced.Put( aLRSpaceItem ); + mpDrawView->SetAttributes( aEditAttrReduced ); + + Invalidate(SID_ATTR_PARA_LRSPACE); + } + break; + } +} + +void DrawViewShell::GetRulerState(SfxItemSet& rSet) +{ + Point aOrigin; + + if (mpDrawView->GetSdrPageView()) + { + aOrigin = mpDrawView->GetSdrPageView()->GetPageOrigin(); + } + + Size aViewSize = GetActiveWindow()->GetViewSize(); + + const Point aPagePos( GetActiveWindow()->GetViewOrigin() ); + Size aPageSize = mpActualPage->GetSize(); + + ::tools::Rectangle aRect(aPagePos, Point( aViewSize.Width() - (aPagePos.X() + aPageSize.Width()), + aViewSize.Height() - (aPagePos.Y() + aPageSize.Height()))); + + if( mpDrawView->IsTextEdit() ) + { + Point aPnt1 = GetActiveWindow()->GetWinViewPos(); + ::tools::Rectangle aMinMaxRect( aPnt1, Size(-1, -1) ); + rSet.Put( SfxRectangleItem(SID_RULER_LR_MIN_MAX, aMinMaxRect) ); + } + else + { + rSet.Put( SfxRectangleItem(SID_RULER_LR_MIN_MAX, aRect) ); + } + + SvxLongLRSpaceItem aLRSpace(aPagePos.X() + mpActualPage->GetLeftBorder(), + aRect.Right() + mpActualPage->GetRightBorder(), + SID_ATTR_LONG_LRSPACE); + SvxLongULSpaceItem aULSpace(aPagePos.Y() + mpActualPage->GetUpperBorder(), + aRect.Bottom() + mpActualPage->GetLowerBorder(), + SID_ATTR_LONG_ULSPACE); + rSet.Put(SvxPagePosSizeItem(Point(0,0) - aPagePos, aViewSize.Width(), + aViewSize.Height())); + SfxPointItem aPointItem( SID_RULER_NULL_OFFSET, aPagePos + aOrigin ); + + SvxProtectItem aProtect( SID_RULER_PROTECT ); + + maMarkRect = mpDrawView->GetAllMarkedRect(); + + const bool bRTL = GetDoc() && GetDoc()->GetDefaultWritingMode() == css::text::WritingMode_RL_TB; + rSet.Put(SfxBoolItem(SID_RULER_TEXT_RIGHT_TO_LEFT, bRTL)); + + if( mpDrawView->AreObjectsMarked() ) + { + if( mpDrawView->IsTextEdit() ) + { + SdrObject* pObj = mpDrawView->GetMarkedObjectList().GetMark( 0 )->GetMarkedSdrObj(); + if( pObj->GetObjInventor() == SdrInventor::Default) + { + SfxItemSet aEditAttr( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aEditAttr ); + if( aEditAttr.GetItemState( EE_PARA_TABS ) >= SfxItemState::DEFAULT ) + { + const SvxTabStopItem& rItem = aEditAttr.Get( EE_PARA_TABS ); + rSet.Put( rItem ); + + const SvxLRSpaceItem& rLRSpaceItem = aEditAttr.Get( EE_PARA_LRSPACE ); + SvxLRSpaceItem aLRSpaceItem( rLRSpaceItem.GetLeft(), + rLRSpaceItem.GetRight(), + rLRSpaceItem.GetTextFirstLineOffset(), SID_ATTR_PARA_LRSPACE ); + + const sal_Int16 nOutlineLevel = aEditAttr.Get( EE_PARA_OUTLLEVEL ).GetValue(); + const SvxNumBulletItem& rNumBulletItem = aEditAttr.Get( EE_PARA_NUMBULLET ); + if( nOutlineLevel != -1 && + rNumBulletItem.GetNumRule().GetLevelCount() > nOutlineLevel ) + { + const SvxNumberFormat& rFormat = rNumBulletItem.GetNumRule().GetLevel(nOutlineLevel); + aLRSpaceItem.SetTextLeft(rFormat.GetAbsLSpace() + rLRSpaceItem.GetTextLeft()); + aLRSpaceItem.SetTextFirstLineOffset( + rLRSpaceItem.GetTextFirstLineOffset() + rFormat.GetFirstLineOffset() + //TODO: overflow + - rFormat.GetCharTextDistance()); + } + + rSet.Put( aLRSpaceItem ); + + Point aPos( aPagePos + maMarkRect.TopLeft() ); + + if ( aEditAttr.GetItemState( SDRATTR_TEXT_LEFTDIST ) == SfxItemState::SET ) + { + const SdrMetricItem& rTLDItem = aEditAttr.Get( SDRATTR_TEXT_LEFTDIST ); + ::tools::Long nLD = rTLDItem.GetValue(); + aPos.AdjustX(nLD ); + } + + aPointItem.SetValue( aPos ); + + ::tools::Rectangle aParaRect(maMarkRect); + if (pObj->GetObjIdentifier() == SdrObjKind::Table) + { + sdr::table::SdrTableObj* pTable = static_cast<sdr::table::SdrTableObj*>(pObj); + sdr::table::CellPos cellpos; + pTable->getActiveCellPos(cellpos); + pTable->getCellBounds(cellpos, aParaRect); + } + + aLRSpace.SetLeft(aPagePos.X() + aParaRect.Left()); + + if ( aEditAttr.GetItemState( SDRATTR_TEXT_LEFTDIST ) == SfxItemState::SET ) + { + const SdrMetricItem& rTLDItem = aEditAttr.Get( SDRATTR_TEXT_LEFTDIST ); + ::tools::Long nLD = rTLDItem.GetValue(); + aLRSpace.SetLeft( aLRSpace.GetLeft() + nLD ); + } + + aLRSpace.SetRight(aRect.Right() + aPageSize.Width() - aParaRect.Right()); + + if ( aEditAttr.GetItemState( SDRATTR_TEXT_RIGHTDIST ) == SfxItemState::SET ) + { + const SdrMetricItem& rTRDItem = aEditAttr.Get( SDRATTR_TEXT_RIGHTDIST ); + ::tools::Long nRD = rTRDItem.GetValue(); + aLRSpace.SetRight( aLRSpace.GetRight() + nRD ); + } + + aULSpace.SetUpper( aPagePos.Y() + maMarkRect.Top() ); + aULSpace.SetLower( aRect.Bottom() + aPageSize.Height() - maMarkRect.Bottom() ); + + rSet.DisableItem( SID_RULER_OBJECT ); + + // lock page margins + aProtect.SetSizeProtect( true ); + aProtect.SetPosProtect( true ); + } + + if( aEditAttr.GetItemState( EE_PARA_WRITINGDIR ) >= SfxItemState::DEFAULT ) + { + const SvxFrameDirectionItem& rItem = aEditAttr.Get( EE_PARA_WRITINGDIR ); + rSet.Put(SfxBoolItem(SID_RULER_TEXT_RIGHT_TO_LEFT, rItem.GetValue() == SvxFrameDirection::Horizontal_RL_TB)); + } + } + } + else + { + rSet.DisableItem( EE_PARA_TABS ); + rSet.DisableItem( SID_RULER_TEXT_RIGHT_TO_LEFT ); + + if( mpDrawView->IsResizeAllowed(true) ) + { + ::tools::Rectangle aResizeRect( maMarkRect ); + + aResizeRect.SetPos(aResizeRect.TopLeft() + aPagePos); + SvxObjectItem aObjItem(aResizeRect.Left(), aResizeRect.Right(), + aResizeRect.Top(), aResizeRect.Bottom()); + rSet.Put(aObjItem); + rSet.DisableItem( EE_PARA_TABS ); + } + else + { + rSet.DisableItem( SID_RULER_OBJECT ); + } + } + } + else + { + rSet.DisableItem( SID_RULER_OBJECT ); + rSet.DisableItem( EE_PARA_TABS ); + } + + rSet.Put( aLRSpace ); + rSet.Put( aULSpace ); + + rSet.Put( aPointItem ); + rSet.Put( aProtect ); +} + +void DrawViewShell::ExecStatusBar(SfxRequest& rReq) +{ + // nothing is executed during a slide show! + if(HasCurrentFunction(SID_PRESENTATION)) + return; + + CheckLineTo (rReq); + + switch ( rReq.GetSlot() ) + { + case SID_ATTR_SIZE: + { + GetViewFrame()->GetDispatcher()->Execute( SID_ATTR_TRANSFORM, SfxCallMode::ASYNCHRON ); + } + break; + + case SID_STATUS_LAYOUT: + { + GetViewFrame()->GetDispatcher()->Execute( SID_PRESENTATION_LAYOUT, SfxCallMode::ASYNCHRON ); + } + break; + } +} + +/** + * set state of snap object entries in popup + */ +void DrawViewShell::GetSnapItemState( SfxItemSet &rSet ) +{ + SdrPageView* pPV; + Point aMPos = GetActiveWindow()->PixelToLogic(maMousePos); + sal_uInt16 nHitLog = static_cast<sal_uInt16>(GetActiveWindow()->PixelToLogic( + Size(FuPoor::HITPIX,0)).Width()); + sal_uInt16 nHelpLine; + + if ( !mpDrawView->PickHelpLine(aMPos, nHitLog, *GetActiveWindow()->GetOutDev(), nHelpLine, pPV) ) + return; + + const SdrHelpLine& rHelpLine = (pPV->GetHelpLines())[nHelpLine]; + + if ( rHelpLine.GetKind() == SdrHelpLineKind::Point ) + { + rSet.Put( SfxStringItem( SID_SET_SNAPITEM, + SdResId( STR_POPUP_EDIT_SNAPPOINT)) ); + rSet.Put( SfxStringItem( SID_DELETE_SNAPITEM, + SdResId( STR_POPUP_DELETE_SNAPPOINT)) ); + } + else + { + rSet.Put( SfxStringItem( SID_SET_SNAPITEM, + SdResId( STR_POPUP_EDIT_SNAPLINE)) ); + rSet.Put( SfxStringItem( SID_DELETE_SNAPITEM, + SdResId( STR_POPUP_DELETE_SNAPLINE)) ); + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews4.cxx b/sd/source/ui/view/drviews4.cxx new file mode 100644 index 0000000000..4226f0e4e8 --- /dev/null +++ b/sd/source/ui/view/drviews4.cxx @@ -0,0 +1,971 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> + +#include <DrawViewShell.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <svl/urlbmk.hxx> +#include <svx/svdpagv.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/flditem.hxx> +#include <svx/svxids.hrc> +#include <svx/ruler.hxx> +#include <svx/svdobjkind.hxx> +#include <editeng/outliner.hxx> +#include <sfx2/ipclient.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svdopath.hxx> +#include <sfx2/viewfrm.hxx> +#include <editeng/editview.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <vcl/cursor.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/dialoghelper.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weldutils.hxx> + +#include <app.hrc> +#include <strings.hrc> + +#include <DrawDocShell.hxx> +#include <drawdoc.hxx> +#include <Window.hxx> +#include <fupoor.hxx> +#include <sdmod.hxx> +#include <Ruler.hxx> +#include <sdresid.hxx> +#include <sdpage.hxx> +#include <slideshow.hxx> +#include <sdpopup.hxx> +#include <drawview.hxx> +#include <svx/bmpmask.hxx> +#include <LayerTabBar.hxx> +#include <ViewShellBase.hxx> + +#include <SlideSorterViewShell.hxx> +#include <svx/svditer.hxx> + +#include <navigatr.hxx> +#include <memory> + +namespace { + void EndTextEditOnPage(sal_uInt16 nPageId) + { + SfxViewShell* pShell = SfxViewShell::GetFirst(); + while (pShell) + { + ::sd::ViewShellBase* pBase = dynamic_cast<::sd::ViewShellBase*>(pShell); + if (pBase) + { + ::sd::ViewShell* pViewSh = pBase->GetMainViewShell().get(); + ::sd::DrawViewShell* pDrawSh = dynamic_cast<::sd::DrawViewShell*>(pViewSh); + if (pDrawSh && pDrawSh->GetDrawView() && pDrawSh->getCurrentPage()->getPageId() == nPageId) + pDrawSh->GetDrawView()->SdrEndTextEdit(); + } + + pShell = SfxViewShell::GetNext(*pShell); + } + } +} + +namespace sd { + +#define PIPETTE_RANGE 0 + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; + +void DrawViewShell::DeleteActualPage() +{ + mpDrawView->SdrEndTextEdit(); + + try + { + Reference<XDrawPagesSupplier> xDrawPagesSupplier( GetDoc()->getUnoModel(), UNO_QUERY_THROW ); + Reference<XDrawPages> xPages( xDrawPagesSupplier->getDrawPages(), UNO_SET_THROW ); + sal_uInt16 nPageCount = GetDoc()->GetSdPageCount(mePageKind); + SdPage* pPage = nullptr; + std::vector<Reference<XDrawPage>> pagesToDelete; + + GetView()->BegUndo(SdResId(STR_UNDO_DELETEPAGES)); + + for (sal_uInt16 i = 0; i < nPageCount; i++) + { + pPage = GetDoc()->GetSdPage(i, mePageKind); + sal_uInt16 nPageIndex = maTabControl->GetPagePos(pPage->getPageId()); + + slidesorter::SlideSorterViewShell* pVShell + = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase()); + bool bUseSlideSorter = pVShell != nullptr; + + if((bUseSlideSorter && IsSelected(nPageIndex)) || (!bUseSlideSorter && pPage->IsSelected())) + { + EndTextEditOnPage(pPage->getPageId()); + Reference< XDrawPage > xPage( xPages->getByIndex( nPageIndex ), UNO_QUERY_THROW ); + pagesToDelete.push_back(xPage); + } + } + for (const auto &xPage: pagesToDelete) + { + xPages->remove(xPage); + } + + GetView()->EndUndo(); + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION( "sd", "SelectionManager::DeleteSelectedMasterPages()"); + } +} + +void DrawViewShell::DeleteActualLayer() +{ + if(!GetLayerTabControl()) // #i87182# + { + OSL_ENSURE(false, "No LayerTabBar (!)"); + return; + } + + SdrLayerAdmin& rAdmin = GetDoc()->GetLayerAdmin(); + sal_uInt16 nId = GetLayerTabControl()->GetCurPageId(); + const OUString& rName = GetLayerTabControl()->GetLayerName(nId); + if(LayerTabBar::IsRealNameOfStandardLayer(rName)) + { + assert(false && "Standard layer may not be deleted."); + return; + } + const OUString& rDisplayName(GetLayerTabControl()->GetPageText(nId)); + OUString aString(SdResId(STR_ASK_DELETE_LAYER)); + + // replace placeholder + aString = aString.replaceFirst("$", rDisplayName); + + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + aString)); + if (xQueryBox->run() == RET_YES) + { + const SdrLayer* pLayer = rAdmin.GetLayer(rName); + mpDrawView->DeleteLayer( pLayer->GetName() ); + + /* in order to redraw TabBar and Window; should be initiated later on by + a hint from Joe (as by a change if the layer order). */ + // ( View::Notify() --> ViewShell::ResetActualLayer() ) + + mbIsLayerModeActive = false; // so that ChangeEditMode() does something + ChangeEditMode(GetEditMode(), true); + } +} + +bool DrawViewShell::KeyInput (const KeyEvent& rKEvt, ::sd::Window* pWin) +{ + bool bRet = false; + + if (!IsInputLocked() || (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)) + { + if(KEY_RETURN == rKEvt.GetKeyCode().GetCode() + && rKEvt.GetKeyCode().IsMod1() + && GetView()->IsTextEdit()) + { + // this should be used for cursor travelling. + SdPage* pActualPage = GetActualPage(); + const SdrMarkList& rMarkList = GetView()->GetMarkedObjectList(); + SdrTextObj* pCandidate = nullptr; + + if(pActualPage && 1 == rMarkList.GetMarkCount()) + { + SdrMark* pMark = rMarkList.GetMark(0); + + // remember which object was the text in edit mode + SdrObject* pOldObj = pMark->GetMarkedSdrObj(); + + // end text edit now + GetView()->SdrEndTextEdit(); + + // look for a new candidate, a successor of pOldObj + SdrObjListIter aIter(pActualPage, SdrIterMode::DeepNoGroups); + bool bDidVisitOldObject(false); + + while(aIter.IsMore() && !pCandidate) + { + SdrObject* pObj = aIter.Next(); + + if(auto pSdrTextObj = DynCastSdrTextObj( pObj )) + { + SdrInventor nInv(pObj->GetObjInventor()); + SdrObjKind nKnd(pObj->GetObjIdentifier()); + + if(SdrInventor::Default == nInv && + (SdrObjKind::TitleText == nKnd || SdrObjKind::OutlineText == nKnd || SdrObjKind::Text == nKnd) + && bDidVisitOldObject) + { + pCandidate = pSdrTextObj; + } + + if(pObj == pOldObj) + { + bDidVisitOldObject = true; + } + } + } + } + + if(pCandidate) + { + // set the new candidate to text edit mode + GetView()->UnMarkAll(); + GetView()->MarkObj(pCandidate, GetView()->GetSdrPageView()); + + GetViewFrame()->GetDispatcher()->Execute( + SID_ATTR_CHAR, SfxCallMode::ASYNCHRON); + } + else + { + // insert a new page with the same page layout + GetViewFrame()->GetDispatcher()->Execute( + SID_INSERTPAGE_QUICK, SfxCallMode::ASYNCHRON); + } + } + else + { + bRet = ViewShell::KeyInput(rKEvt, pWin); + //If object is marked , the corresponding entry is set true , else + //the corresponding entry is set false . + if(KEY_TAB == rKEvt.GetKeyCode().GetCode() + || KEY_ESCAPE == rKEvt.GetKeyCode().GetCode()) + + { + FreshNavigatrTree(); + } + } + if (!bRet && !mbReadOnly) // tdf#139804 + { + bRet = GetView()->KeyInput(rKEvt, pWin); + } + } + + return bRet; +} + +/** + * Start with Drag from ruler (helper lines, origin) + */ +void DrawViewShell::StartRulerDrag ( + const Ruler& rRuler, + const MouseEvent& rMEvt) +{ + GetActiveWindow()->CaptureMouse(); + + Point aWPos = GetActiveWindow()->PixelToLogic(GetActiveWindow()->GetPointerPosPixel()); + + if ( rRuler.GetExtraRect().Contains(rMEvt.GetPosPixel()) ) + { + mpDrawView->BegSetPageOrg(aWPos); + mbIsRulerDrag = true; + } + else + { + // #i34536# if no guide-lines are visible yet, that show them + if( ! mpDrawView->IsHlplVisible()) + mpDrawView->SetHlplVisible(); + + SdrHelpLineKind eKind; + + if ( rMEvt.IsMod1() ) + eKind = SdrHelpLineKind::Point; + else if ( rRuler.IsHorizontal() ) + eKind = SdrHelpLineKind::Horizontal; + else + eKind = SdrHelpLineKind::Vertical; + + mpDrawView->BegDragHelpLine(aWPos, eKind); + mbIsRulerDrag = true; + } +} + +void DrawViewShell::FreshNavigatrTree() +{ + SfxViewFrame *pViewFrame = GetViewFrame(); + if (!pViewFrame) + return; + SfxChildWindow* pWindow = pViewFrame->GetChildWindow( SID_NAVIGATOR ); + if( pWindow ) + { + SdNavigatorFloat* pNavWin = static_cast<SdNavigatorFloat*>( pWindow->GetWindow() ); + if( pNavWin ) + pNavWin->FreshTree( GetDoc() ); + } + // sidebar version + SfxBindings& rBindings = pViewFrame->GetBindings(); + rBindings.Invalidate(SID_NAVIGATOR_STATE, true); +} + +void DrawViewShell::MouseButtonDown(const MouseEvent& rMEvt, + ::sd::Window* pWin) +{ + mbMouseButtonDown = true; + mbMouseSelecting = false; + + // We have to check if a context menu is shown and we have an UI + // active inplace client. In that case we have to ignore the mouse + // button down event. Otherwise we would crash (context menu has been + // opened by inplace client and we would deactivate the inplace client, + // the context menu is closed by VCL asynchronously which in the end + // would work on deleted objects or the context menu has no parent anymore) + SfxInPlaceClient* pIPClient = GetViewShell()->GetIPClient(); + bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() ); + + if (bIsOleActive && vcl::IsInPopupMenuExecute()) + return; + + if ( IsInputLocked() ) + return; + + ViewShell::MouseButtonDown(rMEvt, pWin); + + //If object is marked , the corresponding entry is set true , + //else the corresponding entry is set false . + FreshNavigatrTree(); + if (mbPipette) + { + SfxChildWindow* pWnd = GetViewFrame()->GetChildWindow(SvxBmpMaskChildWindow::GetChildWindowId()); + SvxBmpMask* pBmpMask = pWnd ? static_cast<SvxBmpMask*>(pWnd->GetWindow()) : nullptr; + if (pBmpMask) + pBmpMask->PipetteClicked(); + } +} + +void DrawViewShell::MouseMove(const MouseEvent& rMEvt, ::sd::Window* pWin) +{ + if ( IsMouseButtonDown() ) + mbMouseSelecting = true; + + if ( IsInputLocked() ) + return; + + if ( mpDrawView->IsAction() ) + { + ::tools::Rectangle aOutputArea(Point(0,0), GetActiveWindow()->GetOutputSizePixel()); + + if ( !aOutputArea.Contains(rMEvt.GetPosPixel()) ) + { + bool bInsideOtherWindow = false; + + if (mpContentWindow) + { + aOutputArea = ::tools::Rectangle(Point(0,0), + mpContentWindow->GetOutputSizePixel()); + + Point aPos = mpContentWindow->GetPointerPosPixel(); + if ( aOutputArea.Contains(aPos) ) + bInsideOtherWindow = true; + } + + if (! GetActiveWindow()->HasFocus ()) + { + GetActiveWindow()->ReleaseMouse (); + mpDrawView->BrkAction (); + return; + } + else if ( bInsideOtherWindow ) + { + GetActiveWindow()->ReleaseMouse(); + pWin->CaptureMouse (); + } + } + else if ( pWin != GetActiveWindow() ) + pWin->CaptureMouse(); + } + + // Since the next MouseMove may execute a IsSolidDraggingNow() in + // SdrCreateView::MovCreateObj and there the ApplicationBackgroundColor + // is needed it is necessary to set it here. + if (GetDoc()) + { + ConfigureAppBackgroundColor(); + mpDrawView->SetApplicationBackgroundColor( GetViewOptions().mnAppBackgroundColor ); + } + + ViewShell::MouseMove(rMEvt, pWin); + + maMousePos = rMEvt.GetPosPixel(); + + ::tools::Rectangle aRect; + + if ( mbIsRulerDrag ) + { + Point aLogPos = GetActiveWindow()->PixelToLogic(maMousePos); + mpDrawView->MovAction(aLogPos); + } + + if ( mpDrawView->IsAction() ) + { + mpDrawView->TakeActionRect(aRect); + aRect = GetActiveWindow()->LogicToPixel(aRect); + } + else + { + aRect = ::tools::Rectangle(maMousePos, maMousePos); + } + + ShowMousePosInfo(aRect, pWin); + + SvxBmpMask* pBmpMask = nullptr; + if (mbPipette && GetViewFrame()->HasChildWindow(SvxBmpMaskChildWindow::GetChildWindowId())) + { + SfxChildWindow* pWnd = GetViewFrame()->GetChildWindow(SvxBmpMaskChildWindow::GetChildWindowId()); + pBmpMask = pWnd ? static_cast<SvxBmpMask*>(pWnd->GetWindow()) : nullptr; + } + + if (!pBmpMask) + return; + + const ::tools::Long nStartX = maMousePos.X() - PIPETTE_RANGE; + const ::tools::Long nEndX = maMousePos.X() + PIPETTE_RANGE; + const ::tools::Long nStartY = maMousePos.Y() - PIPETTE_RANGE; + const ::tools::Long nEndY = maMousePos.Y() + PIPETTE_RANGE; + ::tools::Long nRed = 0; + ::tools::Long nGreen = 0; + ::tools::Long nBlue = 0; + const double fDiv = ( ( PIPETTE_RANGE << 1 ) + 1 ) * ( ( PIPETTE_RANGE << 1 ) + 1 ); + + for ( ::tools::Long nY = nStartY; nY <= nEndY; nY++ ) + { + for( ::tools::Long nX = nStartX; nX <= nEndX; nX++ ) + { + const Color aCol( pWin->GetOutDev()->GetPixel( pWin->PixelToLogic( Point( nX, nY ) ) ) ); + + nRed += aCol.GetRed(); + nGreen += aCol.GetGreen(); + nBlue += aCol.GetBlue(); + } + } + + pBmpMask->SetColor( Color( static_cast<sal_uInt8>( nRed / fDiv + .5 ), + static_cast<sal_uInt8>( nGreen / fDiv + .5 ), + static_cast<sal_uInt8>( nBlue / fDiv + .5 ) ) ); +} + +void DrawViewShell::MouseButtonUp(const MouseEvent& rMEvt, ::sd::Window* pWin) +{ + mbMouseButtonDown = false; + + if ( !IsInputLocked() ) + { + bool bIsSetPageOrg = mpDrawView->IsSetPageOrg(); + + if (mbIsRulerDrag) + { + ::tools::Rectangle aOutputArea(Point(0,0), GetActiveWindow()->GetOutputSizePixel()); + + if (aOutputArea.Contains(rMEvt.GetPosPixel())) + { + mpDrawView->EndAction(); + + if (bIsSetPageOrg) + GetViewFrame()->GetBindings().Invalidate(SID_RULER_NULL_OFFSET); + } + else if (rMEvt.IsLeft() && bIsSetPageOrg) + { + mpDrawView->BrkAction(); + SdPage* pPage = static_cast<SdPage*>( mpDrawView->GetSdrPageView()->GetPage() ); + Point aOrg(pPage->GetLeftBorder(), pPage->GetUpperBorder()); + mpDrawView->GetSdrPageView()->SetPageOrigin(aOrg); + GetViewFrame()->GetBindings().Invalidate(SID_RULER_NULL_OFFSET); + } + else + { + mpDrawView->BrkAction(); + } + + GetActiveWindow()->ReleaseMouse(); + mbIsRulerDrag = false; + } + else + ViewShell::MouseButtonUp(rMEvt, pWin); + //If object is marked , the corresponding entry is set true , + //else the corresponding entry is set false . + FreshNavigatrTree(); + } + mbMouseSelecting = false; +} + +void DrawViewShell::Command(const CommandEvent& rCEvt, ::sd::Window* pWin) +{ + // The command event is send to the window after a possible context + // menu from an inplace client is closed. Now we have the chance to + // deactivate the inplace client without any problem regarding parent + // windows and code on the stack. + SfxInPlaceClient* pIPClient = GetViewShell()->GetIPClient(); + bool bIsOleActive = ( pIPClient && pIPClient->IsObjectInPlaceActive() ); + if ( bIsOleActive && ( rCEvt.GetCommand() == CommandEventId::ContextMenu )) + { + // Deactivate OLE object + mpDrawView->UnmarkAll(); + SelectionHasChanged(); + return; + } + + if ( IsInputLocked() ) + return; + + if( GetView() &&GetView()->getSmartTags().Command(rCEvt) ) + return; + + const bool bNativeShow (SlideShow::IsRunning(GetViewShellBase())); + + if( rCEvt.GetCommand() == CommandEventId::PasteSelection && !bNativeShow ) + { + TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromPrimarySelection()); + + if( aDataHelper.GetTransferable().is() ) + { + Point aPos; + sal_Int8 nDnDAction = DND_ACTION_COPY; + + if( GetActiveWindow() ) + aPos = GetActiveWindow()->PixelToLogic( rCEvt.GetMousePosPixel() ); + + if( !mpDrawView->InsertData( aDataHelper, aPos, nDnDAction, false ) ) + { + INetBookmark aINetBookmark( "", "" ); + + if( ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) ) || + ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::FILEGRPDESCRIPTOR, aINetBookmark ) ) || + ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::UNIFORMRESOURCELOCATOR, aINetBookmark ) ) ) + { + InsertURLField( aINetBookmark.GetURL(), aINetBookmark.GetDescription(), "" ); + } + } + } + } + else if( rCEvt.GetCommand() == CommandEventId::ContextMenu && !bNativeShow && + pWin != nullptr && !mpDrawView->IsAction() && !SD_MOD()->GetWaterCan() ) + { + OUString aPopupId; // Resource name for popup menu + + // is there a snap object under the cursor? + SdrPageView* pPV; + Point aMPos = pWin->PixelToLogic( maMousePos ); + sal_uInt16 nHitLog = static_cast<sal_uInt16>(GetActiveWindow()->PixelToLogic( + Size(FuPoor::HITPIX, 0 ) ).Width()); + sal_uInt16 nHelpLine; + // for gluepoints + SdrObject* pObj = nullptr; + sal_uInt16 nPickId = 0; + // for field command + OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView(); + const SvxFieldItem* pFldItem = nullptr; + if( pOLV ) + pFldItem = pOLV->GetFieldAtSelection(); + + // helper line + if ( mpDrawView->PickHelpLine( aMPos, nHitLog, *GetActiveWindow()->GetOutDev(), nHelpLine, pPV) ) + { + ::tools::Rectangle aRect(rCEvt.GetMousePosPixel(), Size(10, 10)); + weld::Window* pParent = weld::GetPopupParent(*pWin, aRect); + ShowSnapLineContextMenu(pParent, aRect, *pPV, nHelpLine); + return; + } + // is gluepoint under cursor marked? + else if( mpDrawView->PickGluePoint( aMPos, pObj, nPickId, pPV ) && + mpDrawView->IsGluePointMarked( pObj, nPickId ) ) + { + aPopupId = "gluepoint"; + } + // field command? + else if( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) ) ) + { + LanguageType eLanguage( LANGUAGE_SYSTEM ); + + // Format popup with outliner language, if possible + if( pOLV->GetOutliner() ) + { + ESelection aSelection( pOLV->GetSelection() ); + eLanguage = pOLV->GetOutliner()->GetLanguage( aSelection.nStartPara, aSelection.nStartPos ); + } + + //fdo#44998 if the outliner has captured the mouse events release the lock + //so the SdFieldPopup can get them + pOLV->ReleaseMouse(); + SdFieldPopup aFieldPopup(pFldItem->GetField(), eLanguage); + + if ( rCEvt.IsMouseEvent() ) + aMPos = rCEvt.GetMousePosPixel(); + else + aMPos = Point( 20, 20 ); + ::tools::Rectangle aRect(aMPos, Size(1, 1)); + weld::Window* pParent = weld::GetPopupParent(*pWin, aRect); + + aFieldPopup.Execute(pParent, aRect); + + std::unique_ptr<SvxFieldData> pField(aFieldPopup.GetField()); + if (pField) + { + SvxFieldItem aFieldItem( *pField, EE_FEATURE_FIELD ); + // select field, so that it will be deleted on insert + ESelection aSel = pOLV->GetSelection(); + bool bSel = true; + if( aSel.nStartPos == aSel.nEndPos ) + { + bSel = false; + aSel.nEndPos++; + } + pOLV->SetSelection( aSel ); + + pOLV->InsertField( aFieldItem ); + + // reset selection back to original state + if( !bSel ) + aSel.nEndPos--; + pOLV->SetSelection( aSel ); + } + } + else + { + // is something selected? + if (mpDrawView->AreObjectsMarked() && + mpDrawView->GetMarkedObjectList().GetMarkCount() == 1 ) + { + pObj = mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(); + if( HasCurrentFunction(SID_BEZIER_EDIT) && (dynamic_cast< SdrPathObj * >( pObj ) != nullptr ) ) + { + aPopupId = "bezier"; + } + else + { + if( mpDrawView->GetTextEditObject() ) + { + OutlinerView* pOutlinerView = mpDrawView->GetTextEditOutlinerView(); + Point aPos(rCEvt.GetMousePosPixel()); + + if ( pOutlinerView ) + { + if( ( rCEvt.IsMouseEvent() && pOutlinerView->IsWrongSpelledWordAtPos(aPos) ) || + ( !rCEvt.IsMouseEvent() && pOutlinerView->IsCursorAtWrongSpelledWord() ) ) + { + // Popup for Online-Spelling now handled by DrawDocShell + Link<SpellCallbackInfo&,void> aLink = LINK(GetDocSh(), DrawDocShell, OnlineSpellCallback); + + if( !rCEvt.IsMouseEvent() ) + { + aPos = GetActiveWindow()->LogicToPixel( pOutlinerView->GetEditView().GetCursor()->GetPos() ); + } + // While showing the spell context menu + // we lock the input so that another + // context menu can not be opened during + // that time (crash #i43235#). In order + // to not lock the UI completely we + // first release the mouse. + GetActiveWindow()->ReleaseMouse(); + LockInput(); + pOutlinerView->ExecuteSpellPopup(aPos, aLink); + pOutlinerView->GetEditView().Invalidate(); + UnlockInput(); + } + else + { + if( (pObj->GetObjInventor() == SdrInventor::Default) && (pObj->GetObjIdentifier() == SdrObjKind::Table) ) + { + aPopupId = "table"; + } + else + { + aPopupId = "drawtext"; + } + } + } + } + else + { + SdrInventor nInv = pObj->GetObjInventor(); + SdrObjKind nId = pObj->GetObjIdentifier(); + + if (nInv == SdrInventor::Default) + { + switch ( nId ) + { + case SdrObjKind::OutlineText: + case SdrObjKind::Caption: + case SdrObjKind::TitleText: + case SdrObjKind::Text: + aPopupId = "textbox"; + break; + + case SdrObjKind::PathLine: + case SdrObjKind::PolyLine: + aPopupId = "curve"; + break; + + case SdrObjKind::FreehandLine: + case SdrObjKind::Edge: + aPopupId = "connector"; + break; + + case SdrObjKind::Line: + aPopupId = "line"; + break; + + case SdrObjKind::Measure: + aPopupId = "measure"; + break; + + case SdrObjKind::Rectangle: + case SdrObjKind::CircleOrEllipse: + case SdrObjKind::FreehandFill: + case SdrObjKind::PathFill: + case SdrObjKind::Polygon: + case SdrObjKind::CircleSection: + case SdrObjKind::CircleArc: + case SdrObjKind::CircleCut: + case SdrObjKind::CustomShape: + aPopupId = "draw"; + break; + + case SdrObjKind::Group: + aPopupId = "group"; + break; + + case SdrObjKind::Graphic: + aPopupId = "graphic"; + break; + + case SdrObjKind::OLE2: + aPopupId = "oleobject"; + break; + case SdrObjKind::Media: + aPopupId = "media"; + break; + case SdrObjKind::Table: + aPopupId = "table"; + break; + default: ; + } + } + else if( nInv == SdrInventor::E3d ) + { + if( nId == SdrObjKind::E3D_Scene ) + { + if( !mpDrawView->IsGroupEntered() ) + aPopupId = "3dscene"; + else + aPopupId = "3dscene2"; + } + else + aPopupId = "3dobject"; + } + else if( nInv == SdrInventor::FmForm ) + { + aPopupId = "form"; + } + } + } + } + + // multiple selection + else if (mpDrawView->AreObjectsMarked() && + mpDrawView->GetMarkedObjectList().GetMarkCount() > 1 ) + { + aPopupId = "multiselect"; + } + + // nothing selected + else + { + aPopupId = "page"; + } + } + // show Popup-Menu + if (!aPopupId.isEmpty()) + { + GetActiveWindow()->ReleaseMouse(); + + if(rCEvt.IsMouseEvent()) + GetViewFrame()->GetDispatcher()->ExecutePopup( aPopupId ); + else + { + //don't open contextmenu at mouse position if not opened via mouse + + //middle of the window if nothing is marked + Point aMenuPos(GetActiveWindow()->GetSizePixel().Width()/2 + ,GetActiveWindow()->GetSizePixel().Height()/2); + + //middle of the bounding rect if something is marked + if( mpDrawView->AreObjectsMarked() && mpDrawView->GetMarkedObjectList().GetMarkCount() >= 1 ) + { + ::tools::Rectangle aMarkRect; + mpDrawView->GetMarkedObjectList().TakeBoundRect(nullptr,aMarkRect); + aMenuPos = GetActiveWindow()->LogicToPixel( aMarkRect.Center() ); + + //move the point into the visible window area + if( aMenuPos.X() < 0 ) + aMenuPos.setX( 0 ); + if( aMenuPos.Y() < 0 ) + aMenuPos.setY( 0 ); + if( aMenuPos.X() > GetActiveWindow()->GetSizePixel().Width() ) + aMenuPos.setX( GetActiveWindow()->GetSizePixel().Width() ); + if( aMenuPos.Y() > GetActiveWindow()->GetSizePixel().Height() ) + aMenuPos.setY( GetActiveWindow()->GetSizePixel().Height() ); + } + + //open context menu at that point + GetViewFrame()->GetDispatcher()->ExecutePopup( aPopupId, GetActiveWindow(), &aMenuPos ); + } + } + } + else + { + ViewShell::Command(rCEvt, pWin); + } +} + +void DrawViewShell::ShowMousePosInfo(const ::tools::Rectangle& rRect, + ::sd::Window const * pWin) +{ + if (mbHasRulers && pWin ) + { + RulerLine pHLines[2]; + RulerLine pVLines[2]; + ::tools::Long nHOffs = 0; + ::tools::Long nVOffs = 0; + sal_uInt16 nCnt; + + if (mpHorizontalRuler) + mpHorizontalRuler->SetLines(); + + if (mpVerticalRuler) + mpVerticalRuler->SetLines(); + + if (mpHorizontalRuler) + { + nHOffs = mpHorizontalRuler->GetNullOffset() + + mpHorizontalRuler->GetPageOffset(); + } + + if (mpVerticalRuler) + { + nVOffs = mpVerticalRuler->GetNullOffset() + + mpVerticalRuler->GetPageOffset(); + } + + nCnt = 1; + pHLines[0].nPos = rRect.Left() - nHOffs; + pVLines[0].nPos = rRect.Top() - nVOffs; + + if ( rRect.Right() != rRect.Left() || rRect.Bottom() != rRect.Top() ) + { + pHLines[1].nPos = rRect.Right() - nHOffs; + pVLines[1].nPos = rRect.Bottom() - nVOffs; + nCnt++; + } + + if (mpHorizontalRuler) + mpHorizontalRuler->SetLines(nCnt, pHLines); + if (mpVerticalRuler) + mpVerticalRuler->SetLines(nCnt, pVLines); + } + + // display with coordinates in StatusBar + OSL_ASSERT (GetViewShell()!=nullptr); + if ( GetViewShell()->GetUIActiveClient() ) + return; + + SfxItemSetFixed< + SID_CONTEXT, SID_CONTEXT, + SID_ATTR_POSITION, SID_ATTR_SIZE> aSet(GetPool()); + + GetStatusBarState(aSet); + + aSet.Put( SfxStringItem( SID_CONTEXT, mpDrawView->GetStatusText() ) ); + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.SetState(aSet); + rBindings.Invalidate(SID_CONTEXT); + rBindings.Invalidate(SID_ATTR_POSITION); + rBindings.Invalidate(SID_ATTR_SIZE); +} + +void DrawViewShell::LockInput() +{ + mnLockCount++; +} + +void DrawViewShell::UnlockInput() +{ + DBG_ASSERT( mnLockCount, "Input for this shell is not locked!" ); + if ( mnLockCount ) + mnLockCount--; +} + +void DrawViewShell::ShowSnapLineContextMenu(weld::Window* pParent, const ::tools::Rectangle& rRect, + SdrPageView& rPageView, const sal_uInt16 nSnapLineIndex) +{ + const SdrHelpLine& rHelpLine (rPageView.GetHelpLines()[nSnapLineIndex]); + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "modules/simpress/ui/snapmenu.ui")); + std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu")); + + if (rHelpLine.GetKind() == SdrHelpLineKind::Point) + { + xMenu->append(OUString::number(SID_SET_SNAPITEM), SdResId(STR_POPUP_EDIT_SNAPPOINT)); + xMenu->append_separator("separator"); + xMenu->append(OUString::number(SID_DELETE_SNAPITEM), SdResId(STR_POPUP_DELETE_SNAPPOINT)); + } + else + { + xMenu->append(OUString::number(SID_SET_SNAPITEM), SdResId(STR_POPUP_EDIT_SNAPLINE)); + xMenu->append_separator("separator"); + xMenu->append(OUString::number(SID_DELETE_SNAPITEM), SdResId(STR_POPUP_DELETE_SNAPLINE)); + } + + const int nResult = xMenu->popup_at_rect(pParent, rRect).toInt32(); + switch (nResult) + { + case SID_SET_SNAPITEM: + { + SfxUInt32Item aHelpLineItem (ID_VAL_INDEX, nSnapLineIndex); + const SfxPoolItem* aArguments[] = {&aHelpLineItem, nullptr}; + GetViewFrame()->GetDispatcher()->Execute( + SID_SET_SNAPITEM, + SfxCallMode::SLOT, + aArguments); + } + break; + + case SID_DELETE_SNAPITEM: + { + rPageView.DeleteHelpLine(nSnapLineIndex); + } + break; + + default: + break; + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews5.cxx b/sd/source/ui/view/drviews5.cxx new file mode 100644 index 0000000000..8583ecc182 --- /dev/null +++ b/sd/source/ui/view/drviews5.cxx @@ -0,0 +1,653 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> +#include <editeng/outliner.hxx> +#include <svx/svxids.hrc> +#include <sfx2/request.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdoutl.hxx> + +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <sdcommands.h> +#include <sal/log.hxx> + +#include <svx/fmshell.hxx> +#include <editeng/eeitem.hxx> +#include <AccessibleDrawDocumentView.hxx> + +#include <sfx2/viewfrm.hxx> +#include <LayerTabBar.hxx> + +#include <app.hrc> +#include <helpids.h> +#include <optsitem.hxx> +#include <sdmod.hxx> +#include <FrameView.hxx> +#include <Window.hxx> +#include <drawview.hxx> +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <Client.hxx> +#include <slideshow.hxx> +#include <unokywds.hxx> +#include <sdpage.hxx> +#include <SdUnoDrawView.hxx> +#include <ViewShellBase.hxx> +#include <FormShellManager.hxx> +#include <DrawController.hxx> +#include <memory> +#include <comphelper/lok.hxx> + +namespace sd { + +void DrawViewShell::ModelHasChanged() +{ + Invalidate(); + // that the navigator also gets an up to date state + GetViewFrame()->GetBindings().Invalidate( SID_NAVIGATOR_STATE, true ); + + SfxBoolItem aItem( SID_3D_STATE, true ); + GetViewFrame()->GetDispatcher()->ExecuteList( + SID_3D_STATE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem }); + + // now initialize the TextEditOutliner which was newly created by the draw engine + ::Outliner* pOutliner = mpDrawView->GetTextEditOutliner(); + if (pOutliner) + { + SfxStyleSheetPool* pSPool = static_cast<SfxStyleSheetPool*>( GetDocSh()->GetStyleSheetPool() ); + pOutliner->SetStyleSheetPool(pSPool); + } +} + +void DrawViewShell::Resize() +{ + ViewShell::Resize(); + + // tdf#151621 Do not set if the embedded object is opening in a new window. + if (GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED + && GetDocSh()->IsInPlaceActive()) + { + SetZoomRect(GetDocSh()->GetVisArea(ASPECT_CONTENT)); + } + + rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if( xSlideshow.is() && xSlideshow->isRunning() && !xSlideshow->isFullScreen() ) + { + xSlideshow->resize(maViewSize); + } +} + +void DrawViewShell::ArrangeGUIElements() +{ + // Retrieve the current size (thickness) of the scroll bars. That is + // the width of the vertical and the height of the horizontal scroll + // bar. + int nScrollBarSize = GetParentWindow()->GetSettings().GetStyleSettings().GetScrollBarSize(); + maScrBarWH = Size (nScrollBarSize, nScrollBarSize); + + ViewShell::ArrangeGUIElements (); + + maTabControl->Hide(); + + OSL_ASSERT (GetViewShell()!=nullptr); + Client* pIPClient = static_cast<Client*>(GetViewShell()->GetIPClient()); + bool bClientActive = false; + if ( pIPClient && pIPClient->IsObjectInPlaceActive() ) + bClientActive = true; + + bool bInPlaceActive = GetViewFrame()->GetFrame().IsInPlace(); + + if ( mbZoomOnPage && !bInPlaceActive && !bClientActive ) + { + // with split, always resize first window + //af pWindow = mpContentWindow.get(); + SfxRequest aReq(SID_SIZE_PAGE, SfxCallMode::SLOT, GetDoc()->GetItemPool()); + ExecuteSlot( aReq ); + } +} + +/** + * Apply data of the FrameView on the current view + */ +void DrawViewShell::ReadFrameViewData(FrameView* pView) +{ + ModifyGuard aGuard( GetDoc() ); + + // this option has to be adjust at the model + GetDoc()->SetPickThroughTransparentTextFrames( + SD_MOD()->GetSdOptions(GetDoc()->GetDocumentType())->IsPickThrough()); + + // initialization of the Character-(Screen-) attribute + if (HasRuler() != pView->HasRuler()) + SetRuler( pView->HasRuler() ); + + if (mpDrawView->GetGridCoarse() != pView->GetGridCoarse()) + mpDrawView->SetGridCoarse( pView->GetGridCoarse() ); + + if (mpDrawView->GetGridFine() != pView->GetGridFine()) + mpDrawView->SetGridFine( pView->GetGridFine() ); + + if (mpDrawView->GetSnapGridWidthX() != pView->GetSnapGridWidthX() || mpDrawView->GetSnapGridWidthY() != pView->GetSnapGridWidthY()) + mpDrawView->SetSnapGridWidth(pView->GetSnapGridWidthX(), pView->GetSnapGridWidthY()); + + if (mpDrawView->IsGridVisible() != pView->IsGridVisible()) + mpDrawView->SetGridVisible( pView->IsGridVisible() ); + + if (mpDrawView->IsGridFront() != pView->IsGridFront()) + mpDrawView->SetGridFront( pView->IsGridFront() ); + + if (mpDrawView->GetSnapAngle() != pView->GetSnapAngle()) + mpDrawView->SetSnapAngle( pView->GetSnapAngle() ); + + if (mpDrawView->IsGridSnap() != pView->IsGridSnap() ) + mpDrawView->SetGridSnap( pView->IsGridSnap() ); + + if (mpDrawView->IsBordSnap() != pView->IsBordSnap() ) + mpDrawView->SetBordSnap( pView->IsBordSnap() ); + + if (mpDrawView->IsHlplSnap() != pView->IsHlplSnap() ) + mpDrawView->SetHlplSnap( pView->IsHlplSnap() ); + + if (mpDrawView->IsOFrmSnap() != pView->IsOFrmSnap() ) + mpDrawView->SetOFrmSnap( pView->IsOFrmSnap() ); + + if (mpDrawView->IsOPntSnap() != pView->IsOPntSnap() ) + mpDrawView->SetOPntSnap( pView->IsOPntSnap() ); + + if (mpDrawView->IsOConSnap() != pView->IsOConSnap() ) + mpDrawView->SetOConSnap( pView->IsOConSnap() ); + + if (mpDrawView->IsHlplVisible() != pView->IsHlplVisible() ) + mpDrawView->SetHlplVisible( pView->IsHlplVisible() ); + + if (mpDrawView->IsDragStripes() != pView->IsDragStripes() ) + mpDrawView->SetDragStripes( pView->IsDragStripes() ); + + if (mpDrawView->IsPlusHandlesAlwaysVisible() != pView->IsPlusHandlesAlwaysVisible() ) + mpDrawView->SetPlusHandlesAlwaysVisible( pView->IsPlusHandlesAlwaysVisible() ); + + if (mpDrawView->GetSnapMagneticPixel() != pView->GetSnapMagneticPixel() ) + mpDrawView->SetSnapMagneticPixel( pView->GetSnapMagneticPixel() ); + + if (mpDrawView->IsMarkedHitMovesAlways() != pView->IsMarkedHitMovesAlways() ) + mpDrawView->SetMarkedHitMovesAlways( pView->IsMarkedHitMovesAlways() ); + + if (mpDrawView->IsMoveOnlyDragging() != pView->IsMoveOnlyDragging() ) + mpDrawView->SetMoveOnlyDragging( pView->IsMoveOnlyDragging() ); + + if (mpDrawView->IsNoDragXorPolys() != pView->IsNoDragXorPolys() ) + mpDrawView->SetNoDragXorPolys( pView->IsNoDragXorPolys() ); + + if (mpDrawView->IsCrookNoContortion() != pView->IsCrookNoContortion() ) + mpDrawView->SetCrookNoContortion( pView->IsCrookNoContortion() ); + + if (mpDrawView->IsAngleSnapEnabled() != pView->IsAngleSnapEnabled() ) + mpDrawView->SetAngleSnapEnabled( pView->IsAngleSnapEnabled() ); + + if (mpDrawView->IsBigOrtho() != pView->IsBigOrtho() ) + mpDrawView->SetBigOrtho( pView->IsBigOrtho() ); + + if (mpDrawView->IsOrtho() != pView->IsOrtho() ) + mpDrawView->SetOrtho( pView->IsOrtho() ); + + if (mpDrawView->GetEliminatePolyPointLimitAngle() != pView->GetEliminatePolyPointLimitAngle() ) + mpDrawView->SetEliminatePolyPointLimitAngle( pView->GetEliminatePolyPointLimitAngle() ); + + if (mpDrawView->IsEliminatePolyPoints() != pView->IsEliminatePolyPoints() ) + mpDrawView->SetEliminatePolyPoints( pView->IsEliminatePolyPoints() ); + + if (mpDrawView->IsSolidDragging() != pView->IsSolidDragging() ) + mpDrawView->SetSolidDragging( pView->IsSolidDragging() ); + + if (mpDrawView->IsQuickTextEditMode() != pView->IsQuickEdit()) + mpDrawView->SetQuickTextEditMode( pView->IsQuickEdit() ); + + // #i26631# + if (mpDrawView->IsMasterPagePaintCaching() != pView->IsMasterPagePaintCaching()) + mpDrawView->SetMasterPagePaintCaching( pView->IsMasterPagePaintCaching() ); + + if (mpDrawView->GetDragThresholdPixels() != pView->GetDragThresholdPixels()) + mpDrawView->SetDragThresholdPixels( pView->GetDragThresholdPixels() ); + + // handle size: 9 pixels + sal_uInt16 nTmp = mpDrawView->GetMarkHdlSizePixel(); + if( nTmp != 9 ) + mpDrawView->SetMarkHdlSizePixel( 9 ); + + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + if (pPageView) + { + if ( pPageView->GetVisibleLayers() != pView->GetVisibleLayers() ) + pPageView->SetVisibleLayers( pView->GetVisibleLayers() ); + + if ( pPageView->GetPrintableLayers() != pView->GetPrintableLayers() ) + pPageView->SetPrintableLayers( pView->GetPrintableLayers() ); + + if ( pPageView->GetLockedLayers() != pView->GetLockedLayers() ) + pPageView->SetLockedLayers( pView->GetLockedLayers() ); + + if (mePageKind == PageKind::Notes) + { + if (pPageView->GetHelpLines() != pView->GetNotesHelpLines()) + pPageView->SetHelpLines( pView->GetNotesHelpLines() ); + } + else if (mePageKind == PageKind::Handout) + { + if (pPageView->GetHelpLines() != pView->GetHandoutHelpLines()) + pPageView->SetHelpLines( pView->GetHandoutHelpLines() ); + } + else + { + if (pPageView->GetHelpLines() != pView->GetStandardHelpLines()) + pPageView->SetHelpLines( pView->GetStandardHelpLines() ); + } + } + + if ( mpDrawView->GetActiveLayer() != pView->GetActiveLayer() ) + mpDrawView->SetActiveLayer( pView->GetActiveLayer() ); + + sal_uInt16 nSelectedPage = 0; + + if (mePageKind != PageKind::Handout) + { + nSelectedPage = pView->GetSelectedPage(); + } + + EditMode eNewEditMode = pView->GetViewShEditMode(/*mePageKind*/); + bool bNewLayerMode = pView->IsLayerMode(); + + if(IsLayerModeActive() && bNewLayerMode) + { + // #i57936# Force mbIsLayerModeActive to false so that ChangeEditMode + // below does something regarding LayerTabBar content refresh. That refresh + // is only done when IsLayerModeActive changes. It needs to be done + // since e.g. Layer visibility was changed above and this may need + // a refresh to show the correct graphical representation + mbIsLayerModeActive = false; + } + + ChangeEditMode(eNewEditMode, bNewLayerMode); + SwitchPage(nSelectedPage); + + // restore DrawMode for 'normal' window + if(GetActiveWindow()->GetOutDev()->GetDrawMode() != pView->GetDrawMode()) + GetActiveWindow()->GetOutDev()->SetDrawMode(pView->GetDrawMode()); + + if ( mpDrawView->IsDesignMode() != pView->IsDesignMode() ) + { + SfxBoolItem aDesignModeItem( SID_FM_DESIGN_MODE, pView->IsDesignMode() ); + GetViewFrame()->GetDispatcher()->ExecuteList(SID_FM_DESIGN_MODE, + SfxCallMode::SYNCHRON | SfxCallMode::RECORD, + { &aDesignModeItem }); + } + + // has to be called in the end, because it executes a WriteFrameViewData() + if (mpDrawView->IsFrameDragSingles() != pView->IsFrameDragSingles() ) + mpDrawView->SetFrameDragSingles( pView->IsFrameDragSingles() ); +} + +/** + * Apply data of the current view on the FrameView + */ +void DrawViewShell::WriteFrameViewData() +{ + // store character-(screen-) attribute of FrameView + mpFrameView->SetRuler( HasRuler() ); + mpFrameView->SetGridCoarse( mpDrawView->GetGridCoarse() ); + mpFrameView->SetGridFine( mpDrawView->GetGridFine() ); + mpFrameView->SetSnapGridWidth(mpDrawView->GetSnapGridWidthX(), mpDrawView->GetSnapGridWidthY()); + mpFrameView->SetGridVisible( mpDrawView->IsGridVisible() ); + mpFrameView->SetGridFront( mpDrawView->IsGridFront() ); + mpFrameView->SetSnapAngle( mpDrawView->GetSnapAngle() ); + mpFrameView->SetGridSnap( mpDrawView->IsGridSnap() ); + mpFrameView->SetBordSnap( mpDrawView->IsBordSnap() ); + mpFrameView->SetHlplSnap( mpDrawView->IsHlplSnap() ); + mpFrameView->SetOFrmSnap( mpDrawView->IsOFrmSnap() ); + mpFrameView->SetOPntSnap( mpDrawView->IsOPntSnap() ); + mpFrameView->SetOConSnap( mpDrawView->IsOConSnap() ); + mpFrameView->SetHlplVisible( mpDrawView->IsHlplVisible() ); + mpFrameView->SetDragStripes( mpDrawView->IsDragStripes() ); + mpFrameView->SetPlusHandlesAlwaysVisible( mpDrawView->IsPlusHandlesAlwaysVisible() ); + mpFrameView->SetFrameDragSingles( mpDrawView->IsFrameDragSingles() ); + mpFrameView->SetMarkedHitMovesAlways( mpDrawView->IsMarkedHitMovesAlways() ); + mpFrameView->SetMoveOnlyDragging( mpDrawView->IsMoveOnlyDragging() ); + mpFrameView->SetNoDragXorPolys( mpDrawView->IsNoDragXorPolys() ); + mpFrameView->SetCrookNoContortion( mpDrawView->IsCrookNoContortion() ); + mpFrameView->SetBigOrtho( mpDrawView->IsBigOrtho() ); + mpFrameView->SetEliminatePolyPointLimitAngle( mpDrawView->GetEliminatePolyPointLimitAngle() ); + mpFrameView->SetEliminatePolyPoints( mpDrawView->IsEliminatePolyPoints() ); + + mpFrameView->SetSolidDragging( mpDrawView->IsSolidDragging() ); + mpFrameView->SetQuickEdit( mpDrawView->IsQuickTextEditMode() ); + + mpFrameView->SetDesignMode( mpDrawView->IsDesignMode() ); + + Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel(); + ::tools::Rectangle aVisArea = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); + if (comphelper::LibreOfficeKit::isActive()) + { + // aVisArea is nonsensical in the LOK case, use the slide size + aVisArea = ::tools::Rectangle(Point(), getCurrentPage()->GetSize()); + } + + mpFrameView->SetVisArea(aVisArea); + + if( mePageKind == PageKind::Handout ) + mpFrameView->SetSelectedPage(0); + else + { + mpFrameView->SetSelectedPage( maTabControl->GetCurPagePos() ); + } + + mpFrameView->SetViewShEditMode(meEditMode); + mpFrameView->SetLayerMode(IsLayerModeActive()); + + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + + if (pPageView) + { + if ( mpFrameView->GetVisibleLayers() != pPageView->GetVisibleLayers() ) + mpFrameView->SetVisibleLayers( pPageView->GetVisibleLayers() ); + + if ( mpFrameView->GetPrintableLayers() != pPageView->GetPrintableLayers() ) + mpFrameView->SetPrintableLayers( pPageView->GetPrintableLayers() ); + + if ( mpFrameView->GetLockedLayers() != pPageView->GetLockedLayers() ) + mpFrameView->SetLockedLayers( pPageView->GetLockedLayers() ); + + if (mePageKind == PageKind::Notes) + { + mpFrameView->SetNotesHelpLines( pPageView->GetHelpLines() ); + } + else if (mePageKind == PageKind::Handout) + { + mpFrameView->SetHandoutHelpLines( pPageView->GetHelpLines() ); + } + else + { + mpFrameView->SetStandardHelpLines( pPageView->GetHelpLines() ); + } + } + + if ( mpFrameView->GetActiveLayer() != mpDrawView->GetActiveLayer() ) + mpFrameView->SetActiveLayer( mpDrawView->GetActiveLayer() ); + + // store DrawMode for 'normal' window + if(mpFrameView->GetDrawMode() != GetActiveWindow()->GetOutDev()->GetDrawMode()) + mpFrameView->SetDrawMode(GetActiveWindow()->GetOutDev()->GetDrawMode()); +} + +void DrawViewShell::PrePaint() +{ + mpDrawView->PrePaint(); +} + +/** + * The event is forwarded to the Viewshell and the current function by the + * window pWin. + * + * Remark: pWin==NULL, if Paint() is called from ShowWindow! + */ +void DrawViewShell::Paint(const ::tools::Rectangle& rRect, ::sd::Window* pWin) +{ + /* This is done before each text edit, so why not do it before every paint. + The default language is only used if the outliner only contains one + character in a symbol font */ + GetDoc()->GetDrawOutliner().SetDefaultLanguage( GetDoc()->GetLanguage( EE_CHAR_LANGUAGE ) ); + + // Set Application Background color for usage in SdrPaintView(s) + mpDrawView->SetApplicationBackgroundColor( GetViewOptions().mnAppBackgroundColor ); + + /* This is done before each text edit, so why not do it before every paint. + The default language is only used if the outliner only contains one + character in a symbol font */ + GetDoc()->GetDrawOutliner().SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ); + + mpDrawView->CompleteRedraw( pWin->GetOutDev(), vcl::Region( rRect ) ); +} + +/** + * adjust zoom factor for InPlace + */ +void DrawViewShell::SetZoomFactor(const Fraction& rZoomX, const Fraction& rZoomY) +{ + ViewShell::SetZoomFactor(rZoomX, rZoomY); + mbZoomOnPage = false; + Point aOrigin = GetActiveWindow()->GetViewOrigin(); + GetActiveWindow()->SetWinViewPos(aOrigin); +} + +void DrawViewShell::HidePage() +{ + FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell(); + if (pFormShell != nullptr) + pFormShell->PrepareClose(false); +} + +void DrawViewShell::WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& rSequence ) +{ + WriteFrameViewData(); + + ViewShell::WriteUserDataSequence( rSequence ); + + const sal_Int32 nIndex = rSequence.getLength(); + rSequence.realloc( nIndex + 1 ); + auto pSequence = rSequence.getArray(); + pSequence[nIndex].Name = sUNO_View_ZoomOnPage ; + pSequence[nIndex].Value <<= mbZoomOnPage; + + // Common SdrModel processing + GetDocSh()->GetDoc()->WriteUserDataSequence(rSequence); +} + +void DrawViewShell::ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& rSequence ) +{ + WriteFrameViewData(); + + ViewShell::ReadUserDataSequence( rSequence ); + + for (const css::beans::PropertyValue& rValue : rSequence) + { + if ( rValue.Name == sUNO_View_ZoomOnPage ) + { + bool bZoomPage = false; + if( rValue.Value >>= bZoomPage ) + { + mbZoomOnPage = bZoomPage; + } + } + // Fallback to common SdrModel processing + else GetDocSh()->GetDoc()->ReadUserDataSequenceValue(&rValue); + } + + // The parameter rSequence contains the config-items from + // <config:config-item-set config:name="ooo:view-settings">. Determine, whether + // they contain "VisibleLayers", "PrintableLayers" and "LockedLayers". If not, it + // is a foreign document or a new document after transition period and the corresponding + // information were read from <draw:layer-set>. In that case we need to bring + // the information from model to view. + bool bHasVisiPrnLockSettings(false); + for ( auto & rPropertyValue : rSequence ) + { + if ( rPropertyValue.Name == sUNO_View_VisibleLayers + || rPropertyValue.Name == sUNO_View_PrintableLayers + || rPropertyValue.Name == sUNO_View_LockedLayers ) + { + bHasVisiPrnLockSettings = true; + break; + } + } + if ( !bHasVisiPrnLockSettings ) + { + const SdrLayerAdmin& rLayerAdmin = GetDocSh()->GetDoc()->GetLayerAdmin(); + SdrLayerIDSet aSdrLayerIDSet; + rLayerAdmin.getVisibleLayersODF( aSdrLayerIDSet ); + mpFrameView -> SetVisibleLayers( aSdrLayerIDSet ); + rLayerAdmin.getPrintableLayersODF( aSdrLayerIDSet ); + mpFrameView -> SetPrintableLayers( aSdrLayerIDSet ); + rLayerAdmin.getLockedLayersODF( aSdrLayerIDSet ); + mpFrameView -> SetLockedLayers( aSdrLayerIDSet ); + } + else + { + // tdf#129898 repair layer "DrawnInSlideshow", which was wrongly written + // in LO 6.2 to 6.4. The ODF defaults were corrected when reading draw:layer-set, but + // not in reading config settings, because there the name is not known. + const SdrLayerAdmin& rLayerAdmin = GetDocSh()->GetDoc()->GetLayerAdmin(); + if (rLayerAdmin.GetLayer("DrawnInSlideshow")) + { + SdrLayerIDSet aSdrLayerIDSet; + rLayerAdmin.getVisibleLayersODF( aSdrLayerIDSet ); + mpFrameView -> SetVisibleLayers( aSdrLayerIDSet ); + rLayerAdmin.getPrintableLayersODF( aSdrLayerIDSet ); + mpFrameView -> SetPrintableLayers( aSdrLayerIDSet ); + rLayerAdmin.getLockedLayersODF( aSdrLayerIDSet ); + mpFrameView -> SetLockedLayers( aSdrLayerIDSet ); + } + } + + + if( mpFrameView->GetPageKind() != mePageKind ) + { + mePageKind = mpFrameView->GetPageKind(); + + if (mePageKind == PageKind::Notes) + { + GetActiveWindow()->SetHelpId( CMD_SID_NOTES_MODE ); + } + else if (mePageKind == PageKind::Handout) + { + GetActiveWindow()->SetHelpId( CMD_SID_HANDOUT_MASTER_MODE ); + } + else + { + GetActiveWindow()->SetHelpId( HID_SDDRAWVIEWSHELL ); + } + } + + ReadFrameViewData( mpFrameView ); + + if( !mbZoomOnPage ) + { + const ::tools::Rectangle aVisArea( mpFrameView->GetVisArea() ); + + // tdf#151621 Do not set if the embedded object is opening in a new window. + if (GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED + && GetDocSh()->IsInPlaceActive()) + { + GetDocSh()->SetVisArea(aVisArea); + } + + VisAreaChanged(aVisArea); + + ::sd::View* pView = GetView(); + + if (pView) + { + pView->VisAreaChanged(GetActiveWindow()->GetOutDev()); + } + + SetZoomRect(aVisArea); + } + ChangeEditMode (meEditMode, ! IsLayerModeActive()); + ResetActualLayer(); +} + +void DrawViewShell::VisAreaChanged(const ::tools::Rectangle& rRect) +{ + ViewShell::VisAreaChanged( rRect ); + + DrawController& rController = *GetViewShellBase().GetDrawController(); + rController.FireVisAreaChanged (rRect); +} + +/** If there is a valid controller then create a new instance of + <type>AccessibleDrawDocumentView</type>. Otherwise return an empty + reference. +*/ +css::uno::Reference<css::accessibility::XAccessible> + DrawViewShell::CreateAccessibleDocumentView (::sd::Window* pWindow) +{ + if (GetViewShellBase().GetController() != nullptr) + { + rtl::Reference<accessibility::AccessibleDrawDocumentView> pDocumentView = + new accessibility::AccessibleDrawDocumentView ( + pWindow, + this, + GetViewShellBase().GetController(), + pWindow->GetAccessibleParentWindow()->GetAccessible()); + pDocumentView->Init(); + return pDocumentView; + } + + SAL_WARN("sd", "DrawViewShell::CreateAccessibleDocumentView: no controller"); + return css::uno::Reference< css::accessibility::XAccessible>(); +} + +int DrawViewShell::GetActiveTabLayerIndex() const +{ + const LayerTabBar* pBar + = const_cast<DrawViewShell*>(this)->GetLayerTabControl (); + if (pBar != nullptr) + return pBar->GetPagePos (pBar->GetCurPageId()); + else + return -1; +} + +void DrawViewShell::SetActiveTabLayerIndex (int nIndex) +{ + LayerTabBar* pBar = GetLayerTabControl (); + if (pBar == nullptr) + return; + + // Ignore invalid indices silently. + if (nIndex>=0 && nIndex<pBar->GetPageCount()) + { + // Tell the draw view and the tab control of the new active layer. + mpDrawView->SetActiveLayer (pBar->GetLayerName (pBar->GetPageId (static_cast<sal_uInt16>(nIndex)))); + pBar->SetCurPageId (pBar->GetPageId (static_cast<sal_uInt16>(nIndex))); + rtl::Reference<SdUnoDrawView> pUnoDrawView(new SdUnoDrawView ( + *this, + *GetView())); + css::uno::Reference< css::drawing::XLayer> rLayer = pUnoDrawView->getActiveLayer(); + GetViewShellBase().GetDrawController()->fireChangeLayer( &rLayer ); + } +} + +LayerTabBar* DrawViewShell::GetLayerTabControl() +{ + return mpLayerTabBar.get(); +} + +int DrawViewShell::GetTabLayerCount() const +{ + const LayerTabBar* pBar + = const_cast<DrawViewShell*>(this)->GetLayerTabControl (); + if (pBar != nullptr) + return pBar->GetPageCount(); + else + return 0; +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews6.cxx b/sd/source/ui/view/drviews6.cxx new file mode 100644 index 0000000000..e02b54f488 --- /dev/null +++ b/sd/source/ui/view/drviews6.cxx @@ -0,0 +1,337 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <DrawViewShell.hxx> +#include <sfx2/request.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/svdograf.hxx> +#include <svx/svxids.hrc> +#include <svx/fontwork.hxx> +#include <svx/bmpmask.hxx> +#include <svx/imapdlg.hxx> +#include <svx/SvxColorChildWindow.hxx> +#include <svx/f3dchild.hxx> +#include <avmedia/mediaplayer.hxx> +#include <svl/intitem.hxx> + +#include <app.hrc> +#include <strings.hrc> + +#include <animobjs.hxx> +#include <AnimationChildWindow.hxx> +#include <sdresid.hxx> +#include <drawdoc.hxx> +#include <drawview.hxx> +#include <svx/svdoashp.hxx> + +namespace sd { + +/** + * handle SfxRequests for FontWork + */ +void DrawViewShell::ExecFormText(SfxRequest& rReq) +{ + // nothing is executed during a slide show! + if(HasCurrentFunction(SID_PRESENTATION)) + return; + + CheckLineTo (rReq); + + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + + if ( rMarkList.GetMarkCount() == 1 && rReq.GetArgs() && + !mpDrawView->IsPresObjSelected() ) + { + const SfxItemSet& rSet = *rReq.GetArgs(); + + if ( mpDrawView->IsTextEdit() ) + mpDrawView->SdrEndTextEdit(); + + mpDrawView->SetAttributes(rSet); + } +} + +/** + * Return state values for FontWork + */ +void DrawViewShell::GetFormTextState(SfxItemSet& rSet) +{ + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const SdrObject* pObj = nullptr; + + if ( rMarkList.GetMarkCount() == 1 ) + pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); + + const SdrTextObj* pTextObj = DynCastSdrTextObj(pObj); + const bool bDeactivate( + !pObj || + !pTextObj || + !pTextObj->HasText() || + dynamic_cast< const SdrObjCustomShape* >(pObj)); // #121538# no FontWork for CustomShapes + + if(bDeactivate) + { +// automatic open/close the FontWork-Dialog; first deactivate it + + rSet.DisableItem(XATTR_FORMTXTSTYLE); + rSet.DisableItem(XATTR_FORMTXTADJUST); + rSet.DisableItem(XATTR_FORMTXTDISTANCE); + rSet.DisableItem(XATTR_FORMTXTSTART); + rSet.DisableItem(XATTR_FORMTXTMIRROR); + rSet.DisableItem(XATTR_FORMTXTHIDEFORM); + rSet.DisableItem(XATTR_FORMTXTOUTLINE); + rSet.DisableItem(XATTR_FORMTXTSHADOW); + rSet.DisableItem(XATTR_FORMTXTSHDWCOLOR); + rSet.DisableItem(XATTR_FORMTXTSHDWXVAL); + rSet.DisableItem(XATTR_FORMTXTSHDWYVAL); + } + else + { + SfxItemSet aSet( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aSet ); + rSet.Set( aSet ); + } +} + +void DrawViewShell::ExecAnimationWin( SfxRequest& rReq ) +{ + // nothing is executed during a slide show! + if (HasCurrentFunction(SID_PRESENTATION)) + return; + + CheckLineTo (rReq); + + sal_uInt16 nSId = rReq.GetSlot(); + + switch( nSId ) + { + case SID_ANIMATOR_INIT: + case SID_ANIMATOR_ADD: + case SID_ANIMATOR_CREATE: + { + AnimationWindow* pAnimWin; + sal_uInt16 nId = AnimationChildWindow::GetChildWindowId(); + + SfxChildWindow* pWnd = GetViewFrame()->GetChildWindow(nId); + + pAnimWin = pWnd ? static_cast<AnimationWindow*>(pWnd->GetWindow()) : nullptr; + + if ( pAnimWin ) + { + if( nSId == SID_ANIMATOR_ADD ) + pAnimWin->AddObj( *mpDrawView ); + else if( nSId == SID_ANIMATOR_CREATE ) + pAnimWin->CreateAnimObj( *mpDrawView ); + } + } + break; + + default: + break; + } +} + +/** + * Return status values for animator + * + * nValue == 0 -> No button + * nValue == 1 -> Button 'accept' + * nValue == 2 -> Button 'accept individually' + * nValue == 3 -> Buttons 'accept' and 'accept individually' + */ +void DrawViewShell::GetAnimationWinState( SfxItemSet& rSet ) +{ + // here we could disable buttons etc. + sal_uInt16 nValue; + + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const size_t nMarkCount = rMarkList.GetMarkCount(); + + if( nMarkCount == 0 ) + nValue = 0; + else if( nMarkCount > 1 ) + nValue = 3; + else // 1 Object + { + const SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); + SdrInventor nInv = pObj->GetObjInventor(); + SdrObjKind nId = pObj->GetObjIdentifier(); + // 1 selected group object + if( nInv == SdrInventor::Default && nId == SdrObjKind::Group ) + nValue = 3; + else if( nInv == SdrInventor::Default && nId == SdrObjKind::Graphic ) // Animated GIF ? + { + sal_uInt16 nCount = 0; + + if( static_cast<const SdrGrafObj*>(pObj)->IsAnimated() ) + nCount = static_cast<const SdrGrafObj*>(pObj)->GetGraphic().GetAnimation().Count(); + if( nCount > 0 ) + nValue = 2; + else + nValue = 1; + } + else + nValue = 1; + } + rSet.Put( SfxUInt16Item( SID_ANIMATOR_STATE, nValue ) ); +} + +void DrawViewShell::SetChildWindowState( SfxItemSet& rSet ) +{ + // State of SfxChild-Windows (Animator, Fontwork etc.) + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_FONTWORK ) ) + { + sal_uInt16 nId = SvxFontWorkChildWindow::GetChildWindowId(); + rSet.Put(SfxBoolItem(SID_FONTWORK, GetViewFrame()->HasChildWindow(nId))); + } + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_COLOR_CONTROL ) ) + { + sal_uInt16 nId = SvxColorChildWindow::GetChildWindowId(); + rSet.Put(SfxBoolItem(SID_COLOR_CONTROL, GetViewFrame()->HasChildWindow(nId))); + } + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ANIMATION_OBJECTS ) ) + { + sal_uInt16 nId = AnimationChildWindow::GetChildWindowId(); + rSet.Put( SfxBoolItem( SID_ANIMATION_OBJECTS, GetViewFrame()->HasChildWindow( nId ) ) ); + } + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_NAVIGATOR ) ) + { + rSet.Put( SfxBoolItem( SID_NAVIGATOR, GetViewFrame()->HasChildWindow( SID_NAVIGATOR ) ) ); + } + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_BMPMASK ) ) + { + sal_uInt16 nId = SvxBmpMaskChildWindow::GetChildWindowId(); + rSet.Put( SfxBoolItem( SID_BMPMASK, GetViewFrame()->HasChildWindow( nId ) ) ); + } + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_IMAP ) ) + { + sal_uInt16 nId = SvxIMapDlgChildWindow::GetChildWindowId(); + rSet.Put( SfxBoolItem( SID_IMAP, GetViewFrame()->HasChildWindow( nId ) ) ); + } + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_3D_WIN ) ) + { + sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId(); + rSet.Put( SfxBoolItem( SID_3D_WIN, GetViewFrame()->HasChildWindow( nId ) ) ); + } +#if HAVE_FEATURE_AVMEDIA + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_AVMEDIA_PLAYER ) ) + { + sal_uInt16 nId = ::avmedia::MediaPlayer::GetChildWindowId(); + rSet.Put( SfxBoolItem( SID_AVMEDIA_PLAYER, GetViewFrame()->HasChildWindow( nId ) ) ); + } +#endif +} + +/** + * Handle SfxRequests for pipette + */ +void DrawViewShell::ExecBmpMask( SfxRequest const & rReq ) +{ + // nothing is executed during a slide show! + if (HasCurrentFunction(SID_PRESENTATION)) + return; + + switch ( rReq.GetSlot() ) + { + case SID_BMPMASK_PIPETTE : + { + mbPipette = rReq.GetArgs()->Get( SID_BMPMASK_PIPETTE ).GetValue(); + } + break; + + case SID_BMPMASK_EXEC : + { + SdrGrafObj* pObj = nullptr; + if( mpDrawView && mpDrawView->GetMarkedObjectList().GetMarkCount() ) + pObj = dynamic_cast< SdrGrafObj* >( mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj() ); + + if ( pObj && !mpDrawView->IsTextEdit() ) + { + rtl::Reference<SdrGrafObj> xNewObj(SdrObject::Clone(*pObj, pObj->getSdrModelFromSdrObject())); + bool bCont = true; + + if (xNewObj->IsLinkedGraphic()) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "modules/sdraw/ui/queryunlinkimagedialog.ui")); + std::unique_ptr<weld::MessageDialog> xQueryBox(xBuilder->weld_message_dialog("QueryUnlinkImageDialog")); + + if (RET_YES == xQueryBox->run()) + xNewObj->ReleaseGraphicLink(); + else + bCont = false; + } + + SfxChildWindow* pWnd = GetViewFrame()->GetChildWindow( + SvxBmpMaskChildWindow::GetChildWindowId()); + SvxBmpMask* pBmpMask = pWnd ? static_cast<SvxBmpMask*>(pWnd->GetWindow()) : nullptr; + assert(pBmpMask); + if (bCont && pBmpMask) + { + const Graphic& rOldGraphic = xNewObj->GetGraphic(); + const Graphic aNewGraphic(pBmpMask->Mask(rOldGraphic)); + + if( aNewGraphic != rOldGraphic ) + { + SdrPageView* pPV = mpDrawView->GetSdrPageView(); + + xNewObj->SetEmptyPresObj(false); + xNewObj->SetGraphic(pBmpMask->Mask(xNewObj->GetGraphic())); + + OUString aStr = mpDrawView->GetDescriptionOfMarkedObjects() + + " " + SdResId(STR_EYEDROPPER); + + mpDrawView->BegUndo( aStr ); + mpDrawView->ReplaceObjectAtView(pObj, *pPV, xNewObj.get()); + mpDrawView->EndUndo(); + } + } + } + } + break; + + default: + break; + } +} + +void DrawViewShell::GetBmpMaskState( SfxItemSet& rSet ) +{ + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const SdrObject* pObj = nullptr; + bool bEnable = false; + + if ( rMarkList.GetMarkCount() == 1 ) + pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); + + // valid graphic object? + if( auto pGrafObj = dynamic_cast< const SdrGrafObj *>( pObj ) ) + if (!pGrafObj->IsEPS() && !mpDrawView->IsTextEdit() ) + bEnable = true; + + // put value + rSet.Put( SfxBoolItem( SID_BMPMASK_EXEC, bEnable ) ); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews7.cxx b/sd/source/ui/view/drviews7.cxx new file mode 100644 index 0000000000..845bc956ed --- /dev/null +++ b/sd/source/ui/view/drviews7.cxx @@ -0,0 +1,1974 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> + +#include <sal/config.h> +#include <sal/log.hxx> + +#include <utility> + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/linguistic2/XThesaurus.hpp> +#include <svx/pageitem.hxx> +#include <svx/rulritem.hxx> +#include <svx/svdouno.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/sizeitem.hxx> +#include <editeng/urlfieldhelper.hxx> +#include <officecfg/Office/Impress.hxx> +#include <officecfg/Office/Security.hxx> +#include <svx/svxids.hrc> +#include <svx/svdpagv.hxx> +#include <svx/clipfmtitem.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/itemset.hxx> +#include <svl/stritem.hxx> +#include <svl/visitem.hxx> +#include <svl/whiter.hxx> +#include <svx/svdograf.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xflclit.hxx> +#include <svx/xflgrit.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xbtmpit.hxx> +#include <editeng/unolingu.hxx> +#include <svx/extrusionbar.hxx> +#include <svx/fontworkbar.hxx> + +// #UndoRedo# +#include <svtools/insdlg.hxx> +#include <unotools/moduleoptions.hxx> +#include <svl/cjkoptions.hxx> +#include <comphelper/processfactory.hxx> +#include <sfx2/request.hxx> + +#include <svtools/cliplistener.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/viewfrm.hxx> + +#include <app.hrc> + +#include <PresentationViewShell.hxx> + +#include <drawdoc.hxx> +#include <DrawViewShell.hxx> +#include <sdmod.hxx> +#include <unokywds.hxx> +#include <sdpage.hxx> +#include <DrawDocShell.hxx> +#include <zoomlist.hxx> +#include <slideshow.hxx> +#include <drawview.hxx> +#include <ViewShellBase.hxx> +#include <ViewShellManager.hxx> +#include <LayerTabBar.hxx> +#include <fupoor.hxx> +#include <Window.hxx> +#include <fuediglu.hxx> +#include <fubullet.hxx> +#include <fuconcs.hxx> +#include <fuformatpaintbrush.hxx> +#include <stlsheet.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::linguistic2; + +/** Create a list of clipboard formats that are supported both from the + current clipboard content and the DrawViewShell. + The list is stored in a new instance of SvxClipboardFormatItem. +*/ +static ::std::unique_ptr<SvxClipboardFormatItem> GetSupportedClipboardFormats ( + TransferableDataHelper& rDataHelper) +{ + ::std::unique_ptr<SvxClipboardFormatItem> pResult ( + new SvxClipboardFormatItem(SID_CLIPBOARD_FORMAT_ITEMS)); + + sal_uInt32 nFormatCount (rDataHelper.GetFormatCount()); + for (sal_uInt32 i=0; i<nFormatCount; i++) + { + const SotClipboardFormatId nTestFormat = rDataHelper.GetFormat(i); + + // Check if the current format is the same as one that has already + // been handled. + bool bDuplicate (false); + for (sal_uInt32 j=0; j<i; j++) + { + if (nTestFormat == rDataHelper.GetFormat(j)) + { + bDuplicate = true; + break; + } + } + + // Look up the format among those that are supported by the + // DrawViewShell. + if ( ! bDuplicate) + { + switch (nTestFormat) + { + case SotClipboardFormatId::EMBED_SOURCE: + { + OUString sName; + + TransferableObjectDescriptor aDescriptor; + if (rDataHelper.GetTransferableObjectDescriptor( + SotClipboardFormatId::OBJECTDESCRIPTOR, aDescriptor)) + { + sName = aDescriptor.maTypeName; + } + if (!sName.isEmpty()) + pResult->AddClipbrdFormat(nTestFormat, sName); + else + pResult->AddClipbrdFormat(nTestFormat); + + break; + } + + + case SotClipboardFormatId::LINK_SOURCE: + case SotClipboardFormatId::DRAWING: + case SotClipboardFormatId::SVXB: + case SotClipboardFormatId::GDIMETAFILE: + case SotClipboardFormatId::BITMAP: + case SotClipboardFormatId::NETSCAPE_BOOKMARK: + case SotClipboardFormatId::STRING: + case SotClipboardFormatId::HTML: + case SotClipboardFormatId::HTML_SIMPLE: + case SotClipboardFormatId::RTF: + case SotClipboardFormatId::RICHTEXT: + case SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT: + pResult->AddClipbrdFormat(nTestFormat); + break; + default: break; + } + } + } + + // Check some OLE formats whose names are handled differently. + SotClipboardFormatId nFormat (SotClipboardFormatId::EMBED_SOURCE_OLE); + bool bHasFormat (rDataHelper.HasFormat(nFormat)); + if ( ! bHasFormat) + { + bHasFormat = rDataHelper.HasFormat(nFormat); + } + if (bHasFormat) + { + OUString sName; + OUString sSource; + if (SvPasteObjectHelper::GetEmbeddedName (rDataHelper, sName, sSource, nFormat)) + pResult->AddClipbrdFormat (nFormat, sName); + } + + return pResult; +} + +namespace sd { + +IMPL_LINK( DrawViewShell, ClipboardChanged, TransferableDataHelper*, pDataHelper, void ) +{ + mbPastePossible = ( pDataHelper->GetFormatCount() != 0 ); + + // Update the list of supported clipboard formats according to the + // new clipboard content. + // There are some stack traces that indicate the possibility of the + // DrawViewShell destructor called during the call to + // GetSupportedClipboardFormats(). If that really has happened then + // exit immediately. + TransferableDataHelper aDataHelper ( + TransferableDataHelper::CreateFromSystemClipboard(GetActiveWindow())); + ::std::unique_ptr<SvxClipboardFormatItem> pFormats (GetSupportedClipboardFormats(aDataHelper)); + if (mpDrawView == nullptr) + return; + mpCurrentClipboardFormats = std::move(pFormats); + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_PASTE ); + rBindings.Invalidate( SID_PASTE_SPECIAL ); + rBindings.Invalidate( SID_PASTE_UNFORMATTED ); + rBindings.Invalidate( SID_CLIPBOARD_FORMAT_ITEMS ); +} + +void DrawViewShell::GetDrawAttrState(SfxItemSet& rSet) +{ + SfxItemSet aSet( mpDrawView->GetGeoAttrFromMarked() ); + rSet.Put(aSet,false); +} + +::Outliner* DrawViewShell::GetOutlinerForMasterPageOutlineTextObj(ESelection &rSel) +{ + if( !mpDrawView ) + return nullptr; + + //when there is one object selected + if (!mpDrawView->AreObjectsMarked() || (mpDrawView->GetMarkedObjectList().GetMarkCount() != 1)) + return nullptr; + + //and we are editing the outline object + if (!mpDrawView->IsTextEdit()) + return nullptr; + + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + if (!pPageView) + return nullptr; + + SdPage* pPage = static_cast<SdPage*>(pPageView->GetPage()); + //only show these in a normal master page + if (!pPage || (pPage->GetPageKind() != PageKind::Standard) || !pPage->IsMasterPage()) + return nullptr; + + OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView(); + ::Outliner* pOL = pOLV ? pOLV->GetOutliner() : nullptr; + if (!pOL) + return nullptr; + rSel = pOLV->GetSelection(); + + return pOL; +} + +void DrawViewShell::GetMarginProperties( SfxItemSet &rSet ) +{ + SdPage *pPage = getCurrentPage(); + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + while ( nWhich ) + { + switch ( nWhich ) + { + case SID_ATTR_PAGE_LRSPACE: + { + // const SvxLRSpaceItem aTmpPageLRSpace ( rDesc.GetMaster().GetLRSpace() ); + const SvxLongLRSpaceItem aLongLR( + static_cast<::tools::Long>(pPage->GetLeftBorder()), + static_cast<::tools::Long>(pPage->GetRightBorder()), + SID_ATTR_PAGE_LRSPACE ); + rSet.Put( aLongLR ); + } + break; + + case SID_ATTR_PAGE_ULSPACE: + { + // const SvxULSpaceItem aUL( rDesc.GetMaster().GetULSpace() ); + SvxLongULSpaceItem aLongUL( + static_cast<::tools::Long>(pPage->GetUpperBorder()), + static_cast<::tools::Long>(pPage->GetLowerBorder()), + SID_ATTR_PAGE_ULSPACE ); + rSet.Put( aLongUL ); + } + break; + + default: + break; + } + nWhich = aIter.NextWhich(); + } +} + +bool DrawViewShell::ShouldDisableEditHyperlink() const +{ + if (!mpDrawView) + return true; + if (!mpDrawView->AreObjectsMarked()) + return true; + if (mpDrawView->GetMarkedObjectList().GetMarkCount() != 1) + return true; + + bool bDisableEditHyperlink = true; + if( mpDrawView->IsTextEdit() ) + { + if (URLFieldHelper::IsCursorAtURLField(mpDrawView->GetTextEditOutlinerView(), + /*AlsoCheckBeforeCursor=*/true)) + bDisableEditHyperlink = false; + } + else + { + SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj() ); + + if ( pUnoCtrl && SdrInventor::FmForm == pUnoCtrl->GetObjInventor() ) + { + const uno::Reference< awt::XControlModel >& xControlModel( pUnoCtrl->GetUnoControlModel() ); + if( xControlModel.is() ) + { + uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + uno::Reference< beans::XPropertySetInfo > xPropInfo( xPropSet->getPropertySetInfo() ); + if( xPropInfo.is() && xPropInfo->hasPropertyByName( "TargetURL") ) + { + bDisableEditHyperlink = false; + } + } + } + } + } + return bDisableEditHyperlink; +} + +void DrawViewShell::GetMenuState( SfxItemSet &rSet ) +{ + if (mpDrawView == nullptr) + { + // This assertion and return are here to prevent crashes. + DBG_ASSERT(mpDrawView!=nullptr, "Please report this assertion to the Impress team."); + return; + } + + ViewShell::GetMenuState(rSet); + bool bDisableVerticalText = !SvtCJKOptions::IsVerticalTextEnabled(); + + if ( bDisableVerticalText ) + { + rSet.DisableItem( SID_DRAW_FONTWORK_VERTICAL ); + rSet.DisableItem( SID_DRAW_CAPTION_VERTICAL ); + rSet.DisableItem( SID_TEXT_FITTOSIZE_VERTICAL ); + rSet.DisableItem( SID_DRAW_TEXT_VERTICAL ); + } + + bool bConvertToPathPossible = mpDrawView->IsConvertToPathObjPossible(); + + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const size_t nMarkCount = rMarkList.GetMarkCount(); + + if( nMarkCount == 1 ) + { + bool bDisable = true; + SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); + if( auto pGrafObj = dynamic_cast<const SdrGrafObj*>( pObj) ) + if( pGrafObj->getQrCode() ) + bDisable = false; + if(bDisable) + { + rSet.DisableItem(SID_EDIT_QRCODE); + } + } + + //format paintbrush + FuFormatPaintBrush::GetMenuState( *this, rSet ); + + // State of SfxChild-Windows (Animator, Fontwork etc.) + SetChildWindowState( rSet ); + + if(HasCurrentFunction()) + { + sal_uInt16 nSId = GetCurrentFunction()->GetSlotID(); + rSet.Put( SfxBoolItem( nSId, true ) ); + } + + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + + GetMenuStateSel(rSet); + + if (SfxItemState::DEFAULT == rSet.GetItemState(SID_ASSIGN_LAYOUT)) + { + bool bDisable = true; + if( pPageView ) + { + SdPage* pPage = dynamic_cast< SdPage* >( pPageView->GetPage() ); + + if( pPage && !pPage->IsMasterPage() ) + { + rSet.Put( SfxUInt32Item( SID_ASSIGN_LAYOUT, static_cast< sal_uInt32 >(pPage->GetAutoLayout()) ) ); + bDisable = false; + } + } + + if(bDisable) + { + rSet.DisableItem(SID_ASSIGN_LAYOUT); + } + } + + if (SfxItemState::DEFAULT == rSet.GetItemState(SID_EXPAND_PAGE)) + { + bool bDisable = true; + if( pPageView ) + { + SdPage* pPage = dynamic_cast< SdPage* >( pPageView->GetPage() ); + + if( pPage && (pPage->GetPageKind() == PageKind::Standard) && !pPage->IsMasterPage() ) + { + SdrObject* pObj = pPage->GetPresObj(PresObjKind::Outline); + + if (pObj!=nullptr ) + { + if( !pObj->IsEmptyPresObj() ) + { + bDisable = false; + } + else + { + // check if the object is in edit, then if it's temporarily not empty + SdrTextObj* pTextObj = DynCastSdrTextObj( pObj ); + if( pTextObj ) + { + if( pTextObj->CanCreateEditOutlinerParaObject() ) + { + bDisable = false; + } + } + } + } + } + } + + if(bDisable) + { + rSet.DisableItem(SID_EXPAND_PAGE); + } + } + + if (SfxItemState::DEFAULT == rSet.GetItemState(SID_SUMMARY_PAGE)) + { + bool bDisable = true; + if( pPageView ) + { + SdPage* pPage = dynamic_cast< SdPage* >( pPageView->GetPage() ); + + if( pPage && (pPage->GetPageKind() == PageKind::Standard) && !pPage->IsMasterPage() ) + { + SdrObject* pObj = pPage->GetPresObj(PresObjKind::Title); + + if(pObj && !pObj->IsEmptyPresObj()) + { + bDisable = false; + } + } + } + + if(bDisable) + { + rSet.DisableItem(SID_SUMMARY_PAGE); + } + } + + if (SfxItemState::DEFAULT == rSet.GetItemState(SID_ASSIGN_LAYOUT)) + { + bool bDisable = true; + if( pPageView ) + { + SdPage* pPage = dynamic_cast< SdPage* >( pPageView->GetPage() ); + + if( pPage && !pPage->IsMasterPage() ) + { + rSet.Put( SfxUInt32Item(SID_ASSIGN_LAYOUT, pPage->GetAutoLayout()) ); + bDisable = false; + } + } + + if(bDisable) + { + rSet.DisableItem(SID_ASSIGN_LAYOUT); + } + } + + // is it possible to start the presentation? + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PRESENTATION ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_REHEARSE_TIMINGS ) ) + { + bool bDisable = true; + sal_uInt16 nCount = GetDoc()->GetSdPageCount( PageKind::Standard ); + + for( sal_uInt16 i = 0; i < nCount && bDisable; i++ ) + { + SdPage* pPage = GetDoc()->GetSdPage(i, PageKind::Standard); + + if( !pPage->IsExcluded() ) + bDisable = false; + } + + if( bDisable || GetDocSh()->IsPreview()) + { + rSet.DisableItem( SID_PRESENTATION ); + rSet.DisableItem( SID_REHEARSE_TIMINGS ); + } + } + + // gluepoints + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_EDITMODE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_INSERT_POINT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_PERCENT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR_LEFT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR_RIGHT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR_TOP ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_ESCDIR_BOTTOM ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_HORZALIGN_CENTER ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_HORZALIGN_LEFT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_HORZALIGN_RIGHT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_VERTALIGN_CENTER ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_VERTALIGN_TOP ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_GLUE_VERTALIGN_BOTTOM ) ) + { + // percent + TriState eState = mpDrawView->IsMarkedGluePointsPercent(); + if( eState == TRISTATE_INDET ) + rSet.InvalidateItem( SID_GLUE_PERCENT ); + else + rSet.Put( SfxBoolItem( SID_GLUE_PERCENT, eState == TRISTATE_TRUE ) ); + + // alignment has no effect by percent + if( eState == TRISTATE_TRUE ) + { + rSet.DisableItem( SID_GLUE_HORZALIGN_CENTER ); + rSet.DisableItem( SID_GLUE_HORZALIGN_LEFT ); + rSet.DisableItem( SID_GLUE_HORZALIGN_RIGHT ); + rSet.DisableItem( SID_GLUE_VERTALIGN_CENTER ); + rSet.DisableItem( SID_GLUE_VERTALIGN_TOP ); + rSet.DisableItem( SID_GLUE_VERTALIGN_BOTTOM ); + } + else + { + // horizontal alignment + SdrAlign nHorz = mpDrawView->GetMarkedGluePointsAlign( false ); + rSet.Put( SfxBoolItem( SID_GLUE_HORZALIGN_CENTER, nHorz == SdrAlign::HORZ_CENTER ) ); + rSet.Put( SfxBoolItem( SID_GLUE_HORZALIGN_LEFT, nHorz == SdrAlign::HORZ_LEFT ) ); + rSet.Put( SfxBoolItem( SID_GLUE_HORZALIGN_RIGHT, nHorz == SdrAlign::HORZ_RIGHT ) ); + // vertical alignment + SdrAlign nVert = mpDrawView->GetMarkedGluePointsAlign( true ); + rSet.Put( SfxBoolItem( SID_GLUE_VERTALIGN_CENTER, nVert == SdrAlign::VERT_CENTER ) ); + rSet.Put( SfxBoolItem( SID_GLUE_VERTALIGN_TOP, nVert == SdrAlign::VERT_TOP ) ); + rSet.Put( SfxBoolItem( SID_GLUE_VERTALIGN_BOTTOM, nVert == SdrAlign::VERT_BOTTOM ) ); + } + + // insert point + rSet.Put( SfxBoolItem( SID_GLUE_INSERT_POINT, mpDrawView->IsInsGluePointMode() ) ); + + // Escape direction + // left + eState = mpDrawView->IsMarkedGluePointsEscDir( SdrEscapeDirection::LEFT ); + if( eState == TRISTATE_INDET ) + rSet.InvalidateItem( SID_GLUE_ESCDIR_LEFT ); + else + rSet.Put( SfxBoolItem( SID_GLUE_ESCDIR_LEFT, eState == TRISTATE_TRUE ) ); + // right + eState = mpDrawView->IsMarkedGluePointsEscDir( SdrEscapeDirection::RIGHT ); + if( eState == TRISTATE_INDET ) + rSet.InvalidateItem( SID_GLUE_ESCDIR_RIGHT ); + else + rSet.Put( SfxBoolItem( SID_GLUE_ESCDIR_RIGHT, eState == TRISTATE_TRUE ) ); + // top + eState = mpDrawView->IsMarkedGluePointsEscDir( SdrEscapeDirection::TOP ); + if( eState == TRISTATE_INDET ) + rSet.InvalidateItem( SID_GLUE_ESCDIR_TOP ); + else + rSet.Put( SfxBoolItem( SID_GLUE_ESCDIR_TOP, eState == TRISTATE_TRUE ) ); + // bottom + eState = mpDrawView->IsMarkedGluePointsEscDir( SdrEscapeDirection::BOTTOM ); + if( eState == TRISTATE_INDET ) + rSet.InvalidateItem( SID_GLUE_ESCDIR_BOTTOM ); + else + rSet.Put( SfxBoolItem( SID_GLUE_ESCDIR_BOTTOM, eState == TRISTATE_TRUE ) ); + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_GRID_FRONT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_HELPLINES_FRONT ) ) + { + rSet.Put( SfxBoolItem( SID_GRID_FRONT, mpDrawView->IsGridFront() ) ); + rSet.Put( SfxBoolItem( SID_HELPLINES_FRONT, mpDrawView->IsHlplFront() ) ); + } + + if (!mpDrawView->IsFrameDragSingles()) + rSet.Put(SfxBoolItem(SID_BEZIER_EDIT, true)); + else + rSet.Put(SfxBoolItem(SID_BEZIER_EDIT, false)); + + if(dynamic_cast<FuEditGluePoints*>( GetCurrentFunction().get())) + rSet.Put(SfxBoolItem(SID_GLUE_EDITMODE, true)); + else + rSet.Put(SfxBoolItem(SID_GLUE_EDITMODE, false)); + + if( !mpDrawView->IsMirrorAllowed( true, true ) ) + { + rSet.DisableItem( SID_HORIZONTAL ); + rSet.DisableItem( SID_VERTICAL ); + rSet.DisableItem( SID_FLIP_HORIZONTAL ); + rSet.DisableItem( SID_FLIP_VERTICAL ); + } + + if( !mpDrawView->IsMirrorAllowed() ) + { + rSet.DisableItem( SID_OBJECT_MIRROR ); +// rSet.DisableItem( SID_CONVERT_TO_3D_LATHE ); +// rSet.DisableItem( SID_CONVERT_TO_3D_LATHE_FAST ); + } + + // interactive transparence control + if(!mpDrawView->IsTransparenceAllowed()) + { + rSet.DisableItem( SID_OBJECT_TRANSPARENCE ); + } + + // interactive gradient control + if(!mpDrawView->IsGradientAllowed()) + { + rSet.DisableItem( SID_OBJECT_GRADIENT ); + } + + // disable morphing if necessary + if ( !mpDrawView->IsMorphingAllowed() ) + rSet.DisableItem( SID_POLYGON_MORPHING ); + + if( !mpDrawView->IsReverseOrderPossible() ) + { + rSet.DisableItem( SID_REVERSE_ORDER ); + } + + if ( !bConvertToPathPossible && + !mpDrawView->IsCrookAllowed( mpDrawView->IsCrookNoContortion() ) ) + { + // implicit transformation into curve not possible + rSet.DisableItem(SID_OBJECT_CROOK_ROTATE); + rSet.DisableItem(SID_OBJECT_CROOK_SLANT); + rSet.DisableItem(SID_OBJECT_CROOK_STRETCH); + } + + if ( !mpDrawView->IsGroupEntered() ) + { + rSet.DisableItem( SID_LEAVE_GROUP ); + rSet.Put( SfxBoolItem( SID_LEAVE_ALL_GROUPS, false ) ); + rSet.ClearItem( SID_LEAVE_ALL_GROUPS ); + rSet.DisableItem( SID_LEAVE_ALL_GROUPS ); + } + else + rSet.Put( SfxBoolItem( SID_LEAVE_ALL_GROUPS, true ) ); + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_THESAURUS ) ) + { + if ( !mpDrawView->IsTextEdit() ) + { + rSet.DisableItem( SID_THESAURUS ); + } + else + { + LanguageType eLang = GetDoc()->GetLanguage( EE_CHAR_LANGUAGE ); + Reference< XThesaurus > xThesaurus( LinguMgr::GetThesaurus() ); + + if (!xThesaurus.is() || eLang == LANGUAGE_NONE || !xThesaurus->hasLocale( LanguageTag::convertToLocale( eLang)) ) + rSet.DisableItem( SID_THESAURUS ); + } + } + + if ( !mpDrawView->IsTextEdit() ) + { + rSet.DisableItem( SID_THESAURUS ); + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_SELECTALL ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_SIZE_ALL ) ) + { + if( pPageView && pPageView->GetObjList()->GetObjCount() == 0 ) + { + // should be disabled if there is no object on the draw area: + rSet.DisableItem( SID_SELECTALL ); + rSet.DisableItem( SID_SIZE_ALL ); + } + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_CONTEXT ) ) + rSet.Put( SfxStringItem( SID_CONTEXT, mpDrawView->GetStatusText() ) ); + + // clipboard (paste) + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PASTE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_PASTE_SPECIAL ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_PASTE_UNFORMATTED ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_CLIPBOARD_FORMAT_ITEMS ) ) + { + if ( !mxClipEvtLstnr.is() ) + { + // avoid clipboard initialization for + // read-only presentation views (workaround for NT4.0 + // clipboard prob...) + if( dynamic_cast< const PresentationViewShell *>( this ) == nullptr ) + { + // create listener + mxClipEvtLstnr = new TransferableClipboardListener( LINK( this, DrawViewShell, ClipboardChanged ) ); + mxClipEvtLstnr->AddListener( GetActiveWindow() ); + + // get initial state + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) ); + mbPastePossible = ( aDataHelper.GetFormatCount() != 0 ); + mpCurrentClipboardFormats = GetSupportedClipboardFormats( aDataHelper ); + } + else + mbPastePossible = false; + } + + if( !mbPastePossible ) + { + rSet.DisableItem( SID_PASTE ); + rSet.DisableItem( SID_PASTE_SPECIAL ); + rSet.DisableItem( SID_PASTE_UNFORMATTED ); + rSet.DisableItem( SID_CLIPBOARD_FORMAT_ITEMS ); + } + else if( SfxItemState::DEFAULT == rSet.GetItemState( SID_CLIPBOARD_FORMAT_ITEMS ) ) + { + if (mpCurrentClipboardFormats != nullptr) + rSet.Put(*mpCurrentClipboardFormats); + } + } + + if ( !bConvertToPathPossible ) + { + rSet.DisableItem(SID_CHANGEBEZIER); + } + + if (mpDrawView == nullptr) + { + // The mpDrawView was not NULL but is now. + // The reason for this may be that the DrawViewShell has been + // destroyed in the meantime. + // We can only return immediately and hope that the deleted + // DrawViewShell is not called again. + DBG_ASSERT(mpDrawView!=nullptr, "Please report this assertion to the Impress team."); + return; + } + + if( !( mpDrawView->IsConvertToPolyObjPossible() || mpDrawView->IsVectorizeAllowed() ) ) + rSet.DisableItem(SID_CHANGEPOLYGON); + + if( !( mpDrawView->IsConvertToPolyObjPossible() || mpDrawView->IsConvertToContourPossible() ) ) + rSet.DisableItem(SID_CONVERT_TO_CONTOUR); + + if ( !mpDrawView->IsConvertTo3DObjPossible() ) + { + rSet.DisableItem(SID_CONVERT_TO_3D); + rSet.DisableItem(SID_CONVERT_TO_3D_LATHE); + rSet.DisableItem(SID_CONVERT_TO_3D_LATHE_FAST); + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_MANAGE_LINKS ) ) + { + if ( GetDoc()->GetLinkCount() == 0 ) + { + rSet.DisableItem(SID_MANAGE_LINKS); + } + } + + if (mePageKind == PageKind::Handout) + { + rSet.DisableItem(SID_PRESENTATION_LAYOUT); + rSet.DisableItem(SID_SELECT_BACKGROUND); + rSet.DisableItem(SID_SAVE_BACKGROUND); + } + + if (mePageKind == PageKind::Notes) + { + rSet.DisableItem(SID_INSERTPAGE); + rSet.DisableItem(SID_RENAMEPAGE); + rSet.DisableItem(SID_RENAMEPAGE_QUICK); + rSet.DisableItem(SID_DUPLICATE_PAGE); + rSet.ClearItem(SID_ANIMATION_OBJECTS); + rSet.DisableItem(SID_ANIMATION_OBJECTS); + rSet.DisableItem(SID_ANIMATION_EFFECTS); + rSet.DisableItem(SID_EXECUTE_ANIMATION_EFFECT); + + if (meEditMode == EditMode::MasterPage) + rSet.DisableItem(SID_MODIFYPAGE); + + rSet.DisableItem(SID_SELECT_BACKGROUND); + rSet.DisableItem(SID_SAVE_BACKGROUND); + rSet.DisableItem(SID_INSERTLAYER); + rSet.DisableItem(SID_LAYERMODE); + rSet.DisableItem(SID_INSERTFILE); + } + else if (mePageKind == PageKind::Handout) + { + rSet.DisableItem(SID_INSERTPAGE); + rSet.DisableItem(SID_DUPLICATE_PAGE); + rSet.ClearItem(SID_ANIMATION_OBJECTS); + rSet.DisableItem(SID_ANIMATION_OBJECTS); + rSet.DisableItem(SID_ANIMATION_EFFECTS); + rSet.DisableItem(SID_EXECUTE_ANIMATION_EFFECT); + rSet.DisableItem(SID_RENAMEPAGE); + rSet.DisableItem(SID_RENAMEPAGE_QUICK); + rSet.DisableItem(SID_INSERTLAYER); + rSet.DisableItem(SID_MODIFYLAYER); + rSet.DisableItem(SID_TOGGLELAYERVISIBILITY); + rSet.DisableItem(SID_RENAMELAYER); + rSet.DisableItem(SID_LAYERMODE); + rSet.DisableItem(SID_INSERTFILE); + rSet.DisableItem(SID_PAGEMODE); + rSet.DisableItem(SID_SELECT_BACKGROUND); + rSet.DisableItem(SID_SAVE_BACKGROUND); + } + else + { + if (meEditMode == EditMode::MasterPage) + { + rSet.DisableItem(SID_INSERTPAGE); + rSet.DisableItem(SID_DUPLICATE_PAGE); + rSet.DisableItem(SID_MODIFYPAGE); + rSet.ClearItem(SID_ANIMATION_OBJECTS); + rSet.DisableItem(SID_ANIMATION_OBJECTS); + } + + rSet.Put (SfxBoolItem (SID_LAYERMODE, IsLayerModeActive())); + } + + if ( ! IsLayerModeActive()) + { + rSet.DisableItem( SID_INSERTLAYER ); + rSet.DisableItem( SID_MODIFYLAYER ); + rSet.DisableItem( SID_TOGGLELAYERVISIBILITY ); + rSet.DisableItem( SID_DELETE_LAYER ); + rSet.DisableItem( SID_RENAMELAYER ); + } + + if (meEditMode == EditMode::Page) + { + /********************************************************************** + * page mode + **********************************************************************/ + rSet.Put(SfxBoolItem(SID_PAGEMODE, true)); + rSet.Put(SfxBoolItem(SID_MASTERPAGE, false)); + rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false)); + + rSet.DisableItem (SID_INSERT_MASTER_PAGE); + rSet.DisableItem (SID_DELETE_MASTER_PAGE); + rSet.DisableItem (SID_RENAME_MASTER_PAGE); + rSet.DisableItem (SID_CLOSE_MASTER_VIEW); + } + else + { + rSet.Put(SfxBoolItem(SID_PAGEMODE, false)); + rSet.Put(SfxBoolItem(SID_MASTERPAGE, true)); + + /********************************************************************** + * Background page mode + **********************************************************************/ + if (mePageKind == PageKind::Standard) + { + rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, true)); + rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false)); + + } + else if (mePageKind == PageKind::Notes) + { + rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, true)); + rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false)); + } + else if (mePageKind == PageKind::Handout) + { + rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, true)); + } + } + + // set state of the ruler + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_RULER ) ) + rSet.Put( SfxBoolItem( SID_RULER, HasRuler() ) ); + + // do not delete the last page or a master page + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_DELETE_PAGE ) + || SfxItemState::DEFAULT == rSet.GetItemState( SID_DELETE_MASTER_PAGE ) ) + { + if (maTabControl->GetPageCount() == 1 || + meEditMode == EditMode::MasterPage || + mePageKind == PageKind::Notes || + mePageKind == PageKind::Handout || + (GetShellType()!=ST_DRAW&&IsLayerModeActive())) + { + if (rSet.GetItemState(SID_DELETE_PAGE) == SfxItemState::DEFAULT) + rSet.DisableItem(SID_DELETE_PAGE); + if (rSet.GetItemState(SID_DELETE_MASTER_PAGE)==SfxItemState::DEFAULT) + rSet.DisableItem(SID_DELETE_MASTER_PAGE); + } + } + + // is it allowed to delete the current layer? + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_DELETE_LAYER ) + || SfxItemState::DEFAULT == rSet.GetItemState( SID_RENAMELAYER ) ) + { + if(GetLayerTabControl()) // #i87182# + { + sal_uInt16 nCurrentLayer = GetLayerTabControl()->GetCurPageId(); + const OUString& rName = GetLayerTabControl()->GetLayerName(nCurrentLayer); + + if (!IsLayerModeActive() || LayerTabBar::IsRealNameOfStandardLayer(rName)) + { + rSet.DisableItem(SID_DELETE_LAYER); + rSet.DisableItem(SID_RENAMELAYER); + } + } + else + { + OSL_ENSURE(false, "No LayerTabBar (!)"); + } + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_CUT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_COPY ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTLINE_BULLET )) + { + OutlinerView* pOlView = mpDrawView->GetTextEditOutlinerView(); + + // special treatment of for SID_OUTLINE_BULLET if objects with different + // kinds of NumBullets are marked + bool bHasOutliner = false; + bool bHasOther = false; + for(size_t nNum = 0; nNum < nMarkCount; ++nNum) + { + SdrObject* pObj = rMarkList.GetMark(nNum)->GetMarkedSdrObj(); + if( pObj->GetObjInventor() == SdrInventor::Default ) + { + if( pObj->GetObjIdentifier() == SdrObjKind::OutlineText ) + { + bHasOutliner = true; + if(bHasOther) + break; + } + else + { + bHasOther = true; + if(bHasOutliner) + break; + } + } + } + + if( bHasOther && bHasOutliner ) + rSet.DisableItem( SID_OUTLINE_BULLET ); + + if (pOlView) + { + if (pOlView->GetSelected().isEmpty() || GetObjectShell()->isContentExtractionLocked()) + { + rSet.DisableItem( SID_CUT ); + rSet.DisableItem( SID_COPY ); + } + } + + } + + FuBullet::GetSlotState( rSet, this, GetViewFrame() ); + + if ( GetDocSh()->IsUIActive() ) + { + rSet.DisableItem( SID_INSERT_OBJECT ); + rSet.DisableItem( SID_INSERT_FLOATINGFRAME ); + rSet.DisableItem( SID_INSERT_MATH ); + rSet.DisableItem( SID_INSERT_DIAGRAM ); + rSet.DisableItem( SID_ATTR_TABLE ); + rSet.DisableItem( SID_SIZE_REAL ); + rSet.DisableItem( SID_SIZE_OPTIMAL ); + rSet.DisableItem( SID_SIZE_ALL ); + rSet.DisableItem( SID_SIZE_PAGE_WIDTH ); + rSet.DisableItem( SID_SIZE_PAGE ); + rSet.DisableItem( SID_DUPLICATE_PAGE ); + rSet.DisableItem( SID_ZOOM_TOOLBOX ); + } + + // Zoom-State + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_IN ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_OUT )|| + SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_PANNING ) ) + { + if( GetActiveWindow()->GetZoom() <= GetActiveWindow()->GetMinZoom() || GetDocSh()->IsUIActive() ) + { + rSet.DisableItem( SID_ZOOM_OUT ); + rSet.DisableItem( SID_ZOOM_PANNING ); + } + if( GetActiveWindow()->GetZoom() >= GetActiveWindow()->GetMaxZoom() || GetDocSh()->IsUIActive() ) + rSet.DisableItem( SID_ZOOM_IN ); + } + + if (!mpZoomList->IsNextPossible()) + { + rSet.DisableItem(SID_ZOOM_NEXT); + } + if (!mpZoomList->IsPreviousPossible()) + { + rSet.DisableItem(SID_ZOOM_PREV); + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_REMOTE_DLG ) ) + { + + bool bDisableSdremoteForGood = false; +#ifndef ENABLE_SDREMOTE + bDisableSdremoteForGood = true; +#endif + bDisableSdremoteForGood |= !(officecfg::Office::Impress::Misc::Start::EnableSdremote::get() + && officecfg::Office::Security::Net::AllowInsecureImpressRemoteWiFi::get() + ); + + // This dialog is only useful for TCP/IP remote control + // which is unusual, under-tested and a security issue. + if ( bDisableSdremoteForGood ) + { + rSet.Put(SfxVisibilityItem(SID_REMOTE_DLG, false)); + } + } + + // EditText active + if (GetViewShellBase().GetViewShellManager()->GetShell(ToolbarId::Draw_Text_Toolbox_Sd) != nullptr) + { + sal_uInt16 nCurrentSId = SID_ATTR_CHAR; + + if(HasCurrentFunction()) + { + nCurrentSId = GetCurrentFunction()->GetSlotID(); + } + if( nCurrentSId != SID_TEXT_FITTOSIZE && + nCurrentSId != SID_TEXT_FITTOSIZE_VERTICAL && + nCurrentSId != SID_ATTR_CHAR_VERTICAL ) + nCurrentSId = SID_ATTR_CHAR; + + rSet.Put( SfxBoolItem( nCurrentSId, true ) ); + } + + if ( GetDocSh()->IsReadOnly() ) + { + rSet.DisableItem( SID_AUTOSPELL_CHECK ); + } + else + { + if (GetDoc()->GetOnlineSpell()) + { + rSet.Put(SfxBoolItem(SID_AUTOSPELL_CHECK, true)); + } + else + { + rSet.Put(SfxBoolItem(SID_AUTOSPELL_CHECK, false)); + } + } + + SdrPageView* pPV = mpDrawView->GetSdrPageView(); + OUString aActiveLayer = mpDrawView->GetActiveLayer(); + + if ( ( !aActiveLayer.isEmpty() && pPV && ( pPV->IsLayerLocked(aActiveLayer) || + !pPV->IsLayerVisible(aActiveLayer) ) ) || + SD_MOD()->GetWaterCan() ) + { + rSet.DisableItem( SID_PASTE ); + rSet.DisableItem( SID_PASTE_SPECIAL ); + rSet.DisableItem( SID_PASTE_UNFORMATTED ); + rSet.DisableItem( SID_CLIPBOARD_FORMAT_ITEMS ); + + rSet.DisableItem( SID_INSERT_FLD_DATE_FIX ); + rSet.DisableItem( SID_INSERT_FLD_DATE_VAR ); + rSet.DisableItem( SID_INSERT_FLD_TIME_FIX ); + rSet.DisableItem( SID_INSERT_FLD_TIME_VAR ); + rSet.DisableItem( SID_INSERT_FLD_AUTHOR ); + rSet.DisableItem( SID_INSERT_FLD_PAGE ); + rSet.DisableItem( SID_INSERT_FLD_PAGE_TITLE ); + rSet.DisableItem( SID_INSERT_FLD_PAGES ); + rSet.DisableItem( SID_INSERT_FLD_FILE ); + + rSet.DisableItem( SID_INSERT_GRAPHIC ); + rSet.DisableItem( SID_INSERT_AVMEDIA ); + rSet.DisableItem( SID_INSERT_DIAGRAM ); + rSet.DisableItem( SID_INSERT_OBJECT ); + rSet.DisableItem( SID_INSERT_FLOATINGFRAME ); + + rSet.DisableItem( SID_INSERT_MATH ); + rSet.DisableItem( SID_INSERT_FRAME ); + rSet.DisableItem( SID_INSERTFILE ); + rSet.DisableItem( SID_ATTR_TABLE ); + rSet.DisableItem( SID_COPYOBJECTS ); + + rSet.DisableItem( SID_SCAN ); + rSet.DisableItem( SID_TWAIN_SELECT ); + rSet.DisableItem( SID_TWAIN_TRANSFER ); + +// rSet.DisableItem( SID_BEZIER_EDIT ); + rSet.DisableItem( SID_GLUE_EDITMODE ); + rSet.DisableItem( SID_OBJECT_ROTATE ); + rSet.DisableItem( SID_OBJECT_SHEAR ); + rSet.DisableItem( SID_OBJECT_MIRROR ); + rSet.DisableItem( SID_OBJECT_CROP ); + rSet.DisableItem( SID_ATTR_GRAF_CROP ); + rSet.DisableItem( SID_OBJECT_TRANSPARENCE ); + rSet.DisableItem( SID_OBJECT_GRADIENT ); + rSet.DisableItem( SID_OBJECT_CROOK_ROTATE ); + rSet.DisableItem( SID_OBJECT_CROOK_SLANT ); + rSet.DisableItem( SID_OBJECT_CROOK_STRETCH ); + + // Disable all object-creating tools + rSet.ClearItem( SID_ATTR_CHAR ); + rSet.DisableItem( SID_ATTR_CHAR ); + rSet.ClearItem( SID_ATTR_CHAR_VERTICAL ); + rSet.DisableItem( SID_ATTR_CHAR_VERTICAL ); + rSet.ClearItem(SID_DRAW_LINE); + rSet.DisableItem(SID_DRAW_LINE); + rSet.ClearItem(SID_DRAW_MEASURELINE); + rSet.DisableItem(SID_DRAW_MEASURELINE); + rSet.ClearItem(SID_DRAW_XLINE); + rSet.DisableItem(SID_DRAW_XLINE); + rSet.ClearItem( SID_LINE_ARROW_START ); + rSet.DisableItem( SID_LINE_ARROW_START ); + rSet.ClearItem( SID_LINE_ARROW_END ); + rSet.DisableItem( SID_LINE_ARROW_END ); + rSet.ClearItem( SID_LINE_ARROWS ); + rSet.DisableItem( SID_LINE_ARROWS ); + rSet.ClearItem( SID_LINE_ARROW_CIRCLE ); + rSet.DisableItem( SID_LINE_ARROW_CIRCLE ); + rSet.ClearItem( SID_LINE_CIRCLE_ARROW ); + rSet.DisableItem( SID_LINE_CIRCLE_ARROW ); + rSet.ClearItem( SID_LINE_ARROW_SQUARE ); + rSet.DisableItem( SID_LINE_ARROW_SQUARE ); + rSet.ClearItem( SID_LINE_SQUARE_ARROW ); + rSet.DisableItem( SID_LINE_SQUARE_ARROW ); + + rSet.ClearItem(SID_DRAW_RECT); + rSet.DisableItem(SID_DRAW_RECT); + rSet.ClearItem(SID_DRAW_RECT_NOFILL); + rSet.DisableItem(SID_DRAW_RECT_NOFILL); + rSet.ClearItem(SID_DRAW_RECT_ROUND); + rSet.DisableItem(SID_DRAW_RECT_ROUND); + rSet.ClearItem(SID_DRAW_RECT_ROUND_NOFILL); + rSet.DisableItem(SID_DRAW_RECT_ROUND_NOFILL); + rSet.ClearItem(SID_DRAW_SQUARE); + rSet.DisableItem(SID_DRAW_SQUARE); + rSet.ClearItem(SID_DRAW_SQUARE_NOFILL); + rSet.DisableItem(SID_DRAW_SQUARE_NOFILL); + rSet.ClearItem(SID_DRAW_SQUARE_ROUND); + rSet.DisableItem(SID_DRAW_SQUARE_ROUND); + rSet.ClearItem(SID_DRAW_SQUARE_ROUND_NOFILL); + rSet.DisableItem(SID_DRAW_SQUARE_ROUND_NOFILL); + rSet.ClearItem(SID_DRAW_ELLIPSE); + rSet.DisableItem(SID_DRAW_ELLIPSE); + rSet.ClearItem(SID_DRAW_ELLIPSE_NOFILL); + rSet.DisableItem(SID_DRAW_ELLIPSE_NOFILL); + rSet.ClearItem(SID_DRAW_CIRCLE); + rSet.DisableItem(SID_DRAW_CIRCLE); + rSet.ClearItem(SID_DRAW_CIRCLE_NOFILL); + rSet.DisableItem(SID_DRAW_CIRCLE_NOFILL); + rSet.ClearItem(SID_DRAW_CAPTION); + rSet.DisableItem(SID_DRAW_CAPTION); + rSet.ClearItem(SID_DRAW_FONTWORK); + rSet.DisableItem(SID_DRAW_FONTWORK); + rSet.ClearItem(SID_DRAW_FONTWORK_VERTICAL); + rSet.DisableItem(SID_DRAW_FONTWORK_VERTICAL); + rSet.ClearItem(SID_DRAW_CAPTION_VERTICAL); + rSet.DisableItem(SID_DRAW_CAPTION_VERTICAL); + rSet.ClearItem(SID_TEXT_FITTOSIZE); + rSet.DisableItem(SID_TEXT_FITTOSIZE); + rSet.ClearItem(SID_TEXT_FITTOSIZE_VERTICAL); + rSet.DisableItem(SID_TEXT_FITTOSIZE_VERTICAL); + rSet.ClearItem(SID_TOOL_CONNECTOR); + rSet.DisableItem(SID_TOOL_CONNECTOR); + rSet.ClearItem(SID_CONNECTOR_ARROW_START); + rSet.DisableItem(SID_CONNECTOR_ARROW_START); + rSet.ClearItem(SID_CONNECTOR_ARROW_END); + rSet.DisableItem(SID_CONNECTOR_ARROW_END); + rSet.ClearItem(SID_CONNECTOR_ARROWS); + rSet.DisableItem(SID_CONNECTOR_ARROWS); + rSet.ClearItem(SID_CONNECTOR_CIRCLE_START); + rSet.DisableItem(SID_CONNECTOR_CIRCLE_START); + rSet.ClearItem(SID_CONNECTOR_CIRCLE_END); + rSet.DisableItem(SID_CONNECTOR_CIRCLE_END); + rSet.ClearItem(SID_CONNECTOR_CIRCLES); + rSet.DisableItem(SID_CONNECTOR_CIRCLES); + rSet.ClearItem(SID_CONNECTOR_LINE); + rSet.DisableItem(SID_CONNECTOR_LINE); + rSet.ClearItem(SID_CONNECTOR_LINE_ARROW_START); + rSet.DisableItem(SID_CONNECTOR_LINE_ARROW_START); + rSet.ClearItem(SID_CONNECTOR_LINE_ARROW_END); + rSet.DisableItem(SID_CONNECTOR_LINE_ARROW_END); + rSet.ClearItem(SID_CONNECTOR_LINE_ARROWS); + rSet.DisableItem(SID_CONNECTOR_LINE_ARROWS); + rSet.ClearItem(SID_CONNECTOR_LINE_CIRCLE_START); + rSet.DisableItem(SID_CONNECTOR_LINE_CIRCLE_START); + rSet.ClearItem(SID_CONNECTOR_LINE_CIRCLE_END); + rSet.DisableItem(SID_CONNECTOR_LINE_CIRCLE_END); + rSet.ClearItem(SID_CONNECTOR_LINE_CIRCLES); + rSet.DisableItem(SID_CONNECTOR_LINE_CIRCLES); + rSet.ClearItem(SID_CONNECTOR_CURVE); + rSet.DisableItem(SID_CONNECTOR_CURVE); + rSet.ClearItem(SID_CONNECTOR_CURVE_ARROW_START); + rSet.DisableItem(SID_CONNECTOR_CURVE_ARROW_START); + rSet.ClearItem(SID_CONNECTOR_CURVE_ARROW_END); + rSet.DisableItem(SID_CONNECTOR_CURVE_ARROW_END); + rSet.ClearItem(SID_CONNECTOR_CURVE_ARROWS); + rSet.DisableItem(SID_CONNECTOR_CURVE_ARROWS); + rSet.ClearItem(SID_CONNECTOR_CURVE_CIRCLE_START); + rSet.DisableItem(SID_CONNECTOR_CURVE_CIRCLE_START); + rSet.ClearItem(SID_CONNECTOR_CURVE_CIRCLE_END); + rSet.DisableItem(SID_CONNECTOR_CURVE_CIRCLE_END); + rSet.ClearItem(SID_CONNECTOR_CURVE_CIRCLES); + rSet.DisableItem(SID_CONNECTOR_CURVE_CIRCLES); + rSet.ClearItem(SID_CONNECTOR_LINES); + rSet.DisableItem(SID_CONNECTOR_LINES); + rSet.ClearItem(SID_CONNECTOR_LINES_ARROW_START); + rSet.DisableItem(SID_CONNECTOR_LINES_ARROW_START); + rSet.ClearItem(SID_CONNECTOR_LINES_ARROW_END); + rSet.DisableItem(SID_CONNECTOR_LINES_ARROW_END); + rSet.ClearItem(SID_CONNECTOR_LINES_ARROWS); + rSet.DisableItem(SID_CONNECTOR_LINES_ARROWS); + rSet.ClearItem(SID_CONNECTOR_LINES_CIRCLE_START); + rSet.DisableItem(SID_CONNECTOR_LINES_CIRCLE_START); + rSet.ClearItem(SID_CONNECTOR_LINES_CIRCLE_END); + rSet.DisableItem(SID_CONNECTOR_LINES_CIRCLE_END); + rSet.ClearItem(SID_CONNECTOR_LINES_CIRCLES); + rSet.DisableItem(SID_CONNECTOR_LINES_CIRCLES); + rSet.ClearItem(SID_DRAW_ARC); + rSet.DisableItem(SID_DRAW_ARC); + rSet.ClearItem(SID_DRAW_CIRCLEARC); + rSet.DisableItem(SID_DRAW_CIRCLEARC); + rSet.ClearItem(SID_DRAW_PIE); + rSet.DisableItem(SID_DRAW_PIE); + rSet.ClearItem(SID_DRAW_PIE_NOFILL); + rSet.DisableItem(SID_DRAW_PIE_NOFILL); + rSet.ClearItem(SID_DRAW_CIRCLEPIE); + rSet.DisableItem(SID_DRAW_CIRCLEPIE); + rSet.ClearItem(SID_DRAW_CIRCLEPIE_NOFILL); + rSet.DisableItem(SID_DRAW_CIRCLEPIE_NOFILL); + rSet.ClearItem(SID_DRAW_ELLIPSECUT); + rSet.DisableItem(SID_DRAW_ELLIPSECUT); + rSet.ClearItem(SID_DRAW_ELLIPSECUT_NOFILL); + rSet.DisableItem(SID_DRAW_ELLIPSECUT_NOFILL); + rSet.ClearItem(SID_DRAW_CIRCLECUT); + rSet.DisableItem(SID_DRAW_CIRCLECUT); + rSet.ClearItem(SID_DRAW_CIRCLECUT_NOFILL); + rSet.DisableItem(SID_DRAW_CIRCLECUT_NOFILL); + rSet.ClearItem(SID_DRAW_POLYGON); + rSet.DisableItem(SID_DRAW_POLYGON); + rSet.ClearItem(SID_DRAW_POLYGON_NOFILL); + rSet.DisableItem(SID_DRAW_POLYGON_NOFILL); + rSet.ClearItem(SID_DRAW_FREELINE); + rSet.DisableItem(SID_DRAW_FREELINE); + rSet.ClearItem(SID_DRAW_FREELINE_NOFILL); + rSet.DisableItem(SID_DRAW_FREELINE_NOFILL); + rSet.ClearItem(SID_DRAW_XPOLYGON); + rSet.DisableItem(SID_DRAW_XPOLYGON); + rSet.ClearItem(SID_DRAW_XPOLYGON_NOFILL); + rSet.DisableItem(SID_DRAW_XPOLYGON_NOFILL); + rSet.ClearItem(SID_DRAW_BEZIER_FILL); + rSet.DisableItem(SID_DRAW_BEZIER_FILL); + rSet.ClearItem(SID_DRAW_BEZIER_NOFILL); + rSet.DisableItem(SID_DRAW_BEZIER_NOFILL); + rSet.ClearItem(SID_3D_CUBE); + rSet.DisableItem(SID_3D_CUBE); + rSet.ClearItem(SID_3D_SHELL); + rSet.DisableItem(SID_3D_SHELL); + rSet.ClearItem(SID_3D_SPHERE); + rSet.DisableItem(SID_3D_SPHERE); + rSet.ClearItem(SID_3D_HALF_SPHERE); + rSet.DisableItem(SID_3D_HALF_SPHERE); + rSet.ClearItem(SID_3D_CYLINDER); + rSet.DisableItem(SID_3D_CYLINDER); + rSet.ClearItem(SID_3D_CONE); + rSet.DisableItem(SID_3D_CONE); + rSet.ClearItem(SID_3D_TORUS); + rSet.DisableItem(SID_3D_TORUS); + rSet.ClearItem(SID_3D_PYRAMID); + rSet.DisableItem(SID_3D_PYRAMID); + } + + if ( !aActiveLayer.isEmpty() && pPV ) + rSet.Put( SfxBoolItem(SID_TOGGLELAYERVISIBILITY, !pPageView->IsLayerVisible(aActiveLayer)) ); + + // are the modules available? + + if (!SvtModuleOptions().IsCalc()) + { + // remove menu entry if module is not available + rSet.Put( SfxVisibilityItem( SID_ATTR_TABLE, false ) ); + } + if (!SvtModuleOptions().IsChart()) + { + rSet.DisableItem( SID_INSERT_DIAGRAM ); + } + if (!SvtModuleOptions().IsMath()) + { + rSet.DisableItem( SID_INSERT_MATH ); + } + + rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if( (xSlideshow.is() && xSlideshow->isRunning() && (xSlideshow->getAnimationMode() != ANIMATIONMODE_PREVIEW) ) || GetDocSh()->IsPreview() ) + { + // Own Slots + rSet.DisableItem( SID_PRESENTATION ); + rSet.DisableItem( SID_ZOOM_IN ); + rSet.DisableItem( SID_ZOOM_OUT ); + rSet.DisableItem( SID_ZOOM_PANNING ); + rSet.DisableItem( SID_ZOOM_MODE ); + rSet.DisableItem( SID_ZOOM_NEXT ); + rSet.DisableItem( SID_ZOOM_PREV ); + rSet.DisableItem( SID_SIZE_REAL ); + rSet.DisableItem( SID_SIZE_OPTIMAL ); + rSet.DisableItem( SID_SIZE_ALL ); + rSet.DisableItem( SID_SIZE_PAGE_WIDTH ); + rSet.DisableItem( SID_SIZE_PAGE ); + rSet.DisableItem( SID_INSERTPAGE ); + rSet.DisableItem( SID_DUPLICATE_PAGE ); + rSet.DisableItem( SID_MODIFYPAGE ); + rSet.DisableItem( SID_RENAMEPAGE ); + rSet.DisableItem( SID_RENAMEPAGE_QUICK ); + rSet.DisableItem( SID_DELETE_PAGE ); + rSet.DisableItem( SID_PAGESETUP ); + + if( xSlideshow.is() && xSlideshow->isRunning() ) + { + rSet.ClearItem(SID_INSERTFILE); + rSet.ClearItem(SID_OBJECT_ROTATE); + rSet.ClearItem(SID_FM_CONFIG); + rSet.ClearItem(SID_ANIMATION_EFFECTS); + rSet.ClearItem(SID_EXECUTE_ANIMATION_EFFECT); + rSet.ClearItem(SID_ANIMATION_OBJECTS); + rSet.ClearItem(SID_3D_WIN); + + rSet.DisableItem(SID_OBJECT_ALIGN); + rSet.DisableItem(SID_ZOOM_TOOLBOX); + rSet.DisableItem(SID_OBJECT_CHOOSE_MODE); + rSet.DisableItem(SID_DRAWTBX_TEXT); + rSet.DisableItem(SID_DRAWTBX_RECTANGLES); + rSet.DisableItem(SID_DRAWTBX_ELLIPSES); + rSet.DisableItem(SID_DRAWTBX_LINES); + rSet.DisableItem(SID_DRAWTBX_ARROWS); + rSet.DisableItem(SID_DRAWTBX_3D_OBJECTS); + rSet.DisableItem(SID_DRAWTBX_CONNECTORS); + rSet.DisableItem(SID_OBJECT_CHOOSE_MODE ); + rSet.DisableItem(SID_DRAWTBX_INSERT); + rSet.DisableItem(SID_INSERTFILE); + rSet.DisableItem(SID_OBJECT_ROTATE); + rSet.DisableItem(SID_POSITION); + rSet.DisableItem(SID_FM_CONFIG); + rSet.DisableItem(SID_ANIMATION_EFFECTS); + rSet.DisableItem(SID_EXECUTE_ANIMATION_EFFECT); + rSet.DisableItem(SID_ANIMATION_OBJECTS); + rSet.DisableItem(SID_3D_WIN); + } + } + + // Menuoption: Change->Convert->To Bitmap, Change->Convert->To Metafile + // disable, if there only Bitmap or Metafiles marked + // Menuoption: Format->Area, Format->Line + // disabled, if the marked objects not able to handle + // these attributes + + bool bSingleGraphicSelected = false; + + if (!mpDrawView->AreObjectsMarked()) + { + rSet.DisableItem (SID_CONVERT_TO_METAFILE); + rSet.DisableItem (SID_CONVERT_TO_BITMAP); + } + else + { + // get marklist + SdrMarkList aMarkList = mpDrawView->GetMarkedObjectList(); + + bool bFoundBitmap = false; + bool bFoundMetafile = false; + bool bFoundObjNoArea = false; + bool bFoundNoGraphicObj = false; + bool bFoundAny = false; + bool bFoundTable = false; + +// const size_t nMarkCount = aMarkList.GetMarkCount(); + for (size_t i=0; i < nMarkCount && !bFoundAny; ++i) + { + SdrObject* pObj = aMarkList.GetMark(i)->GetMarkedSdrObj(); + SdrObjKind nId = pObj->GetObjIdentifier(); + SdrInventor nInv = pObj->GetObjInventor(); + + if(nInv == SdrInventor::Default) + { + // 2D objects + switch( nId ) + { + case SdrObjKind::PathLine : + case SdrObjKind::PolyLine : + case SdrObjKind::Line: + case SdrObjKind::FreehandLine : + case SdrObjKind::Edge: + case SdrObjKind::CircleArc : + bFoundObjNoArea = true; + bFoundNoGraphicObj = true; + break; + case SdrObjKind::OLE2 : + // #i118485# #i118525# Allow Line, Area and Graphic (Metafile, Bitmap) + bSingleGraphicSelected = nMarkCount == 1; + bFoundBitmap = true; + bFoundMetafile = true; + break; + case SdrObjKind::Graphic : + { + bSingleGraphicSelected = nMarkCount == 1; + const SdrGrafObj* pSdrGrafObj = static_cast< const SdrGrafObj* >(pObj); + + // Current size of the OBJ_GRAF + const ::tools::Rectangle aRect = pObj->GetLogicRect(); + const Size aCurrentSizeofObj = aRect.GetSize(); + + // Original size of the OBJ_GRAF + const Size aOriginalSizeofObj = pSdrGrafObj->getOriginalSize(); + + if(aCurrentSizeofObj == aOriginalSizeofObj ) + rSet.DisableItem(SID_ORIGINAL_SIZE); + + switch(pSdrGrafObj->GetGraphicType()) + { + case GraphicType::Bitmap : + bFoundBitmap = true; + if(pSdrGrafObj->isEmbeddedVectorGraphicData()) + { + bFoundMetafile = true; + } + break; + case GraphicType::GdiMetafile : + bFoundMetafile = true; + break; + default: + break; + } + break; + } + case SdrObjKind::Table: + bFoundTable = true; + break; + default : + bFoundAny = true; + } + } + else if(nInv == SdrInventor::E3d) + { + // 3D objects + bFoundAny = true; + } + } + + if( bFoundTable ) + rSet.DisableItem( SID_ATTRIBUTES_LINE ); + + if (!bFoundAny) + { + // Disable menuitem for area-dialog + if( bFoundObjNoArea ) // #i25616# + rSet.DisableItem( SID_ATTRIBUTES_AREA ); + + if( bFoundBitmap && !bFoundMetafile && !bFoundNoGraphicObj ) // only Bitmaps marked + rSet.DisableItem( SID_CONVERT_TO_BITMAP ); + else if( !bFoundBitmap && bFoundMetafile && !bFoundNoGraphicObj ) // only Metafiles marked + rSet.DisableItem( SID_CONVERT_TO_METAFILE ); + else if( !bFoundBitmap && !bFoundMetafile && !bFoundNoGraphicObj ) // nothing to do + { + rSet.DisableItem( SID_CONVERT_TO_BITMAP ); + rSet.DisableItem( SID_CONVERT_TO_METAFILE ); + } + } + } + + if( !bSingleGraphicSelected ) + { + rSet.DisableItem (SID_OBJECT_CROP); + rSet.DisableItem (SID_ATTR_GRAF_CROP); + } + + // Menuoption: Edit->Hyperlink + // Disable, if there is no hyperlink + bool bDisableEditHyperlink = ShouldDisableEditHyperlink(); + + //highlight selected custom shape + { + if(HasCurrentFunction()) + { + rtl::Reference< FuPoor > xFunc( GetCurrentFunction() ); + FuConstructCustomShape* pShapeFunc = dynamic_cast< FuConstructCustomShape* >( xFunc.get() ); + + static const sal_uInt16 nCSTbArray[] = { SID_DRAWTBX_CS_BASIC, SID_DRAWTBX_CS_SYMBOL, + SID_DRAWTBX_CS_ARROW, SID_DRAWTBX_CS_FLOWCHART, + SID_DRAWTBX_CS_CALLOUT, SID_DRAWTBX_CS_STAR }; + + const sal_uInt16 nCurrentSId = GetCurrentFunction()->GetSlotID(); + for (sal_uInt16 i : nCSTbArray) + { + rSet.ClearItem( i ); // Why is this necessary? + rSet.Put( SfxStringItem( i, nCurrentSId == i && pShapeFunc + ? pShapeFunc->GetShapeType() : OUString() ) ); + } + } + } + + if ( bDisableEditHyperlink || GetDocSh()->IsReadOnly() ) + rSet.DisableItem( SID_EDIT_HYPERLINK ); + + if ( bDisableEditHyperlink ) + { + rSet.DisableItem( SID_OPEN_HYPERLINK ); + rSet.DisableItem( SID_COPY_HYPERLINK_LOCATION ); + } + + //fdo#78151 enable show next level/hide last level if editing a master page + //PresObjKind::Outline object and the current selection allow that to happen + { + bool bDisableShowNextLevel = true; + bool bDisableHideLastLevel = true; + + ESelection aSel; + ::Outliner* pOL = GetOutlinerForMasterPageOutlineTextObj(aSel); + if (pOL) + { + //and are on the last paragraph + aSel.Adjust(); + if (aSel.nEndPara == pOL->GetParagraphCount() - 1) + { + sal_uInt16 nDepth = pOL->GetDepth(aSel.nEndPara); + if (nDepth != sal_uInt16(-1)) + { + //there exists another numbering level that + //is currently hidden + if (nDepth < 8) + bDisableShowNextLevel = false; + //there exists a previous numbering level + if (nDepth > 0) + bDisableHideLastLevel = false; + } + } + } + + if (bDisableShowNextLevel) + rSet.DisableItem(SID_SHOW_NEXT_LEVEL); + + if (bDisableHideLastLevel) + rSet.DisableItem(SID_HIDE_LAST_LEVEL); + } + +#if defined(_WIN32) || defined UNX + if( !mxScannerManager.is() ) + { + rSet.DisableItem( SID_TWAIN_SELECT ); + rSet.DisableItem( SID_TWAIN_TRANSFER ); + } +#endif + + // Set the state of two entries in the 'Slide' context sub-menu + // concerning the visibility of master page background and master page + // shapes. + if (rSet.GetItemState(SID_DISPLAY_MASTER_BACKGROUND) == SfxItemState::DEFAULT + || rSet.GetItemState(SID_DISPLAY_MASTER_OBJECTS) == SfxItemState::DEFAULT) + { + SdPage* pPage = GetActualPage(); + if (pPage != nullptr && GetDoc() != nullptr) + { + SdrLayerIDSet aVisibleLayers = pPage->TRG_GetMasterPageVisibleLayers(); + SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin(); + SdrLayerID aBackgroundId = rLayerAdmin.GetLayerID(sUNO_LayerName_background); + SdrLayerID aObjectId = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects); + rSet.Put(SfxBoolItem(SID_DISPLAY_MASTER_BACKGROUND, + aVisibleLayers.IsSet(aBackgroundId))); + rSet.Put(SfxBoolItem(SID_DISPLAY_MASTER_OBJECTS, + aVisibleLayers.IsSet(aObjectId))); + } + } + + if (rSet.GetItemState(SID_SAVE_BACKGROUND) == SfxItemState::DEFAULT) + { + bool bDisableSaveBackground = true; + SdPage* pPage = GetActualPage(); + if (pPage != nullptr && GetDoc() != nullptr) + { + SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aMergedAttr(GetDoc()->GetPool()); + SdStyleSheet* pStyleSheet = pPage->getPresentationStyle(HID_PSEUDOSHEET_BACKGROUND); + MergePageBackgroundFilling(pPage, pStyleSheet, meEditMode == EditMode::MasterPage, aMergedAttr); + if (drawing::FillStyle_BITMAP == aMergedAttr.Get(XATTR_FILLSTYLE).GetValue()) + { + bDisableSaveBackground = false; + } + } + if (bDisableSaveBackground) + rSet.DisableItem(SID_SAVE_BACKGROUND); + } + + if (GetObjectShell()->isExportLocked()) + rSet.DisableItem(SID_PRESENTATION_MINIMIZER); + + if (rSet.GetItemState(SID_INSERT_SIGNATURELINE) == SfxItemState::DEFAULT) + { + if (!GetObjectShell()->IsSignPDF()) + { + // Currently SID_INSERT_SIGNATURELINE assumes a PDF that was opened for signing, disable + // it otherwise. + rSet.DisableItem(SID_INSERT_SIGNATURELINE); + } + } + + GetModeSwitchingMenuState (rSet); +} + +void DrawViewShell::GetModeSwitchingMenuState (SfxItemSet &rSet) +{ + //DrawView + rSet.Put(SfxBoolItem(SID_SLIDE_SORTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_OUTLINE_MODE, false)); + rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false)); + if (mePageKind == PageKind::Notes) + { + rSet.Put(SfxBoolItem(SID_DRAWINGMODE, false)); + rSet.Put(SfxBoolItem(SID_NOTES_MODE, true)); + rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false)); + } + else if (mePageKind == PageKind::Handout) + { + rSet.Put(SfxBoolItem(SID_DRAWINGMODE, false)); + rSet.Put(SfxBoolItem(SID_NOTES_MODE, false)); + rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, true)); + } + else + { + rSet.Put(SfxBoolItem(SID_DRAWINGMODE, true)); + rSet.Put(SfxBoolItem(SID_NOTES_MODE, false)); + rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false)); + } + + // Removed [GetDocSh()->GetCurrentFunction() ||] from the following + // clause because the current function of the docshell can only be + // search and replace or spell checking and in that case switching the + // view mode is allowed. + const bool bIsRunning = SlideShow::IsRunning(GetViewShellBase()); + + if (GetViewFrame()->GetFrame().IsInPlace() || bIsRunning) + { + if ( !GetViewFrame()->GetFrame().IsInPlace() ) + { + rSet.ClearItem( SID_DRAWINGMODE ); + rSet.DisableItem( SID_DRAWINGMODE ); + } + + rSet.ClearItem( SID_NOTES_MODE ); + rSet.DisableItem( SID_NOTES_MODE ); + + rSet.ClearItem( SID_HANDOUT_MASTER_MODE ); + rSet.DisableItem( SID_HANDOUT_MASTER_MODE ); + + rSet.ClearItem( SID_OUTLINE_MODE ); + rSet.DisableItem( SID_OUTLINE_MODE ); + + rSet.ClearItem( SID_SLIDE_MASTER_MODE ); + rSet.DisableItem( SID_SLIDE_MASTER_MODE ); + + rSet.ClearItem( SID_NOTES_MASTER_MODE ); + rSet.DisableItem( SID_NOTES_MASTER_MODE ); + + rSet.ClearItem( SID_SLIDE_SORTER_MODE ); + rSet.DisableItem( SID_SLIDE_SORTER_MODE ); + } + + if (GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED) + { + // Outplace-Edit: do not allow switch + rSet.ClearItem( SID_OUTLINE_MODE ); + rSet.DisableItem( SID_OUTLINE_MODE ); + + rSet.ClearItem( SID_SLIDE_SORTER_MODE ); + rSet.DisableItem( SID_SLIDE_SORTER_MODE ); + + rSet.ClearItem( SID_NOTES_MODE ); + rSet.DisableItem( SID_NOTES_MODE ); + + rSet.ClearItem( SID_HANDOUT_MASTER_MODE ); + rSet.DisableItem( SID_HANDOUT_MASTER_MODE ); + + rSet.ClearItem( SID_SLIDE_MASTER_MODE ); + rSet.DisableItem( SID_SLIDE_MASTER_MODE ); + + rSet.ClearItem( SID_NOTES_MASTER_MODE ); + rSet.DisableItem( SID_NOTES_MASTER_MODE ); + } + + svx::ExtrusionBar::getState( mpDrawView.get(), rSet ); + svx::FontworkBar::getState( mpDrawView.get(), rSet ); +} + +void DrawViewShell::GetPageProperties( SfxItemSet &rSet ) +{ + SdPage *pPage = getCurrentPage(); + + if (pPage == nullptr || GetDoc() == nullptr) + return; + + SvxPageItem aPageItem(SID_ATTR_PAGE); + aPageItem.SetLandscape( pPage->GetOrientation() == Orientation::Landscape ); + + rSet.Put(SvxSizeItem( SID_ATTR_PAGE_SIZE, pPage->GetSize() )); + rSet.Put(aPageItem); + + const SfxItemSet &rPageAttr = pPage->getSdrPageProperties().GetItemSet(); + const XFillStyleItem* pFillStyle = rPageAttr.GetItem(XATTR_FILLSTYLE); + if (!pFillStyle) + return; + + drawing::FillStyle eXFS = pFillStyle->GetValue(); + XFillStyleItem aFillStyleItem( eXFS ); + aFillStyleItem.SetWhich( SID_ATTR_PAGE_FILLSTYLE ); + rSet.Put(aFillStyleItem); + + switch (eXFS) + { + case drawing::FillStyle_SOLID: + if (const XFillColorItem* pColorItem = rPageAttr.GetItem(XATTR_FILLCOLOR)) + { + Color aColor = pColorItem->GetColorValue(); + XFillColorItem aFillColorItem( OUString(), aColor ); + aFillColorItem.SetWhich( SID_ATTR_PAGE_COLOR ); + rSet.Put( aFillColorItem ); + } + break; + + case drawing::FillStyle_GRADIENT: + { + const XFillGradientItem *pGradient = rPageAttr.GetItem( XATTR_FILLGRADIENT ); + XFillGradientItem aFillGradientItem( pGradient->GetName(), pGradient->GetGradientValue(), SID_ATTR_PAGE_GRADIENT ); + rSet.Put( aFillGradientItem ); + } + break; + + case drawing::FillStyle_HATCH: + { + const XFillHatchItem *pFillHatchItem( rPageAttr.GetItem( XATTR_FILLHATCH ) ); + XFillHatchItem aFillHatchItem( pFillHatchItem->GetName(), pFillHatchItem->GetHatchValue()); + aFillHatchItem.SetWhich( SID_ATTR_PAGE_HATCH ); + rSet.Put( aFillHatchItem ); + } + break; + + case drawing::FillStyle_BITMAP: + { + const XFillBitmapItem *pFillBitmapItem = rPageAttr.GetItem( XATTR_FILLBITMAP ); + XFillBitmapItem aFillBitmapItem( pFillBitmapItem->GetName(), pFillBitmapItem->GetGraphicObject() ); + aFillBitmapItem.SetWhich( SID_ATTR_PAGE_BITMAP ); + rSet.Put( aFillBitmapItem ); + } + break; + + default: + break; + } +} + +void DrawViewShell::SetPageProperties (SfxRequest& rReq) +{ + SdPage *pPage = getCurrentPage(); + if (!pPage) + return; + sal_uInt16 nSlotId = rReq.GetSlot(); + const SfxItemSet *pArgs = rReq.GetArgs(); + if (!pArgs) + return; + + if ( ( nSlotId >= SID_ATTR_PAGE_COLOR ) && ( nSlotId <= SID_ATTR_PAGE_FILLSTYLE ) ) + { + SdrPageProperties& rPageProperties = pPage->getSdrPageProperties(); + const SfxItemSet &aPageItemSet = rPageProperties.GetItemSet(); + SfxItemSet aTempSet = aPageItemSet.CloneAsValue(false, &mpDrawView->GetModel().GetItemPool()); + const SfxPoolItem* pItem = nullptr; + + rPageProperties.ClearItem(XATTR_FILLSTYLE); + rPageProperties.ClearItem(XATTR_FILLGRADIENT); + rPageProperties.ClearItem(XATTR_FILLHATCH); + rPageProperties.ClearItem(XATTR_FILLBITMAP); + + switch (nSlotId) + { + case SID_ATTR_PAGE_FILLSTYLE: + { + XFillStyleItem aFSItem( pArgs->Get( XATTR_FILLSTYLE ) ); + drawing::FillStyle eXFS = aFSItem.GetValue(); + + if ( eXFS == drawing::FillStyle_NONE ) + rPageProperties.PutItem( XFillStyleItem( eXFS ) ); + } + break; + + case SID_ATTR_PAGE_COLOR: + { + rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_SOLID ) ); + if (const XFillColorItem* pColorItem = static_cast<const XFillColorItem*>(pArgs->GetItem(SID_ATTR_PAGE_COLOR))) + rPageProperties.PutItem(XFillColorItem("", pColorItem->GetColorValue())); + else + rPageProperties.PutItem(pArgs->Get(XATTR_FILLCOLOR)); + } + break; + + case SID_ATTR_PAGE_GRADIENT: + { + if (SfxItemState::SET == pArgs->GetItemState(SID_FILL_GRADIENT_JSON, false, &pItem)) + { + const SfxStringItem* pJSON = static_cast<const SfxStringItem*>(pItem); + XFillGradientItem aGradientItem( basegfx::BGradient::fromJSON(pJSON->GetValue()) ); + + // MigrateItemSet guarantees unique gradient names + SfxItemSetFixed<XATTR_FILLGRADIENT, XATTR_FILLGRADIENT> aMigrateSet(mpDrawView->GetModel().GetItemPool()); + aMigrateSet.Put( aGradientItem ); + SdrModel::MigrateItemSet(&aMigrateSet, &aTempSet, &mpDrawView->GetModel()); + + rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_GRADIENT ) ); + rPageProperties.PutItemSet( aTempSet ); + } + else + { + XFillGradientItem aGradientItem( pArgs->Get( XATTR_FILLGRADIENT ) ); + + // MigrateItemSet guarantees unique gradient names + SfxItemSetFixed<XATTR_FILLGRADIENT, XATTR_FILLGRADIENT> aMigrateSet(mpDrawView->GetModel().GetItemPool()); + aMigrateSet.Put( aGradientItem ); + SdrModel::MigrateItemSet(&aMigrateSet, &aTempSet, &mpDrawView->GetModel()); + + rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_GRADIENT ) ); + rPageProperties.PutItemSet( aTempSet ); + } + } + break; + + case SID_ATTR_PAGE_HATCH: + { + XFillHatchItem aHatchItem( pArgs->Get( XATTR_FILLHATCH ) ); + rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_HATCH ) ); + rPageProperties.PutItem( aHatchItem ); + } + break; + + case SID_ATTR_PAGE_BITMAP: + { + XFillBitmapItem aBitmapItem( pArgs->Get( XATTR_FILLBITMAP ) ); + rPageProperties.PutItem( XFillStyleItem( drawing::FillStyle_BITMAP ) ); + rPageProperties.PutItem( aBitmapItem ); + } + break; + + default: + break; + } + + rReq.Done(); + } + else + { + PageKind ePageKind = GetPageKind(); + const SfxPoolItem* pPoolItem = nullptr; + Size aNewSize(pPage->GetSize()); + sal_Int32 nLeft = -1, nRight = -1, nUpper = -1, nLower = -1; + bool bScaleAll = true; + Orientation eOrientation = pPage->GetOrientation(); + SdPage* pMasterPage = pPage->IsMasterPage() ? pPage : &static_cast<SdPage&>(pPage->TRG_GetMasterPage()); + bool bFullSize = pMasterPage->IsBackgroundFullSize(); + sal_uInt16 nPaperBin = pPage->GetPaperBin(); + + switch (nSlotId) + { + case SID_ATTR_PAGE_LRSPACE: + if( pArgs->GetItemState(SID_ATTR_PAGE_LRSPACE, + true,&pPoolItem) == SfxItemState::SET ) + { + nLeft = static_cast<const SvxLongLRSpaceItem*>(pPoolItem)->GetLeft(); + nRight = static_cast<const SvxLongLRSpaceItem*>(pPoolItem)->GetRight(); + if (nLeft != -1) + { + nUpper = pPage->GetUpperBorder(); + nLower = pPage->GetLowerBorder(); + } + SetPageSizeAndBorder(ePageKind, aNewSize, nLeft, nRight, nUpper, nLower, bScaleAll, eOrientation, nPaperBin, bFullSize ); + } + break; + + case SID_ATTR_PAGE_ULSPACE: + if( pArgs->GetItemState(SID_ATTR_PAGE_ULSPACE, + true,&pPoolItem) == SfxItemState::SET ) + { + nUpper = static_cast<const SvxLongULSpaceItem*>(pPoolItem)->GetUpper(); + nLower = static_cast<const SvxLongULSpaceItem*>(pPoolItem)->GetLower(); + if (nUpper != -1) + { + nLeft = pPage->GetLeftBorder(); + nRight = pPage->GetRightBorder(); + } + SetPageSizeAndBorder(ePageKind, aNewSize, nLeft, nRight, nUpper, nLower, bScaleAll, eOrientation, nPaperBin, bFullSize ); + } + break; + + default: + break; + } + } +} + +void DrawViewShell::GetState (SfxItemSet& rSet) +{ + // Iterate over all requested items in the set. + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + while (nWhich) + { + switch (nWhich) + { + case SID_SEARCH_ITEM: + case SID_SEARCH_OPTIONS: + // Forward this request to the common (old) code of the + // document shell. + GetDocSh()->GetState (rSet); + break; + default: + SAL_WARN("sd", "DrawViewShell::GetState(): can not handle which id " << nWhich); + break; + } + nWhich = aIter.NextWhich(); + } +} + +void DrawViewShell::Execute (SfxRequest& rReq) +{ + if(SlideShow::IsRunning(GetViewShellBase())) + { + // Do not execute anything during a native slide show. + return; + } + + switch (rReq.GetSlot()) + { + case SID_SEARCH_ITEM: + // Forward this request to the common (old) code of the + // document shell. + GetDocSh()->Execute (rReq); + break; + + case SID_SPELL_DIALOG: + { + SfxViewFrame* pViewFrame = GetViewFrame(); + if (rReq.GetArgs() != nullptr) + pViewFrame->SetChildWindow (SID_SPELL_DIALOG, + static_cast<const SfxBoolItem&>(rReq.GetArgs()-> + Get(SID_SPELL_DIALOG)).GetValue()); + else + pViewFrame->ToggleChildWindow(SID_SPELL_DIALOG); + + pViewFrame->GetBindings().Invalidate(SID_SPELL_DIALOG); + rReq.Ignore (); + } + break; + + default: + SAL_WARN("sd", "DrawViewShell::Execute(): can not handle slot " << rReq.GetSlot()); + break; + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews8.cxx b/sd/source/ui/view/drviews8.cxx new file mode 100644 index 0000000000..0f2907d424 --- /dev/null +++ b/sd/source/ui/view/drviews8.cxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> + +#include <com/sun/star/scanner/XScannerManager2.hpp> +#include <toolkit/helper/vclunohelper.hxx> +#include <svx/svxids.hrc> +#include <sfx2/bindings.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdpagv.hxx> + +#include <Window.hxx> +#include <drawview.hxx> +#include <tools/helpers.hxx> +#include <vcl/svapp.hxx> + +namespace sd { + +void DrawViewShell::ScannerEvent() +{ + if( mxScannerManager.is() ) + { + const css::scanner::ScannerContext aContext( mxScannerManager->getAvailableScanners().getConstArray()[ 0 ] ); + const css::scanner::ScanError eError = mxScannerManager->getError( aContext ); + + if( css::scanner::ScanError_ScanErrorNone == eError ) + { + const css::uno::Reference< css::awt::XBitmap > xBitmap( mxScannerManager->getBitmap( aContext ) ); + + if( xBitmap.is() ) + { + const BitmapEx aScanBmp( VCLUnoHelper::GetBitmap( xBitmap ) ); + + if( !aScanBmp.IsEmpty() ) + { + const SolarMutexGuard aGuard; + SdrPage* pPage = mpDrawView->GetSdrPageView()->GetPage(); + Size aBmpSize( aScanBmp.GetPrefSize() ), aPageSize( pPage->GetSize() ); + const MapMode aMap100( MapUnit::Map100thMM ); + + if( !aBmpSize.Width() || !aBmpSize.Height() ) + aBmpSize = aScanBmp.GetSizePixel(); + + if( aScanBmp.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel ) + aBmpSize = GetActiveWindow()->PixelToLogic( aBmpSize, aMap100 ); + else + aBmpSize = OutputDevice::LogicToLogic( aBmpSize, aScanBmp.GetPrefMapMode(), aMap100 ); + + aPageSize.AdjustWidth( -(pPage->GetLeftBorder() + pPage->GetRightBorder()) ); + aPageSize.AdjustHeight( -(pPage->GetUpperBorder() + pPage->GetLowerBorder()) ); + + if( ( ( aBmpSize.Height() > aPageSize.Height() ) || ( aBmpSize.Width() > aPageSize.Width() ) ) && aBmpSize.Height() && aPageSize.Height() ) + { + double fGrfWH = static_cast<double>(aBmpSize.Width()) / aBmpSize.Height(); + double fWinWH = static_cast<double>(aPageSize.Width()) / aPageSize.Height(); + + if( fGrfWH < fWinWH ) + { + aBmpSize.setWidth( FRound( aPageSize.Height() * fGrfWH ) ); + aBmpSize.setHeight( aPageSize.Height() ); + } + else if( fGrfWH > 0.F ) + { + aBmpSize.setWidth( aPageSize.Width() ); + aBmpSize.setHeight( FRound( aPageSize.Width() / fGrfWH ) ); + } + } + + Point aPnt ( ( aPageSize.Width() - aBmpSize.Width() ) >> 1, ( aPageSize.Height() - aBmpSize.Height() ) >> 1 ); + aPnt += Point( pPage->GetLeftBorder(), pPage->GetUpperBorder() ); + ::tools::Rectangle aRect( aPnt, aBmpSize ); + bool bInsertNewObject = true; + + if( GetView()->AreObjectsMarked() ) + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + + if( rMarkList.GetMarkCount() == 1 ) + { + SdrMark* pMark = rMarkList.GetMark(0); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + + if( auto pGrafObj = dynamic_cast< SdrGrafObj *>( pObj ) ) + { + if( pGrafObj->IsEmptyPresObj() ) + { + bInsertNewObject = false; + pGrafObj->SetEmptyPresObj(false); + pGrafObj->SetOutlinerParaObject(std::nullopt); + pGrafObj->SetGraphic( Graphic( aScanBmp ) ); + } + } + } + } + + if( bInsertNewObject ) + { + rtl::Reference<SdrGrafObj> pGrafObj = new SdrGrafObj( + GetView()->getSdrModelFromSdrView(), + Graphic(aScanBmp), + aRect); + SdrPageView* pPV = GetView()->GetSdrPageView(); + GetView()->InsertObjectAtView( pGrafObj.get(), *pPV, SdrInsertFlags::SETDEFLAYER ); + } + } + } + } + } + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_TWAIN_SELECT ); + rBindings.Invalidate( SID_TWAIN_TRANSFER ); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviews9.cxx b/sd/source/ui/view/drviews9.cxx new file mode 100644 index 0000000000..1ae793e4d6 --- /dev/null +++ b/sd/source/ui/view/drviews9.cxx @@ -0,0 +1,905 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <DrawViewShell.hxx> +#include <svx/svdpagv.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xlineit0.hxx> +#include <svx/xlnwtit.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xflhtit.hxx> +#include <svx/xflgrit.hxx> +#include <svx/xlnclit.hxx> +#include <svx/xflclit.hxx> +#include <sfx2/bindings.hxx> + +#include <sfx2/dispatch.hxx> +#include <svl/intitem.hxx> +#include <sfx2/request.hxx> +#include <svl/stritem.hxx> +#include <svx/svxids.hrc> +#include <svx/xtable.hxx> +#include <vcl/graph.hxx> +#include <svx/svdograf.hxx> +#include <svl/whiter.hxx> +#include <basic/sbstar.hxx> +#include <basic/sberrors.hxx> + +#include <sfx2/viewfrm.hxx> + +#include <app.hrc> +#include <strings.hrc> +#include <Window.hxx> +#include <drawdoc.hxx> +#include <drawview.hxx> +#include <DrawDocShell.hxx> +#include <sdresid.hxx> + +#include <svx/galleryitem.hxx> +#include <com/sun/star/gallery/GalleryItemType.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <memory> + +using namespace com::sun::star; + +namespace sd { + +void DrawViewShell::ExecGallery(SfxRequest const & rReq) +{ + // nothing is executed during a slide show! + if(HasCurrentFunction(SID_PRESENTATION)) + return; + + const SfxItemSet* pArgs = rReq.GetArgs(); + + const SvxGalleryItem* pGalleryItem = SfxItemSet::GetItem<SvxGalleryItem>(pArgs, SID_GALLERY_FORMATS, false); + if ( !pGalleryItem ) + return; + + GetDocSh()->SetWaitCursor( true ); + + sal_Int8 nType( pGalleryItem->GetType() ); + // insert graphic + if (nType == css::gallery::GalleryItemType::GRAPHIC) + { + Graphic aGraphic( pGalleryItem->GetGraphic() ); + + // reduce size if necessary + ScopedVclPtrInstance< Window > aWindow(GetActiveWindow()); + aWindow->SetMapMode(aGraphic.GetPrefMapMode()); + Size aSizePix = aWindow->LogicToPixel(aGraphic.GetPrefSize()); + aWindow->SetMapMode( MapMode(MapUnit::Map100thMM) ); + Size aSize = aWindow->PixelToLogic(aSizePix); + + // constrain size to page size if necessary + SdrPage* pPage = mpDrawView->GetSdrPageView()->GetPage(); + Size aPageSize = pPage->GetSize(); + aPageSize.AdjustWidth( -(pPage->GetLeftBorder() + pPage->GetRightBorder()) ); + aPageSize.AdjustHeight( -(pPage->GetUpperBorder() + pPage->GetLowerBorder()) ); + + // If the image is too large we make it fit into the page + if ( ( ( aSize.Height() > aPageSize.Height() ) || ( aSize.Width() > aPageSize.Width() ) ) && + aSize.Height() && aPageSize.Height() ) + { + float fGrfWH = static_cast<float>(aSize.Width()) / + static_cast<float>(aSize.Height()); + float fWinWH = static_cast<float>(aPageSize.Width()) / + static_cast<float>(aPageSize.Height()); + + // constrain size to page size if necessary + if ((fGrfWH != 0.F) && (fGrfWH < fWinWH)) + { + aSize.setWidth( static_cast<::tools::Long>(aPageSize.Height() * fGrfWH) ); + aSize.setHeight( aPageSize.Height() ); + } + else + { + aSize.setWidth( aPageSize.Width() ); + aSize.setHeight( static_cast<::tools::Long>(aPageSize.Width() / fGrfWH) ); + } + } + + // set output rectangle for graphic + Point aPnt ((aPageSize.Width() - aSize.Width()) / 2, + (aPageSize.Height() - aSize.Height()) / 2); + aPnt += Point(pPage->GetLeftBorder(), pPage->GetUpperBorder()); + ::tools::Rectangle aRect (aPnt, aSize); + + rtl::Reference<SdrGrafObj> pGrafObj; + + bool bInsertNewObject = true; + + if ( mpDrawView->AreObjectsMarked() ) + { + // is there an empty graphic object? + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + + if (rMarkList.GetMarkCount() == 1) + { + SdrMark* pMark = rMarkList.GetMark(0); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + + if (pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::Graphic) + { + pGrafObj = static_cast<SdrGrafObj*>(pObj); + + if( pGrafObj->IsEmptyPresObj() ) + { + // the empty graphic object gets a new graphic + bInsertNewObject = false; + + rtl::Reference<SdrGrafObj> pNewGrafObj(SdrObject::Clone(*pGrafObj, pGrafObj->getSdrModelFromSdrObject())); + pNewGrafObj->SetEmptyPresObj(false); + pNewGrafObj->SetOutlinerParaObject(std::nullopt); + pNewGrafObj->SetGraphic(aGraphic); + + OUString aStr = mpDrawView->GetDescriptionOfMarkedObjects() + + " " + SdResId(STR_UNDO_REPLACE); + mpDrawView->BegUndo(aStr); + SdrPageView* pPV = mpDrawView->GetSdrPageView(); + mpDrawView->ReplaceObjectAtView(pGrafObj.get(), *pPV, pNewGrafObj.get()); + mpDrawView->EndUndo(); + } + } + } + } + + if( bInsertNewObject ) + { + pGrafObj = new SdrGrafObj( + GetView()->getSdrModelFromSdrView(), + aGraphic, + aRect); + SdrPageView* pPV = mpDrawView->GetSdrPageView(); + mpDrawView->InsertObjectAtView(pGrafObj.get(), *pPV, SdrInsertFlags::SETDEFLAYER); + } + } + // insert sound + else if( nType == css::gallery::GalleryItemType::MEDIA ) + { + const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, pGalleryItem->GetURL() ); + GetViewFrame()->GetDispatcher()->ExecuteList(SID_INSERT_AVMEDIA, + SfxCallMode::SYNCHRON, { &aMediaURLItem }); + } + + GetDocSh()->SetWaitCursor( false ); +} + +/** + * Edit macros for attribute configuration + */ + +/* the work flow to adjust the attributes is nearly everywhere the same + 1. read existing attributes + 2. read parameter from the basic-set + 3. delete selected item from the attribute-set + 4. create new attribute-item + 5. insert item into set */ +void DrawViewShell::AttrExec (SfxRequest &rReq) +{ + // nothing is executed during a slide show! + if(HasCurrentFunction(SID_PRESENTATION)) + return; + + CheckLineTo (rReq); + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + SfxItemSet aAttr( GetDoc()->GetPool() ); + + GetView()->GetAttributes( aAttr ); + const SfxItemSet* pArgs = rReq.GetArgs(); + + switch (rReq.GetSlot ()) + { + // set new fill-style + case SID_SETFILLSTYLE : + if (pArgs && pArgs->Count () == 1) + { + const SfxUInt32Item* pFillStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE); + if (CHECK_RANGE (drawing::FillStyle_NONE, static_cast<drawing::FillStyle>(pFillStyle->GetValue ()), drawing::FillStyle_BITMAP)) + { + aAttr.ClearItem (XATTR_FILLSTYLE); + XFillStyleItem aStyleItem(static_cast<drawing::FillStyle>(pFillStyle->GetValue ())); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put (aStyleItem); + rBindings.Invalidate (SID_ATTR_FILL_STYLE); + rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE); + } +#if HAVE_FEATURE_SCRIPTING + else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE); +#endif + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + // determine new line style + case SID_SETLINESTYLE : + if (pArgs && pArgs->Count () == 1) + { + const SfxUInt32Item* pLineStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE); + if (CHECK_RANGE (sal_Int32(drawing::LineStyle_NONE), static_cast<sal_Int32>(pLineStyle->GetValue()), sal_Int32(drawing::LineStyle_DASH))) + { + aAttr.ClearItem (XATTR_LINESTYLE); + XLineStyleItem aStyleItem(static_cast<drawing::LineStyle>(pLineStyle->GetValue())); + aStyleItem.SetWhich(XATTR_LINESTYLE); + aAttr.Put(aStyleItem); + rBindings.Invalidate (SID_ATTR_LINE_STYLE); + } +#if HAVE_FEATURE_SCRIPTING + else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE); +#endif + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + // set line width + case SID_SETLINEWIDTH : + if (pArgs && pArgs->Count () == 1) + { + const SfxUInt32Item* pLineWidth = rReq.GetArg<SfxUInt32Item>(ID_VAL_WIDTH); + aAttr.ClearItem (XATTR_LINEWIDTH); + XLineWidthItem aWidthItem(pLineWidth->GetValue()); + aWidthItem.SetWhich(XATTR_LINEWIDTH); + aAttr.Put(aWidthItem); + rBindings.Invalidate (SID_ATTR_LINE_WIDTH); + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + case SID_SETFILLCOLOR : + if (pArgs && pArgs->Count () == 3) + { + const SfxUInt32Item* pRed = rReq.GetArg<SfxUInt32Item>(ID_VAL_RED); + const SfxUInt32Item* pGreen = rReq.GetArg<SfxUInt32Item>(ID_VAL_GREEN); + const SfxUInt32Item* pBlue = rReq.GetArg<SfxUInt32Item>(ID_VAL_BLUE); + + aAttr.ClearItem (XATTR_FILLCOLOR); + aAttr.ClearItem (XATTR_FILLSTYLE); + XFillColorItem aColorItem(-1, Color (static_cast<sal_uInt8>(pRed->GetValue ()), + static_cast<sal_uInt8>(pGreen->GetValue ()), + static_cast<sal_uInt8>(pBlue->GetValue ()))); + aColorItem.SetWhich(XATTR_FILLCOLOR); + aAttr.Put(aColorItem); + rBindings.Invalidate (SID_ATTR_FILL_COLOR); + rBindings.Invalidate (SID_ATTR_PAGE_COLOR); + rBindings.Invalidate (SID_ATTR_FILL_STYLE); + rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE); + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + case SID_SETLINECOLOR : + if (pArgs && pArgs->Count () == 3) + { + const SfxUInt32Item* pRed = rReq.GetArg<SfxUInt32Item>(ID_VAL_RED); + const SfxUInt32Item* pGreen = rReq.GetArg<SfxUInt32Item>(ID_VAL_GREEN); + const SfxUInt32Item* pBlue = rReq.GetArg<SfxUInt32Item>(ID_VAL_BLUE); + + aAttr.ClearItem (XATTR_LINECOLOR); + XLineColorItem aColorItem(-1, Color(static_cast<sal_uInt8>(pRed->GetValue()), + static_cast<sal_uInt8>(pGreen->GetValue()), + static_cast<sal_uInt8>(pBlue->GetValue()))); + aColorItem.SetWhich(XATTR_LINECOLOR); + aAttr.Put(aColorItem); + rBindings.Invalidate (SID_ATTR_LINE_COLOR); + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + case SID_SETGRADSTARTCOLOR : + case SID_SETGRADENDCOLOR : + if (pArgs && pArgs->Count () == 4) + { + const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX); + const SfxUInt32Item* pRed = rReq.GetArg<SfxUInt32Item>(ID_VAL_RED); + const SfxUInt32Item* pGreen = rReq.GetArg<SfxUInt32Item>(ID_VAL_GREEN); + const SfxUInt32Item* pBlue = rReq.GetArg<SfxUInt32Item>(ID_VAL_BLUE); + assert(pName && pRed && pGreen && pBlue && "must be present"); + + XGradientListRef pGradientList = GetDoc()->GetGradientList (); + ::tools::Long nCounts = pGradientList->Count (); + Color aColor (static_cast<sal_uInt8>(pRed->GetValue ()), + static_cast<sal_uInt8>(pGreen->GetValue ()), + static_cast<sal_uInt8>(pBlue->GetValue ())); + ::tools::Long i; + + aAttr.ClearItem (XATTR_FILLGRADIENT); + aAttr.ClearItem (XATTR_FILLSTYLE); + + for ( i = 0; i < nCounts; i ++) + { + const XGradientEntry* pEntry = pGradientList->GetGradient(i); + + if (pEntry->GetName () == pName->GetValue ()) + { + basegfx::BGradient aGradient(pEntry->GetGradient()); + basegfx::BColorStops aNewColorStops(aGradient.GetColorStops()); + + if (SID_SETGRADSTARTCOLOR == rReq.GetSlot ()) + { + aNewColorStops.replaceStartColor(aColor.getBColor()); + } + else + { + aNewColorStops.replaceEndColor(aColor.getBColor()); + } + + aGradient.SetColorStops(aNewColorStops); + + XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillGradientItem aGradientItem(pName->GetValue (), aGradient); + aGradientItem.SetWhich(XATTR_FILLGRADIENT); + aAttr.Put(aGradientItem); + break; + } + } + + if (i >= nCounts) + { + Color aBlack (0, 0, 0); + basegfx::BGradient aGradient ( + basegfx::BColorStops( + (rReq.GetSlot () == SID_SETGRADSTARTCOLOR) + ? aColor.getBColor() + : aBlack.getBColor(), + (rReq.GetSlot () == SID_SETGRADENDCOLOR) + ? aColor.getBColor() + : aBlack.getBColor())); + + GetDoc()->GetGradientList()->Insert(std::make_unique<XGradientEntry>(aGradient, pName->GetValue())); + + XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillGradientItem aGradientItem(pName->GetValue(), aGradient); + aGradientItem.SetWhich(XATTR_FILLGRADIENT); + aAttr.Put(aGradientItem); + } + + rBindings.Invalidate (SID_ATTR_FILL_STYLE); + rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE); + rBindings.Invalidate (SID_ATTR_FILL_GRADIENT); + rBindings.Invalidate (SID_ATTR_PAGE_GRADIENT); + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + case SID_SETHATCHCOLOR : + if (pArgs && pArgs->Count () == 4) + { + const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX); + const SfxUInt32Item* pRed = rReq.GetArg<SfxUInt32Item>(ID_VAL_RED); + const SfxUInt32Item* pGreen = rReq.GetArg<SfxUInt32Item>(ID_VAL_GREEN); + const SfxUInt32Item* pBlue = rReq.GetArg<SfxUInt32Item>(ID_VAL_BLUE); + assert(pName && pRed && pGreen && pBlue && "must be present"); + + XHatchListRef pHatchList = GetDoc()->GetHatchList (); + ::tools::Long nCounts = pHatchList->Count (); + Color aColor (static_cast<sal_uInt8>(pRed->GetValue ()), + static_cast<sal_uInt8>(pGreen->GetValue ()), + static_cast<sal_uInt8>(pBlue->GetValue ())); + ::tools::Long i; + + aAttr.ClearItem (XATTR_FILLHATCH); + aAttr.ClearItem (XATTR_FILLSTYLE); + + for ( i = 0; i < nCounts; i ++) + { + const XHatchEntry* pEntry = pHatchList->GetHatch(i); + + if (pEntry->GetName () == pName->GetValue ()) + { + XHatch aHatch(pEntry->GetHatch()); + + aHatch.SetColor (aColor); + + XFillStyleItem aStyleItem(drawing::FillStyle_HATCH); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillHatchItem aHatchItem(pName->GetValue(), aHatch); + aHatchItem.SetWhich(XATTR_FILLHATCH); + aAttr.Put(aHatchItem); + break; + } + } + + if (i >= nCounts) + { + XHatch aHatch (aColor); + + GetDoc()->GetHatchList()->Insert(std::make_unique<XHatchEntry>(aHatch, pName->GetValue())); + + XFillStyleItem aStyleItem(drawing::FillStyle_HATCH); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillHatchItem aHatchItem(pName->GetValue (), aHatch); + aHatchItem.SetWhich(XATTR_FILLHATCH); + aAttr.Put(aHatchItem); + } + + rBindings.Invalidate (SID_ATTR_FILL_HATCH); + rBindings.Invalidate (SID_ATTR_PAGE_HATCH); + rBindings.Invalidate (SID_ATTR_FILL_STYLE); + rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE); + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + // configuration for line-dash + case SID_DASH : + if (pArgs && pArgs->Count () == 7) + { + const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX); + const SfxUInt32Item* pStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE); + const SfxUInt32Item* pDots = rReq.GetArg<SfxUInt32Item>(ID_VAL_DOTS); + const SfxUInt32Item* pDotLen = rReq.GetArg<SfxUInt32Item>(ID_VAL_DOTLEN); + const SfxUInt32Item* pDashes = rReq.GetArg<SfxUInt32Item>(ID_VAL_DASHES); + const SfxUInt32Item* pDashLen = rReq.GetArg<SfxUInt32Item>(ID_VAL_DASHLEN); + const SfxUInt32Item* pDistance = rReq.GetArg<SfxUInt32Item>(ID_VAL_DISTANCE); + assert(pName && pStyle && pDots && pDotLen && pDashes && pDashLen && pDistance && "must be present"); + + if (CHECK_RANGE (sal_Int32(css::drawing::DashStyle_RECT), static_cast<sal_Int32>(pStyle->GetValue()), sal_Int32(css::drawing::DashStyle_ROUNDRELATIVE))) + { + XDash aNewDash (static_cast<css::drawing::DashStyle>(pStyle->GetValue ()), static_cast<short>(pDots->GetValue ()), pDotLen->GetValue (), + static_cast<short>(pDashes->GetValue ()), pDashLen->GetValue (), pDistance->GetValue ()); + + aAttr.ClearItem (XATTR_LINEDASH); + aAttr.ClearItem (XATTR_LINESTYLE); + + XDashListRef pDashList = GetDoc()->GetDashList(); + ::tools::Long nCounts = pDashList->Count (); + std::unique_ptr<XDashEntry> pEntry = std::make_unique<XDashEntry>(aNewDash, pName->GetValue()); + ::tools::Long i; + + for ( i = 0; i < nCounts; i++ ) + if (pDashList->GetDash (i)->GetName () == pName->GetValue ()) + break; + + if (i < nCounts) + pDashList->Replace(std::move(pEntry), i); + else + pDashList->Insert(std::move(pEntry)); + + XLineDashItem aDashItem(pName->GetValue(), aNewDash); + aDashItem.SetWhich(XATTR_LINEDASH); + aAttr.Put(aDashItem); + XLineStyleItem aStyleItem(drawing::LineStyle_DASH); + aStyleItem.SetWhich(XATTR_LINESTYLE); + aAttr.Put(aStyleItem); + rBindings.Invalidate (SID_ATTR_LINE_DASH); + rBindings.Invalidate (SID_ATTR_FILL_STYLE); + } +#if HAVE_FEATURE_SCRIPTING + else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE); +#endif + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + // configuration for gradients + case SID_GRADIENT : + if (pArgs && pArgs->Count () == 8) + { + const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX); + const SfxUInt32Item* pStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE); + const SfxUInt32Item* pAngle = rReq.GetArg<SfxUInt32Item>(ID_VAL_ANGLE); + const SfxUInt32Item* pBorder = rReq.GetArg<SfxUInt32Item>(ID_VAL_BORDER); + const SfxUInt32Item* pCenterX = rReq.GetArg<SfxUInt32Item>(ID_VAL_CENTER_X); + const SfxUInt32Item* pCenterY = rReq.GetArg<SfxUInt32Item>(ID_VAL_CENTER_Y); + const SfxUInt32Item* pStart = rReq.GetArg<SfxUInt32Item>(ID_VAL_STARTINTENS); + const SfxUInt32Item* pEnd = rReq.GetArg<SfxUInt32Item>(ID_VAL_ENDINTENS); + assert(pName && pStyle && pAngle && pBorder && pCenterX && pCenterY && pStart && pEnd && "must be present"); + + if (CHECK_RANGE (sal_Int32(css::awt::GradientStyle_LINEAR), static_cast<sal_Int32>(pStyle->GetValue()), sal_Int32(css::awt::GradientStyle_RECT)) && + CHECK_RANGE (0, static_cast<sal_Int32>(pAngle->GetValue ()), 360) && + CHECK_RANGE (0, static_cast<sal_Int32>(pBorder->GetValue ()), 100) && + CHECK_RANGE (0, static_cast<sal_Int32>(pCenterX->GetValue ()), 100) && + CHECK_RANGE (0, static_cast<sal_Int32>(pCenterY->GetValue ()), 100) && + CHECK_RANGE (0, static_cast<sal_Int32>(pStart->GetValue ()), 100) && + CHECK_RANGE (0, static_cast<sal_Int32>(pEnd->GetValue ()), 100)) + { + aAttr.ClearItem (XATTR_FILLGRADIENT); + aAttr.ClearItem (XATTR_FILLSTYLE); + + XGradientListRef pGradientList = GetDoc()->GetGradientList (); + ::tools::Long nCounts = pGradientList->Count (); + ::tools::Long i; + + for ( i = 0; i < nCounts; i++ ) + { + const XGradientEntry* pEntry = pGradientList->GetGradient(i); + + if (pEntry->GetName () == pName->GetValue ()) + { + basegfx::BGradient aGradient(pEntry->GetGradient()); + + aGradient.SetGradientStyle (static_cast<css::awt::GradientStyle>(pStyle->GetValue ())); + aGradient.SetAngle (Degree10(pAngle->GetValue () * 10)); + aGradient.SetBorder (static_cast<short>(pBorder->GetValue ())); + aGradient.SetXOffset (static_cast<short>(pCenterX->GetValue ())); + aGradient.SetYOffset (static_cast<short>(pCenterY->GetValue ())); + aGradient.SetStartIntens (static_cast<short>(pStart->GetValue ())); + aGradient.SetEndIntens (static_cast<short>(pEnd->GetValue ())); + + XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillGradientItem aGradientItem(pName->GetValue (), aGradient); + aGradientItem.SetWhich(XATTR_FILLGRADIENT); + aAttr.Put(aGradientItem); + break; + } + } + + if (i >= nCounts) + { + Color aBlack (0, 0, 0); + basegfx::BGradient aGradient ( + basegfx::BColorStops(aBlack.getBColor(), aBlack.getBColor()), + static_cast<css::awt::GradientStyle>(pStyle->GetValue ()), + Degree10(pAngle->GetValue () * 10), static_cast<short>(pCenterX->GetValue ()), + static_cast<short>(pCenterY->GetValue ()), static_cast<short>(pBorder->GetValue ()), + static_cast<short>(pStart->GetValue ()), static_cast<short>(pEnd->GetValue ())); + + pGradientList->Insert(std::make_unique<XGradientEntry>(aGradient, pName->GetValue())); + XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillGradientItem aGradientItem(pName->GetValue (), aGradient); + aGradientItem.SetWhich(XATTR_FILLGRADIENT); + aAttr.Put(aGradientItem); + } + + rBindings.Invalidate (SID_ATTR_FILL_GRADIENT); + rBindings.Invalidate (SID_ATTR_PAGE_GRADIENT); + rBindings.Invalidate (SID_ATTR_FILL_STYLE); + rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE); + } +#if HAVE_FEATURE_SCRIPTING + else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE); +#endif + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + // configuration for hatch + case SID_HATCH : + if (pArgs && pArgs->Count () == 4) + { + const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX); + const SfxUInt32Item* pStyle = rReq.GetArg<SfxUInt32Item>(ID_VAL_STYLE); + const SfxUInt32Item* pDistance = rReq.GetArg<SfxUInt32Item>(ID_VAL_DISTANCE); + const SfxUInt32Item* pAngle = rReq.GetArg<SfxUInt32Item>(ID_VAL_ANGLE); + assert(pName && pStyle && pDistance && pAngle && "must be present"); + + if (CHECK_RANGE (sal_Int32(css::drawing::HatchStyle_SINGLE), static_cast<sal_Int32>(pStyle->GetValue()), sal_Int32(css::drawing::HatchStyle_TRIPLE)) && + CHECK_RANGE (0, static_cast<sal_Int32>(pAngle->GetValue ()), 360)) + { + aAttr.ClearItem (XATTR_FILLHATCH); + aAttr.ClearItem (XATTR_FILLSTYLE); + + XHatchListRef pHatchList = GetDoc()->GetHatchList (); + ::tools::Long nCounts = pHatchList->Count (); + ::tools::Long i; + + for ( i = 0; i < nCounts; i++ ) + { + const XHatchEntry* pEntry = pHatchList->GetHatch(i); + + if (pEntry->GetName () == pName->GetValue ()) + { + XHatch aHatch(pEntry->GetHatch()); + + aHatch.SetHatchStyle (static_cast<css::drawing::HatchStyle>(pStyle->GetValue ())); + aHatch.SetDistance (pDistance->GetValue ()); + aHatch.SetAngle (Degree10(pAngle->GetValue () * 10)); + + XFillStyleItem aStyleItem(drawing::FillStyle_HATCH); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillHatchItem aHatchItem(pName->GetValue (), aHatch); + aHatchItem.SetWhich(XATTR_FILLHATCH); + aAttr.Put(aHatchItem); + break; + } + } + + if (i >= nCounts) + { + XHatch aHatch (Color(0), static_cast<css::drawing::HatchStyle>(pStyle->GetValue ()), pDistance->GetValue (), + Degree10(pAngle->GetValue () * 10)); + + pHatchList->Insert(std::make_unique<XHatchEntry>(aHatch, pName->GetValue())); + XFillStyleItem aStyleItem(drawing::FillStyle_HATCH); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillHatchItem aHatchItem(pName->GetValue (), aHatch); + aHatchItem.SetWhich(XATTR_FILLHATCH); + aAttr.Put(aHatchItem); + } + + rBindings.Invalidate (SID_ATTR_FILL_HATCH); + rBindings.Invalidate (SID_ATTR_FILL_STYLE); + } +#if HAVE_FEATURE_SCRIPTING + else StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE); +#endif + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + case SID_SELECTGRADIENT : + if (pArgs && (pArgs->Count() == 1)) + { + const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX); + assert(pName && "must be present"); + + XGradientListRef pGradientList = GetDoc()->GetGradientList (); + ::tools::Long nCounts = pGradientList->Count (); + + for (::tools::Long i = 0; i < nCounts; i ++) + { + const XGradientEntry* pEntry = pGradientList->GetGradient(i); + + if (pEntry->GetName () == pName->GetValue ()) + { + aAttr.ClearItem (XATTR_FILLGRADIENT); + aAttr.ClearItem (XATTR_FILLSTYLE); + XFillStyleItem aStyleItem(drawing::FillStyle_GRADIENT); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillGradientItem aGradientItem(pName->GetValue (), pEntry->GetGradient ()); + aGradientItem.SetWhich(XATTR_FILLGRADIENT); + aAttr.Put(aGradientItem); + rBindings.Invalidate (SID_ATTR_FILL_GRADIENT); + rBindings.Invalidate (SID_ATTR_PAGE_GRADIENT); + rBindings.Invalidate (SID_ATTR_FILL_STYLE); + rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE); + break; + } + } + + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + case SID_SELECTHATCH : + if (pArgs && pArgs->Count() == 1) + { + const SfxStringItem* pName = rReq.GetArg<SfxStringItem>(ID_VAL_INDEX); + assert(pName && "must be present"); + + XHatchListRef pHatchList = GetDoc()->GetHatchList (); + ::tools::Long nCounts = pHatchList->Count (); + + for (::tools::Long i = 0; i < nCounts; i ++) + { + const XHatchEntry* pEntry = pHatchList->GetHatch(i); + + if (pEntry->GetName () == pName->GetValue ()) + { + aAttr.ClearItem (XATTR_FILLHATCH); + aAttr.ClearItem (XATTR_FILLSTYLE); + XFillStyleItem aStyleItem(drawing::FillStyle_HATCH); + aStyleItem.SetWhich(XATTR_FILLSTYLE); + aAttr.Put(aStyleItem); + XFillHatchItem aHatchItem(pName->GetValue (), pEntry->GetHatch ()); + aHatchItem.SetWhich(XATTR_FILLHATCH); + aAttr.Put(aHatchItem); + + rBindings.Invalidate (SID_ATTR_FILL_HATCH); + rBindings.Invalidate (SID_ATTR_PAGE_HATCH); + rBindings.Invalidate (SID_ATTR_FILL_STYLE); + rBindings.Invalidate (SID_ATTR_PAGE_FILLSTYLE); + break; + } + } + + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + + case SID_UNSELECT : + mpDrawView->UnmarkAll (); + break; + + case SID_GETRED : + if (pArgs && pArgs->Count () == 1) + { + break; + } +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + break; + +/* case SID_SETFONTFAMILYNAME : + case SID_SETFONTSTYLENAME : + case SID_SETFONTFAMILY : + case SID_SETFONTPITCH : + case SID_SETFONTCHARSET : + case SID_SETFONTPOSTURE : + case SID_SETFONTWEIGHT : + case SID_SETFONTUNDERLINE : + case SID_SETFONTCROSSEDOUT : + case SID_SETFONTSHADOWED : + case SID_SETFONTCONTOUR : + case SID_SETFONTCOLOR : + case SID_SETFONTLANGUAGE : + case SID_SETFONTWORDLINE : + case SID_SETFONTCASEMAP : + case SID_SETFONTESCAPE : + case SID_SETFONTKERNING : + break;*/ + + default : + ; + } + + mpDrawView->SetAttributes (const_cast<const SfxItemSet &>(aAttr)); + rReq.Ignore (); +} + +/** + * Edit macros for attribute configuration + */ +void DrawViewShell::AttrState (SfxItemSet& rSet) +{ + SfxWhichIter aIter (rSet); + sal_uInt16 nWhich = aIter.FirstWhich (); + SfxItemSet aAttr( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttr ); + + while (nWhich) + { + switch (nWhich) + { + case SID_GETFILLSTYLE : + { + const XFillStyleItem &rFillStyleItem = aAttr.Get (XATTR_FILLSTYLE); + + rSet.Put (SfxUInt32Item (nWhich, static_cast<::tools::Long>(rFillStyleItem.GetValue ()))); + break; + } + + case SID_GETLINESTYLE : + { + const XLineStyleItem &rLineStyleItem = aAttr.Get (XATTR_LINESTYLE); + + rSet.Put (SfxUInt32Item (nWhich, static_cast<::tools::Long>(rLineStyleItem.GetValue ()))); + break; + } + + case SID_GETLINEWIDTH : + { + const XLineWidthItem &rLineWidthItem = aAttr.Get (XATTR_LINEWIDTH); + + rSet.Put (SfxUInt32Item (nWhich, static_cast<::tools::Long>(rLineWidthItem.GetValue ()))); + break; + } + + case SID_GETGREEN : + case SID_GETRED : + case SID_GETBLUE : + { + const SfxUInt32Item &rWhatKind = static_cast<const SfxUInt32Item &>( rSet.Get (ID_VAL_WHATKIND) ); + Color aColor; + + switch (rWhatKind.GetValue ()) + { + case 1 : + { + const XLineColorItem &rLineColorItem = aAttr.Get (XATTR_LINECOLOR); + + aColor = rLineColorItem.GetColorValue (); + break; + } + + case 2 : + { + const XFillColorItem &rFillColorItem = aAttr.Get (XATTR_FILLCOLOR); + + aColor = rFillColorItem.GetColorValue (); + break; + } + + case 3 : + case 4 : + { + const XFillGradientItem &rFillGradientItem = aAttr.Get (XATTR_FILLGRADIENT); + const basegfx::BGradient &rGradient = rFillGradientItem.GetGradientValue (); + + aColor = (rWhatKind.GetValue () == 3) + ? Color(rGradient.GetColorStops().front().getStopColor()) + : Color(rGradient.GetColorStops().back().getStopColor()); + break; + } + + case 5: + { + const XFillHatchItem &rFillHatchItem = aAttr.Get (XATTR_FILLHATCH); + const XHatch &rHatch = rFillHatchItem.GetHatchValue (); + + aColor = rHatch.GetColor (); + break; + } + + default : + ; + } + + rSet.Put (SfxUInt32Item (nWhich, static_cast<::tools::Long>((nWhich == SID_GETRED) + ? aColor.GetRed () + : (nWhich == SID_GETGREEN) + ? aColor.GetGreen () + : aColor.GetBlue ()))); + break; + } + + default : + ; + } + + nWhich = aIter.NextWhich (); + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsa.cxx b/sd/source/ui/view/drviewsa.cxx new file mode 100644 index 0000000000..5d5cfe6132 --- /dev/null +++ b/sd/source/ui/view/drviewsa.cxx @@ -0,0 +1,873 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> +#include <com/sun/star/scanner/ScannerManager.hpp> +#include <cppuhelper/implbase.hxx> +#include <comphelper/processfactory.hxx> +#include <editeng/sizeitem.hxx> +#include <svx/svdlayer.hxx> +#include <svx/svdograf.hxx> +#include <sfx2/zoomitem.hxx> +#include <sfx2/lokhelper.hxx> +#include <svx/svdpagv.hxx> +#include <svl/ptitem.hxx> +#include <svl/stritem.hxx> +#include <sfx2/request.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/zoomslideritem.hxx> +#include <svl/eitem.hxx> + +#include <sdcommands.h> +#include <svx/f3dchild.hxx> +#include <svx/clipfmtitem.hxx> + +#include <sfx2/viewfrm.hxx> +#include <svtools/cliplistener.hxx> +#include <svx/float3d.hxx> +#include <svx/extedit.hxx> +#include <svx/sidebar/SelectionAnalyzer.hxx> +#include <svx/sidebar/SelectionChangeHandler.hxx> +#include <helpids.h> + +#include <view/viewoverlaymanager.hxx> +#include <app.hrc> +#include <strings.hrc> +#include <sdmod.hxx> +#include <sdpage.hxx> +#include <FrameView.hxx> +#include <drawdoc.hxx> +#include <sdresid.hxx> +#include <DrawDocShell.hxx> +#include <Window.hxx> +#include <fupoor.hxx> +#include <fusel.hxx> +#include <funavig.hxx> +#include <drawview.hxx> +#include <SdUnoDrawView.hxx> +#include <ViewShellBase.hxx> +#include <slideshow.hxx> +#include <annotationmanager.hxx> +#include <DrawController.hxx> +#include <unomodel.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/lok.hxx> +#include <comphelper/servicehelper.hxx> +#include <LayerTabBar.hxx> + +#include <memory> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using vcl::EnumContext; + +namespace sd { + +bool DrawViewShell::mbPipette = false; + +namespace { + +class ScannerEventListener : public ::cppu::WeakImplHelper< lang::XEventListener > +{ +private: + + DrawViewShell* mpParent; + +public: + + explicit ScannerEventListener( DrawViewShell* pParent ) : mpParent( pParent ) {} + + // XEventListener + virtual void SAL_CALL disposing( const lang::EventObject& rEventObject ) override; + + void ParentDestroyed() { mpParent = nullptr; } +}; + +} + +void SAL_CALL ScannerEventListener::disposing( const lang::EventObject& /*rEventObject*/ ) +{ + if( mpParent ) + mpParent->ScannerEvent(); +} + +DrawViewShell::DrawViewShell( ViewShellBase& rViewShellBase, vcl::Window* pParentWindow, PageKind ePageKind, FrameView* pFrameViewArgument ) + : ViewShell (pParentWindow, rViewShellBase) + , maTabControl(VclPtr<sd::TabControl>::Create(this, pParentWindow)) + , mbIsLayerModeActive(false) + , mbIsInSwitchPage(false) + , mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler( + [this] () { return this->GetSidebarContextName(); }, + uno::Reference<frame::XController>(rViewShellBase.GetDrawController()), + vcl::EnumContext::Context::Default)) + , mbMouseButtonDown(false) + , mbMouseSelecting(false) +{ + if (pFrameViewArgument != nullptr) + mpFrameView = pFrameViewArgument; + else + mpFrameView = new FrameView(GetDoc()); + Construct(GetDocSh(), ePageKind); + + mpSelectionChangeHandler->Connect(); + + SetContextName(GetSidebarContextName()); + + doShow(); + + ConfigureAppBackgroundColor(); + SD_MOD()->GetColorConfig().AddListener(this); + maViewOptions.mnDocBackgroundColor = SD_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; + + if (comphelper::LibreOfficeKit::isActive()) + { + SdXImpressDocument* pModel = comphelper::getFromUnoTunnel<SdXImpressDocument>(rViewShellBase.GetCurrentDocument()); + SfxLokHelper::notifyViewRenderState(&rViewShellBase, pModel); + } +} + +DrawViewShell::~DrawViewShell() +{ + suppress_fun_call_w_exception(ImplDestroy()); +} + +void DrawViewShell::ImplDestroy() +{ + SD_MOD()->GetColorConfig().RemoveListener(this); + + mpSelectionChangeHandler->Disconnect(); + + mpAnnotationManager.reset(); + mpViewOverlayManager.reset(); + + OSL_ASSERT (GetViewShell()!=nullptr); + + if( mxScannerListener.is() ) + static_cast< ScannerEventListener* >( mxScannerListener.get() )->ParentDestroyed(); + + // Remove references to items within Svx3DWin + // (maybe do a listening sometime in Svx3DWin) + sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId(); + SfxChildWindow* pWindow = GetViewFrame() ? GetViewFrame()->GetChildWindow(nId) : nullptr; + if(pWindow) + { + Svx3DWin* p3DWin = static_cast< Svx3DWin* > (pWindow->GetWindow()); + if(p3DWin) + p3DWin->DocumentReload(); + } + + EndListening (*GetDoc()); + EndListening (*GetDocSh()); + + if( SlideShow::IsRunning(*this) ) + StopSlideShow(); + + DisposeFunctions(); + + sal_uInt16 aPageCnt = GetDoc()->GetSdPageCount(mePageKind); + + for (sal_uInt16 i = 0; i < aPageCnt; i++) + { + SdPage* pPage = GetDoc()->GetSdPage(i, mePageKind); + + if (pPage == mpActualPage) + { + GetDoc()->SetSelected(pPage, true); + } + else + { + GetDoc()->SetSelected(pPage, false); + } + } + + if ( mxClipEvtLstnr.is() ) + { + mxClipEvtLstnr->RemoveListener( GetActiveWindow() ); + mxClipEvtLstnr->ClearCallbackLink(); // prevent callback if another thread is waiting + mxClipEvtLstnr.clear(); + } + + mpDrawView.reset(); + // Set mpView to NULL so that the destructor of the ViewShell base class + // does not access it. + mpView = nullptr; + + mpFrameView->Disconnect(); + maTabControl.disposeAndClear(); +} + +/** + * common part of both constructors + */ +void DrawViewShell::Construct(DrawDocShell* pDocSh, PageKind eInitialPageKind) +{ + mpActualPage = nullptr; + mbReadOnly = GetDocSh()->IsReadOnly(); + mxClipEvtLstnr.clear(); + mbPastePossible = false; + mbIsLayerModeActive = false; + + mpFrameView->Connect(); + + OSL_ASSERT (GetViewShell()!=nullptr); + + SetPool( &GetDoc()->GetPool() ); + + GetDoc()->CreateFirstPages(); + + mpDrawView.reset( new DrawView(pDocSh, GetActiveWindow()->GetOutDev(), this) ); + mpView = mpDrawView.get(); // Pointer of base class ViewShell + mpDrawView->SetSwapAsynchron(); // Asynchronous load of graphics + + // We do not read the page kind from the frame view anymore so we have + // to set it in order to resync frame view and this view. + mpFrameView->SetPageKind(eInitialPageKind); + mePageKind = eInitialPageKind; + meEditMode = EditMode::Page; + DocumentType eDocType = GetDoc()->GetDocumentType(); // RTTI does not work here + switch (mePageKind) + { + case PageKind::Standard: + meShellType = ST_IMPRESS; + break; + + case PageKind::Notes: + meShellType = ST_NOTES; + break; + + case PageKind::Handout: + meShellType = ST_HANDOUT; + break; + } + + Size aPageSize( GetDoc()->GetSdPage(0, mePageKind)->GetSize() ); + Point aPageOrg( aPageSize.Width(), aPageSize.Height() / 2); + Size aSize(aPageSize.Width() * 3, aPageSize.Height() * 2); + InitWindows(aPageOrg, aSize, Point(-1, -1)); + + Point aVisAreaPos; + + if ( pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED ) + { + aVisAreaPos = pDocSh->GetVisArea(ASPECT_CONTENT).TopLeft(); + } + + mpDrawView->SetWorkArea(::tools::Rectangle(Point() - aVisAreaPos - aPageOrg, aSize)); + + // objects can not grow bigger than ViewSize + GetDoc()->SetMaxObjSize(aSize); + + // Split-Handler for TabControls + maTabControl->SetSplitHdl( LINK( this, DrawViewShell, TabSplitHdl ) ); + + /* In order to set the correct EditMode of the FrameView, we select another + one (small trick). */ + if (mpFrameView->GetViewShEditMode(/*mePageKind*/) == EditMode::Page) + { + meEditMode = EditMode::MasterPage; + } + else + { + meEditMode = EditMode::Page; + } + + // Use configuration of FrameView + ReadFrameViewData(mpFrameView); + + if( eDocType == DocumentType::Draw ) + { + GetActiveWindow()->SetHelpId( HID_SDGRAPHICVIEWSHELL ); + } + else + { + if (mePageKind == PageKind::Notes) + { + GetActiveWindow()->SetHelpId( CMD_SID_NOTES_MODE ); + + // AutoLayouts have to be created + GetDoc()->StopWorkStartupDelay(); + } + else if (mePageKind == PageKind::Handout) + { + GetActiveWindow()->SetHelpId( CMD_SID_HANDOUT_MASTER_MODE ); + + // AutoLayouts have to be created + GetDoc()->StopWorkStartupDelay(); + } + else + { + GetActiveWindow()->SetHelpId( HID_SDDRAWVIEWSHELL ); + } + } + + // start selection function + SfxRequest aReq(SID_OBJECT_SELECT, SfxCallMode::SLOT, GetDoc()->GetItemPool()); + FuPermanent(aReq); + mpDrawView->SetFrameDragSingles(); + + if (pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED) + { + mbZoomOnPage = false; + } + else + { + mbZoomOnPage = true; + } + + mbIsRulerDrag = false; + + SetName ("DrawViewShell"); + + mnLockCount = 0; + + uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + + try + { + mxScannerManager = scanner::ScannerManager::create( xContext ); + + mxScannerListener = new ScannerEventListener( this ); + } + catch (DeploymentException const &) + { + SAL_INFO("sd", "Scanner manager not available"); + } + catch (Exception const &) + { + // Eat the exception and log it + // We can still continue if scanner manager is not available. + DBG_UNHANDLED_EXCEPTION("sd"); + } + + mpAnnotationManager.reset( new AnnotationManager( GetViewShellBase() ) ); + mpViewOverlayManager.reset( new ViewOverlayManager( GetViewShellBase() ) ); +} + +void DrawViewShell::Init (bool bIsMainViewShell) +{ + ViewShell::Init(bIsMainViewShell); + + if (!IsListening(*GetDocSh())) + StartListening (*GetDocSh()); +} + +void DrawViewShell::Shutdown() +{ + ViewShell::Shutdown(); + + if(SlideShow::IsRunning( GetViewShellBase() ) ) + { + // Turn off effects. + GetDrawView()->SetAnimationMode(SdrAnimationMode::Disable); + } +} + +css::uno::Reference<css::drawing::XDrawSubController> DrawViewShell::CreateSubController() +{ + css::uno::Reference<css::drawing::XDrawSubController> xSubController; + + if (IsMainViewShell()) + { + // Create uno sub controller for the main view shell. + xSubController.set( new SdUnoDrawView( *this, *GetView())); + } + + return xSubController; +} + +bool DrawViewShell::RelocateToParentWindow (vcl::Window* pParentWindow) +{ + // DrawViewShells can not be relocated to a new parent window at the + // moment, so return <FALSE/> except when the given parent window is the + // parent window that is already in use. + return pParentWindow==GetParentWindow(); +} + +/** + * check if we have to draw a polyline + */ + +/* + Polylines are represented by macros as a sequence of: + MoveTo (x, y) + LineTo (x, y) [or BezierTo (x, y)] + LineTo (x, y) + : + There is no end command for polylines. Therefore, we have to test all + commands in the requests for LineTo (BezierTo) and we have to gather + the point-parameter. The first not-LineTo leads to the creation of the + polyline from the gathered points. +*/ + +void DrawViewShell::CheckLineTo(SfxRequest& rReq) +{ +#ifdef DBG_UTIL + if(rReq.IsAPI()) + { + if(SID_LINETO == rReq.GetSlot() || SID_BEZIERTO == rReq.GetSlot() || SID_MOVETO == rReq.GetSlot() ) + { + OSL_FAIL("DrawViewShell::CheckLineTo: slots SID_LINETO, SID_BEZIERTO, SID_MOVETO no longer supported."); + } + } +#endif + + rReq.Ignore (); +} + +/** + * Change page parameter if SID_PAGESIZE or SID_PAGEMARGIN + */ +void DrawViewShell::SetupPage (Size const &rSize, + ::tools::Long nLeft, + ::tools::Long nRight, + ::tools::Long nUpper, + ::tools::Long nLower, + bool bSize, + bool bMargin, + bool bScaleAll) +{ + sal_uInt16 nPageCnt = GetDoc()->GetMasterSdPageCount(mePageKind); + sal_uInt16 i; + + for (i = 0; i < nPageCnt; i++) + { + // first, handle all master pages + SdPage *pPage = GetDoc()->GetMasterSdPage(i, mePageKind); + + if( pPage ) + { + if( bSize ) + { + ::tools::Rectangle aBorderRect(nLeft, nUpper, nRight, nLower); + pPage->ScaleObjects(rSize, aBorderRect, bScaleAll); + pPage->SetSize(rSize); + + } + if( bMargin ) + { + pPage->SetLeftBorder(nLeft); + pPage->SetRightBorder(nRight); + pPage->SetUpperBorder(nUpper); + pPage->SetLowerBorder(nLower); + } + + if ( mePageKind == PageKind::Standard ) + { + GetDoc()->GetMasterSdPage(i, PageKind::Notes)->CreateTitleAndLayout(); + } + + pPage->CreateTitleAndLayout(); + } + } + + nPageCnt = GetDoc()->GetSdPageCount(mePageKind); + + for (i = 0; i < nPageCnt; i++) + { + // then, handle all pages + SdPage *pPage = GetDoc()->GetSdPage(i, mePageKind); + + if( pPage ) + { + if( bSize ) + { + ::tools::Rectangle aBorderRect(nLeft, nUpper, nRight, nLower); + pPage->ScaleObjects(rSize, aBorderRect, bScaleAll); + pPage->SetSize(rSize); + } + if( bMargin ) + { + pPage->SetLeftBorder(nLeft); + pPage->SetRightBorder(nRight); + pPage->SetUpperBorder(nUpper); + pPage->SetLowerBorder(nLower); + } + + if ( mePageKind == PageKind::Standard ) + { + SdPage* pNotesPage = GetDoc()->GetSdPage(i, PageKind::Notes); + pNotesPage->SetAutoLayout( pNotesPage->GetAutoLayout() ); + } + + pPage->SetAutoLayout( pPage->GetAutoLayout() ); + } + } + + if ( mePageKind == PageKind::Standard ) + { + SdPage* pHandoutPage = GetDoc()->GetSdPage(0, PageKind::Handout); + pHandoutPage->CreateTitleAndLayout(true); + } + + ::tools::Long nWidth = mpActualPage->GetSize().Width(); + ::tools::Long nHeight = mpActualPage->GetSize().Height(); + + Point aPageOrg(nWidth, nHeight / 2); + Size aSize( nWidth * 3, nHeight * 2); + + InitWindows(aPageOrg, aSize, Point(-1, -1), true); + + Point aVisAreaPos; + + if ( GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED ) + { + aVisAreaPos = GetDocSh()->GetVisArea(ASPECT_CONTENT).TopLeft(); + } + + GetView()->SetWorkArea(::tools::Rectangle(Point() - aVisAreaPos - aPageOrg, aSize)); + + UpdateScrollBars(); + + Point aNewOrigin(mpActualPage->GetLeftBorder(), mpActualPage->GetUpperBorder()); + GetView()->GetSdrPageView()->SetPageOrigin(aNewOrigin); + + GetViewFrame()->GetBindings().Invalidate(SID_RULER_NULL_OFFSET); + + // zoom onto (new) page size + GetViewFrame()->GetDispatcher()->Execute(SID_SIZE_PAGE, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); +} + +void DrawViewShell::GetStatusBarState(SfxItemSet& rSet) +{ + /* Zoom-Item + Here we should propagate the corresponding value (Optimal ?, page width + or page) with the help of the ZoomItems !!! */ + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_ZOOM ) ) + { + if (GetDocSh()->IsUIActive() || SlideShow::IsRunning(GetViewShellBase()) + || !GetActiveWindow()) + { + rSet.DisableItem( SID_ATTR_ZOOM ); + } + else + { + std::unique_ptr<SvxZoomItem> pZoomItem; + sal_uInt16 nZoom = static_cast<sal_uInt16>(GetActiveWindow()->GetZoom()); + + if( mbZoomOnPage ) + pZoomItem.reset(new SvxZoomItem( SvxZoomType::WHOLEPAGE, nZoom )); + else + pZoomItem.reset(new SvxZoomItem( SvxZoomType::PERCENT, nZoom )); + + // constrain area + SvxZoomEnableFlags nZoomValues = SvxZoomEnableFlags::ALL; + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + + if( pPageView && pPageView->GetObjList()->GetObjCount() == 0 ) + { + nZoomValues &= ~SvxZoomEnableFlags::OPTIMAL; + } + + pZoomItem->SetValueSet( nZoomValues ); + rSet.Put( std::move(pZoomItem) ); + } + } + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_ZOOMSLIDER ) ) + { + rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetDoc() ) ); + if (GetDocSh()->IsUIActive() || (xSlideshow.is() && xSlideshow->isRunning()) || !GetActiveWindow() ) + { + rSet.DisableItem( SID_ATTR_ZOOMSLIDER ); + } + else + { + sd::Window * pActiveWindow = GetActiveWindow(); + SvxZoomSliderItem aZoomItem( static_cast<sal_uInt16>(pActiveWindow->GetZoom()), static_cast<sal_uInt16>(pActiveWindow->GetMinZoom()), static_cast<sal_uInt16>(pActiveWindow->GetMaxZoom()) ) ; + + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + if( pPageView ) + { + Point aPagePos(0, 0); + Size aPageSize = pPageView->GetPage()->GetSize(); + + aPagePos.AdjustX(aPageSize.Width() / 2 ); + aPageSize.setWidth( static_cast<::tools::Long>(aPageSize.Width() * 1.03) ); + + aPagePos.AdjustY(aPageSize.Height() / 2 ); + aPageSize.setHeight( static_cast<::tools::Long>(aPageSize.Height() * 1.03) ); + aPagePos.AdjustY( -(aPageSize.Height() / 2) ); + + aPagePos.AdjustX( -(aPageSize.Width() / 2) ); + + ::tools::Rectangle aFullPageZoomRect( aPagePos, aPageSize ); + aZoomItem.AddSnappingPoint( pActiveWindow->GetZoomForRect( aFullPageZoomRect ) ); + } + aZoomItem.AddSnappingPoint(100); + rSet.Put( aZoomItem ); + } + } + + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + if (pPageView) + { + Point aPos = GetActiveWindow()->PixelToLogic(maMousePos); + pPageView->LogicToPagePos(aPos); + Fraction aUIScale(GetDoc()->GetUIScale()); + aPos.setX( ::tools::Long(aPos.X() / aUIScale) ); + aPos.setY( ::tools::Long(aPos.Y() / aUIScale) ); + + // position- and size items + if ( mpDrawView->IsAction() ) + { + ::tools::Rectangle aRect; + mpDrawView->TakeActionRect( aRect ); + + if ( aRect.IsEmpty() ) + rSet.Put( SfxPointItem(SID_ATTR_POSITION, aPos) ); + else + { + pPageView->LogicToPagePos(aRect); + aPos = aRect.TopLeft(); + aPos.setX( ::tools::Long(aPos.X() / aUIScale) ); + aPos.setY( ::tools::Long(aPos.Y() / aUIScale) ); + rSet.Put( SfxPointItem( SID_ATTR_POSITION, aPos) ); + Size aSize( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() ); + aSize.setHeight( ::tools::Long(aSize.Height() / aUIScale) ); + aSize.setWidth( ::tools::Long(aSize.Width() / aUIScale) ); + rSet.Put( SvxSizeItem( SID_ATTR_SIZE, aSize) ); + } + } + else + { + if ( mpDrawView->AreObjectsMarked() ) + { + ::tools::Rectangle aRect = mpDrawView->GetAllMarkedRect(); + pPageView->LogicToPagePos(aRect); + + // Show the position of the selected shape(s) + Point aShapePosition (aRect.TopLeft()); + aShapePosition.setX( ::tools::Long(aShapePosition.X() / aUIScale) ); + aShapePosition.setY( ::tools::Long(aShapePosition.Y() / aUIScale) ); + rSet.Put (SfxPointItem(SID_ATTR_POSITION, aShapePosition)); + + Size aSize( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() ); + aSize.setHeight( ::tools::Long(aSize.Height() / aUIScale) ); + aSize.setWidth( ::tools::Long(aSize.Width() / aUIScale) ); + rSet.Put( SvxSizeItem( SID_ATTR_SIZE, aSize) ); + } + else + { + rSet.Put( SfxPointItem(SID_ATTR_POSITION, aPos) ); + rSet.Put( SvxSizeItem( SID_ATTR_SIZE, Size( 0, 0 ) ) ); + } + } + } + + // Display of current page and layer. + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_STATUS_PAGE ) ) + { + sal_Int32 nPageCount = sal_Int32(GetDoc()->GetSdPageCount(mePageKind)); + sal_Int32 nActivePageCount = sal_Int32(GetDoc()->GetActiveSdPageCount()); + // Always show the slide/page number. + OUString aOUString; + if (GetDoc()->GetDocumentType() == DocumentType::Draw) + aOUString = (nPageCount == nActivePageCount) ? SdResId(STR_SD_PAGE_COUNT_DRAW) : SdResId(STR_SD_PAGE_COUNT_CUSTOM_DRAW); + else + aOUString = (nPageCount == nActivePageCount) ? SdResId(STR_SD_PAGE_COUNT) : SdResId(STR_SD_PAGE_COUNT_CUSTOM); + + aOUString = aOUString.replaceFirst("%1", OUString::number(maTabControl->GetCurPagePos() + 1)); + aOUString = aOUString.replaceFirst("%2", OUString::number(nPageCount)); + if(nPageCount != nActivePageCount) + aOUString = aOUString.replaceFirst("%3", OUString::number(nActivePageCount)); + + // If in layer mode additionally show the layer that contains all + // selected shapes of the page. If the shapes are distributed on + // more than one layer, no layer name is shown. + if (IsLayerModeActive()) + { + SdrLayerAdmin& rLayerAdmin = GetDoc()->GetLayerAdmin(); + SdrLayerID nLayer(0), nOldLayer(0); + SdrObject* pObj = nullptr; + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const size_t nMarkCount = rMarkList.GetMarkCount(); + bool bOneLayer = true; + + // Use the first ten selected shapes as a (hopefully + // representative) sample of all shapes of the current page. + // Detect whether they belong to the same layer. + for( size_t j = 0; j < nMarkCount && bOneLayer && j < 10; ++j ) + { + pObj = rMarkList.GetMark( j )->GetMarkedSdrObj(); + if( pObj ) + { + nLayer = pObj->GetLayer(); + + if( j != 0 && nLayer != nOldLayer ) + bOneLayer = false; + + nOldLayer = nLayer; + } + } + + // Append the layer name to the current page number. + if( bOneLayer && nMarkCount ) + { + SdrLayer* pLayer = rLayerAdmin.GetLayerPerID( nLayer ); + if( pLayer ) + { + aOUString += " (" + LayerTabBar::convertToLocalizedName(pLayer->GetName()) + ")"; + } + } + } + + rSet.Put (SfxStringItem (SID_STATUS_PAGE, aOUString)); + } + // Layout + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_STATUS_LAYOUT ) ) + { + OUString aString = mpActualPage->GetLayoutName(); + sal_Int32 nPos = aString.indexOf(SD_LT_SEPARATOR); + if (nPos != -1) + aString = aString.copy(0, nPos); + rSet.Put( SfxStringItem( SID_STATUS_LAYOUT, aString ) ); + } + // Scale + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_SCALE ) ) + { + const Fraction& aUIScale = GetDoc()->GetUIScale(); + OUString aString = OUString::number(aUIScale.GetNumerator()) + + ":" + OUString::number(aUIScale.GetDenominator()); + rSet.Put( SfxStringItem( SID_SCALE, aString ) ); + } +} + +void DrawViewShell::Notify (SfxBroadcaster&, const SfxHint& rHint) +{ + if (rHint.GetId()!=SfxHintId::ModeChanged) + return; + + // Change to selection when turning on read-only mode. + if(GetDocSh()->IsReadOnly() && dynamic_cast< FuSelection* >( GetCurrentFunction().get() ) ) + { + SfxRequest aReq(SID_OBJECT_SELECT, SfxCallMode::SLOT, GetDoc()->GetItemPool()); + FuPermanent(aReq); + } + + // Turn on design mode when document is not read-only. + if (GetDocSh()->IsReadOnly() != mbReadOnly ) + { + mbReadOnly = GetDocSh()->IsReadOnly(); + + SfxBoolItem aItem( SID_FM_DESIGN_MODE, !mbReadOnly ); + GetViewFrame()->GetDispatcher()->ExecuteList(SID_FM_DESIGN_MODE, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem }); + } + +} + +void DrawViewShell::ExecuteAnnotation (SfxRequest const & rRequest) +{ + if (mpAnnotationManager) + mpAnnotationManager->ExecuteAnnotation( rRequest ); +} + +void DrawViewShell::GetAnnotationState (SfxItemSet& rItemSet ) +{ + if (mpAnnotationManager) + mpAnnotationManager->GetAnnotationState( rItemSet ); +} + +OUString const & DrawViewShell::GetSidebarContextName() const +{ + svx::sidebar::SelectionAnalyzer::ViewType eViewType (svx::sidebar::SelectionAnalyzer::ViewType::Standard); + switch (mePageKind) + { + case PageKind::Handout: + eViewType = svx::sidebar::SelectionAnalyzer::ViewType::Handout; + break; + case PageKind::Notes: + eViewType = svx::sidebar::SelectionAnalyzer::ViewType::Notes; + break; + case PageKind::Standard: + if (meEditMode == EditMode::MasterPage) + eViewType = svx::sidebar::SelectionAnalyzer::ViewType::Master; + else + eViewType = svx::sidebar::SelectionAnalyzer::ViewType::Standard; + break; + } + return EnumContext::GetContextName( + svx::sidebar::SelectionAnalyzer::GetContextForSelection_SD( + mpDrawView->GetMarkedObjectList(), + eViewType)); +} + +void DrawViewShell::ExecGoToNextPage (SfxRequest& rReq) +{ + SetCurrentFunction( FuNavigation::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + Cancel(); +} + +void DrawViewShell::GetStateGoToNextPage (SfxItemSet& rSet) +{ + SdPage* pPage = GetActualPage(); + sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2; + sal_uInt16 totalPages = GetDoc()->GetSdPageCount(pPage->GetPageKind()); + if (nSdPage + 1 >= totalPages) + rSet.DisableItem( SID_GO_TO_NEXT_PAGE ); +} + +void DrawViewShell::ExecGoToPreviousPage (SfxRequest& rReq) +{ + SetCurrentFunction( FuNavigation::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + Cancel(); +} + +void DrawViewShell::GetStateGoToPreviousPage (SfxItemSet& rSet) +{ + SdPage* pPage = GetActualPage(); + sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2; + if (nSdPage == 0) + rSet.DisableItem( SID_GO_TO_PREVIOUS_PAGE ); +} + + +void DrawViewShell::ExecGoToFirstPage (SfxRequest& rReq) +{ + SetCurrentFunction( FuNavigation::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + Cancel(); +} + +void DrawViewShell::GetStateGoToFirstPage (SfxItemSet& rSet) +{ + SdPage* pPage = GetActualPage(); + sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2; + if (nSdPage == 0) + rSet.DisableItem( SID_GO_TO_FIRST_PAGE ); +} + +void DrawViewShell::ExecGoToLastPage (SfxRequest& rReq) +{ + SetCurrentFunction( FuNavigation::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + Cancel(); +} + +void DrawViewShell::GetStateGoToLastPage (SfxItemSet& rSet) +{ + SdPage* pPage = GetActualPage(); + sal_uInt16 nSdPage = (pPage->GetPageNum() - 1) / 2; + sal_uInt16 totalPages = GetDoc()->GetSdPageCount(pPage->GetPageKind()); + if (nSdPage + 1 >= totalPages) + rSet.DisableItem( SID_GO_TO_LAST_PAGE ); +} + + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsb.cxx b/sd/source/ui/view/drviewsb.cxx new file mode 100644 index 0000000000..6f6bba8555 --- /dev/null +++ b/sd/source/ui/view/drviewsb.cxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svx/svdlayer.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/fmshell.hxx> +#include <svx/svxdlg.hxx> +#include <osl/diagnose.h> + +#include <app.hrc> + +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <unokywds.hxx> +#include <sdpage.hxx> +#include <DrawViewShell.hxx> +#include <drawview.hxx> +#include <unmodpg.hxx> +#include <ViewShellBase.hxx> +#include <FormShellManager.hxx> +#include <LayerTabBar.hxx> +#include <SlideSorterViewShell.hxx> +#include <SlideSorter.hxx> +#include <controller/SlideSorterController.hxx> + +namespace sd { + +bool DrawViewShell::RenameSlide( sal_uInt16 nPageId, const OUString & rName ) +{ + bool bOutDummy; + if( GetDoc()->GetPageByName( rName, bOutDummy ) != SDRPAGE_NOTFOUND ) + return false; + + SdPage* pPageToRename = nullptr; + PageKind ePageKind = GetPageKind(); + + if( GetEditMode() == EditMode::Page ) + { + pPageToRename = GetDoc()->GetSdPage( maTabControl->GetPagePos(nPageId), ePageKind ); + + // Undo + SdPage* pUndoPage = pPageToRename; + SdrLayerAdmin & rLayerAdmin = GetDoc()->GetLayerAdmin(); + SdrLayerID nBackground = rLayerAdmin.GetLayerID(sUNO_LayerName_background); + SdrLayerID nBgObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects); + SdrLayerIDSet aVisibleLayers = mpActualPage->TRG_GetMasterPageVisibleLayers(); + + SfxUndoManager* pManager = GetDoc()->GetDocSh()->GetUndoManager(); + pManager->AddUndoAction( + std::make_unique<ModifyPageUndoAction>( + GetDoc(), pUndoPage, rName, pUndoPage->GetAutoLayout(), + aVisibleLayers.IsSet( nBackground ), + aVisibleLayers.IsSet( nBgObj ))); + + // rename + pPageToRename->SetName( rName ); + + if( ePageKind == PageKind::Standard ) + { + // also rename notes-page + SdPage* pNotesPage = GetDoc()->GetSdPage( maTabControl->GetPagePos(nPageId), PageKind::Notes ); + pNotesPage->SetName( rName ); + } + } + else + { + // rename MasterPage -> rename LayoutTemplate + pPageToRename = GetDoc()->GetMasterSdPage( maTabControl->GetPagePos(nPageId), ePageKind ); + GetDoc()->RenameLayoutTemplate( pPageToRename->GetLayoutName(), rName ); + } + + bool bSuccess = (rName == pPageToRename->GetName()); + + if( bSuccess ) + { + // user edited page names may be changed by the page so update control + maTabControl->SetPageText( nPageId, rName ); + + // set document to modified state + GetDoc()->SetChanged(); + + // inform navigator about change + if (GetViewFrame()) + { + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate(SID_NAVIGATOR_STATE, true); + } + + // Tell the slide sorter about the name change (necessary for + // accessibility.) + slidesorter::SlideSorterViewShell* pSlideSorterViewShell + = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase()); + if (pSlideSorterViewShell != nullptr) + { + pSlideSorterViewShell->GetSlideSorter().GetController().PageNameHasChanged( + maTabControl->GetPagePos(nPageId), rName); + } + } + + return bSuccess; +} + +IMPL_LINK( DrawViewShell, RenameSlideHdl, AbstractSvxNameDialog&, rDialog, bool ) +{ + OUString aNewName; + rDialog.GetName( aNewName ); + + SdPage* pCurrentPage = GetDoc()->GetSdPage( maTabControl->GetCurPagePos(), GetPageKind() ); + + return pCurrentPage && ( aNewName == pCurrentPage->GetName() || GetDocSh()->IsNewPageNameValid( aNewName ) ); +} + +void DrawViewShell::ModifyLayer ( + SdrLayer* pLayer, + const OUString& rLayerName, + const OUString& rLayerTitle, + const OUString& rLayerDesc, + bool bIsVisible, + bool bIsLocked, + bool bIsPrintable) +{ + if(!GetLayerTabControl()) // #i87182# + { + OSL_ENSURE(false, "No LayerTabBar (!)"); + return; + } + + if( !pLayer ) + return; + + const sal_uInt16 nPageCount = GetLayerTabControl()->GetPageCount(); + sal_uInt16 nCurPage = 0; + sal_uInt16 nPos; + for( nPos = 0; nPos < nPageCount; nPos++ ) + { + sal_uInt16 nId = GetLayerTabControl()->GetPageId( nPos ); + if (GetLayerTabControl()->GetLayerName(nId) == pLayer->GetName()) + { + nCurPage = nId; + break; + } + } + + pLayer->SetName( rLayerName ); + pLayer->SetTitle( rLayerTitle ); + pLayer->SetDescription( rLayerDesc ); + mpDrawView->SetLayerVisible( rLayerName, bIsVisible ); + mpDrawView->SetLayerLocked( rLayerName, bIsLocked); + mpDrawView->SetLayerPrintable(rLayerName, bIsPrintable); + + GetDoc()->SetChanged(); + + GetLayerTabControl()->SetPageText(nCurPage, rLayerName); + + // Set page bits for modified tab name display + + TabBarPageBits nBits = TabBarPageBits::NONE; + + if (!bIsVisible) + { + nBits = TabBarPageBits::Blue; + } + if (bIsLocked) + { + nBits |= TabBarPageBits::Italic; + } + if (!bIsPrintable) + { + nBits |= TabBarPageBits::Underline; + } + + // Save the bits + + GetLayerTabControl()->SetPageBits(nCurPage, nBits); + + GetViewFrame()->GetDispatcher()->Execute( + SID_SWITCHLAYER, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); + + // Call Invalidate at the form shell. + FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell(); + if (pFormShell != nullptr) + pFormShell->Invalidate(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsc.cxx b/sd/source/ui/view/drviewsc.cxx new file mode 100644 index 0000000000..6be86e63cb --- /dev/null +++ b/sd/source/ui/view/drviewsc.cxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> + +#include <svx/imapdlg.hxx> +#include <svx/svdoole2.hxx> +#include <svx/svdograf.hxx> +#include <svx/svxdlg.hxx> +#include <svx/ImageMapInfo.hxx> + +#include <sfx2/viewfrm.hxx> + +#include <drawdoc.hxx> +#include <drawview.hxx> +#include <memory> + +namespace sd { + +void DrawViewShell::UpdateIMapDlg( SdrObject* pObj ) +{ + if( ( dynamic_cast< SdrGrafObj *>( pObj ) == nullptr && dynamic_cast< SdrOle2Obj *>( pObj ) == nullptr ) + || mpDrawView->IsTextEdit() + || !GetViewFrame()->HasChildWindow( SvxIMapDlgChildWindow::GetChildWindowId() ) ) + return; + + Graphic aGraphic; + ImageMap* pIMap = nullptr; + std::unique_ptr<TargetList> pTargetList; + SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo( pObj ); + + // get graphic from shape + SdrGrafObj* pGrafObj = dynamic_cast< SdrGrafObj* >( pObj ); + if( pGrafObj ) + aGraphic = pGrafObj->GetGraphic(); + + if ( pIMapInfo ) + { + pIMap = const_cast<ImageMap*>(&pIMapInfo->GetImageMap()); + pTargetList.reset(new TargetList); + SfxViewFrame::GetTargetList( *pTargetList ); + } + + SvxIMapDlgChildWindow::UpdateIMapDlg( aGraphic, pIMap, pTargetList.get(), pObj ); +} + +IMPL_LINK( DrawViewShell, NameObjectHdl, AbstractSvxObjectNameDialog&, rDialog, bool ) +{ + OUString aName; + rDialog.GetName( aName ); + return aName.isEmpty() || ( GetDoc() && !GetDoc()->GetObj( aName ) ); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsd.cxx b/sd/source/ui/view/drviewsd.cxx new file mode 100644 index 0000000000..1a6bb3aee9 --- /dev/null +++ b/sd/source/ui/view/drviewsd.cxx @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> + +#include <svx/svxids.hrc> +#include <svl/stritem.hxx> +#include <sfx2/childwin.hxx> +#include <sfx2/docfile.hxx> +#include <svl/intitem.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/request.hxx> + +#include <sfx2/viewfrm.hxx> + +#include <app.hrc> +#include <sdpage.hxx> +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <pgjump.hxx> +#include <navigatr.hxx> +#include <drawview.hxx> + +namespace sd { + +/** + * handle SfxRequests for navigator + */ +void DrawViewShell::ExecNavigatorWin( SfxRequest& rReq ) +{ + CheckLineTo (rReq); + + sal_uInt16 nSId = rReq.GetSlot(); + + switch( nSId ) + { + case SID_NAVIGATOR_INIT: + { + SfxChildWindow* pWindow = GetViewFrame()->GetChildWindow( SID_NAVIGATOR ); + if( pWindow ) + { + SdNavigatorFloat* pNavWin = static_cast<SdNavigatorFloat*>(pWindow->GetWindow()); + if( pNavWin ) + pNavWin->InitTreeLB( GetDoc() ); + } + } + break; + + case SID_NAVIGATOR_PAGE: + case SID_NAVIGATOR_OBJECT: + { + if (nSId == SID_NAVIGATOR_PAGE) + { + if ( mpDrawView->IsTextEdit() ) + mpDrawView->SdrEndTextEdit(); + + const SfxItemSet* pArgs = rReq.GetArgs(); + PageJump eJump = static_cast<PageJump>( pArgs->Get(SID_NAVIGATOR_PAGE).GetValue() ); + + switch (eJump) + { + case PAGE_FIRST: + { + // jump to first page + SwitchPage(0); + } + break; + + case PAGE_LAST: + { + // jump to last page + SwitchPage(GetDoc()->GetSdPageCount(mpActualPage->GetPageKind()) - 1); + } + break; + + case PAGE_NEXT: + { + // jump to next page + sal_uInt16 nSdPage = (mpActualPage->GetPageNum() - 1) / 2; + + if (nSdPage < GetDoc()->GetSdPageCount(mpActualPage->GetPageKind()) - 1) + { + SwitchPage(nSdPage + 1); + } + } + break; + + case PAGE_PREVIOUS: + { + // jump to previous page + sal_uInt16 nSdPage = (mpActualPage->GetPageNum() - 1) / 2; + + if (nSdPage > 0) + { + SwitchPage(nSdPage - 1); + } + } + break; + + case PAGE_NONE: + break; + } + } + else if (nSId == SID_NAVIGATOR_OBJECT) + { + OUString aBookmarkStr("#"); + const SfxItemSet* pArgs = rReq.GetArgs(); + OUString aTarget = pArgs->Get(SID_NAVIGATOR_OBJECT).GetValue(); + aBookmarkStr += aTarget; + SfxStringItem aStrItem(SID_FILE_NAME, aBookmarkStr); + SfxStringItem aReferer(SID_REFERER, GetDocSh()->GetMedium()->GetName()); + SfxViewFrame* pFrame = GetViewFrame(); + SfxFrameItem aFrameItem(SID_DOCFRAME, pFrame); + SfxBoolItem aBrowseItem(SID_BROWSE, true); + pFrame->GetDispatcher()-> + ExecuteList(SID_OPENDOC, SfxCallMode::SYNCHRON | SfxCallMode::RECORD, + { &aStrItem, &aFrameItem, &aBrowseItem, &aReferer }); + } + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_NAVIGATOR_STATE ); + rBindings.Invalidate( SID_NAVIGATOR_PAGENAME ); + } + break; + + default: + break; + } +} + +void DrawViewShell::GetNavigatorWinState( SfxItemSet& rSet ) +{ + NavState nState = NavState::NONE; + sal_uInt16 nCurrentPage = 0; + sal_uInt16 nLastPage; + OUString aPageName; + + nState |= NavState::TableUpdate; + + if (mpActualPage != nullptr) + { + nCurrentPage = ( mpActualPage->GetPageNum() - 1 ) / 2; + aPageName = mpActualPage->GetName(); + } + nLastPage = GetDoc()->GetSdPageCount( mePageKind ) - 1; + + + // first page / previous page + if( nCurrentPage == 0 ) + { + nState |= NavState::BtnFirstDisabled | NavState::BtnPrevDisabled; + } + else + { + nState |= NavState::BtnFirstEnabled | NavState::BtnPrevEnabled; + } + + // last page / next page + if( nCurrentPage == nLastPage ) + { + nState |= NavState::BtnLastDisabled | NavState::BtnNextDisabled; + } + else + { + nState |= NavState::BtnLastEnabled | NavState::BtnNextEnabled; + } + + rSet.Put( SfxUInt32Item( SID_NAVIGATOR_STATE, static_cast<sal_uInt32>(nState) ) ); + rSet.Put( SfxStringItem( SID_NAVIGATOR_PAGENAME, aPageName ) ); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewse.cxx b/sd/source/ui/view/drviewse.cxx new file mode 100644 index 0000000000..0b293773b0 --- /dev/null +++ b/sd/source/ui/view/drviewse.cxx @@ -0,0 +1,1719 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <com/sun/star/presentation/XPresentation2.hpp> +#include <com/sun/star/form/FormButtonType.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <i18nutil/unicode.hxx> +#include <i18nutil/transliteration.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/uno/Any.hxx> + +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <comphelper/lok.hxx> +#include <comphelper/propertyvalue.hxx> +#include <editeng/editstat.hxx> +#include <editeng/outlobj.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svl/urlbmk.hxx> +#include <svx/clipfmtitem.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdopath.hxx> +#include <svx/svdundo.hxx> +#include <svx/svdorect.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/poolitem.hxx> +#include <svl/stritem.hxx> +#include <editeng/eeitem.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/request.hxx> +#include <svx/svxids.hrc> +#include <editeng/flditem.hxx> +#include <svx/obj3d.hxx> +#include <svx/svdobjkind.hxx> +#include <svx/svdouno.hxx> +#include <svx/dataaccessdescriptor.hxx> +#include <tools/urlobj.hxx> +#include <sfx2/ipclient.hxx> +#include <avmedia/mediawindow.hxx> +#include <svl/urihelper.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/notebookbar/SfxNotebookBar.hxx> +#include <osl/diagnose.h> + +#include <DrawViewShell.hxx> +#include <slideshow.hxx> +#include <ViewShellHint.hxx> +#include <framework/FrameworkHelper.hxx> +#include <app.hrc> +#include <strings.hrc> + +#include <drawdoc.hxx> +#include <fusel.hxx> +#include <futext.hxx> +#include <fuconrec.hxx> +#include <fuconcs.hxx> +#include <fuconuno.hxx> +#include <fuconbez.hxx> +#include <fuediglu.hxx> +#include <fuconarc.hxx> +#include <fucon3d.hxx> +#include <sdresid.hxx> +#include <unokywds.hxx> +#include <Outliner.hxx> +#include <sdpage.hxx> +#include <FrameView.hxx> +#include <zoomlist.hxx> +#include <drawview.hxx> +#include <DrawDocShell.hxx> +#include <ViewShellBase.hxx> +#include <ToolBarManager.hxx> +#include <anminfo.hxx> +#include <optsitem.hxx> +#include <Window.hxx> +#include <fuformatpaintbrush.hxx> +#include <fuzoom.hxx> +#include <sdmod.hxx> +#include <basegfx/utils/zoomtools.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::beans; + +namespace sd { + +// Permanent Functions + +static void ImpAddPrintableCharactersToTextEdit(SfxRequest const & rReq, ::sd::View* pView) +{ + // evtl. feed characters to activated textedit + const SfxItemSet* pSet = rReq.GetArgs(); + + if(!pSet) + return; + + OUString aInputString; + + if(SfxItemState::SET == pSet->GetItemState(SID_ATTR_CHAR)) + aInputString = pSet->Get(SID_ATTR_CHAR).GetValue(); + + if(aInputString.isEmpty()) + return; + + OutlinerView* pOLV = pView->GetTextEditOutlinerView(); + + if(pOLV) + { + for(sal_Int32 a(0); a < aInputString.getLength(); a++) + { + vcl::KeyCode aKeyCode; + // tdf#38669 - create the key event using a Unicode character + KeyEvent aKeyEvent(aInputString[a], aKeyCode); + + // add actual character + pOLV->PostKeyEvent(aKeyEvent); + } + } +} + +void DrawViewShell::FuPermanent(SfxRequest& rReq) +{ + // We do not execute a thing during a native slide show + + if (SlideShow::IsRunning(GetViewShellBase())) + return; + + sal_uInt16 nSId = rReq.GetSlot(); + + if( HasCurrentFunction() && + ( nSId == SID_TEXTEDIT || nSId == SID_ATTR_CHAR || nSId == SID_TEXT_FITTOSIZE || + nSId == SID_ATTR_CHAR_VERTICAL || nSId == SID_TEXT_FITTOSIZE_VERTICAL ) ) + { + rtl::Reference<FuPoor> xFunc( GetCurrentFunction() ); + + FuText* pFuText = dynamic_cast< FuText* >( xFunc.get() ); + + if( pFuText ) + { + pFuText->SetPermanent(true); + xFunc->ReceiveRequest( rReq ); + + Invalidate(); + + // evtl. feed characters to activated textedit + if(SID_ATTR_CHAR == nSId && GetView() && GetView()->IsTextEdit()) + ImpAddPrintableCharactersToTextEdit(rReq, GetView()); + + rReq.Done(); + return; + } + } + + CheckLineTo (rReq); + sal_uInt16 nOldSId = 0; + bool bPermanent = false; + + if( !mpDrawView ) + return; + + if(HasCurrentFunction()) + { + if( (nSId == SID_FORMATPAINTBRUSH) && (GetCurrentFunction()->GetSlotID() == SID_TEXTEDIT) ) + { + // save text edit mode for format paintbrush! + SetOldFunction( GetCurrentFunction() ); + } + else + { + if(GetOldFunction() == GetCurrentFunction()) + { + SetOldFunction(nullptr); + } + } + + if ( nSId != SID_TEXTEDIT && nSId != SID_ATTR_CHAR && nSId != SID_TEXT_FITTOSIZE && + nSId != SID_ATTR_CHAR_VERTICAL && nSId != SID_TEXT_FITTOSIZE_VERTICAL && + nSId != SID_FORMATPAINTBRUSH && + mpDrawView->IsTextEdit() ) + { + mpDrawView->SdrEndTextEdit(); + } + + if( HasCurrentFunction() ) + { + nOldSId = GetCurrentFunction()->GetSlotID(); + + if (nOldSId == nSId || + ((nOldSId == SID_TEXTEDIT || nOldSId == SID_ATTR_CHAR || nOldSId == SID_TEXT_FITTOSIZE || + nOldSId == SID_ATTR_CHAR_VERTICAL || nOldSId == SID_TEXT_FITTOSIZE_VERTICAL) && + (nSId == SID_TEXTEDIT || nSId == SID_ATTR_CHAR || nSId == SID_TEXT_FITTOSIZE || + nSId == SID_ATTR_CHAR_VERTICAL || nSId == SID_TEXT_FITTOSIZE_VERTICAL ))) + { + bPermanent = true; + } + + GetCurrentFunction()->Deactivate(); + } + + SetCurrentFunction(nullptr); + + SfxBindings& rBind = GetViewFrame()->GetBindings(); + rBind.Invalidate(nOldSId); + rBind.Update(nOldSId); + } + + // for LibreOfficeKit - choosing a shape should construct it directly + bool bCreateDirectly = false; + + switch ( nSId ) + { + case SID_TEXTEDIT: // BASIC ??? + case SID_ATTR_CHAR: + case SID_ATTR_CHAR_VERTICAL: + case SID_TEXT_FITTOSIZE: + case SID_TEXT_FITTOSIZE_VERTICAL: + { + SetCurrentFunction( FuText::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + GetCurrentFunction()->DoExecute(rReq); + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_ATTR_CHAR ); + rBindings.Invalidate( SID_ATTR_CHAR_VERTICAL ); + rBindings.Invalidate( SID_TEXT_FITTOSIZE ); + rBindings.Invalidate( SID_TEXT_FITTOSIZE_VERTICAL ); + + // evtl. feed characters to activated textedit + if(SID_ATTR_CHAR == nSId && GetView() && GetView()->IsTextEdit()) + ImpAddPrintableCharactersToTextEdit(rReq, GetView()); + + rReq.Done(); + + const SfxItemSet* pArgs = rReq.GetArgs(); + if (pArgs && pArgs->HasItem(FN_PARAM_1)) + bCreateDirectly = static_cast<const SfxBoolItem&>(pArgs->Get(FN_PARAM_1)).GetValue(); + } + break; + + case SID_FM_CREATE_CONTROL: + { + SetCurrentFunction( FuConstructUnoControl::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) ); + rReq.Done(); + } + break; + + case SID_FM_CREATE_FIELDCONTROL: + { + const SfxUnoAnyItem* pDescriptorItem = rReq.GetArg<SfxUnoAnyItem>(SID_FM_DATACCESS_DESCRIPTOR); + DBG_ASSERT( pDescriptorItem, "DrawViewShell::FuPermanent(SID_FM_CREATE_FIELDCONTROL): invalid request args!" ); + + if(pDescriptorItem) + { + // get the form view + FmFormView* pFormView = mpDrawView.get(); + SdrPageView* pPageView = pFormView ? pFormView->GetSdrPageView() : nullptr; + + if(pPageView) + { + svx::ODataAccessDescriptor aDescriptor(pDescriptorItem->GetValue()); + rtl::Reference<SdrObject> pNewDBField = pFormView->CreateFieldControl(aDescriptor); + + if(pNewDBField) + { + ::tools::Rectangle aVisArea = GetActiveWindow()->PixelToLogic(::tools::Rectangle(Point(0,0), GetActiveWindow()->GetOutputSizePixel())); + Point aObjPos(aVisArea.Center()); + Size aObjSize(pNewDBField->GetLogicRect().GetSize()); + aObjPos.AdjustX( -(aObjSize.Width() / 2) ); + aObjPos.AdjustY( -(aObjSize.Height() / 2) ); + ::tools::Rectangle aNewObjectRectangle(aObjPos, aObjSize); + + pNewDBField->SetLogicRect(aNewObjectRectangle); + + GetView()->InsertObjectAtView(pNewDBField.get(), *pPageView); + } + } + } + rReq.Done(); + } + break; + + case SID_OBJECT_SELECT: + case SID_OBJECT_ROTATE: + case SID_OBJECT_MIRROR: + case SID_OBJECT_CROP: + case SID_OBJECT_TRANSPARENCE: + case SID_OBJECT_GRADIENT: + case SID_OBJECT_SHEAR: + case SID_OBJECT_CROOK_ROTATE: + case SID_OBJECT_CROOK_SLANT: + case SID_OBJECT_CROOK_STRETCH: + case SID_CONVERT_TO_3D_LATHE: + { + sal_uInt16 nSlotId = rReq.GetSlot(); + + // toggle function + if( nOldSId == nSlotId ) + { + nSlotId = SID_OBJECT_SELECT; + rReq.SetSlot( nSlotId ); + } + + if (nSlotId == SID_OBJECT_CROOK_ROTATE || + nSlotId == SID_OBJECT_CROOK_SLANT || + nSlotId == SID_OBJECT_CROOK_STRETCH) + { + if ( mpDrawView->GetMarkedObjectList().GetMarkCount() > 0 && + !mpDrawView->IsCrookAllowed( mpDrawView->IsCrookNoContortion() ) ) + { + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + SdResId(STR_ASK_FOR_CONVERT_TO_BEZIER))); + if (xQueryBox->run() == RET_YES ) + { + // implicit transformation into bezier + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->ConvertMarkedToPathObj(false); + } + } + } + } + else if (nSlotId == SID_OBJECT_SHEAR) + { + size_t i = 0; + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const size_t nMarkCnt = rMarkList.GetMarkCount(); + bool b3DObjMarked = false; + + while (i < nMarkCnt && !b3DObjMarked) + { + if (DynCastE3dObject( rMarkList.GetMark(i)->GetMarkedSdrObj() )) + { + b3DObjMarked = true; + } + else + { + i++; + } + } + + if ( nMarkCnt > 0 && !b3DObjMarked && + (!mpDrawView->IsShearAllowed() || !mpDrawView->IsDistortAllowed()) ) + { + if ( mpDrawView->IsPresObjSelected() ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + SdResId(STR_ASK_FOR_CONVERT_TO_BEZIER))); + if (xQueryBox->run() == RET_YES) + { + // implicit transformation into bezier + weld::WaitObject aWait(GetFrameWeld()); + mpDrawView->ConvertMarkedToPathObj(false); + } + } + } + } + + SetCurrentFunction( FuSelection::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq) ); + rReq.Done(); + Invalidate( SID_OBJECT_SELECT ); + } + break; + + case SID_DRAW_LINE: + case SID_DRAW_XLINE: + case SID_DRAW_MEASURELINE: + case SID_LINE_ARROW_START: + case SID_LINE_ARROW_END: + case SID_LINE_ARROWS: + case SID_LINE_ARROW_CIRCLE: + case SID_LINE_CIRCLE_ARROW: + case SID_LINE_ARROW_SQUARE: + case SID_LINE_SQUARE_ARROW: + + case SID_DRAW_RECT: + case SID_DRAW_RECT_NOFILL: + case SID_DRAW_RECT_ROUND: + case SID_DRAW_RECT_ROUND_NOFILL: + case SID_DRAW_SQUARE: + case SID_DRAW_SQUARE_NOFILL: + case SID_DRAW_SQUARE_ROUND: + case SID_DRAW_SQUARE_ROUND_NOFILL: + case SID_DRAW_ELLIPSE: + case SID_DRAW_ELLIPSE_NOFILL: + case SID_DRAW_CIRCLE: + case SID_DRAW_CIRCLE_NOFILL: + case SID_DRAW_CAPTION: + case SID_DRAW_CAPTION_VERTICAL: + case SID_TOOL_CONNECTOR: + case SID_CONNECTOR_ARROW_START: + case SID_CONNECTOR_ARROW_END: + case SID_CONNECTOR_ARROWS: + case SID_CONNECTOR_CIRCLE_START: + case SID_CONNECTOR_CIRCLE_END: + case SID_CONNECTOR_CIRCLES: + case SID_CONNECTOR_LINE: + case SID_CONNECTOR_LINE_ARROW_START: + case SID_CONNECTOR_LINE_ARROW_END: + case SID_CONNECTOR_LINE_ARROWS: + case SID_CONNECTOR_LINE_CIRCLE_START: + case SID_CONNECTOR_LINE_CIRCLE_END: + case SID_CONNECTOR_LINE_CIRCLES: + case SID_CONNECTOR_CURVE: + case SID_CONNECTOR_CURVE_ARROW_START: + case SID_CONNECTOR_CURVE_ARROW_END: + case SID_CONNECTOR_CURVE_ARROWS: + case SID_CONNECTOR_CURVE_CIRCLE_START: + case SID_CONNECTOR_CURVE_CIRCLE_END: + case SID_CONNECTOR_CURVE_CIRCLES: + case SID_CONNECTOR_LINES: + case SID_CONNECTOR_LINES_ARROW_START: + case SID_CONNECTOR_LINES_ARROW_END: + case SID_CONNECTOR_LINES_ARROWS: + case SID_CONNECTOR_LINES_CIRCLE_START: + case SID_CONNECTOR_LINES_CIRCLE_END: + case SID_CONNECTOR_LINES_CIRCLES: + case SID_INSERT_SIGNATURELINE: + { + bCreateDirectly = comphelper::LibreOfficeKit::isActive(); + SetCurrentFunction( FuConstructRectangle::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) ); + rReq.Done(); + } + break; + case SID_DRAW_POLYGON: + case SID_DRAW_POLYGON_NOFILL: + case SID_DRAW_XPOLYGON: + case SID_DRAW_XPOLYGON_NOFILL: + case SID_DRAW_FREELINE: + case SID_DRAW_FREELINE_NOFILL: + case SID_DRAW_BEZIER_FILL: // BASIC + case SID_DRAW_BEZIER_NOFILL: // BASIC + { + SetCurrentFunction( FuConstructBezierPolygon::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent) ); + rReq.Done(); + } + break; + + case SID_GLUE_EDITMODE: + { + if (nOldSId != SID_GLUE_EDITMODE) + { + SetCurrentFunction( FuEditGluePoints::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) ); + } + else + { + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + } + + rReq.Done(); + } + break; + + case SID_DRAW_ARC: + case SID_DRAW_CIRCLEARC: + case SID_DRAW_PIE: + case SID_DRAW_PIE_NOFILL: + case SID_DRAW_CIRCLEPIE: + case SID_DRAW_CIRCLEPIE_NOFILL: + case SID_DRAW_ELLIPSECUT: + case SID_DRAW_ELLIPSECUT_NOFILL: + case SID_DRAW_CIRCLECUT: + case SID_DRAW_CIRCLECUT_NOFILL: + { + SetCurrentFunction( FuConstructArc::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent) ); + rReq.Done(); + } + break; + + case SID_3D_CUBE: + case SID_3D_SHELL: + case SID_3D_SPHERE: + case SID_3D_TORUS: + case SID_3D_HALF_SPHERE: + case SID_3D_CYLINDER: + case SID_3D_CONE: + case SID_3D_PYRAMID: + { + SetCurrentFunction( FuConstruct3dObject::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) ); + rReq.Done(); + } + break; + + case SID_DRAWTBX_CS_BASIC : + case SID_DRAWTBX_CS_SYMBOL : + case SID_DRAWTBX_CS_ARROW : + case SID_DRAWTBX_CS_FLOWCHART : + case SID_DRAWTBX_CS_CALLOUT : + case SID_DRAWTBX_CS_STAR : + case SID_DRAW_CS_ID : + { + SetCurrentFunction( FuConstructCustomShape::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq, bPermanent ) ); + rReq.Done(); + + bCreateDirectly = comphelper::LibreOfficeKit::isActive(); + const SfxItemSet* pArgs = rReq.GetArgs(); + if (pArgs && pArgs->HasItem(FN_PARAM_1)) + { + bCreateDirectly = static_cast<const SfxBoolItem&>(pArgs->Get(FN_PARAM_1)).GetValue(); + } + + if ( nSId != SID_DRAW_CS_ID ) + { + SfxBindings& rBind = GetViewFrame()->GetBindings(); + rBind.Invalidate( nSId ); + rBind.Update( nSId ); + } + } + break; + + case SID_FORMATPAINTBRUSH: + { + SetCurrentFunction( FuFormatPaintBrush::Create( this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + rReq.Done(); + SfxBindings& rBind = GetViewFrame()->GetBindings(); + rBind.Invalidate( nSId ); + rBind.Update( nSId ); + break; + } + + case SID_ZOOM_MODE: + case SID_ZOOM_PANNING: + { + if (nOldSId != nSId) + { + mbZoomOnPage = false; + SetCurrentFunction( FuZoom::Create(this, GetActiveWindow(), mpDrawView.get(), GetDoc(), rReq ) ); + } + else + { + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + } + rReq.Done(); + } + break; + + default: + break; + } + + if(HasOldFunction()) + { + sal_uInt16 nSlotId = GetOldFunction()->GetSlotID(); + + GetOldFunction()->Deactivate(); + SetOldFunction(nullptr); + + SfxBindings& rBind = GetViewFrame()->GetBindings(); + rBind.Invalidate( nSlotId ); + rBind.Update( nSlotId ); + } + + if(HasCurrentFunction()) + { + GetCurrentFunction()->Activate(); + SetOldFunction( GetCurrentFunction() ); + } + + // invalidate shell, is faster than every individually (says MI) + // now explicit the last slot incl. Update() + Invalidate(); + + // CTRL-SID_OBJECT_SELECT -> select first draw object if none is selected yet + if(SID_OBJECT_SELECT == nSId && HasCurrentFunction() && (rReq.GetModifier() & KEY_MOD1)) + { + if(!GetView()->AreObjectsMarked()) + { + // select first object + GetView()->UnmarkAllObj(); + GetView()->MarkNextObj(true); + + // ...and make it visible + if(GetView()->AreObjectsMarked()) + GetView()->MakeVisible(GetView()->GetAllMarkedRect(), *GetActiveWindow()); + } + } + + // with qualifier construct directly + if(!(HasCurrentFunction() && ((rReq.GetModifier() & KEY_MOD1) || bCreateDirectly))) + return; + + // disable interactive drawing for LOK + if (bCreateDirectly) + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + + // get SdOptions + SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDoc()->GetDocumentType()); + sal_uInt32 nDefaultObjectSizeWidth(pOptions->GetDefaultObjectSizeWidth()); + sal_uInt32 nDefaultObjectSizeHeight(pOptions->GetDefaultObjectSizeHeight()); + + // calc position and size + ::tools::Rectangle aVisArea = GetActiveWindow()->PixelToLogic(::tools::Rectangle(Point(0,0), GetActiveWindow()->GetOutputSizePixel())); + if (comphelper::LibreOfficeKit::isActive()) + { + // aVisArea is nonsensical in the LOK case, use the slide size + aVisArea = ::tools::Rectangle(Point(), getCurrentPage()->GetSize()); + } + + Point aPagePos = aVisArea.Center(); + aPagePos.AdjustX( -sal_Int32(nDefaultObjectSizeWidth / 2) ); + aPagePos.AdjustY( -sal_Int32(nDefaultObjectSizeHeight / 2) ); + ::tools::Rectangle aNewObjectRectangle(aPagePos, Size(nDefaultObjectSizeWidth, nDefaultObjectSizeHeight)); + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + + if(!pPageView) + return; + + // create the default object + rtl::Reference<SdrObject> pObj = GetCurrentFunction()->CreateDefaultObject(nSId, aNewObjectRectangle); + + if(!pObj) + return; + + auto pObjTmp = pObj.get(); + // insert into page + GetView()->InsertObjectAtView(pObj.get(), *pPageView); + + // Now that pFuActual has done what it was created for we + // can switch on the edit mode for callout objects. + switch (nSId) + { + case SID_DRAW_CAPTION: + case SID_DRAW_CAPTION_VERTICAL: + { + // Make FuText the current function. + SfxUInt16Item aItem (SID_TEXTEDIT, 1); + GetViewFrame()->GetDispatcher()-> + ExecuteList(SID_TEXTEDIT, SfxCallMode::SYNCHRON | + SfxCallMode::RECORD, { &aItem }); + // Put text object into edit mode. + GetView()->SdrBeginTextEdit(static_cast<SdrTextObj*>(pObjTmp), pPageView); + break; + } + } +} + +void DrawViewShell::FuDeleteSelectedObjects() +{ + if( !mpDrawView ) + return; + + bool bConsumed = false; + + //if any placeholders are selected + if (mpDrawView->IsPresObjSelected(false)) + { + //If there are placeholders in the list which can be toggled + //off in edit->master->master elements then do that here, + std::vector<SdrObject*> aPresMarksToRemove; + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + for (size_t i=0; i < rMarkList.GetMarkCount(); ++i) + { + SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj(); + SdPage* pPage = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject()); + PresObjKind eKind = pPage->GetPresObjKind(pObj); + if (eKind == PresObjKind::Footer || eKind == PresObjKind::Header || + eKind == PresObjKind::DateTime || eKind == PresObjKind::SlideNumber) + { + aPresMarksToRemove.push_back(pObj); + } + } + + for (SdrObject* pObj : aPresMarksToRemove) + { + //Unmark object + mpDrawView->MarkObj(pObj, mpDrawView->GetSdrPageView(), true); + SdPage* pPage = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject()); + //remove placeholder from master page + pPage->DestroyDefaultPresObj(pPage->GetPresObjKind(pObj)); + } + + bConsumed = true; + } + + // placeholders which cannot be deleted selected + if (mpDrawView->IsPresObjSelected(false, true, false, true)) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + bConsumed = true; + } + + if (bConsumed) + return; + + vcl::KeyCode aKCode(KEY_DELETE); + KeyEvent aKEvt( 0, aKCode); + + bConsumed = mpDrawView->getSmartTags().KeyInput( aKEvt ); + + if (!bConsumed && HasCurrentFunction()) + bConsumed = GetCurrentFunction()->KeyInput(aKEvt); + + if (!bConsumed) + mpDrawView->DeleteMarked(); +} + +void DrawViewShell::FuSupport(SfxRequest& rReq) +{ + if( rReq.GetSlot() == SID_STYLE_FAMILY && rReq.GetArgs()) + GetDocSh()->SetStyleFamily(static_cast<SfxStyleFamily>(rReq.GetArgs()->Get( SID_STYLE_FAMILY ).GetValue())); + + // We do not execute a thing during a native slide show + if(SlideShow::IsRunning(GetViewShellBase()) && + (rReq.GetSlot() != SID_PRESENTATION_END && + rReq.GetSlot() != SID_SIZE_PAGE)) + return; + + CheckLineTo (rReq); + + if( !mpDrawView ) + return; + + sal_uInt16 nSId = rReq.GetSlot(); + + switch ( nSId ) + { + case SID_CLEAR_UNDO_STACK: + { + GetDocSh()->ClearUndoBuffer(); + rReq.Ignore (); + } + break; + + case SID_PRESENTATION: + case SID_PRESENTATION_CURRENT_SLIDE: + case SID_REHEARSE_TIMINGS: + { + slideshowhelp::ShowSlideShow(rReq, *GetDoc()); + rReq.Ignore (); + } + break; + + case SID_PRESENTATION_END: + { + StopSlideShow(); + + rReq.Ignore (); + } + break; + + case SID_BEZIER_EDIT: + { + mpDrawView->SetFrameDragSingles(!mpDrawView->IsFrameDragSingles()); + + /****************************************************************** + * turn ObjectBar on + ******************************************************************/ + if( dynamic_cast< FuSelection* >( GetCurrentFunction().get() ) || dynamic_cast< FuConstructBezierPolygon* >( GetCurrentFunction().get() ) ) + { + // Tell the tool bar manager about the context change. + GetViewShellBase().GetToolBarManager()->SelectionHasChanged(*this,*mpDrawView); + } + + Invalidate(SID_BEZIER_EDIT); + rReq.Ignore(); + } + break; + + case SID_OBJECT_CLOSE: + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + if ( rMarkList.GetMark(0) && !mpDrawView->IsAction() ) + { + SdrPathObj* pPathObj = static_cast<SdrPathObj*>( rMarkList.GetMark(0)->GetMarkedSdrObj()); + const bool bUndo = mpDrawView->IsUndoEnabled(); + if( bUndo ) + mpDrawView->BegUndo(SdResId(STR_UNDO_BEZCLOSE)); + + mpDrawView->UnmarkAllPoints(); + + if( bUndo ) + mpDrawView->AddUndo(std::make_unique<SdrUndoGeoObj>(*pPathObj)); + + pPathObj->ToggleClosed(); + + if( bUndo ) + mpDrawView->EndUndo(); + } + rReq.Done(); + } + break; + + case SID_CUT: + { + if ( mpDrawView->IsPresObjSelected(false, true, false, true) ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + //tdf#126197: EndTextEdit in all views if current one is not in TextEdit + if ( !mpDrawView->IsTextEdit() ) + mpDrawView->EndTextEditAllViews(); + + if(HasCurrentFunction()) + { + GetCurrentFunction()->DoCut(); + } + else if(mpDrawView) + { + mpDrawView->DoCut(); + } + } + rReq.Ignore (); + } + break; + + case SID_COPY: + { + if ( mpDrawView->IsPresObjSelected(false, true, false, true) ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + else + { + if(HasCurrentFunction()) + { + GetCurrentFunction()->DoCopy(); + } + else if( mpDrawView ) + { + mpDrawView->DoCopy(); + } + } + rReq.Ignore (); + } + break; + + case SID_PASTE: + { + weld::WaitObject aWait(GetFrameWeld()); + + if(HasCurrentFunction()) + { + GetCurrentFunction()->DoPaste(); + } + else if(mpDrawView) + { + mpDrawView->DoPaste(); + } + + rReq.Ignore (); + } + break; + + case SID_UNICODE_NOTATION_TOGGLE: + { + if( mpDrawView->IsTextEdit() ) + { + OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView(); + if( pOLV ) + { + OUString sInput = pOLV->GetSurroundingText(); + ESelection aSel( pOLV->GetSelection() ); + if( aSel.nStartPos > aSel.nEndPos ) + aSel.nEndPos = aSel.nStartPos; + + //calculate a valid end-position by reading logical characters + sal_Int32 nUtf16Pos=0; + while( (nUtf16Pos < sInput.getLength()) && (nUtf16Pos < aSel.nEndPos) ) + { + sInput.iterateCodePoints(&nUtf16Pos); + //The mouse can set the cursor in the middle of a multi-unit character, + // so reset to the proper end of the logical characters + if( nUtf16Pos > aSel.nEndPos ) + aSel.nEndPos = nUtf16Pos; + } + + ToggleUnicodeCodepoint aToggle; + while( nUtf16Pos && aToggle.AllowMoreInput( sInput[nUtf16Pos-1]) ) + --nUtf16Pos; + OUString sReplacement = aToggle.ReplacementString(); + if( !sReplacement.isEmpty() ) + { + OUString sStringToReplace = aToggle.StringToReplace(); + mpDrawView->BegUndo(sStringToReplace +"->"+ sReplacement); + aSel.nStartPos = aSel.nEndPos - sStringToReplace.getLength(); + pOLV->SetSelection( aSel ); + pOLV->InsertText(sReplacement, true); + mpDrawView->EndUndo(); + } + } + } + } + break; + + case SID_PASTE_UNFORMATTED: + { + weld::WaitObject aWait(GetFrameWeld()); + + if(HasCurrentFunction()) + { + GetCurrentFunction()->DoPasteUnformatted(); + } + else if(mpDrawView) + { + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) ); + if (aDataHelper.GetTransferable().is()) + { + sal_Int8 nAction = DND_ACTION_COPY; + mpDrawView->InsertData( aDataHelper, + GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(), GetActiveWindow()->GetOutputSizePixel() ).Center() ), + nAction, false, SotClipboardFormatId::STRING); + } + } + + rReq.Ignore (); + } + break; + + case SID_CLIPBOARD_FORMAT_ITEMS: + { + weld::WaitObject aWait(GetFrameWeld()); + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) ); + const SfxItemSet* pReqArgs = rReq.GetArgs(); + SotClipboardFormatId nFormat = SotClipboardFormatId::NONE; + + if( pReqArgs ) + { + const SfxUInt32Item* pIsActive = rReq.GetArg<SfxUInt32Item>(SID_CLIPBOARD_FORMAT_ITEMS); + nFormat = static_cast<SotClipboardFormatId>(pIsActive->GetValue()); + } + + if( nFormat != SotClipboardFormatId::NONE && aDataHelper.GetTransferable().is() ) + { + sal_Int8 nAction = DND_ACTION_COPY; + + if( !mpDrawView->InsertData( aDataHelper, + GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(), GetActiveWindow()->GetOutputSizePixel() ).Center() ), + nAction, false, nFormat ) ) + { + INetBookmark aINetBookmark( "", "" ); + + if( ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) ) || + ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::FILEGRPDESCRIPTOR, aINetBookmark ) ) || + ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::UNIFORMRESOURCELOCATOR, aINetBookmark ) ) ) + { + InsertURLField( aINetBookmark.GetURL(), aINetBookmark.GetDescription(), "" ); + } + } + } + } + break; + + case SID_DELETE: + { + if ( mpDrawView->IsTextEdit() ) + { + OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView(); + + if (pOLV) + { + vcl::KeyCode aKCode(KEY_DELETE); + KeyEvent aKEvt( 0, aKCode); + // We use SdrObjEditView to handle DEL for underflow handling + (void)mpDrawView->KeyInput(aKEvt, nullptr); + } + } + else + { + mpDrawView->EndTextEditAllViews(); + FuDeleteSelectedObjects(); + } + rReq.Ignore (); + } + break; + + case SID_NOTES_MODE: + case SID_SLIDE_MASTER_MODE: + case SID_NOTES_MASTER_MODE: + case SID_HANDOUT_MASTER_MODE: + + // AutoLayouts have to be ready. + GetDoc()->StopWorkStartupDelay(); + [[fallthrough]]; + + case SID_DRAWINGMODE: + case SID_SLIDE_SORTER_MODE: + case SID_OUTLINE_MODE: + // Let the sub-shell manager handle the slot handling. + framework::FrameworkHelper::Instance(GetViewShellBase())->HandleModeChangeSlot( + nSId, + rReq); + rReq.Ignore (); + break; + + case SID_MASTERPAGE: // BASIC + { + if (comphelper::LibreOfficeKit::isActive()) + GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, + ".uno:SlideMasterPage=true"_ostr); + + // AutoLayouts needs to be finished + GetDoc()->StopWorkStartupDelay(); + + const SfxItemSet* pReqArgs = rReq.GetArgs(); + + if ( pReqArgs ) + { + const SfxBoolItem* pIsActive = rReq.GetArg<SfxBoolItem>(SID_MASTERPAGE); + mbIsLayerModeActive = pIsActive->GetValue (); + } + + Broadcast ( + ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START)); + + // turn on default layer of MasterPage + mpDrawView->SetActiveLayer(sUNO_LayerName_background_objects); + + ChangeEditMode(EditMode::MasterPage, mbIsLayerModeActive); + + if(HasCurrentFunction(SID_BEZIER_EDIT)) + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); + + Broadcast ( + ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END)); + + InvalidateWindows(); + Invalidate(); + + rReq.Done(); + } + break; + + case SID_CLOSE_MASTER_VIEW: + { + // Notify of disabling master view, which is enabled in DrawViewShell::ChangeEditMode. + if (comphelper::LibreOfficeKit::isActive()) + GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED, + ".uno:SlideMasterPage=false"_ostr); + + Broadcast ( + ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_START)); + + // Switch page back to the first one. Not doing so leads to a + // crash. This seems to be some bug in the edit mode switching + // and page switching methods. + SwitchPage (0); + ChangeEditMode(EditMode::Page, IsLayerModeActive()); + Broadcast ( + ViewShellHint(ViewShellHint::HINT_CHANGE_EDIT_MODE_END)); + + if(HasCurrentFunction(SID_BEZIER_EDIT)) + { + GetViewFrame()->GetDispatcher()->Execute( + SID_OBJECT_SELECT, + SfxCallMode::ASYNCHRON); + } + + rReq.Done(); + } + break; + + case SID_RULER: + { + const SfxItemSet* pReqArgs = rReq.GetArgs(); + + // Remember old ruler state + bool bOldHasRuler(HasRuler()); + + if ( pReqArgs ) + { + const SfxBoolItem* pIsActive = rReq.GetArg<SfxBoolItem>(SID_RULER); + SetRuler (pIsActive->GetValue ()); + } + else SetRuler (!HasRuler()); + + // Did ruler state change? Tell that to SdOptions, too. + bool bHasRuler(HasRuler()); + + if(bOldHasRuler != bHasRuler) + { + SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDoc()->GetDocumentType()); + + if(pOptions && pOptions->IsRulerVisible() != bHasRuler) + { + pOptions->SetRulerVisible(bHasRuler); + } + } + + Invalidate (SID_RULER); + Resize(); + rReq.Done (); + } + break; + + case SID_SIZE_PAGE: + case SID_SIZE_PAGE_WIDTH: // BASIC + { + mbZoomOnPage = ( rReq.GetSlot() == SID_SIZE_PAGE ); + + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + + if ( pPageView ) + { + Point aPagePos(0, 0); // = pPageView->GetOffset(); + Size aPageSize = pPageView->GetPage()->GetSize(); + + aPagePos.AdjustX(aPageSize.Width() / 2 ); + aPageSize.setWidth( static_cast<::tools::Long>(aPageSize.Width() * 1.03) ); + + if( rReq.GetSlot() == SID_SIZE_PAGE ) + { + aPagePos.AdjustY(aPageSize.Height() / 2 ); + aPageSize.setHeight( static_cast<::tools::Long>(aPageSize.Height() * 1.03) ); + aPagePos.AdjustY( -(aPageSize.Height() / 2) ); + } + else + { + Point aPt = GetActiveWindow()->PixelToLogic( Point( 0, GetActiveWindow()->GetSizePixel().Height() / 2 ) ); + aPagePos.AdjustY(aPt.Y() ); + aPageSize.setHeight( 2 ); + } + + aPagePos.AdjustX( -(aPageSize.Width() / 2) ); + + SetZoomRect( ::tools::Rectangle( aPagePos, aPageSize ) ); + + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), + GetActiveWindow()->GetOutputSizePixel()) ); + mpZoomList->InsertZoomRect(aVisAreaWin); + } + Invalidate( SID_ZOOM_IN ); + Invalidate( SID_ZOOM_OUT ); + Invalidate( SID_ZOOM_PANNING ); + rReq.Done (); + } + break; + + case SID_SIZE_REAL: // BASIC + { + mbZoomOnPage = false; + SetZoom( 100 ); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), + GetActiveWindow()->GetOutputSizePixel()) ); + mpZoomList->InsertZoomRect(aVisAreaWin); + Invalidate( SID_ZOOM_IN ); + Invalidate( SID_ZOOM_OUT ); + Invalidate( SID_ZOOM_PANNING ); + rReq.Done (); + } + break; + + case SID_ZOOM_OUT: // BASIC + { + const sal_uInt16 nOldZoom = GetActiveWindow()->GetZoom(); + const sal_uInt16 nNewZoom = basegfx::zoomtools::zoomOut(nOldZoom); + SetZoom(nNewZoom); + + mbZoomOnPage = false; + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), + GetActiveWindow()->GetOutputSizePixel()) ); + mpZoomList->InsertZoomRect(aVisAreaWin); + Invalidate( SID_ZOOM_IN ); + Invalidate( SID_ZOOM_OUT ); + Invalidate( SID_ZOOM_PANNING ); + rReq.Done (); + } + break; + + case SID_ZOOM_IN: + { + const sal_uInt16 nOldZoom = GetActiveWindow()->GetZoom(); + const sal_uInt16 nNewZoom = basegfx::zoomtools::zoomIn(nOldZoom); + SetZoom(nNewZoom); + + mbZoomOnPage = false; + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), + GetActiveWindow()->GetOutputSizePixel()) ); + mpZoomList->InsertZoomRect(aVisAreaWin); + Invalidate( SID_ZOOM_IN ); + Invalidate(SID_ZOOM_OUT); + Invalidate( SID_ZOOM_PANNING ); + rReq.Done (); + } + break; + + case SID_SIZE_VISAREA: + { + ::tools::Rectangle aVisArea = mpFrameView->GetVisArea(); + Size aVisAreaSize = aVisArea.GetSize(); + + if (!aVisAreaSize.IsEmpty()) + { + mbZoomOnPage = false; + SetZoomRect(aVisArea); + Invalidate( SID_ZOOM_IN ); + Invalidate( SID_ZOOM_OUT ); + Invalidate( SID_ZOOM_PANNING ); + } + rReq.Done (); + } + break; + + // name confusion: SID_SIZE_OPTIMAL -> Zoom onto selected objects + // --> Is offered as object zoom in program + case SID_SIZE_OPTIMAL: // BASIC + { + mbZoomOnPage = false; + if ( mpDrawView->AreObjectsMarked() ) + { + maMarkRect = mpDrawView->GetAllMarkedRect(); + ::tools::Long nW = static_cast<::tools::Long>(maMarkRect.GetWidth() * 1.03); + ::tools::Long nH = static_cast<::tools::Long>(maMarkRect.GetHeight() * 1.03); + Point aPos = maMarkRect.Center(); + aPos.AdjustX( -(nW / 2) ); + aPos.AdjustY( -(nH / 2) ); + if ( nW && nH ) + { + SetZoomRect(::tools::Rectangle(aPos, Size(nW, nH))); + + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), + GetActiveWindow()->GetOutputSizePixel()) ); + mpZoomList->InsertZoomRect(aVisAreaWin); + } + } + Invalidate( SID_ZOOM_IN ); + Invalidate( SID_ZOOM_OUT ); + Invalidate( SID_ZOOM_PANNING ); + rReq.Done (); + } + break; + + // name confusion: SID_SIZE_ALL -> Zoom onto all objects + // --> Is offered as optimal in program + case SID_SIZE_ALL: // BASIC + { + mbZoomOnPage = false; + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + + if( pPageView ) + { + ::tools::Rectangle aBoundRect( pPageView->GetObjList()->GetAllObjBoundRect() ); + + ::tools::Long nW = static_cast<::tools::Long>(aBoundRect.GetWidth() * 1.03); + ::tools::Long nH = static_cast<::tools::Long>(aBoundRect.GetHeight() * 1.03); + Point aPos = aBoundRect.Center(); + aPos.AdjustX( -(nW / 2) ); + aPos.AdjustY( -(nH / 2) ); + if ( nW && nH ) + { + SetZoomRect( ::tools::Rectangle( aPos, Size( nW, nH ) ) ); + + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), + GetActiveWindow()->GetOutputSizePixel()) ); + mpZoomList->InsertZoomRect(aVisAreaWin); + } + + Invalidate( SID_ZOOM_IN ); + Invalidate( SID_ZOOM_OUT ); + Invalidate( SID_ZOOM_PANNING ); + } + rReq.Done (); + } + break; + + case SID_ZOOM_PREV: + { + if (mpDrawView->IsTextEdit()) + { + mpDrawView->SdrEndTextEdit(); + } + + if (mpZoomList->IsPreviousPossible()) + { + // set previous ZoomRect + SetZoomRect(mpZoomList->GetPreviousZoomRect()); + } + rReq.Done (); + } + break; + + case SID_ZOOM_NEXT: + { + if (mpDrawView->IsTextEdit()) + { + mpDrawView->SdrEndTextEdit(); + } + + if (mpZoomList->IsNextPossible()) + { + // set next ZoomRect + SetZoomRect(mpZoomList->GetNextZoomRect()); + } + rReq.Done (); + } + break; + + case SID_GLUE_INSERT_POINT: + case SID_GLUE_PERCENT: + case SID_GLUE_ESCDIR: + case SID_GLUE_ESCDIR_LEFT: + case SID_GLUE_ESCDIR_RIGHT: + case SID_GLUE_ESCDIR_TOP: + case SID_GLUE_ESCDIR_BOTTOM: + case SID_GLUE_HORZALIGN_CENTER: + case SID_GLUE_HORZALIGN_LEFT: + case SID_GLUE_HORZALIGN_RIGHT: + case SID_GLUE_VERTALIGN_CENTER: + case SID_GLUE_VERTALIGN_TOP: + case SID_GLUE_VERTALIGN_BOTTOM: + { + rtl::Reference<FuPoor> xFunc( GetCurrentFunction() ); + FuEditGluePoints* pFunc = dynamic_cast< FuEditGluePoints* >( xFunc.get() ); + + if(pFunc) + pFunc->ReceiveRequest(rReq); + + rReq.Done(); + } + break; + + case SID_AUTOSPELL_CHECK: + { + bool bOnlineSpell; + const SfxPoolItem* pItem; + + if (rReq.GetArgs()->HasItem(FN_PARAM_1, &pItem)) + bOnlineSpell = static_cast<const SfxBoolItem*>(pItem)->GetValue(); + else // Toggle + bOnlineSpell = !GetDoc()->GetOnlineSpell(); + + GetDoc()->SetOnlineSpell(bOnlineSpell); + + ::Outliner* pOL = mpDrawView->GetTextEditOutliner(); + + if (pOL) + { + EEControlBits nCntrl = pOL->GetControlWord(); + + if (bOnlineSpell) + nCntrl |= EEControlBits::ONLINESPELLING; + else + nCntrl &= ~EEControlBits::ONLINESPELLING; + + pOL->SetControlWord(nCntrl); + } + + GetActiveWindow()->Invalidate(); + rReq.Done (); + } + break; + + case SID_TRANSLITERATE_SENTENCE_CASE: + case SID_TRANSLITERATE_TITLE_CASE: + case SID_TRANSLITERATE_TOGGLE_CASE: + case SID_TRANSLITERATE_UPPER: + case SID_TRANSLITERATE_LOWER: + case SID_TRANSLITERATE_HALFWIDTH: + case SID_TRANSLITERATE_FULLWIDTH: + case SID_TRANSLITERATE_HIRAGANA: + case SID_TRANSLITERATE_KATAKANA: + { + OutlinerView* pOLV = GetView()->GetTextEditOutlinerView(); + if( pOLV ) + { + TransliterationFlags nType = TransliterationFlags::NONE; + + switch( nSId ) + { + case SID_TRANSLITERATE_SENTENCE_CASE: + nType = TransliterationFlags::SENTENCE_CASE; + break; + case SID_TRANSLITERATE_TITLE_CASE: + nType = TransliterationFlags::TITLE_CASE; + break; + case SID_TRANSLITERATE_TOGGLE_CASE: + nType = TransliterationFlags::TOGGLE_CASE; + break; + case SID_TRANSLITERATE_UPPER: + nType = TransliterationFlags::LOWERCASE_UPPERCASE; + break; + case SID_TRANSLITERATE_LOWER: + nType = TransliterationFlags::UPPERCASE_LOWERCASE; + break; + case SID_TRANSLITERATE_HALFWIDTH: + nType = TransliterationFlags::FULLWIDTH_HALFWIDTH; + break; + case SID_TRANSLITERATE_FULLWIDTH: + nType = TransliterationFlags::HALFWIDTH_FULLWIDTH; + break; + case SID_TRANSLITERATE_HIRAGANA: + nType = TransliterationFlags::KATAKANA_HIRAGANA; + break; + case SID_TRANSLITERATE_KATAKANA: + nType = TransliterationFlags::HIRAGANA_KATAKANA; + break; + } + + pOLV->TransliterateText( nType ); + } + + rReq.Done(); + } + break; + + // #UndoRedo# + case SID_UNDO : + { + // moved implementation to BaseClass + ImpSidUndo(rReq); + } + break; + case SID_REDO : + { + // moved implementation to BaseClass + ImpSidRedo(rReq); + } + break; + + default: + break; + } +} + +void DrawViewShell::FuSupportRotate(SfxRequest const &rReq) +{ + if( rReq.GetSlot() != SID_TRANSLITERATE_ROTATE_CASE ) + return; + + ::sd::View* pView = GetView(); + + if (!pView) + return; + + OutlinerView* pOLV = pView->GetTextEditOutlinerView(); + + if (!pOLV) + return; + + pOLV->TransliterateText( m_aRotateCase.getNextMode() ); +} + +void DrawViewShell::InsertURLField(const OUString& rURL, const OUString& rText, + const OUString& rTarget) +{ + OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView(); + + if (pOLV) + { + ESelection aSel( pOLV->GetSelection() ); + SvxFieldItem aURLItem( SvxURLField( rURL, rText, SvxURLFormat::Repr ), EE_FEATURE_FIELD ); + pOLV->InsertField( aURLItem ); + if ( aSel.nStartPos <= aSel.nEndPos ) + aSel.nEndPos = aSel.nStartPos + 1; + else + aSel.nStartPos = aSel.nEndPos + 1; + pOLV->SetSelection( aSel ); + } + else + { + Outliner* pOutl = GetDoc()->GetInternalOutliner(); + pOutl->Init( OutlinerMode::TextObject ); + OutlinerMode nOutlMode = pOutl->GetOutlinerMode(); + + SvxURLField aURLField(rURL, rText, SvxURLFormat::Repr); + aURLField.SetTargetFrame(rTarget); + SvxFieldItem aURLItem(aURLField, EE_FEATURE_FIELD); + pOutl->QuickInsertField( aURLItem, ESelection() ); + std::optional<OutlinerParaObject> pOutlParaObject = pOutl->CreateParaObject(); + + rtl::Reference<SdrRectObj> pRectObj = new SdrRectObj( + GetView()->getSdrModelFromSdrView(), + SdrObjKind::Text); + + pOutl->UpdateFields(); + pOutl->SetUpdateLayout( true ); + Size aSize(pOutl->CalcTextSize()); + pOutl->SetUpdateLayout( false ); + + Point aPos; + ::tools::Rectangle aRect(aPos, GetActiveWindow()->GetOutputSizePixel() ); + aPos = aRect.Center(); + aPos = GetActiveWindow()->PixelToLogic(aPos); + + if (aPos.getX() - (aSize.Width() / 2) >= 0) + aPos.AdjustX( -(aSize.Width() / 2) ); + if (aPos.getY() - (aSize.Height() / 2) >= 0) + aPos.AdjustY( -(aSize.Height() / 2) ); + + ::tools::Rectangle aLogicRect(aPos, aSize); + pRectObj->SetLogicRect(aLogicRect); + pRectObj->SetOutlinerParaObject( std::move(pOutlParaObject) ); + mpDrawView->InsertObjectAtView(pRectObj.get(), *mpDrawView->GetSdrPageView()); + pOutl->Init( nOutlMode ); + } +} + +void DrawViewShell::InsertURLButton(const OUString& rURL, const OUString& rText, + const OUString& rTarget, const Point* pPos) +{ + bool bNewObj = true; + + const OUString sTargetURL( ::URIHelper::SmartRel2Abs( INetURLObject( GetDocSh()->GetMedium()->GetBaseURL() ), rURL, URIHelper::GetMaybeFileHdl(), true, false, + INetURLObject::EncodeMechanism::WasEncoded, + INetURLObject::DecodeMechanism::Unambiguous ) ); + if (mpDrawView->GetMarkedObjectList().GetMarkCount() > 0) + { + SdrObject* pMarkedObj = mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(); + if( pMarkedObj ) try + { + // change first marked object + if (SdrInventor::FmForm == pMarkedObj->GetObjInventor()) + { + SdrUnoObj* pUnoCtrl = static_cast< SdrUnoObj* >( pMarkedObj ); + + Reference< awt::XControlModel > xControlModel( pUnoCtrl->GetUnoControlModel(), UNO_SET_THROW ); + Reference< beans::XPropertySet > xPropSet( xControlModel, UNO_QUERY_THROW ); + + bool bIsButton = pMarkedObj->GetObjIdentifier() == SdrObjKind::FormButton; + if (!bIsButton && pMarkedObj->GetObjIdentifier() == SdrObjKind::UNO) + { + const Reference<beans::XPropertySetInfo> xInfo(xPropSet->getPropertySetInfo()); + bIsButton = xInfo.is() && xInfo->hasPropertyByName("ButtonType") + && xInfo->hasPropertyByName("Label") + && xInfo->hasPropertyByName("TargetURL"); + } + if (bIsButton) + { + bNewObj = false; + + xPropSet->setPropertyValue("Label", Any(rText)); + xPropSet->setPropertyValue("TargetURL", Any(sTargetURL)); + + if (!rTarget.isEmpty()) + xPropSet->setPropertyValue("TargetFrame", Any(rTarget)); + + xPropSet->setPropertyValue("ButtonType", Any(form::FormButtonType_URL)); +#if HAVE_FEATURE_AVMEDIA + if (::avmedia::MediaWindow::isMediaURL(rURL, ""/*TODO?*/)) + { + xPropSet->setPropertyValue("DispatchURLInternal", Any(true)); + } +#endif + } + } + if (bNewObj) + { + // add url as interaction for first selected shape + bNewObj = false; + + SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pMarkedObj, true); + pInfo->meClickAction = presentation::ClickAction_DOCUMENT; + pInfo->SetBookmark( sTargetURL ); + } + } + catch( uno::Exception& ) + { + } + } + + if (!bNewObj) + return; + + try + { + rtl::Reference<SdrUnoObj> pUnoCtrl = static_cast< SdrUnoObj* >( + SdrObjFactory::MakeNewObject( + GetView()->getSdrModelFromSdrView(), + SdrInventor::FmForm, + SdrObjKind::FormButton).get()); //, + //mpDrawView->GetSdrPageView()->GetPage())); + + Reference< awt::XControlModel > xControlModel( pUnoCtrl->GetUnoControlModel(), uno::UNO_SET_THROW ); + Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY_THROW ); + + xPropSet->setPropertyValue( "Label" , Any( rText ) ); + xPropSet->setPropertyValue( "TargetURL" , Any( sTargetURL ) ); + + if( !rTarget.isEmpty() ) + xPropSet->setPropertyValue( "TargetFrame" , Any( rTarget ) ); + + xPropSet->setPropertyValue( "ButtonType" , Any( form::FormButtonType_URL ) ); +#if HAVE_FEATURE_AVMEDIA + if ( ::avmedia::MediaWindow::isMediaURL( rURL, ""/*TODO?*/ ) ) + xPropSet->setPropertyValue( "DispatchURLInternal" , Any( true ) ); +#endif + + Point aPos; + + if (pPos) + { + aPos = *pPos; + } + else + { + aPos = ::tools::Rectangle(aPos, GetActiveWindow()->GetOutputSizePixel()).Center(); + aPos = GetActiveWindow()->PixelToLogic(aPos); + } + + Size aSize(4000, 1000); + aPos.AdjustX( -(aSize.Width() / 2) ); + aPos.AdjustY( -(aSize.Height() / 2) ); + pUnoCtrl->SetLogicRect(::tools::Rectangle(aPos, aSize)); + + SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER; + + OSL_ASSERT (GetViewShell()!=nullptr); + SfxInPlaceClient* pIpClient = GetViewShell()->GetIPClient(); + if (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive()) + { + nOptions |= SdrInsertFlags::DONTMARK; + } + + mpDrawView->InsertObjectAtView(pUnoCtrl.get(), *mpDrawView->GetSdrPageView(), nOptions); + } + catch( Exception& ) + { + } +} + +void DrawViewShell::ShowUIControls (bool bVisible) +{ + ViewShell::ShowUIControls (bVisible); + maTabControl->Show (bVisible); +} + +namespace slideshowhelp +{ + void ShowSlideShow(SfxRequest const & rReq, SdDrawDocument &rDoc) + { + Reference< XPresentation2 > xPresentation( rDoc.getPresentation() ); + if( !xPresentation.is() ) + return; + + sfx2::SfxNotebookBar::LockNotebookBar(); + if (SID_REHEARSE_TIMINGS == rReq.GetSlot()) + xPresentation->rehearseTimings(); + else if (rDoc.getPresentationSettings().mbCustomShow) + { + //fdo#69975 if a custom show has been set, then + //use it whether or not we've been asked to + //start from the current or first slide + xPresentation->start(); + + // if the custom show not set by default, only show it. + if (rDoc.getPresentationSettings().mbStartCustomShow) + rDoc.getPresentationSettings().mbCustomShow = false; + } + else if (SID_PRESENTATION_CURRENT_SLIDE == rReq.GetSlot()) + { + //If there is no custom show set, start will automatically + //start at the current page + xPresentation->start(); + } + else + { + //Start at page 0, this would blow away any custom + //show settings if any were set + Sequence< PropertyValue > aArguments{ comphelper::makePropertyValue("FirstPage", + OUString("0")) }; + xPresentation->startWithArguments( aArguments ); + } + sfx2::SfxNotebookBar::UnlockNotebookBar(); + } +} + +void DrawViewShell::StopSlideShow() +{ + Reference< XPresentation2 > xPresentation( GetDoc()->getPresentation() ); + if(xPresentation.is() && xPresentation->isRunning()) + { + if( mpDrawView->IsTextEdit() ) + mpDrawView->SdrEndTextEdit(); + + xPresentation->end(); + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsf.cxx b/sd/source/ui/view/drviewsf.cxx new file mode 100644 index 0000000000..1844d79603 --- /dev/null +++ b/sd/source/ui/view/drviewsf.cxx @@ -0,0 +1,844 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> +#include <com/sun/star/form/FormButtonType.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <comphelper/string.hxx> +#include <svx/svxids.hrc> +#include <svx/sdmetitm.hxx> +#include <svx/hlnkitem.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/udlnitem.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/whiter.hxx> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/itempool.hxx> +#include <sfx2/tplpitem.hxx> +#include <sfx2/bindings.hxx> +#include <svx/xdef.hxx> +#include <svx/svdoutl.hxx> +#include <svx/svdouno.hxx> +#include <svx/svdpagv.hxx> +#include <svx/fmshell.hxx> +#include <svl/cjkoptions.hxx> +#include <app.hrc> + +#include <sdmod.hxx> +#include <sdpage.hxx> +#include <stlsheet.hxx> +#include <drawview.hxx> +#include <drawdoc.hxx> +#include <Window.hxx> +#include <ViewShellBase.hxx> +#include <FormShellManager.hxx> +#include <anminfo.hxx> + +#include <editeng/lspcitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/escapementitem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/adjustitem.hxx> +#include <editeng/urlfieldhelper.hxx> +#include <svx/nbdtmgfact.hxx> +#include <svx/nbdtmg.hxx> +#include <memory> + +using namespace com::sun::star::drawing; +using namespace svx::sidebar; +using namespace ::com::sun::star; + +namespace sd { + +/** + * Set state of controller SfxSlots + */ +void DrawViewShell::GetCtrlState(SfxItemSet &rSet) +{ + if (rSet.GetItemState(SID_RELOAD) != SfxItemState::UNKNOWN) + { + // let "last version" of SFx en/disable + GetViewFrame()->GetSlotState (SID_RELOAD, nullptr, &rSet); + } + + if (SfxItemState::DEFAULT == rSet.GetItemState(SID_HYPERLINK_GETLINK)) + { + SvxHyperlinkItem aHLinkItem; + + OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView(); + + if (pOLV) + { + const SvxFieldItem* pFieldItem = pOLV->GetFieldAtSelection(); + const SvxFieldData* pField = pFieldItem ? pFieldItem->GetField() : nullptr; + if( auto pUrlField = dynamic_cast< const SvxURLField *>( pField ) ) + { + aHLinkItem.SetName(pUrlField->GetRepresentation()); + aHLinkItem.SetURL(pUrlField->GetURL()); + aHLinkItem.SetTargetFrame(pUrlField->GetTargetFrame()); + } + else + { + // use selected text as name for urls + OUString sReturn = pOLV->GetSelected(); + if (sReturn.getLength() > 255) + sReturn = sReturn.copy(0, 255); + aHLinkItem.SetName(comphelper::string::stripEnd(sReturn, ' ')); + } + } + else + { + if (mpDrawView->GetMarkedObjectList().GetMarkCount() > 0) + { + bool bFound = false; + + SdrObject* pMarkedObj = mpDrawView->GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(); + if( pMarkedObj && (SdrInventor::FmForm == pMarkedObj->GetObjInventor()) ) + { + SdrUnoObj* pUnoCtrl = dynamic_cast< SdrUnoObj* >( pMarkedObj ); + + if(pUnoCtrl) try + { + uno::Reference< awt::XControlModel > xControlModel( pUnoCtrl->GetUnoControlModel(), uno::UNO_SET_THROW ); + uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySetInfo > xPropInfo( xPropSet->getPropertySetInfo(), uno::UNO_SET_THROW ); + + form::FormButtonType eButtonType = form::FormButtonType_URL; + static constexpr OUString sButtonType( u"ButtonType"_ustr ); + if(xPropInfo->hasPropertyByName( sButtonType ) && (xPropSet->getPropertyValue( sButtonType ) >>= eButtonType ) ) + { + OUString aString; + + // Label + static constexpr OUString sLabel( u"Label"_ustr ); + if(xPropInfo->hasPropertyByName(sLabel)) + { + if( xPropSet->getPropertyValue(sLabel) >>= aString ) + aHLinkItem.SetName(aString); + } + + // URL + static constexpr OUString sTargetURL( u"TargetURL"_ustr ); + if(xPropInfo->hasPropertyByName(sTargetURL)) + { + if( xPropSet->getPropertyValue(sTargetURL) >>= aString ) + aHLinkItem.SetURL(aString); + } + + // Target + static constexpr OUString sTargetFrame( u"TargetFrame"_ustr ); + if(xPropInfo->hasPropertyByName(sTargetFrame) ) + { + if( xPropSet->getPropertyValue(sTargetFrame) >>= aString ) + aHLinkItem.SetTargetFrame(aString); + } + + aHLinkItem.SetInsertMode(HLINK_BUTTON); + bFound = true; + } + } + catch( uno::Exception& ) + { + } + } + + // try interaction link + if( !bFound && pMarkedObj ) + { + SdAnimationInfo* pInfo = SdDrawDocument::GetShapeUserData(*pMarkedObj); + if( pInfo && (pInfo->meClickAction == presentation::ClickAction_DOCUMENT) ) + aHLinkItem.SetURL( pInfo->GetBookmark()); + aHLinkItem.SetInsertMode(HLINK_BUTTON); + } + } + } + + rSet.Put(aHLinkItem); + } + rSet.Put( SfxBoolItem( SID_READONLY_MODE, mbReadOnly ) ); + + // output quality + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTPUT_QUALITY_COLOR ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTPUT_QUALITY_GRAYSCALE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTPUT_QUALITY_BLACKWHITE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTPUT_QUALITY_CONTRAST ) ) + { + const sal_uLong nMode = static_cast<sal_Int32>(GetActiveWindow()->GetOutDev()->GetDrawMode()); + rSet.Put( SfxBoolItem( SID_OUTPUT_QUALITY_COLOR, sal_uLong(OUTPUT_DRAWMODE_COLOR) == nMode ) ); + rSet.Put( SfxBoolItem( SID_OUTPUT_QUALITY_GRAYSCALE, static_cast<sal_uLong>(OUTPUT_DRAWMODE_GRAYSCALE) == nMode ) ); + rSet.Put( SfxBoolItem( SID_OUTPUT_QUALITY_BLACKWHITE, static_cast<sal_uLong>(OUTPUT_DRAWMODE_BLACKWHITE) == nMode ) ); + rSet.Put( SfxBoolItem( SID_OUTPUT_QUALITY_CONTRAST, static_cast<sal_uLong>(OUTPUT_DRAWMODE_CONTRAST) == nMode ) ); + } + + if ( SfxItemState::DEFAULT == rSet.GetItemState(SID_MAIL_SCROLLBODY_PAGEDOWN) ) + { + rSet.Put( SfxBoolItem( SID_MAIL_SCROLLBODY_PAGEDOWN, true ) ); + } + + if ( SfxItemState::DEFAULT == rSet.GetItemState(SID_ATTR_YEAR2000) ) + { + FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell(); + if (pFormShell != nullptr) + { + sal_uInt16 nState = 0; + if (pFormShell->GetY2KState(nState)) + rSet.Put( SfxUInt16Item( SID_ATTR_YEAR2000, nState ) ); + else + rSet.DisableItem( SID_ATTR_YEAR2000 ); + } + } + + if ( !GetView()->GetTextEditOutliner() ) + { + if( !SvtCJKOptions::IsChangeCaseMapEnabled() ) + { + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, false ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, false ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, false ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, false ); + } + else + { + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, true ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, true ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, true ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, true ); + } + + rSet.DisableItem( SID_TRANSLITERATE_SENTENCE_CASE ); + rSet.DisableItem( SID_TRANSLITERATE_TITLE_CASE ); + rSet.DisableItem( SID_TRANSLITERATE_TOGGLE_CASE ); + rSet.DisableItem( SID_TRANSLITERATE_UPPER ); + rSet.DisableItem( SID_TRANSLITERATE_LOWER ); + rSet.DisableItem( SID_TRANSLITERATE_HALFWIDTH ); + rSet.DisableItem( SID_TRANSLITERATE_FULLWIDTH ); + rSet.DisableItem( SID_TRANSLITERATE_HIRAGANA ); + rSet.DisableItem( SID_TRANSLITERATE_KATAKANA ); + } + else + { + if( !SvtCJKOptions::IsChangeCaseMapEnabled() ) + { + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, false ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, false ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, false ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, false ); + rSet.DisableItem( SID_TRANSLITERATE_HALFWIDTH ); + rSet.DisableItem( SID_TRANSLITERATE_FULLWIDTH ); + rSet.DisableItem( SID_TRANSLITERATE_HIRAGANA ); + rSet.DisableItem( SID_TRANSLITERATE_KATAKANA ); + } + else + { + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, true ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, true ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, true ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, true ); + } + } +} + +void DrawViewShell::GetAttrState( SfxItemSet& rSet ) +{ + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + + bool bAttr = false; + SfxAllItemSet aAllSet( *rSet.GetPool() ); + + while ( nWhich ) + { + sal_uInt16 nSlotId = SfxItemPool::IsWhich(nWhich) + ? GetPool().GetSlotId(nWhich) + : nWhich; + switch ( nSlotId ) + { + case SID_ATTR_PARA_ADJUST_LEFT: + { + SfxItemSet aAttrs( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + + SvxAdjust eAdj = aAttrs.Get( EE_PARA_JUST ).GetAdjust(); + if ( eAdj == SvxAdjust::Left) + { + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, true ) ); + } + + bAttr = true; + + Invalidate(nSlotId); + } + break; + case SID_ATTR_PARA_ADJUST_CENTER: + { + SfxItemSet aAttrs( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + + SvxAdjust eAdj = aAttrs.Get( EE_PARA_JUST ).GetAdjust(); + if ( eAdj == SvxAdjust::Center) + { + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, true ) ); + } + + bAttr = true; + + Invalidate(nSlotId); + } + break; + case SID_ATTR_PARA_ADJUST_RIGHT: + { + SfxItemSet aAttrs( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + + SvxAdjust eAdj = aAttrs.Get( EE_PARA_JUST ).GetAdjust(); + if ( eAdj == SvxAdjust::Right) + { + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, true ) ); + } + + bAttr = true; + + Invalidate(nSlotId); + } + break; + case SID_ATTR_PARA_ADJUST_BLOCK: + { + SfxItemSet aAttrs( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + + SvxAdjust eAdj = aAttrs.Get( EE_PARA_JUST ).GetAdjust(); + if ( eAdj == SvxAdjust::Block) + { + rSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, true ) ); + } + + bAttr = true; + + Invalidate(nSlotId); + } + break; + case SID_ATTR_PARA_LRSPACE: + { + SfxItemSet aAttrs( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + SvxLRSpaceItem aLRSpace = aAttrs.Get( EE_PARA_LRSPACE ); + aLRSpace.SetWhich(SID_ATTR_PARA_LRSPACE); + rSet.Put(aLRSpace); + bAttr = true; + Invalidate(SID_ATTR_PARA_LRSPACE); + } + break; + case SID_ATTR_PARA_LINESPACE: + { + SfxItemSet aAttrs( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + SvxLineSpacingItem aLineLR = aAttrs.Get( EE_PARA_SBL ); + rSet.Put(aLineLR); + bAttr = true; + Invalidate(SID_ATTR_PARA_LINESPACE); + } + break; + case SID_ATTR_PARA_ULSPACE: + { + SfxItemSet aAttrs( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + SvxULSpaceItem aULSP = aAttrs.Get( EE_PARA_ULSPACE ); + aULSP.SetWhich(SID_ATTR_PARA_ULSPACE); + rSet.Put(aULSP); + bAttr = true; + Invalidate(SID_ATTR_PARA_ULSPACE); + } + break; + case SID_ULINE_VAL_NONE: + case SID_ULINE_VAL_SINGLE: + case SID_ULINE_VAL_DOUBLE: + case SID_ULINE_VAL_DOTTED: + { + SfxItemSet aAttrs( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + if( aAttrs.GetItemState( EE_CHAR_UNDERLINE ) >= SfxItemState::DEFAULT ) + { + FontLineStyle eLineStyle = aAttrs.Get(EE_CHAR_UNDERLINE).GetLineStyle(); + + switch (nSlotId) + { + case SID_ULINE_VAL_NONE: + rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_NONE)); + break; + case SID_ULINE_VAL_SINGLE: + rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_SINGLE)); + break; + case SID_ULINE_VAL_DOUBLE: + rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_DOUBLE)); + break; + case SID_ULINE_VAL_DOTTED: + rSet.Put(SfxBoolItem(nSlotId, eLineStyle == LINESTYLE_DOTTED)); + break; + } + } + + bAttr = true; + + Invalidate(nSlotId); + } + break; + case SID_ATTR_FILL_STYLE: + case SID_ATTR_FILL_COLOR: + case SID_ATTR_FILL_GRADIENT: + case SID_ATTR_FILL_HATCH: + case SID_ATTR_FILL_BITMAP: + case SID_ATTR_FILL_SHADOW: + case SID_ATTR_SHADOW_COLOR: + case SID_ATTR_SHADOW_TRANSPARENCE: + case SID_ATTR_SHADOW_BLUR: + case SID_ATTR_SHADOW_XDISTANCE: + case SID_ATTR_SHADOW_YDISTANCE: + case SID_ATTR_FILL_USE_SLIDE_BACKGROUND: + case SID_ATTR_FILL_TRANSPARENCE: + case SID_ATTR_FILL_FLOATTRANSPARENCE: + case SID_ATTR_LINE_STYLE: + case SID_ATTR_LINE_DASH: + case SID_ATTR_LINE_WIDTH: + case SID_ATTR_LINE_COLOR: + case SID_ATTR_LINE_TRANSPARENCE: + case SID_ATTR_LINE_JOINT: + case SID_ATTR_LINE_CAP: + case SID_ATTR_TEXT_FITTOSIZE: + case SID_ATTR_CHAR_FONT: + case SID_ATTR_CHAR_FONTHEIGHT: + case SID_ATTR_CHAR_SHADOWED: + case SID_ATTR_CHAR_POSTURE: + case SID_ATTR_CHAR_OVERLINE: + case SID_ATTR_CHAR_UNDERLINE: + case SID_ATTR_CHAR_STRIKEOUT: + case SID_ATTR_CHAR_CONTOUR: + case SID_ATTR_CHAR_WEIGHT: + case SID_ATTR_CHAR_COLOR: + case SID_ATTR_CHAR_KERNING: + case SID_ATTR_CHAR_CASEMAP: + case SID_ATTR_GLOW_COLOR: + case SID_ATTR_GLOW_RADIUS: + case SID_ATTR_GLOW_TRANSPARENCY: + case SID_ATTR_SOFTEDGE_RADIUS: + case SID_SET_SUB_SCRIPT: + case SID_SET_SUPER_SCRIPT: + { + bAttr = true; + } + break; + + case SID_ATTR_TEXTCOLUMNS_NUMBER: + case SID_ATTR_TEXTCOLUMNS_SPACING: + { + SfxItemSet aAttrs(GetDoc()->GetPool()); + mpDrawView->GetAttributes(aAttrs); + const sal_uInt16 nActWhich = nSlotId == SID_ATTR_TEXTCOLUMNS_NUMBER + ? SDRATTR_TEXTCOLUMNS_NUMBER + : SDRATTR_TEXTCOLUMNS_SPACING; + rSet.Put(aAttrs.Get(nActWhich).CloneSetWhich(nSlotId)); + } + break; + + case SID_HYPHENATION: + { + SfxItemSet aAttrs( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aAttrs ); + if( aAttrs.GetItemState( EE_PARA_HYPHENATE ) >= SfxItemState::DEFAULT ) + { + bool bValue = aAttrs.Get( EE_PARA_HYPHENATE ).GetValue(); + rSet.Put( SfxBoolItem( SID_HYPHENATION, bValue ) ); + } + } + break; + + case SID_THEME_DIALOG: + { + bool bDisable = true; + SdrPageView* pPageView = mpDrawView->GetSdrPageView(); + if (pPageView) + { + SdPage* pPage = dynamic_cast<SdPage*>(pPageView->GetPage()); + if (pPage && pPage->IsMasterPage()) + bDisable = false; + } + if (bDisable) + rSet.DisableItem(nWhich); + } + break; + + case SID_STYLE_FAMILY2: + case SID_STYLE_FAMILY3: + case SID_STYLE_FAMILY5: + case SID_STYLE_APPLY: // StyleControl + { + SfxStyleSheet* pStyleSheet = mpDrawView->GetStyleSheet(); + if( pStyleSheet ) + { + if( nSlotId != SID_STYLE_APPLY && !mpDrawView->AreObjectsMarked() ) + { + SfxTemplateItem aTmpItem( nWhich, OUString() ); + aAllSet.Put( aTmpItem, aTmpItem.Which() ); + } + else + { + if (pStyleSheet->GetFamily() == SfxStyleFamily::Page) + pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet(); + + if( pStyleSheet ) + { + SfxStyleFamily eFamily = pStyleSheet->GetFamily(); + + if ((eFamily == SfxStyleFamily::Para && nSlotId == SID_STYLE_FAMILY2) || + (eFamily == SfxStyleFamily::Frame && nSlotId == SID_STYLE_FAMILY3) || + (eFamily == SfxStyleFamily::Pseudo && nSlotId == SID_STYLE_FAMILY5)) + { + SfxTemplateItem aTmpItem ( nWhich, pStyleSheet->GetName() ); + aAllSet.Put( aTmpItem, aTmpItem.Which() ); + } + else + { + SfxTemplateItem aTmpItem(nWhich, OUString()); + aAllSet.Put(aTmpItem,aTmpItem.Which() ); + } + } + } + } + else + { SfxTemplateItem aItem( nWhich, OUString() ); + aAllSet.Put( aItem, aItem.Which() ); + } + } + break; + + case SID_SET_DEFAULT: + { + if( !mpDrawView->GetMarkedObjectList().GetMarkCount() || + ( !mpDrawView->IsTextEdit() && !mpDrawView->GetStyleSheet() ) + ) + rSet.DisableItem( nWhich ); + } + break; + + case SID_REMOVE_HYPERLINK: + { + if (!URLFieldHelper::IsCursorAtURLField(mpDrawView->GetTextEditOutlinerView(), + /*AlsoCheckBeforeCursor=*/true)) + rSet.DisableItem(nWhich); + } + break; + + case SID_STYLE_WATERCAN: + { + std::unique_ptr<SfxUInt16Item> pFamilyItem; + GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem); + if (pFamilyItem && static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo) + rSet.Put(SfxBoolItem(nWhich,false)); + else + { + SfxBoolItem aItem(nWhich, SD_MOD()->GetWaterCan()); + aAllSet.Put( aItem, aItem.Which()); + } + } + break; + + case SID_STYLE_NEW: + { + std::unique_ptr<SfxUInt16Item> pFamilyItem; + GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem); + if (pFamilyItem && static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo) + { + rSet.DisableItem(nWhich); + } + } + break; + + case SID_STYLE_DRAGHIERARCHIE: + { + std::unique_ptr<SfxUInt16Item> pFamilyItem; + GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem); + if (pFamilyItem && static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo) + rSet.DisableItem(nWhich); + } + break; + + case SID_STYLE_NEW_BY_EXAMPLE: + { + // It is not possible to create PseudoStyleSheets 'by Example'; + // normal style sheets need a selected object for that + + std::unique_ptr<SfxUInt16Item> pFamilyItem; + GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem); + if (pFamilyItem) + { + if (static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo) + { + rSet.DisableItem(nWhich); + } + else if (static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Para) + { + if (!mpDrawView->AreObjectsMarked()) + { + rSet.DisableItem(nWhich); + } + } + } + // if there is no (yet) a style designer, we have to go back into the + // view state; an actual set family can not be considered + else + { + if (!mpDrawView->AreObjectsMarked()) + { + rSet.DisableItem(nWhich); + } + } + } + break; + + case SID_STYLE_UPDATE_BY_EXAMPLE: + { + if (!mpDrawView->AreObjectsMarked()) + { + rSet.DisableItem(nWhich); + } + } + break; + case FN_BUL_NUM_RULE_INDEX: + case FN_NUM_NUM_RULE_INDEX: + { + SfxItemSet aEditAttr( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( aEditAttr ); + + SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aNewAttr( GetPool() ); + aNewAttr.Put( aEditAttr, false ); + + std::unique_ptr<SvxNumRule> pNumRule; + const SfxPoolItem* pTmpItem=nullptr; + TypedWhichId<SvxNumBulletItem> nNumItemId = SID_ATTR_NUMBERING_RULE; + sal_uInt16 nActNumLvl = mpDrawView->GetSelectionLevel(); + pTmpItem=GetNumBulletItem(aNewAttr, nNumItemId); + + if (pTmpItem) + pNumRule.reset(new SvxNumRule(static_cast<const SvxNumBulletItem*>(pTmpItem)->GetNumRule())); + + if ( pNumRule ) + { + sal_uInt16 nMask = 1; + sal_uInt16 nCount = 0; + sal_uInt16 nCurLevel = sal_uInt16(0xFFFF); + for(sal_uInt16 i = 0; i < pNumRule->GetLevelCount(); i++) + { + if(nActNumLvl & nMask) + { + nCount++; + nCurLevel = i; + } + nMask <<= 1; + } + if ( nCount == 1 ) + { + const SvxNumberFormat* pNumFmt = pNumRule->Get(nCurLevel); + if ( pNumFmt ) + { + bool bBullets = false; + switch(pNumFmt->GetNumberingType()) + { + case SVX_NUM_CHAR_SPECIAL: + case SVX_NUM_BITMAP: + bBullets = true; + break; + + default: + bBullets = false; + } + + rSet.Put(SfxUInt16Item(FN_BUL_NUM_RULE_INDEX,sal_uInt16(0xFFFF))); + rSet.Put(SfxUInt16Item(FN_NUM_NUM_RULE_INDEX,sal_uInt16(0xFFFF))); + if ( bBullets ) + { + NBOTypeMgrBase* pBullets = NBOutlineTypeMgrFact::CreateInstance(NBOType::Bullets); + if ( pBullets ) + { + sal_uInt16 nBulIndex = pBullets->GetNBOIndexForNumRule(*pNumRule,nActNumLvl); + rSet.Put(SfxUInt16Item(FN_BUL_NUM_RULE_INDEX,nBulIndex)); + } + }else + { + NBOTypeMgrBase* pNumbering = NBOutlineTypeMgrFact::CreateInstance(NBOType::Numbering); + if ( pNumbering ) + { + sal_uInt16 nBulIndex = pNumbering->GetNBOIndexForNumRule(*pNumRule,nActNumLvl); + rSet.Put(SfxUInt16Item(FN_NUM_NUM_RULE_INDEX,nBulIndex)); + } + } + } + } + } + } + break; + case FN_NUM_BULLET_ON: + case FN_NUM_NUMBERING_ON: + { + bool bEnable = false; + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const size_t nMarkCount = rMarkList.GetMarkCount(); + for (size_t nIndex = 0; nIndex < nMarkCount; ++nIndex) + { + SdrTextObj* pTextObj = DynCastSdrTextObj(rMarkList.GetMark(nIndex)->GetMarkedSdrObj()); + if (pTextObj && pTextObj->GetObjInventor() == SdrInventor::Default) + { + if (pTextObj->GetObjIdentifier() != SdrObjKind::OLE2) + { + bEnable = true; + break; + } + } + } + if (bEnable) + { + rSet.Put(SfxBoolItem(FN_NUM_BULLET_ON, false)); + rSet.Put(SfxBoolItem(FN_NUM_NUMBERING_ON, false)); + } + else + { + rSet.DisableItem(FN_NUM_BULLET_ON); + rSet.DisableItem(FN_NUM_NUMBERING_ON); + } + } + break; + } + nWhich = aIter.NextWhich(); + } + + std::optional<SfxItemSet> pSet; + + if( bAttr ) + { + pSet.emplace( GetDoc()->GetPool() ); + mpDrawView->GetAttributes( *pSet ); + rSet.Put( *pSet, false ); + } + + rSet.Put( aAllSet, false ); + + // there were changes at area and/or line attributes + if( !(bAttr && pSet) ) + return; + + // if the view owns selected objects, corresponding items have to be + // changed from SfxItemState::DEFAULT (_ON) to SfxItemState::DISABLED + if( mpDrawView->AreObjectsMarked() ) + { + SfxWhichIter aNewIter( *pSet ); + nWhich = aNewIter.FirstWhich(); + while( nWhich ) + { + if (nWhich >= XATTR_LINE_FIRST && nWhich <= XATTR_LINE_LAST + && SfxItemState::DEFAULT == aNewIter.GetItemState() ) + { + rSet.ClearItem( nWhich ); + rSet.DisableItem( nWhich ); + } + nWhich = aNewIter.NextWhich(); + } + } + + SfxItemState eState = pSet->GetItemState( EE_PARA_LRSPACE ); + if ( eState == SfxItemState::DONTCARE ) + { + rSet.InvalidateItem(EE_PARA_LRSPACE); + rSet.InvalidateItem(SID_ATTR_PARA_LRSPACE); + } + eState = pSet->GetItemState( EE_PARA_SBL ); + if ( eState == SfxItemState::DONTCARE ) + { + rSet.InvalidateItem(EE_PARA_SBL); + rSet.InvalidateItem(SID_ATTR_PARA_LINESPACE); + } + eState = pSet->GetItemState( EE_PARA_ULSPACE ); + if ( eState == SfxItemState::DONTCARE ) + { + rSet.InvalidateItem(EE_PARA_ULSPACE); + rSet.InvalidateItem(SID_ATTR_PARA_ULSPACE); + } + + SvxEscapement eEsc = static_cast<SvxEscapement>(pSet->Get( EE_CHAR_ESCAPEMENT ).GetEnumValue()); + rSet.Put(SfxBoolItem(SID_SET_SUPER_SCRIPT, eEsc == SvxEscapement::Superscript)); + rSet.Put(SfxBoolItem(SID_SET_SUB_SCRIPT, eEsc == SvxEscapement::Subscript)); + + eState = pSet->GetItemState( EE_CHAR_KERNING ); + if ( eState == SfxItemState::DONTCARE ) + { + rSet.InvalidateItem(EE_CHAR_KERNING); + rSet.InvalidateItem(SID_ATTR_CHAR_KERNING); + } +} + +OUString DrawViewShell::GetSelectionText(bool bCompleteWords) +{ + OUString aStrSelection; + ::Outliner* pOl = mpDrawView->GetTextEditOutliner(); + OutlinerView* pOlView = mpDrawView->GetTextEditOutlinerView(); + + if (pOl && pOlView) + { + if (bCompleteWords) + { + ESelection aSel = pOlView->GetSelection(); + OUString aStrCurrentDelimiters = pOl->GetWordDelimiters(); + + pOl->SetWordDelimiters(" .,;\"'"); + aStrSelection = pOl->GetWord( aSel.nEndPara, aSel.nEndPos ); + pOl->SetWordDelimiters( aStrCurrentDelimiters ); + } + else + { + aStrSelection = pOlView->GetSelected(); + } + } + + return aStrSelection; +} + +bool DrawViewShell::HasSelection(bool bText) const +{ + bool bReturn = false; + + if (bText) + { + OutlinerView* pOlView = mpDrawView->GetTextEditOutlinerView(); + + if (pOlView && !pOlView->GetSelected().isEmpty()) + { + bReturn = true; + } + } + else if (mpDrawView->GetMarkedObjectList().GetMarkCount() != 0) + { + bReturn = true; + } + + return bReturn; +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsg.cxx b/sd/source/ui/view/drviewsg.cxx new file mode 100644 index 0000000000..2563168433 --- /dev/null +++ b/sd/source/ui/view/drviewsg.cxx @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> +#include <ViewShellImplementation.hxx> + +#include <svx/svxids.hrc> +#include <svx/imapdlg.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/svdograf.hxx> +#include <svx/ImageMapInfo.hxx> + +#include <app.hrc> + +#include <drawdoc.hxx> +#include <sdmod.hxx> +#include <optsitem.hxx> +#include <FrameView.hxx> +#include <drawview.hxx> + +namespace sd { + +void DrawViewShell::ExecIMap( SfxRequest const & rReq ) +{ + // during a slide show, nothing is executed! + if(HasCurrentFunction(SID_PRESENTATION) ) + return; + + if ( rReq.GetSlot() != SID_IMAP_EXEC ) + return; + + SdrMark* pMark = mpDrawView->GetMarkedObjectList().GetMark(0); + + if ( !pMark ) + return; + + SdrObject* pSdrObj = pMark->GetMarkedSdrObj(); + SvxIMapDlg* pDlg = ViewShell::Implementation::GetImageMapDialog(); + + if ( pDlg->GetEditingObject() == static_cast<void*>(pSdrObj) ) + { + const ImageMap& rImageMap = pDlg->GetImageMap(); + SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo( pSdrObj ); + + if ( !pIMapInfo ) + pSdrObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SvxIMapInfo( rImageMap )) ); + else + pIMapInfo->SetImageMap( rImageMap ); + + GetDoc()->SetChanged(); + } +} + +void DrawViewShell::GetIMapState( SfxItemSet& rSet ) +{ + bool bDisable = true; + + if( GetViewFrame()->HasChildWindow( SvxIMapDlgChildWindow::GetChildWindowId() ) ) + { + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + + if ( rMarkList.GetMarkCount() == 1 ) + { + const SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); + + SvxIMapDlg* pImageMapDialog = ViewShell::Implementation::GetImageMapDialog(); + if ( ( dynamic_cast< const SdrGrafObj *>( pObj ) != nullptr /*|| pObj->ISA( SdrOle2Obj )*/ ) + && pImageMapDialog!=nullptr + && ( pImageMapDialog->GetEditingObject() == static_cast<void const *>(pObj) ) ) + { + bDisable = false; + } + } + } + + rSet.Put( SfxBoolItem( SID_IMAP_EXEC, bDisable ) ); +} + +void DrawViewShell::ExecOptionsBar( SfxRequest& rReq ) +{ + // during a slide show, nothing is executed! + if(HasCurrentFunction(SID_PRESENTATION)) + return; + + bool bDefault = false; + sal_uInt16 nSlot = rReq.GetSlot(); + + SdOptions* pOptions = SD_MOD()->GetSdOptions(GetDoc()->GetDocumentType()); + + switch( nSlot ) + { + case SID_SOLID_CREATE: + pOptions->SetSolidDragging( !mpDrawView->IsSolidDragging() ); + break; + + // Grid- / Help lines option + case SID_GRID_VISIBLE: // not here yet! + { + pOptions->SetGridVisible( !mpDrawView->IsGridVisible() ); + } + break; + + case SID_GRID_USE: + { + pOptions->SetUseGridSnap( !mpDrawView->IsGridSnap() ); + } + break; + + case SID_HELPLINES_VISIBLE: // not here yet! + { + pOptions->SetHelplines( !mpDrawView->IsHlplVisible() ); + } + break; + + case SID_HELPLINES_USE: + { + pOptions->SetSnapHelplines( !mpDrawView->IsHlplSnap() ); + } + break; + + case SID_HELPLINES_MOVE: + { + pOptions->SetDragStripes( !mpDrawView->IsDragStripes() ); + } + break; + + case SID_SNAP_BORDER: + { + pOptions->SetSnapBorder( !mpDrawView->IsBordSnap() ); + } + break; + + case SID_SNAP_FRAME: + { + pOptions->SetSnapFrame( !mpDrawView->IsOFrmSnap() ); + } + break; + + case SID_SNAP_POINTS: + { + pOptions->SetSnapPoints( !mpDrawView->IsOPntSnap() ); + } + break; + + case SID_QUICKEDIT: + { + pOptions->SetQuickEdit( !mpDrawView->IsQuickTextEditMode() ); + } + break; + + case SID_PICK_THROUGH: + { + pOptions->SetPickThrough( + !mpDrawView->GetModel().IsPickThroughTransparentTextFrames() ); + } + break; + + case SID_DOUBLECLICK_TEXTEDIT: + { + pOptions->SetDoubleClickTextEdit( !mpFrameView->IsDoubleClickTextEdit() ); + } + break; + + case SID_CLICK_CHANGE_ROTATION: + { + pOptions->SetClickChangeRotation( !mpFrameView->IsClickChangeRotation() ); + } + break; + + default: + bDefault = true; + break; + } + + if( bDefault ) + return; + + pOptions->StoreConfig(); + + // Saves the configuration IMMEDIATELY + // SfxGetpApp()->SaveConfiguration(); + WriteFrameViewData(); + + mpFrameView->Update( pOptions ); + ReadFrameViewData( mpFrameView ); + + Invalidate( nSlot ); + rReq.Done(); + +} + +void DrawViewShell::GetOptionsBarState( SfxItemSet& rSet ) +{ + rSet.Put( SfxBoolItem( SID_SOLID_CREATE, mpDrawView->IsSolidDragging() ) ); + rSet.Put( SfxBoolItem( SID_GRID_VISIBLE, mpDrawView->IsGridVisible() ) ); + rSet.Put( SfxBoolItem( SID_GRID_USE, mpDrawView->IsGridSnap() ) ); + rSet.Put( SfxBoolItem( SID_HELPLINES_VISIBLE, mpDrawView->IsHlplVisible() ) ); + rSet.Put( SfxBoolItem( SID_HELPLINES_USE, mpDrawView->IsHlplSnap() ) ); + rSet.Put( SfxBoolItem( SID_HELPLINES_MOVE, mpDrawView->IsDragStripes() ) ); + + rSet.Put( SfxBoolItem( SID_SNAP_BORDER, mpDrawView->IsBordSnap() ) ); + rSet.Put( SfxBoolItem( SID_SNAP_FRAME, mpDrawView->IsOFrmSnap() ) ); + rSet.Put( SfxBoolItem( SID_SNAP_POINTS, mpDrawView->IsOPntSnap() ) ); + + rSet.Put( SfxBoolItem( SID_QUICKEDIT, mpDrawView->IsQuickTextEditMode() ) ); + rSet.Put( SfxBoolItem( SID_PICK_THROUGH, + mpDrawView->GetModel().IsPickThroughTransparentTextFrames() ) ); + + rSet.Put( SfxBoolItem( SID_DOUBLECLICK_TEXTEDIT, mpFrameView->IsDoubleClickTextEdit() ) ); + rSet.Put( SfxBoolItem( SID_CLICK_CHANGE_ROTATION, mpFrameView->IsClickChangeRotation() ) ); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsh.cxx b/sd/source/ui/view/drviewsh.cxx new file mode 100644 index 0000000000..f323497ac4 --- /dev/null +++ b/sd/source/ui/view/drviewsh.cxx @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> + +#include <sal/log.hxx> +#include <rtl/math.hxx> +#include <comphelper/lok.hxx> + +#include <DrawDocShell.hxx> + +#include <slideshow.hxx> + +namespace sd { + +void DrawViewShell::GotoBookmark(std::u16string_view rBookmark) +{ + ::sd::DrawDocShell* pDocSh = GetDocSh(); + if( pDocSh ) + { + if( !pDocSh->GetViewShell() ) //#i26016# this case occurs if the jump-target-document was opened already with file open dialog before triggering the jump via hyperlink + pDocSh->Connect(this); + pDocSh->GotoBookmark(rBookmark); + } +} + +/** + * Make area visible (scroll part of picture) +|* +\************************************************************************/ + +void DrawViewShell::MakeVisible(const ::tools::Rectangle& rRect, vcl::Window& rWin) +{ + if ( (IsMouseButtonDown() && !IsMouseSelecting()) || SlideShow::IsRunning( GetViewShellBase() ) ) + return; + + // tdf#98646 check if Rectangle which contains the bounds of the region to + // be shown eventually contains values that cause overflows when processing + // e.g. when calling GetWidth() + const bool bOverflowInX(!rtl::math::approxEqual(static_cast<double>(rRect.getOpenWidth()), static_cast<double>(rRect.Right()) - static_cast<double>(rRect.Left()))); + const bool bOverflowInY(!rtl::math::approxEqual(static_cast<double>(rRect.getOpenHeight()), static_cast<double>(rRect.Bottom()) - static_cast<double>(rRect.Top()))); + + if(bOverflowInX || bOverflowInY) + { + SAL_WARN("sd", "The given Rectangle contains values that lead to numerical overflows (!)"); + return; + } + + // In older versions, if in X or Y the size of the object was + // smaller than the visible area, the user-defined zoom was + // changed. This was decided to be a bug for + // StarOffice 6.x (Apr 2002), thus I developed a + // version which instead handles X/Y bigger/smaller and visibility + // questions separately + const Size aLogicSize(rRect.GetSize()); + + // visible area + Size aVisSizePixel(rWin.GetOutputSizePixel()); + bool bTiledRendering = comphelper::LibreOfficeKit::isActive() && !rWin.IsMapModeEnabled(); + if (bTiledRendering) + { + rWin.GetOutDev()->Push(vcl::PushFlags::MAPMODE); + rWin.EnableMapMode(); + } + ::tools::Rectangle aVisArea(rWin.PixelToLogic(::tools::Rectangle(Point(0,0), aVisSizePixel))); + if (bTiledRendering) + rWin.GetOutDev()->Pop(); + Size aVisAreaSize(aVisArea.GetSize()); + + if ( aVisArea.Contains(rRect) ) + return; + + // object is not entirely in visible area + sal_Int32 nFreeSpaceX(aVisAreaSize.Width() - aLogicSize.Width()); + sal_Int32 nFreeSpaceY(aVisAreaSize.Height() - aLogicSize.Height()); + + // allow a mode for move-only visibility without zooming. + const sal_Int32 nPercentBorder(30); + const ::tools::Rectangle aInnerRectangle( + aVisArea.Left() + ((aVisAreaSize.Width() * nPercentBorder) / 200), + aVisArea.Top() + ((aVisAreaSize.Height() * nPercentBorder) / 200), + aVisArea.Right() - ((aVisAreaSize.Width() * nPercentBorder) / 200), + aVisArea.Bottom() - ((aVisAreaSize.Height() * nPercentBorder) / 200) + ); + Point aNewPos(aVisArea.TopLeft()); + + if(nFreeSpaceX < 0) + { + if(aInnerRectangle.Left() > rRect.Right()) + { + // object moves out to the left + aNewPos.AdjustX( -(aVisAreaSize.Width() / 2) ); + } + + if(aInnerRectangle.Right() < rRect.Left()) + { + // object moves out to the right + aNewPos.AdjustX(aVisAreaSize.Width() / 2 ); + } + } + else + { + if(nFreeSpaceX > rRect.GetWidth()) + { + nFreeSpaceX = rRect.GetWidth(); + } + + if(nFreeSpaceX <= 0) + { + SAL_WARN("sd", "The given Rectangle contains values that lead to numerical overflows (!)"); + } + else + { + const ::tools::Long distRight(rRect.Right() - aNewPos.X() - aVisAreaSize.Width()); + + if(distRight > 0) + { + ::tools::Long mult = (distRight / nFreeSpaceX) + 1; + aNewPos.AdjustX(mult * nFreeSpaceX ); + } + + const ::tools::Long distLeft(aNewPos.X() - rRect.Left()); + + if(distLeft > 0) + { + ::tools::Long mult = (distLeft / nFreeSpaceX) + 1; + aNewPos.AdjustX( -(mult * nFreeSpaceX) ); + } + } + } + + if(nFreeSpaceY < 0) + { + if(aInnerRectangle.Top() > rRect.Bottom()) + { + // object moves out to the top + aNewPos.AdjustY( -(aVisAreaSize.Height() / 2) ); + } + + if(aInnerRectangle.Bottom() < rRect.Top()) + { + // object moves out to the right + aNewPos.AdjustY(aVisAreaSize.Height() / 2 ); + } + } + else + { + if(nFreeSpaceY > rRect.GetHeight()) + { + nFreeSpaceY = rRect.GetHeight(); + } + + if(nFreeSpaceY <= 0) + { + SAL_WARN("sd", "The given Rectangle contains values that lead to numerical overflows (!)"); + } + else + { + const ::tools::Long distBottom(rRect.Bottom() - aNewPos.Y() - aVisAreaSize.Height()); + + if(distBottom > 0) + { + ::tools::Long mult = (distBottom / nFreeSpaceY) + 1; + aNewPos.AdjustY(mult * nFreeSpaceY ); + } + + const ::tools::Long distTop(aNewPos.Y() - rRect.Top()); + + if(distTop > 0) + { + ::tools::Long mult = (distTop / nFreeSpaceY) + 1; + aNewPos.AdjustY( -(mult * nFreeSpaceY) ); + } + } + } + + // did position change? Does it need to be set? + if(aNewPos != aVisArea.TopLeft()) + { + aVisArea.SetPos(aNewPos); + SetZoomRect(aVisArea); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsi.cxx b/sd/source/ui/view/drviewsi.cxx new file mode 100644 index 0000000000..0398408249 --- /dev/null +++ b/sd/source/ui/view/drviewsi.cxx @@ -0,0 +1,165 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> +#include <svx/xfillit0.hxx> +#include <editeng/eeitem.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/svxids.hrc> +#include <sfx2/dispatch.hxx> +#include <svx/float3d.hxx> +#include <svx/f3dchild.hxx> +#include <vcl/weld.hxx> + +#include <strings.hrc> + +#include <drawdoc.hxx> +#include <Window.hxx> +#include <sdresid.hxx> + +using namespace ::com::sun::star; + +namespace sd { + +/** + * Handle SfxRequests for EffekteWindow + */ +void DrawViewShell::ExecEffectWin( SfxRequest& rReq ) +{ + CheckLineTo (rReq); + + sal_uInt16 nSId = rReq.GetSlot(); + + switch( nSId ) + { + case SID_3D_INIT: + { + sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId(); + SfxChildWindow* pWindow = GetViewFrame()->GetChildWindow( nId ); + if( pWindow ) + { + Svx3DWin* p3DWin = static_cast<Svx3DWin*>( pWindow->GetWindow() ); + if( p3DWin ) + p3DWin->InitColorLB(); + } + } + break; + + case SID_3D_STATE: + { + Update3DWindow(); + } + break; + + case SID_3D_ASSIGN: + { + AssignFrom3DWindow(); + } + break; + + } +} + +void DrawViewShell::Update3DWindow() +{ + sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId(); + SfxChildWindow* pWindow = GetViewFrame()->GetChildWindow( nId ); + if( pWindow ) + { + Svx3DWin* p3DWin = static_cast<Svx3DWin*>( pWindow->GetWindow() ); + if( p3DWin && p3DWin->IsUpdateMode() ) + { + SfxItemSet aTmpItemSet = GetView()->Get3DAttributes(); + p3DWin->Update( aTmpItemSet ); + } + } +} + +/*----------------------------------------------------------------------------*/ + +void DrawViewShell::AssignFrom3DWindow() +{ + sal_uInt16 nId = Svx3DChildWindow::GetChildWindowId(); + SfxChildWindow* pWin = GetViewFrame()->GetChildWindow( nId ); + if( !pWin ) + return; + + Svx3DWin* p3DWin = static_cast<Svx3DWin*>( pWin->GetWindow() ); + if( !(p3DWin && GetView()) ) + return; + + if(!GetView()->IsPresObjSelected()) + { + SfxItemSetFixed<SDRATTR_START, SDRATTR_END> aSet( GetDoc()->GetPool() ); + p3DWin->GetAttr( aSet ); + + // own UNDO-compounding also around transformation in 3D + GetView()->BegUndo(SdResId(STR_UNDO_APPLY_3D_FAVOURITE)); + + if(GetView()->IsConvertTo3DObjPossible()) + { + // assign only text-attribute + SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aTextSet( GetDoc()->GetPool() ); + aTextSet.Put( aSet, false ); + GetView()->SetAttributes( aTextSet ); + + // transform text into 3D + sal_uInt16 nSId = SID_CONVERT_TO_3D; + SfxBoolItem aItem( nSId, true ); + GetViewFrame()->GetDispatcher()->ExecuteList( + nSId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD, + { &aItem }); + + // Determine if a FILL attribute is set. + // If not, hard set a fill attribute + drawing::FillStyle eFillStyle = aSet.Get(XATTR_FILLSTYLE).GetValue(); + if(eFillStyle == drawing::FillStyle_NONE) + aSet.Put(XFillStyleItem (drawing::FillStyle_SOLID)); + + // remove some 3DSCENE attributes since these were + // created by convert to 3D and may not be changed + // to the defaults again. + aSet.ClearItem(SDRATTR_3DSCENE_DISTANCE); + aSet.ClearItem(SDRATTR_3DSCENE_FOCAL_LENGTH); + aSet.ClearItem(SDRATTR_3DOBJ_DEPTH); + } + + // assign attribute + GetView()->Set3DAttributes( aSet ); + + // end UNDO + GetView()->EndUndo(); + } + else + { + vcl::Window* pWindow = GetActiveWindow(); + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWindow ? pWindow->GetFrameWeld() : nullptr, + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); + } + + // get focus back + GetActiveWindow()->GrabFocus(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsj.cxx b/sd/source/ui/view/drviewsj.cxx new file mode 100644 index 0000000000..55103bf675 --- /dev/null +++ b/sd/source/ui/view/drviewsj.cxx @@ -0,0 +1,567 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <DrawViewShell.hxx> +#include <com/sun/star/embed/EmbedMisc.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <com/sun/star/presentation/ClickAction.hpp> +#include <sfx2/objsh.hxx> +#include <svx/svxids.hrc> +#include <svx/sdmetitm.hxx> +#include <editeng/flditem.hxx> +#include <svx/svdogrp.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdoole2.hxx> +#include <svx/sdtfsitm.hxx> +#include <svx/svdopath.hxx> +#include <svx/obj3d.hxx> +#include <svx/scene3d.hxx> + +#include <app.hrc> + +#include <anminfo.hxx> +#include <drawdoc.hxx> +#include <drawview.hxx> + +using namespace com::sun::star; + +namespace sd { + +/** + * Set state (Enabled/Disabled) of Menu-SfxSlots + */ +void DrawViewShell::GetMenuStateSel( SfxItemSet &rSet ) +{ + // Status of menu entries (Buttons,...) + + // Single selection + const SdrMarkList& rMarkList = mpDrawView->GetMarkedObjectList(); + const size_t nMarkCount = rMarkList.GetMarkCount(); + + if ( nMarkCount == 1 ) + { + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_BEZIER_EDIT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_UNGROUP ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_ENTER_GROUP ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_NAME_GROUP ) || + + // #i68101# + SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_TITLE_DESCRIPTION ) || + + SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_FILL_STYLE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_FILL_USE_SLIDE_BACKGROUND ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_FILL_TRANSPARENCE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_FILL_FLOATTRANSPARENCE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_CHANGEBEZIER ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_CHANGEPOLYGON ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_LINEEND_POLYGON ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_MEASURE_DLG ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_CONNECTION_DLG ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_CONNECTION_NEW_ROUTING ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_SHEAR ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_LEFT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_CENTER ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_RIGHT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_UP ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_MIDDLE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_OBJECT_ALIGN_DOWN ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_FRAME_TO_TOP ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_MOREFRONT ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_FRAME_UP ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_MOREBACK ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_FRAME_DOWN ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_FRAME_TO_BOTTOM ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_BEFORE_OBJ ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_BEHIND_OBJ ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_REVERSE_ORDER ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_ORIGINAL_SIZE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_SAVE_GRAPHIC ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_COMPRESS_GRAPHIC ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_TEXTATTR_DLG ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_EXECUTE_ANIMATION_EFFECT )) + { + const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); + const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pObj); + const SdrOle2Obj* pSdrOle2Obj = dynamic_cast< const SdrOle2Obj* >(pObj); + const SdAnimationInfo* pAnimationInfo + = SdDrawDocument::GetAnimationInfo(rMarkList.GetMark(0)->GetMarkedSdrObj()); + SdrInventor nInv = pObj->GetObjInventor(); + SdrObjKind nId = pObj->GetObjIdentifier(); + SdrObjTransformInfoRec aInfoRec; + pObj->TakeObjInfo( aInfoRec ); + + // don't show original size entry if not possible + if(pSdrOle2Obj) + { + if (pSdrOle2Obj->GetObjRef().is() && + (pSdrOle2Obj->GetObjRef()->getStatus( pSdrOle2Obj->GetAspect() ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE) ) + rSet.DisableItem(SID_ORIGINAL_SIZE); + } + + if(!pSdrGrafObj) + { + rSet.DisableItem(SID_SAVE_GRAPHIC); + rSet.DisableItem(SID_COMPRESS_GRAPHIC); + } + + if (!pAnimationInfo + || pAnimationInfo->meClickAction == presentation::ClickAction::ClickAction_NONE + // Sound does not work in edit mode + || pAnimationInfo->meClickAction == presentation::ClickAction::ClickAction_SOUND + // No point in exiting the presentation in edit mode + || pAnimationInfo->meClickAction + == presentation::ClickAction::ClickAction_STOPPRESENTATION) + { + rSet.DisableItem(SID_EXECUTE_ANIMATION_EFFECT); + } + + /* If it is not a group object or 3D object, we disable "enter + group". */ + const auto* pSdrObjGroup = dynamic_cast<const SdrObjGroup*>(pObj); + + if( !( ( pSdrObjGroup != nullptr && nInv == SdrInventor::Default ) || + DynCastE3dScene(pObj) ) ) + { + rSet.DisableItem( SID_ENTER_GROUP ); + } + + // Don't allow enter Diagrams + if(nullptr != pSdrObjGroup && pSdrObjGroup->isDiagram()) + { + rSet.DisableItem( SID_ENTER_GROUP ); + } + + // If it is not a group object, we disable "ungroup" + if(pSdrObjGroup == nullptr || nInv != SdrInventor::Default) + { + rSet.DisableItem(SID_UNGROUP); + } + + // Support advanced DiagramHelper + if(!pSdrObjGroup || !pSdrObjGroup->isDiagram()) + { + rSet.DisableItem( SID_REGENERATE_DIAGRAM ); + rSet.DisableItem( SID_EDIT_DIAGRAM ); + } + + if( nInv == SdrInventor::Default && + (nId == SdrObjKind::Line || + nId == SdrObjKind::PolyLine || + nId == SdrObjKind::PathLine || + nId == SdrObjKind::FreehandLine )) + { + //rSet.DisableItem( SID_ATTRIBUTES_AREA ); // remove again! + rSet.DisableItem( SID_ATTR_FILL_STYLE ); + rSet.DisableItem( SID_ATTR_FILL_USE_SLIDE_BACKGROUND ); + rSet.DisableItem( SID_ATTR_FILL_TRANSPARENCE ); + rSet.DisableItem( SID_ATTR_FILL_FLOATTRANSPARENCE ); + } + if( (dynamic_cast< const SdrPathObj *>( pObj ) == nullptr&& !aInfoRec.bCanConvToPath) || dynamic_cast< const SdrObjGroup *>( pObj ) != nullptr ) // As long as JOE handles it incorrectly! + { // JOE: a group object may can be converted into a PathObj + rSet.DisableItem( SID_LINEEND_POLYGON ); + } + if(nInv == SdrInventor::Default && + (nId == SdrObjKind::PathFill || nId == SdrObjKind::PathLine || !aInfoRec.bCanConvToPath)) + rSet.DisableItem( SID_CHANGEBEZIER ); + + if( nInv == SdrInventor::Default && + ( nId == SdrObjKind::Polygon || nId == SdrObjKind::PolyLine || !aInfoRec.bCanConvToPoly ) && + !GetView()->IsVectorizeAllowed() ) + { + rSet.DisableItem( SID_CHANGEPOLYGON ); + } + + if(nInv == SdrInventor::Default && nId == SdrObjKind::Table ) + { + rSet.DisableItem( SID_TEXTATTR_DLG ); + } + + if( nInv != SdrInventor::Default || nId != SdrObjKind::Measure ) + rSet.DisableItem( SID_MEASURE_DLG ); + + if( nInv != SdrInventor::Default || nId != SdrObjKind::Edge ) + rSet.DisableItem( SID_CONNECTION_DLG ); + else + { + bool bDisable = true; + SfxItemSet aAttrSet( GetDoc()->GetPool() ); + GetView()->GetAttributes( aAttrSet ); + + if( aAttrSet.GetItemState( SDRATTR_EDGELINE1DELTA ) >= SfxItemState::DEFAULT && + aAttrSet.GetItemState( SDRATTR_EDGELINE2DELTA ) >= SfxItemState::DEFAULT && + aAttrSet.GetItemState( SDRATTR_EDGELINE3DELTA ) >= SfxItemState::DEFAULT ) + { + ::tools::Long nVal1 = aAttrSet.Get( SDRATTR_EDGELINE1DELTA ).GetValue(); + ::tools::Long nVal2 = aAttrSet.Get( SDRATTR_EDGELINE2DELTA ).GetValue(); + ::tools::Long nVal3 = aAttrSet.Get( SDRATTR_EDGELINE3DELTA ).GetValue(); + { + if( nVal1 != 0 || nVal2 != 0 || nVal3 != 0 ) + bDisable = false; + } + } + if( bDisable ) + rSet.DisableItem( SID_CONNECTION_NEW_ROUTING ); + } + + if ( nInv == SdrInventor::E3d || + (!mpDrawView->IsConvertToPathObjPossible() && + !mpDrawView->IsShearAllowed() && + !mpDrawView->IsDistortAllowed()) ) + { + rSet.DisableItem( SID_OBJECT_SHEAR ); + } + + if(dynamic_cast< const E3dCompoundObject *>( pObj ) != nullptr) + { + rSet.DisableItem( SID_OBJECT_ALIGN ); + rSet.DisableItem( SID_OBJECT_ALIGN_LEFT ); + rSet.DisableItem( SID_OBJECT_ALIGN_CENTER ); + rSet.DisableItem( SID_OBJECT_ALIGN_RIGHT ); + rSet.DisableItem( SID_OBJECT_ALIGN_UP ); + rSet.DisableItem( SID_OBJECT_ALIGN_MIDDLE ); + rSet.DisableItem( SID_OBJECT_ALIGN_DOWN ); + rSet.DisableItem( SID_FRAME_TO_TOP ); + rSet.DisableItem( SID_MOREFRONT ); + rSet.DisableItem( SID_FRAME_UP ); + rSet.DisableItem( SID_MOREBACK ); + rSet.DisableItem( SID_FRAME_DOWN ); + rSet.DisableItem( SID_FRAME_TO_BOTTOM ); + rSet.DisableItem( SID_BEFORE_OBJ ); + rSet.DisableItem( SID_BEHIND_OBJ ); + rSet.DisableItem( SID_REVERSE_ORDER ); + rSet.DisableItem( SID_POSITION ); + } + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_DISMANTLE ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_BREAK ) ) + { + if ( !mpDrawView->IsDismantlePossible() ) + { + rSet.DisableItem( SID_DISMANTLE ); + } + + if ( !mpDrawView->IsDismantlePossible(true) && + !mpDrawView->IsImportMtfPossible() && + !mpDrawView->IsBreak3DObjPossible() ) + { + rSet.DisableItem( SID_BREAK ); + } + } + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_MODIFY_FIELD ) ) + { + OutlinerView* pOLV = mpDrawView->GetTextEditOutlinerView(); + + if( pOLV ) + { + const SvxFieldItem* pFldItem = pOLV->GetFieldAtSelection(); + + if( !( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) ) ) ) + { + rSet.DisableItem( SID_MODIFY_FIELD ); + } + } + else + rSet.DisableItem( SID_MODIFY_FIELD ); + } + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_OUTLINE_TEXT_AUTOFIT ) ) + { + const SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj(); + const SdrTextFitToSizeTypeItem* pItem = pObj->GetMergedItemSet().GetItem<SdrTextFitToSizeTypeItem>(SDRATTR_TEXT_FITTOSIZE); + const bool bSet = pItem && pItem->GetValue() != drawing::TextFitToSizeType_NONE; + rSet.Put(SfxBoolItem(SID_OUTLINE_TEXT_AUTOFIT, bSet)); + } + + rSet.DisableItem(SID_GROUP); + rSet.DisableItem(SID_TEXT_COMBINE); + rSet.DisableItem(SID_COMBINE); + rSet.DisableItem(SID_DISTRIBUTE_HLEFT); + rSet.DisableItem(SID_DISTRIBUTE_HCENTER); + rSet.DisableItem(SID_DISTRIBUTE_HDISTANCE); + rSet.DisableItem(SID_DISTRIBUTE_HRIGHT); + rSet.DisableItem(SID_DISTRIBUTE_VTOP); + rSet.DisableItem(SID_DISTRIBUTE_VCENTER); + rSet.DisableItem(SID_DISTRIBUTE_VDISTANCE); + rSet.DisableItem(SID_DISTRIBUTE_VBOTTOM); + rSet.DisableItem(SID_POLY_MERGE); + rSet.DisableItem(SID_POLY_SUBSTRACT); + rSet.DisableItem(SID_POLY_INTERSECT); + rSet.DisableItem(SID_EQUALIZEWIDTH); + rSet.DisableItem(SID_EQUALIZEHEIGHT); + rSet.DisableItem(SID_CONNECT); + } + // multi-selection + else if( nMarkCount > 1 ) + { + // distribute dialog for 3+n objects + if(nMarkCount <= 2) + { + rSet.DisableItem(SID_DISTRIBUTE_HLEFT); + rSet.DisableItem(SID_DISTRIBUTE_HCENTER); + rSet.DisableItem(SID_DISTRIBUTE_HDISTANCE); + rSet.DisableItem(SID_DISTRIBUTE_HRIGHT); + rSet.DisableItem(SID_DISTRIBUTE_VTOP); + rSet.DisableItem(SID_DISTRIBUTE_VCENTER); + rSet.DisableItem(SID_DISTRIBUTE_VDISTANCE); + rSet.DisableItem(SID_DISTRIBUTE_VBOTTOM); + } + + rSet.DisableItem( SID_LINEEND_POLYGON ); + rSet.DisableItem( SID_ENTER_GROUP ); + // Now names for objects have to be unique + rSet.DisableItem( SID_NAME_GROUP ); + // #i68101# + rSet.DisableItem( SID_OBJECT_TITLE_DESCRIPTION ); + rSet.DisableItem( SID_MODIFY_FIELD ); + + { + bool bText = false; + bool bLine = false; + bool bGroup = false; + bool bDrawObj = false; + bool b3dObj = false; + bool bTable = false; + bool bMeasureObj = false; + bool bEdgeObj = false; // Connector + bool bE3dCompoundObject = false; + + for( size_t i = 0; i < nMarkCount && !bText && i < 50; ++i ) + { + SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj(); + SdrInventor nInv = pObj->GetObjInventor(); + SdrObjKind nId = pObj->GetObjIdentifier(); + + if (nInv == SdrInventor::Default) + { + switch (nId) + { + case SdrObjKind::Text: bText = true; break; + + case SdrObjKind::Line: bLine = true; break; + + case SdrObjKind::Edge: bEdgeObj = true; break; + + case SdrObjKind::Measure: bMeasureObj = true; break; + + case SdrObjKind::Rectangle: + case SdrObjKind::CircleOrEllipse: + case SdrObjKind::FreehandLine: + case SdrObjKind::FreehandFill: + case SdrObjKind::PathFill: + case SdrObjKind::PathLine: + case SdrObjKind::CircleSection: + case SdrObjKind::CircleArc: + case SdrObjKind::CircleCut: bDrawObj = true; break; + + case SdrObjKind::Group: bGroup = true; break; + + case SdrObjKind::Graphic: break; + + case SdrObjKind::Table: bTable = true; break; + default: ; + } + } + else if (nInv == SdrInventor::E3d) + { + if(DynCastE3dScene(pObj)) + b3dObj = true; + else if(dynamic_cast< const E3dCompoundObject* >(pObj) != nullptr) + bE3dCompoundObject = true; + } + } + if( bLine && !bText && !bDrawObj &&!b3dObj) + { + rSet.DisableItem( SID_ATTR_FILL_STYLE ); + rSet.DisableItem( SID_ATTR_FILL_USE_SLIDE_BACKGROUND ); + rSet.DisableItem( SID_ATTR_FILL_TRANSPARENCE ); + rSet.DisableItem( SID_ATTR_FILL_FLOATTRANSPARENCE ); + } + if( !bEdgeObj ) + rSet.DisableItem( SID_CONNECTION_DLG ); + + if (b3dObj) + { + rSet.DisableItem( SID_COMBINE ); + rSet.DisableItem(SID_POLY_MERGE); + rSet.DisableItem(SID_POLY_SUBSTRACT); + rSet.DisableItem(SID_POLY_INTERSECT); + rSet.DisableItem(SID_EQUALIZEWIDTH); + rSet.DisableItem(SID_EQUALIZEHEIGHT); + } + + if (b3dObj || + (!mpDrawView->IsConvertToPathObjPossible() && + !mpDrawView->IsShearAllowed() && + !mpDrawView->IsDistortAllowed()) ) + { + rSet.DisableItem( SID_OBJECT_SHEAR ); + } + + if( !bGroup ) + { + rSet.DisableItem( SID_UNGROUP ); + } + if( bTable ) + rSet.DisableItem( SID_TEXTATTR_DLG ); + + if( !bMeasureObj ) + rSet.DisableItem( SID_MEASURE_DLG ); + + if(bE3dCompoundObject) + { + rSet.DisableItem( SID_OBJECT_ALIGN ); + rSet.DisableItem( SID_OBJECT_ALIGN_LEFT ); + rSet.DisableItem( SID_OBJECT_ALIGN_CENTER ); + rSet.DisableItem( SID_OBJECT_ALIGN_RIGHT ); + rSet.DisableItem( SID_OBJECT_ALIGN_UP ); + rSet.DisableItem( SID_OBJECT_ALIGN_MIDDLE ); + rSet.DisableItem( SID_OBJECT_ALIGN_DOWN ); + rSet.DisableItem( SID_FRAME_TO_TOP ); + rSet.DisableItem( SID_MOREFRONT ); + rSet.DisableItem( SID_FRAME_UP ); + rSet.DisableItem( SID_MOREBACK ); + rSet.DisableItem( SID_FRAME_DOWN ); + rSet.DisableItem( SID_FRAME_TO_BOTTOM ); + rSet.DisableItem( SID_BEFORE_OBJ ); + rSet.DisableItem( SID_BEHIND_OBJ ); + rSet.DisableItem( SID_REVERSE_ORDER ); + rSet.DisableItem( SID_POSITION ); + } + } + + if ( !mpDrawView->IsDismantlePossible() ) + { + rSet.DisableItem( SID_DISMANTLE ); + } + if ( !mpDrawView->IsDismantlePossible(true) && + !mpDrawView->IsImportMtfPossible() && + !mpDrawView->IsBreak3DObjPossible() ) + { + rSet.DisableItem( SID_BREAK ); + } + if ( !mpDrawView->IsCombinePossible() ) + { + rSet.DisableItem(SID_COMBINE); + rSet.DisableItem(SID_POLY_MERGE); + rSet.DisableItem(SID_POLY_SUBSTRACT); + rSet.DisableItem(SID_POLY_INTERSECT); + rSet.DisableItem(SID_EQUALIZEWIDTH); + rSet.DisableItem(SID_EQUALIZEHEIGHT); + } + if ( !mpDrawView->IsCombinePossible(true) ) + { + rSet.DisableItem( SID_CONNECT ); + } + if ( !mpDrawView->IsGroupPossible() ) + { + rSet.DisableItem( SID_GROUP ); + } + if ( !mpDrawView->IsUnGroupPossible() ) + { + rSet.DisableItem( SID_UNGROUP ); + } + } + // select no object + else + { + rSet.DisableItem( SID_ENTER_GROUP ); + rSet.DisableItem( SID_CUT ); + rSet.DisableItem( SID_COPY ); + rSet.DisableItem( SID_DELETE ); + rSet.DisableItem( SID_ATTR_TRANSFORM ); + + rSet.DisableItem( SID_OBJECT_ALIGN ); + rSet.DisableItem( SID_OBJECT_ALIGN_LEFT ); + rSet.DisableItem( SID_OBJECT_ALIGN_CENTER ); + rSet.DisableItem( SID_OBJECT_ALIGN_RIGHT ); + rSet.DisableItem( SID_OBJECT_ALIGN_UP ); + rSet.DisableItem( SID_OBJECT_ALIGN_MIDDLE ); + rSet.DisableItem( SID_OBJECT_ALIGN_DOWN ); + + rSet.DisableItem( SID_FRAME_TO_TOP ); + rSet.DisableItem( SID_MOREFRONT ); + rSet.DisableItem( SID_FRAME_UP ); + rSet.DisableItem( SID_MOREBACK ); + rSet.DisableItem( SID_FRAME_DOWN ); + rSet.DisableItem( SID_FRAME_TO_BOTTOM ); + rSet.DisableItem( SID_BEFORE_OBJ ); + rSet.DisableItem( SID_BEHIND_OBJ ); + rSet.DisableItem( SID_POSITION ); + + rSet.DisableItem( SID_SIZE_OPTIMAL ); + rSet.DisableItem( SID_LINEEND_POLYGON ); + rSet.DisableItem( SID_COPYOBJECTS ); + rSet.DisableItem( SID_HORIZONTAL ); + rSet.DisableItem( SID_VERTICAL ); + rSet.DisableItem( SID_FLIP_HORIZONTAL ); + rSet.DisableItem( SID_FLIP_VERTICAL ); + rSet.DisableItem( SID_GROUP ); + rSet.DisableItem( SID_UNGROUP ); + rSet.DisableItem( SID_NAME_GROUP ); + + // #i68101# + rSet.DisableItem( SID_OBJECT_TITLE_DESCRIPTION ); + + rSet.DisableItem( SID_DISMANTLE ); + rSet.DisableItem( SID_BREAK ); + rSet.DisableItem( SID_TEXT_COMBINE ); + rSet.DisableItem( SID_COMBINE ); + rSet.DisableItem(SID_DISTRIBUTE_DLG); + rSet.DisableItem(SID_DISTRIBUTE_HLEFT); + rSet.DisableItem(SID_DISTRIBUTE_HCENTER); + rSet.DisableItem(SID_DISTRIBUTE_HDISTANCE); + rSet.DisableItem(SID_DISTRIBUTE_HRIGHT); + rSet.DisableItem(SID_DISTRIBUTE_VTOP); + rSet.DisableItem(SID_DISTRIBUTE_VCENTER); + rSet.DisableItem(SID_DISTRIBUTE_VDISTANCE); + rSet.DisableItem(SID_DISTRIBUTE_VBOTTOM); + rSet.DisableItem(SID_POLY_MERGE); + rSet.DisableItem(SID_POLY_SUBSTRACT); + rSet.DisableItem(SID_POLY_INTERSECT); + rSet.DisableItem(SID_EQUALIZEWIDTH); + rSet.DisableItem(SID_EQUALIZEHEIGHT); + rSet.DisableItem( SID_CONNECT ); + rSet.DisableItem( SID_ANIMATION_EFFECTS ); + rSet.DisableItem( SID_EXECUTE_ANIMATION_EFFECT ); + rSet.DisableItem( SID_MODIFY_FIELD ); + rSet.DisableItem (SID_OBJECT_SHEAR); + } + + if (GetObjectShell()->isContentExtractionLocked()) + { + rSet.DisableItem(SID_COPY); + rSet.DisableItem(SID_CUT); + } + if(GetObjectShell()->isExportLocked()) + { + rSet.DisableItem(SID_SAVE_GRAPHIC); + rSet.DisableItem(SID_EXTERNAL_EDIT); + } + if (GetDoc()->getImagePreferredDPI() <= 0) + { + rSet.DisableItem(SID_GRAPHIC_SIZE_CHECK); + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/drviewsk.cxx b/sd/source/ui/view/drviewsk.cxx new file mode 100644 index 0000000000..92a00d5d2d --- /dev/null +++ b/sd/source/ui/view/drviewsk.cxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <DrawViewShell.hxx> +#include <ViewShellBase.hxx> +#include <sdmod.hxx> + +#include <comphelper/lok.hxx> +#include <comphelper/servicehelper.hxx> +#include <sfx2/lokhelper.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <unomodel.hxx> + +namespace sd { + +void DrawViewShell::ConfigurationChanged( utl::ConfigurationBroadcaster* pCb, ConfigurationHints ) +{ + svtools::ColorConfig *pColorConfig = dynamic_cast<svtools::ColorConfig*>(pCb); + ConfigureAppBackgroundColor(pColorConfig); + if (comphelper::LibreOfficeKit::isActive()) + { + SfxViewShell* pCurrentShell = SfxViewShell::Current(); + ViewShellBase* pShellBase = dynamic_cast<ViewShellBase*>(pCurrentShell); + if (!pShellBase) + return; + if (DrawViewShell* pCurrentDrawShell = dynamic_cast<DrawViewShell*>(pShellBase->GetMainViewShell().get())) + { + pCurrentDrawShell->maViewOptions.mnDocBackgroundColor = pColorConfig->GetColorValue(svtools::DOCCOLOR).nColor; + pCurrentDrawShell->maViewOptions.msColorSchemeName = svtools::ColorConfig::GetCurrentSchemeName(); + } + SdXImpressDocument* pDoc = comphelper::getFromUnoTunnel<SdXImpressDocument>(pCurrentShell->GetCurrentDocument()); + SfxLokHelper::notifyViewRenderState(pCurrentShell, pDoc); + Color aFillColor(pColorConfig->GetColorValue(svtools::APPBACKGROUND).nColor); + pCurrentShell->libreOfficeKitViewCallback(LOK_CALLBACK_APPLICATION_BACKGROUND_COLOR, + aFillColor.AsRGBHexString().toUtf8()); + } +} + +void DrawViewShell::ConfigureAppBackgroundColor( svtools::ColorConfig *pColorConfig ) +{ + if (!pColorConfig) + pColorConfig = &SD_MOD()->GetColorConfig(); + Color aFillColor( pColorConfig->GetColorValue( svtools::APPBACKGROUND ).nColor ); + if (comphelper::LibreOfficeKit::isActive()) + aFillColor = COL_TRANSPARENT; + // tdf#87905 Use darker background color for master view + if (meEditMode == EditMode::MasterPage) + aFillColor.DecreaseLuminance( 64 ); + maViewOptions.mnAppBackgroundColor = aFillColor; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sd/source/ui/view/drvwshrg.cxx b/sd/source/ui/view/drvwshrg.cxx new file mode 100644 index 0000000000..792d5b833a --- /dev/null +++ b/sd/source/ui/view/drvwshrg.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <DrawViewShell.hxx> +#include <sfx2/infobar.hxx> + +#include <svx/fontwork.hxx> +#include <svx/bmpmask.hxx> +#include <svx/imapdlg.hxx> +#include <svx/SvxColorChildWindow.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/sidebar/SidebarChildWindow.hxx> +#include <sfx2/devtools/DevelopmentToolChildWindow.hxx> +#include <svx/f3dchild.hxx> + +#include <svx/svxids.hrc> +#include <svx/hyperdlg.hxx> +#include <avmedia/mediaplayer.hxx> + +#include <app.hrc> + +#include <SpellDialogChildWindow.hxx> +#include <GraphicViewShell.hxx> +#include <AnimationChildWindow.hxx> + +using namespace sd; +#define ShellClass_DrawViewShell +#include <sdslots.hxx> +#define ShellClass_GraphicViewShell +#include <sdgslots.hxx> + +namespace sd +{ +/** + * Declare SFX-Slotmap and Standardinterface + */ + +SFX_IMPL_INTERFACE(DrawViewShell, SfxShell) + +void DrawViewShell::InitInterface_Impl() +{ + GetStaticInterface()->RegisterPopupMenu("drawtext"); + + GetStaticInterface()->RegisterChildWindow(SID_NAVIGATOR, true); + + GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxFontWorkChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxColorChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(AnimationChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(Svx3DChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxBmpMaskChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxIMapDlgChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxHlinkDlgWrapper::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(::sd::SpellDialogChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SID_SEARCH_DLG); +#if HAVE_FEATURE_AVMEDIA + GetStaticInterface()->RegisterChildWindow(::avmedia::MediaPlayer::GetChildWindowId()); +#endif + GetStaticInterface()->RegisterChildWindow( + sfx2::sidebar::SidebarChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId()); +} + +// SdGraphicViewShell +SFX_IMPL_INTERFACE(GraphicViewShell, SfxShell) + +void GraphicViewShell::InitInterface_Impl() +{ + GetStaticInterface()->RegisterPopupMenu("drawtext"); + + GetStaticInterface()->RegisterChildWindow(SID_NAVIGATOR, true); + + GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxFontWorkChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxColorChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(Svx3DChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxBmpMaskChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxIMapDlgChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxHlinkDlgWrapper::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(::sd::SpellDialogChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SID_SEARCH_DLG); +#if HAVE_FEATURE_AVMEDIA + GetStaticInterface()->RegisterChildWindow(::avmedia::MediaPlayer::GetChildWindowId()); +#endif + GetStaticInterface()->RegisterChildWindow( + sfx2::sidebar::SidebarChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId()); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/frmview.cxx b/sd/source/ui/view/frmview.cxx new file mode 100644 index 0000000000..61b7bfdf2e --- /dev/null +++ b/sd/source/ui/view/frmview.cxx @@ -0,0 +1,919 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <FrameView.hxx> + +#include <svx/svxids.hrc> +#include <com/sun/star/drawing/framework/ResourceId.hpp> +#include <com/sun/star/drawing/framework/XView.hpp> +#include <rtl/ustrbuf.hxx> +#include <unokywds.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <o3tl/string_view.hxx> +#include <osl/diagnose.h> + +#include <vector> +#include <ViewShell.hxx> +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <optsitem.hxx> +#include <ViewShellBase.hxx> +#include <sdmod.hxx> +#include <pres.hxx> +#include <framework/FrameworkHelper.hxx> +#include <comphelper/processfactory.hxx> +#include <sfx2/viewfrm.hxx> +#include <officecfg/Office/Common.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +namespace sd { + +FrameView::FrameView(SdDrawDocument* pDrawDoc, FrameView* pFrameView /* = NULL */) +: SdrView(*pDrawDoc, nullptr), // TTTT SdDrawDocument* -> should be reference + mnRefCount(0), + mnPresViewShellId(SID_VIEWSHELL0), + mbIsNavigatorShowingAllShapes(false) +{ + EndListening(*pDrawDoc); + + EnableExtendedKeyInputDispatcher(false); + EnableExtendedMouseEventDispatcher(false); + + SetGridFront( false ); + SetHlplFront( false ); + SetOConSnap( false ); + SetFrameDragSingles(); + SetSlidesPerRow(4); + + if( nullptr == pFrameView ) + { + DrawDocShell* pDocShell = pDrawDoc->GetDocSh(); + + if ( pDocShell ) + { + // document is loaded, is there a FrameView? + sal_uLong nSdViewShellCount = 0; + SfxViewFrame* pSfxViewFrame = SfxViewFrame::GetFirst(pDocShell); + + while (pSfxViewFrame) + { + // Count the FrameViews and remember the type of the main + // view shell. + SfxViewShell* pSfxViewSh = pSfxViewFrame->GetViewShell(); + ViewShellBase* pBase = dynamic_cast<ViewShellBase*>( pSfxViewSh ); + + if (pBase != nullptr) + { + nSdViewShellCount++; + + OUString sViewURL; + Reference<drawing::framework::XView> xView ( + framework::FrameworkHelper::Instance(*pBase)->GetView( + drawing::framework::ResourceId::create( + ::comphelper::getProcessComponentContext(), + framework::FrameworkHelper::msCenterPaneURL))); + if (xView.is()) + sViewURL = xView->getResourceId()->getResourceURL(); + + switch (framework::FrameworkHelper::GetViewId(sViewURL)) + { + default: +// case ViewShell::ST_IMPRESS: +// case ViewShell::ST_NOTES: +// case ViewShell::ST_HANDOUT: + mnPresViewShellId = SID_VIEWSHELL0; + break; + + case ViewShell::ST_SLIDE_SORTER: + mnPresViewShellId = SID_VIEWSHELL1; + break; + + case ViewShell::ST_OUTLINE: + mnPresViewShellId = SID_VIEWSHELL2; + break; + } + } + + pSfxViewFrame = SfxViewFrame::GetNext(*pSfxViewFrame, pDocShell); + } + + SdDrawDocument* pDoc = pDocShell->GetDoc(); + pFrameView = pDoc->GetFrameView(nSdViewShellCount); + } + } + + if (pFrameView) + { + // initialize FrameView with the FrameView of the DocShell + SetRuler( pFrameView->HasRuler() ); + SetGridCoarse( pFrameView->GetGridCoarse() ); + SetGridFine( pFrameView->GetGridFine() ); + SetSnapGridWidth(pFrameView->GetSnapGridWidthX(), pFrameView->GetSnapGridWidthY()); + SetGridVisible( pFrameView->IsGridVisible() ); + SetGridFront( pFrameView->IsGridFront() ); + SetSnapAngle( pFrameView->GetSnapAngle() ); + SetGridSnap( pFrameView->IsGridSnap() ); + SetBordSnap( pFrameView->IsBordSnap() ); + SetHlplSnap( pFrameView->IsHlplSnap() ); + SetOFrmSnap( pFrameView->IsOFrmSnap() ); + SetOPntSnap( pFrameView->IsOPntSnap() ); + SetOConSnap( pFrameView->IsOConSnap() ); + SetHlplVisible( pFrameView->IsHlplVisible() ); + SetDragStripes( pFrameView->IsDragStripes() ); + SetPlusHandlesAlwaysVisible( pFrameView->IsPlusHandlesAlwaysVisible() ); + SetFrameDragSingles( pFrameView->IsFrameDragSingles() ); + SetSnapMagneticPixel( pFrameView->GetSnapMagneticPixel() ); + SetMarkedHitMovesAlways( pFrameView->IsMarkedHitMovesAlways() ); + SetMoveOnlyDragging( pFrameView->IsMoveOnlyDragging() ); + SetCrookNoContortion( pFrameView->IsCrookNoContortion() ); + SetSlantButShear( pFrameView->IsSlantButShear() ); + SetNoDragXorPolys( pFrameView->IsNoDragXorPolys() ); + SetAngleSnapEnabled( pFrameView->IsAngleSnapEnabled() ); + SetBigOrtho( pFrameView->IsBigOrtho() ); + SetOrtho( pFrameView->IsOrtho() ); + SetEliminatePolyPointLimitAngle( pFrameView->GetEliminatePolyPointLimitAngle() ); + SetEliminatePolyPoints( pFrameView->IsEliminatePolyPoints() ); + SetDesignMode( pFrameView->IsDesignMode() ); + + SetSolidDragging( pFrameView->IsSolidDragging() ); + + maVisibleLayers = pFrameView->GetVisibleLayers(); + maPrintableLayers = pFrameView->GetPrintableLayers(); + maLockedLayers = pFrameView->GetLockedLayers(); + maStandardHelpLines = pFrameView->GetStandardHelpLines(); + maNotesHelpLines = pFrameView->GetNotesHelpLines(); + maHandoutHelpLines = pFrameView->GetHandoutHelpLines(); + SetActiveLayer( pFrameView->GetActiveLayer() ); + mbNoColors = pFrameView->IsNoColors(); + mbNoAttribs = pFrameView->IsNoAttribs() ; + maVisArea = pFrameView->GetVisArea(); + mePageKind = pFrameView->GetPageKind(); + mePageKindOnLoad = pFrameView->GetPageKindOnLoad(); + mnSelectedPage = pFrameView->GetSelectedPage(); + mnSelectedPageOnLoad = pFrameView->GetSelectedPageOnLoad(); + mePageEditMode = pFrameView->GetViewShEditMode(); + // meStandardEditMode = pFrameView->GetViewShEditMode(PageKind::Standard); + // meNotesEditMode = pFrameView->GetViewShEditMode(PageKind::Notes); + // meHandoutEditMode = pFrameView->GetViewShEditMode(PageKind::Handout); + SetViewShEditModeOnLoad(pFrameView->GetViewShEditModeOnLoad()); + mbLayerMode = pFrameView->IsLayerMode(); + mbQuickEdit = pFrameView->IsQuickEdit(); + + // #i26631# + SetMasterPagePaintCaching( pFrameView->IsMasterPagePaintCaching() ); + + SetDragWithCopy( pFrameView->IsDragWithCopy() ); + mbDoubleClickTextEdit = pFrameView->IsDoubleClickTextEdit(); + mbClickChangeRotation = pFrameView->IsClickChangeRotation(); + mnSlidesPerRow = pFrameView->GetSlidesPerRow(); + mnDrawMode = pFrameView->GetDrawMode(); + mbIsNavigatorShowingAllShapes = pFrameView->IsNavigatorShowingAllShapes(); + SetPreviousViewShellType (pFrameView->GetPreviousViewShellType()); + SetViewShellTypeOnLoad (pFrameView->GetViewShellTypeOnLoad()); + } + else + { + // initialize FrameView with the application data + + // Layers need to be set, otherwise they are not visible and not printable in + // Impress documents. The document contains already the actual layers and their + // settings for visible, printable and locked. In case not read from <draw:layer-set>, + // ODF defaults are used. + SdrLayerAdmin rLayerAdmin = pDrawDoc -> GetLayerAdmin(); + rLayerAdmin.getVisibleLayersODF(maVisibleLayers); + rLayerAdmin.getPrintableLayersODF(maPrintableLayers); + rLayerAdmin.getLockedLayersODF(maLockedLayers); + SetGridCoarse( Size( 1000, 1000 ) ); + SetSnapGridWidth(Fraction(1000, 1), Fraction(1000, 1)); + SetActiveLayer(sUNO_LayerName_layout); + mbNoColors = true; + mbNoAttribs = false; + maVisArea = ::tools::Rectangle( Point(), Size(0, 0) ); + mePageKind = PageKind::Standard; + mePageKindOnLoad = PageKind::Standard; + mnSelectedPage = 0; + mnSelectedPageOnLoad = 0; + mePageEditMode = EditMode::Page; + // meStandardEditMode = EditMode::Page; + // meNotesEditMode = EditMode::Page; + // meHandoutEditMode = EditMode::MasterPage; + SetViewShEditModeOnLoad(EditMode::Page); + mbLayerMode = false; + SetEliminatePolyPoints(false); + mbDoubleClickTextEdit = false; + mbClickChangeRotation = false; + mnSlidesPerRow = 4; + + { + bool bUseContrast = Application::GetSettings().GetStyleSettings().GetHighContrastMode(); + mnDrawMode = bUseContrast ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR; + } + mbIsNavigatorShowingAllShapes = true; + SetPreviousViewShellType (ViewShell::ST_NONE); + SetViewShellTypeOnLoad (ViewShell::ST_IMPRESS); + + // get default for design mode + bool bInitDesignMode = pDrawDoc->GetOpenInDesignMode(); + if( pDrawDoc->OpenInDesignModeIsDefaulted() ) + { + bInitDesignMode = true; + } + + SfxObjectShell* pObjShell = pDrawDoc->GetObjectShell(); + if( pObjShell && pObjShell->IsReadOnly() ) + bInitDesignMode = false; + SetDesignMode( bInitDesignMode ); + + Update( SD_MOD()->GetSdOptions(pDrawDoc->GetDocumentType()) ); + } + +} + +FrameView::~FrameView() +{ +} + +void FrameView::Connect() +{ + mnRefCount++; +} + +void FrameView::Disconnect() +{ + if (mnRefCount > 0) + { + mnRefCount--; + } + + if (mnRefCount == 0) + { + delete this; + } +} + +/** + * Update with data from the specified SdOptions + */ +void FrameView::Update(SdOptions const * pOptions) +{ + if (!pOptions) + return; + + mbRuler = pOptions->IsRulerVisible(); + SetGridVisible( pOptions->IsGridVisible() ); + SetSnapAngle( pOptions->GetAngle() ); + SetGridSnap( pOptions->IsUseGridSnap() ); + SetBordSnap( pOptions->IsSnapBorder() ); + SetHlplSnap( pOptions->IsSnapHelplines() ); + SetOFrmSnap( pOptions->IsSnapFrame() ); + SetOPntSnap( pOptions->IsSnapPoints() ); + SetHlplVisible( pOptions->IsHelplines() ); + SetDragStripes( pOptions->IsDragStripes() ); + SetPlusHandlesAlwaysVisible( pOptions->IsHandlesBezier() ); + SetSnapMagneticPixel( pOptions->GetSnapArea() ); + SetMarkedHitMovesAlways( pOptions->IsMarkedHitMovesAlways() ); + SetMoveOnlyDragging( pOptions->IsMoveOnlyDragging() ); + SetSlantButShear( pOptions->IsMoveOnlyDragging() ); + SetNoDragXorPolys ( !pOptions->IsMoveOutline() ); + SetCrookNoContortion( pOptions->IsCrookNoContortion() ); + SetAngleSnapEnabled( pOptions->IsRotate() ); + SetBigOrtho( pOptions->IsBigOrtho() ); + SetOrtho( pOptions->IsOrtho() ); + SetEliminatePolyPointLimitAngle( pOptions->GetEliminatePolyPointLimitAngle() ); + GetModel().SetPickThroughTransparentTextFrames( pOptions->IsPickThrough() ); + + SetSolidDragging( pOptions->IsSolidDragging() ); + + SetGridCoarse( Size( pOptions->GetFieldDrawX(), pOptions->GetFieldDrawY() ) ); + SetGridFine( Size( pOptions->GetFieldDivisionX(), pOptions->GetFieldDivisionY() ) ); + Fraction aFractX(pOptions->GetFieldDrawX(), pOptions->GetFieldDrawX() / ( pOptions->GetFieldDivisionX() ? pOptions->GetFieldDivisionX() : 1 )); + Fraction aFractY(pOptions->GetFieldDrawY(), pOptions->GetFieldDrawY() / ( pOptions->GetFieldDivisionY() ? pOptions->GetFieldDivisionY() : 1 )); + SetSnapGridWidth(aFractX, aFractY); + SetQuickEdit(pOptions->IsQuickEdit()); + + // #i26631# + SetMasterPagePaintCaching( pOptions->IsMasterPagePaintCaching() ); + + SetDragWithCopy(pOptions->IsDragWithCopy()); + SetDragThresholdPixels(pOptions->GetDragThresholdPixels()); + SetDoubleClickTextEdit( pOptions->IsDoubleClickTextEdit() ); + SetClickChangeRotation( pOptions->IsClickChangeRotation() ); +} + +/** + * Set EditMode (Page or MasterPage) of working mode + */ +void FrameView::SetViewShEditMode(EditMode eMode) +{ + mePageEditMode = eMode; +} + +/** + * Return EditMode (Page or MasterPage) of working mode + */ +EditMode FrameView::GetViewShEditMode() const +{ + return mePageEditMode; +} + +void FrameView::SetViewShEditModeOnLoad (EditMode eMode) +{ + meEditModeOnLoad = eMode; +} + +static OUString createHelpLinesString( const SdrHelpLineList& rHelpLines ) +{ + OUStringBuffer aLines; + + const sal_uInt16 nCount = rHelpLines.GetCount(); + for( sal_uInt16 nHlpLine = 0; nHlpLine < nCount; nHlpLine++ ) + { + const SdrHelpLine& rHelpLine = rHelpLines[nHlpLine]; + const Point& rPos = rHelpLine.GetPos(); + + switch( rHelpLine.GetKind() ) + { + case SdrHelpLineKind::Point: + aLines.append( 'P' ); + aLines.append( static_cast<sal_Int32>(rPos.X()) ); + aLines.append( ',' ); + aLines.append( static_cast<sal_Int32>(rPos.Y()) ); + break; + case SdrHelpLineKind::Vertical: + aLines.append( 'V' ); + aLines.append( static_cast<sal_Int32>(rPos.X()) ); + break; + case SdrHelpLineKind::Horizontal: + aLines.append( 'H' ); + aLines.append( static_cast<sal_Int32>(rPos.Y()) ); + break; + default: + OSL_FAIL( "Unsupported helpline Kind!" ); + } + } + + return aLines.makeStringAndClear(); +} + +void FrameView::WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& rValues ) +{ + std::vector< std::pair< OUString, Any > > aUserData; + aUserData.reserve(41); // worst case + + aUserData.emplace_back( sUNO_View_GridIsVisible, Any( IsGridVisible() ) ); + aUserData.emplace_back( sUNO_View_GridIsFront, Any( IsGridFront() ) ); + aUserData.emplace_back( sUNO_View_IsSnapToGrid, Any( IsGridSnap() ) ); + aUserData.emplace_back( sUNO_View_IsSnapToPageMargins, Any( IsBordSnap() ) ); + aUserData.emplace_back( sUNO_View_IsSnapToSnapLines, Any( IsHlplSnap() ) ); + aUserData.emplace_back( sUNO_View_IsSnapToObjectFrame, Any( IsOFrmSnap() ) ); + aUserData.emplace_back( sUNO_View_IsSnapToObjectPoints, Any( IsOPntSnap() ) ); + + aUserData.emplace_back( sUNO_View_IsPlusHandlesAlwaysVisible, Any( IsPlusHandlesAlwaysVisible() ) ); + aUserData.emplace_back( sUNO_View_IsFrameDragSingles, Any( IsFrameDragSingles() ) ); + + aUserData.emplace_back( sUNO_View_EliminatePolyPointLimitAngle, Any( static_cast<sal_Int32>(GetEliminatePolyPointLimitAngle()) ) ); + aUserData.emplace_back( sUNO_View_IsEliminatePolyPoints, Any( IsEliminatePolyPoints() ) ); + + if ( officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::get() ) + { + SdrLayerAdmin& rLayerAdmin = getSdrModelFromSdrView().GetLayerAdmin(); + Any aAny; + rLayerAdmin.QueryValue(GetVisibleLayers(), aAny); + aUserData.emplace_back( sUNO_View_VisibleLayers, aAny ); + + rLayerAdmin.QueryValue(GetPrintableLayers(), aAny); + aUserData.emplace_back( sUNO_View_PrintableLayers, aAny ); + + rLayerAdmin.QueryValue(GetLockedLayers(), aAny); + aUserData.emplace_back( sUNO_View_LockedLayers, aAny ); + } + + aUserData.emplace_back( sUNO_View_NoAttribs, Any( IsNoAttribs() ) ); + aUserData.emplace_back( sUNO_View_NoColors, Any( IsNoColors() ) ); + + if( GetStandardHelpLines().GetCount() ) + aUserData.emplace_back( sUNO_View_SnapLinesDrawing, Any( createHelpLinesString( GetStandardHelpLines() ) ) ); + + if( GetNotesHelpLines().GetCount() ) + aUserData.emplace_back( sUNO_View_SnapLinesNotes, Any( createHelpLinesString( GetNotesHelpLines() ) ) ); + + if( GetHandoutHelpLines().GetCount() ) + aUserData.emplace_back( sUNO_View_SnapLinesHandout, Any( createHelpLinesString( GetHandoutHelpLines() ) ) ); + + aUserData.emplace_back( sUNO_View_RulerIsVisible, Any( HasRuler() ) ); + aUserData.emplace_back( sUNO_View_PageKind, Any( static_cast<sal_Int16>(GetPageKind()) ) ); + aUserData.emplace_back( sUNO_View_SelectedPage, Any( static_cast<sal_Int16>(GetSelectedPage()) ) ); + aUserData.emplace_back( sUNO_View_IsLayerMode, Any( IsLayerMode() ) ); + + aUserData.emplace_back( sUNO_View_IsDoubleClickTextEdit, Any( IsDoubleClickTextEdit() ) ); + aUserData.emplace_back( sUNO_View_IsClickChangeRotation, Any( IsClickChangeRotation() ) ); + + aUserData.emplace_back( sUNO_View_SlidesPerRow, Any( static_cast<sal_Int16>(GetSlidesPerRow()) ) ); + aUserData.emplace_back( sUNO_View_EditMode, Any( static_cast<sal_Int32>(GetViewShEditMode()) ) ); + // aUserData.emplace_back( sUNO_View_EditModeStandard, makeAny( (sal_Int32)GetViewShEditMode( PageKind::Standard ) ) ); + // aUserData.emplace_back( sUNO_View_EditModeNotes, makeAny( (sal_Int32)GetViewShEditMode( PageKind::Notes ) ) ); + // aUserData.emplace_back( sUNO_View_EditModeHandout, makeAny( (sal_Int32)GetViewShEditMode( PageKind::Handout ) ) ); + + { + const ::tools::Rectangle aVisArea = GetVisArea(); + + aUserData.emplace_back( sUNO_View_VisibleAreaTop, Any( static_cast<sal_Int32>(aVisArea.Top()) ) ); + aUserData.emplace_back( sUNO_View_VisibleAreaLeft, Any( static_cast<sal_Int32>(aVisArea.Left()) ) ); + aUserData.emplace_back( sUNO_View_VisibleAreaWidth, Any( static_cast<sal_Int32>(aVisArea.GetWidth()) ) ); + aUserData.emplace_back( sUNO_View_VisibleAreaHeight, Any( static_cast<sal_Int32>(aVisArea.GetHeight()) ) ); + } + + aUserData.emplace_back( sUNO_View_GridCoarseWidth, Any( static_cast<sal_Int32>(GetGridCoarse().Width()) ) ); + aUserData.emplace_back( sUNO_View_GridCoarseHeight, Any( static_cast<sal_Int32>(GetGridCoarse().Height()) ) ); + aUserData.emplace_back( sUNO_View_GridFineWidth, Any( static_cast<sal_Int32>(GetGridFine().Width()) ) ); + aUserData.emplace_back( sUNO_View_GridFineHeight, Any( static_cast<sal_Int32>(GetGridFine().Height()) ) ); + aUserData.emplace_back( sUNO_View_GridSnapWidthXNumerator, Any( GetSnapGridWidthX().GetNumerator() ) ); + aUserData.emplace_back( sUNO_View_GridSnapWidthXDenominator, Any( GetSnapGridWidthX().GetDenominator() ) ); + aUserData.emplace_back( sUNO_View_GridSnapWidthYNumerator, Any( GetSnapGridWidthY().GetNumerator() ) ); + aUserData.emplace_back( sUNO_View_GridSnapWidthYDenominator, Any( GetSnapGridWidthY().GetDenominator() ) ); + aUserData.emplace_back( sUNO_View_IsAngleSnapEnabled, Any( IsAngleSnapEnabled() ) ); + aUserData.emplace_back( sUNO_View_SnapAngle, Any( static_cast<sal_Int32>(GetSnapAngle()) ) ); + + const sal_Int32 nOldLength = rValues.getLength(); + rValues.realloc( nOldLength + aUserData.size() ); + + PropertyValue* pValue = &(rValues.getArray()[nOldLength]); + + for( const auto& rItem : aUserData ) + { + pValue->Name = rItem.first; + pValue->Value = rItem.second; + ++pValue; + } +} + +static void createHelpLinesFromString( const OUString& rLines, SdrHelpLineList& rHelpLines ) +{ + const sal_Unicode * pStr = rLines.getStr(); + SdrHelpLine aNewHelpLine; + OUStringBuffer sBuffer; + + while( *pStr ) + { + Point aPoint; + + switch( *pStr ) + { + case 'P': + aNewHelpLine.SetKind( SdrHelpLineKind::Point ); + break; + case 'V': + aNewHelpLine.SetKind( SdrHelpLineKind::Vertical ); + break; + case 'H': + aNewHelpLine.SetKind( SdrHelpLineKind::Horizontal ); + break; + default: + OSL_FAIL( "syntax error in snap lines settings string" ); + return; + } + + pStr++; + + while( (*pStr >= '0' && *pStr <= '9') || (*pStr == '+') || (*pStr == '-') ) + { + sBuffer.append( *pStr++ ); + } + + sal_Int32 nValue = o3tl::toInt32(sBuffer); + sBuffer.setLength(0); + + if( aNewHelpLine.GetKind() == SdrHelpLineKind::Horizontal ) + { + aPoint.setY( nValue ); + } + else + { + aPoint.setX( nValue ); + + if( aNewHelpLine.GetKind() == SdrHelpLineKind::Point ) + { + if( *pStr++ != ',' ) + return; + + while( (*pStr >= '0' && *pStr <= '9') || (*pStr == '+') || (*pStr == '-') ) + { + sBuffer.append( *pStr++ ); + } + + aPoint.setY( o3tl::toInt32(sBuffer) ); + sBuffer.setLength(0); + + } + } + + aNewHelpLine.SetPos( aPoint ); + rHelpLines.Insert( aNewHelpLine ); + } +} + +void FrameView::ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& rSequence ) +{ + const sal_Int32 nLength = rSequence.getLength(); + if (!nLength) + return; + + SdDrawDocument* pDrawDocument = dynamic_cast<SdDrawDocument*>(&GetModel()); + const bool bImpress = pDrawDocument && pDrawDocument->GetDocumentType() == DocumentType::Impress; + + bool bBool = false; + sal_Int32 nInt32 = 0; + sal_Int16 nInt16 = 0; + OUString aString; + + sal_Int32 aSnapGridWidthXNum = GetSnapGridWidthX().GetNumerator(); + sal_Int32 aSnapGridWidthXDom = GetSnapGridWidthX().GetDenominator(); + + sal_Int32 aSnapGridWidthYNum = GetSnapGridWidthY().GetNumerator(); + sal_Int32 aSnapGridWidthYDom = GetSnapGridWidthY().GetDenominator(); + + for (const css::beans::PropertyValue& rValue : rSequence) + { + if ( rValue.Name == sUNO_View_ViewId ) + { + } + else if ( rValue.Name == sUNO_View_SnapLinesDrawing ) + { + if( rValue.Value >>= aString ) + { + SdrHelpLineList aHelpLines; + createHelpLinesFromString( aString, aHelpLines ); + SetStandardHelpLines( aHelpLines ); + } + } + else if ( rValue.Name == sUNO_View_SnapLinesNotes ) + { + if( rValue.Value >>= aString ) + { + SdrHelpLineList aHelpLines; + createHelpLinesFromString( aString, aHelpLines ); + SetNotesHelpLines( aHelpLines ); + } + } + else if ( rValue.Name == sUNO_View_SnapLinesHandout ) + { + if( rValue.Value >>= aString ) + { + SdrHelpLineList aHelpLines; + createHelpLinesFromString( aString, aHelpLines ); + SetHandoutHelpLines( aHelpLines ); + } + } + else if ( rValue.Name == sUNO_View_RulerIsVisible ) + { + if( rValue.Value >>= bBool ) + { + SetRuler( bBool ); + } + } + else if ( rValue.Name == sUNO_View_PageKind ) + { + if( rValue.Value >>= nInt16 ) + { + SdDrawDocument* pDoc = dynamic_cast<SdDrawDocument*>(&GetModel()); + if( pDoc && pDoc->GetDocSh() && ( SfxObjectCreateMode::EMBEDDED == pDoc->GetDocSh()->GetCreateMode() ) ) + SetPageKind( static_cast<PageKind>(nInt16) ); + + SetPageKindOnLoad( static_cast<PageKind>(nInt16) ); + } + } + else if ( rValue.Name == sUNO_View_SelectedPage ) + { + if( rValue.Value >>= nInt16 ) + { + SdDrawDocument* pDoc = dynamic_cast<SdDrawDocument*>(&GetModel()); + if( pDoc && pDoc->GetDocSh() && ( SfxObjectCreateMode::EMBEDDED == pDoc->GetDocSh()->GetCreateMode() ) ) + SetSelectedPage( static_cast<sal_uInt16>(nInt16) ); + + SetSelectedPageOnLoad( static_cast<sal_uInt16>(nInt16) ); + } + } + else if ( rValue.Name == sUNO_View_IsLayerMode ) + { + if( rValue.Value >>= bBool ) + { + SetLayerMode( bBool ); + } + } + else if ( rValue.Name == sUNO_View_IsDoubleClickTextEdit ) + { + if( rValue.Value >>= bBool ) + { + SetDoubleClickTextEdit( bBool ); + } + } + else if ( rValue.Name == sUNO_View_IsClickChangeRotation ) + { + if( rValue.Value >>= bBool ) + { + SetClickChangeRotation( bBool ); + } + } + else if ( rValue.Name == sUNO_View_SlidesPerRow ) + { + if( rValue.Value >>= nInt16 ) + { + SetSlidesPerRow( static_cast<sal_uInt16>(nInt16) ); + } + } + else if ( rValue.Name == sUNO_View_EditMode ) + { + if( rValue.Value >>= nInt32 ) + { + SdDrawDocument* pDoc = dynamic_cast<SdDrawDocument*>(&GetModel()); + if( pDoc && pDoc->GetDocSh() && ( SfxObjectCreateMode::EMBEDDED == pDoc->GetDocSh()->GetCreateMode() ) ) + SetViewShEditMode( static_cast<EditMode>(nInt32) ); + } + } + // This one is kept for compatibility. Old value read from sUNO_View_EditModeStandard + // is used. New value will be written into sUNO_View_EditMode. + // Values from sUNO_View_EditModeNotes and sUNO_View_EditModeHangout will be ignored. + else if ( rValue.Name == sUNO_View_EditModeStandard ) + { + if( rValue.Value >>= nInt32 ) + { + SdDrawDocument* pDoc = dynamic_cast<SdDrawDocument*>(&GetModel()); + if( pDoc && pDoc->GetDocSh() && ( SfxObjectCreateMode::EMBEDDED == pDoc->GetDocSh()->GetCreateMode() ) ) + SetViewShEditMode( static_cast<EditMode>(nInt32) ); + } + } + else if ( rValue.Name == sUNO_View_VisibleAreaTop ) + { + sal_Int32 nTop = 0; + if( rValue.Value >>= nTop ) + { + ::tools::Rectangle aVisArea( GetVisArea() ); + aVisArea.AdjustBottom(nTop - aVisArea.Top() ); + aVisArea.SetTop( nTop ); + SetVisArea( aVisArea ); + } + } + else if ( rValue.Name == sUNO_View_VisibleAreaLeft ) + { + sal_Int32 nLeft = 0; + if( rValue.Value >>= nLeft ) + { + ::tools::Rectangle aVisArea( GetVisArea() ); + aVisArea.AdjustRight(nLeft - aVisArea.Left() ); + aVisArea.SetLeft( nLeft ); + SetVisArea( aVisArea ); + } + } + else if ( rValue.Name == sUNO_View_VisibleAreaWidth ) + { + sal_Int32 nWidth = 0; + if( rValue.Value >>= nWidth ) + { + ::tools::Rectangle aVisArea( GetVisArea() ); + aVisArea.SetRight( aVisArea.Left() + nWidth - 1 ); + SetVisArea( aVisArea ); + } + } + else if ( rValue.Name == sUNO_View_VisibleAreaHeight ) + { + sal_Int32 nHeight = 0; + if( rValue.Value >>= nHeight ) + { + ::tools::Rectangle aVisArea( GetVisArea() ); + aVisArea.SetBottom( nHeight + aVisArea.Top() - 1 ); + SetVisArea( aVisArea ); + } + } + + else if ( rValue.Name == sUNO_View_GridIsVisible ) + { + if( rValue.Value >>= bBool ) + { + SetGridVisible( bBool ); + } + } + + else if ( rValue.Name == sUNO_View_IsSnapToGrid ) + { + if( rValue.Value >>= bBool ) + { + SetGridSnap( bBool ); + } + } + else if ( rValue.Name == sUNO_View_GridIsFront ) + { + if( rValue.Value >>= bBool ) + { + SetGridFront( bBool ); + } + } + else if ( rValue.Name == sUNO_View_IsSnapToPageMargins ) + { + if( rValue.Value >>= bBool ) + { + SetBordSnap( bBool ); + } + } + else if ( rValue.Name == sUNO_View_IsSnapToSnapLines ) + { + if( rValue.Value >>= bBool ) + { + SetHlplSnap( bBool ); + } + } + else if ( rValue.Name == sUNO_View_IsSnapToObjectFrame ) + { + if( rValue.Value >>= bBool ) + { + SetOFrmSnap( bBool ); + } + } + else if ( rValue.Name == sUNO_View_IsSnapToObjectPoints ) + { + if( rValue.Value >>= bBool ) + { + SetOPntSnap( bBool ); + } + } + else if ( rValue.Name == sUNO_View_IsPlusHandlesAlwaysVisible ) + { + if( rValue.Value >>= bBool ) + { + SetPlusHandlesAlwaysVisible( bBool ); + } + } + else if ( rValue.Name == sUNO_View_IsFrameDragSingles ) + { + if( rValue.Value >>= bBool ) + { + SetFrameDragSingles( bBool ); + } + } + else if ( rValue.Name == sUNO_View_EliminatePolyPointLimitAngle ) + { + if( rValue.Value >>= nInt32 ) + { + SetEliminatePolyPointLimitAngle( Degree100(nInt32) ); + } + } + else if ( rValue.Name == sUNO_View_IsEliminatePolyPoints ) + { + if( rValue.Value >>= bBool ) + { + SetEliminatePolyPoints( bBool ); + } + } + else if ( rValue.Name == sUNO_View_ActiveLayer ) + { + if( rValue.Value >>= aString ) + { + SetActiveLayer( aString ); + } + } + else if ( rValue.Name == sUNO_View_NoAttribs ) + { + if( rValue.Value >>= bBool ) + { + SetNoAttribs( bBool ); + } + } + else if ( rValue.Name == sUNO_View_NoColors ) + { + if( rValue.Value >>= bBool ) + { + SetNoColors( bBool ); + } + } + else if ( rValue.Name == sUNO_View_GridCoarseWidth ) + { + if( rValue.Value >>= nInt32 ) + { + const Size aCoarse( nInt32, GetGridCoarse().Height() ); + SetGridCoarse( aCoarse ); + } + } + else if ( rValue.Name == sUNO_View_GridCoarseHeight ) + { + if( rValue.Value >>= nInt32 ) + { + const Size aCoarse( GetGridCoarse().Width(), nInt32 ); + SetGridCoarse( aCoarse ); + } + } + else if ( rValue.Name == sUNO_View_GridFineWidth ) + { + if( rValue.Value >>= nInt32 ) + { + const Size aCoarse( nInt32, GetGridFine().Height() ); + SetGridFine( aCoarse ); + } + } + else if ( rValue.Name == sUNO_View_GridFineHeight ) + { + if( rValue.Value >>= nInt32 ) + { + const Size aCoarse( GetGridFine().Width(), nInt32 ); + SetGridFine( aCoarse ); + } + } + else if ( rValue.Name == sUNO_View_IsAngleSnapEnabled ) + { + if( rValue.Value >>= bBool ) + { + SetAngleSnapEnabled( bBool ); + } + } + else if ( rValue.Name == sUNO_View_SnapAngle ) + { + if( rValue.Value >>= nInt32 ) + { + SetSnapAngle( Degree100(nInt32) ); + } + } + else if ( rValue.Name == sUNO_View_GridSnapWidthXNumerator ) + { + rValue.Value >>= aSnapGridWidthXNum; + } + else if ( rValue.Name == sUNO_View_GridSnapWidthXDenominator ) + { + rValue.Value >>= aSnapGridWidthXDom; + } + else if ( rValue.Name == sUNO_View_GridSnapWidthYNumerator ) + { + rValue.Value >>= aSnapGridWidthYNum; + } + else if ( rValue.Name == sUNO_View_GridSnapWidthYDenominator ) + { + rValue.Value >>= aSnapGridWidthYDom; + } + else if (!bImpress && rValue.Name == sUNO_View_VisibleLayers ) + { + SdrLayerIDSet aSdrLayerIDSets; + aSdrLayerIDSets.PutValue( rValue.Value ); + SetVisibleLayers( aSdrLayerIDSets ); + } + else if (!bImpress && rValue.Name == sUNO_View_PrintableLayers ) + { + SdrLayerIDSet aSdrLayerIDSets; + aSdrLayerIDSets.PutValue( rValue.Value ); + SetPrintableLayers( aSdrLayerIDSets ); + } + else if (!bImpress && rValue.Name == sUNO_View_LockedLayers ) + { + SdrLayerIDSet aSdrLayerIDSets; + aSdrLayerIDSets.PutValue( rValue.Value ); + SetLockedLayers( aSdrLayerIDSets ); + } + } + + SetViewShEditModeOnLoad(EditMode::Page); + + const Fraction aSnapGridWidthX( aSnapGridWidthXNum, aSnapGridWidthXDom ); + const Fraction aSnapGridWidthY( aSnapGridWidthYNum, aSnapGridWidthYDom ); + + SetSnapGridWidth( aSnapGridWidthX, aSnapGridWidthY ); +} + +void FrameView::SetPreviousViewShellType (ViewShell::ShellType eType) +{ + mePreviousViewShellType = eType; +} + +void FrameView::SetViewShellTypeOnLoad (ViewShell::ShellType eType) +{ + meViewShellTypeOnLoad = eType; +} + +void FrameView::SetSelectedPage(sal_uInt16 nPage) +{ + mnSelectedPage = nPage; +} + +void FrameView::SetIsNavigatorShowingAllShapes (const bool bIsNavigatorShowingAllShapes) +{ + mbIsNavigatorShowingAllShapes = bIsNavigatorShowingAllShapes; +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/grviewsh.cxx b/sd/source/ui/view/grviewsh.cxx new file mode 100644 index 0000000000..b914b2da8c --- /dev/null +++ b/sd/source/ui/view/grviewsh.cxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <GraphicViewShell.hxx> +#include <LayerTabBar.hxx> +#include <FrameView.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/viewfrm.hxx> + +constexpr sal_Int32 TAB_HEIGHT_MARGIN = 10; + +namespace sd { + +GraphicViewShell::GraphicViewShell ( + ViewShellBase& rViewShellBase, + vcl::Window* pParentWindow, + FrameView* pFrameView) + : DrawViewShell ( + rViewShellBase, + pParentWindow, + PageKind::Standard, + pFrameView) +{ + ConstructGraphicViewShell(); +} + +GraphicViewShell::~GraphicViewShell() +{ +} + +void GraphicViewShell::ConstructGraphicViewShell() +{ + meShellType = ST_DRAW; + + mpLayerTabBar.reset (VclPtr<LayerTabBar>::Create(this, GetParentWindow())); + + // #i67363# no layer tabbar in preview mode + if ( !GetObjectShell()->IsPreview() ) + mpLayerTabBar->Show(); +} + +void GraphicViewShell::ChangeEditMode ( + EditMode eMode, + bool ) +{ + // There is no page tab that could be shown instead of the layer tab. + // Therefore we have it always visible regardless of what the caller + // said. (We have to change the callers behaviour, of course.) + DrawViewShell::ChangeEditMode (eMode, true); +} + +void GraphicViewShell::ArrangeGUIElements() +{ + if (mpLayerTabBar && mpLayerTabBar->IsVisible()) + { + Size aSize = mpLayerTabBar->GetSizePixel(); + const Size aFrameSize (GetViewFrame()->GetWindow().GetOutputSizePixel()); + + aSize.setHeight(GetParentWindow()->GetFont().GetFontHeight() + TAB_HEIGHT_MARGIN); + aSize.setWidth( aFrameSize.Width() ); + + Point aPos (0, maViewSize.Height() - aSize.Height()); + + mpLayerTabBar->SetPosSizePixel (aPos, aSize); + } + + DrawViewShell::ArrangeGUIElements(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/outlnvs2.cxx b/sd/source/ui/view/outlnvs2.cxx new file mode 100644 index 0000000000..003a4c1f92 --- /dev/null +++ b/sd/source/ui/view/outlnvs2.cxx @@ -0,0 +1,637 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <OutlineViewShell.hxx> +#include <Outliner.hxx> + +#include <app.hrc> +#include <svx/hlnkitem.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/request.hxx> +#include <sfx2/zoomitem.hxx> +#include <svx/svxids.hrc> +#include <svx/svdoutl.hxx> +#include <svx/zoomslideritem.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/editstat.hxx> +#include <unotools/useroptions.hxx> + +#include <sfx2/viewfrm.hxx> +#include <Window.hxx> +#include <fubullet.hxx> +#include <fuolbull.hxx> +#include <fuscale.hxx> +#include <fuchar.hxx> +#include <fuinsfil.hxx> +#include <fuprobjs.hxx> +#include <futhes.hxx> +#include <futempl.hxx> +#include <fusldlg.hxx> +#include <zoomlist.hxx> +#include <fuexpand.hxx> +#include <fusumry.hxx> +#include <fucushow.hxx> +#include <sdabstdlg.hxx> +#include <DrawDocShell.hxx> +#include <DrawViewShell.hxx> +#include <OutlineView.hxx> +#include <slideshow.hxx> +#include <memory> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +namespace sd { + +/************************************************************************/ + +/** + * SfxRequests for temporary functions + */ + +void OutlineViewShell::FuTemporary(SfxRequest &rReq) +{ + DeactivateCurrentFunction(); + + OutlinerView* pOutlinerView = pOlView->GetViewByWindow( GetActiveWindow() ); + sal_uInt16 nSId = rReq.GetSlot(); + + switch( nSId ) + { + case SID_ATTR_ZOOM: + { + const SfxItemSet* pArgs = rReq.GetArgs(); + + if ( pArgs ) + { + SvxZoomType eZT = pArgs->Get( SID_ATTR_ZOOM ).GetType(); + switch( eZT ) + { + case SvxZoomType::PERCENT: + SetZoom( static_cast<::tools::Long>( pArgs->Get( SID_ATTR_ZOOM ).GetValue()) ); + Invalidate( SID_ATTR_ZOOM ); + Invalidate( SID_ATTR_ZOOMSLIDER ); + break; + default: + break; + } + rReq.Done(); + } + else + { + // open the zoom dialog here + SetCurrentFunction( FuScale::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + } + Cancel(); + } + break; + + case SID_ATTR_ZOOMSLIDER: + { + const SfxItemSet* pArgs = rReq.GetArgs(); + + const SfxUInt16Item* pScale = (pArgs && pArgs->Count () == 1) ? + rReq.GetArg(SID_ATTR_ZOOMSLIDER) : nullptr; + if (pScale && CHECK_RANGE (5, pScale->GetValue (), 3000)) + { + SetZoom (pScale->GetValue ()); + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_ATTR_ZOOM ); + rBindings.Invalidate( SID_ZOOM_IN ); + rBindings.Invalidate( SID_ZOOM_OUT ); + rBindings.Invalidate( SID_ATTR_ZOOMSLIDER ); + + } + + Cancel(); + rReq.Done (); + break; + } + + case SID_ZOOM_IN: + { + SetZoom( std::min<::tools::Long>( GetActiveWindow()->GetZoom() * 2, GetActiveWindow()->GetMaxZoom() ) ); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), + GetActiveWindow()->GetOutputSizePixel()) ); + mpZoomList->InsertZoomRect(aVisAreaWin); + Invalidate( SID_ATTR_ZOOM ); + Invalidate( SID_ZOOM_IN ); + Invalidate(SID_ZOOM_OUT); + Invalidate( SID_ATTR_ZOOMSLIDER ); + Cancel(); + rReq.Done(); + } + break; + + case SID_SIZE_REAL: + { + SetZoom( 100 ); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), + GetActiveWindow()->GetOutputSizePixel()) ); + mpZoomList->InsertZoomRect(aVisAreaWin); + Invalidate( SID_ATTR_ZOOM ); + Invalidate( SID_ATTR_ZOOMSLIDER ); + Cancel(); + rReq.Done(); + } + break; + + case SID_ZOOM_OUT: + { + SetZoom( std::max<::tools::Long>( GetActiveWindow()->GetZoom() / 2, GetActiveWindow()->GetMinZoom() ) ); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), + GetActiveWindow()->GetOutputSizePixel()) ); + mpZoomList->InsertZoomRect(aVisAreaWin); + Invalidate( SID_ATTR_ZOOM ); + Invalidate( SID_ZOOM_OUT); + Invalidate( SID_ZOOM_IN ); + Invalidate( SID_ATTR_ZOOMSLIDER ); + Cancel(); + rReq.Done(); + } + break; + + case SID_OUTLINE_COLLAPSE_ALL: + { + pOutlinerView->CollapseAll(); + Cancel(); + rReq.Done(); + } + break; + + case SID_OUTLINE_COLLAPSE: + { + pOutlinerView->Collapse(); + Cancel(); + rReq.Done(); + } + break; + + case SID_OUTLINE_EXPAND_ALL: + { + pOutlinerView->ExpandAll(); + Cancel(); + rReq.Done(); + } + break; + + case SID_OUTLINE_EXPAND: + { + pOutlinerView->Expand(); + Cancel(); + rReq.Done(); + } + break; + + case SID_OUTLINE_FORMAT: + { + ::Outliner* pOutl = pOutlinerView->GetOutliner(); + pOutl->SetFlatMode( !pOutl->IsFlatMode() ); + Invalidate( SID_COLORVIEW ); + Cancel(); + rReq.Done(); + } + break; + + case SID_SELECTALL: + { + ::Outliner& rOutl = pOlView->GetOutliner(); + sal_Int32 nParaCount = rOutl.GetParagraphCount(); + if (nParaCount > 0) + { + pOutlinerView->SelectRange( 0, nParaCount ); + } + Cancel(); + } + break; + + case SID_PRESENTATION: + case SID_PRESENTATION_CURRENT_SLIDE: + case SID_REHEARSE_TIMINGS: + { + pOlView->PrepareClose(); + slideshowhelp::ShowSlideShow(rReq, *GetDoc()); + Cancel(); + rReq.Done(); + } + break; + + case SID_COLORVIEW: + { + ::Outliner* pOutl = pOutlinerView->GetOutliner(); + EEControlBits nCntrl = pOutl->GetControlWord(); + + if ( !(nCntrl & EEControlBits::NOCOLORS) ) + { + // color view is enabled: disable + pOutl->SetControlWord(nCntrl | EEControlBits::NOCOLORS); + } + else + { + // color view is disabled: enable + pOutl->SetControlWord(nCntrl & ~EEControlBits::NOCOLORS); + } + + InvalidateWindows(); + Invalidate( SID_COLORVIEW ); + Cancel(); + rReq.Done(); + } + break; + + case SID_STYLE_EDIT: + case SID_STYLE_UPDATE_BY_EXAMPLE: + { + if( rReq.GetArgs() ) + { + SetCurrentFunction( FuTemplate::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + Cancel(); + } + + rReq.Ignore (); + } + break; + + case SID_PRESENTATION_DLG: + { + SetCurrentFunction( FuSlideShowDlg::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_REMOTE_DLG: + { +#ifdef ENABLE_SDREMOTE + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateRemoteDialog(GetFrameWeld())); + pDlg->Execute(); +#endif + } + break; + + case SID_CUSTOMSHOW_DLG: + { + SetCurrentFunction( FuCustomShowDlg::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_PHOTOALBUM: + { + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + vcl::Window* pWin = GetActiveWindow(); + ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateSdPhotoAlbumDialog( + pWin ? pWin->GetFrameWeld() : nullptr, + GetDoc())); + + pDlg->Execute(); + + Cancel(); + rReq.Ignore (); + } + break; + } + + if(HasCurrentFunction()) + GetCurrentFunction()->Activate(); + + Invalidate( SID_OUTLINE_COLLAPSE_ALL ); + Invalidate( SID_OUTLINE_COLLAPSE ); + Invalidate( SID_OUTLINE_EXPAND_ALL ); + Invalidate( SID_OUTLINE_EXPAND ); + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_OUTLINE_LEFT ); + rBindings.Invalidate( SID_OUTLINE_RIGHT ); + rBindings.Invalidate( SID_OUTLINE_UP ); + rBindings.Invalidate( SID_OUTLINE_DOWN ); + + Invalidate( SID_OUTLINE_FORMAT ); + Invalidate( SID_COLORVIEW ); + Invalidate(SID_CUT); + Invalidate(SID_COPY); + Invalidate(SID_PASTE); + Invalidate(SID_PASTE_UNFORMATTED); +} + +void OutlineViewShell::FuTemporaryModify(SfxRequest &rReq) +{ + sal_uInt16 nSId = rReq.GetSlot(); + std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard; + if (nSId != SID_OUTLINE_BULLET && nSId != FN_SVX_SET_BULLET && nSId != FN_SVX_SET_NUMBER) + { + aGuard.reset( new OutlineViewModelChangeGuard(*pOlView) ); + } + DeactivateCurrentFunction(); + + OutlinerView* pOutlinerView = pOlView->GetViewByWindow( GetActiveWindow() ); + //sal_uInt16 nSId = rReq.GetSlot(); + + switch( nSId ) + { + case SID_HYPERLINK_SETLINK: + { + const SfxItemSet* pReqArgs = rReq.GetArgs(); + + if (pReqArgs) + { + const SvxHyperlinkItem* pHLItem = + &pReqArgs->Get(SID_HYPERLINK_SETLINK); + + SvxFieldItem aURLItem(SvxURLField(pHLItem->GetURL(), + pHLItem->GetName(), + SvxURLFormat::Repr), EE_FEATURE_FIELD); + ESelection aSel( pOutlinerView->GetSelection() ); + pOutlinerView->InsertField(aURLItem); + if ( aSel.nStartPos <= aSel.nEndPos ) + aSel.nEndPos = aSel.nStartPos + 1; + else + aSel.nStartPos = aSel.nEndPos + 1; + pOutlinerView->SetSelection( aSel ); + } + + Cancel(); + rReq.Ignore (); + } + break; + + case FN_INSERT_SOFT_HYPHEN: + case FN_INSERT_HARDHYPHEN: + case FN_INSERT_HARD_SPACE: + case FN_INSERT_NNBSP: + case SID_INSERT_RLM : + case SID_INSERT_LRM : + case SID_INSERT_WJ : + case SID_INSERT_ZWSP: + case SID_CHARMAP: + { + SetCurrentFunction( FuBullet::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_OUTLINE_BULLET: + case FN_SVX_SET_BULLET: + case FN_SVX_SET_NUMBER: + { + SetCurrentFunction( FuBulletAndPosition::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_THESAURUS: + { + SetCurrentFunction( FuThesaurus::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + Cancel(); + rReq.Ignore (); + } + break; + + case SID_CHAR_DLG_EFFECT: + case SID_CHAR_DLG: + { + SetCurrentFunction( FuChar::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + Cancel(); + } + break; + + case SID_INSERTFILE: + { + SetCurrentFunction( FuInsertFile::Create(this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq) ); + Cancel(); + } + break; + + case SID_PRESENTATIONOBJECT: + { + SetCurrentFunction( FuPresentationObjects::Create(this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq) ); + Cancel(); + } + break; + + case SID_SET_DEFAULT: + { + pOutlinerView->RemoveAttribs(true); // sal_True = also paragraph attributes + Cancel(); + rReq.Done(); + } + break; + + case SID_SUMMARY_PAGE: + { + pOlView->SetSelectedPages(); + SetCurrentFunction( FuSummaryPage::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + pOlView->GetOutliner().Clear(); + pOlView->FillOutliner(); + pOlView->GetActualPage(); + Cancel(); + } + break; + + case SID_EXPAND_PAGE: + { + pOlView->SetSelectedPages(); + SetCurrentFunction( FuExpandPage::Create( this, GetActiveWindow(), pOlView.get(), GetDoc(), rReq ) ); + pOlView->GetOutliner().Clear(); + pOlView->FillOutliner(); + pOlView->GetActualPage(); + Cancel(); + } + break; + + case SID_INSERT_FLD_DATE_FIX: + case SID_INSERT_FLD_DATE_VAR: + case SID_INSERT_FLD_TIME_FIX: + case SID_INSERT_FLD_TIME_VAR: + case SID_INSERT_FLD_AUTHOR: + case SID_INSERT_FLD_PAGE: + case SID_INSERT_FLD_PAGE_TITLE: + case SID_INSERT_FLD_PAGES: + case SID_INSERT_FLD_FILE: + { + std::unique_ptr<SvxFieldItem> pFieldItem; + + switch( nSId ) + { + case SID_INSERT_FLD_DATE_FIX: + pFieldItem.reset(new SvxFieldItem( + SvxDateField( Date( Date::SYSTEM ), SvxDateType::Fix ), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_DATE_VAR: + pFieldItem.reset(new SvxFieldItem( SvxDateField(), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_TIME_FIX: + pFieldItem.reset(new SvxFieldItem( + SvxExtTimeField( ::tools::Time( ::tools::Time::SYSTEM ), SvxTimeType::Fix ), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_TIME_VAR: + pFieldItem.reset(new SvxFieldItem( SvxExtTimeField(), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_AUTHOR: + { + SvtUserOptions aUserOptions; + pFieldItem.reset(new SvxFieldItem( + SvxAuthorField( + aUserOptions.GetFirstName(), aUserOptions.GetLastName(), aUserOptions.GetID() ) + , EE_FEATURE_FIELD )); + } + break; + + case SID_INSERT_FLD_PAGE: + pFieldItem.reset(new SvxFieldItem( SvxPageField(), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_PAGE_TITLE: + pFieldItem.reset(new SvxFieldItem( SvxPageTitleField(), EE_FEATURE_FIELD)); + break; + + case SID_INSERT_FLD_PAGES: + pFieldItem.reset(new SvxFieldItem( SvxPagesField(), EE_FEATURE_FIELD )); + break; + + case SID_INSERT_FLD_FILE: + { + OUString aName; + if( GetDocSh()->HasName() ) + aName = GetDocSh()->GetMedium()->GetName(); + //else + // aName = GetDocSh()->GetName(); + pFieldItem.reset(new SvxFieldItem( SvxExtFileField( aName ), EE_FEATURE_FIELD )); + } + break; + } + + const SvxFieldItem* pOldFldItem = pOutlinerView->GetFieldAtSelection(); + + if( pOldFldItem && ( nullptr != dynamic_cast< const SvxURLField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxDateField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxTimeField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtTimeField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtFileField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxAuthorField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxPageField *>( pOldFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxPagesField *>( pOldFldItem->GetField() )) ) + { + // select field, so it gets deleted on Insert + ESelection aSel = pOutlinerView->GetSelection(); + if( aSel.nStartPos == aSel.nEndPos ) + aSel.nEndPos++; + pOutlinerView->SetSelection( aSel ); + } + + if( pFieldItem ) + pOutlinerView->InsertField( *pFieldItem ); + + pFieldItem.reset(); + + Cancel(); + rReq.Ignore (); + } + break; + + case SID_MODIFY_FIELD: + { + const SvxFieldItem* pFldItem = pOutlinerView->GetFieldAtSelection(); + + if( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) ) ) + { + // Dialog... + SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); + vcl::Window* pWin = GetActiveWindow(); + ScopedVclPtr<AbstractSdModifyFieldDlg> pDlg(pFact->CreateSdModifyFieldDlg(pWin ? pWin->GetFrameWeld() : nullptr, pFldItem->GetField(), pOutlinerView->GetAttribs() )); + if( pDlg->Execute() == RET_OK ) + { + std::unique_ptr<SvxFieldData> pField(pDlg->GetField()); + if( pField ) + { + SvxFieldItem aFieldItem( *pField, EE_FEATURE_FIELD ); + //pOLV->DeleteSelected(); <-- unfortunately missing! + // select field, so it gets deleted on Insert + ESelection aSel = pOutlinerView->GetSelection(); + bool bSel = true; + if( aSel.nStartPos == aSel.nEndPos ) + { + bSel = false; + aSel.nEndPos++; + } + pOutlinerView->SetSelection( aSel ); + + pOutlinerView->InsertField( aFieldItem ); + + // reset selection to original state + if( !bSel ) + aSel.nEndPos--; + pOutlinerView->SetSelection( aSel ); + + pField.reset(); + } + + SfxItemSet aSet( pDlg->GetItemSet() ); + if( aSet.Count() ) + { + pOutlinerView->SetAttribs( aSet ); + + ::Outliner* pOutliner = pOutlinerView->GetOutliner(); + if( pOutliner ) + pOutliner->UpdateFields(); + } + } + } + + Cancel(); + rReq.Ignore (); + } + break; + } + + if(HasCurrentFunction()) + GetCurrentFunction()->Activate(); + + Invalidate( SID_OUTLINE_COLLAPSE_ALL ); + Invalidate( SID_OUTLINE_COLLAPSE ); + Invalidate( SID_OUTLINE_EXPAND_ALL ); + Invalidate( SID_OUTLINE_EXPAND ); + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_OUTLINE_LEFT ); + rBindings.Invalidate( SID_OUTLINE_RIGHT ); + rBindings.Invalidate( SID_OUTLINE_UP ); + rBindings.Invalidate( SID_OUTLINE_DOWN ); + + Invalidate( SID_OUTLINE_FORMAT ); + Invalidate( SID_COLORVIEW ); + Invalidate(SID_CUT); + Invalidate(SID_COPY); + Invalidate(SID_PASTE); + Invalidate(SID_PASTE_UNFORMATTED); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/outlnvsh.cxx b/sd/source/ui/view/outlnvsh.cxx new file mode 100644 index 0000000000..718b28514e --- /dev/null +++ b/sd/source/ui/view/outlnvsh.cxx @@ -0,0 +1,1886 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <OutlineViewShell.hxx> +#include <Outliner.hxx> + +#include <helpids.h> +#include <app.hrc> +#include <svx/hyperdlg.hxx> +#include <svx/zoomslideritem.hxx> +#include <svx/svdundo.hxx> + +#include <sfx2/infobar.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/zoomitem.hxx> +#include <editeng/editview.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/editund2.hxx> +#include <sfx2/shell.hxx> +#include <sfx2/request.hxx> +#include <svx/hlnkitem.hxx> +#include <svx/svdotext.hxx> +#include <svx/svdoutl.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/settings.hxx> + +#include <sal/log.hxx> +#include <svl/stritem.hxx> +#include <svl/whiter.hxx> +#include <editeng/editstat.hxx> +#include <svl/itempool.hxx> +#include <sfx2/tplpitem.hxx> +#include <sfx2/sidebar/SidebarChildWindow.hxx> +#include <vcl/EnumContext.hxx> +#include <sot/formats.hxx> +#include <com/sun/star/linguistic2/XThesaurus.hpp> +#include <editeng/unolingu.hxx> +#include <editeng/outlobj.hxx> +#include <svl/cjkoptions.hxx> +#include <svtools/cliplistener.hxx> +#include <svl/srchitem.hxx> +#include <editeng/editobj.hxx> +#include <fubullet.hxx> + +#include <strings.hrc> + +#include <Window.hxx> +#include <drawdoc.hxx> +#include <sdresid.hxx> +#include <sdpage.hxx> +#include <fuoltext.hxx> +#include <FrameView.hxx> +#include <zoomlist.hxx> +#include <stlsheet.hxx> +#include <SdUnoOutlineView.hxx> +#include <SpellDialogChildWindow.hxx> + +#include <AccessibleOutlineView.hxx> +#include <ViewShellBase.hxx> +#include <DrawController.hxx> +#include <DrawDocShell.hxx> +#include <OutlineView.hxx> +#include <framework/FrameworkHelper.hxx> +#include <sfx2/devtools/DevelopmentToolChildWindow.hxx> + +#include <memory> + +#define ShellClass_OutlineViewShell +using namespace sd; +#include <sdslots.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::linguistic2; + +namespace sd { + +#define MIN_ZOOM 10 // minimum zoom factor +#define MAX_ZOOM 1000 // maximum zoom factor + +/** + * Declare SFX-Slotmap and standard interface + */ +SFX_IMPL_INTERFACE(OutlineViewShell, SfxShell) + +void OutlineViewShell::InitInterface_Impl() +{ + GetStaticInterface()->RegisterPopupMenu("outline"); + + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS, SfxVisibilityFlags::Standard | SfxVisibilityFlags::FullScreen | SfxVisibilityFlags::Server, + ToolbarId::Outline_Toolbox); + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_APPLICATION, SfxVisibilityFlags::Standard | SfxVisibilityFlags::Client | SfxVisibilityFlags::Viewer | SfxVisibilityFlags::ReadonlyDoc, + ToolbarId::Draw_Viewer_Toolbox); + + GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SvxHlinkDlgWrapper::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(::sd::SpellDialogChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(SID_SEARCH_DLG); + GetStaticInterface()->RegisterChildWindow(sfx2::sidebar::SidebarChildWindow::GetChildWindowId()); + GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId()); +} + + +/** + * common initialization part of both constructors + */ +void OutlineViewShell::Construct() +{ + bool bModified = GetDoc()->IsChanged(); + + meShellType = ST_OUTLINE; + Size aSize(29700, 21000); + Point aWinPos (0, 0); + Point aViewOrigin(0, 0); + GetActiveWindow()->SetMinZoomAutoCalc(false); + GetActiveWindow()->SetMinZoom( MIN_ZOOM ); + GetActiveWindow()->SetMaxZoom( MAX_ZOOM ); + InitWindows(aViewOrigin, aSize, aWinPos); + pOlView.reset( new OutlineView(*GetDocSh(), GetActiveWindow(), *this) ); + mpView = pOlView.get(); // Pointer of base class ViewShell + + SetPool( &GetDoc()->GetPool() ); + + SetZoom(69); + + // Apply settings of FrameView + ReadFrameViewData(mpFrameView); + + ::Outliner& rOutl = pOlView->GetOutliner(); + rOutl.SetUpdateLayout(true); + + if (!bModified) + { + rOutl.ClearModifyFlag(); + } + + pLastPage = GetActualPage(); + + SetName( "OutlineViewShell" ); + + GetActiveWindow()->SetHelpId( HID_SDOUTLINEVIEWSHELL ); +} + +Reference<drawing::XDrawSubController> OutlineViewShell::CreateSubController() +{ + Reference<drawing::XDrawSubController> xSubController; + + if (IsMainViewShell()) + { + // Create uno sub controller for the main view shell. + xSubController.set( new SdUnoOutlineView(*this) ); + } + + return xSubController; +} + +/** + * Default constructor, windows must not center themselves automatically + */ +OutlineViewShell::OutlineViewShell ( + SfxViewFrame* /*pFrame*/, + ViewShellBase& rViewShellBase, + vcl::Window* pParentWindow, + FrameView* pFrameViewArgument) + : ViewShell(pParentWindow, rViewShellBase), + pLastPage( nullptr ), + bPastePossible(false), + mbInitialized(false) + +{ + if (pFrameViewArgument != nullptr) + mpFrameView = pFrameViewArgument; + else + mpFrameView = new FrameView(GetDoc()); + + mpFrameView->Connect(); + + Construct(); + + SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::OutlineText)); + + m_StrOldPageName.clear(); + + doShow(); +} + +OutlineViewShell::~OutlineViewShell() +{ + DisposeFunctions(); + + pOlView.reset(); + + mpFrameView->Disconnect(); + + if ( mxClipEvtLstnr.is() ) + { + mxClipEvtLstnr->RemoveListener( GetActiveWindow() ); + mxClipEvtLstnr->ClearCallbackLink(); // prevent callback if another thread is waiting + } +} + +void OutlineViewShell::Shutdown() +{ + ViewShell::Shutdown(); + + PrepareClose(); +} + +/** + * Paint method: the event gets forwarded from pWindow to the Viewshell + * and the current function + */ +void OutlineViewShell::Paint(const ::tools::Rectangle& rRect, ::sd::Window* pWin) +{ + if (pOlView) + { + pOlView->Paint(rRect, pWin); + } +} + +void OutlineViewShell::ArrangeGUIElements () +{ + // Retrieve the current size (thickness) of the scroll bars. That is + // the width of the vertical and the height of the horizontal scroll + // bar. + int nScrollBarSize = + GetParentWindow()->GetSettings().GetStyleSettings().GetScrollBarSize(); + maScrBarWH = Size (nScrollBarSize, nScrollBarSize); + + ViewShell::ArrangeGUIElements (); + + ::sd::Window* pWindow = mpContentWindow.get(); + if (pWindow == nullptr) + return; + + pWindow->SetMinZoomAutoCalc(false); + + // change OutputArea of the OutlinerView + OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWindow); + + ::tools::Rectangle aWin(Point(0,0), pWindow->GetOutputSizePixel()); + + aWin = pWindow->PixelToLogic(aWin); + pOutlinerView->SetOutputArea(aWin); + + ::tools::Rectangle aVis = pOutlinerView->GetVisArea(); + + ::tools::Rectangle aText(Point(0,0), + Size(pOlView->GetPaperWidth(), + pOlView->GetOutliner().GetTextHeight())); + if (aWin.GetHeight() > aText.Bottom()) + aText.SetBottom( aWin.GetHeight() ); + + if (!aWin.IsEmpty()) // not when opening + { + InitWindows(Point(0,0), aText.GetSize(), aVis.TopLeft()); + UpdateScrollBars(); + } +} + +/** + * Handle SfxRequest for the Controller + */ +void OutlineViewShell::ExecCtrl(SfxRequest &rReq) +{ + sal_uInt16 nSlot = rReq.GetSlot(); + switch ( nSlot ) + { + case SID_MAIL_SCROLLBODY_PAGEDOWN: + { + ExecReq( rReq ); + break; + } + + case SID_OPT_LOCALE_CHANGED: + { + pOlView->GetOutliner().UpdateFields(); + UpdatePreview( GetActualPage() ); + rReq.Done(); + break; + } + + default: + break; + } +} + +/** + * Activate(): during the first invocation the fields get updated + */ +void OutlineViewShell::Activate( bool bIsMDIActivate ) +{ + if ( ! mbInitialized) + { + mbInitialized = true; + SfxRequest aRequest (SID_EDIT_OUTLINER, SfxCallMode::SLOT, GetDoc()->GetItemPool()); + FuPermanent (aRequest); + } + + ViewShell::Activate( bIsMDIActivate ); + SfxShell::BroadcastContextForActivation(true); + + pOlView->SetLinks(); + pOlView->ConnectToApplication(); + + if( bIsMDIActivate ) + { + OutlinerView* pOutlinerView = pOlView->GetViewByWindow( GetActiveWindow() ); + ::Outliner* pOutl = pOutlinerView->GetOutliner(); + pOutl->UpdateFields(); + } +} + +void OutlineViewShell::Deactivate( bool bIsMDIActivate ) +{ + pOlView->DisconnectFromApplication(); + + // Links must be kept also on deactivated viewshell, to allow drag'n'drop + // to function properly + ViewShell::Deactivate( bIsMDIActivate ); +} + +/** + * Set status of Controller-SfxSlots + */ +void OutlineViewShell::GetCtrlState(SfxItemSet &rSet) +{ + if (SfxItemState::DEFAULT == rSet.GetItemState(SID_HYPERLINK_GETLINK)) + { + SvxHyperlinkItem aHLinkItem; + + OutlinerView* pOLV = pOlView->GetViewByWindow(GetActiveWindow()); + if (pOLV) + { + const SvxFieldItem* pFieldItem = pOLV->GetFieldAtSelection(); + if (pFieldItem) + { + ESelection aSel = pOLV->GetSelection(); + if ( abs( aSel.nEndPos - aSel.nStartPos ) == 1 ) + { + const SvxFieldData* pField = pFieldItem->GetField(); + if ( auto pUrlField = dynamic_cast< const SvxURLField *>( pField ) ) + { + aHLinkItem.SetName(pUrlField->GetRepresentation()); + aHLinkItem.SetURL(pUrlField->GetURL()); + aHLinkItem.SetTargetFrame(pUrlField->GetTargetFrame()); + } + } + } + } + rSet.Put(aHLinkItem); + } + rSet.Put( SfxBoolItem( SID_READONLY_MODE, GetDocSh()->IsReadOnly() ) ); + + if ( SfxItemState::DEFAULT == rSet.GetItemState(SID_MAIL_SCROLLBODY_PAGEDOWN) ) + rSet.Put( SfxBoolItem( SID_MAIL_SCROLLBODY_PAGEDOWN, true ) ); + + if ( !(SfxItemState::DEFAULT == rSet.GetItemState(SID_TRANSLITERATE_HALFWIDTH) || + SfxItemState::DEFAULT == rSet.GetItemState(SID_TRANSLITERATE_FULLWIDTH) || + SfxItemState::DEFAULT == rSet.GetItemState(SID_TRANSLITERATE_HIRAGANA) || + SfxItemState::DEFAULT == rSet.GetItemState(SID_TRANSLITERATE_KATAKANA)) ) + return; + + if( !SvtCJKOptions::IsChangeCaseMapEnabled() ) + { + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, false ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, false ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, false ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, false ); + rSet.DisableItem( SID_TRANSLITERATE_HALFWIDTH ); + rSet.DisableItem( SID_TRANSLITERATE_FULLWIDTH ); + rSet.DisableItem( SID_TRANSLITERATE_HIRAGANA ); + rSet.DisableItem( SID_TRANSLITERATE_KATAKANA ); + } + else + { + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HALFWIDTH, true ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_FULLWIDTH, true ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_HIRAGANA, true ); + GetViewFrame()->GetBindings().SetVisibleState( SID_TRANSLITERATE_KATAKANA, true ); + } +} + +/** + * SfxRequests for support functions + */ +void OutlineViewShell::FuSupport(SfxRequest &rReq) +{ + if( rReq.GetSlot() == SID_STYLE_FAMILY && rReq.GetArgs()) + GetDocSh()->SetStyleFamily(static_cast<SfxStyleFamily>(rReq.GetArgs()->Get( SID_STYLE_FAMILY ).GetValue())); + + bool bPreviewState = false; + sal_uInt16 nSlot = rReq.GetSlot(); + + std::unique_ptr<OutlineViewModelChangeGuard, o3tl::default_delete<OutlineViewModelChangeGuard>> aGuard; + if( pOlView && ( + (nSlot == SID_TRANSLITERATE_SENTENCE_CASE) || + (nSlot == SID_TRANSLITERATE_TITLE_CASE) || + (nSlot == SID_TRANSLITERATE_TOGGLE_CASE) || + (nSlot == SID_TRANSLITERATE_UPPER) || + (nSlot == SID_TRANSLITERATE_LOWER) || + (nSlot == SID_TRANSLITERATE_HALFWIDTH) || + (nSlot == SID_TRANSLITERATE_FULLWIDTH) || + (nSlot == SID_TRANSLITERATE_HIRAGANA) || + (nSlot == SID_TRANSLITERATE_KATAKANA) || + (nSlot == SID_CUT) || + (nSlot == SID_PASTE) || + (nSlot == SID_PASTE_UNFORMATTED) || + (nSlot == SID_DELETE))) + { + aGuard.reset( new OutlineViewModelChangeGuard( *pOlView ) ); + } + + switch ( nSlot ) + { + case SID_CUT: + { + if(HasCurrentFunction()) + { + GetCurrentFunction()->DoCut(); + } + else if (pOlView) + { + pOlView->DoCut(); + } + rReq.Done(); + bPreviewState = true; + } + break; + + case SID_COPY: + { + if(HasCurrentFunction()) + { + GetCurrentFunction()->DoCopy(); + } + else if (pOlView) + { + pOlView->DoCopy(); + } + rReq.Done(); + bPreviewState = true; + } + break; + + case SID_PASTE: + { + OutlineViewPageChangesGuard aGuard2(pOlView.get()); + + if(HasCurrentFunction()) + { + GetCurrentFunction()->DoPaste(); + } + else if (pOlView) + { + pOlView->DoPaste(); + } + rReq.Done(); + bPreviewState = true; + } + break; + + case SID_PASTE_UNFORMATTED: + { + OutlineViewPageChangesGuard aGuard2(pOlView.get()); + + if(HasCurrentFunction()) + { + GetCurrentFunction()->DoPasteUnformatted(); + } + else if(pOlView) + { + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) ); + if (aDataHelper.GetTransferable().is()) + { + sal_Int8 nAction = DND_ACTION_COPY; + pOlView->InsertData( aDataHelper, + GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(), GetActiveWindow()->GetOutputSizePixel() ).Center() ), + nAction, false, SotClipboardFormatId::STRING); + } + } + + rReq.Ignore (); + } + break; + case SID_DELETE: + { + if( pOlView ) + { + OutlinerView* pOutlView = pOlView->GetViewByWindow(GetActiveWindow()); + if (pOutlView) + { + OutlineViewPageChangesGuard aGuard2(pOlView.get()); + + vcl::KeyCode aKCode(KEY_DELETE); + KeyEvent aKEvt( 0, aKCode ); + pOutlView->PostKeyEvent(aKEvt); + + rtl::Reference<FuPoor> xFunc( GetCurrentFunction() ); + FuOutlineText* pFuOutlineText = dynamic_cast< FuOutlineText* >( xFunc.get() ); + if( pFuOutlineText ) + pFuOutlineText->UpdateForKeyPress (aKEvt); + } + } + rReq.Done(); + bPreviewState = true; + } + break; + + case SID_DRAWINGMODE: + case SID_SLIDE_MASTER_MODE: + case SID_NOTES_MODE: + case SID_NOTES_MASTER_MODE: + case SID_HANDOUT_MASTER_MODE: + case SID_SLIDE_SORTER_MODE: + case SID_OUTLINE_MODE: + framework::FrameworkHelper::Instance(GetViewShellBase())->HandleModeChangeSlot( + nSlot, + rReq); + rReq.Done(); + break; + + case SID_RULER: + SetRuler( !HasRuler() ); + Invalidate( SID_RULER ); + rReq.Done(); + break; + + case SID_ZOOM_PREV: + { + if (mpZoomList->IsPreviousPossible()) + { + SetZoomRect(mpZoomList->GetPreviousZoomRect()); + } + rReq.Done (); + } + break; + + case SID_ZOOM_NEXT: + { + if (mpZoomList->IsNextPossible()) + { + SetZoomRect(mpZoomList->GetNextZoomRect()); + } + rReq.Done (); + } + break; + + case SID_AUTOSPELL_CHECK: + { + GetDoc()->SetOnlineSpell(!GetDoc()->GetOnlineSpell()); + rReq.Done (); + } + break; + + case SID_TRANSLITERATE_SENTENCE_CASE: + case SID_TRANSLITERATE_TITLE_CASE: + case SID_TRANSLITERATE_TOGGLE_CASE: + case SID_TRANSLITERATE_UPPER: + case SID_TRANSLITERATE_LOWER: + case SID_TRANSLITERATE_HALFWIDTH: + case SID_TRANSLITERATE_FULLWIDTH: + case SID_TRANSLITERATE_HIRAGANA: + case SID_TRANSLITERATE_KATAKANA: + { + OutlinerView* pOLV = pOlView ? pOlView->GetViewByWindow( GetActiveWindow() ) : nullptr; + if( pOLV ) + { + TransliterationFlags nType = TransliterationFlags::NONE; + + switch( nSlot ) + { + case SID_TRANSLITERATE_SENTENCE_CASE: + nType = TransliterationFlags::SENTENCE_CASE; + break; + case SID_TRANSLITERATE_TITLE_CASE: + nType = TransliterationFlags::TITLE_CASE; + break; + case SID_TRANSLITERATE_TOGGLE_CASE: + nType = TransliterationFlags::TOGGLE_CASE; + break; + case SID_TRANSLITERATE_UPPER: + nType = TransliterationFlags::LOWERCASE_UPPERCASE; + break; + case SID_TRANSLITERATE_LOWER: + nType = TransliterationFlags::UPPERCASE_LOWERCASE; + break; + case SID_TRANSLITERATE_HALFWIDTH: + nType = TransliterationFlags::FULLWIDTH_HALFWIDTH; + break; + case SID_TRANSLITERATE_FULLWIDTH: + nType = TransliterationFlags::HALFWIDTH_FULLWIDTH; + break; + case SID_TRANSLITERATE_HIRAGANA: + nType = TransliterationFlags::KATAKANA_HIRAGANA; + break; + case SID_TRANSLITERATE_KATAKANA: + nType = TransliterationFlags::HIRAGANA_KATAKANA; + break; + } + + pOLV->TransliterateText( nType ); + } + + rReq.Done(); + bPreviewState = true; + } + break; + + // added Undo/Redo handling + case SID_UNDO : + { + OutlineViewPageChangesGuard aGuard2(pOlView.get()); + ImpSidUndo(rReq); + } + break; + case SID_REDO : + { + OutlineViewPageChangesGuard aGuard2(pOlView.get()); + ImpSidRedo(rReq); + } + break; + + default: + break; + } + + if( bPreviewState ) + Invalidate( SID_PREVIEW_STATE ); + + Invalidate(SID_CUT); + Invalidate(SID_COPY); + Invalidate(SID_PASTE); +} + +/** + * SfxRequests for permanent functions + */ +void OutlineViewShell::FuPermanent(SfxRequest &rReq) +{ + if(HasCurrentFunction()) + { + DeactivateCurrentFunction(true); + } + + switch ( rReq.GetSlot() ) + { + case SID_EDIT_OUTLINER: + { + ::Outliner& rOutl = pOlView->GetOutliner(); + rOutl.GetUndoManager().Clear(); + rOutl.UpdateFields(); + + SetCurrentFunction( FuOutlineText::Create(this,GetActiveWindow(),pOlView.get(),GetDoc(),rReq) ); + + rReq.Done(); + } + break; + + default: + break; + } + + if(HasOldFunction()) + { + GetOldFunction()->Deactivate(); + SetOldFunction(nullptr); + } + + if(HasCurrentFunction()) + { + GetCurrentFunction()->Activate(); + SetOldFunction(GetCurrentFunction()); + } +} + +IMPL_LINK( OutlineViewShell, ClipboardChanged, TransferableDataHelper*, pDataHelper, void ) +{ + bPastePossible = pDataHelper->GetFormatCount() != 0 && + ( pDataHelper->HasFormat( SotClipboardFormatId::STRING ) || + pDataHelper->HasFormat( SotClipboardFormatId::RTF ) || + pDataHelper->HasFormat( SotClipboardFormatId::RICHTEXT ) || + pDataHelper->HasFormat( SotClipboardFormatId::HTML ) ); + + SfxBindings& rBindings = GetViewFrame()->GetBindings(); + rBindings.Invalidate( SID_PASTE ); + rBindings.Invalidate( SID_PASTE_SPECIAL ); + rBindings.Invalidate( SID_PASTE_UNFORMATTED ); + rBindings.Invalidate( SID_CLIPBOARD_FORMAT_ITEMS ); +} + +/** + * Set Status (Enabled/Disabled) of Menu-SfxSlots + */ +void OutlineViewShell::GetMenuState( SfxItemSet &rSet ) +{ + ViewShell::GetMenuState(rSet); + + rSet.Put(SfxBoolItem(SID_SLIDE_SORTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_DRAWINGMODE, false)); + rSet.Put(SfxBoolItem(SID_SLIDE_MASTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_OUTLINE_MODE, true)); + rSet.Put(SfxBoolItem(SID_NOTES_MODE, false)); + rSet.Put(SfxBoolItem(SID_NOTES_MASTER_MODE, false)); + rSet.Put(SfxBoolItem(SID_HANDOUT_MASTER_MODE, false)); + + if (!mpZoomList->IsNextPossible()) + { + rSet.DisableItem(SID_ZOOM_NEXT); + } + if (!mpZoomList->IsPreviousPossible()) + { + rSet.DisableItem(SID_ZOOM_PREV); + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_IN ) || + SfxItemState::DEFAULT == rSet.GetItemState( SID_ZOOM_OUT ) ) + { + if( GetActiveWindow()->GetZoom() <= GetActiveWindow()->GetMinZoom() || GetDocSh()->IsUIActive() ) + rSet.DisableItem( SID_ZOOM_OUT ); + if( GetActiveWindow()->GetZoom() >= GetActiveWindow()->GetMaxZoom() || GetDocSh()->IsUIActive() ) + rSet.DisableItem( SID_ZOOM_IN ); + } + + ::Outliner& rOutl = pOlView->GetOutliner(); + + // allow 'Select All'? + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_SELECTALL ) ) + { + sal_Int32 nParaCount = rOutl.GetParagraphCount(); + bool bDisable = nParaCount == 0; + if (!bDisable && nParaCount == 1) + { + OUString aTest = rOutl.GetText(rOutl.GetParagraph(0)); + if (aTest.isEmpty()) + { + bDisable = true; + } + } + if (bDisable) + rSet.DisableItem(SID_SELECTALL); + } + + // set status of Ruler + rSet.Put( SfxBoolItem( SID_RULER, HasRuler() ) ); + + // Enable formatting? + rSet.Put( SfxBoolItem( SID_OUTLINE_FORMAT, !rOutl.IsFlatMode() ) ); + + if( rOutl.IsFlatMode() ) + rSet.DisableItem( SID_COLORVIEW ); + else + { + // Enable color view? + EEControlBits nCntrl = rOutl.GetControlWord(); + bool bNoColor = false; + if (nCntrl & EEControlBits::NOCOLORS) + bNoColor = true; + + rSet.Put( SfxBoolItem( SID_COLORVIEW, bNoColor ) ); + } + + // Buttons of toolbar + // first the selection dependent ones: COLLAPSE, EXPAND + bool bDisableCollapse = true; + bool bDisableExpand = true; + bool bUnique = true; + OutlinerView* pOutlinerView = pOlView->GetViewByWindow(GetActiveWindow()); + + std::vector<Paragraph*> aSelList; + pOutlinerView->CreateSelectionList(aSelList); + + if (!aSelList.empty()) + { + sal_Int16 nTmpDepth = rOutl.GetDepth( rOutl.GetAbsPos( aSelList.front() ) ); + bool bPage = ::Outliner::HasParaFlag( aSelList.front(), ParaFlag::ISPAGE ); + + for (const Paragraph* pPara : aSelList) + { + sal_Int16 nDepth = rOutl.GetDepth( rOutl.GetAbsPos( pPara ) ); + + if( nDepth != nTmpDepth || bPage != ::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE )) + bUnique = false; + + if (rOutl.HasChildren(pPara)) + { + if (!rOutl.IsExpanded(pPara)) + bDisableExpand = false; + else + bDisableCollapse = false; + } + } + } + + if (bDisableExpand) + rSet.DisableItem(SID_OUTLINE_EXPAND); + if (bDisableCollapse) + rSet.DisableItem(SID_OUTLINE_COLLAPSE); + + // does the selection provide a unique presentation layout? + // if not, the templates must not be edited + SfxItemSetFixed<SID_STATUS_LAYOUT, SID_STATUS_LAYOUT> aSet(*rSet.GetPool()); + GetStatusBarState(aSet); + OUString aTest = aSet.Get(SID_STATUS_LAYOUT).GetValue(); + if (aTest.isEmpty()) + { + bUnique = false; + } + + if (!bUnique) + rSet.DisableItem( SID_PRESENTATIONOBJECT ); + + // now the selection independent ones: COLLAPSE_ALL, EXPAND_ALL + bool bDisableCollapseAll = true; + bool bDisableExpandAll = true; + + // does the selection contain something collapsible/expandable? + if (!bDisableCollapse) + bDisableCollapseAll = false; + if (!bDisableExpand) + bDisableExpandAll = false; + + // otherwise look through all paragraphs + if (bDisableCollapseAll || bDisableExpandAll) + { + sal_Int32 nParaPos = 0; + Paragraph* pPara = rOutl.GetParagraph( nParaPos ); + while (pPara && (bDisableCollapseAll || bDisableExpandAll)) + { + if (!rOutl.IsExpanded(pPara) && rOutl.HasChildren(pPara)) + bDisableExpandAll = false; + + if (rOutl.IsExpanded(pPara) && rOutl.HasChildren(pPara)) + bDisableCollapseAll = false; + + pPara = rOutl.GetParagraph( ++nParaPos ); + } + } + + if (bDisableExpandAll) + rSet.DisableItem(SID_OUTLINE_EXPAND_ALL); + if (bDisableCollapseAll) + rSet.DisableItem(SID_OUTLINE_COLLAPSE_ALL); + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PASTE ) ) + { + if ( !mxClipEvtLstnr.is() ) + { + // create listener + mxClipEvtLstnr = new TransferableClipboardListener( LINK( this, OutlineViewShell, ClipboardChanged ) ); + mxClipEvtLstnr->AddListener( GetActiveWindow() ); + + // get initial state + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( GetActiveWindow() ) ); + bPastePossible = ( aDataHelper.GetFormatCount() != 0 && + ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) || + aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || + aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) || + aDataHelper.HasFormat( SotClipboardFormatId::HTML ) ) ); + } + + if( !bPastePossible ) + { + rSet.DisableItem( SID_PASTE ); + } + } + + if (!pOlView->GetViewByWindow(GetActiveWindow())->HasSelection() + || GetObjectShell()->isContentExtractionLocked()) + { + rSet.DisableItem(SID_CUT); + rSet.DisableItem(SID_COPY); + } + + if (pOlView->GetOutliner().IsModified()) + { + GetDoc()->SetChanged(); + } + + // the status has to be set here because of overriding + if( !GetDocSh()->IsModified() ) + { + rSet.DisableItem( SID_SAVEDOC ); + } + + if ( GetDocSh()->IsReadOnly() ) + { + rSet.DisableItem( SID_AUTOSPELL_CHECK ); + } + else + { + if (GetDoc()->GetOnlineSpell()) + { + rSet.Put(SfxBoolItem(SID_AUTOSPELL_CHECK, true)); + } + else + { + rSet.Put(SfxBoolItem(SID_AUTOSPELL_CHECK, false)); + } + } + + // field commands + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_MODIFY_FIELD ) ) + { + const SvxFieldItem* pFldItem = pOutlinerView->GetFieldAtSelection(); + + if( !( pFldItem && (nullptr != dynamic_cast< const SvxDateField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxAuthorField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtFileField *>( pFldItem->GetField() ) || + nullptr != dynamic_cast< const SvxExtTimeField *>( pFldItem->GetField() ) ) ) ) + { + rSet.DisableItem( SID_MODIFY_FIELD ); + } + } + + if (SfxItemState::DEFAULT == rSet.GetItemState(SID_EXPAND_PAGE)) + { + bool bDisable = true; + sal_uInt16 i = 0; + sal_uInt16 nCount = GetDoc()->GetSdPageCount(PageKind::Standard); + pOlView->SetSelectedPages(); + + while (i < nCount && bDisable) + { + SdPage* pPage = GetDoc()->GetSdPage(i, PageKind::Standard); + + if (pPage->IsSelected()) + { + SdrObject* pObj = pPage->GetPresObj(PresObjKind::Outline); + + if (pObj!=nullptr ) + { + if( !pObj->IsEmptyPresObj() ) + { + bDisable = false; + } + else + { + // check if the object is in edit, then if it's temporarily not empty + SdrTextObj* pTextObj = DynCastSdrTextObj( pObj ); + if( pTextObj ) + { + if( pTextObj->CanCreateEditOutlinerParaObject() ) + { + bDisable = false; + } + } + } + } + } + + i++; + } + + if (bDisable) + { + rSet.DisableItem(SID_EXPAND_PAGE); + } + } + + if (SfxItemState::DEFAULT == rSet.GetItemState(SID_SUMMARY_PAGE)) + { + bool bDisable = true; + sal_uInt16 i = 0; + sal_uInt16 nCount = GetDoc()->GetSdPageCount(PageKind::Standard); + pOlView->SetSelectedPages(); + + while (i < nCount && bDisable) + { + SdPage* pPage = GetDoc()->GetSdPage(i, PageKind::Standard); + + if (pPage->IsSelected()) + { + SdrObject* pObj = pPage->GetPresObj(PresObjKind::Title); + + if (pObj && !pObj->IsEmptyPresObj()) + { + bDisable = false; + } + } + + i++; + } + + if (bDisable) + { + rSet.DisableItem(SID_SUMMARY_PAGE); + } + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_THESAURUS ) ) + { + if ( !pOlView->IsTextEdit() ) + { + rSet.DisableItem( SID_THESAURUS ); + } + else + { + LanguageType eLang = GetDoc()->GetLanguage( EE_CHAR_LANGUAGE ); + Reference< XThesaurus > xThesaurus( LinguMgr::GetThesaurus() ); + + if (!xThesaurus.is() || eLang == LANGUAGE_NONE || !xThesaurus->hasLocale( LanguageTag::convertToLocale( eLang))) + rSet.DisableItem( SID_THESAURUS ); + } + } + + // is starting the presentation possible? + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_PRESENTATION ) ) + { + bool bDisable = true; + sal_uInt16 nCount = GetDoc()->GetSdPageCount( PageKind::Standard ); + + for( sal_uInt16 i = 0; i < nCount && bDisable; i++ ) + { + SdPage* pPage = GetDoc()->GetSdPage(i, PageKind::Standard); + + if( !pPage->IsExcluded() ) + bDisable = false; + } + if( bDisable || GetDocSh()->IsPreview()) + { + rSet.DisableItem( SID_PRESENTATION ); + } + } + + FuBullet::GetSlotState( rSet, this, GetViewFrame() ); + +} + +/** + * gets invoked when ScrollBar is used + */ +void OutlineViewShell::VirtHScrollHdl(ScrollAdaptor* pHScroll) +{ + ::tools::Long nThumb = pHScroll->GetThumbPos(); + ::tools::Long nRange = pHScroll->GetRange().Len(); + double fX = static_cast<double>(nThumb) / nRange; + + Window* pWin = mpContentWindow.get(); + OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWin); + ::tools::Long nViewWidth = pWin->PixelToLogic( + pWin->GetSizePixel()).Width(); + ::tools::Long nTextWidth = pOlView->GetPaperWidth(); + nViewWidth = std::max(nViewWidth, nTextWidth); + ::tools::Long nCurrentPos = pOutlinerView->GetVisArea().Left(); + ::tools::Long nTargetPos = static_cast<::tools::Long>(fX * nViewWidth); + ::tools::Long nDelta = nTargetPos - nCurrentPos; + + pOutlinerView->HideCursor(); + pOutlinerView->Scroll(-nDelta, 0); + pOutlinerView->ShowCursor(false); +} + +void OutlineViewShell::VirtVScrollHdl(ScrollAdaptor* pVScroll) +{ + ::tools::Long nThumb = pVScroll->GetThumbPos(); + ::tools::Long nRange = pVScroll->GetRange().Len(); + double fY = static_cast<double>(nThumb) / nRange; + + Window* pWin = mpContentWindow.get(); + OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWin); + ::tools::Long nViewHeight = pWin->PixelToLogic( + pWin->GetSizePixel()).Height(); + ::tools::Long nTextHeight = pOlView->GetOutliner().GetTextHeight(); + nViewHeight += nTextHeight; + ::tools::Long nCurrentPos = pOutlinerView->GetVisArea().Top(); + ::tools::Long nTargetPos = static_cast<::tools::Long>(fY * nViewHeight); + ::tools::Long nDelta = nTargetPos - nCurrentPos; + + pOutlinerView->HideCursor(); + pOutlinerView->Scroll(0, -nDelta); + pOutlinerView->ShowCursor(false); +} + +/** + * PrepareClose, gets called when the Shell shall be destroyed. + * Forwards the invocation to the View + */ +bool OutlineViewShell::PrepareClose( bool bUI ) +{ + if( !ViewShell::PrepareClose(bUI) ) + return false; + + if (pOlView) + pOlView->PrepareClose(); + return true; +} + +/** + * Zoom with zoom factor. Inform OutlinerView + */ +void OutlineViewShell::SetZoom(::tools::Long nZoom) +{ + ViewShell::SetZoom(nZoom); + + ::sd::Window* pWindow = mpContentWindow.get(); + if (pWindow) + { + // change OutputArea of OutlinerView + OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWindow); + ::tools::Rectangle aWin(Point(0,0), pWindow->GetOutputSizePixel()); + aWin = pWindow->PixelToLogic(aWin); + pOutlinerView->SetOutputArea(aWin); + } + + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER ); +} + +/** + * Zoom with zoom rectangle. Inform OutlinerView + */ +void OutlineViewShell::SetZoomRect(const ::tools::Rectangle& rZoomRect) +{ + ViewShell::SetZoomRect(rZoomRect); + + ::sd::Window* pWindow = mpContentWindow.get(); + if (pWindow) + { + // change OutputArea of OutlinerView + OutlinerView* pOutlinerView = pOlView->GetViewByWindow(pWindow); + ::tools::Rectangle aWin(Point(0,0), pWindow->GetOutputSizePixel()); + aWin = pWindow->PixelToLogic(aWin); + pOutlinerView->SetOutputArea(aWin); + } + + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER ); +} + +/** + * Before saving: Update Model of the Drawing Engine, then forward the + * invocation to the ObjectShell. + */ +void OutlineViewShell::Execute(SfxRequest& rReq) +{ + bool bForwardCall = true; + + switch(rReq.GetSlot()) + { + case SID_SAVEDOC: + case SID_SAVEASDOC: + PrepareClose(); + break; + + case SID_SEARCH_ITEM: + // Forward this request to the common (old) code of the + // document shell. + GetDocSh()->Execute (rReq); + bForwardCall = false; + break; + + case SID_SPELL_DIALOG: + { + SfxViewFrame* pViewFrame = GetViewFrame(); + if (rReq.GetArgs() != nullptr) + pViewFrame->SetChildWindow (SID_SPELL_DIALOG, + static_cast<const SfxBoolItem&>(rReq.GetArgs()-> + Get(SID_SPELL_DIALOG)).GetValue()); + else + pViewFrame->ToggleChildWindow(SID_SPELL_DIALOG); + + pViewFrame->GetBindings().Invalidate(SID_SPELL_DIALOG); + rReq.Done (); + + bForwardCall = false; + } + break; + + default: + SAL_WARN("sd", "OutlineViewShell::Execute(): can not handle slot " << rReq.GetSlot()); + break; + + } + + if (bForwardCall) + static_cast<DrawDocShell*>(GetViewFrame()->GetObjectShell())->ExecuteSlot( rReq ); +} + +/** + * Read FrameViews data and set actual views data + */ +void OutlineViewShell::ReadFrameViewData(FrameView* pView) +{ + ::Outliner& rOutl = pOlView->GetOutliner(); + + rOutl.SetFlatMode( pView->IsNoAttribs() ); + + EEControlBits nCntrl = rOutl.GetControlWord(); + + if ( pView->IsNoColors() ) + rOutl.SetControlWord(nCntrl | EEControlBits::NOCOLORS); + else + rOutl.SetControlWord(nCntrl & ~EEControlBits::NOCOLORS); + + sal_uInt16 nPage = mpFrameView->GetSelectedPage(); + pLastPage = GetDoc()->GetSdPage( nPage, PageKind::Standard ); + pOlView->SetActualPage(pLastPage); +} + +/** + * Write actual views data to FrameView + */ +void OutlineViewShell::WriteFrameViewData() +{ + ::Outliner& rOutl = pOlView->GetOutliner(); + + EEControlBits nCntrl = rOutl.GetControlWord(); + bool bNoColor = false; + if (nCntrl & EEControlBits::NOCOLORS) + bNoColor = true; + mpFrameView->SetNoColors(bNoColor); + mpFrameView->SetNoAttribs( rOutl.IsFlatMode() ); + SdPage* pActualPage = pOlView->GetActualPage(); + DBG_ASSERT(pActualPage, "No current page"); + if( pActualPage ) + mpFrameView->SetSelectedPage((pActualPage->GetPageNum() - 1) / 2); +} + +/** + * Handle SfxRequests for the StatusBar + */ +void OutlineViewShell::ExecStatusBar(SfxRequest&) +{ +} + +void OutlineViewShell::GetStatusBarState(SfxItemSet& rSet) +{ + // Zoom-Item + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_ZOOM ) ) + { + sal_uInt16 nZoom = static_cast<sal_uInt16>(GetActiveWindow()->GetZoom()); + + std::unique_ptr<SvxZoomItem> pZoomItem(new SvxZoomItem( SvxZoomType::PERCENT, nZoom )); + + // limit area + SvxZoomEnableFlags nZoomValues = SvxZoomEnableFlags::ALL; + nZoomValues &= ~SvxZoomEnableFlags::OPTIMAL; + nZoomValues &= ~SvxZoomEnableFlags::WHOLEPAGE; + nZoomValues &= ~SvxZoomEnableFlags::PAGEWIDTH; + + pZoomItem->SetValueSet( nZoomValues ); + rSet.Put( std::move(pZoomItem) ); + } + + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_ATTR_ZOOMSLIDER ) ) + { + if (GetDocSh()->IsUIActive() || !GetActiveWindow() ) + { + rSet.DisableItem( SID_ATTR_ZOOMSLIDER ); + } + else + { + sd::Window * pActiveWindow = GetActiveWindow(); + SvxZoomSliderItem aZoomItem( static_cast<sal_uInt16>(pActiveWindow->GetZoom()), static_cast<sal_uInt16>(pActiveWindow->GetMinZoom()), static_cast<sal_uInt16>(pActiveWindow->GetMaxZoom()) ) ; + aZoomItem.AddSnappingPoint(100); + rSet.Put( aZoomItem ); + } + } + + // page view and layout + + sal_uInt16 nPageCount = GetDoc()->GetSdPageCount( PageKind::Standard ); + OUString aPageStr, aLayoutStr; + + ::sd::Window* pWin = GetActiveWindow(); + OutlinerView* pActiveView = pOlView->GetViewByWindow( pWin ); + + std::vector<Paragraph*> aSelList; + pActiveView->CreateSelectionList(aSelList); + + Paragraph *pFirstPara = nullptr; + Paragraph *pLastPara = nullptr; + + if (!aSelList.empty()) + { + pFirstPara = *(aSelList.begin()); + pLastPara = *(aSelList.rbegin()); + } + + if( !::Outliner::HasParaFlag(pFirstPara,ParaFlag::ISPAGE) ) + pFirstPara = pOlView->GetPrevTitle( pFirstPara ); + + if( !::Outliner::HasParaFlag(pLastPara, ParaFlag::ISPAGE) ) + pLastPara = pOlView->GetPrevTitle( pLastPara ); + + // only one page selected? + if( pFirstPara == pLastPara ) + { + // how many pages are we before the selected page? + sal_uLong nPos = 0; + while( pFirstPara ) + { + pFirstPara = pOlView->GetPrevTitle( pFirstPara ); + if( pFirstPara ) + nPos++; + } + + if( nPos >= GetDoc()->GetSdPageCount( PageKind::Standard ) ) + nPos = 0; + + SdrPage* pPage = GetDoc()->GetSdPage( static_cast<sal_uInt16>(nPos), PageKind::Standard ); + + if (GetDoc()->GetDocumentType() == DocumentType::Draw) + aPageStr = SdResId(STR_SD_PAGE_COUNT_DRAW); + else + aPageStr = SdResId(STR_SD_PAGE_COUNT); + + aPageStr = aPageStr.replaceFirst("%1", OUString::number(static_cast<sal_Int32>(nPos + 1))); + aPageStr = aPageStr.replaceFirst("%2", OUString::number(nPageCount)); + + aLayoutStr = pPage->GetLayoutName(); + sal_Int32 nIndex = aLayoutStr.indexOf(SD_LT_SEPARATOR); + if (nIndex != -1) + aLayoutStr = aLayoutStr.copy(0, nIndex); + //Now, CurrentPage property change is already sent for DrawView and OutlineView, so it is not necessary to send again here + if(m_StrOldPageName!=aPageStr) + { + GetViewShellBase().GetDrawController()->fireSwitchCurrentPage(nPos); + m_StrOldPageName = aPageStr; + } + } + rSet.Put( SfxStringItem( SID_STATUS_PAGE, aPageStr ) ); + rSet.Put( SfxStringItem( SID_STATUS_LAYOUT, aLayoutStr ) ); +} + +void OutlineViewShell::Command( const CommandEvent& rCEvt, ::sd::Window* pWin ) +{ + if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) + { + GetActiveWindow()->ReleaseMouse(); + + OutlinerView* pOLV = pOlView->GetViewByWindow(GetActiveWindow()); + Point aPos(rCEvt.GetMousePosPixel()); + + if (pOLV && pOLV->IsWrongSpelledWordAtPos(aPos)) + { + // Popup for Online-Spelling now handled by DrawDocShell + Link<SpellCallbackInfo&,void> aLink = LINK(GetDocSh(), DrawDocShell, OnlineSpellCallback); + + pOLV->ExecuteSpellPopup(aPos, aLink); + pOLV->GetEditView().Invalidate(); + } + else + { + GetViewFrame()->GetDispatcher()->ExecutePopup("outline"); + } + } + else + { + ViewShell::Command( rCEvt, pWin ); + + // if necessary communicate the new context to the Preview + Invalidate( SID_PREVIEW_STATE ); + + } +} + +bool OutlineViewShell::KeyInput(const KeyEvent& rKEvt, ::sd::Window* pWin) +{ + bool bReturn = false; + OutlineViewPageChangesGuard aGuard(pOlView.get()); + + if (pWin == nullptr && HasCurrentFunction()) + { + bReturn = GetCurrentFunction()->KeyInput(rKEvt); + } + + // no, forward to base class + else + { + bReturn = ViewShell::KeyInput(rKEvt, pWin); + } + + Invalidate(SID_STYLE_EDIT); + Invalidate(SID_STYLE_NEW); + Invalidate(SID_STYLE_DELETE); + Invalidate(SID_STYLE_HIDE); + Invalidate(SID_STYLE_SHOW); + Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE); + Invalidate(SID_STYLE_NEW_BY_EXAMPLE); + Invalidate(SID_STYLE_WATERCAN); + Invalidate(SID_STYLE_FAMILY5); + + // check and distinguish cursor movements- or input-keys + vcl::KeyCode aKeyGroup( rKEvt.GetKeyCode().GetGroup() ); + if( (aKeyGroup != KEYGROUP_CURSOR && aKeyGroup != KEYGROUP_FKEYS) || + (GetActualPage() != pLastPage) ) + { + Invalidate( SID_PREVIEW_STATE ); + } + + return bReturn; +} + +/** + * Status of Attribute-Items + */ +void OutlineViewShell::GetAttrState( SfxItemSet& rSet ) +{ + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + SfxAllItemSet aAllSet( *rSet.GetPool() ); + + while ( nWhich ) + { + sal_uInt16 nSlotId = SfxItemPool::IsWhich(nWhich) + ? GetPool().GetSlotId(nWhich) + : nWhich; + + switch ( nSlotId ) + { + case SID_STYLE_FAMILY2: + case SID_STYLE_FAMILY3: + { + rSet.DisableItem( nWhich ); + } + break; + + case SID_STYLE_FAMILY5: + { + SfxStyleSheet* pStyleSheet = pOlView->GetViewByWindow(GetActiveWindow())->GetStyleSheet(); + + if( pStyleSheet ) + { + pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet(); + + if (pStyleSheet) + { + SfxTemplateItem aItem( nWhich, pStyleSheet->GetName() ); + aAllSet.Put( aItem, aItem.Which() ); + } + } + + if( !pStyleSheet ) + { + SfxTemplateItem aItem( nWhich, OUString() ); + aAllSet.Put( aItem, aItem.Which() ); + // rSet.DisableItem( nWhich ); + } + } + break; + + case SID_STYLE_EDIT: + { + std::unique_ptr<SfxUInt16Item> pFamilyItem; + GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem); + if (pFamilyItem && static_cast<SfxStyleFamily>(pFamilyItem->GetValue()) == SfxStyleFamily::Pseudo) + { + SfxItemSetFixed<SID_STATUS_LAYOUT, SID_STATUS_LAYOUT> aSet(*rSet.GetPool()); + GetStatusBarState(aSet); + OUString aRealStyle = aSet.Get(SID_STATUS_LAYOUT).GetValue(); + if (aRealStyle.isEmpty()) + { + // no unique layout name found + rSet.DisableItem(nWhich); + } + } + } + break; + + case SID_STYLE_UPDATE_BY_EXAMPLE: + { + ::sd::Window* pActWin = GetActiveWindow(); + OutlinerView* pOV = pOlView->GetViewByWindow(pActWin); + ESelection aESel(pOV->GetSelection()); + + if (aESel.nStartPara != aESel.nEndPara || + aESel.nStartPos != aESel.nEndPos) + // spanned selection, i.e. StyleSheet and/or + // attribution not necessarily unique + rSet.DisableItem(nWhich); + } + break; + + case SID_STYLE_NEW: + case SID_STYLE_DELETE: + case SID_STYLE_HIDE: + case SID_STYLE_SHOW: + case SID_STYLE_NEW_BY_EXAMPLE: + case SID_STYLE_WATERCAN: + { + rSet.DisableItem(nWhich); + } + break; + } + + nWhich = aIter.NextWhich(); + } + + rSet.Put( aAllSet, false ); +} + +void OutlineViewShell::MouseButtonUp(const MouseEvent& rMEvt, ::sd::Window* pWin) +{ + // first the base classes + ViewShell::MouseButtonUp(rMEvt, pWin); + + Invalidate(SID_STYLE_EDIT); + Invalidate(SID_STYLE_NEW); + Invalidate(SID_STYLE_DELETE); + Invalidate(SID_STYLE_HIDE); + Invalidate(SID_STYLE_SHOW); + Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE); + Invalidate(SID_STYLE_NEW_BY_EXAMPLE); + Invalidate(SID_STYLE_WATERCAN); + Invalidate(SID_STYLE_FAMILY5); + + // if necessary communicate the new context to the Preview + if( GetActualPage() != pLastPage ) + Invalidate( SID_PREVIEW_STATE ); +} + +SdPage* OutlineViewShell::getCurrentPage() const +{ + // since there are no master pages in outline view, we can + // for now use the GetActualPage method + return const_cast<OutlineViewShell*>(this)->GetActualPage(); +} + +/** + * Returns the first selected page. + * If nothing is selected, the first page is returned. + */ +SdPage* OutlineViewShell::GetActualPage() +{ + return pOlView->GetActualPage(); +} + +void OutlineViewShell::UpdatePreview( SdPage* pPage ) +{ + const bool bNewPage = pPage != pLastPage; + pLastPage = pPage; + if (bNewPage) + { + OutlineViewPageChangesGuard aGuard(pOlView.get()); + SetCurrentPage(pPage); + } +} + +void OutlineViewShell::UpdateTitleObject( SdPage* pPage, Paragraph const * pPara ) +{ + DBG_ASSERT( pPage, "sd::OutlineViewShell::UpdateTitleObject(), pPage == 0?" ); + DBG_ASSERT( pPara, "sd::OutlineViewShell::UpdateTitleObject(), pPara == 0?" ); + + if( !pPage || !pPara ) + return; + + ::Outliner& rOutliner = pOlView->GetOutliner(); + SdrTextObj* pTO = OutlineView::GetTitleTextObject( pPage ); + + OUString aTest = rOutliner.GetText(pPara); + bool bText = !aTest.isEmpty(); + + if( bText ) + { + bool bNewObject = false; + // create a title object if we don't have one but have text + if( !pTO ) + { + DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateTitleObject(), no undo for model change!?" ); + pTO = OutlineView::CreateTitleTextObject(pPage); + bNewObject = true; + } + + // if we have a title object and a text, set the text + std::optional<OutlinerParaObject> pOPO; + if (pTO) + pOPO = rOutliner.CreateParaObject(rOutliner.GetAbsPos(pPara), 1); + if (pOPO) + { + pOPO->SetOutlinerMode( OutlinerMode::TitleObject ); + assert(pTO); + pOPO->SetVertical( pTO->IsVerticalWriting() ); + if( pTO->GetOutlinerParaObject() && (pOPO->GetTextObject() == pTO->GetOutlinerParaObject()->GetTextObject()) ) + { + // do nothing, same text already set + } + else + { + DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateTitleObject(), no undo for model change!?" ); + if( !bNewObject && pOlView->isRecordingUndo() ) + pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoObjectSetText(*pTO,0)); + + pTO->SetOutlinerParaObject( std::move(pOPO) ); + pTO->SetEmptyPresObj( false ); + pTO->ActionChanged(); + } + } + } + else if( pTO ) + { + // no text but object available? + // outline object available, but we have no text + if(pPage->IsPresObj(pTO)) + { + // if it is not already empty + if( !pTO->IsEmptyPresObj() ) + { + DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateTitleObject(), no undo for model change!?" ); + + // make it empty + if( pOlView->isRecordingUndo() ) + pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoObjectSetText(*pTO,0)); + pPage->RestoreDefaultText( pTO ); + pTO->SetEmptyPresObj(true); + pTO->ActionChanged(); + } + } + else + { + DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateTitleObject(), no undo for model change!?" ); + // outline object is not part of the layout, delete it + if( pOlView->isRecordingUndo() ) + pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoRemoveObject(*pTO)); + pPage->RemoveObject(pTO->GetOrdNum()); + } + } +} + +void OutlineViewShell::UpdateOutlineObject( SdPage* pPage, Paragraph* pPara ) +{ + DBG_ASSERT( pPage, "sd::OutlineViewShell::UpdateOutlineObject(), pPage == 0?" ); + DBG_ASSERT( pPara, "sd::OutlineViewShell::UpdateOutlineObject(), pPara == 0?" ); + + if( !pPage || !pPara ) + return; + + ::Outliner& rOutliner = pOlView->GetOutliner(); + std::optional<OutlinerParaObject> pOPO; + SdrTextObj* pTO = nullptr; + + OutlinerMode eOutlinerMode = OutlinerMode::TitleObject; + pTO = static_cast<SdrTextObj*>(pPage->GetPresObj( PresObjKind::Text )); + if( !pTO ) + { + eOutlinerMode = OutlinerMode::OutlineObject; + pTO = OutlineView::GetOutlineTextObject( pPage ); + } + + // how many paragraphs in the outline? + sal_Int32 nTitlePara = rOutliner.GetAbsPos( pPara ); + sal_Int32 nPara = nTitlePara + 1; + sal_Int32 nParasInLayout = 0; + pPara = rOutliner.GetParagraph( nPara ); + while( pPara && !::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) ) + { + nParasInLayout++; + pPara = rOutliner.GetParagraph( ++nPara ); + } + if( nParasInLayout ) + { + // create an OutlinerParaObject + pOPO = rOutliner.CreateParaObject( nTitlePara + 1, nParasInLayout ); + } + + if( pOPO ) + { + DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateOutlineObject(), no undo for model change!?" ); + bool bNewObject = false; + + // do we need an outline text object? + if( !pTO ) + { + pTO = OutlineView::CreateOutlineTextObject( pPage ); + bNewObject = true; + } + + // page object, outline text in Outliner: + // apply text + if( pTO ) + { + pOPO->SetVertical( pTO->IsVerticalWriting() ); + pOPO->SetOutlinerMode( eOutlinerMode ); + if( pTO->GetOutlinerParaObject() && (pOPO->GetTextObject() == pTO->GetOutlinerParaObject()->GetTextObject()) ) + { + // do nothing, same text already set + } + else + { + if( !bNewObject && pOlView->isRecordingUndo() ) + pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoObjectSetText(*pTO,0)); + + pTO->SetOutlinerParaObject( std::move(pOPO) ); + pTO->SetEmptyPresObj( false ); + pTO->ActionChanged(); + } + } + } + else if( pTO ) + { + // page object but no outline text: + // if the object is in the outline of the page -> default text + + // otherwise delete object + if( pPage->IsPresObj(pTO) ) + { + if( !pTO->IsEmptyPresObj() ) + { + DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateOutlineObject(), no undo for model change!?" ); + + // delete old OutlinerParaObject, too + if( pOlView->isRecordingUndo() ) + pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoObjectSetText(*pTO,0)); + pPage->RestoreDefaultText( pTO ); + pTO->SetEmptyPresObj(true); + pTO->ActionChanged(); + } + } + else + { + DBG_ASSERT( pOlView->isRecordingUndo(), "sd::OutlineViewShell::UpdateOutlineObject(), no undo for model change!?" ); + if( pOlView->isRecordingUndo() ) + pOlView->AddUndo(GetDoc()->GetSdrUndoFactory().CreateUndoRemoveObject(*pTO)); + pPage->RemoveObject(pTO->GetOrdNum()); + } + } +} + +/** + * Fill Outliner from Stream + */ +ErrCode OutlineViewShell::ReadRtf(SvStream& rInput) +{ + ErrCode bRet = ERRCODE_NONE; + + ::Outliner& rOutl = pOlView->GetOutliner(); + + OutlineViewPageChangesGuard aGuard( pOlView.get() ); + OutlineViewModelChangeGuard aGuard2( *pOlView ); + + bRet = rOutl.Read( rInput, OUString(), EETextFormat::Rtf, GetDocSh()->GetHeaderAttributes() ); + + SdPage* pPage = GetDoc()->GetSdPage( GetDoc()->GetSdPageCount(PageKind::Standard) - 1, PageKind::Standard ); + SfxStyleSheet* pTitleSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Title ); + SfxStyleSheet* pOutlSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Outline ); + + sal_Int32 nParaCount = rOutl.GetParagraphCount(); + if ( nParaCount > 0 ) + { + for ( sal_Int32 nPara = 0; nPara < nParaCount; nPara++ ) + { + pOlView->UpdateParagraph( nPara ); + + sal_Int16 nDepth = rOutl.GetDepth( nPara ); + + if( (nDepth == 0) || !nPara ) + { + Paragraph* pPara = rOutl.GetParagraph( nPara ); + rOutl.SetDepth(pPara, -1); + rOutl.SetParaFlag(pPara, ParaFlag::ISPAGE); + + rOutl.SetStyleSheet( nPara, pTitleSheet ); + + if( nPara ) // first slide already exists + pOlView->InsertSlideForParagraph( pPara ); + } + else + { + rOutl.SetDepth( rOutl.GetParagraph( nPara ), nDepth - 1 ); + OUString aStyleSheetName = pOutlSheet->GetName(); + if (!aStyleSheetName.isEmpty()) + aStyleSheetName = aStyleSheetName.copy(0, aStyleSheetName.getLength() - 1); + aStyleSheetName += OUString::number( nDepth ); + SfxStyleSheetBasePool* pStylePool = GetDoc()->GetStyleSheetPool(); + SfxStyleSheet* pStyle = static_cast<SfxStyleSheet*>( pStylePool->Find( aStyleSheetName, pOutlSheet->GetFamily() ) ); + DBG_ASSERT( pStyle, "AutoStyleSheetName - Style not found!" ); + if ( pStyle ) + rOutl.SetStyleSheet( nPara, pStyle ); + } + } + } + + rOutl.GetUndoManager().Clear(); + + return bRet; +} + +void OutlineViewShell::WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& rSequence ) +{ + WriteFrameViewData(); + + ViewShell::WriteUserDataSequence( rSequence ); +} + +void OutlineViewShell::ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& rSequence ) +{ + WriteFrameViewData(); + + ViewShell::ReadUserDataSequence( rSequence ); + + ReadFrameViewData( mpFrameView ); +} + +void OutlineViewShell::VisAreaChanged(const ::tools::Rectangle& rRect) +{ + ViewShell::VisAreaChanged( rRect ); + + GetViewShellBase().GetDrawController()->FireVisAreaChanged(rRect); +} + +/** If there is a valid controller then create a new instance of + <type>AccessibleDrawDocumentView</type>. Otherwise return an empty + reference. +*/ +css::uno::Reference<css::accessibility::XAccessible> + OutlineViewShell::CreateAccessibleDocumentView (::sd::Window* pWindow) +{ + OSL_ASSERT (GetViewShell()!=nullptr); + if (GetViewShell()->GetController() != nullptr) + { + rtl::Reference<::accessibility::AccessibleOutlineView> pDocumentView = + new ::accessibility::AccessibleOutlineView ( + pWindow, + this, + GetViewShell()->GetController(), + pWindow->GetAccessibleParentWindow()->GetAccessible()); + pDocumentView->Init(); + return pDocumentView; + } + + SAL_WARN("sd", "OutlineViewShell::CreateAccessibleDocumentView: no controller"); + return css::uno::Reference< css::accessibility::XAccessible >(); +} + +void OutlineViewShell::GetState (SfxItemSet& rSet) +{ + // Iterate over all requested items in the set. + SfxWhichIter aIter( rSet ); + sal_uInt16 nWhich = aIter.FirstWhich(); + while (nWhich) + { + switch (nWhich) + { + case SID_SEARCH_ITEM: + case SID_SEARCH_OPTIONS: + // Call common (old) implementation in the document shell. + GetDocSh()->GetState (rSet); + break; + default: + SAL_WARN("sd", "OutlineViewShell::GetState(): can not handle which id " << nWhich); + break; + } + nWhich = aIter.NextWhich(); + } +} + +void OutlineViewShell::SetCurrentPage (SdPage* pPage) +{ + // Adapt the selection of the model. + for (sal_uInt16 i=0; i<GetDoc()->GetSdPageCount(PageKind::Standard); i++) + GetDoc()->SetSelected( + GetDoc()->GetSdPage(i, PageKind::Standard), + false); + GetDoc()->SetSelected (pPage, true); + + DrawController& rController(*GetViewShellBase().GetDrawController()); + rController.FireSelectionChangeListener(); + rController.FireSwitchCurrentPage (pPage); + + pOlView->SetActualPage(pPage); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/outlview.cxx b/sd/source/ui/view/outlview.cxx new file mode 100644 index 0000000000..d424f0117c --- /dev/null +++ b/sd/source/ui/view/outlview.cxx @@ -0,0 +1,1713 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <OutlineView.hxx> +#include <sfx2/progress.hxx> +#include <vcl/commandinfoprovider.hxx> +#include <vcl/svapp.hxx> +#include <svx/svxids.hrc> +#include <editeng/outliner.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/editstat.hxx> +#include <editeng/lrspitem.hxx> +#include <svx/svdotext.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/style.hxx> +#include <svx/svdundo.hxx> +#include <editeng/numitem.hxx> +#include <editeng/outlobj.hxx> +#include <editeng/editeng.hxx> +#include <xmloff/autolayout.hxx> +#include <tools/debug.hxx> + +#include <editeng/editobj.hxx> +#include <editeng/editund2.hxx> + +#include <editeng/editview.hxx> + +#include <com/sun/star/frame/XFrame.hpp> + +#include <DrawDocShell.hxx> +#include <drawdoc.hxx> +#include <Window.hxx> +#include <sdpage.hxx> +#include <pres.hxx> +#include <OutlineViewShell.hxx> +#include <app.hrc> +#include <strings.hrc> +#include <sdmod.hxx> +#include <sdresid.hxx> +#include <Outliner.hxx> +#include <EventMultiplexer.hxx> +#include <ViewShellBase.hxx> +#include <ViewShellManager.hxx> +#include <undo/undomanager.hxx> +#include <stlsheet.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; + +namespace sd { + +// a progress bar gets displayed when more than +// PROCESS_WITH_PROGRESS_THRESHOLD pages are concerned +#define PROCESS_WITH_PROGRESS_THRESHOLD 5 + +OutlineView::OutlineView( DrawDocShell& rDocSh, vcl::Window* pWindow, OutlineViewShell& rOutlineViewShell) +: ::sd::View(*rDocSh.GetDoc(), pWindow->GetOutDev(), &rOutlineViewShell) +, mrOutlineViewShell(rOutlineViewShell) +, mrOutliner(*mrDoc.GetOutliner()) +, mnPagesToProcess(0) +, mnPagesProcessed(0) +, mbFirstPaint(true) +, maDocColor( COL_WHITE ) +, maLRSpaceItem(2000, 0, 0, EE_PARA_OUTLLRSPACE) +{ + bool bInitOutliner = false; + + if (mrOutliner.GetViewCount() == 0) + { + // initialize Outliner: set Reference Device + bInitOutliner = true; + mrOutliner.Init( OutlinerMode::OutlineView ); + mrOutliner.SetRefDevice( SD_MOD()->GetVirtualRefDevice() ); + //viewsize without the width of the image and number in front + mnPaperWidth = (mrOutlineViewShell.GetActiveWindow()->GetViewSize().Width() - 4000); + mrOutliner.SetPaperSize(Size(mnPaperWidth, 400000000)); + } + else + { + // width: DIN A4, two margins at 1 cm each + mnPaperWidth = 19000; + } + + mpOutlinerViews[0].reset( new OutlinerView(&mrOutliner, pWindow) ); + mpOutlinerViews[0]->SetOutputArea(::tools::Rectangle()); + mrOutliner.SetUpdateLayout(false); + mrOutliner.InsertView(mpOutlinerViews[0].get(), EE_APPEND); + + onUpdateStyleSettings( true ); + + if (bInitOutliner) + { + // fill Outliner with contents + FillOutliner(); + } + + Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,OutlineView,EventMultiplexerListener) ); + mrOutlineViewShell.GetViewShellBase().GetEventMultiplexer()->AddEventListener(aLink); + + Reference<XFrame> xFrame = mrOutlineViewShell.GetViewShellBase().GetFrame()->GetFrame().GetFrameInterface(); + maSlideImage = vcl::CommandInfoProvider::GetImageForCommand(".uno:ShowSlide", xFrame, vcl::ImageType::Size26); + + // Tell undo manager of the document about the undo manager of the + // outliner, so that the former can synchronize with the later. + sd::UndoManager* pDocUndoMgr = dynamic_cast<sd::UndoManager*>(mpDocSh->GetUndoManager()); + if (pDocUndoMgr != nullptr) + pDocUndoMgr->SetLinkedUndoManager(&mrOutliner.GetUndoManager()); +} + +/** + * Destructor, restore Links, clear Outliner + */ +OutlineView::~OutlineView() +{ + DBG_ASSERT(maDragAndDropModelGuard == nullptr, + "sd::OutlineView::~OutlineView(), prior drag operation not finished correctly!"); + + Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,OutlineView,EventMultiplexerListener) ); + mrOutlineViewShell.GetViewShellBase().GetEventMultiplexer()->RemoveEventListener( aLink ); + DisconnectFromApplication(); + + mpProgress.reset(); + + // unregister OutlinerViews and destroy them + for (auto & rpView : mpOutlinerViews) + { + if (rpView) + { + mrOutliner.RemoveView( rpView.get() ); + rpView.reset(); + } + } + + if (mrOutliner.GetViewCount() == 0) + { + // uninitialize Outliner: enable color display + ResetLinks(); + EEControlBits nCntrl = mrOutliner.GetControlWord(); + mrOutliner.SetUpdateLayout(false); // otherwise there will be drawn on SetControlWord + mrOutliner.SetControlWord(nCntrl & ~EEControlBits::NOCOLORS); + mrOutliner.ForceAutoColor( SvtAccessibilityOptions::GetIsAutomaticFontColor() ); + mrOutliner.Clear(); + } +} + +void OutlineView::ConnectToApplication() +{ + // When the mode is switched to outline the main view shell grabs focus. + // This is done for getting cut/copy/paste commands on slides in the left + // pane (slide sorter view shell) to work properly. + SfxShell* pTopViewShell = mrOutlineViewShell.GetViewShellBase().GetViewShellManager()->GetTopViewShell(); + if (pTopViewShell && pTopViewShell == &mrOutlineViewShell) + { + mrOutlineViewShell.GetActiveWindow()->GrabFocus(); + } + + Application::AddEventListener(LINK(this, OutlineView, AppEventListenerHdl)); +} + +void OutlineView::DisconnectFromApplication() +{ + Application::RemoveEventListener(LINK(this, OutlineView, AppEventListenerHdl)); +} + +void OutlineView::Paint(const ::tools::Rectangle& rRect, ::sd::Window const * pWin) +{ + OutlinerView* pOlView = GetViewByWindow(pWin); + + if (pOlView) + { + pOlView->HideCursor(); + pOlView->Paint(rRect); + + pOlView->ShowCursor(mbFirstPaint); + + mbFirstPaint = false; + } +} + +void OutlineView::AddDeviceToPaintView(OutputDevice& rDev, vcl::Window* pWindow) +{ + bool bAdded = false; + bool bValidArea = false; + ::tools::Rectangle aOutputArea; + const Color aWhiteColor( COL_WHITE ); + sal_uInt16 nView = 0; + + while (nView < MAX_OUTLINERVIEWS && !bAdded) + { + if (mpOutlinerViews[nView] == nullptr) + { + mpOutlinerViews[nView].reset( new OutlinerView(&mrOutliner, dynamic_cast< ::sd::Window* >(rDev.GetOwnerWindow())) ); + mpOutlinerViews[nView]->SetBackgroundColor( aWhiteColor ); + mrOutliner.InsertView(mpOutlinerViews[nView].get(), EE_APPEND); + bAdded = true; + + if (bValidArea) + { + mpOutlinerViews[nView]->SetOutputArea(aOutputArea); + } + } + else if (!bValidArea) + { + aOutputArea = mpOutlinerViews[nView]->GetOutputArea(); + bValidArea = true; + } + + nView++; + } + + // white background in Outliner + rDev.SetBackground( Wallpaper( aWhiteColor ) ); + + ::sd::View::AddDeviceToPaintView(rDev, pWindow); +} + +void OutlineView::DeleteDeviceFromPaintView(OutputDevice& rDev) +{ + bool bRemoved = false; + sal_uInt16 nView = 0; + vcl::Window* pWindow; + + while (nView < MAX_OUTLINERVIEWS && !bRemoved) + { + if (mpOutlinerViews[nView] != nullptr) + { + pWindow = mpOutlinerViews[nView]->GetWindow(); + + if (pWindow->GetOutDev() == &rDev) + { + mrOutliner.RemoveView( mpOutlinerViews[nView].get() ); + mpOutlinerViews[nView].reset(); + bRemoved = true; + } + } + + nView++; + } + + ::sd::View::DeleteDeviceFromPaintView(rDev); +} + +/** + * Return a pointer to the OutlinerView corresponding to the window + */ +OutlinerView* OutlineView::GetViewByWindow (vcl::Window const * pWin) const +{ + OutlinerView* pOlView = nullptr; + for (std::unique_ptr<OutlinerView> const & pView : mpOutlinerViews) + { + if (pView != nullptr) + { + if ( pWin == pView->GetWindow() ) + { + pOlView = pView.get(); + } + } + } + return pOlView; +} + +/** + * Return the title before a random paragraph + */ +Paragraph* OutlineView::GetPrevTitle(const Paragraph* pPara) +{ + sal_Int32 nPos = mrOutliner.GetAbsPos(pPara); + + if (nPos > 0) + { + while(nPos) + { + pPara = mrOutliner.GetParagraph(--nPos); + if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) ) + { + return const_cast< Paragraph* >( pPara ); + } + } + + } + return nullptr; +} + +/** + * Return the title after a random paragraph + */ +Paragraph* OutlineView::GetNextTitle(const Paragraph* pPara) +{ + Paragraph* pResult = const_cast< Paragraph* >( pPara ); + + sal_Int32 nPos = mrOutliner.GetAbsPos(pResult); + + do + { + pResult = mrOutliner.GetParagraph(++nPos); + if( pResult && ::Outliner::HasParaFlag(pResult, ParaFlag::ISPAGE) ) + return pResult; + } + while( pResult ); + + return nullptr; +} + +/** + * Handler for inserting pages (paragraphs) + */ +IMPL_LINK( OutlineView, ParagraphInsertedHdl, Outliner::ParagraphHdlParam, aParam, void ) +{ + // we get calls to this handler during binary insert of drag and drop contents but + // we ignore it here and handle it later in OnEndPasteOrDrop() + if (maDragAndDropModelGuard != nullptr) + return; + + OutlineViewPageChangesGuard aGuard(this); + + sal_Int32 nAbsPos = mrOutliner.GetAbsPos( aParam.pPara ); + + UpdateParagraph( nAbsPos ); + + if( (nAbsPos == 0) || + ::Outliner::HasParaFlag(aParam.pPara, ParaFlag::ISPAGE) || + ::Outliner::HasParaFlag(mrOutliner.GetParagraph( nAbsPos-1 ), ParaFlag::ISPAGE) ) + { + InsertSlideForParagraph( aParam.pPara ); + } +} + +/** creates and inserts an empty slide for the given paragraph */ +SdPage* OutlineView::InsertSlideForParagraph( Paragraph* pPara ) +{ + DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::InsertSlideForParagraph(), model change without undo?!" ); + + OutlineViewPageChangesGuard aGuard(this); + + mrOutliner.SetParaFlag( pPara, ParaFlag::ISPAGE ); + // how many titles are there before the new title paragraph? + sal_uLong nExample = 0; // position of the "example" page + sal_uLong nTarget = 0; // position of insertion + while(pPara) + { + pPara = GetPrevTitle(pPara); + if (pPara) + nTarget++; + } + + // if a new paragraph is created via RETURN before the first paragraph, the + // Outliner reports the old paragraph (which was moved down) as a new + // paragraph + if (nTarget == 1) + { + OUString aTest = mrOutliner.GetText(mrOutliner.GetParagraph(0)); + if (aTest.isEmpty()) + { + nTarget = 0; + } + } + + // the "example" page is the previous page - if it is available + if (nTarget > 0) + { + nExample = nTarget - 1; + + sal_uInt16 nPageCount = mrDoc.GetSdPageCount( PageKind::Standard ); + if( nExample >= nPageCount ) + nExample = nPageCount - 1; + } + + /********************************************************************** + * All the time, a standard page is created before a notes page. + * It is ensured that after each standard page the corresponding notes page + * follows. A handout page is exactly one handout page. + **********************************************************************/ + + // this page is exemplary + SdPage* pExample = mrDoc.GetSdPage(static_cast<sal_uInt16>(nExample), PageKind::Standard); + rtl::Reference<SdPage> pPage = mrDoc.AllocSdPage(false); + + pPage->SetLayoutName(pExample->GetLayoutName()); + + // insert (page) + mrDoc.InsertPage(pPage.get(), static_cast<sal_uInt16>(nTarget) * 2 + 1); + if( isRecordingUndo() ) + AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoNewPage(*pPage)); + + // assign a master page to the standard page + pPage->TRG_SetMasterPage(pExample->TRG_GetMasterPage()); + + // set page size + pPage->SetSize(pExample->GetSize()); + pPage->SetBorder( pExample->GetLeftBorder(), + pExample->GetUpperBorder(), + pExample->GetRightBorder(), + pExample->GetLowerBorder() ); + + // create new presentation objects (after <Title> or <Title with subtitle> + // follows <Title with outline>, otherwise apply the layout of the previous + // page + AutoLayout eAutoLayout = pExample->GetAutoLayout(); + if (eAutoLayout == AUTOLAYOUT_TITLE || + eAutoLayout == AUTOLAYOUT_TITLE_ONLY) + { + pPage->SetAutoLayout(AUTOLAYOUT_TITLE_CONTENT, true); + } + else + { + pPage->SetAutoLayout(pExample->GetAutoLayout(), true); + } + + /********************************************************************** + |* now the notes page + \*********************************************************************/ + pExample = mrDoc.GetSdPage(static_cast<sal_uInt16>(nExample), PageKind::Notes); + rtl::Reference<SdPage> pNotesPage = mrDoc.AllocSdPage(false); + + pNotesPage->SetLayoutName(pExample->GetLayoutName()); + + pNotesPage->SetPageKind(PageKind::Notes); + + // insert (notes page) + mrDoc.InsertPage(pNotesPage.get(), static_cast<sal_uInt16>(nTarget) * 2 + 2); + if( isRecordingUndo() ) + AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoNewPage(*pNotesPage)); + + // assign a master page to the notes page + pNotesPage->TRG_SetMasterPage(pExample->TRG_GetMasterPage()); + + // set page size, there must be already one page available + pNotesPage->SetSize(pExample->GetSize()); + pNotesPage->SetBorder( pExample->GetLeftBorder(), + pExample->GetUpperBorder(), + pExample->GetRightBorder(), + pExample->GetLowerBorder() ); + + // create presentation objects + pNotesPage->SetAutoLayout(pExample->GetAutoLayout(), true); + + mrOutliner.UpdateFields(); + + return pPage.get(); +} + +/** + * Handler for deleting pages (paragraphs) + */ +IMPL_LINK( OutlineView, ParagraphRemovingHdl, ::Outliner::ParagraphHdlParam, aParam, void ) +{ + DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::ParagraphRemovingHdl(), model change without undo?!" ); + + OutlineViewPageChangesGuard aGuard(this); + + Paragraph* pPara = aParam.pPara; + if( !::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) ) + return; + + // how many titles are in front of the title paragraph in question? + sal_uLong nPos = 0; + while(pPara) + { + pPara = GetPrevTitle(pPara); + if (pPara) nPos++; + } + + // delete page and notes page + sal_uInt16 nAbsPos = static_cast<sal_uInt16>(nPos) * 2 + 1; + SdrPage* pPage = mrDoc.GetPage(nAbsPos); + if( isRecordingUndo() ) + AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage)); + mrDoc.RemovePage(nAbsPos); + + nAbsPos = static_cast<sal_uInt16>(nPos) * 2 + 1; + pPage = mrDoc.GetPage(nAbsPos); + if( isRecordingUndo() ) + AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage)); + mrDoc.RemovePage(nAbsPos); + + // progress display if necessary + if (mnPagesToProcess) + { + mnPagesProcessed++; + + if(mpProgress) + mpProgress->SetState(mnPagesProcessed); + + if (mnPagesProcessed == mnPagesToProcess) + { + mpProgress.reset(); + mnPagesToProcess = 0; + mnPagesProcessed = 0; + } + } + aParam.pOutliner->UpdateFields(); +} + +/** + * Handler for changing the indentation depth of paragraphs (requires inserting + * or deleting of pages in some cases) + */ +IMPL_LINK( OutlineView, DepthChangedHdl, ::Outliner::DepthChangeHdlParam, aParam, void ) +{ + DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::DepthChangedHdl(), no undo for model change?!" ); + + OutlineViewPageChangesGuard aGuard(this); + + Paragraph* pPara = aParam.pPara; + ::Outliner* pOutliner = aParam.pOutliner; + if( ::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) && ((aParam.nPrevFlags & ParaFlag::ISPAGE) == ParaFlag::NONE) ) + { + // the current paragraph is transformed into a slide + + mrOutliner.SetDepth( pPara, -1 ); + + // are multiple level 1 paragraphs being brought to level 0 and we + // should start a progress view or a timer and didn't already? + if (mnPagesToProcess == 0) + { + Window* pActWin = mrOutlineViewShell.GetActiveWindow(); + OutlinerView* pOlView = GetViewByWindow(pActWin); + + std::vector<Paragraph*> aSelList; + pOlView->CreateSelectionList(aSelList); + + mnPagesToProcess = std::count_if(aSelList.begin(), aSelList.end(), + [&pOutliner](const Paragraph *pParagraph) { + return !Outliner::HasParaFlag(pParagraph, ParaFlag::ISPAGE) && + (pOutliner->GetDepth(pOutliner->GetAbsPos(pParagraph)) <= 0); + }); + + mnPagesToProcess++; // the paragraph being in level 0 already + // should be included + mnPagesProcessed = 0; + + if (mnPagesToProcess > PROCESS_WITH_PROGRESS_THRESHOLD) + { + mpProgress.reset( new SfxProgress( GetDocSh(), SdResId(STR_CREATE_PAGES), mnPagesToProcess ) ); + } + else + { + mpDocSh->SetWaitCursor( true ); + } + } + + ParagraphInsertedHdl( { aParam.pOutliner, aParam.pPara } ); + + mnPagesProcessed++; + + // should there be a progress display? + if (mnPagesToProcess > PROCESS_WITH_PROGRESS_THRESHOLD) + { + if (mpProgress) + mpProgress->SetState(mnPagesProcessed); + } + + // was this the last page? + if (mnPagesProcessed == mnPagesToProcess) + { + if (mnPagesToProcess > PROCESS_WITH_PROGRESS_THRESHOLD && mpProgress) + { + mpProgress.reset(); + } + else + mpDocSh->SetWaitCursor( false ); + + mnPagesToProcess = 0; + mnPagesProcessed = 0; + } + pOutliner->UpdateFields(); + } + else if( !::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ) && ((aParam.nPrevFlags & ParaFlag::ISPAGE) != ParaFlag::NONE) ) + { + // the paragraph was a page but now becomes a normal paragraph + + // how many titles are before the title paragraph in question? + sal_uLong nPos = 0; + Paragraph* pParagraph = pPara; + while(pParagraph) + { + pParagraph = GetPrevTitle(pParagraph); + if (pParagraph) + nPos++; + } + // delete page and notes page + + sal_uInt16 nAbsPos = static_cast<sal_uInt16>(nPos) * 2 + 1; + SdrPage* pPage = mrDoc.GetPage(nAbsPos); + if( isRecordingUndo() ) + AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage)); + mrDoc.RemovePage(nAbsPos); + + nAbsPos = static_cast<sal_uInt16>(nPos) * 2 + 1; + pPage = mrDoc.GetPage(nAbsPos); + if( isRecordingUndo() ) + AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeletePage(*pPage)); + mrDoc.RemovePage(nAbsPos); + + pPage = GetPageForParagraph( pPara ); + + mrOutliner.SetDepth( pPara, (pPage && (static_cast<SdPage*>(pPage)->GetAutoLayout() == AUTOLAYOUT_TITLE)) ? -1 : 0 ); + + // progress display if necessary + if (mnPagesToProcess) + { + mnPagesProcessed++; + if (mpProgress) + mpProgress->SetState(mnPagesProcessed); + + if (mnPagesProcessed == mnPagesToProcess) + { + mpProgress.reset(); + mnPagesToProcess = 0; + mnPagesProcessed = 0; + } + } + pOutliner->UpdateFields(); + } + else if ( (pOutliner->GetPrevDepth() == 1) && ( pOutliner->GetDepth( pOutliner->GetAbsPos( pPara ) ) == 2 ) ) + { + // how many titles are in front of the title paragraph in question? + sal_Int32 nPos = -1; + + Paragraph* pParagraph = pPara; + while(pParagraph) + { + pParagraph = GetPrevTitle(pParagraph); + if (pParagraph) + nPos++; + } + + if(nPos >= 0) + { + SdPage*pPage = mrDoc.GetSdPage( static_cast<sal_uInt16>(nPos), PageKind::Standard); + + if(pPage && pPage->GetPresObj(PresObjKind::Text)) + pOutliner->SetDepth( pPara, 0 ); + } + + } + // how many titles are in front of the title paragraph in question? + sal_Int32 nPos = -1; + + Paragraph* pTempPara = pPara; + while(pTempPara) + { + pTempPara = GetPrevTitle(pTempPara); + if (pTempPara) + nPos++; + } + + if( nPos < 0 ) + return; + + SdPage* pPage = mrDoc.GetSdPage( static_cast<sal_uInt16>(nPos), PageKind::Standard ); + + if( !pPage ) + return; + + SfxStyleSheet* pStyleSheet = nullptr; + sal_Int32 nPara = pOutliner->GetAbsPos( pPara ); + sal_Int16 nDepth = pOutliner->GetDepth( nPara ); + bool bSubTitle = pPage->GetPresObj(PresObjKind::Text) != nullptr; + + if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) ) + { + pStyleSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Title ); + } + else if( bSubTitle ) + { + pStyleSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Text ); + } + else + { + pStyleSheet = pPage->GetStyleSheetForPresObj( PresObjKind::Outline ); + + if( nDepth > 0 ) + { + OUString aNewStyleSheetName = pStyleSheet->GetName(); + if (!aNewStyleSheetName.isEmpty()) + aNewStyleSheetName = aNewStyleSheetName.copy(0, aNewStyleSheetName.getLength() - 1); + aNewStyleSheetName += OUString::number( nDepth+1 ); + SfxStyleSheetBasePool* pStylePool = mrDoc.GetStyleSheetPool(); + pStyleSheet = static_cast<SfxStyleSheet*>( pStylePool->Find( aNewStyleSheetName, pStyleSheet->GetFamily() ) ); + } + } + + // before we set the style sheet we need to preserve the bullet item + // since all items will be deleted while setting a new style sheet + SfxItemSet aOldAttrs( pOutliner->GetParaAttribs( nPara ) ); + + pOutliner->SetStyleSheet( nPara, pStyleSheet ); + + // restore the old bullet item but not if the style changed + if ( pOutliner->GetPrevDepth() != -1 && nDepth != -1 && + aOldAttrs.GetItemState( EE_PARA_NUMBULLET ) == SfxItemState::SET ) + { + SfxItemSet aAttrs( pOutliner->GetParaAttribs( nPara ) ); + aAttrs.Put( *aOldAttrs.GetItem( EE_PARA_NUMBULLET ) ); + pOutliner->SetParaAttribs( nPara, aAttrs ); + } +} + +/** + * Handler for StatusEvents + */ +IMPL_LINK_NOARG(OutlineView, StatusEventHdl, EditStatus&, void) +{ + ::sd::Window* pWin = mrOutlineViewShell.GetActiveWindow(); + OutlinerView* pOutlinerView = GetViewByWindow(pWin); + ::tools::Rectangle aVis = pOutlinerView->GetVisArea(); + ::tools::Rectangle aText(Point(0,0), + Size(mnPaperWidth, + mrOutliner.GetTextHeight())); + ::tools::Rectangle aWin(Point(0,0), pWin->GetOutputSizePixel()); + aWin = pWin->PixelToLogic(aWin); + + if (!aVis.IsEmpty()) // not when opening + { + if (aWin.GetHeight() > aText.Bottom()) + aText.SetBottom( aWin.GetHeight() ); + + mrOutlineViewShell.InitWindows(Point(0,0), aText.GetSize(), aVis.TopLeft()); + mrOutlineViewShell.UpdateScrollBars(); + } +} + +IMPL_LINK_NOARG(OutlineView, BeginDropHdl, EditView*, void) +{ + DBG_ASSERT(maDragAndDropModelGuard == nullptr, + "sd::OutlineView::BeginDropHdl(), prior drag operation not finished correctly!"); + + maDragAndDropModelGuard.reset( new OutlineViewModelChangeGuard( *this ) ); +} + +IMPL_LINK_NOARG(OutlineView, EndDropHdl, EditView*, void) +{ + maDragAndDropModelGuard.reset(); +} + +/** + * Handler for the start of a paragraph movement + */ +IMPL_LINK( OutlineView, BeginMovingHdl, ::Outliner *, pOutliner, void ) +{ + OutlineViewPageChangesGuard aGuard(this); + + // list of selected title paragraphs + mpOutlinerViews[0]->CreateSelectionList(maSelectedParas); + + std::erase_if(maSelectedParas, + [](const Paragraph* pPara) { return !Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE); }); + + // select the pages belonging to the paragraphs on level 0 to select + sal_uInt16 nPos = 0; + sal_Int32 nParaPos = 0; + Paragraph* pPara = pOutliner->GetParagraph( 0 ); + std::vector<Paragraph*>::const_iterator fiter; + + while(pPara) + { + if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) ) // one page? + { + maOldParaOrder.push_back(pPara); + SdPage* pPage = mrDoc.GetSdPage(nPos, PageKind::Standard); + + fiter = std::find(maSelectedParas.begin(),maSelectedParas.end(),pPara); + + pPage->SetSelected(fiter != maSelectedParas.end()); + + ++nPos; + } + pPara = pOutliner->GetParagraph( ++nParaPos ); + } +} + +/** + * Handler for the end of a paragraph movement + */ +IMPL_LINK( OutlineView, EndMovingHdl, ::Outliner *, pOutliner, void ) +{ + OutlineViewPageChangesGuard aGuard(this); + + DBG_ASSERT( isRecordingUndo(), "sd::OutlineView::EndMovingHdl(), model change without undo?!" ); + + // look for insertion position via the first paragraph + Paragraph* pSearchIt = maSelectedParas.empty() ? nullptr : *(maSelectedParas.begin()); + + // look for the first of the selected paragraphs in the new ordering + sal_uInt16 nPosNewOrder = 0; + sal_Int32 nParaPos = 0; + Paragraph* pPara = pOutliner->GetParagraph( 0 ); + Paragraph* pPrev = nullptr; + while (pPara && pPara != pSearchIt) + { + if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) ) + { + nPosNewOrder++; + pPrev = pPara; + } + pPara = pOutliner->GetParagraph( ++nParaPos ); + } + + sal_uInt16 nPos = nPosNewOrder; // don't change nPosNewOrder + if (nPos == 0) + { + nPos = sal_uInt16(-1); // insert before the first page + } + else + { + // look for the predecessor in the old ordering + std::vector<Paragraph*>::const_iterator it = std::find(maOldParaOrder.begin(), + maOldParaOrder.end(), + pPrev); + + if (it != maOldParaOrder.end()) + nPos = static_cast<sal_uInt16>(it-maOldParaOrder.begin()); + else + nPos = 0xffff; + + DBG_ASSERT(nPos != 0xffff, "Paragraph not found"); + } + + mrDoc.MovePages(nPos); + + // deselect the pages again + sal_uInt16 nPageCount = static_cast<sal_uInt16>(maSelectedParas.size()); + while (nPageCount) + { + SdPage* pPage = mrDoc.GetSdPage(nPosNewOrder, PageKind::Standard); + pPage->SetSelected(false); + nPosNewOrder++; + nPageCount--; + } + + pOutliner->UpdateFields(); + + maSelectedParas.clear(); + maOldParaOrder.clear(); +} + +/** + * Look for the title text object in one page of the model + */ +SdrTextObj* OutlineView::GetTitleTextObject(SdrPage const * pPage) +{ + SdrTextObj* pResult = nullptr; + + for (const rtl::Reference<SdrObject>& pObject : *pPage) + { + if (pObject->GetObjInventor() == SdrInventor::Default && + pObject->GetObjIdentifier() == SdrObjKind::TitleText) + { + pResult = static_cast<SdrTextObj*>(pObject.get()); + break; + } + } + return pResult; +} + +/** + * Look for the outline text object in one page of the model + */ +SdrTextObj* OutlineView::GetOutlineTextObject(SdrPage const * pPage) +{ + SdrTextObj* pResult = nullptr; + + for (const rtl::Reference<SdrObject>& pObject : *pPage) + { + if (pObject->GetObjInventor() == SdrInventor::Default && + pObject->GetObjIdentifier() == SdrObjKind::OutlineText) + { + pResult = static_cast<SdrTextObj*>(pObject.get()); + break; + } + } + return pResult; +} + +SdrTextObj* OutlineView::CreateTitleTextObject(SdPage* pPage) +{ + DBG_ASSERT( GetTitleTextObject(pPage) == nullptr, "sd::OutlineView::CreateTitleTextObject(), there is already a title text object!" ); + + if( pPage->GetAutoLayout() == AUTOLAYOUT_NONE ) + { + // simple case + pPage->SetAutoLayout( AUTOLAYOUT_TITLE_ONLY, true ); + } + else + { + // we already have a layout with a title but the title + // object was deleted, create a new one + pPage->InsertAutoLayoutShape( nullptr, PresObjKind::Title, false, pPage->GetTitleRect(), true ); + } + + return GetTitleTextObject(pPage); +} + +SdrTextObj* OutlineView::CreateOutlineTextObject(SdPage* pPage) +{ + DBG_ASSERT( GetOutlineTextObject(pPage) == nullptr, "sd::OutlineView::CreateOutlineTextObject(), there is already a layout text object!" ); + + AutoLayout eNewLayout = pPage->GetAutoLayout(); + switch( eNewLayout ) + { + case AUTOLAYOUT_NONE: + case AUTOLAYOUT_TITLE_ONLY: + case AUTOLAYOUT_TITLE: eNewLayout = AUTOLAYOUT_TITLE_CONTENT; break; + + case AUTOLAYOUT_CHART: eNewLayout = AUTOLAYOUT_CHARTTEXT; break; + + case AUTOLAYOUT_ORG: + case AUTOLAYOUT_TAB: + case AUTOLAYOUT_OBJ: eNewLayout = AUTOLAYOUT_OBJTEXT; break; + default: + break; + } + + if( eNewLayout != pPage->GetAutoLayout() ) + { + pPage->SetAutoLayout( eNewLayout, true ); + } + else + { + // we already have a layout with a text but the text + // object was deleted, create a new one + pPage->InsertAutoLayoutShape( nullptr, + PresObjKind::Outline, + false, pPage->GetLayoutRect(), true ); + } + + return GetOutlineTextObject(pPage); +} + +/** updates draw model with all changes from outliner model */ +void OutlineView::PrepareClose() +{ + ::sd::UndoManager* pDocUndoMgr = dynamic_cast<sd::UndoManager*>(mpDocSh->GetUndoManager()); + if (pDocUndoMgr != nullptr) + pDocUndoMgr->SetLinkedUndoManager(nullptr); + + mrOutliner.GetUndoManager().Clear(); + + BegUndo(SdResId(STR_UNDO_CHANGE_TITLE_AND_LAYOUT)); + UpdateDocument(); + EndUndo(); + mrDoc.SetSelected(GetActualPage(), true); +} + +/** + * Set attributes of the selected text + */ +bool OutlineView::SetAttributes(const SfxItemSet& rSet, bool /*bSlide*/, bool /*bReplaceAll*/, bool /*bMaster*/) +{ + bool bOk = false; + + OutlinerView* pOlView = GetViewByWindow(mrOutlineViewShell.GetActiveWindow()); + + if (pOlView) + { + pOlView->SetAttribs(rSet); + bOk = true; + } + + mrOutlineViewShell.Invalidate (SID_PREVIEW_STATE); + + return bOk; +} + +/** + * Get attributes of the selected text + */ +void OutlineView::GetAttributes( SfxItemSet& rTargetSet, bool ) const +{ + OutlinerView* pOlView = GetViewByWindow( + mrOutlineViewShell.GetActiveWindow()); + assert(pOlView && "No OutlinerView found"); + + rTargetSet.Put( pOlView->GetAttribs(), false ); +} + +/** creates outliner model from draw model */ +void OutlineView::FillOutliner() +{ + mrOutliner.GetUndoManager().Clear(); + mrOutliner.EnableUndo(false); + ResetLinks(); + const bool bPrevUpdateLayout = mrOutliner.SetUpdateLayout(false); + + Paragraph* pTitleToSelect = nullptr; + sal_uInt16 nPageCount = mrDoc.GetSdPageCount(PageKind::Standard); + + // fill outliner with paragraphs from slides title & (outlines|subtitles) + for (sal_uInt16 nPage = 0; nPage < nPageCount; nPage++) + { + SdPage* pPage = mrDoc.GetSdPage(nPage, PageKind::Standard); + Paragraph * pPara = nullptr; + + // take text from title shape + SdrTextObj* pTO = GetTitleTextObject(pPage); + if(pTO && !(pTO->IsEmptyPresObj())) + { + OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject(); + if (pOPO) + { + bool bVertical = pOPO->IsEffectivelyVertical(); + pOPO->SetVertical( false ); + mrOutliner.AddText(*pOPO); + pOPO->SetVertical( bVertical ); + pPara = mrOutliner.GetParagraph( mrOutliner.GetParagraphCount()-1 ); + } + } + + if( pPara == nullptr ) // no title, insert an empty paragraph + { + pPara = mrOutliner.Insert(OUString()); + mrOutliner.SetDepth(pPara, -1); + + // do not apply hard attributes from the previous paragraph + mrOutliner.SetParaAttribs( mrOutliner.GetAbsPos(pPara), + mrOutliner.GetEmptyItemSet() ); + + mrOutliner.SetStyleSheet( mrOutliner.GetAbsPos( pPara ), pPage->GetStyleSheetForPresObj( PresObjKind::Title ) ); + } + + mrOutliner.SetParaFlag( pPara, ParaFlag::ISPAGE ); + + sal_Int32 nPara = mrOutliner.GetAbsPos( pPara ); + + UpdateParagraph( nPara ); + + // remember paragraph of currently selected page + if (pPage->IsSelected()) + pTitleToSelect = pPara; + + // take text from subtitle or outline + pTO = static_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Text)); + const bool bSubTitle = pTO != nullptr; + + if (!pTO) // if no subtile found, try outline + pTO = GetOutlineTextObject(pPage); + + if(pTO && !(pTO->IsEmptyPresObj())) // found some text + { + OutlinerParaObject* pOPO = pTO->GetOutlinerParaObject(); + if (pOPO) + { + sal_Int32 nParaCount1 = mrOutliner.GetParagraphCount(); + bool bVertical = pOPO->IsEffectivelyVertical(); + pOPO->SetVertical( false ); + mrOutliner.AddText(*pOPO); + pOPO->SetVertical( bVertical ); + + sal_Int32 nParaCount2 = mrOutliner.GetParagraphCount(); + for (sal_Int32 n = nParaCount1; n < nParaCount2; n++) + { + if( bSubTitle ) + { + Paragraph* p = mrOutliner.GetParagraph(n); + if(p && mrOutliner.GetDepth( n ) > 0 ) + mrOutliner.SetDepth(p, 0); + } + + UpdateParagraph( n ); + } + } + } + } + + // place cursor at the start + Paragraph* pFirstPara = mrOutliner.GetParagraph( 0 ); + mpOutlinerViews[0]->Select( pFirstPara ); + mpOutlinerViews[0]->Select( pFirstPara, false ); + + // select title of slide that was selected + if (pTitleToSelect) + mpOutlinerViews[0]->Select(pTitleToSelect); + + SetLinks(); + + mrOutliner.EnableUndo(true); + + mrOutliner.SetUpdateLayout(bPrevUpdateLayout); +} + +/** + * Handler for deleting of level 0 paragraphs (pages): Warning + */ +IMPL_LINK_NOARG(OutlineView, RemovingPagesHdl, OutlinerView*, bool) +{ + sal_Int32 nNumOfPages = mrOutliner.GetSelPageCount(); + + if (nNumOfPages > PROCESS_WITH_PROGRESS_THRESHOLD) + { + mnPagesToProcess = nNumOfPages; + mnPagesProcessed = 0; + } + + if (mnPagesToProcess) + { + mpProgress.reset( new SfxProgress( GetDocSh(), SdResId(STR_DELETE_PAGES), mnPagesToProcess ) ); + } + mrOutliner.UpdateFields(); + + return true; +} + +/** + * Handler for indenting level 0 paragraphs (pages): Warning + */ +IMPL_LINK( OutlineView, IndentingPagesHdl, OutlinerView *, pOutlinerView, bool ) +{ + return RemovingPagesHdl(pOutlinerView); +} + +/** returns the first slide that is selected in the outliner or where + the cursor is located */ +SdPage* OutlineView::GetActualPage() +{ + ::sd::Window* pWin = mrOutlineViewShell.GetActiveWindow(); + OutlinerView* pActiveView = GetViewByWindow(pWin); + + std::vector<Paragraph*> aSelList; + pActiveView->CreateSelectionList(aSelList); + + Paragraph *pPar = aSelList.empty() ? nullptr : *(aSelList.begin()); + SdPage* pCurrent = GetPageForParagraph(pPar); + + DBG_ASSERT( pCurrent || + (mpDocSh->GetUndoManager() && static_cast< sd::UndoManager *>(mpDocSh->GetUndoManager())->IsDoing()) || + maDragAndDropModelGuard, + "sd::OutlineView::GetActualPage(), no current page?" ); + + if( pCurrent ) + return pCurrent; + + return mrDoc.GetSdPage( 0, PageKind::Standard ); +} + +SdPage* OutlineView::GetPageForParagraph( Paragraph* pPara ) +{ + if( !::Outliner::HasParaFlag(pPara,ParaFlag::ISPAGE) ) + pPara = GetPrevTitle(pPara); + + sal_uInt32 nPageToSelect = 0; + while(pPara) + { + pPara = GetPrevTitle(pPara); + if(pPara) + nPageToSelect++; + } + + if( nPageToSelect < static_cast<sal_uInt32>(mrDoc.GetSdPageCount( PageKind::Standard )) ) + return mrDoc.GetSdPage( static_cast<sal_uInt16>(nPageToSelect), PageKind::Standard ); + + return nullptr; +} + +Paragraph* OutlineView::GetParagraphForPage( ::Outliner const & rOutl, SdPage const * pPage ) +{ + // get the number of paragraphs with ident 0 we need to skip before + // we find the actual page + sal_uInt32 nPagesToSkip = (pPage->GetPageNum() - 1) >> 1; + + sal_Int32 nParaPos = 0; + Paragraph* pPara = rOutl.GetParagraph( 0 ); + while( pPara ) + { + // if this paragraph is a page... + if( ::Outliner::HasParaFlag(pPara,ParaFlag::ISPAGE) ) + { + // see if we already skipped enough pages + if( 0 == nPagesToSkip ) + break; // and if so, end the loop + + // we skipped another page + nPagesToSkip--; + } + + // get next paragraph + pPara = mrOutliner.GetParagraph( ++nParaPos ); + } + + return pPara; +} + +/** selects the paragraph for the given page at the outliner view*/ +void OutlineView::SetActualPage( SdPage const * pActual ) +{ + if( pActual && mrOutliner.GetIgnoreCurrentPageChangesLevel()==0 && !mbFirstPaint) + { + // if we found a paragraph, select its text at the outliner view + Paragraph* pPara = GetParagraphForPage( mrOutliner, pActual ); + if( pPara ) + mpOutlinerViews[0]->Select( pPara ); + } +} + +/** + * Get StyleSheet from the selection + */ +SfxStyleSheet* OutlineView::GetStyleSheet() const +{ + ::sd::Window* pActWin = mrOutlineViewShell.GetActiveWindow(); + OutlinerView* pOlView = GetViewByWindow(pActWin); + SfxStyleSheet* pResult = pOlView->GetStyleSheet(); + return pResult; +} + +/** + * Mark pages as selected / not selected + */ +void OutlineView::SetSelectedPages() +{ + // list of selected title paragraphs + std::vector<Paragraph*> aSelParas; + mpOutlinerViews[0]->CreateSelectionList(aSelParas); + + std::erase_if(aSelParas, + [](const Paragraph* pPara) { return !Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE); }); + + // select the pages belonging to the paragraphs on level 0 to select + sal_uInt16 nPos = 0; + sal_Int32 nParaPos = 0; + Paragraph *pPara = mrOutliner.GetParagraph( 0 ); + std::vector<Paragraph*>::const_iterator fiter; + + while(pPara) + { + if( ::Outliner::HasParaFlag(pPara, ParaFlag::ISPAGE) ) // one page + { + SdPage* pPage = mrDoc.GetSdPage(nPos, PageKind::Standard); + DBG_ASSERT(pPage!=nullptr, + "Trying to select non-existing page OutlineView::SetSelectedPages()"); + + if (pPage) + { + fiter = std::find(aSelParas.begin(),aSelParas.end(),pPara); + pPage->SetSelected(fiter != aSelParas.end()); + } + + nPos++; + } + + pPara = mrOutliner.GetParagraph( ++nParaPos ); + } +} + +/** + * Set new links + */ +void OutlineView::SetLinks() +{ + // set notification links + mrOutliner.SetParaInsertedHdl(LINK(this, OutlineView, ParagraphInsertedHdl)); + mrOutliner.SetParaRemovingHdl(LINK(this, OutlineView, ParagraphRemovingHdl)); + mrOutliner.SetDepthChangedHdl(LINK(this, OutlineView, DepthChangedHdl)); + mrOutliner.SetBeginMovingHdl(LINK(this, OutlineView, BeginMovingHdl)); + mrOutliner.SetEndMovingHdl(LINK(this, OutlineView, EndMovingHdl)); + mrOutliner.SetRemovingPagesHdl(LINK(this, OutlineView, RemovingPagesHdl)); + mrOutliner.SetIndentingPagesHdl(LINK(this, OutlineView, IndentingPagesHdl)); + mrOutliner.SetStatusEventHdl(LINK(this, OutlineView, StatusEventHdl)); + mrOutliner.SetBeginDropHdl(LINK(this,OutlineView, BeginDropHdl)); + mrOutliner.SetEndDropHdl(LINK(this,OutlineView, EndDropHdl)); + mrOutliner.SetPaintFirstLineHdl(LINK(this,OutlineView,PaintingFirstLineHdl)); + mrOutliner.SetBeginPasteOrDropHdl(LINK(this,OutlineView, BeginPasteOrDropHdl)); + mrOutliner.SetEndPasteOrDropHdl(LINK(this,OutlineView, EndPasteOrDropHdl)); +} + +/** + * Restore old links + */ +void OutlineView::ResetLinks() const +{ + mrOutliner.SetParaInsertedHdl(Link<::Outliner::ParagraphHdlParam,void>()); + mrOutliner.SetParaRemovingHdl(Link<::Outliner::ParagraphHdlParam,void>()); + mrOutliner.SetDepthChangedHdl(Link<::Outliner::DepthChangeHdlParam,void>()); + mrOutliner.SetBeginMovingHdl(Link<::Outliner*,void>()); + mrOutliner.SetEndMovingHdl(Link<::Outliner*,void>()); + mrOutliner.SetStatusEventHdl(Link<EditStatus&,void>()); + mrOutliner.SetRemovingPagesHdl(Link<OutlinerView*,bool>()); + mrOutliner.SetIndentingPagesHdl(Link<OutlinerView*,bool>()); + mrOutliner.SetDrawPortionHdl(Link<DrawPortionInfo*,void>()); + mrOutliner.SetBeginPasteOrDropHdl(Link<PasteOrDropInfos*,void>()); + mrOutliner.SetEndPasteOrDropHdl(Link<PasteOrDropInfos*,void>()); +} + +sal_Int8 OutlineView::AcceptDrop( const AcceptDropEvent&, DropTargetHelper&, SdrLayerID) +{ + return DND_ACTION_NONE; +} + +sal_Int8 OutlineView::ExecuteDrop( const ExecuteDropEvent&, ::sd::Window*, sal_uInt16, SdrLayerID) +{ + return DND_ACTION_NONE; +} + +// Re-implement GetScriptType for this view to get correct results +SvtScriptType OutlineView::GetScriptType() const +{ + SvtScriptType nScriptType = ::sd::View::GetScriptType(); + + std::optional<OutlinerParaObject> pTempOPObj = mrOutliner.CreateParaObject(); + if(pTempOPObj) + { + nScriptType = pTempOPObj->GetTextObject().GetScriptType(); + } + + return nScriptType; +} + +void OutlineView::onUpdateStyleSettings( bool bForceUpdate /* = false */ ) +{ + svtools::ColorConfig aColorConfig; + const Color aDocColor( aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor ); + if( !(bForceUpdate || (maDocColor != aDocColor)) ) + return; + + sal_uInt16 nView; + for( nView = 0; nView < MAX_OUTLINERVIEWS; nView++ ) + { + if (mpOutlinerViews[nView] != nullptr) + { + mpOutlinerViews[nView]->SetBackgroundColor( aDocColor ); + + vcl::Window* pWindow = mpOutlinerViews[nView]->GetWindow(); + + if( pWindow ) + pWindow->SetBackground( Wallpaper( aDocColor ) ); + + } + } + + mrOutliner.SetBackgroundColor( aDocColor ); + + maDocColor = aDocColor; +} + +IMPL_LINK_NOARG(OutlineView, AppEventListenerHdl, VclSimpleEvent&, void) +{ + onUpdateStyleSettings(false); +} + +IMPL_LINK(OutlineView, EventMultiplexerListener, ::sd::tools::EventMultiplexerEvent&, rEvent, void) +{ + switch (rEvent.meEventId) + { + case EventMultiplexerEventId::CurrentPageChanged: + SetActualPage(mrOutlineViewShell.GetActualPage()); + break; + + case EventMultiplexerEventId::PageOrder: + if (mrOutliner.GetIgnoreCurrentPageChangesLevel()==0) + { + if (((mrDoc.GetPageCount()-1)%2) == 0) + { + mrOutliner.Clear(); + FillOutliner(); + ::sd::Window* pWindow = mrOutlineViewShell.GetActiveWindow(); + if (pWindow != nullptr) + pWindow->Invalidate(); + } + } + break; + + default: break; + } +} + +void OutlineView::IgnoreCurrentPageChanges (bool bIgnoreChanges) +{ + if (bIgnoreChanges) + mrOutliner.IncreIgnoreCurrentPageChangesLevel(); + else + mrOutliner.DecreIgnoreCurrentPageChangesLevel(); +} + +/** call this method before you do anything that can modify the outliner + and or the drawing document model. It will create needed undo actions */ +void OutlineView::BeginModelChange() +{ + mrOutliner.GetUndoManager().EnterListAction("", "", 0, mrOutlineViewShell.GetViewShellBase().GetViewShellId()); + BegUndo(SdResId(STR_UNDO_CHANGE_TITLE_AND_LAYOUT)); +} + +/** call this method after BeginModelChange(), when all possible model + changes are done. */ +void OutlineView::EndModelChange() +{ + UpdateDocument(); + + SfxUndoManager* pDocUndoMgr = mpDocSh->GetUndoManager(); + + bool bHasUndoActions = pDocUndoMgr->GetUndoActionCount() != 0; + + EndUndo(); + + DBG_ASSERT( bHasUndoActions == (mrOutliner.GetUndoManager().GetUndoActionCount() != 0), "sd::OutlineView::EndModelChange(), undo actions not in sync!" ); + + mrOutliner.GetUndoManager().LeaveListAction(); + + if( bHasUndoActions && mrOutliner.GetEditEngine().HasTriedMergeOnLastAddUndo() ) + TryToMergeUndoActions(); + + mrOutlineViewShell.Invalidate( SID_UNDO ); + mrOutlineViewShell.Invalidate( SID_REDO ); +} + +/** updates all changes in the outliner model to the draw model */ +void OutlineView::UpdateDocument() +{ + OutlineViewPageChangesGuard aGuard(this); + + const sal_uInt32 nPageCount = mrDoc.GetSdPageCount(PageKind::Standard); + Paragraph* pPara = mrOutliner.GetParagraph( 0 ); + sal_uInt32 nPage; + for (nPage = 0; nPage < nPageCount; nPage++) + { + SdPage* pPage = mrDoc.GetSdPage( static_cast<sal_uInt16>(nPage), PageKind::Standard); + mrDoc.SetSelected(pPage, false); + + mrOutlineViewShell.UpdateTitleObject( pPage, pPara ); + mrOutlineViewShell.UpdateOutlineObject( pPage, pPara ); + + if( pPara ) + pPara = GetNextTitle(pPara); + } + + DBG_ASSERT( pPara == nullptr, "sd::OutlineView::UpdateDocument(), slides are out of sync, creating missing ones" ); + while( pPara ) + { + SdPage* pPage = InsertSlideForParagraph( pPara ); + mrDoc.SetSelected(pPage, false); + + mrOutlineViewShell.UpdateTitleObject( pPage, pPara ); + mrOutlineViewShell.UpdateOutlineObject( pPage, pPara ); + + pPara = GetNextTitle(pPara); + } +} + +/** merge edit engine undo actions if possible */ +void OutlineView::TryToMergeUndoActions() +{ + SfxUndoManager& rOutlineUndo = mrOutliner.GetUndoManager(); + if( rOutlineUndo.GetUndoActionCount() <= 1 ) + return; + + SfxListUndoAction* pListAction = dynamic_cast< SfxListUndoAction* >( rOutlineUndo.GetUndoAction() ); + SfxListUndoAction* pPrevListAction = dynamic_cast< SfxListUndoAction* >( rOutlineUndo.GetUndoAction(1) ); + if( !(pListAction && pPrevListAction) ) + return; + + // find the top EditUndo action in the top undo action list + size_t nAction = pListAction->maUndoActions.size(); + EditUndo* pEditUndo = nullptr; + while( !pEditUndo && nAction ) + { + pEditUndo = dynamic_cast< EditUndo* >(pListAction->GetUndoAction(--nAction)); + } + + sal_uInt16 nEditPos = nAction; // we need this later to remove the merged undo actions + + // make sure it is the only EditUndo action in the top undo list + while( pEditUndo && nAction ) + { + if( dynamic_cast< EditUndo* >(pListAction->GetUndoAction(--nAction)) ) + pEditUndo = nullptr; + } + + // do we have one and only one EditUndo action in the top undo list? + if( !pEditUndo ) + return; + + // yes, see if we can merge it with the prev undo list + + nAction = pPrevListAction->maUndoActions.size(); + EditUndo* pPrevEditUndo = nullptr; + while( !pPrevEditUndo && nAction ) + pPrevEditUndo = dynamic_cast< EditUndo* >(pPrevListAction->GetUndoAction(--nAction)); + + if( !(pPrevEditUndo && pPrevEditUndo->Merge( pEditUndo )) ) + return; + + // ok we merged the only EditUndo of the top undo list with + // the top EditUndo of the previous undo list + + // first remove the merged undo action + assert( pListAction->GetUndoAction(nEditPos) == pEditUndo && + "sd::OutlineView::TryToMergeUndoActions(), wrong edit pos!" ); + pListAction->Remove(nEditPos); + + if ( !pListAction->maUndoActions.empty() ) + { + // now we have to move all remaining doc undo actions from the top undo + // list to the previous undo list and remove the top undo list + + size_t nCount = pListAction->maUndoActions.size(); + size_t nDestAction = pPrevListAction->maUndoActions.size(); + while( nCount-- ) + { + std::unique_ptr<SfxUndoAction> pTemp = pListAction->Remove(0); + pPrevListAction->Insert( std::move(pTemp), nDestAction++ ); + } + pPrevListAction->nCurUndoAction = pPrevListAction->maUndoActions.size(); + } + + rOutlineUndo.RemoveLastUndoAction(); +} + +IMPL_LINK(OutlineView, PaintingFirstLineHdl, PaintFirstLineInfo*, pInfo, void) +{ + if( !pInfo ) + return; + + Paragraph* pPara = mrOutliner.GetParagraph( pInfo->mnPara ); + EditEngine& rEditEngine = const_cast< EditEngine& >( mrOutliner.GetEditEngine() ); + + Size aImageSize( pInfo->mpOutDev->PixelToLogic( maSlideImage.GetSizePixel() ) ); + Size aOffset( 100, 100 ); + + // paint slide number + if( !(pPara && ::Outliner::HasParaFlag(pPara,ParaFlag::ISPAGE)) ) + return; + + ::tools::Long nPage = 0; // todo, printing?? + for ( sal_Int32 n = 0; n <= pInfo->mnPara; n++ ) + { + Paragraph* p = mrOutliner.GetParagraph( n ); + if ( ::Outliner::HasParaFlag(p,ParaFlag::ISPAGE) ) + nPage++; + } + + ::tools::Long nBulletHeight = static_cast<::tools::Long>(mrOutliner.GetLineHeight( pInfo->mnPara )); + ::tools::Long nFontHeight = 0; + if ( !rEditEngine.IsFlatMode() ) + { + nFontHeight = nBulletHeight / 5; + } + else + { + nFontHeight = (nBulletHeight * 10) / 25; + } + + Size aFontSz( 0, nFontHeight ); + + Size aOutSize( 2000, nBulletHeight ); + + const float fImageHeight = (static_cast<float>(aOutSize.Height()) * float(4)) / float(7); + if (aImageSize.Width() != 0) + { + const float fImageRatio = static_cast<float>(aImageSize.Height()) / static_cast<float>(aImageSize.Width()); + aImageSize.setWidth( static_cast<::tools::Long>( fImageRatio * fImageHeight ) ); + } + aImageSize.setHeight( static_cast<::tools::Long>(fImageHeight) ); + + Point aImagePos( pInfo->mrStartPos ); + aImagePos.AdjustX(aOutSize.Width() - aImageSize.Width() - aOffset.Width() ) ; + aImagePos.AdjustY((aOutSize.Height() - aImageSize.Height()) / 2 ); + + pInfo->mpOutDev->DrawImage( aImagePos, aImageSize, maSlideImage ); + + const bool bVertical = mrOutliner.IsVertical(); + const bool bRightToLeftPara = rEditEngine.IsRightToLeft( pInfo->mnPara ); + + LanguageType eLang = rEditEngine.GetDefaultLanguage(); + + Point aTextPos( aImagePos.X() - aOffset.Width(), pInfo->mrStartPos.Y() ); + vcl::Font aNewFont( OutputDevice::GetDefaultFont( DefaultFontType::SANS_UNICODE, eLang, GetDefaultFontFlags::NONE ) ); + aNewFont.SetFontSize( aFontSz ); + aNewFont.SetVertical( bVertical ); + aNewFont.SetOrientation( Degree10(bVertical ? 2700 : 0) ); + aNewFont.SetColor( COL_AUTO ); + pInfo->mpOutDev->SetFont( aNewFont ); + OUString aPageText = OUString::number( nPage ); + Size aTextSz; + aTextSz.setWidth( pInfo->mpOutDev->GetTextWidth( aPageText ) ); + aTextSz.setHeight( pInfo->mpOutDev->GetTextHeight() ); + if ( !bVertical ) + { + aTextPos.AdjustY((aOutSize.Height() - aTextSz.Height()) / 2 ); + if ( !bRightToLeftPara ) + { + aTextPos.AdjustX( -(aTextSz.Width()) ); + } + else + { + aTextPos.AdjustX(aTextSz.Width() ); + } + } + else + { + aTextPos.AdjustY( -(aTextSz.Width()) ); + aTextPos.AdjustX(nBulletHeight / 2 ); + } + pInfo->mpOutDev->DrawText( aTextPos, aPageText ); +} + +void OutlineView::UpdateParagraph( sal_Int32 nPara ) +{ + SfxItemSet aNewAttrs2( mrOutliner.GetParaAttribs( nPara ) ); + aNewAttrs2.Put( maLRSpaceItem ); + mrOutliner.SetParaAttribs( nPara, aNewAttrs2 ); +} + +void OutlineView::OnBeginPasteOrDrop( PasteOrDropInfos* /*pInfo*/ ) +{ +} + +/** this is called after a paste or drop operation, make sure that the newly inserted paragraphs + get the correct style sheet and new slides are inserted. */ +void OutlineView::OnEndPasteOrDrop( PasteOrDropInfos* pInfo ) +{ + SdPage* pPage = nullptr; + SfxStyleSheetBasePool* pStylePool = GetDoc().GetStyleSheetPool(); + + for( sal_Int32 nPara = pInfo->nStartPara; nPara <= pInfo->nEndPara; nPara++ ) + { + Paragraph* pPara = mrOutliner.GetParagraph( nPara ); + + bool bPage = ::Outliner::HasParaFlag( pPara, ParaFlag::ISPAGE ); + + if( !bPage ) + { + SdStyleSheet* pStyleSheet = dynamic_cast< SdStyleSheet* >( mrOutliner.GetStyleSheet( nPara ) ); + if( pStyleSheet ) + { + if ( pStyleSheet->GetApiName() == "title" ) + bPage = true; + } + } + + if( !pPara ) + continue; // fatality!? + + if( bPage && (nPara != pInfo->nStartPara) ) + { + // insert new slide for this paragraph + pPage = InsertSlideForParagraph( pPara ); + } + else + { + // newly inserted non page paragraphs get the outline style + if( !pPage ) + pPage = GetPageForParagraph( pPara ); + + if( pPage ) + { + SfxStyleSheet* pStyle = pPage->GetStyleSheetForPresObj( bPage ? PresObjKind::Title : PresObjKind::Outline ); + + if( !bPage ) + { + const sal_Int16 nDepth = mrOutliner.GetDepth( nPara ); + if( nDepth > 0 ) + { + OUString aStyleSheetName = pStyle->GetName(); + if (!aStyleSheetName.isEmpty()) + aStyleSheetName = aStyleSheetName.copy(0, aStyleSheetName.getLength() - 1); + aStyleSheetName += OUString::number( nDepth ); + pStyle = static_cast<SfxStyleSheet*>( pStylePool->Find( aStyleSheetName, pStyle->GetFamily() ) ); + DBG_ASSERT( pStyle, "sd::OutlineView::OnEndPasteOrDrop(), Style not found!" ); + } + } + + mrOutliner.SetStyleSheet( nPara, pStyle ); + } + + UpdateParagraph( nPara ); + } + } +} + + +OutlineViewModelChangeGuard::OutlineViewModelChangeGuard( OutlineView& rView ) +: mrView( rView ) +{ + mrView.BeginModelChange(); +} + +OutlineViewModelChangeGuard::~OutlineViewModelChangeGuard() COVERITY_NOEXCEPT_FALSE +{ + mrView.EndModelChange(); +} + + +OutlineViewPageChangesGuard::OutlineViewPageChangesGuard( OutlineView* pView ) +: mpView( pView ) +{ + if( mpView ) + mpView->IgnoreCurrentPageChanges( true ); +} + +OutlineViewPageChangesGuard::~OutlineViewPageChangesGuard() +{ + if( mpView ) + mpView->IgnoreCurrentPageChanges( false ); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/presvish.cxx b/sd/source/ui/view/presvish.cxx new file mode 100644 index 0000000000..34a789f4dd --- /dev/null +++ b/sd/source/ui/view/presvish.cxx @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <PresentationViewShell.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/svxids.hrc> +#include <svx/ruler.hxx> +#include <FrameView.hxx> +#include <DrawDocShell.hxx> +#include <slideshow.hxx> +#include <app.hrc> +#include <ViewShellBase.hxx> + +#include <fupoor.hxx> +#include <Window.hxx> + +#define ShellClass_PresentationViewShell +using namespace sd; +#include <sdslots.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +namespace sd { + +SFX_IMPL_INTERFACE(PresentationViewShell, DrawViewShell) + +void PresentationViewShell::InitInterface_Impl() +{ + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS, SfxVisibilityFlags::Standard | SfxVisibilityFlags::FullScreen | SfxVisibilityFlags::Server, + ToolbarId::Draw_Toolbox_Sd); + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_APPLICATION, SfxVisibilityFlags::Standard | SfxVisibilityFlags::Client | SfxVisibilityFlags::Viewer | SfxVisibilityFlags::ReadonlyDoc, + ToolbarId::Draw_Viewer_Toolbox); + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OPTIONS, SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server, + ToolbarId::Draw_Options_Toolbox); + GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_COMMONTASK, SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server, + ToolbarId::Draw_CommonTask_Toolbox); +} + + +PresentationViewShell::PresentationViewShell( ViewShellBase& rViewShellBase, vcl::Window* pParentWindow, FrameView* pFrameView) + : DrawViewShell(rViewShellBase, pParentWindow, PageKind::Standard, pFrameView) + , mnAbortSlideShowEvent(nullptr) +{ + if( GetDocSh() && GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED ) + maOldVisArea = GetDocSh()->GetVisArea( ASPECT_CONTENT ); + meShellType = ST_PRESENTATION; +} + +PresentationViewShell::~PresentationViewShell() +{ + if (mnAbortSlideShowEvent) + Application::RemoveUserEvent(mnAbortSlideShowEvent); + + if( GetDocSh() && GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED && !maOldVisArea.IsEmpty() ) + GetDocSh()->SetVisArea( maOldVisArea ); +} + +void PresentationViewShell::FinishInitialization( FrameView* pFrameView ) +{ + DrawViewShell::Init(true); + + // Use the frame view that comes form the view shell that initiated our + // creation. + if (pFrameView != nullptr) + { + GetFrameView()->Disconnect(); + SetFrameView (pFrameView); + pFrameView->Connect(); + } + SetRuler(false); + WriteFrameViewData(); + + GetActiveWindow()->GrabFocus(); +} + +VclPtr<SvxRuler> PresentationViewShell::CreateHRuler(::sd::Window*) +{ + return nullptr; +} + +VclPtr<SvxRuler> PresentationViewShell::CreateVRuler(::sd::Window*) +{ + return nullptr; +} + +IMPL_LINK_NOARG(PresentationViewShell, AbortSlideShowHdl, void*, void) +{ + mnAbortSlideShowEvent = nullptr; + rtl::Reference<SlideShow> xSlideShow(SlideShow::GetSlideShow(GetViewShellBase())); + if (xSlideShow.is()) + xSlideShow->end(); +} + +void PresentationViewShell::Activate( bool bIsMDIActivate ) +{ + DrawViewShell::Activate( bIsMDIActivate ); + + if( bIsMDIActivate ) + { + SfxBoolItem aItem( SID_NAVIGATOR_INIT, true ); + + GetViewFrame()->GetDispatcher()->ExecuteList(SID_NAVIGATOR_INIT, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, { &aItem }); + + rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if( xSlideShow.is() ) + { + bool bSuccess = xSlideShow->activate(GetViewShellBase()); + if (!bSuccess) + { + /* tdf#64711 PresentationViewShell is deleted by 'end' due to end closing + the object shell. So if we call xSlideShow->end during Activate there are + a lot of places in the call stack of Activate which understandable don't + expect this ViewShell to be deleted during use. Defer to the next event + loop the abort of the slideshow + */ + if (!mnAbortSlideShowEvent) + mnAbortSlideShowEvent = Application::PostUserEvent(LINK(this, PresentationViewShell, AbortSlideShowHdl)); + } + } + + if( HasCurrentFunction() ) + GetCurrentFunction()->Activate(); + + ReadFrameViewData(mpFrameView); + } + + GetDocSh()->Connect( this ); +} + +void PresentationViewShell::Paint( const ::tools::Rectangle& /*rRect*/, ::sd::Window* ) +{ + rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if( xSlideShow.is() ) + xSlideShow->paint(); +} + +void PresentationViewShell::Resize() +{ + ViewShell::Resize(); // do not call DrawViewShell here! + + rtl::Reference< sd::SlideShow > xSlideshow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if( xSlideshow.is() ) + xSlideshow->resize(maViewSize); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/sdruler.cxx b/sd/source/ui/view/sdruler.cxx new file mode 100644 index 0000000000..571ffb37f8 --- /dev/null +++ b/sd/source/ui/view/sdruler.cxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <Ruler.hxx> +#include <svl/ptitem.hxx> +#include <svx/ruler.hxx> +#include <svx/svxids.hrc> +#include <sfx2/ctrlitem.hxx> +#include <sfx2/bindings.hxx> +#include <vcl/commandevent.hxx> + +#include <View.hxx> +#include <DrawViewShell.hxx> +#include <Window.hxx> + +#include <helpids.h> + +namespace sd { + +/** + * Controller-Item for ruler + */ +class RulerCtrlItem : public SfxControllerItem +{ + Ruler &rRuler; + + protected: + virtual void StateChangedAtToolBoxControl( sal_uInt16 nSId, SfxItemState eState, + const SfxPoolItem* pItem ) override; + + public: + RulerCtrlItem(Ruler& rRlr, SfxBindings& rBind); +}; + +RulerCtrlItem::RulerCtrlItem(Ruler& rRlr, SfxBindings& rBind) +: SfxControllerItem(SID_RULER_NULL_OFFSET, rBind) +, rRuler(rRlr) +{ +} + +void RulerCtrlItem::StateChangedAtToolBoxControl( sal_uInt16 nSId, SfxItemState, const SfxPoolItem* pState ) +{ + switch( nSId ) + { + case SID_RULER_NULL_OFFSET: + { + const SfxPointItem* pItem = dynamic_cast< const SfxPointItem* >(pState); + DBG_ASSERT(pState == nullptr || pItem != nullptr, "SfxPointItem expected"); + if ( pItem ) + rRuler.SetNullOffset(pItem->GetValue()); + } + break; + } +} + +Ruler::Ruler( DrawViewShell& rViewSh, vcl::Window* pParent, ::sd::Window* pWin, SvxRulerSupportFlags nRulerFlags, SfxBindings& rBindings, WinBits nWinStyle) + : SvxRuler(pParent, pWin, nRulerFlags, rBindings, nWinStyle) + , pDrViewShell(&rViewSh) +{ + rBindings.EnterRegistrations(); + pCtrlItem.reset( new RulerCtrlItem(*this, rBindings) ); + rBindings.LeaveRegistrations(); + + if ( nWinStyle & WB_HSCROLL ) + { + bHorz = true; + SetHelpId( HID_SD_RULER_HORIZONTAL ); + } + else + { + bHorz = false; + SetHelpId( HID_SD_RULER_VERTICAL ); + } +} + +Ruler::~Ruler() +{ + disposeOnce(); +} + +void Ruler::dispose() +{ + SfxBindings& rBindings = pCtrlItem->GetBindings(); + rBindings.EnterRegistrations(); + pCtrlItem.reset(); + rBindings.LeaveRegistrations(); + SvxRuler::dispose(); +} + +void Ruler::MouseButtonDown(const MouseEvent& rMEvt) +{ + Point aMPos = rMEvt.GetPosPixel(); + RulerType eType = GetRulerType(aMPos); + + if ( !pDrViewShell->GetView()->IsTextEdit() && + rMEvt.IsLeft() && rMEvt.GetClicks() == 1 && + (eType == RulerType::DontKnow || eType == RulerType::Outside) ) + { + pDrViewShell->StartRulerDrag(*this, rMEvt); + } + else + SvxRuler::MouseButtonDown(rMEvt); +} + +void Ruler::SetNullOffset(const Point& rOffset) +{ + ::tools::Long nOffset; + + if ( bHorz ) nOffset = rOffset.X(); + else nOffset = rOffset.Y(); + + SetNullOffsetLogic(nOffset); +} + +void Ruler::Command(const CommandEvent& rCEvt) +{ + if( rCEvt.GetCommand() == CommandEventId::ContextMenu && + !pDrViewShell->GetView()->IsTextEdit() ) + { + SvxRuler::Command( rCEvt ); + } +} + +void Ruler::ExtraDown() +{ + if( !pDrViewShell->GetView()->IsTextEdit() ) + SvxRuler::ExtraDown(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/sdview.cxx b/sd/source/ui/view/sdview.cxx new file mode 100644 index 0000000000..dd4ddaab1f --- /dev/null +++ b/sd/source/ui/view/sdview.cxx @@ -0,0 +1,1397 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <com/sun/star/embed/NoVisualAreaSizeException.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <com/sun/star/linguistic2/XSpellChecker1.hpp> + +#include <View.hxx> +#include <avmedia/mediawindow.hxx> +#include <editeng/outlobj.hxx> +#include <editeng/unolingu.hxx> +#include <o3tl/deleter.hxx> +#include <svx/obj3d.hxx> +#include <svx/fmview.hxx> +#include <editeng/outliner.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdoole2.hxx> +#include <svx/svdundo.hxx> + +#include <vcl/settings.hxx> + +#include <officecfg/Office/Common.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdoutl.hxx> +#include <svx/sdr/contact/displayinfo.hxx> + +#include <svx/svdetc.hxx> +#include <editeng/editstat.hxx> + +#include <sfx2/viewfrm.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <svx/xfillit0.hxx> + +#include <app.hrc> +#include <strings.hrc> +#include <Window.hxx> +#include <Client.hxx> +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> +#include <sdmod.hxx> +#include <sdpage.hxx> +#include <sdresid.hxx> +#include <unokywds.hxx> +#include <ViewClipboard.hxx> +#include <undo/undomanager.hxx> +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <svx/sdr/contact/viewcontact.hxx> +#include <svx/svdotable.hxx> +#include <EventMultiplexer.hxx> +#include <ViewShellBase.hxx> +#include <ViewShell.hxx> + +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/color/bcolor.hxx> +#include <drawinglayer/attribute/lineattribute.hxx> +#include <drawinglayer/attribute/strokeattribute.hxx> +#include <drawinglayer/primitive2d/textlayoutdevice.hxx> +#include <drawinglayer/primitive2d/PolygonStrokePrimitive2D.hxx> +#include <svx/sdr/contact/objectcontact.hxx> +#include <svx/sdr/table/tablecontroller.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <drawinglayer/primitive2d/textprimitive2d.hxx> +#include <svx/unoapi.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <comphelper/lok.hxx> +#include <sfx2/lokhelper.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <DrawController.hxx> +#include <svtools/optionsdrawinglayer.hxx> + +#include <memory> +#include <numeric> + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace sdr::table; +namespace sd { + +View::View( + SdDrawDocument& rDrawDoc, + OutputDevice* pOutDev, + ViewShell* pViewShell) +: FmFormView(rDrawDoc, pOutDev), + mrDoc(rDrawDoc), + mpDocSh(rDrawDoc.GetDocSh()), + mpViewSh(pViewShell), + mpDropMarkerObj(nullptr), + mnDragSrcPgNum(SDRPAGE_NOTFOUND), + mnAction(DND_ACTION_NONE), + maDropErrorIdle("sd View DropError"), + maDropInsertFileIdle("sd View DropInsertFile"), + mnLockRedrawSmph(0), + mbIsDropAllowed(true), + maSmartTags(*this), + mpClipboard (new ViewClipboard (*this)) +{ + // #i73602# Use default from the configuration + SetBufferedOverlayAllowed(SvtOptionsDrawinglayer::IsOverlayBuffer_DrawImpress()); + + // #i74769#, #i75172# Use default from the configuration + SetBufferedOutputAllowed(SvtOptionsDrawinglayer::IsPaintBuffer_DrawImpress()); + + EnableExtendedKeyInputDispatcher(false); + EnableExtendedMouseEventDispatcher(false); + + SetUseIncompatiblePathCreateInterface(false); + + SetMinMoveDistancePixel(2); + SetHitTolerancePixel(2); + SetMeasureLayer(sUNO_LayerName_measurelines); + + // Timer for delayed drop (has to be for MAC) + maDropErrorIdle.SetInvokeHandler( LINK(this, View, DropErrorHdl) ); + maDropInsertFileIdle.SetInvokeHandler( LINK(this, View, DropInsertFileHdl) ); +} + +void View::ImplClearDrawDropMarker() +{ + mpDropMarker.reset(); +} + +View::~View() +{ + maSmartTags.Dispose(); + + // release content of selection clipboard, if we own the content + ClearSelectionClipboard(); + +#if HAVE_FEATURE_AVMEDIA + if (mxDropMediaSizeListener) + { + suppress_fun_call_w_exception(mxDropMediaSizeListener->dispose()); + mxDropMediaSizeListener.clear(); + } +#endif + + maDropErrorIdle.Stop(); + maDropInsertFileIdle.Stop(); + + ImplClearDrawDropMarker(); + + while(PaintWindowCount()) + { + // remove all registered OutDevs + suppress_fun_call_w_exception(DeleteDeviceFromPaintView(*GetFirstOutputDevice())); + } +} + +namespace { + +class ViewRedirector : public sdr::contact::ViewObjectContactRedirector +{ +public: + ViewRedirector(); + + // all default implementations just call the same methods at the original. To do something + // different, override the method and at least do what the method does. + virtual void createRedirectedPrimitive2DSequence( + const sdr::contact::ViewObjectContact& rOriginal, + const sdr::contact::DisplayInfo& rDisplayInfo, + drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) override; +}; + +} + +ViewRedirector::ViewRedirector() +{ +} + +void ViewRedirector::createRedirectedPrimitive2DSequence( + const sdr::contact::ViewObjectContact& rOriginal, + const sdr::contact::DisplayInfo& rDisplayInfo, + drawinglayer::primitive2d::Primitive2DDecompositionVisitor& rVisitor) +{ + SdrObject* pObject = rOriginal.GetViewContact().TryToGetSdrObject(); + SdrPage* pSdrPage = pObject ? pObject->getSdrPageFromSdrObject() : nullptr; + if(!pObject || !pSdrPage) + { + // not a SdrObject visualisation (maybe e.g. page) or no page + sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence(rOriginal, rDisplayInfo, rVisitor); + return; + } + + const bool bDoCreateGeometry(pSdrPage->checkVisibility( rOriginal, rDisplayInfo, true )); + + if(!bDoCreateGeometry && + (( pObject->GetObjInventor() != SdrInventor::Default ) || ( pObject->GetObjIdentifier() != SdrObjKind::Page )) ) + return; + + PresObjKind eKind(PresObjKind::NONE); + const bool bSubContentProcessing(rDisplayInfo.GetSubContentActive()); + const bool bIsMasterPageObject(pSdrPage->IsMasterPage()); + const bool bIsPrinting(rOriginal.GetObjectContact().isOutputToPrinter()); + const SdrPageView* pPageView = rOriginal.GetObjectContact().TryToGetSdrPageView(); + const SdrPage* pVisualizedPage = GetSdrPageFromXDrawPage(rOriginal.GetObjectContact().getViewInformation2D().getVisualizedPage()); + const SdPage* pObjectsSdPage = dynamic_cast< SdPage* >(pSdrPage); + const bool bIsInsidePageObj(pPageView && pPageView->GetPage() != pVisualizedPage); + + // check if we need to draw a placeholder border. Never do it for + // objects inside a SdrPageObj and never when printing + if(!bIsInsidePageObj && !bIsPrinting) + { + bool bCreateOutline(false); + + if( pObject->IsEmptyPresObj() && DynCastSdrTextObj( pObject ) != nullptr ) + { + if( !bSubContentProcessing || !pObject->IsNotVisibleAsMaster() ) + { + eKind = pObjectsSdPage ? pObjectsSdPage->GetPresObjKind(pObject) : PresObjKind::NONE; + bCreateOutline = true; + } + } + else if( ( pObject->GetObjInventor() == SdrInventor::Default ) && ( pObject->GetObjIdentifier() == SdrObjKind::Text ) ) + { + if( pObjectsSdPage ) + { + eKind = pObjectsSdPage->GetPresObjKind(pObject); + + if((eKind == PresObjKind::Footer) || (eKind == PresObjKind::Header) || (eKind == PresObjKind::DateTime) || (eKind == PresObjKind::SlideNumber) ) + { + if( !bSubContentProcessing ) + { + // only draw a boundary for header&footer objects on the masterpage itself + bCreateOutline = true; + } + } + } + } + else if( ( pObject->GetObjInventor() == SdrInventor::Default ) && ( pObject->GetObjIdentifier() == SdrObjKind::Page ) ) + { + // only for handout page, else this frame will be created for each + // page preview object in SlideSorter and PagePane + if(pObjectsSdPage && PageKind::Handout == pObjectsSdPage->GetPageKind()) + { + bCreateOutline = true; + } + } + + if(bCreateOutline) + { + // empty presentation objects get a gray frame + const svtools::ColorConfig aColorConfig; + const svtools::ColorConfigValue aColor( aColorConfig.GetColorValue( svtools::OBJECTBOUNDARIES ) ); + + if( aColor.bIsVisible ) + { + // get basic object transformation + const basegfx::BColor aRGBColor(aColor.nColor.getBColor()); + basegfx::B2DHomMatrix aObjectMatrix; + basegfx::B2DPolyPolygon aObjectPolyPolygon; + pObject->TRGetBaseGeometry(aObjectMatrix, aObjectPolyPolygon); + + // create dashed border + { + // create object polygon + basegfx::B2DPolygon aPolygon(basegfx::utils::createUnitPolygon()); + aPolygon.transform(aObjectMatrix); + + // create line and stroke attribute + ::std::vector< double > aDotDashArray { 160.0, 80.0 }; + + const double fFullDotDashLen(::std::accumulate(aDotDashArray.begin(), aDotDashArray.end(), 0.0)); + const drawinglayer::attribute::LineAttribute aLine(aRGBColor); + drawinglayer::attribute::StrokeAttribute aStroke(std::move(aDotDashArray), fFullDotDashLen); + + // create primitive and add + const drawinglayer::primitive2d::Primitive2DReference xRef(new drawinglayer::primitive2d::PolygonStrokePrimitive2D( + std::move(aPolygon), + aLine, + std::move(aStroke))); + rVisitor.visit(xRef); + } + + // now paint the placeholder description, but only when masterpage + // is displayed as page directly (MasterPage view) + if(!bSubContentProcessing && bIsMasterPageObject) + { + OUString aObjectString; + + switch( eKind ) + { + case PresObjKind::Title: + { + if(pObjectsSdPage && pObjectsSdPage->GetPageKind() == PageKind::Standard) + { + static OUString aTitleAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_TITLE)); + aObjectString = aTitleAreaStr; + } + + break; + } + case PresObjKind::Outline: + { + static OUString aOutlineAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_OUTLINE)); + aObjectString = aOutlineAreaStr; + break; + } + case PresObjKind::Footer: + { + static OUString aFooterAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_FOOTER)); + aObjectString = aFooterAreaStr; + break; + } + case PresObjKind::Header: + { + static OUString aHeaderAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_HEADER)); + aObjectString = aHeaderAreaStr; + break; + } + case PresObjKind::DateTime: + { + static OUString aDateTimeStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_DATETIME)); + aObjectString = aDateTimeStr; + break; + } + case PresObjKind::Notes: + { + static OUString aDateTimeStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_NOTES)); + aObjectString = aDateTimeStr; + break; + } + case PresObjKind::SlideNumber: + { + if(pObjectsSdPage && pObjectsSdPage->GetPageKind() == PageKind::Standard) + { + static OUString aSlideAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_SLIDE)); + aObjectString = aSlideAreaStr; + } + else + { + static OUString aNumberAreaStr(SdResId(STR_PLACEHOLDER_DESCRIPTION_NUMBER)); + aObjectString = aNumberAreaStr; + } + break; + } + default: + { + break; + } + } + + if( !aObjectString.isEmpty() ) + { + // decompose object matrix to be able to place text correctly + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate, fShearX; + aObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX); + + // create font + SdrTextObj* pTextObj = DynCastSdrTextObj( pObject ); + const SdrTextVertAdjust eTVA(pTextObj ? pTextObj->GetTextVerticalAdjust() : SDRTEXTVERTADJUST_CENTER); + vcl::Font aScaledVclFont; + + // use a text size factor to get more reliable text sizes from the text layouter + // (and from vcl), tipp from HDU + static const sal_uInt32 nTextSizeFactor(100); + + // use a factor to get more linear text size calculations + aScaledVclFont.SetFontHeight( 500 * nTextSizeFactor ); + + // get basic geometry and get text size + drawinglayer::primitive2d::TextLayouterDevice aTextLayouter; + aTextLayouter.setFont(aScaledVclFont); + const sal_Int32 nTextLength(aObjectString.getLength()); + + // do not forget to use the factor again to get the width for the 500 + const double fTextWidth(aTextLayouter.getTextWidth(aObjectString, 0, nTextLength) * (1.0 / nTextSizeFactor)); + const double fTextHeight(aTextLayouter.getTextHeight() * (1.0 / nTextSizeFactor)); + + // calculate text primitive position. If text is at bottom, use top for + // the extra text and vice versa + const double fHorDist(125); + const double fVerDist(125); + const double fPosX((aTranslate.getX() + aScale.getX()) - fTextWidth - fHorDist); + const double fPosY((SDRTEXTVERTADJUST_BOTTOM == eTVA) + ? aTranslate.getY() - fVerDist + fTextHeight + : (aTranslate.getY() + aScale.getY()) - fVerDist); + + // get font attributes; use normally scaled font + vcl::Font aVclFont; + basegfx::B2DVector aTextSizeAttribute; + + aVclFont.SetFontHeight( 500 ); + + drawinglayer::attribute::FontAttribute aFontAttribute( + drawinglayer::primitive2d::getFontAttributeFromVclFont( + aTextSizeAttribute, + aVclFont, + false, + false)); + + // fill text matrix + const basegfx::B2DHomMatrix aTextMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( + aTextSizeAttribute.getX(), aTextSizeAttribute.getY(), + fShearX, + fRotate, + fPosX, fPosY)); + + // create DXTextArray (can be empty one) + ::std::vector< double > aDXArray{}; + + // create locale; this may need some more information in the future + css::lang::Locale aLocale; + + // create primitive and add + const drawinglayer::primitive2d::Primitive2DReference xRef( + new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( + aTextMatrix, + aObjectString, + 0, + nTextLength, + std::move(aDXArray), + {}, + std::move(aFontAttribute), + std::move(aLocale), + aRGBColor)); + rVisitor.visit(xRef); + } + } + } + } + } + + if(bDoCreateGeometry) + { + sdr::contact::ViewObjectContactRedirector::createRedirectedPrimitive2DSequence( + rOriginal, + rDisplayInfo, rVisitor); + } +} + +namespace +{ + void setOutlinerBgFromPage(::Outliner& rOutl, SdrPageView& rPgView, bool bScreenDisplay) + { + SdPage* pPage = static_cast<SdPage*>(rPgView.GetPage()); + if (pPage) + { + // #i75566# Name change GetBackgroundColor -> GetPageBackgroundColor and + // hint value if screen display. Only then the AutoColor mechanisms shall be applied + rOutl.SetBackgroundColor(pPage->GetPageBackgroundColor(&rPgView, bScreenDisplay)); + } + } +} + +/** + * The event will be forwarded to the View + */ +void View::CompleteRedraw(OutputDevice* pOutDev, const vcl::Region& rReg, sdr::contact::ViewObjectContactRedirector* pRedirector /*=0*/) +{ + // execute ?? + if (mnLockRedrawSmph != 0) + return; + + SdrPageView* pPgView = GetSdrPageView(); + + if (pPgView) + { + SdPage* pPage = static_cast<SdPage*>( pPgView->GetPage() ); + if( pPage ) + { + SdrOutliner& rOutl = mrDoc.GetDrawOutliner(); + bool bScreenDisplay(true); + + // #i75566# printing; suppress AutoColor BackgroundColor generation + // for visibility reasons by giving GetPageBackgroundColor() + // the needed hint + // #i75566# PDF export; suppress AutoColor BackgroundColor generation (see printing) + if (pOutDev && ((OUTDEV_PRINTER == pOutDev->GetOutDevType()) + || (OUTDEV_PDF == pOutDev->GetOutDevType()))) + bScreenDisplay = false; + + setOutlinerBgFromPage(rOutl, *pPgView, bScreenDisplay); + } + } + + ViewRedirector aViewRedirector; + FmFormView::CompleteRedraw(pOutDev, rReg, pRedirector ? pRedirector : &aViewRedirector); +} + +void View::MarkListHasChanged() +{ + FmFormView::MarkListHasChanged(); + + if( GetMarkedObjectCount() > 0 ) + maSmartTags.deselect(); +} + +bool View::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll, bool /*bSlide*/, bool /*bMaster*/) +{ + bool bOk = FmFormView::SetAttributes(rSet, bReplaceAll); + return bOk; +} + +void View::GetAttributes( SfxItemSet& rTargetSet, bool bOnlyHardAttr ) const +{ + FmFormView::GetAttributes( rTargetSet, bOnlyHardAttr ); +} + +/** + * Is a presentation object selected? + */ +bool View::IsPresObjSelected(bool bOnPage, bool bOnMasterPage, bool bCheckPresObjListOnly, bool bCheckLayoutOnly) const +{ + SdrMarkList* pMarkList; + + if (mnDragSrcPgNum != SDRPAGE_NOTFOUND && + mnDragSrcPgNum != GetSdrPageView()->GetPage()->GetPageNum()) + { + /* Drag&Drop is in progress + Source and destination page are different: + we use the saved mark list */ + pMarkList = mpDragSrcMarkList.get(); + } + else + { + // We use the current mark list + pMarkList = new SdrMarkList(GetMarkedObjectList()); + } + + SdrMark* pMark; + SdPage* pPage; + + bool bSelected = false; + bool bMasterPage = false; + + for (size_t nMark = pMarkList->GetMarkCount(); nMark && !bSelected; ) + { + --nMark; + // Backwards through mark list + pMark = pMarkList->GetMark(nMark); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + + if ( pObj && ( bCheckPresObjListOnly || pObj->IsEmptyPresObj() || pObj->GetUserCall() ) ) + { + pPage = static_cast<SdPage*>( pObj->getSdrPageFromSdrObject() ); + bMasterPage = pPage && pPage->IsMasterPage(); + + if ( (bMasterPage && bOnMasterPage) || (!bMasterPage && bOnPage) ) + { + if ( pPage && pPage->IsPresObj(pObj) ) + { + if( bCheckLayoutOnly ) + { + PresObjKind eKind = pPage->GetPresObjKind(pObj); + + if((eKind != PresObjKind::Footer) && (eKind != PresObjKind::Header) && (eKind != PresObjKind::DateTime) && (eKind != PresObjKind::SlideNumber) ) + bSelected = true; + } + else + { + bSelected = true; + } + } + } + } + } + + if (pMarkList != mpDragSrcMarkList.get()) + { + delete pMarkList; + } + + return bSelected; +} + +void View::SelectAll() +{ + if ( IsTextEdit() ) + { + OutlinerView* pOLV = GetTextEditOutlinerView(); + const ::Outliner* pOutliner = GetTextEditOutliner(); + pOLV->SelectRange( 0, pOutliner->GetParagraphCount() ); + } + else + { + MarkAll(); + } +} + +bool View::SetStyleSheet(SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr) +{ + // forward to SdrView + FmFormView::SetStyleSheet(pStyleSheet, bDontRemoveHardAttr); + return true; +} + +/** + * Start text input + */ +static void SetSpellOptions( const SdDrawDocument& rDoc, EEControlBits& rCntrl ) +{ + bool bOnlineSpell = rDoc.GetOnlineSpell(); + + if( bOnlineSpell ) + rCntrl |= EEControlBits::ONLINESPELLING; + else + rCntrl &= ~EEControlBits::ONLINESPELLING; +} + +void OutlinerMasterViewFilter::Start(SdrOutliner *pOutl) +{ + m_pOutl = pOutl; + OutlinerView* pOutlView = m_pOutl->GetView(0); + m_bReadOnly = pOutlView->IsReadOnly(); + pOutlView->SetReadOnly(true); +} + +void OutlinerMasterViewFilter::End() +{ + if (m_pOutl) + { + OutlinerView* pOutlView = m_pOutl->GetView(0); + pOutlView->SetReadOnly(m_bReadOnly); + m_pOutl = nullptr; + } +} + +SfxViewShell* View::GetSfxViewShell() const +{ + SfxViewShell* pRet = nullptr; + + if (mpViewSh) + pRet = &mpViewSh->GetViewShellBase(); + + return pRet; +} + +// Create a new view-local UndoManager manager for Impress/Draw +std::unique_ptr<SdrUndoManager> View::createLocalTextUndoManager() +{ + std::unique_ptr<SdrUndoManager> pUndoManager(new sd::UndoManager); + pUndoManager->SetDocShell(mpDocSh); + return pUndoManager; +} + +bool View::SdrBeginTextEdit( + SdrObject* pObj, SdrPageView* pPV, vcl::Window* pWin, + bool bIsNewObj, + SdrOutliner* pOutl, OutlinerView* pGivenOutlinerView, + bool bDontDeleteOutliner, bool bOnlyOneView, bool bGrabFocus ) +{ + SdrPage* pPage = pObj ? pObj->getSdrPageFromSdrObject() : nullptr; + bool bMasterPage = pPage && pPage->IsMasterPage(); + + GetViewShell()->GetViewShellBase().GetEventMultiplexer()->MultiplexEvent( + EventMultiplexerEventId::BeginTextEdit, static_cast<void*>(pObj) ); + + if( pOutl==nullptr && pObj ) + pOutl = SdrMakeOutliner(OutlinerMode::TextObject, pObj->getSdrModelFromSdrObject()).release(); + + // make draw&impress specific initialisations + if( pOutl ) + { + pOutl->SetStyleSheetPool(static_cast<SfxStyleSheetPool*>( mrDoc.GetStyleSheetPool() )); + pOutl->SetCalcFieldValueHdl(LINK(SD_MOD(), SdModule, CalcFieldValueHdl)); + EEControlBits nCntrl = pOutl->GetControlWord(); + nCntrl |= EEControlBits::ALLOWBIGOBJS; + nCntrl |= EEControlBits::MARKFIELDS; + nCntrl |= EEControlBits::AUTOCORRECT; + + nCntrl &= ~EEControlBits::ULSPACESUMMATION; + if ( mrDoc.IsSummationOfParagraphs() ) + nCntrl |= EEControlBits::ULSPACESUMMATION; + + SetSpellOptions( mrDoc, nCntrl ); + + pOutl->SetControlWord(nCntrl); + + Reference< linguistic2::XSpellChecker1 > xSpellChecker( LinguMgr::GetSpellChecker() ); + if ( xSpellChecker.is() ) + pOutl->SetSpeller( xSpellChecker ); + + Reference< linguistic2::XHyphenator > xHyphenator( LinguMgr::GetHyphenator() ); + if( xHyphenator.is() ) + pOutl->SetHyphenator( xHyphenator ); + + pOutl->SetDefaultLanguage( Application::GetSettings().GetLanguageTag().getLanguageType() ); + } + + bool bReturn = FmFormView::SdrBeginTextEdit( + pObj, pPV, pWin, bIsNewObj, pOutl, + pGivenOutlinerView, bDontDeleteOutliner, + bOnlyOneView, bGrabFocus); + + if ( mpViewSh ) + { + mpViewSh->GetViewShellBase().GetDrawController()->FireSelectionChangeListener(); + + if (pObj && pObj->GetObjIdentifier() == SdrObjKind::Table) + mpViewSh->UpdateScrollBars(); + + if (comphelper::LibreOfficeKit::isActive()) + { + if (OutlinerView* pView = GetTextEditOutlinerView()) + { + ::tools::Rectangle aRectangle = pView->GetOutputArea(); + if (pWin && pWin->GetMapMode().GetMapUnit() == MapUnit::Map100thMM) + { + aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip); + } + OString sRectangle = aRectangle.toString(); + SfxLokHelper::notifyOtherViews(&mpViewSh->GetViewShellBase(), LOK_CALLBACK_VIEW_LOCK, "rectangle", sRectangle); + } + } + } + + if (::Outliner* pOL = bReturn ? GetTextEditOutliner() : nullptr) + { + if (pObj) + { + if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::Table ) + { + Color aBackground = GetTextEditBackgroundColor(*this); + pOL->SetBackgroundColor( aBackground ); + } + else + { + // tdf#148140 Set the background to determine autocolor. + // Use any explicit bg with fallback to underlying page if + // none found + if (!pObj->setSuitableOutlinerBg(*pOL) && pPV) + setOutlinerBgFromPage(*pOL, *pPV, true); + } + } + + pOL->SetParaInsertedHdl(LINK(this, View, OnParagraphInsertedHdl)); + pOL->SetParaRemovingHdl(LINK(this, View, OnParagraphRemovingHdl)); + } + + if (bMasterPage && bReturn && pOutl) + { + const SdrTextObj* pTextObj = pOutl->GetTextObj(); + const SdPage* pSdPage = pTextObj ? static_cast<const SdPage*>(pTextObj->getSdrPageFromSdrObject()) : nullptr; + const PresObjKind eKind = pSdPage ? pSdPage->GetPresObjKind(const_cast<SdrTextObj*>(pTextObj)) : PresObjKind::NONE; + switch (eKind) + { + case PresObjKind::Title: + case PresObjKind::Outline: + case PresObjKind::Text: + maMasterViewFilter.Start(pOutl); + break; + default: + break; + } + } + + return bReturn; +} + +/** ends current text editing */ +SdrEndTextEditKind View::SdrEndTextEdit(bool bDontDeleteReally) +{ + maMasterViewFilter.End(); + + SdrTextObj* xObj = GetTextEditObject(); + + bool bDefaultTextRestored = RestoreDefaultText( xObj ); + + SdrEndTextEditKind eKind = FmFormView::SdrEndTextEdit(bDontDeleteReally); + + if( bDefaultTextRestored ) + { + if( xObj && !xObj->IsEmptyPresObj() ) + { + xObj->SetEmptyPresObj( true ); + } + else + { + eKind = SdrEndTextEditKind::Unchanged; + } + } + else if( xObj && xObj->IsEmptyPresObj() ) + { + if( xObj && xObj->HasText() ) + { + SdrPage* pPage = xObj->getSdrPageFromSdrObject(); + if( !pPage || !pPage->IsMasterPage() ) + xObj->SetEmptyPresObj( false ); + } + } + + GetViewShell()->GetViewShellBase().GetEventMultiplexer()->MultiplexEvent( + EventMultiplexerEventId::EndTextEdit, + static_cast<void*>(xObj) ); + + if( xObj ) + { + if ( mpViewSh ) + { + mpViewSh->GetViewShellBase().GetDrawController()->FireSelectionChangeListener(); + + if (comphelper::LibreOfficeKit::isActive()) + SfxLokHelper::notifyOtherViews(&mpViewSh->GetViewShellBase(), LOK_CALLBACK_VIEW_LOCK, "rectangle", "EMPTY"_ostr); + + } + + SdPage* pPage = dynamic_cast< SdPage* >( xObj->getSdrPageFromSdrObject() ); + if( pPage ) + pPage->onEndTextEdit( xObj ); + } + + return eKind; +} + +/** restores the default text if the given text object is currently in edit mode and + no text has been entered already. Is only useful just before text edit ends. */ +bool View::RestoreDefaultText( SdrTextObj* pTextObj ) +{ + bool bRestored = false; + + if( pTextObj && (pTextObj == GetTextEditObject()) ) + { + if( !pTextObj->HasText() ) + { + SdPage* pPage = dynamic_cast< SdPage* >( pTextObj->getSdrPageFromSdrObject() ); + + if(pPage) + { + bRestored = pPage->RestoreDefaultText( pTextObj ); + if( bRestored ) + { + SdrOutliner* pOutliner = GetTextEditOutliner(); + pTextObj->SetTextEditOutliner( pOutliner ); + OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject(); + if (pOutliner) + pOutliner->SetText(*pParaObj); + } + } + } + } + + return bRestored; +} + +/** + * Sets the original size of the marked objects. + */ +void View::SetMarkedOriginalSize() +{ + std::unique_ptr<SdrUndoGroup> pUndoGroup(new SdrUndoGroup(mrDoc)); + const size_t nCount = GetMarkedObjectCount(); + bool bOK = false; + + for( size_t i = 0; i < nCount; ++i ) + { + SdrObject* pObj = GetMarkedObjectByIndex(i); + + if( pObj->GetObjInventor() == SdrInventor::Default ) + { + if( pObj->GetObjIdentifier() == SdrObjKind::OLE2 ) + { + uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObj)->GetObjRef(); + if( xObj.is() ) + { + // TODO/LEAN: working with VisualArea can switch object to running state + + sal_Int64 nAspect = static_cast<SdrOle2Obj*>(pObj)->GetAspect(); + Size aOleSize; + + if ( nAspect == embed::Aspects::MSOLE_ICON ) + { + MapMode aMap100( MapUnit::Map100thMM ); + aOleSize = static_cast<SdrOle2Obj*>(pObj)->GetOrigObjSize( &aMap100 ); + bOK = true; + } + else + { + MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) ); + try + { + awt::Size aSz = xObj->getVisualAreaSize( nAspect ); + aOleSize = OutputDevice::LogicToLogic(Size(aSz.Width, aSz.Height), MapMode(aUnit), MapMode(MapUnit::Map100thMM)); + bOK = true; + } + catch( embed::NoVisualAreaSizeException& ) + {} + } + + if ( bOK ) + { + ::tools::Rectangle aDrawRect( pObj->GetLogicRect() ); + + pUndoGroup->AddAction( mrDoc.GetSdrUndoFactory().CreateUndoGeoObject( *pObj ) ); + pObj->Resize( aDrawRect.TopLeft(), Fraction( aOleSize.Width(), aDrawRect.GetWidth() ), + Fraction( aOleSize.Height(), aDrawRect.GetHeight() ) ); + } + } + } + else if( pObj->GetObjIdentifier() == SdrObjKind::Graphic ) + { + const SdrGrafObj* pSdrGrafObj = static_cast< const SdrGrafObj* >(pObj); + const Size aSize = pSdrGrafObj->getOriginalSize( ); + pUndoGroup->AddAction(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj)); + ::tools::Rectangle aRect( pObj->GetLogicRect() ); + aRect.SetSize( aSize ); + pObj->SetLogicRect( aRect ); + bOK = true; + } + } + } + + if( bOK ) + { + pUndoGroup->SetComment(SdResId(STR_UNDO_ORIGINALSIZE)); + mpDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup)); + } +} + +/** + * Connect OLE object to client. + */ +void View::DoConnect(SdrOle2Obj* pObj) +{ + if (!mpViewSh) + return; + + uno::Reference < embed::XEmbeddedObject > xObj( pObj->GetObjRef() ); + if( !xObj.is() ) + return; + + ::sd::Window* pWindow = mpViewSh->GetActiveWindow(); + SfxInPlaceClient* pSdClient = mpViewSh-> GetViewShellBase().FindIPClient( xObj, pWindow ); + if ( pSdClient ) + return; + + pSdClient = new Client(pObj, mpViewSh, pWindow); + ::tools::Rectangle aRect = pObj->GetLogicRect(); + { + // TODO/LEAN: working with visual area can switch object to running state + Size aDrawSize = aRect.GetSize(); + + MapMode aMapMode( mrDoc.GetScaleUnit() ); + Size aObjAreaSize = pObj->GetOrigObjSize( &aMapMode ); + + Fraction aScaleWidth (aDrawSize.Width(), aObjAreaSize.Width() ); + Fraction aScaleHeight(aDrawSize.Height(), aObjAreaSize.Height() ); + aScaleWidth.ReduceInaccurate(10); // compatible to SdrOle2Obj + aScaleHeight.ReduceInaccurate(10); + pSdClient->SetSizeScale(aScaleWidth, aScaleHeight); + + // visible area is only changed in-place! + // the object area must be set after the scaling, since it triggers resize + aRect.SetSize(aObjAreaSize); + pSdClient->SetObjArea(aRect); + } +} + +bool View::IsMorphingAllowed() const +{ + const SdrMarkList& rMarkList = GetMarkedObjectList(); + bool bRet = false; + + if ( rMarkList.GetMarkCount() == 2 ) + { + const SdrObject* pObj1 = rMarkList.GetMark( 0 )->GetMarkedSdrObj(); + const SdrObject* pObj2 = rMarkList.GetMark( 1 )->GetMarkedSdrObj(); + const SdrObjKind nKind1 = pObj1->GetObjIdentifier(); + const SdrObjKind nKind2 = pObj2->GetObjIdentifier(); + + if ( ( nKind1 != SdrObjKind::Text && nKind2 != SdrObjKind::Text ) && + ( nKind1 != SdrObjKind::TitleText && nKind2 != SdrObjKind::TitleText ) && + ( nKind1 != SdrObjKind::OutlineText && nKind2 != SdrObjKind::OutlineText ) && + ( nKind1 != SdrObjKind::Group && nKind2 != SdrObjKind::Group ) && + ( nKind1 != SdrObjKind::Line && nKind2 != SdrObjKind::Line ) && + ( nKind1 != SdrObjKind::PolyLine && nKind2 != SdrObjKind::PolyLine ) && + ( nKind1 != SdrObjKind::PathLine && nKind2 != SdrObjKind::PathLine ) && + ( nKind1 != SdrObjKind::FreehandLine && nKind2 != SdrObjKind::FreehandLine ) && + ( nKind1 != SdrObjKind::PathPolyLine && nKind2 != SdrObjKind::PathPolyLine ) && + ( nKind1 != SdrObjKind::Measure && nKind2 != SdrObjKind::Measure ) && + ( nKind1 != SdrObjKind::Edge && nKind2 != SdrObjKind::Edge ) && + ( nKind1 != SdrObjKind::Graphic && nKind2 != SdrObjKind::Graphic ) && + ( nKind1 != SdrObjKind::OLE2 && nKind2 != SdrObjKind::OLE2 ) && + ( nKind1 != SdrObjKind::Caption && nKind2 != SdrObjKind::Caption ) && + DynCastE3dObject( pObj1 ) == nullptr && DynCastE3dObject( pObj2 ) == nullptr ) + { + SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLSTYLE> aSet1( mrDoc.GetPool() ); + SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLSTYLE> aSet2( mrDoc.GetPool() ); + + aSet1.Put(pObj1->GetMergedItemSet()); + aSet2.Put(pObj2->GetMergedItemSet()); + + const drawing::FillStyle eFillStyle1 = aSet1.Get( XATTR_FILLSTYLE ).GetValue(); + const drawing::FillStyle eFillStyle2 = aSet2.Get( XATTR_FILLSTYLE ).GetValue(); + + if( ( eFillStyle1 == drawing::FillStyle_NONE || eFillStyle1 == drawing::FillStyle_SOLID ) && + ( eFillStyle2 == drawing::FillStyle_NONE || eFillStyle2 == drawing::FillStyle_SOLID ) ) + bRet = true; + } + } + + return bRet; +} + +bool View::IsVectorizeAllowed() const +{ + const SdrMarkList& rMarkList = GetMarkedObjectList(); + bool bRet = false; + + if( rMarkList.GetMarkCount() == 1 ) + { + const SdrGrafObj* pObj = dynamic_cast< const SdrGrafObj* >(rMarkList.GetMark( 0 )->GetMarkedSdrObj()); + + if(pObj) + { + if(GraphicType::Bitmap == pObj->GetGraphicType() && !pObj->isEmbeddedVectorGraphicData()) + { + bRet = true; + } + } + } + + return bRet; +} + +void View::onAccessibilityOptionsChanged() +{ + if( !mpViewSh ) + return; + + ::sd::Window* pWindow = mpViewSh->GetActiveWindow(); + if( !pWindow ) + return; + + const StyleSettings& rStyleSettings = pWindow->GetSettings().GetStyleSettings(); + + if( mpViewSh->GetViewFrame() && mpViewSh->GetViewFrame()->GetDispatcher() ) + { + sal_uInt16 nOutputSlot, nPreviewSlot; + + if( rStyleSettings.GetHighContrastMode() ) + { + nOutputSlot = SID_OUTPUT_QUALITY_CONTRAST; + } + else + { + nOutputSlot = SID_OUTPUT_QUALITY_COLOR; + } + + if( rStyleSettings.GetHighContrastMode() + && officecfg::Office::Common::Accessibility::IsForPagePreviews::get() ) + { + nPreviewSlot = SID_PREVIEW_QUALITY_CONTRAST; + } + else + { + nPreviewSlot = SID_PREVIEW_QUALITY_COLOR; + } + + mpViewSh->GetViewFrame()->GetDispatcher()->Execute( nOutputSlot, SfxCallMode::ASYNCHRON ); + mpViewSh->GetViewFrame()->GetDispatcher()->Execute( nPreviewSlot, SfxCallMode::ASYNCHRON ); + } + + mpViewSh->Invalidate(); +} + +IMPL_LINK( View, OnParagraphInsertedHdl, ::Outliner::ParagraphHdlParam, aParam, void ) +{ + SdrObject* pObj = GetTextEditObject(); + + if( aParam.pPara && pObj ) + { + SdPage* pPage = dynamic_cast< SdPage* >( pObj->getSdrPageFromSdrObject() ); + if( pPage ) + pPage->onParagraphInserted( aParam.pOutliner, aParam.pPara, pObj ); + } +} + +/** + * Handler for the deletion of the pages (paragraphs). + */ +IMPL_LINK( View, OnParagraphRemovingHdl, ::Outliner::ParagraphHdlParam, aParam, void ) +{ + SdrObject* pObj = GetTextEditObject(); + + if( aParam.pPara && pObj ) + { + SdPage* pPage = dynamic_cast< SdPage* >( pObj->getSdrPageFromSdrObject() ); + if( pPage ) + pPage->onParagraphRemoving( aParam.pOutliner, aParam.pPara, pObj ); + } +} + +bool View::isRecordingUndo() const +{ + if( mrDoc.IsUndoEnabled() ) + { + sd::UndoManager* pUndoManager = mrDoc.GetUndoManager(); + return pUndoManager && pUndoManager->IsInListAction(); + } + else + { + return false; + } +} + +void View::AddCustomHdl() +{ + maSmartTags.addCustomHandles( maHdlList ); +} + +void View::updateHandles() +{ + AdjustMarkHdl(); +} + +SdrViewContext View::GetContext() const +{ + SdrViewContext eContext = SdrViewContext::Standard; + if( maSmartTags.getContext( eContext ) ) + return eContext; + else + return FmFormView::GetContext(); +} + +bool View::HasMarkablePoints() const +{ + if( maSmartTags.HasMarkablePoints() ) + return true; + else + return FmFormView::HasMarkablePoints(); +} + +sal_Int32 View::GetMarkablePointCount() const +{ + sal_Int32 nCount = FmFormView::GetMarkablePointCount(); + nCount += maSmartTags.GetMarkablePointCount(); + return nCount; +} + +bool View::HasMarkedPoints() const +{ + if( maSmartTags.HasMarkedPoints() ) + return true; + else + return FmFormView::HasMarkedPoints(); +} + +bool View::MarkPoint(SdrHdl& rHdl, bool bUnmark ) +{ + if( maSmartTags.MarkPoint( rHdl, bUnmark ) ) + return true; + else + return FmFormView::MarkPoint( rHdl, bUnmark ); +} + +bool View::MarkPoints(const ::tools::Rectangle* pRect, bool bUnmark) +{ + if( maSmartTags.MarkPoints( pRect, bUnmark ) ) + return true; + else + return FmFormView::MarkPoints( pRect, bUnmark ); +} + +void View::CheckPossibilities() +{ + FmFormView::CheckPossibilities(); + maSmartTags.CheckPossibilities(); +} + +void View::OnBeginPasteOrDrop( PasteOrDropInfos* pInfo ) +{ + SdrOutliner* pOutliner = GetTextEditOutliner(); + if (!pOutliner) + return; + + // Turn character attributes of the paragraph of the insert position into + // character-level attributes, so they are not lost when OnEndPasteOrDrop() + // sets the paragraph stylesheet. + SfxItemSet aSet(pOutliner->GetParaAttribs(pInfo->nStartPara)); + pOutliner->SetCharAttribs(pInfo->nStartPara, aSet); +} + +/** this is called after a paste or drop operation, make sure that the newly inserted paragraphs + get the correct style sheet. */ +void View::OnEndPasteOrDrop( PasteOrDropInfos* pInfo ) +{ + /* Style Sheet handling */ + SdrTextObj* pTextObj = GetTextEditObject(); + SdrOutliner* pOutliner = GetTextEditOutliner(); + if( !pOutliner || !pTextObj || !pTextObj->getSdrPageFromSdrObject() ) + return; + + SdPage* pPage = static_cast< SdPage* >( pTextObj->getSdrPageFromSdrObject() ); + const PresObjKind eKind = pPage->GetPresObjKind(pTextObj); + + // outline kinds are taken care of in Outliner::ImplSetLevelDependentStyleSheet + if( eKind == PresObjKind::Outline ) + return; + + SfxStyleSheet* pStyleSheet = nullptr; + if( eKind != PresObjKind::NONE ) + pStyleSheet = pPage->GetStyleSheetForPresObj(eKind); + else + pStyleSheet = pTextObj->GetStyleSheet(); + // just put the object style on each new paragraph + for ( sal_Int32 nPara = pInfo->nStartPara; nPara <= pInfo->nEndPara; nPara++ ) + { + pOutliner->SetStyleSheet( nPara, pStyleSheet ); + } +} + +bool View::ShouldToggleOn( + const bool bBulletOnOffMode, + const bool bNormalBullet) +{ + // If setting bullets/numbering by the dialog, always should toggle on. + if (!bBulletOnOffMode) + return true; + SdrModel& rSdrModel = GetModel(); + + bool bToggleOn = false; + std::unique_ptr<SdrOutliner> pOutliner(SdrMakeOutliner(OutlinerMode::TextObject, rSdrModel)); + const size_t nMarkCount = GetMarkedObjectCount(); + for (size_t nIndex = 0; nIndex < nMarkCount && !bToggleOn; ++nIndex) + { + SdrTextObj* pTextObj = DynCastSdrTextObj(GetMarkedObjectByIndex(nIndex)); + if (!pTextObj || pTextObj->IsTextEditActive()) + continue; + if( dynamic_cast< const SdrTableObj *>( pTextObj ) != nullptr) + { + SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >(pTextObj); + if (!pTableObj) + continue; + CellPos aStart, aEnd; + SvxTableController* pTableController = dynamic_cast< SvxTableController* >(getSelectionController().get()); + if (pTableController) + { + pTableController->getSelectedCells(aStart, aEnd); + } + else + { + aStart = SdrTableObj::getFirstCell(); + aEnd = pTableObj->getLastCell(); + } + sal_Int32 nColCount = pTableObj->getColumnCount(); + for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow && !bToggleOn; nRow++) + { + for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol && !bToggleOn; nCol++) + { + sal_Int32 nCellIndex = nRow * nColCount + nCol; + SdrText* pText = pTableObj->getText(nCellIndex); + if (!pText || !pText->GetOutlinerParaObject()) + continue; + pOutliner->SetText(*(pText->GetOutlinerParaObject())); + sal_Int16 nStatus = pOutliner->GetBulletsNumberingStatus(); + bToggleOn = (bNormalBullet && nStatus != 0) || (!bNormalBullet && nStatus != 1); + pOutliner->Clear(); + } + } + } + else + { + OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject(); + if (!pParaObj) + continue; + pOutliner->SetText(*pParaObj); + sal_Int16 nStatus = pOutliner->GetBulletsNumberingStatus(); + bToggleOn = (bNormalBullet && nStatus != 0) || (!bNormalBullet && nStatus != 1); + pOutliner->Clear(); + } + } + return bToggleOn; +} + +void View::ChangeMarkedObjectsBulletsNumbering( + const bool bToggle, + const bool bHandleBullets, + const SvxNumRule* pNumRule ) +{ + SdrModel& rSdrModel = GetModel(); + OutputDevice* pOut = GetFirstOutputDevice(); + vcl::Window* pWindow = pOut ? pOut->GetOwnerWindow() : nullptr; + if (!pWindow) + return; + + const bool bUndoEnabled = rSdrModel.IsUndoEnabled(); + std::unique_ptr<SdrUndoGroup> pUndoGroup(bUndoEnabled ? new SdrUndoGroup(rSdrModel) : nullptr); + + const bool bToggleOn = ShouldToggleOn( bToggle, bHandleBullets ); + + std::unique_ptr<SdrOutliner> pOutliner(SdrMakeOutliner(OutlinerMode::TextObject, rSdrModel)); + OutlinerView aOutlinerView(pOutliner.get(), pWindow); + + const size_t nMarkCount = GetMarkedObjectCount(); + for (size_t nIndex = 0; nIndex < nMarkCount; ++nIndex) + { + SdrTextObj* pTextObj = DynCastSdrTextObj(GetMarkedObjectByIndex(nIndex)); + if (!pTextObj || pTextObj->IsTextEditActive()) + continue; + if( dynamic_cast< SdrTableObj *>( pTextObj ) != nullptr) + { + SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >(pTextObj); + if (!pTableObj) + continue; + CellPos aStart, aEnd; + SvxTableController* pTableController = dynamic_cast< SvxTableController* >(getSelectionController().get()); + if (pTableController) + { + pTableController->getSelectedCells(aStart, aEnd); + } + else + { + aStart = SdrTableObj::getFirstCell(); + aEnd = pTableObj->getLastCell(); + } + sal_Int32 nColCount = pTableObj->getColumnCount(); + for (sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++) + { + for (sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++) + { + sal_Int32 nCellIndex = nRow * nColCount + nCol; + SdrText* pText = pTableObj->getText(nCellIndex); + if (!pText || !pText->GetOutlinerParaObject()) + continue; + + pOutliner->SetText(*(pText->GetOutlinerParaObject())); + if (bUndoEnabled) + { + pUndoGroup->AddAction(rSdrModel.GetSdrUndoFactory().CreateUndoObjectSetText(*pTextObj, nCellIndex)); + } + if ( !bToggleOn ) + { + aOutlinerView.SwitchOffBulletsNumbering(); + } + else + { + aOutlinerView.ApplyBulletsNumbering( bHandleBullets, pNumRule, bToggle ); + } + sal_uInt32 nParaCount = pOutliner->GetParagraphCount(); + pText->SetOutlinerParaObject(pOutliner->CreateParaObject(0, static_cast<sal_uInt16>(nParaCount))); + pOutliner->Clear(); + } + } + // Broadcast the object change event. + if (!pTextObj->AdjustTextFrameWidthAndHeight()) + { + pTextObj->SetChanged(); + pTextObj->BroadcastObjectChange(); + } + } + else + { + OutlinerParaObject* pParaObj = pTextObj->GetOutlinerParaObject(); + if (!pParaObj) + continue; + pOutliner->SetText(*pParaObj); + if (bUndoEnabled) + { + pUndoGroup->AddAction( + rSdrModel.GetSdrUndoFactory().CreateUndoObjectSetText(*pTextObj, 0)); + } + if ( !bToggleOn ) + { + aOutlinerView.SwitchOffBulletsNumbering(); + } + else + { + aOutlinerView.ApplyBulletsNumbering( bHandleBullets, pNumRule, bToggle ); + } + sal_uInt32 nParaCount = pOutliner->GetParagraphCount(); + pTextObj->SetOutlinerParaObject(pOutliner->CreateParaObject(0, static_cast<sal_uInt16>(nParaCount))); + pOutliner->Clear(); + } + } + + if ( bUndoEnabled && pUndoGroup->GetActionCount() > 0 ) + { + rSdrModel.BegUndo(); + rSdrModel.AddUndo(std::move(pUndoGroup)); + rSdrModel.EndUndo(); + } +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/sdview2.cxx b/sd/source/ui/view/sdview2.cxx new file mode 100644 index 0000000000..af76e39afd --- /dev/null +++ b/sd/source/ui/view/sdview2.cxx @@ -0,0 +1,910 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <View.hxx> + +#include <vector> +#include <com/sun/star/embed/XEmbedPersist.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <comphelper/sequenceashashmap.hxx> +#include <tools/urlobj.hxx> +#include <svx/svdoole2.hxx> +#include <svx/svxdlg.hxx> +#include <sfx2/docfile.hxx> +#include <svx/svdundo.hxx> +#include <svx/svdpagv.hxx> +#include <svl/urlbmk.hxx> +#include <editeng/outliner.hxx> +#include <svx/xflclit.hxx> +#include <sot/formats.hxx> +#include <editeng/editeng.hxx> + +#include <svtools/embedtransfer.hxx> +#include <tools/debug.hxx> + +#include <anminfo.hxx> +#include <strings.hrc> +#include <sdxfer.hxx> +#include <sdresid.hxx> +#include <sdmod.hxx> +#include <sdtreelb.hxx> +#include <DrawViewShell.hxx> +#include <DrawDocShell.hxx> +#include <fudraw.hxx> +#include <drawdoc.hxx> +#include <Window.hxx> +#include <sdpage.hxx> +#include <unoaprms.hxx> +#include <helpids.h> +#include <vcl/svapp.hxx> + +#include <slideshow.hxx> +#include <memory> + +namespace sd { + +using namespace ::com::sun::star; + +namespace { + +struct SdNavigatorDropEvent : public ExecuteDropEvent +{ + VclPtr< ::sd::Window> mpTargetWindow; + + SdNavigatorDropEvent ( + const ExecuteDropEvent& rEvt, + ::sd::Window* pTargetWindow ) + : ExecuteDropEvent( rEvt ), + mpTargetWindow( pTargetWindow ) + {} +}; + +} + +css::uno::Reference< css::datatransfer::XTransferable > View::CreateClipboardDataObject() +{ + // since SdTransferable::CopyToClipboard is called, this + // dynamically created object is destroyed automatically + rtl::Reference<SdTransferable> pTransferable = new SdTransferable( &mrDoc, nullptr, false ); + + SD_MOD()->pTransferClip = pTransferable.get(); + + mrDoc.CreatingDataObj( pTransferable.get() ); + pTransferable->SetWorkDocument( static_cast<SdDrawDocument*>(CreateMarkedObjModel().release()) ); + mrDoc.CreatingDataObj( nullptr ); + + // #112978# need to use GetAllMarkedBoundRect instead of GetAllMarkedRect to get + // fat lines correctly + const ::tools::Rectangle aMarkRect( GetAllMarkedBoundRect() ); + std::unique_ptr<TransferableObjectDescriptor> pObjDesc(new TransferableObjectDescriptor); + SdrOle2Obj* pSdrOleObj = nullptr; + SdrPageView* pPgView = GetSdrPageView(); + SdPage* pOldPage = pPgView ? static_cast<SdPage*>( pPgView->GetPage() ) : nullptr; + SdPage* pNewPage = const_cast<SdPage*>(static_cast<const SdPage*>( pTransferable->GetWorkDocument()->GetPage( 0 ) )); + + if( pOldPage ) + { + pNewPage->SetSize( pOldPage->GetSize() ); + pNewPage->SetLayoutName( pOldPage->GetLayoutName() ); + } + + if( GetMarkedObjectCount() == 1 ) + { + SdrObject* pObj = GetMarkedObjectByIndex(0); + + if( auto pOle2Obj = dynamic_cast<SdrOle2Obj *>( pObj ) ) + if( pOle2Obj->GetObjRef() ) + { + // If object has no persistence it must be copied as part of the document + try + { + uno::Reference< embed::XEmbedPersist > xPersObj( pOle2Obj->GetObjRef(), uno::UNO_QUERY ); + if ( xPersObj.is() && xPersObj->hasEntry() ) + pSdrOleObj = pOle2Obj; + } + catch( uno::Exception& ) + {} + } + } + + if( pSdrOleObj ) + SvEmbedTransferHelper::FillTransferableObjectDescriptor( *pObjDesc, pSdrOleObj->GetObjRef(), pSdrOleObj->GetGraphic(), pSdrOleObj->GetAspect() ); + else + pTransferable->GetWorkDocument()->GetDocSh()->FillTransferableObjectDescriptor( *pObjDesc ); + + if( mpDocSh ) + pObjDesc->maDisplayName = mpDocSh->GetMedium()->GetURLObject().GetURLNoPass(); + + pObjDesc->maSize = aMarkRect.GetSize(); + + pTransferable->SetStartPos( aMarkRect.TopLeft() ); + pTransferable->SetObjectDescriptor( std::move(pObjDesc) ); + pTransferable->CopyToClipboard( mpViewSh->GetActiveWindow() ); + + return pTransferable; +} + +css::uno::Reference< css::datatransfer::XTransferable > View::CreateDragDataObject( View* pWorkView, vcl::Window& rWindow, const Point& rDragPos ) +{ + rtl::Reference<SdTransferable> pTransferable = new SdTransferable( &mrDoc, pWorkView, false ); + + SD_MOD()->pTransferDrag = pTransferable.get(); + + std::unique_ptr<TransferableObjectDescriptor> pObjDesc(new TransferableObjectDescriptor); + OUString aDisplayName; + SdrOle2Obj* pSdrOleObj = nullptr; + + if( GetMarkedObjectCount() == 1 ) + { + SdrObject* pObj = GetMarkedObjectByIndex( 0 ); + + if( auto pOle2Obj = dynamic_cast<SdrOle2Obj *>( pObj ) ) + if( pOle2Obj->GetObjRef() ) + { + // If object has no persistence it must be copied as part of the document + try + { + uno::Reference< embed::XEmbedPersist > xPersObj( pOle2Obj->GetObjRef(), uno::UNO_QUERY ); + if ( xPersObj.is() && xPersObj->hasEntry() ) + pSdrOleObj = pOle2Obj; + } + catch( uno::Exception& ) + {} + } + } + + if( mpDocSh ) + aDisplayName = mpDocSh->GetMedium()->GetURLObject().GetURLNoPass(); + + if( pSdrOleObj ) + SvEmbedTransferHelper::FillTransferableObjectDescriptor( *pObjDesc, pSdrOleObj->GetObjRef(), pSdrOleObj->GetGraphic(), pSdrOleObj->GetAspect() ); + else if (mpDocSh) + mpDocSh->FillTransferableObjectDescriptor( *pObjDesc ); + + pObjDesc->maSize = GetAllMarkedRect().GetSize(); + pObjDesc->maDragStartPos = rDragPos; + pObjDesc->maDisplayName = aDisplayName; + + pTransferable->SetStartPos( rDragPos ); + pTransferable->SetObjectDescriptor( std::move(pObjDesc) ); + pTransferable->StartDrag( &rWindow, DND_ACTION_COPYMOVE | DND_ACTION_LINK ); + + return pTransferable; +} + +css::uno::Reference< css::datatransfer::XTransferable > View::CreateSelectionDataObject( View* pWorkView ) +{ + rtl::Reference<SdTransferable> pTransferable = new SdTransferable( &mrDoc, pWorkView, true ); + std::unique_ptr<TransferableObjectDescriptor> pObjDesc(new TransferableObjectDescriptor); + const ::tools::Rectangle aMarkRect( GetAllMarkedRect() ); + + SD_MOD()->pTransferSelection = pTransferable.get(); + + if( mpDocSh ) + { + mpDocSh->FillTransferableObjectDescriptor( *pObjDesc ); + pObjDesc->maDisplayName = mpDocSh->GetMedium()->GetURLObject().GetURLNoPass(); + } + + pObjDesc->maSize = aMarkRect.GetSize(); + + pTransferable->SetStartPos( aMarkRect.TopLeft() ); + pTransferable->SetObjectDescriptor( std::move(pObjDesc) ); + pTransferable->CopyToPrimarySelection(); + + return pTransferable; +} + +void View::UpdateSelectionClipboard() // false case +{ + if (!mpViewSh) + return; + if (!mpViewSh->GetActiveWindow()) + return; + if (GetMarkedObjectList().GetMarkCount()) + CreateSelectionDataObject( this ); + else + ClearSelectionClipboard(); +} + +void View::ClearSelectionClipboard() // true case +{ + if (!mpViewSh) + return; + if (!mpViewSh->GetActiveWindow()) + return; + if (SD_MOD()->pTransferSelection && SD_MOD()->pTransferSelection->GetView() == this) + { + TransferableHelper::ClearPrimarySelection(); + SD_MOD()->pTransferSelection = nullptr; + } +} + +void View::DoCut() +{ + const OutlinerView* pOLV = GetTextEditOutlinerView(); + + if( pOLV ) + const_cast<OutlinerView*>(pOLV)->Cut(); + else if( AreObjectsMarked() ) + { + OUString aStr(SdResId(STR_UNDO_CUT)); + + DoCopy(); + BegUndo(aStr + " " + GetDescriptionOfMarkedObjects()); + DeleteMarked(); + EndUndo(); + } +} + +void View::DoCopy() +{ + const OutlinerView* pOLV = GetTextEditOutlinerView(); + + if( pOLV ) + const_cast<OutlinerView*>(pOLV)->Copy(); + else if( AreObjectsMarked() ) + { + BrkAction(); + CreateClipboardDataObject(); + } +} + +void View::DoPaste (::sd::Window* pWindow) +{ + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( mpViewSh->GetActiveWindow() ) ); + if( !aDataHelper.GetTransferable().is() ) + return; // empty clipboard? + + const OutlinerView* pOLV = GetTextEditOutlinerView(); + + if( pOLV && EditEngine::HasValidData( aDataHelper.GetTransferable() ) ) + { + const_cast< OutlinerView* >(pOLV)->PasteSpecial(); + + SdrObject* pObj = GetTextEditObject(); + SdPage* pPage = static_cast<SdPage*>( pObj ? pObj->getSdrPageFromSdrObject() : nullptr ); + ::Outliner* pOutliner = pOLV->GetOutliner(); + + if( pOutliner) + { + if( pObj && pPage && pPage->GetPresObjKind(pObj) == PresObjKind::Title ) + { + // remove all hard linebreaks from the title + if (pOutliner->GetParagraphCount() > 1) + { + bool bOldUpdateMode = pOutliner->SetUpdateLayout( false ); + + const EditEngine& rEdit = pOutliner->GetEditEngine(); + const sal_Int32 nParaCount = rEdit.GetParagraphCount(); + + for( sal_Int32 nPara = nParaCount - 2; nPara >= 0; nPara-- ) + { + const sal_Int32 nParaLen = rEdit.GetTextLen( nPara ); + pOutliner->QuickDelete( ESelection( nPara, nParaLen, nPara+1, 0 ) ); + pOutliner->QuickInsertLineBreak( ESelection( nPara, nParaLen, nPara, nParaLen ) ); + } + + DBG_ASSERT( rEdit.GetParagraphCount() <= 1, "Titleobject contains hard line breaks" ); + pOutliner->SetUpdateLayout(bOldUpdateMode); + } + } + + if( !mrDoc.IsChanged() ) + { + if (pOutliner->IsModified()) + mrDoc.SetChanged(); + } + } + } + else + { + Point aPos = pWindow->GetVisibleCenter(); + DrawViewShell* pDrViewSh = static_cast<DrawViewShell*>( mpDocSh->GetViewShell() ); + + if (pDrViewSh != nullptr) + { + sal_Int8 nDnDAction = DND_ACTION_COPY; + if( !InsertData( aDataHelper, aPos, nDnDAction, false ) ) + { + INetBookmark aINetBookmark( "", "" ); + + if( ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) ) || + ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::FILEGRPDESCRIPTOR, aINetBookmark ) ) || + ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::UNIFORMRESOURCELOCATOR, aINetBookmark ) ) ) + { + pDrViewSh->InsertURLField( aINetBookmark.GetURL(), aINetBookmark.GetDescription(), "" ); + } + } + } + } +} + +void View::StartDrag( const Point& rStartPos, vcl::Window* pWindow ) +{ + if (!AreObjectsMarked() || !IsAction() || !mpViewSh || !pWindow) + return; + + BrkAction(); + + if( IsTextEdit() ) + SdrEndTextEdit(); + + if (DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(mpDocSh ? mpDocSh->GetViewShell() : nullptr)) + { + const rtl::Reference<FuPoor>& xFunction(pDrawViewShell->GetCurrentFunction()); + if (FuDraw* pFunction = dynamic_cast<FuDraw*>(xFunction.get())) + pFunction->ForcePointer(); + } + + mpDragSrcMarkList.reset( new SdrMarkList(GetMarkedObjectList()) ); + mnDragSrcPgNum = GetSdrPageView()->GetPage()->GetPageNum(); + + CreateDragDataObject( this, *pWindow, rStartPos ); +} + +void View::DragFinished( sal_Int8 nDropAction ) +{ + const bool bUndo = IsUndoEnabled(); + const bool bGroupUndo = bUndo && mpDragSrcMarkList; + if (bGroupUndo) + { + OUString aStr(SdResId(STR_UNDO_DRAGDROP)); + BegUndo(aStr + " " + mpDragSrcMarkList->GetMarkDescription()); + } + + SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + + if( pDragTransferable ) + pDragTransferable->SetView( nullptr ); + + if( ( nDropAction & DND_ACTION_MOVE ) && + pDragTransferable && !pDragTransferable->IsInternalMove() && + mpDragSrcMarkList && mpDragSrcMarkList->GetMarkCount() && + !IsPresObjSelected() ) + { + mpDragSrcMarkList->ForceSort(); + + if( bUndo ) + BegUndo(); + + const size_t nCnt = mpDragSrcMarkList->GetMarkCount(); + + for( size_t nm = nCnt; nm>0; ) + { + --nm; + SdrMark* pM=mpDragSrcMarkList->GetMark(nm); + if( bUndo ) + AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeleteObject(*pM->GetMarkedSdrObj())); + } + + mpDragSrcMarkList->GetMark(0)->GetMarkedSdrObj()->GetOrdNum(); + + for (size_t nm = nCnt; nm>0;) + { + --nm; + SdrMark* pM=mpDragSrcMarkList->GetMark(nm); + SdrObject* pObj=pM->GetMarkedSdrObj(); + + if( pObj && pObj->getSdrPageFromSdrObject() ) + { + const size_t nOrdNum = pObj->GetOrdNumDirect(); + rtl::Reference<SdrObject> pChkObj = pObj->getSdrPageFromSdrObject()->RemoveObject(nOrdNum); + DBG_ASSERT(pChkObj.get()==pObj,"pChkObj!=pObj in RemoveObject()"); + } + } + + if( bUndo ) + EndUndo(); + } + + if( pDragTransferable ) + pDragTransferable->SetInternalMove( false ); + + if (bGroupUndo) + EndUndo(); + mnDragSrcPgNum = SDRPAGE_NOTFOUND; + mpDragSrcMarkList.reset(); +} + +sal_Int8 View::AcceptDrop( const AcceptDropEvent& rEvt, DropTargetHelper& rTargetHelper, + SdrLayerID nLayer ) +{ + OUString aLayerName = GetActiveLayer(); + SdrPageView* pPV = GetSdrPageView(); + sal_Int8 nDropAction = rEvt.mnAction; + sal_Int8 nRet = DND_ACTION_NONE; + + if( nLayer != SDRLAYER_NOTFOUND ) + { + SdrLayerAdmin& rLayerAdmin = mrDoc.GetLayerAdmin(); + SdrLayer* pLayer = rLayerAdmin.GetLayerPerID(nLayer); + assert(pLayer && "layer missing"); + aLayerName = pLayer->GetName(); + } + + if( mbIsDropAllowed && !pPV->IsLayerLocked( aLayerName ) && pPV->IsLayerVisible( aLayerName ) ) + { + const OutlinerView* pOLV = GetTextEditOutlinerView(); + bool bIsInsideOutlinerView = false; + + if( pOLV ) + { + ::tools::Rectangle aRect( pOLV->GetOutputArea() ); + + if (GetMarkedObjectCount() == 1) + { + SdrMark* pMark = GetSdrMarkByIndex(0); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + aRect.Union( pObj->GetLogicRect() ); + } + + if( aRect.Contains( pOLV->GetWindow()->PixelToLogic( rEvt.maPosPixel ) ) ) + { + bIsInsideOutlinerView = true; + } + } + + if( !bIsInsideOutlinerView ) + { + SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + + if(pDragTransferable && (nDropAction & DND_ACTION_LINK)) + { + // suppress own data when it's intention is to use it as fill information + pDragTransferable = nullptr; + } + + if( pDragTransferable ) + { + const View* pSourceView = pDragTransferable->GetView(); + + if( pDragTransferable->IsPageTransferable() ) + { + nRet = DND_ACTION_COPY; + } + else if( pSourceView ) + { + if( !( nDropAction & DND_ACTION_LINK ) || + !pSourceView->GetDocSh()->GetMedium()->GetName().isEmpty() ) + { + nRet = nDropAction; + } + } + } + else + { + const bool bDrawing = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::DRAWING ); + const bool bGraphic = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::SVXB ); + const bool bMtf = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::GDIMETAFILE ); + const bool bBitmap = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::BITMAP ); + bool bBookmark = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK ); + bool bXFillExchange = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::XFA ); + + // check handle insert + if ((bXFillExchange && (SdrDragMode::Gradient == GetDragMode())) + || (SdrDragMode::Transparence == GetDragMode())) + { + const SdrHdlList& rHdlList = GetHdlList(); + + for( size_t n = 0; n < rHdlList.GetHdlCount(); ++n ) + { + SdrHdl* pIAOHandle = rHdlList.GetHdl( n ); + + if( pIAOHandle && ( SdrHdlKind::Color == pIAOHandle->GetKind() ) ) + { + if(pIAOHandle->getOverlayObjectList().isHitPixel(rEvt.maPosPixel)) + { + nRet = nDropAction; + static_cast< SdrHdlColor* >( pIAOHandle )->SetSize( SDR_HANDLE_COLOR_SIZE_SELECTED ); + } + else + { + static_cast< SdrHdlColor* >( pIAOHandle )->SetSize( SDR_HANDLE_COLOR_SIZE_NORMAL ); + } + } + } + } + + // check object insert + if( !nRet && ( bXFillExchange || ( ( bDrawing || bGraphic || bMtf || bBitmap || bBookmark ) && ( nDropAction & DND_ACTION_LINK ) ) ) ) + { + SdrPageView* pPageView = nullptr; + ::sd::Window* pWindow = mpViewSh->GetActiveWindow(); + Point aPos( pWindow->PixelToLogic( rEvt.maPosPixel ) ); + SdrObject* pPickObj = PickObj(aPos, getHitTolLog(), pPageView); + bool bIsPresTarget = false; + + if (pPickObj && (pPickObj->IsEmptyPresObj() || pPickObj->GetUserCall())) + { + SdPage* pPage = static_cast<SdPage*>( pPickObj->getSdrPageFromSdrObject() ); + + if( pPage && pPage->IsMasterPage() ) + bIsPresTarget = pPage->IsPresObj( pPickObj ); + } + + if (pPickObj && !bIsPresTarget && (bGraphic || bMtf || bBitmap || bXFillExchange)) + { + if( mpDropMarkerObj != pPickObj ) + { + mpDropMarkerObj = pPickObj; + ImplClearDrawDropMarker(); + + if(mpDropMarkerObj) + { + mpDropMarker.reset( new SdrDropMarkerOverlay(*this, *mpDropMarkerObj) ); + } + } + + nRet = nDropAction; + } + else + bXFillExchange = false; + } + + // check normal insert + if( !nRet ) + { + const bool bSBAFormat = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::SVX_FORMFIELDEXCH ); + const bool bEditEngineODF = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT ); + const bool bString = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::STRING ); + const bool bRTF = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::RTF ); + const bool bFile = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ); + const bool bFileList = rTargetHelper.IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ); + + if( mpDropMarker ) + { + ImplClearDrawDropMarker(); + mpDropMarkerObj = nullptr; + } + + if( bBookmark && bFile && ( nDropAction & DND_ACTION_MOVE ) && mpViewSh && SlideShow::IsRunning(mpViewSh->GetViewShellBase()) ) + bBookmark = false; + + if( bDrawing || bGraphic || bMtf || bBitmap || bBookmark || bFile || bFileList || bXFillExchange || bSBAFormat || bEditEngineODF || bString || bRTF ) + nRet = nDropAction; + + // For entries from the navigator, change action copy. + if (bBookmark + && rTargetHelper.IsDropFormatSupported( + SdPageObjsTLV::SdPageObjsTransferable::GetListBoxDropFormatId()) + && (nDropAction & DND_ACTION_MOVE)!=0) + { + nRet = DND_ACTION_COPY; + } + } + } + } + } + + // destroy drop marker if this is a leaving event + if( rEvt.mbLeaving && mpDropMarker ) + { + ImplClearDrawDropMarker(); + mpDropMarkerObj = nullptr; + } + + return nRet; +} + +sal_Int8 View::ExecuteDrop( const ExecuteDropEvent& rEvt, + ::sd::Window* pTargetWindow, sal_uInt16 nPage, SdrLayerID nLayer ) +{ + SdrPageView* pPV = GetSdrPageView(); + OUString aActiveLayer = GetActiveLayer(); + sal_Int8 nDropAction = rEvt.mnAction; + sal_Int8 nRet = DND_ACTION_NONE; + + // destroy drop marker if it is shown + if( mpDropMarker ) + { + ImplClearDrawDropMarker(); + mpDropMarkerObj = nullptr; + } + + if( !pPV->IsLayerLocked( aActiveLayer ) ) + { + const OutlinerView* pOLV = GetTextEditOutlinerView(); + bool bIsInsideOutlinerView = false; + + if( pOLV ) + { + ::tools::Rectangle aRect( pOLV->GetOutputArea() ); + + if( GetMarkedObjectCount() == 1 ) + { + SdrMark* pMark = GetSdrMarkByIndex(0); + SdrObject* pObj = pMark->GetMarkedSdrObj(); + aRect.Union( pObj->GetLogicRect() ); + } + + Point aPos( pOLV->GetWindow()->PixelToLogic( rEvt.maPosPixel ) ); + + if( aRect.Contains( aPos ) ) + { + bIsInsideOutlinerView = true; + } + } + + if( !bIsInsideOutlinerView ) + { + Point aPos; + TransferableDataHelper aDataHelper( rEvt.maDropEvent.Transferable ); + + if( pTargetWindow ) + aPos = pTargetWindow->PixelToLogic( rEvt.maPosPixel ); + + // handle insert? + if ((SdrDragMode::Gradient == GetDragMode()) + || ((SdrDragMode::Transparence == GetDragMode()) + && aDataHelper.HasFormat(SotClipboardFormatId::XFA))) + { + const SdrHdlList& rHdlList = GetHdlList(); + + for( size_t n = 0; !nRet && n < rHdlList.GetHdlCount(); ++n ) + { + SdrHdl* pIAOHandle = rHdlList.GetHdl( n ); + + if( pIAOHandle && ( SdrHdlKind::Color == pIAOHandle->GetKind() ) ) + { + if(pIAOHandle->getOverlayObjectList().isHitPixel(rEvt.maPosPixel)) + { + uno::Any const data(aDataHelper.GetAny(SotClipboardFormatId::XFA, "")); + uno::Sequence<beans::NamedValue> props; + if (data >>= props) + { + ::comphelper::SequenceAsHashMap const map(props); + Color aColor(COL_BLACK); + auto const it = map.find("FillColor"); + if (it != map.end()) + { + XFillColorItem color; + color.PutValue(it->second, 0); + aColor = color.GetColorValue(); + } + static_cast< SdrHdlColor* >( pIAOHandle )->SetColor( aColor, true ); + nRet = nDropAction; + } + } + } + } + } + + // standard insert? + if( !nRet && InsertData( aDataHelper, aPos, nDropAction, true, SotClipboardFormatId::NONE, nPage, nLayer ) ) + nRet = nDropAction; + + // special insert? + if( !nRet && mpViewSh ) + { + INetBookmark aINetBookmark( (OUString()), (OUString()) ); + + // insert bookmark + if( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) && + aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) ) + { + SdPageObjsTLV::SdPageObjsTransferable* pPageObjsTransferable = SdPageObjsTLV::SdPageObjsTransferable::getImplementation( aDataHelper.GetXTransferable() ); + + if( pPageObjsTransferable && + ( NAVIGATOR_DRAGTYPE_LINK == pPageObjsTransferable->GetDragType() || + NAVIGATOR_DRAGTYPE_EMBEDDED == pPageObjsTransferable->GetDragType() ) ) + { + // insert bookmark from own navigator (handled async. due to possible message box ) + Application::PostUserEvent( LINK( this, View, ExecuteNavigatorDrop ), + new SdNavigatorDropEvent( rEvt, pTargetWindow ) ); + nRet = nDropAction; + } + else + { + SdrPageView* pPageView = nullptr; + + SdrObject* pPickObj = PickObj(aPos, getHitTolLog(), pPageView); + if (pPickObj) + { + // insert as clip action => jump + OUString aBookmark( aINetBookmark.GetURL() ); + SdAnimationInfo* pInfo = SdDrawDocument::GetAnimationInfo( pPickObj ); + + if( !aBookmark.isEmpty() ) + { + bool bCreated = false; + + presentation::ClickAction eClickAction = presentation::ClickAction_DOCUMENT; + + sal_Int32 nIndex = aBookmark.indexOf( '#' ); + if( nIndex != -1 ) + { + const std::u16string_view aDocName( aBookmark.subView( 0, nIndex ) ); + + if (mpDocSh->GetMedium()->GetName() == aDocName || aDocName == mpDocSh->GetName()) + { + // internal jump, only use the part after and including '#' + eClickAction = presentation::ClickAction_BOOKMARK; + aBookmark = aBookmark.copy( nIndex+1 ); + } + } + + if( !pInfo ) + { + pInfo = SdDrawDocument::GetShapeUserData( *pPickObj, true ); + bCreated = true; + } + + // create undo action with old and new sizes + std::unique_ptr<SdAnimationPrmsUndoAction> pAction(new SdAnimationPrmsUndoAction(&mrDoc, pPickObj, bCreated)); + pAction->SetActive(pInfo->mbActive, pInfo->mbActive); + pAction->SetEffect(pInfo->meEffect, pInfo->meEffect); + pAction->SetTextEffect(pInfo->meTextEffect, pInfo->meTextEffect); + pAction->SetSpeed(pInfo->meSpeed, pInfo->meSpeed); + pAction->SetDim(pInfo->mbDimPrevious, pInfo->mbDimPrevious); + pAction->SetDimColor(pInfo->maDimColor, pInfo->maDimColor); + pAction->SetDimHide(pInfo->mbDimHide, pInfo->mbDimHide); + pAction->SetSoundOn(pInfo->mbSoundOn, pInfo->mbSoundOn); + pAction->SetSound(pInfo->maSoundFile, pInfo->maSoundFile); + pAction->SetPlayFull(pInfo->mbPlayFull, pInfo->mbPlayFull); + pAction->SetClickAction(pInfo->meClickAction, eClickAction); + pAction->SetBookmark(pInfo->GetBookmark(), aBookmark); + pAction->SetVerb(pInfo->mnVerb, pInfo->mnVerb); + pAction->SetSecondEffect(pInfo->meSecondEffect, pInfo->meSecondEffect); + pAction->SetSecondSpeed(pInfo->meSecondSpeed, pInfo->meSecondSpeed); + pAction->SetSecondSoundOn(pInfo->mbSecondSoundOn, pInfo->mbSecondSoundOn); + pAction->SetSecondPlayFull(pInfo->mbSecondPlayFull, pInfo->mbSecondPlayFull); + + OUString aString(SdResId(STR_UNDO_ANIMATION)); + pAction->SetComment(aString); + mpDocSh->GetUndoManager()->AddUndoAction(std::move(pAction)); + pInfo->meClickAction = eClickAction; + pInfo->SetBookmark( aBookmark ); + mrDoc.SetChanged(); + + nRet = nDropAction; + } + } + else if( auto pDrawViewShell = dynamic_cast< DrawViewShell *>( mpViewSh ) ) + { + // insert as normal URL button + pDrawViewShell->InsertURLButton( aINetBookmark.GetURL(), aINetBookmark.GetDescription(), OUString(), &aPos ); + nRet = nDropAction; + } + } + } + } + } + } + + return nRet; +} + +IMPL_LINK( View, ExecuteNavigatorDrop, void*, p, void ) +{ + SdNavigatorDropEvent* pSdNavigatorDropEvent = static_cast<SdNavigatorDropEvent*>(p); + TransferableDataHelper aDataHelper( pSdNavigatorDropEvent->maDropEvent.Transferable ); + SdPageObjsTLV::SdPageObjsTransferable* pPageObjsTransferable = SdPageObjsTLV::SdPageObjsTransferable::getImplementation( aDataHelper.GetXTransferable() ); + INetBookmark aINetBookmark; + + if( pPageObjsTransferable && aDataHelper.GetINetBookmark( SotClipboardFormatId::NETSCAPE_BOOKMARK, aINetBookmark ) ) + { + Point aPos; + OUString aBookmark; + SdPage* pPage = static_cast<SdPage*>( GetSdrPageView()->GetPage() ); + sal_uInt16 nPgPos = 0xFFFF; + + if( pSdNavigatorDropEvent->mpTargetWindow ) + aPos = pSdNavigatorDropEvent->mpTargetWindow->PixelToLogic( pSdNavigatorDropEvent->maPosPixel ); + + const OUString& aURL( aINetBookmark.GetURL() ); + sal_Int32 nIndex = aURL.indexOf( '#' ); + if( nIndex != -1 ) + aBookmark = aURL.copy( nIndex+1 ); + + std::vector<OUString> aExchangeList; + std::vector<OUString> aBookmarkList(1,aBookmark); + + if( !pPage->IsMasterPage() ) + { + if( pPage->GetPageKind() == PageKind::Standard ) + nPgPos = pPage->GetPageNum() + 2; + else if( pPage->GetPageKind() == PageKind::Notes ) + nPgPos = pPage->GetPageNum() + 1; + } + + /* In order t ensure unique page names, we test the ones we want to + insert. If necessary. we put them into and replacement list (bNameOK + == sal_False -> User canceled). */ + bool bLink = pPageObjsTransferable->GetDragType() == NAVIGATOR_DRAGTYPE_LINK; + bool bNameOK = GetExchangeList( aExchangeList, aBookmarkList, 2 ); + + /* Since we don't know the type (page or object), we fill a list with + pages and objects. + Of course we have problems if there are pages and objects with the + same name!!! */ + if( bNameOK ) + { + mrDoc.InsertBookmark( aBookmarkList, aExchangeList, + bLink, nPgPos, + &pPageObjsTransferable->GetDocShell(), + &aPos ); + } + } + + delete pSdNavigatorDropEvent; +} + +bool View::GetExchangeList (std::vector<OUString> &rExchangeList, + std::vector<OUString> &rBookmarkList, + const sal_uInt16 nType) +{ + assert(rExchangeList.empty()); + + bool bListIdentical = true; ///< Bookmark list and exchange list are identical + bool bNameOK = true; ///< name is unique + + for ( const auto& rBookmark : rBookmarkList ) + { + OUString aNewName = rBookmark; + + if( nType == 0 || nType == 2 ) + bNameOK = mpDocSh->CheckPageName(mpViewSh->GetFrameWeld(), aNewName); + + if( bNameOK && ( nType == 1 || nType == 2 ) ) + { + if( mrDoc.GetObj( aNewName ) ) + { + OUString aTitle(SdResId(STR_TITLE_NAMEGROUP)); + OUString aDesc(SdResId(STR_DESC_NAMEGROUP)); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractSvxNameDialog> pDlg(pFact->CreateSvxNameDialog(mpViewSh->GetFrameWeld(), aNewName, aDesc)); + + pDlg->SetEditHelpId( HID_SD_NAMEDIALOG_OBJECT ); + + bNameOK = false; + pDlg->SetText( aTitle ); + + while( !bNameOK && pDlg->Execute() == RET_OK ) + { + pDlg->GetName( aNewName ); + + if( !mrDoc.GetObj( aNewName ) ) + bNameOK = true; + } + } + } + + bListIdentical = rBookmark == aNewName; + + rExchangeList.push_back(aNewName); + + if (!bNameOK) + break; + } + + // Exchange list is identical to bookmark list + if( !rExchangeList.empty() && bListIdentical ) + rExchangeList.clear(); + + return bNameOK; +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/sdview3.cxx b/sd/source/ui/view/sdview3.cxx new file mode 100644 index 0000000000..ddd0ad28ec --- /dev/null +++ b/sd/source/ui/view/sdview3.cxx @@ -0,0 +1,1620 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <View.hxx> +#include <com/sun/star/embed/XEmbedObjectClipboardCreator.hpp> +#include <com/sun/star/embed/NoVisualAreaSizeException.hpp> +#include <com/sun/star/embed/MSOLEObjectSystemCreator.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <sot/filelist.hxx> +#include <editeng/editdata.hxx> +#include <svx/xfillit0.hxx> +#include <svx/xflclit.hxx> +#include <svx/xlnclit.hxx> +#include <svx/svdpagv.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/mieclip.hxx> +#include <svx/svdoole2.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdundo.hxx> +#include <svl/itempool.hxx> +#include <sot/formats.hxx> +#include <editeng/outliner.hxx> +#include <svx/obj3d.hxx> +#include <svx/e3dundo.hxx> +#include <svx/unomodel.hxx> +#include <svx/ImageMapInfo.hxx> +#include <unotools/streamwrap.hxx> +#include <vcl/graph.hxx> +#include <vcl/metaact.hxx> +#include <vcl/pdfread.hxx> +#include <vcl/TypeSerializer.hxx> +#include <svx/svxids.hrc> +#include <toolkit/helper/vclunohelper.hxx> +#include <svtools/embedhlp.hxx> +#include <osl/diagnose.h> +#include <DrawDocShell.hxx> +#include <fupoor.hxx> +#include <tablefunction.hxx> +#include <Window.hxx> +#include <sdxfer.hxx> +#include <sdpage.hxx> +#include <drawdoc.hxx> +#include <sdmod.hxx> +#include <sdresid.hxx> +#include <strings.hrc> +#include <SlideSorterViewShell.hxx> +#include <unomodel.hxx> +#include <ViewClipboard.hxx> +#include <sfx2/ipclient.hxx> +#include <sfx2/classificationhelper.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <comphelper/storagehelper.hxx> +#include <comphelper/processfactory.hxx> +#include <svx/sdrhittesthelper.hxx> +#include <svx/xbtmpit.hxx> +#include <memory> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::clipboard; + +namespace sd { + +#define CHECK_FORMAT_TRANS( _def_Type ) ( ( nFormat == (_def_Type) || nFormat == SotClipboardFormatId::NONE ) && aDataHelper.HasFormat( _def_Type ) ) + +/************************************************************************* +|* +|* Paste +|* +\************************************************************************/ + +namespace { + +struct ImpRememberOrigAndClone +{ + SdrObject* pOrig; + SdrObject* pClone; +}; + +} + +static SdrObject* ImpGetClone(std::vector<ImpRememberOrigAndClone>& aConnectorContainer, SdrObject const * pConnObj) +{ + for(const ImpRememberOrigAndClone& rImp : aConnectorContainer) + { + if(pConnObj == rImp.pOrig) + return rImp.pClone; + } + return nullptr; +} + +// restrict movement to WorkArea +static void ImpCheckInsertPos(Point& rPos, const Size& rSize, const ::tools::Rectangle& rWorkArea) +{ + if(rWorkArea.IsEmpty()) + return; + + ::tools::Rectangle aMarkRect(Point(rPos.X() - (rSize.Width() / 2), rPos.Y() - (rSize.Height() / 2)), rSize); + + if(aMarkRect.Contains(rWorkArea)) + return; + + if(aMarkRect.Left() < rWorkArea.Left()) + { + rPos.AdjustX(rWorkArea.Left() - aMarkRect.Left() ); + } + + if(aMarkRect.Right() > rWorkArea.Right()) + { + rPos.AdjustX( -(aMarkRect.Right() - rWorkArea.Right()) ); + } + + if(aMarkRect.Top() < rWorkArea.Top()) + { + rPos.AdjustY(rWorkArea.Top() - aMarkRect.Top() ); + } + + if(aMarkRect.Bottom() > rWorkArea.Bottom()) + { + rPos.AdjustY( -(aMarkRect.Bottom() - rWorkArea.Bottom()) ); + } +} + +bool View::InsertMetaFile( const TransferableDataHelper& rDataHelper, const Point& rPos, ImageMap const * pImageMap, bool bOptimize ) +{ + GDIMetaFile aMtf; + + if( !rDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMtf ) ) + return false; + + bool bVector = false; + Graphic aGraphic; + + // check if metafile only contains a pixel image, if so insert a bitmap instead + if( bOptimize ) + { + MetaAction* pAction = aMtf.FirstAction(); + while( pAction && !bVector ) + { + switch( pAction->GetType() ) + { + case MetaActionType::POINT: + case MetaActionType::LINE: + case MetaActionType::RECT: + case MetaActionType::ROUNDRECT: + case MetaActionType::ELLIPSE: + case MetaActionType::ARC: + case MetaActionType::PIE: + case MetaActionType::CHORD: + case MetaActionType::POLYLINE: + case MetaActionType::POLYGON: + case MetaActionType::POLYPOLYGON: + case MetaActionType::TEXT: + case MetaActionType::TEXTARRAY: + case MetaActionType::STRETCHTEXT: + case MetaActionType::TEXTRECT: + case MetaActionType::GRADIENT: + case MetaActionType::HATCH: + case MetaActionType::WALLPAPER: + case MetaActionType::EPS: + case MetaActionType::TEXTLINE: + case MetaActionType::FLOATTRANSPARENT: + case MetaActionType::GRADIENTEX: + case MetaActionType::BMPSCALEPART: + case MetaActionType::BMPEXSCALEPART: + bVector = true; + break; + case MetaActionType::BMP: + case MetaActionType::BMPSCALE: + case MetaActionType::BMPEX: + case MetaActionType::BMPEXSCALE: + if( aGraphic.GetType() != GraphicType::NONE ) + { + bVector = true; + } + else switch( pAction->GetType() ) + { + case MetaActionType::BMP: + { + MetaBmpAction* pBmpAction = dynamic_cast< MetaBmpAction* >( pAction ); + if( pBmpAction ) + aGraphic = Graphic(BitmapEx(pBmpAction->GetBitmap())); + } + break; + case MetaActionType::BMPSCALE: + { + MetaBmpScaleAction* pBmpScaleAction = dynamic_cast< MetaBmpScaleAction* >( pAction ); + if( pBmpScaleAction ) + aGraphic = Graphic(BitmapEx(pBmpScaleAction->GetBitmap())); + } + break; + case MetaActionType::BMPEX: + { + MetaBmpExAction* pBmpExAction = dynamic_cast< MetaBmpExAction* >( pAction ); + if( pBmpExAction ) + aGraphic = Graphic(pBmpExAction->GetBitmapEx() ); + } + break; + case MetaActionType::BMPEXSCALE: + { + MetaBmpExScaleAction* pBmpExScaleAction = dynamic_cast< MetaBmpExScaleAction* >( pAction ); + if( pBmpExScaleAction ) + aGraphic = Graphic( pBmpExScaleAction->GetBitmapEx() ); + } + break; + default: break; + } + break; + default: break; + } + + pAction = aMtf.NextAction(); + } + } + + // it is not a vector metafile but it also has no graphic? + if( !bVector && (aGraphic.GetType() == GraphicType::NONE) ) + bVector = true; + + // restrict movement to WorkArea + Point aInsertPos( rPos ); + Size aImageSize = bVector ? aMtf.GetPrefSize() : aGraphic.GetSizePixel(); + ImpCheckInsertPos(aInsertPos, aImageSize, GetWorkArea()); + + if( bVector ) + aGraphic = Graphic( aMtf ); + + aGraphic.SetPrefMapMode( aMtf.GetPrefMapMode() ); + aGraphic.SetPrefSize( aMtf.GetPrefSize() ); + InsertGraphic( aGraphic, mnAction, aInsertPos, nullptr, pImageMap ); + + return true; +} + +bool View::InsertData( const TransferableDataHelper& rDataHelper, + const Point& rPos, sal_Int8& rDnDAction, bool bDrag, + SotClipboardFormatId nFormat, sal_uInt16 nPage, SdrLayerID nLayer ) +{ + maDropPos = rPos; + mnAction = rDnDAction; + mbIsDropAllowed = false; + + TransferableDataHelper aDataHelper( rDataHelper ); + SdrObject* pPickObj = nullptr; + SdPage* pPage = nullptr; + std::unique_ptr<ImageMap> pImageMap; + bool bReturn = false; + bool bLink = ( ( mnAction & DND_ACTION_LINK ) != 0 ); + bool bCopy = ( ( ( mnAction & DND_ACTION_COPY ) != 0 ) || bLink ); + SdrInsertFlags nPasteOptions = SdrInsertFlags::SETDEFLAYER; + + if (mpViewSh != nullptr) + { + OSL_ASSERT (mpViewSh->GetViewShell()!=nullptr); + SfxInPlaceClient* pIpClient = mpViewSh->GetViewShell()->GetIPClient(); + if( dynamic_cast< ::sd::slidesorter::SlideSorterViewShell *>( mpViewSh ) != nullptr + || (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive())) + nPasteOptions |= SdrInsertFlags::DONTMARK; + } + + if( bDrag ) + { + SdrPageView* pPV = nullptr; + pPickObj = PickObj(rPos, getHitTolLog(), pPV); + } + + if( nPage != SDRPAGE_NOTFOUND ) + pPage = static_cast<SdPage*>( mrDoc.GetPage( nPage ) ); + + SdTransferable* pOwnData = nullptr; + SdTransferable* pImplementation = SdTransferable::getImplementation( aDataHelper.GetTransferable() ); + + if(pImplementation && (rDnDAction & DND_ACTION_LINK)) + { + // suppress own data when it's intention is to use it as fill information + pImplementation = nullptr; + } + + bool bSelfDND = false; + + // try to get own transfer data + if( pImplementation ) + { + if( SD_MOD()->pTransferClip == pImplementation ) + pOwnData = SD_MOD()->pTransferClip; + else if( SD_MOD()->pTransferDrag == pImplementation ) + { + pOwnData = SD_MOD()->pTransferDrag; + bSelfDND = true; + } + else if( SD_MOD()->pTransferSelection == pImplementation ) + pOwnData = SD_MOD()->pTransferSelection; + } + + const bool bGroupUndoFromDragWithDrop = bSelfDND && mpDragSrcMarkList && IsUndoEnabled(); + if (bGroupUndoFromDragWithDrop) + { + OUString aStr(SdResId(STR_UNDO_DRAGDROP)); + BegUndo(aStr + " " + mpDragSrcMarkList->GetMarkDescription()); + } + + // ImageMap? + if( !pOwnData && aDataHelper.HasFormat( SotClipboardFormatId::SVIM ) ) + { + ::tools::SvRef<SotTempStream> xStm; + + if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVIM, xStm ) ) + { + pImageMap.reset(new ImageMap); + // mba: clipboard always must contain absolute URLs (could be from alien source) + pImageMap->Read( *xStm ); + } + } + + bool bTable = false; + // check special cases for pasting table formats as RTL + if( !bLink && (nFormat == SotClipboardFormatId::NONE || (nFormat == SotClipboardFormatId::RTF) || (nFormat == SotClipboardFormatId::RICHTEXT)) ) + { + // if the object supports rtf and there is a table involved, default is to create a table + bool bIsRTF = aDataHelper.HasFormat( SotClipboardFormatId::RTF ); + if( ( bIsRTF || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ) + && ! aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) ) + { + ::tools::SvRef<SotTempStream> xStm; + + if( aDataHelper.GetSotStorageStream( bIsRTF ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT, xStm ) ) + { + xStm->Seek( 0 ); + + OStringBuffer aLine; + while (xStm->ReadLine(aLine)) + { + size_t x = std::string_view(aLine).find( "\\trowd" ); + if (x != std::string_view::npos) + { + bTable = true; + nFormat = bIsRTF ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT; + break; + } + } + } + } + } + + // Changed the whole decision tree to be dependent of bReturn as a flag that + // the work was done; this allows to check multiple formats and not just fail + // when a CHECK_FORMAT_TRANS(*format*) detected format does not work. This is + // e.g. necessary for SotClipboardFormatId::BITMAP + + if (!bReturn && pOwnData) + { + // Paste only if SfxClassificationHelper recommends so. + const SfxObjectShellRef& pSource = pOwnData->GetDocShell(); + SfxObjectShell* pDestination = mrDoc.GetDocSh(); + if (pSource.is() && pDestination) + { + SfxClassificationCheckPasteResult eResult = SfxClassificationHelper::CheckPaste(pSource->getDocProperties(), pDestination->getDocProperties()); + if (!SfxClassificationHelper::ShowPasteInfo(eResult)) + bReturn = true; + } + } + + if( !bReturn && pOwnData && nFormat == SotClipboardFormatId::NONE ) + { + const View* pSourceView = pOwnData->GetView(); + + if( pOwnData->GetDocShell().is() && pOwnData->IsPageTransferable() ) + { + mpClipboard->HandlePageDrop (*pOwnData); + bReturn = true; + } + else if( pSourceView ) + { + if( pSourceView == this ) + { + // same view + if( nLayer != SDRLAYER_NOTFOUND ) + { + // drop on layer tab bar + SdrLayerAdmin& rLayerAdmin = mrDoc.GetLayerAdmin(); + SdrLayer* pLayer = rLayerAdmin.GetLayerPerID( nLayer ); + SdrPageView* pPV = GetSdrPageView(); + OUString aLayer = pLayer->GetName(); + + if( !pPV->IsLayerLocked( aLayer ) ) + { + pOwnData->SetInternalMove( true ); + SortMarkedObjects(); + + for( size_t nM = 0; nM < GetMarkedObjectCount(); ++nM ) + { + SdrMark* pM = GetSdrMarkByIndex( nM ); + SdrObject* pO = pM->GetMarkedSdrObj(); + + if( pO ) + { + // #i11702# + if( IsUndoEnabled() ) + { + BegUndo(SdResId(STR_MODIFYLAYER)); + AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectLayerChange(*pO, pO->GetLayer(), nLayer)); + EndUndo(); + } + + pO->SetLayer( nLayer ); + } + } + + bReturn = true; + } + } + else + { + SdrPageView* pPV = GetSdrPageView(); + bool bDropOnTabBar = true; + + if( !pPage && pPV->GetPage()->GetPageNum() != mnDragSrcPgNum ) + { + pPage = static_cast<SdPage*>( pPV->GetPage() ); + bDropOnTabBar = false; + } + + if( pPage ) + { + // drop on other page + OUString aActiveLayer = GetActiveLayer(); + + if( !pPV->IsLayerLocked( aActiveLayer ) ) + { + if( !IsPresObjSelected() ) + { + SdrMarkList* pMarkList; + + if( (mnDragSrcPgNum != SDRPAGE_NOTFOUND) && (mnDragSrcPgNum != pPV->GetPage()->GetPageNum()) ) + { + pMarkList = mpDragSrcMarkList.get(); + } + else + { + // actual mark list is used + pMarkList = new SdrMarkList( GetMarkedObjectList()); + } + + pMarkList->ForceSort(); + + // stuff to remember originals and clones + std::vector<ImpRememberOrigAndClone> aConnectorContainer; + size_t nConnectorCount = 0; + Point aCurPos; + + // calculate real position of current + // source objects, if necessary (#103207) + if( pOwnData == SD_MOD()->pTransferSelection ) + { + ::tools::Rectangle aCurBoundRect; + + if( pMarkList->TakeBoundRect( pPV, aCurBoundRect ) ) + aCurPos = aCurBoundRect.TopLeft(); + else + aCurPos = pOwnData->GetStartPos(); + } + else + aCurPos = pOwnData->GetStartPos(); + + const Size aVector( maDropPos.X() - aCurPos.X(), maDropPos.Y() - aCurPos.Y() ); + + std::unordered_set<rtl::OUString> aNameSet; + for(size_t a = 0; a < pMarkList->GetMarkCount(); ++a) + { + SdrMark* pM = pMarkList->GetMark(a); + rtl::Reference<SdrObject> pObj(pM->GetMarkedSdrObj()->CloneSdrObject(pPage->getSdrModelFromSdrPage())); + + if(pObj) + { + if(!bDropOnTabBar) + { + // do a NbcMove(...) instead of setting SnapRects here + pObj->NbcMove(aVector); + } + + SdrObject* pMarkParent = pM->GetMarkedSdrObj()->getParentSdrObjectFromSdrObject(); + if (bCopy || (pMarkParent && pMarkParent->IsGroupObject())) + pPage->InsertObjectThenMakeNameUnique(pObj.get(), aNameSet); + else + pPage->InsertObject(pObj.get()); + + if( IsUndoEnabled() ) + { + BegUndo(SdResId(STR_UNDO_DRAGDROP)); + AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pObj)); + EndUndo(); + } + + ImpRememberOrigAndClone aRem; + aRem.pOrig = pM->GetMarkedSdrObj(); + aRem.pClone = pObj.get(); + aConnectorContainer.push_back(aRem); + + if(dynamic_cast< SdrEdgeObj *>( pObj.get() ) != nullptr) + nConnectorCount++; + } + } + + // try to re-establish connections at clones + if(nConnectorCount) + { + for(size_t a = 0; a < aConnectorContainer.size(); ++a) + { + ImpRememberOrigAndClone* pRem = &aConnectorContainer[a]; + + if(auto pCloneEdge = dynamic_cast<SdrEdgeObj *>( pRem->pClone )) + { + SdrEdgeObj* pOrigEdge = static_cast<SdrEdgeObj*>(pRem->pOrig); + + // test first connection + SdrObjConnection& rConn0 = pOrigEdge->GetConnection(false); + SdrObject* pConnObj = rConn0.GetSdrObject(); + if(pConnObj) + { + SdrObject* pConnClone = ImpGetClone(aConnectorContainer, pConnObj); + if(pConnClone) + { + // if dest obj was cloned, too, re-establish connection + pCloneEdge->ConnectToNode(false, pConnClone); + pCloneEdge->GetConnection(false).SetConnectorId(rConn0.GetConnectorId()); + } + else + { + // set position of connection point of original connected object + const SdrGluePointList* pGlueList = pConnObj->GetGluePointList(); + if(pGlueList) + { + sal_uInt16 nInd = pGlueList->FindGluePoint(rConn0.GetConnectorId()); + + if(SDRGLUEPOINT_NOTFOUND != nInd) + { + const SdrGluePoint& rGluePoint = (*pGlueList)[nInd]; + Point aPosition = rGluePoint.GetAbsolutePos(*pConnObj); + aPosition.AdjustX(aVector.Width() ); + aPosition.AdjustY(aVector.Height() ); + pCloneEdge->SetTailPoint(false, aPosition); + } + } + } + } + + // test second connection + SdrObjConnection& rConn1 = pOrigEdge->GetConnection(true); + pConnObj = rConn1.GetSdrObject(); + if(pConnObj) + { + SdrObject* pConnClone = ImpGetClone(aConnectorContainer, pConnObj); + if(pConnClone) + { + // if dest obj was cloned, too, re-establish connection + pCloneEdge->ConnectToNode(true, pConnClone); + pCloneEdge->GetConnection(true).SetConnectorId(rConn1.GetConnectorId()); + } + else + { + // set position of connection point of original connected object + const SdrGluePointList* pGlueList = pConnObj->GetGluePointList(); + if(pGlueList) + { + sal_uInt16 nInd = pGlueList->FindGluePoint(rConn1.GetConnectorId()); + + if(SDRGLUEPOINT_NOTFOUND != nInd) + { + const SdrGluePoint& rGluePoint = (*pGlueList)[nInd]; + Point aPosition = rGluePoint.GetAbsolutePos(*pConnObj); + aPosition.AdjustX(aVector.Width() ); + aPosition.AdjustY(aVector.Height() ); + pCloneEdge->SetTailPoint(true, aPosition); + } + } + } + } + } + } + } + + if( pMarkList != mpDragSrcMarkList.get() ) + delete pMarkList; + + bReturn = true; + } + else + { + maDropErrorIdle.Start(); + bReturn = false; + } + } + } + else + { + pOwnData->SetInternalMove( true ); + MoveAllMarked( Size( maDropPos.X() - pOwnData->GetStartPos().X(), + maDropPos.Y() - pOwnData->GetStartPos().Y() ), bCopy ); + bReturn = true; + } + } + } + else + { + // different views + if( !pSourceView->IsPresObjSelected() ) + { + // model is owned by from AllocModel() created DocShell + SdDrawDocument* pSourceDoc = static_cast<SdDrawDocument*>(&pSourceView->GetModel()); + pSourceDoc->CreatingDataObj( pOwnData ); + SdDrawDocument* pModel = static_cast<SdDrawDocument*>( pSourceView->CreateMarkedObjModel().release() ); + bReturn = Paste(*pModel, maDropPos, pPage, nPasteOptions); + + if( !pPage ) + pPage = static_cast<SdPage*>( GetSdrPageView()->GetPage() ); + + OUString aLayout = pPage->GetLayoutName(); + sal_Int32 nPos = aLayout.indexOf(SD_LT_SEPARATOR); + if (nPos != -1) + aLayout = aLayout.copy(0, nPos); + pPage->SetPresentationLayout( aLayout, false, false ); + pSourceDoc->CreatingDataObj( nullptr ); + } + else + { + maDropErrorIdle.Start(); + bReturn = false; + } + } + } + else + { + SdDrawDocument* pWorkModel = const_cast<SdDrawDocument*>(pOwnData->GetWorkDocument()); + SdPage* pWorkPage = pWorkModel->GetSdPage( 0, PageKind::Standard ); + + pWorkPage->SetSdrObjListRectsDirty(); + + // #i120393# Clipboard data uses full object geometry range + const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() ); + + maDropPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) ); + maDropPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) ); + + // delete pages, that are not of any interest for us + for( ::tools::Long i = pWorkModel->GetPageCount() - 1; i >= 0; i-- ) + { + SdPage* pP = static_cast< SdPage* >( pWorkModel->GetPage( static_cast<sal_uInt16>(i) ) ); + + if( pP->GetPageKind() != PageKind::Standard ) + pWorkModel->DeletePage( static_cast<sal_uInt16>(i) ); + } + + bReturn = Paste(*pWorkModel, maDropPos, pPage, nPasteOptions); + + if( !pPage ) + pPage = static_cast<SdPage*>( GetSdrPageView()->GetPage() ); + + OUString aLayout = pPage->GetLayoutName(); + sal_Int32 nPos = aLayout.indexOf(SD_LT_SEPARATOR); + if (nPos != -1) + aLayout = aLayout.copy(0, nPos); + pPage->SetPresentationLayout( aLayout, false, false ); + } + } + + if(!bReturn && CHECK_FORMAT_TRANS( SotClipboardFormatId::PDF )) + { + ::tools::SvRef<SotTempStream> xStm; + if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::PDF, xStm ) ) + { + Point aInsertPos(rPos); + Graphic aGraphic; + if (vcl::ImportPDF(*xStm, aGraphic)) + { + const sal_uInt64 nGraphicContentSize(xStm->Tell()); + xStm->Seek(0); + BinaryDataContainer aGraphicContent(*xStm, nGraphicContentSize); + aGraphic.SetGfxLink(std::make_shared<GfxLink>(aGraphicContent, GfxLinkType::NativePdf)); + + InsertGraphic(aGraphic, mnAction, aInsertPos, nullptr, nullptr); + bReturn = true; + } + } + } + + if(!bReturn && CHECK_FORMAT_TRANS( SotClipboardFormatId::DRAWING )) + { + ::tools::SvRef<SotTempStream> xStm; + + if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xStm ) ) + { + DrawDocShellRef xShell = new DrawDocShell(SfxObjectCreateMode::INTERNAL, false, DocumentType::Impress); + xShell->DoInitNew(); + + SdDrawDocument* pModel = xShell->GetDoc(); + pModel->InsertPage(pModel->AllocPage(false).get()); + + Reference< XComponent > xComponent = xShell->GetModel(); + xStm->Seek( 0 ); + + css::uno::Reference< css::io::XInputStream > xInputStream( new utl::OInputStreamWrapper( *xStm ) ); + bReturn = SvxDrawingLayerImport( pModel, xInputStream, xComponent, "com.sun.star.comp.Impress.XMLOasisImporter" ); + + if( pModel->GetPageCount() == 0 ) + { + OSL_FAIL("empty or invalid drawing xml document on clipboard!" ); + } + else + { + bool bChanged = false; + + if( bReturn ) + { + if( pModel->GetSdPage( 0, PageKind::Standard )->GetObjCount() == 1 ) + { + // only one object + SdrObject* pObj = pModel->GetSdPage( 0, PageKind::Standard )->GetObj( 0 ); + SdrPageView* pPV = nullptr; + SdrObject* pPickObj2 = PickObj(rPos, getHitTolLog(), pPV); + + if( ( mnAction & DND_ACTION_MOVE ) && pPickObj2 && pObj ) + { + // replace object + SdrPage* pWorkPage = GetSdrPageView()->GetPage(); + rtl::Reference<SdrObject> pNewObj(pObj->CloneSdrObject(pWorkPage->getSdrModelFromSdrPage())); + ::tools::Rectangle aPickObjRect( pPickObj2->GetCurrentBoundRect() ); + Size aPickObjSize( aPickObjRect.GetSize() ); + Point aVec( aPickObjRect.TopLeft() ); + ::tools::Rectangle aObjRect( pNewObj->GetCurrentBoundRect() ); + Size aObjSize( aObjRect.GetSize() ); + + Fraction aScaleWidth( aPickObjSize.Width(), aObjSize.Width() ); + Fraction aScaleHeight( aPickObjSize.Height(), aObjSize.Height() ); + pNewObj->NbcResize( aObjRect.TopLeft(), aScaleWidth, aScaleHeight ); + + aVec -= aObjRect.TopLeft(); + pNewObj->NbcMove( Size( aVec.X(), aVec.Y() ) ); + + const bool bUndo = IsUndoEnabled(); + + if( bUndo ) + BegUndo(SdResId(STR_UNDO_DRAGDROP)); + pNewObj->NbcSetLayer( pPickObj->GetLayer() ); + pWorkPage->InsertObject( pNewObj.get() ); + if( bUndo ) + { + AddUndo( mrDoc.GetSdrUndoFactory().CreateUndoNewObject( *pNewObj ) ); + AddUndo( mrDoc.GetSdrUndoFactory().CreateUndoDeleteObject( *pPickObj2 ) ); + } + pWorkPage->RemoveObject( pPickObj2->GetOrdNum() ); + + if( bUndo ) + { + EndUndo(); + } + + bChanged = true; + mnAction = DND_ACTION_COPY; + } + else if( ( mnAction & DND_ACTION_LINK ) && pPickObj && pObj && + dynamic_cast< const SdrGrafObj *>( pPickObj ) == nullptr && + dynamic_cast< const SdrOle2Obj *>( pPickObj ) == nullptr ) + { + SfxItemSet aSet( mrDoc.GetPool() ); + + // set new attributes to object + const bool bUndo = IsUndoEnabled(); + if( bUndo ) + { + BegUndo( SdResId(STR_UNDO_DRAGDROP) ); + AddUndo( mrDoc.GetSdrUndoFactory().CreateUndoAttrObject( *pPickObj ) ); + } + + aSet.Put( pObj->GetMergedItemSet() ); + + /* Do not take over corner radius. There are + gradients (rectangles) in the gallery with corner + radius of 0. We should not use that on the + object. */ + aSet.ClearItem( SDRATTR_CORNER_RADIUS ); + + const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(pObj); + + if(pSdrGrafObj) + { + // If we have a graphic as source object, use its graphic + // content as fill style + aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP)); + aSet.Put(XFillBitmapItem(pSdrGrafObj->GetGraphic())); + } + + pPickObj->SetMergedItemSetAndBroadcast( aSet ); + + if( DynCastE3dObject( pPickObj ) && DynCastE3dObject( pObj ) ) + { + // handle 3D attribute in addition + SfxItemSetFixed<SID_ATTR_3D_START, SID_ATTR_3D_END> aNewSet( mrDoc.GetPool() ); + SfxItemSetFixed<SID_ATTR_3D_START, SID_ATTR_3D_END> aOldSet( mrDoc.GetPool() ); + + aOldSet.Put(pPickObj->GetMergedItemSet()); + aNewSet.Put( pObj->GetMergedItemSet() ); + + if( bUndo ) + AddUndo( + std::make_unique<E3dAttributesUndoAction>( + *static_cast< E3dObject* >(pPickObj), + aNewSet, + aOldSet)); + pPickObj->SetMergedItemSetAndBroadcast( aNewSet ); + } + + if( bUndo ) + EndUndo(); + bChanged = true; + } + } + } + + if( !bChanged ) + { + SdrPage* pWorkPage = pModel->GetSdPage( 0, PageKind::Standard ); + + pWorkPage->SetSdrObjListRectsDirty(); + + if( pOwnData ) + { + // #i120393# Clipboard data uses full object geometry range + const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() ); + + maDropPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) ); + maDropPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) ); + } + + bReturn = Paste(*pModel, maDropPos, pPage, nPasteOptions); + } + + xShell->DoClose(); + } + } + } + + if(!bReturn && CHECK_FORMAT_TRANS(SotClipboardFormatId::SBA_FIELDDATAEXCHANGE)) + { + OUString aOUString; + + if( aDataHelper.GetString( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE, aOUString ) ) + { + rtl::Reference<SdrObject> pObj = CreateFieldControl( aOUString ); + + if( pObj ) + { + ::tools::Rectangle aRect( pObj->GetLogicRect() ); + Size aSize( aRect.GetSize() ); + + maDropPos.AdjustX( -( aSize.Width() >> 1 ) ); + maDropPos.AdjustY( -( aSize.Height() >> 1 ) ); + + aRect.SetPos( maDropPos ); + pObj->SetLogicRect( aRect ); + InsertObjectAtView( pObj.get(), *GetSdrPageView(), SdrInsertFlags::SETDEFLAYER ); + bReturn = true; + } + } + } + + if(!bReturn && + !bLink && + (CHECK_FORMAT_TRANS(SotClipboardFormatId::EMBED_SOURCE) || CHECK_FORMAT_TRANS(SotClipboardFormatId::EMBEDDED_OBJ)) && + aDataHelper.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR)) + { + //TODO/LATER: is it possible that this format is binary?! (from old versions of SO) + uno::Reference < io::XInputStream > xStm; + TransferableObjectDescriptor aObjDesc; + + if (aDataHelper.GetTransferableObjectDescriptor(SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc)) + { + OUString aDocShellID = SfxObjectShell::CreateShellID(mrDoc.GetDocSh()); + xStm = aDataHelper.GetInputStream(nFormat != SotClipboardFormatId::NONE ? nFormat : SotClipboardFormatId::EMBED_SOURCE, aDocShellID); + if (!xStm.is()) + xStm = aDataHelper.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ, aDocShellID); + } + + if (xStm.is()) + { + if( mrDoc.GetDocSh() && ( mrDoc.GetDocSh()->GetClassName() == aObjDesc.maClassName ) ) + { + uno::Reference < embed::XStorage > xStore( ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm ) ); + ::sd::DrawDocShellRef xDocShRef( new ::sd::DrawDocShell( SfxObjectCreateMode::EMBEDDED, true, mrDoc.GetDocumentType() ) ); + + // mba: BaseURL doesn't make sense for clipboard functionality + SfxMedium *pMedium = new SfxMedium( xStore, OUString() ); + if( xDocShRef->DoLoad( pMedium ) ) + { + SdDrawDocument* pModel = xDocShRef->GetDoc(); + SdPage* pWorkPage = pModel->GetSdPage( 0, PageKind::Standard ); + + pWorkPage->SetSdrObjListRectsDirty(); + + if( pOwnData ) + { + // #i120393# Clipboard data uses full object geometry range + const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() ); + + maDropPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) ); + maDropPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) ); + } + + // delete pages, that are not of any interest for us + for( ::tools::Long i = pModel->GetPageCount() - 1; i >= 0; i-- ) + { + SdPage* pP = static_cast< SdPage* >( pModel->GetPage( static_cast<sal_uInt16>(i) ) ); + + if( pP->GetPageKind() != PageKind::Standard ) + pModel->DeletePage( static_cast<sal_uInt16>(i) ); + } + + bReturn = Paste(*pModel, maDropPos, pPage, nPasteOptions); + + if( !pPage ) + pPage = static_cast<SdPage*>(GetSdrPageView()->GetPage()); + + OUString aLayout = pPage->GetLayoutName(); + sal_Int32 nPos = aLayout.indexOf(SD_LT_SEPARATOR); + if (nPos != -1) + aLayout = aLayout.copy(0, nPos); + pPage->SetPresentationLayout( aLayout, false, false ); + } + + xDocShRef->DoClose(); + xDocShRef.clear(); + + } + else + { + OUString aName; + uno::Reference < embed::XEmbeddedObject > xObj = mpDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject( xStm, aName ); + if ( xObj.is() ) + { + svt::EmbeddedObjectRef aObjRef( xObj, aObjDesc.mnViewAspect ); + + Size aSize; + if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON ) + { + if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() ) + aSize = aObjDesc.maSize; + else + { + MapMode aMapMode( MapUnit::Map100thMM ); + aSize = aObjRef.GetSize( &aMapMode ); + } + } + else + { + awt::Size aSz; + MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( aObjDesc.mnViewAspect ) ); + if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() ) + { + Size aTmp(OutputDevice::LogicToLogic(aObjDesc.maSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit))); + aSz.Width = aTmp.Width(); + aSz.Height = aTmp.Height(); + xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz ); + } + + try + { + aSz = xObj->getVisualAreaSize( aObjDesc.mnViewAspect ); + } + catch( embed::NoVisualAreaSizeException& ) + { + // if the size still was not set the default size will be set later + } + + aSize = Size( aSz.Width, aSz.Height ); + + if( !aSize.Width() || !aSize.Height() ) + { + aSize.setWidth( 14100 ); + aSize.setHeight( 10000 ); + aSize = OutputDevice::LogicToLogic(Size(14100, 10000), MapMode(MapUnit::Map100thMM), MapMode(aMapUnit)); + aSz.Width = aSize.Width(); + aSz.Height = aSize.Height(); + xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz ); + } + + aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM)); + } + + Size aMaxSize( mrDoc.GetMaxObjSize() ); + + maDropPos.AdjustX( -(std::min( aSize.Width(), aMaxSize.Width() ) >> 1) ); + maDropPos.AdjustY( -(std::min( aSize.Height(), aMaxSize.Height() ) >> 1) ); + + ::tools::Rectangle aRect( maDropPos, aSize ); + rtl::Reference<SdrOle2Obj> pObj = new SdrOle2Obj( + getSdrModelFromSdrView(), + aObjRef, + aName, + aRect); + SdrPageView* pPV = GetSdrPageView(); + SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER; + + if (mpViewSh!=nullptr) + { + OSL_ASSERT (mpViewSh->GetViewShell()!=nullptr); + SfxInPlaceClient* pIpClient + = mpViewSh->GetViewShell()->GetIPClient(); + if (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive()) + nOptions |= SdrInsertFlags::DONTMARK; + } + + // bInserted of false means that pObj has been deleted + bool bInserted = InsertObjectAtView( pObj.get(), *pPV, nOptions ); + + if (bInserted && pImageMap) + pObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SvxIMapInfo( *pImageMap )) ); + + if (bInserted && pObj->IsChart()) + { + bool bDisableDataTableDialog = false; + svt::EmbeddedObjectRef::TryRunningState( xObj ); + uno::Reference< beans::XPropertySet > xProps( xObj->getComponent(), uno::UNO_QUERY ); + if ( xProps.is() && + ( xProps->getPropertyValue( "DisableDataTableDialog" ) >>= bDisableDataTableDialog ) && + bDisableDataTableDialog ) + { + xProps->setPropertyValue( "DisableDataTableDialog" , uno::Any( false ) ); + xProps->setPropertyValue( "DisableComplexChartTypes" , uno::Any( false ) ); + uno::Reference< util::XModifiable > xModifiable( xProps, uno::UNO_QUERY ); + if ( xModifiable.is() ) + { + xModifiable->setModified( true ); + } + } + } + + bReturn = true; + } + } + } + } + + if(!bReturn && + !bLink && + (CHECK_FORMAT_TRANS(SotClipboardFormatId::EMBEDDED_OBJ_OLE) || CHECK_FORMAT_TRANS(SotClipboardFormatId::EMBED_SOURCE_OLE)) && + aDataHelper.HasFormat(SotClipboardFormatId::OBJECTDESCRIPTOR_OLE)) + { + // online insert ole if format is forced or no gdi metafile is available + if( (nFormat != SotClipboardFormatId::NONE) || !aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) ) + { + uno::Reference < io::XInputStream > xStm; + TransferableObjectDescriptor aObjDesc; + + if ( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR_OLE, aObjDesc ) ) + { + uno::Reference < embed::XEmbeddedObject > xObj; + OUString aName; + + xStm = aDataHelper.GetInputStream(nFormat != SotClipboardFormatId::NONE ? nFormat : SotClipboardFormatId::EMBED_SOURCE_OLE, OUString()); + if (!xStm.is()) + xStm = aDataHelper.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ_OLE, OUString()); + + if (xStm.is()) + { + xObj = mpDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject( xStm, aName ); + } + else + { + try + { + uno::Reference< embed::XStorage > xTmpStor = ::comphelper::OStorageHelper::GetTemporaryStorage(); + uno::Reference < embed::XEmbedObjectClipboardCreator > xClipboardCreator = + embed::MSOLEObjectSystemCreator::create( ::comphelper::getProcessComponentContext() ); + + embed::InsertedObjectInfo aInfo = xClipboardCreator->createInstanceInitFromClipboard( + xTmpStor, + "DummyName" , + uno::Sequence< beans::PropertyValue >() ); + + // TODO/LATER: in future InsertedObjectInfo will be used to get container related information + // for example whether the object should be an iconified one + xObj = aInfo.Object; + if ( xObj.is() ) + mpDocSh->GetEmbeddedObjectContainer().InsertEmbeddedObject( xObj, aName ); + } + catch( uno::Exception& ) + {} + } + + if ( xObj.is() ) + { + svt::EmbeddedObjectRef aObjRef( xObj, aObjDesc.mnViewAspect ); + + // try to get the replacement image from the clipboard + Graphic aGraphic; + SotClipboardFormatId nGrFormat = SotClipboardFormatId::NONE; + +// (for Selection Manager in Trusted Solaris) +#ifndef __sun + if( aDataHelper.GetGraphic( SotClipboardFormatId::SVXB, aGraphic ) ) + nGrFormat = SotClipboardFormatId::SVXB; + else if( aDataHelper.GetGraphic( SotClipboardFormatId::GDIMETAFILE, aGraphic ) ) + nGrFormat = SotClipboardFormatId::GDIMETAFILE; + else if( aDataHelper.GetGraphic( SotClipboardFormatId::BITMAP, aGraphic ) ) + nGrFormat = SotClipboardFormatId::BITMAP; +#endif + + // insert replacement image ( if there is one ) into the object helper + if ( nGrFormat != SotClipboardFormatId::NONE ) + { + datatransfer::DataFlavor aDataFlavor; + SotExchange::GetFormatDataFlavor( nGrFormat, aDataFlavor ); + aObjRef.SetGraphic( aGraphic, aDataFlavor.MimeType ); + } + + Size aSize; + if ( aObjDesc.mnViewAspect == embed::Aspects::MSOLE_ICON ) + { + if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() ) + aSize = aObjDesc.maSize; + else + { + MapMode aMapMode( MapUnit::Map100thMM ); + aSize = aObjRef.GetSize( &aMapMode ); + } + } + else + { + MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( aObjDesc.mnViewAspect ) ); + + awt::Size aSz; + try{ + aSz = xObj->getVisualAreaSize( aObjDesc.mnViewAspect ); + } + catch( embed::NoVisualAreaSizeException& ) + { + // the default size will be set later + } + + if( aObjDesc.maSize.Width() && aObjDesc.maSize.Height() ) + { + Size aTmp(OutputDevice::LogicToLogic(aObjDesc.maSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit))); + if ( aSz.Width != aTmp.Width() || aSz.Height != aTmp.Height() ) + { + aSz.Width = aTmp.Width(); + aSz.Height = aTmp.Height(); + xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz ); + } + } + + aSize = Size( aSz.Width, aSz.Height ); + + if( !aSize.Width() || !aSize.Height() ) + { + aSize = OutputDevice::LogicToLogic(Size(14100, 10000), MapMode(MapUnit::Map100thMM), MapMode(aMapUnit)); + aSz.Width = aSize.Width(); + aSz.Height = aSize.Height(); + xObj->setVisualAreaSize( aObjDesc.mnViewAspect, aSz ); + } + + aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM)); + } + + Size aMaxSize( mrDoc.GetMaxObjSize() ); + + maDropPos.AdjustX( -(std::min( aSize.Width(), aMaxSize.Width() ) >> 1) ); + maDropPos.AdjustY( -(std::min( aSize.Height(), aMaxSize.Height() ) >> 1) ); + + ::tools::Rectangle aRect( maDropPos, aSize ); + rtl::Reference<SdrOle2Obj> pObj = new SdrOle2Obj( + getSdrModelFromSdrView(), + aObjRef, + aName, + aRect); + SdrPageView* pPV = GetSdrPageView(); + SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER; + + if (mpViewSh!=nullptr) + { + OSL_ASSERT (mpViewSh->GetViewShell()!=nullptr); + SfxInPlaceClient* pIpClient + = mpViewSh->GetViewShell()->GetIPClient(); + if (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive()) + nOptions |= SdrInsertFlags::DONTMARK; + } + + bReturn = InsertObjectAtView( pObj.get(), *pPV, nOptions ); + + if (bReturn) + { + if( pImageMap ) + pObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SvxIMapInfo( *pImageMap )) ); + + // let the object stay in loaded state after insertion + pObj->Unload(); + } + } + } + } + + if( !bReturn && aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) ) + { + // if no object was inserted, insert a picture + InsertMetaFile( aDataHelper, rPos, pImageMap.get(), true ); + bReturn = true; + } + } + + if(!bReturn && (!bLink || pPickObj) && CHECK_FORMAT_TRANS(SotClipboardFormatId::SVXB)) + { + ::tools::SvRef<SotTempStream> xStm; + + if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm ) ) + { + Point aInsertPos( rPos ); + Graphic aGraphic; + + TypeSerializer aSerializer(*xStm); + aSerializer.readGraphic(aGraphic); + + if( pOwnData && pOwnData->GetWorkDocument() ) + { + const SdDrawDocument* pWorkModel = pOwnData->GetWorkDocument(); + SdrPage* pWorkPage = const_cast<SdrPage*>( ( pWorkModel->GetPageCount() > 1 ) ? + pWorkModel->GetSdPage( 0, PageKind::Standard ) : + pWorkModel->GetPage( 0 ) ); + + pWorkPage->SetSdrObjListRectsDirty(); + + // #i120393# Clipboard data uses full object geometry range + const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() ); + + aInsertPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) ); + aInsertPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) ); + } + + // restrict movement to WorkArea + Size aImageMapSize = OutputDevice::LogicToLogic(aGraphic.GetPrefSize(), + aGraphic.GetPrefMapMode(), MapMode(MapUnit::Map100thMM)); + + ImpCheckInsertPos(aInsertPos, aImageMapSize, GetWorkArea()); + + InsertGraphic( aGraphic, mnAction, aInsertPos, nullptr, pImageMap.get() ); + bReturn = true; + } + } + + if(!bReturn && (!bLink || pPickObj) && CHECK_FORMAT_TRANS(SotClipboardFormatId::GDIMETAFILE)) + { + Point aInsertPos( rPos ); + + if( pOwnData && pOwnData->GetWorkDocument() ) + + { + const SdDrawDocument* pWorkModel = pOwnData->GetWorkDocument(); + SdrPage* pWorkPage = const_cast<SdrPage*>( ( pWorkModel->GetPageCount() > 1 ) ? + pWorkModel->GetSdPage( 0, PageKind::Standard ) : + pWorkModel->GetPage( 0 ) ); + + pWorkPage->SetSdrObjListRectsDirty(); + + // #i120393# Clipboard data uses full object geometry range + const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() ); + + aInsertPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) ); + aInsertPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) ); + } + + bReturn = InsertMetaFile( aDataHelper, aInsertPos, pImageMap.get(), nFormat == SotClipboardFormatId::NONE ); + } + + if(!bReturn && (!bLink || pPickObj) && CHECK_FORMAT_TRANS(SotClipboardFormatId::BITMAP)) + { + BitmapEx aBmpEx; + + // get basic Bitmap data + aDataHelper.GetBitmapEx(SotClipboardFormatId::BITMAP, aBmpEx); + + if(aBmpEx.IsEmpty()) + { + // if this did not work, try to get graphic formats and convert these to bitmap + Graphic aGraphic; + + if(aDataHelper.GetGraphic(SotClipboardFormatId::GDIMETAFILE, aGraphic)) + { + aBmpEx = aGraphic.GetBitmapEx(); + } + else if(aDataHelper.GetGraphic(SotClipboardFormatId::SVXB, aGraphic)) + { + aBmpEx = aGraphic.GetBitmapEx(); + } + else if(aDataHelper.GetGraphic(SotClipboardFormatId::BITMAP, aGraphic)) + { + aBmpEx = aGraphic.GetBitmapEx(); + } + } + + if(!aBmpEx.IsEmpty()) + { + Point aInsertPos( rPos ); + + if( pOwnData && pOwnData->GetWorkDocument() ) + { + const SdDrawDocument* pWorkModel = pOwnData->GetWorkDocument(); + SdrPage* pWorkPage = const_cast<SdrPage*>( ( pWorkModel->GetPageCount() > 1 ) ? + pWorkModel->GetSdPage( 0, PageKind::Standard ) : + pWorkModel->GetPage( 0 ) ); + + pWorkPage->SetSdrObjListRectsDirty(); + + // #i120393# Clipboard data uses full object geometry range + const Size aSize( pWorkPage->GetAllObjBoundRect().GetSize() ); + + aInsertPos.setX( pOwnData->GetStartPos().X() + ( aSize.Width() >> 1 ) ); + aInsertPos.setY( pOwnData->GetStartPos().Y() + ( aSize.Height() >> 1 ) ); + } + + // restrict movement to WorkArea + Size aImageMapSize(aBmpEx.GetPrefSize()); + ImpCheckInsertPos(aInsertPos, aImageMapSize, GetWorkArea()); + + InsertGraphic( aBmpEx, mnAction, aInsertPos, nullptr, pImageMap.get() ); + bReturn = true; + } + } + + if(!bReturn && pPickObj && CHECK_FORMAT_TRANS( SotClipboardFormatId::XFA ) ) + { + uno::Any const data(aDataHelper.GetAny(SotClipboardFormatId::XFA, "")); + uno::Sequence<beans::NamedValue> props; + if (data >>= props) + { + if( IsUndoEnabled() ) + { + BegUndo( SdResId(STR_UNDO_DRAGDROP) ); + AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pPickObj)); + EndUndo(); + } + + ::comphelper::SequenceAsHashMap const map(props); + drawing::FillStyle eFill(drawing::FillStyle_BITMAP); // default to something that's ignored + Color aColor(COL_BLACK); + auto it = map.find("FillStyle"); + if (it != map.end()) + { + XFillStyleItem style; + style.PutValue(it->second, 0); + eFill = style.GetValue(); + } + it = map.find("FillColor"); + if (it != map.end()) + { + XFillColorItem color; + color.PutValue(it->second, 0); + aColor = color.GetColorValue(); + } + + if( eFill == drawing::FillStyle_SOLID || eFill == drawing::FillStyle_NONE ) + { + SfxItemSet aSet( mrDoc.GetPool() ); + bool bClosed = pPickObj->IsClosedObj(); + ::sd::Window* pWin = mpViewSh->GetActiveWindow(); + double fHitLog = pWin->PixelToLogic(Size(FuPoor::HITPIX, 0 ) ).Width(); + const ::tools::Long n2HitLog = fHitLog * 2; + Point aHitPosR( rPos ); + Point aHitPosL( rPos ); + Point aHitPosT( rPos ); + Point aHitPosB( rPos ); + const SdrLayerIDSet* pVisiLayer = &GetSdrPageView()->GetVisibleLayers(); + + aHitPosR.AdjustX(n2HitLog ); + aHitPosL.AdjustX( -n2HitLog ); + aHitPosT.AdjustY(n2HitLog ); + aHitPosB.AdjustY( -n2HitLog ); + + if( bClosed && + SdrObjectPrimitiveHit(*pPickObj, aHitPosR, {fHitLog, fHitLog}, *GetSdrPageView(), pVisiLayer, false) && + SdrObjectPrimitiveHit(*pPickObj, aHitPosL, {fHitLog, fHitLog}, *GetSdrPageView(), pVisiLayer, false) && + SdrObjectPrimitiveHit(*pPickObj, aHitPosT, {fHitLog, fHitLog}, *GetSdrPageView(), pVisiLayer, false) && + SdrObjectPrimitiveHit(*pPickObj, aHitPosB, {fHitLog, fHitLog}, *GetSdrPageView(), pVisiLayer, false) ) + { + // area fill + if(eFill == drawing::FillStyle_SOLID ) + aSet.Put(XFillColorItem("", aColor)); + + aSet.Put( XFillStyleItem( eFill ) ); + } + else + aSet.Put( XLineColorItem( "", aColor ) ); + + // add text color + pPickObj->SetMergedItemSetAndBroadcast( aSet ); + } + bReturn = true; + } + } + + if(!bReturn && !bLink && CHECK_FORMAT_TRANS(SotClipboardFormatId::HTML)) + { + ::tools::SvRef<SotTempStream> xStm; + + if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::HTML, xStm ) ) + { + xStm->Seek( 0 ); + // mba: clipboard always must contain absolute URLs (could be from alien source) + bReturn = SdrView::Paste( *xStm, EETextFormat::Html, maDropPos, pPage, nPasteOptions ); + } + } + + if(!bReturn && !bLink && CHECK_FORMAT_TRANS(SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT)) + { + ::tools::SvRef<SotTempStream> xStm; + if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT, xStm ) ) + { + OutlinerView* pOLV = GetTextEditOutlinerView(); + + xStm->Seek( 0 ); + + if( pOLV ) + { + ::tools::Rectangle aRect( pOLV->GetOutputArea() ); + Point aPos( pOLV->GetWindow()->PixelToLogic( maDropPos ) ); + + if( aRect.Contains( aPos ) || ( !bDrag && IsTextEdit() ) ) + { + // mba: clipboard always must contain absolute URLs (could be from alien source) + pOLV->Read( *xStm, EETextFormat::Xml, mpDocSh->GetHeaderAttributes() ); + bReturn = true; + } + } + + if( !bReturn ) + // mba: clipboard always must contain absolute URLs (could be from alien source) + bReturn = SdrView::Paste( *xStm, EETextFormat::Xml, maDropPos, pPage, nPasteOptions ); + } + } + + if(!bReturn && !bLink) + { + bool bIsRTF = CHECK_FORMAT_TRANS(SotClipboardFormatId::RTF); + if (bIsRTF || CHECK_FORMAT_TRANS(SotClipboardFormatId::RICHTEXT)) + { + ::tools::SvRef<SotTempStream> xStm; + + if( aDataHelper.GetSotStorageStream( bIsRTF ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT, xStm ) ) + { + xStm->Seek( 0 ); + + if( bTable ) + { + bReturn = PasteRTFTable( xStm, pPage, nPasteOptions ); + } + else + { + OutlinerView* pOLV = GetTextEditOutlinerView(); + + if( pOLV ) + { + ::tools::Rectangle aRect( pOLV->GetOutputArea() ); + Point aPos( pOLV->GetWindow()->PixelToLogic( maDropPos ) ); + + if( aRect.Contains( aPos ) || ( !bDrag && IsTextEdit() ) ) + { + // mba: clipboard always must contain absolute URLs (could be from alien source) + pOLV->Read( *xStm, EETextFormat::Rtf, mpDocSh->GetHeaderAttributes() ); + bReturn = true; + } + } + + if( !bReturn ) + // mba: clipboard always must contain absolute URLs (could be from alien source) + bReturn = SdrView::Paste( *xStm, EETextFormat::Rtf, maDropPos, pPage, nPasteOptions ); + } + } + } + + bool bIsHtmlSimple = CHECK_FORMAT_TRANS(SotClipboardFormatId::HTML_SIMPLE); + if (bIsHtmlSimple) + { + ::tools::SvRef<SotTempStream> xStm; + + if (aDataHelper.GetSotStorageStream(SotClipboardFormatId::HTML_SIMPLE, xStm)) + { + xStm->Seek(0); + + OutlinerView* pOLV = GetTextEditOutlinerView(); + MSE40HTMLClipFormatObj aMSE40HTMLClipFormatObj; + SvStream* pHtmlStream = aMSE40HTMLClipFormatObj.IsValid(*xStm); + + if (pOLV) + { + ::tools::Rectangle aRect(pOLV->GetOutputArea()); + Point aPos(pOLV->GetWindow()->PixelToLogic(maDropPos)); + + if (aRect.Contains(aPos) || (!bDrag && IsTextEdit())) + { + // mba: clipboard always must contain absolute URLs (could be from alien source) + pOLV->Read(*pHtmlStream, EETextFormat::Html, mpDocSh->GetHeaderAttributes()); + bReturn = true; + } + } + + if (!bReturn) + // mba: clipboard always must contain absolute URLs (could be from alien source) + bReturn = SdrView::Paste(*pHtmlStream, EETextFormat::Html, maDropPos, pPage, nPasteOptions); + } + } + } + + if(!bReturn && CHECK_FORMAT_TRANS(SotClipboardFormatId::FILE_LIST)) + { + FileList aDropFileList; + + if( aDataHelper.GetFileList( SotClipboardFormatId::FILE_LIST, aDropFileList ) ) + { + maDropFileVector.clear(); + + for( sal_uLong i = 0, nCount = aDropFileList.Count(); i < nCount; i++ ) + maDropFileVector.push_back( aDropFileList.GetFile( i ) ); + + maDropInsertFileIdle.Start(); + } + + bReturn = true; + } + + if(!bReturn && CHECK_FORMAT_TRANS(SotClipboardFormatId::SIMPLE_FILE)) + { + OUString aDropFile; + + if( aDataHelper.GetString( SotClipboardFormatId::SIMPLE_FILE, aDropFile ) ) + { + maDropFileVector.clear(); + maDropFileVector.push_back( aDropFile ); + maDropInsertFileIdle.Start(); + } + + bReturn = true; + } + + if(!bReturn && !bLink && CHECK_FORMAT_TRANS(SotClipboardFormatId::STRING)) + { + if( ( SotClipboardFormatId::STRING == nFormat ) || + ( !aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) && + !aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) && + !aDataHelper.HasFormat( SotClipboardFormatId::FILENAME ) ) ) + { + OUString aOUString; + + if( aDataHelper.GetString( SotClipboardFormatId::STRING, aOUString ) ) + { + OutlinerView* pOLV = GetTextEditOutlinerView(); + + if( pOLV ) + { + pOLV->InsertText( aOUString ); + bReturn = true; + } + + if( !bReturn ) + bReturn = SdrView::Paste( aOUString, maDropPos, pPage, nPasteOptions ); + } + } + } + + MarkListHasChanged(); + mbIsDropAllowed = true; + rDnDAction = mnAction; + + if (bGroupUndoFromDragWithDrop) + { + // this is called eventually by the underlying toolkit anyway in the case of a self-dnd + // but we call it early in this case to group its undo actions into this open dnd undo group + // and rely on that repeated calls to View::DragFinished are safe to do + DragFinished(mnAction); + EndUndo(); + } + + return bReturn; +} + +bool View::PasteRTFTable( const ::tools::SvRef<SotTempStream>& xStm, SdrPage* pPage, SdrInsertFlags nPasteOptions ) +{ + DrawDocShellRef xShell = new DrawDocShell(SfxObjectCreateMode::INTERNAL, false, DocumentType::Impress); + xShell->DoInitNew(); + + SdDrawDocument* pModel = xShell->GetDoc(); + pModel->GetItemPool().SetDefaultMetric(MapUnit::Map100thMM); + pModel->InsertPage(pModel->AllocPage(false).get()); + + CreateTableFromRTF(*xStm, pModel); + bool bRet = Paste(*pModel, maDropPos, pPage, nPasteOptions); + + xShell->DoClose(); + + return bRet; +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/sdview4.cxx b/sd/source/ui/view/sdview4.cxx new file mode 100644 index 0000000000..f46c876dac --- /dev/null +++ b/sd/source/ui/view/sdview4.cxx @@ -0,0 +1,641 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <View.hxx> + +#include <comphelper/propertyvalue.hxx> +#include <osl/file.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/request.hxx> +#include <sfx2/docfilt.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/sfxsids.hrc> +#include <vcl/outdev.hxx> +#include <vcl/pdfread.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svx/svdpagv.hxx> +#include <svx/xbtmpit.hxx> +#include <svx/svdundo.hxx> +#include <svx/xfillit0.hxx> +#include <svx/svdograf.hxx> +#include <svx/svdomedia.hxx> +#include <svx/svdoole2.hxx> +#include <svx/ImageMapInfo.hxx> +#include <sfx2/app.hxx> +#include <avmedia/mediawindow.hxx> +#include <svtools/ehdl.hxx> +#include <svtools/sfxecode.hxx> +#include <svtools/embedhlp.hxx> +#include <vcl/graphicfilter.hxx> +#include <app.hrc> +#include <Window.hxx> +#include <DrawDocShell.hxx> +#include <DrawViewShell.hxx> +#include <fuinsfil.hxx> +#include <drawdoc.hxx> +#include <sdresid.hxx> +#include <strings.hrc> +#include <sdpage.hxx> +#include <view/SlideSorterView.hxx> +#include <com/sun/star/embed/XEmbedPersist.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/embed/NoVisualAreaSizeException.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <com/sun/star/media/XPlayer.hpp> +#include <svtools/soerr.hxx> +#include <sfx2/ipclient.hxx> +#include <tools/debug.hxx> + +using namespace com::sun::star; + +namespace sd { + +/** + * If an empty graphic object is provided, we fill it. Otherwise we fill an + * existing object at the specified position. If there is no object at the + * position, we create a new object and return a pointer to it. + */ +SdrGrafObj* View::InsertGraphic( const Graphic& rGraphic, sal_Int8& rAction, + const Point& rPos, SdrObject* pObj, ImageMap const * pImageMap ) +{ + SdrEndTextEdit(); + mnAction = rAction; + + // Is there an object at the position rPos? + rtl::Reference<SdrGrafObj> pNewGrafObj; + SdrPageView* pPV = GetSdrPageView(); + SdrObject* pPickObj = pObj; + const bool bOnMaster = pPV && pPV->GetPage() && pPV->GetPage()->IsMasterPage(); + + if(pPV && dynamic_cast< const ::sd::slidesorter::view::SlideSorterView* >(this) != nullptr) + { + if(!pPV->GetPageRect().Contains(rPos)) + pPV = nullptr; + } + + if( !pPickObj && pPV ) + { + SdrPageView* pPageView = pPV; + pPickObj = PickObj(rPos, getHitTolLog(), pPageView); + } + + const bool bIsGraphic(dynamic_cast< const SdrGrafObj* >(pPickObj) != nullptr); + + if (DND_ACTION_LINK == mnAction + && pPickObj + && pPV + && (bIsGraphic || (pPickObj->IsEmptyPresObj() && !bOnMaster))) // #121603# Do not use pObj, it may be NULL + { + // hit on SdrGrafObj with wanted new linked graphic (or PresObj placeholder hit) + if( IsUndoEnabled() ) + BegUndo(SdResId(STR_INSERTGRAPHIC)); + + SdPage* pPage = static_cast<SdPage*>( pPickObj->getSdrPageFromSdrObject() ); + + if( bIsGraphic ) + { + // We fill the object with the Bitmap + pNewGrafObj = SdrObject::Clone(static_cast<SdrGrafObj&>(*pPickObj), pPickObj->getSdrModelFromSdrObject()); + pNewGrafObj->SetGraphic(rGraphic); + } + else + { + pNewGrafObj = new SdrGrafObj( + getSdrModelFromSdrView(), + rGraphic, + pPickObj->GetLogicRect()); + pNewGrafObj->SetEmptyPresObj(true); + } + + if ( pNewGrafObj->IsEmptyPresObj() ) + { + ::tools::Rectangle aRect( pNewGrafObj->GetLogicRect() ); + pNewGrafObj->AdjustToMaxRect( aRect ); + pNewGrafObj->SetOutlinerParaObject(std::nullopt); + pNewGrafObj->SetEmptyPresObj(false); + } + + if (pPage && pPage->IsPresObj(pPickObj)) + { + // Insert new PresObj into the list + pPage->InsertPresObj( pNewGrafObj.get(), PresObjKind::Graphic ); + pNewGrafObj->SetUserCall(pPickObj->GetUserCall()); + } + + if (pImageMap) + pNewGrafObj->AppendUserData(std::unique_ptr<SdrObjUserData>(new SvxIMapInfo(*pImageMap))); + + ReplaceObjectAtView(pPickObj, *pPV, pNewGrafObj.get()); // maybe ReplaceObjectAtView + + if( IsUndoEnabled() ) + EndUndo(); + } + else if (DND_ACTION_LINK == mnAction + && pPickObj + && !bIsGraphic + && pPickObj->IsClosedObj() + && !dynamic_cast< const SdrOle2Obj* >(pPickObj)) + { + // fill style change (fill object with graphic), independent of mnAction + // and thus of DND_ACTION_LINK or DND_ACTION_MOVE + if( IsUndoEnabled() ) + { + BegUndo(SdResId(STR_UNDO_DRAGDROP)); + AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pPickObj)); + EndUndo(); + } + + SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLBITMAP> aSet(mpDocSh->GetPool()); + + aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP)); + aSet.Put(XFillBitmapItem(rGraphic)); + pPickObj->SetMergedItemSetAndBroadcast(aSet); + } + + else if ( pPV ) + { + Size aSizePixel = rGraphic.GetSizePixel(); + + // create new object + Size aSize; + + if ( rGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel ) + { + ::OutputDevice* pOutDev = nullptr; + if( mpViewSh ) + pOutDev = mpViewSh->GetActiveWindow()->GetOutDev(); + + if( !pOutDev ) + pOutDev = Application::GetDefaultDevice(); + + if( pOutDev ) + aSize = pOutDev->PixelToLogic(rGraphic.GetPrefSize(), MapMode(MapUnit::Map100thMM)); + } + else + { + aSize = OutputDevice::LogicToLogic( rGraphic.GetPrefSize(), + rGraphic.GetPrefMapMode(), + MapMode( MapUnit::Map100thMM ) ); + } + + sal_Int32 nPreferredDPI = mrDoc.getImagePreferredDPI(); + + if (rGraphic.GetGfxLink().GetType() == GfxLinkType::NativePdf && nPreferredDPI == 0 && vcl::PDF_INSERT_MAGIC_SCALE_FACTOR > 1) + nPreferredDPI = Application::GetDefaultDevice()->GetDPIX() * vcl::PDF_INSERT_MAGIC_SCALE_FACTOR; + + if (nPreferredDPI > 0) + { + auto nWidth = o3tl::convert(aSizePixel.Width() / double(nPreferredDPI), o3tl::Length::in, o3tl::Length::mm100); + auto nHeight = o3tl::convert(aSizePixel.Height() / double(nPreferredDPI), o3tl::Length::in, o3tl::Length::mm100); + if (nWidth > 0 && nHeight > 0) + aSize = Size(nWidth, nHeight); + } + + pNewGrafObj = new SdrGrafObj(getSdrModelFromSdrView(), rGraphic, ::tools::Rectangle(rPos, aSize)); + + if (nPreferredDPI > 0) + { + // move to the center of insertion point + pNewGrafObj->NbcMove(Size(-aSize.Width() / 2, -aSize.Height() / 2)); + } + else + { + SdrPage* pPage = pPV->GetPage(); + Size aPageSize( pPage->GetSize() ); + aPageSize.AdjustWidth( -(pPage->GetLeftBorder() + pPage->GetRightBorder()) ); + aPageSize.AdjustHeight( -(pPage->GetUpperBorder() + pPage->GetLowerBorder()) ); + pNewGrafObj->AdjustToMaxRect( ::tools::Rectangle( Point(), aPageSize ), true ); + } + + SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER; + bool bIsPresTarget = false; + + if ((mpViewSh + && mpViewSh->GetViewShell()!=nullptr + && mpViewSh->GetViewShell()->GetIPClient() + && mpViewSh->GetViewShell()->GetIPClient()->IsObjectInPlaceActive()) + || dynamic_cast<const ::sd::slidesorter::view::SlideSorterView* >(this)) + nOptions |= SdrInsertFlags::DONTMARK; + + if( ( mnAction & DND_ACTION_MOVE ) && pPickObj && (pPickObj->IsEmptyPresObj() || pPickObj->GetUserCall()) ) + { + SdPage* pP = static_cast< SdPage* >( pPickObj->getSdrPageFromSdrObject() ); + + if ( pP && pP->IsMasterPage() ) + bIsPresTarget = pP->IsPresObj(pPickObj); + } + + if( ( mnAction & DND_ACTION_MOVE ) && pPickObj && !bIsPresTarget ) + { + // replace object + if (pImageMap) + pNewGrafObj->AppendUserData(std::unique_ptr<SdrObjUserData>(new SvxIMapInfo(*pImageMap))); + + ::tools::Rectangle aPickObjRect(pPickObj->GetCurrentBoundRect()); + Size aPickObjSize(aPickObjRect.GetSize()); + ::tools::Rectangle aObjRect(pNewGrafObj->GetCurrentBoundRect()); + Size aObjSize(aObjRect.GetSize()); + + Fraction aScaleWidth(aPickObjSize.Width(), aObjSize.Width()); + Fraction aScaleHeight(aPickObjSize.Height(), aObjSize.Height()); + pNewGrafObj->NbcResize(aObjRect.TopLeft(), aScaleWidth, aScaleHeight); + + Point aVec = aPickObjRect.TopLeft() - aObjRect.TopLeft(); + pNewGrafObj->NbcMove(Size(aVec.X(), aVec.Y())); + + const bool bUndo = IsUndoEnabled(); + + if( bUndo ) + BegUndo(SdResId(STR_UNDO_DRAGDROP)); + pNewGrafObj->NbcSetLayer(pPickObj->GetLayer()); + SdrPage* pP = pPV->GetPage(); + pP->InsertObject(pNewGrafObj.get()); + if( bUndo ) + { + AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoNewObject(*pNewGrafObj)); + AddUndo(mrDoc.GetSdrUndoFactory().CreateUndoDeleteObject(*pPickObj)); + } + pP->RemoveObject(pPickObj->GetOrdNum()); + + if( bUndo ) + { + EndUndo(); + } + mnAction = DND_ACTION_COPY; + } + else + { + bool bSuccess = InsertObjectAtView(pNewGrafObj.get(), *pPV, nOptions); + if (!bSuccess) + pNewGrafObj = nullptr; + else if (pImageMap) + pNewGrafObj->AppendUserData(std::unique_ptr<SdrObjUserData>(new SvxIMapInfo(*pImageMap))); + } + } + + rAction = mnAction; + + return pNewGrafObj.get(); +} + +void View::InsertMediaURL( const OUString& rMediaURL, sal_Int8& rAction, + const Point& rPos, const Size& rSize, + bool const bLink ) +{ + OUString realURL; + if (bLink) + { + realURL = rMediaURL; + } + else + { + uno::Reference<frame::XModel> const xModel( + GetDoc().GetObjectShell()->GetModel()); +#if HAVE_FEATURE_AVMEDIA + bool const bRet = ::avmedia::EmbedMedia(xModel, rMediaURL, realURL); + if (!bRet) { return; } +#else + return; +#endif + } + + InsertMediaObj(realURL, rAction, rPos, rSize); +} + +SdrMediaObj* View::InsertMediaObj( const OUString& rMediaURL, sal_Int8& rAction, + const Point& rPos, const Size& rSize ) +{ + SdrEndTextEdit(); + mnAction = rAction; + + rtl::Reference<SdrMediaObj> pNewMediaObj; + SdrPageView* pPV = GetSdrPageView(); + SdrObject* pPickObj = GetEmptyPresentationObject( PresObjKind::Media ); + + if(pPV && dynamic_cast<const ::sd::slidesorter::view::SlideSorterView* >(this) ) + { + if(!pPV->GetPageRect().Contains(rPos)) + pPV = nullptr; + } + + if( mnAction == DND_ACTION_LINK && pPV && dynamic_cast< SdrMediaObj *>( pPickObj ) ) + { + pNewMediaObj = SdrObject::Clone(static_cast<SdrMediaObj&>(*pPickObj), pPickObj->getSdrModelFromSdrObject()); + pNewMediaObj->setURL(rMediaURL, ""/*TODO?*/); + + BegUndo(SdResId(STR_UNDO_DRAGDROP)); + ReplaceObjectAtView(pPickObj, *pPV, pNewMediaObj.get()); + EndUndo(); + } + else if( pPV ) + { + ::tools::Rectangle aRect( rPos, rSize ); + SdrObjUserCall* pUserCall = nullptr; + if( pPickObj ) + { + aRect = pPickObj->GetLogicRect(); + pUserCall = pPickObj->GetUserCall(); // ReplaceObjectAtView can free pPickObj + } + + pNewMediaObj = new SdrMediaObj( + getSdrModelFromSdrView(), + aRect); + + bool bIsPres = false; + if( pPickObj ) + { + SdPage* pPage = static_cast< SdPage* >(pPickObj->getSdrPageFromSdrObject()); + bIsPres = pPage && pPage->IsPresObj(pPickObj); + if( bIsPres ) + { + pPage->InsertPresObj( pNewMediaObj.get(), PresObjKind::Media ); + } + } + + if( pPickObj ) + ReplaceObjectAtView(pPickObj, *pPV, pNewMediaObj.get()); + else + { + if (!InsertObjectAtView(pNewMediaObj.get(), *pPV, SdrInsertFlags::SETDEFLAYER)) + pNewMediaObj = nullptr; + } + + OUString referer; + DrawDocShell * sh = GetDocSh(); + if (sh != nullptr && sh->HasName()) { + referer = sh->GetMedium()->GetName(); + } + + if (pNewMediaObj) + { + pNewMediaObj->setURL(rMediaURL, referer); + + if( pPickObj ) + { + pNewMediaObj->AdjustToMaxRect( aRect ); + if( bIsPres ) + pNewMediaObj->SetUserCall( pUserCall ); + } + } + } + + rAction = mnAction; + + return pNewMediaObj.get(); +} + +/** + * Timer handler for InsertFile at Drop() + */ +IMPL_LINK_NOARG(View, DropInsertFileHdl, Timer *, void) +{ + DBG_ASSERT( mpViewSh, "sd::View::DropInsertFileHdl(), I need a view shell to work!" ); + if( !mpViewSh ) + return; + + SfxErrorContext aEc( ERRCTX_ERROR, mpViewSh->GetFrameWeld(), RID_SO_ERRCTX ); + ErrCode nError = ERRCODE_NONE; + + ::std::vector< OUString >::const_iterator aIter( maDropFileVector.begin() ); + + while( (aIter != maDropFileVector.end()) && !nError ) + { + OUString aCurrentDropFile( *aIter ); + INetURLObject aURL( aCurrentDropFile ); + bool bHandled = false; + + if( aURL.GetProtocol() == INetProtocol::NotValid ) + { + OUString aURLStr; + osl::FileBase::getFileURLFromSystemPath( aCurrentDropFile, aURLStr ); + aURL = INetURLObject( aURLStr ); + } + + GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter(); + Graphic aGraphic; + + aCurrentDropFile = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + +#if HAVE_FEATURE_AVMEDIA + if( !::avmedia::MediaWindow::isMediaURL( aCurrentDropFile, ""/*TODO?*/ ) ) +#else +#endif + { + if( !rGraphicFilter.ImportGraphic( aGraphic, aURL ) ) + { + sal_Int8 nTempAction = ( aIter == maDropFileVector.begin() ) ? mnAction : 0; + const bool bLink = ( ( nTempAction & DND_ACTION_LINK ) != 0 ); + SdrGrafObj* pGrafObj = InsertGraphic( aGraphic, nTempAction, maDropPos, nullptr, nullptr ); + if(pGrafObj && bLink) + { + pGrafObj->SetGraphicLink( aCurrentDropFile ); + } + + // return action from first inserted graphic + if( aIter == maDropFileVector.begin() ) + mnAction = nTempAction; + + bHandled = true; + } + if (!bHandled) + { + std::shared_ptr<const SfxFilter> pFoundFilter; + SfxMedium aSfxMedium( aCurrentDropFile, StreamMode::READ | StreamMode::SHARE_DENYNONE ); + ErrCode nErr = SfxGetpApp()->GetFilterMatcher().GuessFilter( aSfxMedium, pFoundFilter ); + + if( pFoundFilter && !nErr ) + { + ::std::vector< OUString > aFilterVector; + OUString aFilterName = pFoundFilter->GetFilterName(); + OUString aLowerAsciiFileName = aCurrentDropFile.toAsciiLowerCase(); + + FuInsertFile::GetSupportedFilterVector( aFilterVector ); + + if( ( ::std::find( aFilterVector.begin(), aFilterVector.end(), pFoundFilter->GetMimeType() ) != aFilterVector.end() ) || + aFilterName.indexOf( "Text" ) != -1 || + aFilterName.indexOf( "Rich" ) != -1 || + aFilterName.indexOf( "RTF" ) != -1 || + aFilterName.indexOf( "HTML" ) != -1 || + aLowerAsciiFileName.indexOf(".sdd") != -1 || + aLowerAsciiFileName.indexOf(".sda") != -1 || + aLowerAsciiFileName.indexOf(".sxd") != -1 || + aLowerAsciiFileName.indexOf(".sxi") != -1 || + aLowerAsciiFileName.indexOf(".std") != -1 || + aLowerAsciiFileName.indexOf(".sti") != -1 ) + { + ::sd::Window* pWin = mpViewSh->GetActiveWindow(); + SfxRequest aReq(SID_INSERTFILE, ::SfxCallMode::SLOT, mrDoc.GetItemPool()); + SfxStringItem aItem1( ID_VAL_DUMMY0, aCurrentDropFile ), aItem2( ID_VAL_DUMMY1, pFoundFilter->GetFilterName() ); + + aReq.AppendItem( aItem1 ); + aReq.AppendItem( aItem2 ); + FuInsertFile::Create( mpViewSh, pWin, this, &mrDoc, aReq ); + bHandled = true; + } + } + } + } + +#if HAVE_FEATURE_AVMEDIA + if (!bHandled) + { + bool bShallowDetect = ::avmedia::MediaWindow::isMediaURL(aCurrentDropFile, ""/*TODO?*/); + if (bShallowDetect) + { + mxDropMediaSizeListener.set(new avmedia::PlayerListener( + [this, aCurrentDropFile](const css::uno::Reference<css::media::XPlayer>& rPlayer){ + SolarMutexGuard g; + + css::awt::Size aSize = rPlayer->getPreferredPlayerWindowSize(); + Size aPrefSize(aSize.Width, aSize.Height); + + if (aPrefSize.Width() && aPrefSize.Height()) + { + ::sd::Window* pWin = mpViewSh->GetActiveWindow(); + + if( pWin ) + aPrefSize = pWin->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM)); + else + aPrefSize = Application::GetDefaultDevice()->PixelToLogic(aPrefSize, MapMode(MapUnit::Map100thMM)); + } + else + aPrefSize = Size( 5000, 5000 ); + + InsertMediaURL(aCurrentDropFile, mnAction, maDropPos, aPrefSize, true); + + mxDropMediaSizeListener.clear(); + })); + } + bHandled = bShallowDetect && ::avmedia::MediaWindow::isMediaURL(aCurrentDropFile, ""/*TODO?*/, true, mxDropMediaSizeListener); + } +#endif + + if (!bHandled) + { + if( mnAction & DND_ACTION_LINK ) + static_cast< DrawViewShell* >( mpViewSh )->InsertURLButton( aCurrentDropFile, aCurrentDropFile, OUString(), &maDropPos ); + else + { + if( mpViewSh ) + { + try + { + //TODO/MBA: testing + OUString aName; + uno::Sequence < beans::PropertyValue > aMedium{ comphelper::makePropertyValue( + "URL", aCurrentDropFile) }; + + uno::Reference < embed::XEmbeddedObject > xObj = mpDocSh->GetEmbeddedObjectContainer(). + InsertEmbeddedObject( aMedium, aName ); + + uno::Reference < embed::XEmbedPersist > xPersist( xObj, uno::UNO_QUERY ); + if ( xPersist.is()) + { + // TODO/LEAN: VisualArea access can switch the object to running state + sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT; + + xPersist->storeOwn(); + + awt::Size aSz; + try + { + aSz = xObj->getVisualAreaSize( nAspect ); + } + catch( embed::NoVisualAreaSizeException& ) + { + // the default size will be set later + } + + Size aSize( aSz.Width, aSz.Height ); + ::tools::Rectangle aRect; + + if (!aSize.Width() || !aSize.Height()) + { + aSize.setWidth( 1410 ); + aSize.setHeight( 1000 ); + } + + aRect = ::tools::Rectangle( maDropPos, aSize ); + + rtl::Reference<SdrOle2Obj> pOleObj = new SdrOle2Obj( + getSdrModelFromSdrView(), + svt::EmbeddedObjectRef(xObj, nAspect), + aName, + aRect); + SdrInsertFlags nOptions = SdrInsertFlags::SETDEFLAYER; + + if (mpViewSh != nullptr) + { + OSL_ASSERT (mpViewSh->GetViewShell()!=nullptr); + SfxInPlaceClient* pIpClient = + mpViewSh->GetViewShell()->GetIPClient(); + if (pIpClient!=nullptr && pIpClient->IsObjectInPlaceActive()) + nOptions |= SdrInsertFlags::DONTMARK; + } + + if (InsertObjectAtView( pOleObj.get(), *GetSdrPageView(), nOptions )) + pOleObj->SetLogicRect( aRect ); + aSz.Width = aRect.GetWidth(); + aSz.Height = aRect.GetHeight(); + xObj->setVisualAreaSize( nAspect,aSz ); + } + } + catch( uno::Exception& ) + { + nError = ERRCODE_IO_GENERAL; + // TODO/LATER: better error handling + } + } + } + } + + ++aIter; + } + + if( nError ) + ErrorHandler::HandleError( nError ); +} + +/** + * Timer handler for Errorhandling at Drop() + */ +IMPL_LINK_NOARG(View, DropErrorHdl, Timer *, void) +{ + vcl::Window* pWin = mpViewSh ? mpViewSh->GetActiveWindow() : nullptr; + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWin ? pWin->GetFrameWeld() : nullptr, + VclMessageType::Info, VclButtonsType::Ok, + SdResId(STR_ACTION_NOTPOSSIBLE))); + xInfoBox->run(); +} + +/** + * @returns StyleSheet from selection + */ +SfxStyleSheet* View::GetStyleSheet() const +{ + return SdrView::GetStyleSheet(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/sdview5.cxx b/sd/source/ui/view/sdview5.cxx new file mode 100644 index 0000000000..c3ac066bc0 --- /dev/null +++ b/sd/source/ui/view/sdview5.cxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sdpage.hxx> +#include <View.hxx> +#include <pres.hxx> + +#include <svx/svdpagv.hxx> + +namespace sd { + +static bool implIsMultiPresObj( PresObjKind eKind ) +{ + switch( eKind ) + { + case PresObjKind::Outline: + case PresObjKind::Graphic: + case PresObjKind::Object: + case PresObjKind::Chart: + case PresObjKind::OrgChart: + case PresObjKind::Table: + case PresObjKind::Media: + return true; + default: + return false; + } +} + +SdPage* View::GetPage() +{ + SdPage* pPage = nullptr; + SdrPageView* pPV = GetSdrPageView(); + if( pPV ) + { + pPage = static_cast< SdPage* >( pPV->GetPage() ); + } + + return pPage; +} + +// returns selected object in case there's just one object in the selection +SdrObject* View::GetSelectedSingleObject(SdPage const * pPage) +{ + SdrObject* pRet = nullptr; + if( pPage ) + { + // first try selected shape + if ( AreObjectsMarked() ) + { + const SdrMarkList& rMarkList = GetMarkedObjectList(); + + if (rMarkList.GetMarkCount() == 1) + { + SdrMark* pMark = rMarkList.GetMark(0); + pRet = pMark->GetMarkedSdrObj(); + } + } + } + + return pRet; +} + +SdrObject* View::GetEmptyPresentationObject( PresObjKind eKind ) +{ + SdPage* pPage = GetPage(); + SdrObject* pEmptyObj = nullptr; + + if ( pPage && !pPage->IsMasterPage() ) { + SdrObject* pObj = GetSelectedSingleObject( pPage ); + + if( pObj && pObj->IsEmptyPresObj() && implIsMultiPresObj( pPage->GetPresObjKind(pObj) ) ) + pEmptyObj = pObj; + + // try to find empty pres obj of same type + if( !pEmptyObj ) + { + int nIndex = 1; + do + { + pEmptyObj = pPage->GetPresObj(eKind, nIndex++ ); + } + while( (pEmptyObj != nullptr) && (!pEmptyObj->IsEmptyPresObj()) ); + } + + // last try to find empty pres obj of multiple type + if( !pEmptyObj ) + { + const std::list< SdrObject* >& rShapes = pPage->GetPresentationShapeList().getList(); + + auto iter = std::find_if(rShapes.begin(), rShapes.end(), + [&pPage](SdrObject* pShape) { return pShape->IsEmptyPresObj() && implIsMultiPresObj(pPage->GetPresObjKind(pShape)); }); + if (iter != rShapes.end()) + pEmptyObj = (*iter); + } + } + + return pEmptyObj; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/sdwindow.cxx b/sd/source/ui/view/sdwindow.cxx new file mode 100644 index 0000000000..6d5481318e --- /dev/null +++ b/sd/source/ui/view/sdwindow.cxx @@ -0,0 +1,1058 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <Window.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/request.hxx> + +#include <sfx2/viewfrm.hxx> +#include <svx/svxids.hrc> + +#include <editeng/outliner.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> + +#include <app.hrc> +#include <ViewShell.hxx> +#include <DrawViewShell.hxx> +#include <DrawDocShell.hxx> +#include <PresentationViewShell.hxx> +#include <View.hxx> +#include <FrameView.hxx> +#include <OutlineViewShell.hxx> +#include <OutlineView.hxx> +#include <drawdoc.hxx> +#include <WindowUpdater.hxx> +#include <ViewShellBase.hxx> +#include <uiobject.hxx> + +#include <officecfg/Office/Common.hxx> +#include <sal/log.hxx> +#include <tools/debug.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/settings.hxx> +#include <comphelper/lok.hxx> +#include <sfx2/lokhelper.hxx> + +namespace sd { + +#define SCROLL_LINE_FACT 0.05 ///< factor for line scrolling +#define SCROLL_PAGE_FACT 0.5 ///< factor for page scrolling +#define SCROLL_SENSITIVE 20 ///< sensitive area in pixel +#define ZOOM_MULTIPLICATOR 10000 ///< multiplier to avoid rounding errors +#define MIN_ZOOM 5 ///< minimal zoom factor +#define MAX_ZOOM 3000 ///< maximal zoom factor + +Window::Window(vcl::Window* pParent) + : vcl::DocWindow(pParent, WinBits(WB_CLIPCHILDREN | WB_DIALOGCONTROL)), + DropTargetHelper( this ), + maWinPos(0, 0), // precautionary; but the values should be set + maViewOrigin(0, 0), // again from the owner of the window + maViewSize(1000, 1000), + maPrevSize(-1,-1), + mnMinZoom(MIN_ZOOM), + mnMaxZoom(MAX_ZOOM), + mbMinZoomAutoCalc(false), + mbCenterAllowed(true), + mnTicks (0), + mpViewShell(nullptr), + mbUseDropScroll (true) +{ + SetDialogControlFlags( DialogControlFlags::Return | DialogControlFlags::WantFocus ); + + MapMode aMap(GetMapMode()); + aMap.SetMapUnit(MapUnit::Map100thMM); + SetMapMode(aMap); + + // with it, the vcl::WindowColor is used in the slide mode + SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetWindowColor() ) ); + + // adjust contrast mode initially + bool bUseContrast = GetSettings().GetStyleSettings().GetHighContrastMode(); + GetOutDev()->SetDrawMode( bUseContrast + ? sd::OUTPUT_DRAWMODE_CONTRAST + : sd::OUTPUT_DRAWMODE_COLOR ); + + // #i78183# Added after discussed with AF + EnableRTL(false); +} + +Window::~Window() +{ + disposeOnce(); +} + +void Window::dispose() +{ + if (mpViewShell != nullptr) + { + WindowUpdater* pWindowUpdater = mpViewShell->GetWindowUpdater(); + if (pWindowUpdater != nullptr) + pWindowUpdater->UnregisterWindow (this); + } + DropTargetHelper::dispose(); + vcl::Window::dispose(); +} + +void Window::SetViewShell (ViewShell* pViewSh) +{ + WindowUpdater* pWindowUpdater = nullptr; + // Unregister at device updater of old view shell. + if (mpViewShell != nullptr) + { + pWindowUpdater = mpViewShell->GetWindowUpdater(); + if (pWindowUpdater != nullptr) + pWindowUpdater->UnregisterWindow (this); + } + + mpViewShell = pViewSh; + + // Register at device updater of new view shell + if (mpViewShell != nullptr) + { + pWindowUpdater = mpViewShell->GetWindowUpdater(); + if (pWindowUpdater != nullptr) + pWindowUpdater->RegisterWindow (this); + } +} + +ViewShell* Window::GetViewShell() +{ + return mpViewShell; +} + +void Window::CalcMinZoom() +{ + // Are we entitled to change the minimal zoom factor? + if ( !mbMinZoomAutoCalc ) + return; + + // Get current zoom factor. + ::tools::Long nZoom = GetZoom(); + + // Get the rectangle of the output area in logical coordinates + // and calculate the scaling factors that would lead to the view + // area (also called application area) to completely fill the + // window. + Size aWinSize = PixelToLogic(GetOutputSizePixel()); + sal_uLong nX = static_cast<sal_uLong>(static_cast<double>(aWinSize.Width()) + * double(ZOOM_MULTIPLICATOR) / static_cast<double>(maViewSize.Width())); + sal_uLong nY = static_cast<sal_uLong>(static_cast<double>(aWinSize.Height()) + * double(ZOOM_MULTIPLICATOR) / static_cast<double>(maViewSize.Height())); + + // Decide whether to take the larger or the smaller factor. + sal_uLong nFact = std::min(nX, nY); + + // The factor is transformed according to the current zoom factor. + nFact = nFact * nZoom / ZOOM_MULTIPLICATOR; + mnMinZoom = std::max(sal_uInt16(MIN_ZOOM), static_cast<sal_uInt16>(nFact)); + + // If the current zoom factor is smaller than the calculated minimal + // zoom factor then set the new minimal factor as the current zoom + // factor. + if ( nZoom < static_cast<::tools::Long>(mnMinZoom) ) + SetZoomFactor(mnMinZoom); +} + +void Window::SetMinZoom (::tools::Long nMin) +{ + mnMinZoom = static_cast<sal_uInt16>(nMin); +} + +void Window::SetMaxZoom (::tools::Long nMax) +{ + mnMaxZoom = static_cast<sal_uInt16>(nMax); +} + +::tools::Long Window::GetZoom() const +{ + if( GetMapMode().GetScaleX().GetDenominator() ) + { + return ::tools::Long(GetMapMode().GetScaleX() * 100); + } + else + { + return 0; + } +} + +void Window::Resize() +{ + vcl::Window::Resize(); + CalcMinZoom(); + + if( mpViewShell && mpViewShell->GetViewFrame() ) + mpViewShell->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER ); +} + +void Window::PrePaint(vcl::RenderContext& /*rRenderContext*/) +{ + if ( mpViewShell ) + mpViewShell->PrePaint(); +} + +void Window::Paint(vcl::RenderContext& /*rRenderContext*/, const ::tools::Rectangle& rRect) +{ + if ( mpViewShell ) + mpViewShell->Paint(rRect, this); +} + +void Window::KeyInput(const KeyEvent& rKEvt) +{ + if (getenv("SD_DEBUG") && rKEvt.GetKeyCode().GetCode() == KEY_F12 && mpViewShell) + { + mpViewShell->GetDoc()->dumpAsXml(nullptr); + if (OutlinerView *pOLV = mpViewShell->GetView()->GetTextEditOutlinerView()) + pOLV->GetEditView().GetEditEngine()->dumpAsXmlEditDoc(nullptr); + return; + } + + if (!(mpViewShell && mpViewShell->KeyInput(rKEvt, this))) + { + if (mpViewShell && rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE) + { + mpViewShell->GetViewShell()->Escape(); + } + else + { + vcl::Window::KeyInput(rKEvt); + } + } +} + +void Window::MouseButtonDown(const MouseEvent& rMEvt) +{ + if ( mpViewShell ) + mpViewShell->MouseButtonDown(rMEvt, this); +} + +void Window::MouseMove(const MouseEvent& rMEvt) +{ + if ( mpViewShell ) + mpViewShell->MouseMove(rMEvt, this); +} + +void Window::MouseButtonUp(const MouseEvent& rMEvt) +{ + mnTicks = 0; + + if ( mpViewShell ) + mpViewShell->MouseButtonUp(rMEvt, this); +} + +void Window::Command(const CommandEvent& rCEvt) +{ + if (mpViewShell) + mpViewShell->Command(rCEvt, this); + //pass at least alt press/release to parent impl + if (rCEvt.GetCommand() == CommandEventId::ModKeyChange) + vcl::Window::Command(rCEvt); + //show the text edit outliner view cursor + else if (mpViewShell && !HasFocus() && rCEvt.GetCommand() == CommandEventId::CursorPos) + { + // tdf#138855 Getting Focus may destroy TextEditOutlinerView so Grab if + // text editing active, but fetch the TextEditOutlinerView post-grab + if (mpViewShell->GetView()->IsTextEdit()) + { + GrabFocus(); + OutlinerView* pOLV = mpViewShell->GetView()->GetTextEditOutlinerView(); + if (pOLV && this == pOLV->GetWindow()) + pOLV->ShowCursor(); + } + } +} + +bool Window::EventNotify( NotifyEvent& rNEvt ) +{ + bool bResult = false; + if ( mpViewShell ) + { + bResult = mpViewShell->Notify(rNEvt, this); + } + if( !bResult ) + bResult = vcl::Window::EventNotify(rNEvt); + + return bResult; +} + +void Window::RequestHelp(const HelpEvent& rEvt) +{ + if (!mpViewShell || !mpViewShell->RequestHelp(rEvt)) + vcl::Window::RequestHelp( rEvt ); +} + +/** + * Set the position of the upper left corner from the visible area of the + * window. + */ +void Window::SetWinViewPos(const Point& rPnt) +{ + maWinPos = rPnt; +} + +/** + * Set origin of the representation in respect to the whole working area. + */ +void Window::SetViewOrigin(const Point& rPnt) +{ + maViewOrigin = rPnt; +} + +/** + * Set size of the whole working area which can be seen with the window. + */ +void Window::SetViewSize(const Size& rSize) +{ + maViewSize = rSize; + CalcMinZoom(); +} + +void Window::SetCenterAllowed (bool bIsAllowed) +{ + mbCenterAllowed = bIsAllowed; +} + +::tools::Long Window::SetZoomFactor(::tools::Long nZoom) +{ + // Clip the zoom factor to the valid range marked by nMinZoom as + // calculated by CalcMinZoom() and the constant MAX_ZOOM. + if ( nZoom > MAX_ZOOM ) + nZoom = MAX_ZOOM; + if ( nZoom < static_cast<::tools::Long>(mnMinZoom) ) + nZoom = mnMinZoom; + + // Set the zoom factor at the window's map mode. + if (!comphelper::LibreOfficeKit::isActive()) + { + MapMode aMap(GetMapMode()); + aMap.SetScaleX(Fraction(nZoom, 100)); + aMap.SetScaleY(Fraction(nZoom, 100)); + SetMapMode(aMap); + } + + // invalidate previous size - it was relative to the old scaling + maPrevSize = Size(-1,-1); + + // Update the map mode's origin (to what effect?). + UpdateMapOrigin(); + + // Update the view's snapping to the new zoom factor. + if ( auto pDrawViewShell = dynamic_cast< DrawViewShell *>( mpViewShell ) ) + pDrawViewShell->GetView()->RecalcLogicSnapMagnetic(*GetOutDev()); + + // Return the zoom factor just in case it has been changed above to lie + // inside the valid range. + return nZoom; +} + +void Window::SetZoomIntegral(::tools::Long nZoom) +{ + // Clip the zoom factor to the valid range marked by nMinZoom as + // previously calculated by <member>CalcMinZoom()</member> and the + // MAX_ZOOM constant. + if ( nZoom > MAX_ZOOM ) + nZoom = MAX_ZOOM; + if ( nZoom < static_cast<::tools::Long>(mnMinZoom) ) + nZoom = mnMinZoom; + + // Calculate the window's new origin. + Size aSize = PixelToLogic(GetOutputSizePixel()); + ::tools::Long nW = aSize.Width() * GetZoom() / nZoom; + ::tools::Long nH = aSize.Height() * GetZoom() / nZoom; + maWinPos.AdjustX((aSize.Width() - nW) / 2 ); + maWinPos.AdjustY((aSize.Height() - nH) / 2 ); + if ( maWinPos.X() < 0 ) maWinPos.setX( 0 ); + if ( maWinPos.Y() < 0 ) maWinPos.setY( 0 ); + + // Finally update this window's map mode to the given zoom factor that + // has been clipped to the valid range. + SetZoomFactor(nZoom); +} + +::tools::Long Window::GetZoomForRect( const ::tools::Rectangle& rZoomRect ) +{ + ::tools::Long nRetZoom = 100; + + if( (rZoomRect.GetWidth() != 0) && (rZoomRect.GetHeight() != 0)) + { + // Calculate the scale factors which will lead to the given + // rectangle being fully visible (when translated accordingly) as + // large as possible in the output area independently in both + // coordinate directions . + sal_uLong nX(0); + sal_uLong nY(0); + + const Size aWinSize( PixelToLogic(GetOutputSizePixel()) ); + if(rZoomRect.GetHeight()) + { + nX = static_cast<sal_uLong>(static_cast<double>(aWinSize.Height()) + * double(ZOOM_MULTIPLICATOR) / static_cast<double>(rZoomRect.GetHeight())); + } + + if(rZoomRect.GetWidth()) + { + nY = static_cast<sal_uLong>(static_cast<double>(aWinSize.Width()) + * double(ZOOM_MULTIPLICATOR) / static_cast<double>(rZoomRect.GetWidth())); + } + + // Use the smaller one of both so that the zoom rectangle will be + // fully visible with respect to both coordinate directions. + sal_uLong nFact = std::min(nX, nY); + + // Transform the current zoom factor so that it leads to the desired + // scaling. + nRetZoom = nFact * GetZoom() / ZOOM_MULTIPLICATOR; + + // Calculate the new origin. + if ( nFact == 0 ) + { + // Don't change anything if the scale factor is degenerate. + nRetZoom = GetZoom(); + } + else + { + // Clip the zoom factor to the valid range marked by nMinZoom as + // previously calculated by <member>CalcMinZoom()</member> and the + // MAX_ZOOM constant. + if ( nRetZoom > MAX_ZOOM ) + nRetZoom = MAX_ZOOM; + if ( nRetZoom < static_cast<::tools::Long>(mnMinZoom) ) + nRetZoom = mnMinZoom; + } + } + + return nRetZoom; +} + +/** Recalculate the zoom factor and translation so that the given rectangle + is displayed centered and as large as possible while still being fully + visible in the window. +*/ +::tools::Long Window::SetZoomRect (const ::tools::Rectangle& rZoomRect) +{ + ::tools::Long nNewZoom = 100; + + if (rZoomRect.GetWidth() == 0 || rZoomRect.GetHeight() == 0) + { + // The given rectangle is degenerate. Use the default zoom factor + // (above) of 100%. + SetZoomIntegral(nNewZoom); + } + else + { + Point aPos = rZoomRect.TopLeft(); + // Transform the output area from pixel coordinates into logical + // coordinates. + Size aWinSize = PixelToLogic(GetOutputSizePixel()); + // Paranoia! The degenerate case of zero width or height has been + // taken care of above. + DBG_ASSERT(rZoomRect.GetWidth(), "ZoomRect-Width = 0!"); + DBG_ASSERT(rZoomRect.GetHeight(), "ZoomRect-Height = 0!"); + + // Calculate the scale factors which will lead to the given + // rectangle being fully visible (when translated accordingly) as + // large as possible in the output area independently in both + // coordinate directions . + sal_uLong nX(0); + sal_uLong nY(0); + + if(rZoomRect.GetHeight()) + { + nX = static_cast<sal_uLong>(static_cast<double>(aWinSize.Height()) + * double(ZOOM_MULTIPLICATOR) / static_cast<double>(rZoomRect.GetHeight())); + } + + if(rZoomRect.GetWidth()) + { + nY = static_cast<sal_uLong>(static_cast<double>(aWinSize.Width()) + * double(ZOOM_MULTIPLICATOR) / static_cast<double>(rZoomRect.GetWidth())); + } + + // Use the smaller one of both so that the zoom rectangle will be + // fully visible with respect to both coordinate directions. + sal_uLong nFact = std::min(nX, nY); + + // Transform the current zoom factor so that it leads to the desired + // scaling. + ::tools::Long nZoom = nFact * GetZoom() / ZOOM_MULTIPLICATOR; + + // Calculate the new origin. + if ( nFact == 0 ) + { + // Don't change anything if the scale factor is degenerate. + nNewZoom = GetZoom(); + } + else + { + // Calculate the new window position that centers the given + // rectangle on the screen. + if ( nZoom > MAX_ZOOM ) + nFact = nFact * MAX_ZOOM / nZoom; + + maWinPos = maViewOrigin + aPos; + + aWinSize.setWidth( static_cast<::tools::Long>(static_cast<double>(aWinSize.Width()) * double(ZOOM_MULTIPLICATOR) / static_cast<double>(nFact)) ); + maWinPos.AdjustX((rZoomRect.GetWidth() - aWinSize.Width()) / 2 ); + aWinSize.setHeight( static_cast<::tools::Long>(static_cast<double>(aWinSize.Height()) * double(ZOOM_MULTIPLICATOR) / static_cast<double>(nFact)) ); + maWinPos.AdjustY((rZoomRect.GetHeight() - aWinSize.Height()) / 2 ); + + if ( maWinPos.X() < 0 ) maWinPos.setX( 0 ); + if ( maWinPos.Y() < 0 ) maWinPos.setY( 0 ); + + // Adapt the window's map mode to the new zoom factor. + nNewZoom = SetZoomFactor(nZoom); + } + } + + return nNewZoom; +} + +void Window::SetMinZoomAutoCalc (bool bAuto) +{ + mbMinZoomAutoCalc = bAuto; +} + +/** + * Calculate and set new MapMode origin. + * If aWinPos.X()/Y() == -1, then we center the corresponding position (e.g. for + * initialization). + */ +void Window::UpdateMapOrigin(bool bInvalidate) +{ + bool bChanged = false; + const Size aWinSize = PixelToLogic(GetOutputSizePixel()); + + if ( mbCenterAllowed ) + { + if( maPrevSize != Size(-1,-1) ) + { + // keep view centered around current pos, when window + // resizes + maWinPos.AdjustX( -((aWinSize.Width() - maPrevSize.Width()) / 2) ); + maWinPos.AdjustY( -((aWinSize.Height() - maPrevSize.Height()) / 2) ); + bChanged = true; + } + + if ( maWinPos.X() > maViewSize.Width() - aWinSize.Width() ) + { + maWinPos.setX( maViewSize.Width() - aWinSize.Width() ); + bChanged = true; + } + if ( maWinPos.Y() > maViewSize.Height() - aWinSize.Height() ) + { + maWinPos.setY( maViewSize.Height() - aWinSize.Height() ); + bChanged = true; + } + if ( aWinSize.Width() > maViewSize.Width() || maWinPos.X() < 0 ) + { + maWinPos.setX( maViewSize.Width() / 2 - aWinSize.Width() / 2 ); + bChanged = true; + } + if ( aWinSize.Height() > maViewSize.Height() || maWinPos.Y() < 0 ) + { + maWinPos.setY( maViewSize.Height() / 2 - aWinSize.Height() / 2 ); + bChanged = true; + } + } + + UpdateMapMode (); + + maPrevSize = aWinSize; + + // When tiled rendering, the above UpdateMapMode() call doesn't touch the map mode. + if (bChanged && bInvalidate && !comphelper::LibreOfficeKit::isActive()) + Invalidate(); +} + +void Window::UpdateMapMode() +{ + maWinPos -= maViewOrigin; + Size aPix(maWinPos.X(), maWinPos.Y()); + aPix = LogicToPixel(aPix); + // Size has to be a multiple of BRUSH_SIZE due to the correct depiction of + // pattern + // #i2237# + // removed old stuff here which still forced zoom to be + // %BRUSH_SIZE which is outdated now + + if (dynamic_cast< DrawViewShell *>( mpViewShell )) + { + // page should not "stick" to the window border + if (aPix.Width() == 0) + { + // #i2237# + // Since BRUSH_SIZE alignment is outdated now, i use the + // former constant here directly + aPix.AdjustWidth( -8 ); + } + if (aPix.Height() == 0) + { + // #i2237# + // Since BRUSH_SIZE alignment is outdated now, i use the + // former constant here directly + aPix.AdjustHeight( -8 ); + } + } + + aPix = PixelToLogic(aPix); + maWinPos.setX( aPix.Width() ); + maWinPos.setY( aPix.Height() ); + Point aNewOrigin (-maWinPos.X(), -maWinPos.Y()); + maWinPos += maViewOrigin; + + if (!comphelper::LibreOfficeKit::isActive()) + { + MapMode aMap(GetMapMode()); + aMap.SetOrigin(aNewOrigin); + SetMapMode(aMap); + } +} + +/** + * @returns X position of the visible area as fraction (< 1) of the whole + * working area. + */ +double Window::GetVisibleX() const +{ + return maViewSize.Width() == 0 ? 0 : (static_cast<double>(maWinPos.X()) / maViewSize.Width()); +} + +/** + * @returns Y position of the visible area as fraction (< 1) of the whole + * working area. + */ +double Window::GetVisibleY() const +{ + return maViewSize.Height() == 0 ? 0 : (static_cast<double>(maWinPos.Y()) / maViewSize.Height()); +} + +/** + * Set x and y position of the visible area as fraction (< 1) of the whole + * working area. Negative values are ignored. + */ +void Window::SetVisibleXY(double fX, double fY) +{ + ::tools::Long nOldX = maWinPos.X(); + ::tools::Long nOldY = maWinPos.Y(); + + if ( fX >= 0 ) + maWinPos.setX( static_cast<::tools::Long>(fX * maViewSize.Width()) ); + if ( fY >= 0 ) + maWinPos.setY( static_cast<::tools::Long>(fY * maViewSize.Height()) ); + UpdateMapOrigin(false); + Scroll(nOldX - maWinPos.X(), nOldY - maWinPos.Y(), ScrollFlags::Children); + PaintImmediately(); +} + +/** + * @returns width of the visible area in proportion to the width of the whole + * working area. + */ +double Window::GetVisibleWidth() const +{ + Size aWinSize = PixelToLogic(GetOutputSizePixel()); + if ( aWinSize.Width() > maViewSize.Width() ) + aWinSize.setWidth( maViewSize.Width() ); + return + maViewSize.Width() == 0 ? 0 : (static_cast<double>(aWinSize.Width()) / maViewSize.Width()); +} + +/** + * @returns height of the visible area in proportion to the height of the whole + * working area. + */ +double Window::GetVisibleHeight() const +{ + Size aWinSize = PixelToLogic(GetOutputSizePixel()); + if ( aWinSize.Height() > maViewSize.Height() ) + aWinSize.setHeight( maViewSize.Height() ); + return maViewSize.Height() == 0 + ? 0 : (static_cast<double>(aWinSize.Height()) / maViewSize.Height()); +} + +Point Window::GetVisibleCenter() +{ + Point aPos = ::tools::Rectangle(Point(), GetOutputSizePixel()).Center(); + + // For LOK + bool bMapModeWasEnabled(IsMapModeEnabled()); + EnableMapMode(/*true*/); + aPos = PixelToLogic(aPos); + EnableMapMode(bMapModeWasEnabled); + + return aPos; +} + +/** + * @returns width of a scroll column in proportion to the width of the whole + * working area. + */ +double Window::GetScrlLineWidth() const +{ + return (GetVisibleWidth() * SCROLL_LINE_FACT); +} + +/** + * @returns height of a scroll column in proportion to the height of the whole + * working area. + */ +double Window::GetScrlLineHeight() const +{ + return (GetVisibleHeight() * SCROLL_LINE_FACT); +} + +/** + * @returns width of a scroll page in proportion to the width of the whole + * working area. + */ +double Window::GetScrlPageWidth() const +{ + return (GetVisibleWidth() * SCROLL_PAGE_FACT); +} + +/** + * @returns height of a scroll page in proportion to the height of the whole + * working area. + */ +double Window::GetScrlPageHeight() const +{ + return (GetVisibleHeight() * SCROLL_PAGE_FACT); +} + +/** + * Deactivate window. + */ +void Window::LoseFocus() +{ + mnTicks = 0; + vcl::Window::LoseFocus (); +} + +/** + * Activate window. + */ +void Window::GrabFocus() +{ + mnTicks = 0; + vcl::Window::GrabFocus (); +} + +void Window::DataChanged( const DataChangedEvent& rDCEvt ) +{ + vcl::Window::DataChanged( rDCEvt ); + + /* Omit PRINTER by all documents which are not using a printer. + Omit FONTS and FONTSUBSTITUTION if no text output is available or if the + document does not allow text. */ + + if ( !((rDCEvt.GetType() == DataChangedEventType::PRINTER) || + (rDCEvt.GetType() == DataChangedEventType::DISPLAY) || + (rDCEvt.GetType() == DataChangedEventType::FONTS) || + (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))) ) + return; + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + /* Rearrange or initiate Resize for scroll bars since the size of + the scroll bars my have changed. Within this, inside the resize- + handler, the size of the scroll bars will be asked from the + Settings. */ + Resize(); + + /* Re-set data, which are from system control or from Settings. May + have to re-set more data since the resolution may also has + changed. */ + if( mpViewShell ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + DrawModeFlags nOutputMode; + sal_uInt16 nPreviewSlot; + + if( rStyleSettings.GetHighContrastMode() ) + nOutputMode = sd::OUTPUT_DRAWMODE_CONTRAST; + else + nOutputMode = sd::OUTPUT_DRAWMODE_COLOR; + + if( rStyleSettings.GetHighContrastMode() + && officecfg::Office::Common::Accessibility::IsForPagePreviews::get() ) + nPreviewSlot = SID_PREVIEW_QUALITY_CONTRAST; + else + nPreviewSlot = SID_PREVIEW_QUALITY_COLOR; + + if( dynamic_cast< DrawViewShell *>( mpViewShell ) != nullptr ) + { + GetOutDev()->SetDrawMode( nOutputMode ); + mpViewShell->GetFrameView()->SetDrawMode( nOutputMode ); + Invalidate(); + } + + // Overwrite window color for OutlineView + if( dynamic_cast< OutlineViewShell *>( mpViewShell ) != nullptr ) + { + svtools::ColorConfig aColorConfig; + const Color aDocColor( aColorConfig.GetColorValue( svtools::DOCCOLOR ).nColor ); + SetBackground( Wallpaper( aDocColor ) ); + } + + SfxRequest aReq( nPreviewSlot, SfxCallMode::SLOT, mpViewShell->GetDocSh()->GetDoc()->GetItemPool() ); + mpViewShell->ExecReq( aReq ); + mpViewShell->Invalidate(); + mpViewShell->ArrangeGUIElements(); + + // re-create handles to show new outfit + if(dynamic_cast< DrawViewShell *>( mpViewShell ) != nullptr) + { + mpViewShell->GetView()->AdjustMarkHdl(); + } + } + } + + if ( (rDCEvt.GetType() == DataChangedEventType::DISPLAY) || + ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) ) + { + /* Virtual devices, which also depends on the resolution or the + system control, should be updated. Otherwise, we should update + the virtual devices at least at DataChangedEventType::DISPLAY since some + systems allow to change the resolution and color depth during + runtime. Or the virtual devices have to be updated when the color + palette has changed since a different color matching can be used + when outputting. */ + } + + if ( rDCEvt.GetType() == DataChangedEventType::FONTS ) + { + /* If the document provides font choose boxes, we have to update + them. I don't know how this looks like (also not really me, I + only translated the comment ;). We may can handle it global. We + have to discuss it with PB, but he is ill at the moment. + Before we handle it here, discuss it with PB and me. */ + } + + if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) || + (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ) + { + /* Do reformatting since the fonts of the document may no longer + exist, or exist now, or are replaced with others. */ + if( mpViewShell ) + { + DrawDocShell* pDocSh = mpViewShell->GetDocSh(); + if( pDocSh ) + pDocSh->SetPrinter( pDocSh->GetPrinter( true ) ); + } + } + + if ( rDCEvt.GetType() == DataChangedEventType::PRINTER ) + { + /* I don't know how the handling should look like. Maybe we delete a + printer and look what we have to do. Maybe I have to add + something to the VCL, in case the used printer is deleted. + Otherwise I may recalculate the formatting here if the current + printer is destroyed. */ + if( mpViewShell ) + { + DrawDocShell* pDocSh = mpViewShell->GetDocSh(); + if( pDocSh ) + pDocSh->SetPrinter( pDocSh->GetPrinter( true ) ); + } + } + + // Update everything + Invalidate(); +} + +sal_Int8 Window::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + sal_Int8 nRet = DND_ACTION_NONE; + + if( mpViewShell && !mpViewShell->GetDocSh()->IsReadOnly() ) + { + nRet = mpViewShell->AcceptDrop( rEvt, *this, this, SDRPAGE_NOTFOUND, SDRLAYER_NOTFOUND ); + + if (mbUseDropScroll && dynamic_cast< OutlineViewShell *>( mpViewShell ) == nullptr) + DropScroll( rEvt.maPosPixel ); + } + + return nRet; +} + +sal_Int8 Window::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + sal_Int8 nRet = DND_ACTION_NONE; + + if( mpViewShell ) + { + nRet = mpViewShell->ExecuteDrop( rEvt, *this, this, SDRPAGE_NOTFOUND, SDRLAYER_NOTFOUND ); + } + + return nRet; +} + +void Window::SetUseDropScroll (bool bUseDropScroll) +{ + mbUseDropScroll = bUseDropScroll; +} + +void Window::DropScroll(const Point& rMousePos) +{ + short nDx = 0; + short nDy = 0; + + Size aSize = GetOutputSizePixel(); + + if (aSize.Width() > SCROLL_SENSITIVE * 3) + { + if ( rMousePos.X() < SCROLL_SENSITIVE ) + { + nDx = -1; + } + + if ( rMousePos.X() >= aSize.Width() - SCROLL_SENSITIVE ) + { + nDx = 1; + } + } + + if (aSize.Height() > SCROLL_SENSITIVE * 3) + { + if ( rMousePos.Y() < SCROLL_SENSITIVE ) + { + nDy = -1; + } + + if ( rMousePos.Y() >= aSize.Height() - SCROLL_SENSITIVE ) + { + nDy = 1; + } + } + + if ( (nDx || nDy) && (rMousePos.X()!=0 || rMousePos.Y()!=0 ) ) + { + if (mnTicks > 20) + mpViewShell->ScrollLines(nDx, nDy); + else + mnTicks ++; + } +} + +css::uno::Reference<css::accessibility::XAccessible> + Window::CreateAccessible() +{ + // If current viewshell is PresentationViewShell, just return empty because the correct ShowWin will be created later. + if (dynamic_cast< PresentationViewShell *>( mpViewShell )) + { + return vcl::Window::CreateAccessible (); + } + css::uno::Reference< css::accessibility::XAccessible > xAcc = GetAccessible(false); + if (xAcc) + { + return xAcc; + } + if (mpViewShell != nullptr) + { + xAcc = mpViewShell->CreateAccessibleDocumentView (this); + SetAccessible(xAcc); + return xAcc; + } + else + { + SAL_WARN("sd", "::sd::Window::CreateAccessible: no view shell"); + return vcl::Window::CreateAccessible (); + } +} + +OutlinerView* Window::GetOutlinerView() const +{ + OutlinerView *pOLV = nullptr; + sd::View* pView = mpViewShell->GetView(); + if (mpViewShell->GetShellType() == ViewShell::ST_OUTLINE) + { + if (OutlineView* pOView = dynamic_cast<OutlineView*>(pView)) + pOLV = pOView->GetViewByWindow(this); + } + else if (pView->IsTextEdit()) + { + pOLV = pView->GetTextEditOutlinerView(); + } + return pOLV; +} + +OUString Window::GetSurroundingText() const +{ + OutlinerView *pOLV = GetOutlinerView(); + if (pOLV) + return pOLV->GetEditView().GetSurroundingText(); + return OUString(); +} + +Selection Window::GetSurroundingTextSelection() const +{ + OutlinerView *pOLV = GetOutlinerView(); + if (pOLV) + return pOLV->GetEditView().GetSurroundingTextSelection(); + return Selection( 0, 0 ); +} + +bool Window::DeleteSurroundingText(const Selection& rSelection) +{ + OutlinerView *pOLV = GetOutlinerView(); + if (pOLV) + return pOLV->GetEditView().DeleteSurroundingText(rSelection); + return false; +} + +void Window::LogicInvalidate(const ::tools::Rectangle* pRectangle) +{ + DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>(mpViewShell); + if (!pDrawViewShell || pDrawViewShell->IsInSwitchPage()) + return; + + if (!comphelper::LibreOfficeKit::isActive()) + return; + ::tools::Rectangle aRectangle; + ::tools::Rectangle* pResultRectangle; + if (!pRectangle) + pResultRectangle = nullptr; + else + { + aRectangle = *pRectangle; + if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM) + { + aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip); + } + pResultRectangle = &aRectangle; + } + SfxViewShell& rSfxViewShell = pDrawViewShell->GetViewShellBase(); + SfxLokHelper::notifyInvalidation(&rSfxViewShell, pResultRectangle); +} + +FactoryFunction Window::GetUITestFactory() const +{ + if (get_id() == "impress_win") + return ImpressWindowUIObject::create; + + return WindowUIObject::create; +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/tabcontr.cxx b/sd/source/ui/view/tabcontr.cxx new file mode 100644 index 0000000000..b09a254e9f --- /dev/null +++ b/sd/source/ui/view/tabcontr.cxx @@ -0,0 +1,358 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <TabControl.hxx> + +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/vclevent.hxx> + +#include <app.hrc> + +#include <DrawViewShell.hxx> +#include <helpids.h> +#include <View.hxx> +#include <drawdoc.hxx> +#include <DrawDocShell.hxx> + +namespace sd { + + +TabControl::TabControlTransferable::~TabControlTransferable() +{ +} + +void TabControl::TabControlTransferable::AddSupportedFormats() +{ + AddFormat( SotClipboardFormatId::STARDRAW_TABBAR ); +} + +bool TabControl::TabControlTransferable::GetData( const css::datatransfer::DataFlavor& /*rFlavor*/, const OUString& /*rDestDoc*/ ) +{ + return false; +} + +void TabControl::TabControlTransferable::DragFinished( sal_Int8 /*nDropAction*/ ) +{ + mrParent.DragFinished(); +} + +TabControl::TabControl(DrawViewShell* pViewSh, vcl::Window* pParent) : + TabBar( pParent, WinBits( WB_BORDER | WB_3DLOOK | WB_SCROLL | WB_SIZEABLE | WB_DRAG) ), + DragSourceHelper( this ), + DropTargetHelper( this ), + pDrViewSh(pViewSh), + bInternalMove(false) +{ + EnableEditMode(); + SetSizePixel(Size(0, 0)); + SetMaxPageWidth( 150 ); + SetHelpId( HID_SD_TABBAR_PAGES ); +} + +TabControl::~TabControl() +{ + disposeOnce(); +} + +void TabControl::dispose() +{ + DragSourceHelper::dispose(); + DropTargetHelper::dispose(); + TabBar::dispose(); +} + +void TabControl::Select() +{ + SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher(); + pDispatcher->Execute(SID_SWITCHPAGE, SfxCallMode::ASYNCHRON | + SfxCallMode::RECORD); +} + +void TabControl::MouseButtonDown(const MouseEvent& rMEvt) +{ + if (rMEvt.IsLeft() + && !rMEvt.IsMod1() + && !rMEvt.IsMod2() + && !rMEvt.IsShift()) + { + Point aPos = PixelToLogic( rMEvt.GetPosPixel() ); + sal_uInt16 aPageId = GetPageId(aPos); + + //initialize + if (aPageId == 0) + { + SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher(); + + pDispatcher->Execute(SID_INSERTPAGE_QUICK, + SfxCallMode::SYNCHRON | SfxCallMode::RECORD); + } + } + + // A single left click with pressed control key on a tab page first + // switches to that page before the usual handling (copying with drag + // and drop) takes place. + else if (rMEvt.IsLeft() && rMEvt.IsMod1() && !rMEvt.IsMod2() && !rMEvt.IsShift()) + { + pDrViewSh->SwitchPage (GetPageId (rMEvt.GetPosPixel()) - 1); + } + + // When only the right button is pressed then first process a + // synthesized left button click to make the page the current one + // whose tab has been clicked. When then the actual right button + // click is processed the resulting context menu relates to the + // now current page. + if (rMEvt.IsRight() && ! rMEvt.IsLeft()) + { + MouseEvent aSyntheticEvent ( + rMEvt.GetPosPixel(), + rMEvt.GetClicks(), + rMEvt.GetMode(), + MOUSE_LEFT, + rMEvt.GetModifier()); + TabBar::MouseButtonDown(aSyntheticEvent); + } + + TabBar::MouseButtonDown(rMEvt); +} + +void TabControl::DoubleClick() +{ + if (GetCurPageId() != 0) + { + SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher(); + pDispatcher->Execute( SID_MODIFYPAGE, + SfxCallMode::SYNCHRON | SfxCallMode::RECORD ); + } +} + +void TabControl::StartDrag( sal_Int8, const Point& ) +{ + bInternalMove = true; + + // object is delete by reference mechanism + ( new TabControl::TabControlTransferable( *this ) )->StartDrag( this, DND_ACTION_COPYMOVE ); +} + +void TabControl::DragFinished() +{ + bInternalMove = false; +} + +sal_Int8 TabControl::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + sal_Int8 nRet = DND_ACTION_NONE; + + if( rEvt.mbLeaving ) + EndSwitchPage(); + + if( !pDrViewSh->GetDocSh()->IsReadOnly() ) + { + SdDrawDocument* pDoc = pDrViewSh->GetDoc(); + Point aPos( rEvt.maPosPixel ); + + if( bInternalMove ) + { + if( rEvt.mbLeaving || ( pDrViewSh->GetEditMode() == EditMode::MasterPage ) ) + HideDropPos(); + else + { + ShowDropPos( aPos ); + nRet = rEvt.mnAction; + } + } + else + { + HideDropPos(); + + sal_Int32 nPageId = GetPageId( aPos ) - 1; + + if( ( nPageId >= 0 ) && pDoc->GetPage( static_cast<sal_uInt16>(nPageId) ) ) + { + nRet = pDrViewSh->AcceptDrop( rEvt, *this, nullptr, static_cast<sal_uInt16>(nPageId), SDRLAYER_NOTFOUND ); + SwitchPage( aPos ); + } + } + } + + return nRet; +} + +sal_Int8 TabControl::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + SdDrawDocument* pDoc = pDrViewSh->GetDoc(); + Point aPos( rEvt.maPosPixel ); + sal_Int8 nRet = DND_ACTION_NONE; + + if( bInternalMove ) + { + sal_uInt16 nPageId = ShowDropPos( aPos ) - 1; + + switch (rEvt.mnAction) + { + case DND_ACTION_MOVE: + if( pDrViewSh->IsSwitchPageAllowed() && pDoc->MovePages( nPageId ) ) + { + SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher(); + pDispatcher->Execute(SID_SWITCHPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); + } + break; + + case DND_ACTION_COPY: + { + // Copying the selected page to the place that rEvt points + // takes place in three steps: + // 1. Create a copy of the selected page. This copy will + // lie directly behind the selected page. + // 2. Move the copy to the desired place. + // 3. Select the copy. + if (pDrViewSh->IsSwitchPageAllowed()) + { + // 1. Create a copy. + sal_uInt16 nPageNumOfCopy = pDoc->DuplicatePage (GetCurPageId() - 1); + // 2. Move page. For this first switch to the copy: + // MovePages operates on the currently selected page(s). + pDrViewSh->SwitchPage (nPageNumOfCopy); + // Adapt target page id when necessary, i.e. page copy + // has been inserted in front of the target page. + sal_uInt16 nPageNum = nPageId; + if ((nPageNumOfCopy <= nPageNum) && (nPageNum != sal_uInt16(-1))) + nPageNum += 1; + if (pDoc->MovePages(nPageNum)) + { + // 3. Switch to the copy that has been moved to its + // final destination. Use an asynchron slot call to + // be executed after the still pending ones. + if (nPageNumOfCopy >= nPageNum || (nPageNum == sal_uInt16(-1))) + nPageNum += 1; + SetCurPageId (GetPageId(nPageNum)); + SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher(); + pDispatcher->Execute(SID_SWITCHPAGE, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); + } + } + + break; + } + } + + nRet = rEvt.mnAction; + } + else + { + sal_Int32 nPageId = GetPageId( aPos ) - 1; + + if( ( nPageId >= 0 ) && pDoc->GetPage( static_cast<sal_uInt16>(nPageId) ) ) + { + nRet = pDrViewSh->ExecuteDrop( rEvt, *this, nullptr, static_cast<sal_uInt16>(nPageId), SDRLAYER_NOTFOUND ); + } + } + + HideDropPos(); + EndSwitchPage(); + + return nRet; +} + +void TabControl::Command(const CommandEvent& rCEvt) +{ + if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) + { + SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher(); + pDispatcher->ExecutePopup("pagetab"); + } +} + +bool TabControl::StartRenaming() +{ + bool bOK = false; + + if (pDrViewSh->GetPageKind() == PageKind::Standard) + { + bOK = true; + + ::sd::View* pView = pDrViewSh->GetView(); + + if ( pView->IsTextEdit() ) + pView->SdrEndTextEdit(); + } + + return bOK; +} + +TabBarAllowRenamingReturnCode TabControl::AllowRenaming() +{ + bool bOK = true; + + OUString aNewName( GetEditText() ); + OUString aCompareName( GetPageText( GetEditPageId() ) ); + + if( aCompareName != aNewName ) + { + // rename page + if (pDrViewSh->GetDocSh()->CheckPageName(GetFrameWeld(), aNewName)) + { + SetEditText( aNewName ); + EndRenaming(); + } + else + { + bOK = false; + } + } + return bOK ? TABBAR_RENAMING_YES : TABBAR_RENAMING_NO; +} + +void TabControl::EndRenaming() +{ + if( !IsEditModeCanceled() ) + pDrViewSh->RenameSlide( GetEditPageId(), GetEditText() ); +} + +void TabControl::ActivatePage() +{ + if ( /*IsInSwitching && */ pDrViewSh->IsSwitchPageAllowed() ) + { + SfxDispatcher* pDispatcher = pDrViewSh->GetViewFrame()->GetDispatcher(); + pDispatcher->Execute(SID_SWITCHPAGE, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); + } +} + +bool TabControl::DeactivatePage() +{ + return pDrViewSh->IsSwitchPageAllowed(); +} + +void TabControl::SendActivatePageEvent() +{ + CallEventListeners (VclEventId::TabbarPageActivated, + reinterpret_cast<void*>(GetCurPageId())); +} + +void TabControl::SendDeactivatePageEvent() +{ + CallEventListeners (VclEventId::TabbarPageDeactivated, + reinterpret_cast<void*>(GetCurPageId())); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/unmodpg.cxx b/sd/source/ui/view/unmodpg.cxx new file mode 100644 index 0000000000..4ca02f2942 --- /dev/null +++ b/sd/source/ui/view/unmodpg.cxx @@ -0,0 +1,274 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svx/svdlayer.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/svdviter.hxx> +#include <svx/svdview.hxx> +#include <tools/debug.hxx> + +#include <strings.hrc> +#include <strings.hxx> +#include <glob.hxx> +#include <app.hrc> + +#include <unmodpg.hxx> +#include <sdpage.hxx> +#include <sdresid.hxx> +#include <unokywds.hxx> +#include <drawdoc.hxx> +#include <utility> + +#include <ViewShell.hxx> +#include <ViewShellBase.hxx> +#include <DrawDocShell.hxx> +#include <SlideSorter.hxx> +#include <SlideSorterViewShell.hxx> +#include <view/SlideSorterView.hxx> + +ModifyPageUndoAction::ModifyPageUndoAction( + SdDrawDocument* pTheDoc, + SdPage* pThePage, + const OUString& aTheNewName, + AutoLayout eTheNewAutoLayout, + bool bTheNewBckgrndVisible, + bool bTheNewBckgrndObjsVisible) +: SdUndoAction(pTheDoc) +{ + DBG_ASSERT(pThePage, "Undo without a page???"); + + mpPage = pThePage; + maNewName = aTheNewName; + meNewAutoLayout = eTheNewAutoLayout; + mbNewBckgrndVisible = bTheNewBckgrndVisible; + mbNewBckgrndObjsVisible = bTheNewBckgrndObjsVisible; + + meOldAutoLayout = mpPage->GetAutoLayout(); + + if (!mpPage->IsMasterPage()) + { + maOldName = mpPage->GetName(); + SdrLayerAdmin& rLayerAdmin = mpDoc->GetLayerAdmin(); + SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background); + SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects); + SdrLayerIDSet aVisibleLayers = mpPage->TRG_GetMasterPageVisibleLayers(); + + mbOldBckgrndVisible = aVisibleLayers.IsSet(aBckgrnd); + mbOldBckgrndObjsVisible = aVisibleLayers.IsSet(aBckgrndObj); + } + else + { + mbOldBckgrndVisible = false; + mbOldBckgrndObjsVisible = false; + } + + if (pTheDoc && pTheDoc->GetDocumentType() == DocumentType::Draw) + SetComment( SdResId(STR_UNDO_MODIFY_PAGE_DRAW) ); + else + SetComment( SdResId(STR_UNDO_MODIFY_PAGE) ); +} + +void ModifyPageUndoAction::Undo() +{ + // invalidate Selection, there could be objects deleted in this UNDO + // which are no longer allowed to be selected then. + SdrViewIter::ForAllViews(mpPage, + [] (SdrView* pView) + { + if(pView->AreObjectsMarked()) + pView->UnmarkAll(); + }); + + mpPage->SetAutoLayout( meOldAutoLayout ); + + if (!mpPage->IsMasterPage()) + { + if (mpPage->GetName() != maOldName) + { + mpPage->SetName(maOldName); + + if (mpPage->GetPageKind() == PageKind::Standard) + { + SdPage* pNotesPage = static_cast<SdPage*>(mpDoc->GetPage(mpPage->GetPageNum() + 1)); + pNotesPage->SetName(maOldName); + } + } + + SdrLayerAdmin& rLayerAdmin = mpDoc->GetLayerAdmin(); + SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background); + SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects); + SdrLayerIDSet aVisibleLayers; + aVisibleLayers.Set(aBckgrnd, mbOldBckgrndVisible); + aVisibleLayers.Set(aBckgrndObj, mbOldBckgrndObjsVisible); + mpPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers); + } + + // Redisplay + SfxViewFrame* pCurrent = SfxViewFrame::Current(); + if( pCurrent ) + { + pCurrent->GetDispatcher()->Execute( + SID_SWITCHPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD ); + } +} + +void ModifyPageUndoAction::Redo() +{ + // invalidate Selection, there could be objects deleted in this UNDO + // which are no longer allowed to be selected then. + SdrViewIter::ForAllViews(mpPage, + [] (SdrView* pView) + { + if(pView->AreObjectsMarked()) + pView->UnmarkAll(); + }); + + mpPage->meAutoLayout = meNewAutoLayout; + + if (!mpPage->IsMasterPage()) + { + if (mpPage->GetName() != maNewName) + { + mpPage->SetName(maNewName); + + if (mpPage->GetPageKind() == PageKind::Standard) + { + SdPage* pNotesPage = static_cast<SdPage*>(mpDoc->GetPage(mpPage->GetPageNum() + 1)); + pNotesPage->SetName(maNewName); + } + } + + SdrLayerAdmin& rLayerAdmin = mpDoc->GetLayerAdmin(); + SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background); + SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects); + SdrLayerIDSet aVisibleLayers; + aVisibleLayers.Set(aBckgrnd, mbNewBckgrndVisible); + aVisibleLayers.Set(aBckgrndObj, mbNewBckgrndObjsVisible); + mpPage->TRG_SetMasterPageVisibleLayers(aVisibleLayers); + } + + // Redisplay + SfxViewFrame* pCurrent = SfxViewFrame::Current(); + if( pCurrent ) + { + pCurrent->GetDispatcher()->Execute( + SID_SWITCHPAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD ); + } +} + +ModifyPageUndoAction::~ModifyPageUndoAction() +{ +} + +ChangeSlideExclusionStateUndoAction::ChangeSlideExclusionStateUndoAction( + SdDrawDocument* pDocument, const sd::slidesorter::model::PageDescriptor::State eState, + const bool bOldStateValue) + : SdUndoAction(pDocument) + , meState(eState) + , mbOldStateValue(bOldStateValue) + , maComment(bOldStateValue ? SdResId(STR_UNDO_SHOW_SLIDE) : SdResId(STR_UNDO_HIDE_SLIDE)) +{ +} + +ChangeSlideExclusionStateUndoAction::ChangeSlideExclusionStateUndoAction( + SdDrawDocument* pDocument, const sd::slidesorter::model::SharedPageDescriptor& rpDescriptor, + const sd::slidesorter::model::PageDescriptor::State eState, const bool bOldStateValue) + : ChangeSlideExclusionStateUndoAction(pDocument, eState, bOldStateValue) +{ + mrpDescriptors.push_back(rpDescriptor); +} + +void ChangeSlideExclusionStateUndoAction::AddPageDescriptor( + const sd::slidesorter::model::SharedPageDescriptor& rpDescriptor) +{ + mrpDescriptors.push_back(rpDescriptor); +} + +void ChangeSlideExclusionStateUndoAction::Undo() +{ + sd::DrawDocShell* pDocShell = mpDoc ? mpDoc->GetDocSh() : nullptr; + sd::ViewShell* pViewShell = pDocShell ? pDocShell->GetViewShell() : nullptr; + if (pViewShell) + { + sd::slidesorter::SlideSorterViewShell* pSlideSorterViewShell + = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase()); + if (pSlideSorterViewShell) + { + for (const sd::slidesorter::model::SharedPageDescriptor& rpDescriptor : mrpDescriptors) + pSlideSorterViewShell->GetSlideSorter().GetView().SetState(rpDescriptor, meState, + mbOldStateValue); + } + } +} + +void ChangeSlideExclusionStateUndoAction::Redo() +{ + sd::DrawDocShell* pDocShell = mpDoc ? mpDoc->GetDocSh() : nullptr; + sd::ViewShell* pViewShell = pDocShell ? pDocShell->GetViewShell() : nullptr; + if (pViewShell) + { + sd::slidesorter::SlideSorterViewShell* pSlideSorterViewShell + = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase()); + if (pSlideSorterViewShell) + { + for (const sd::slidesorter::model::SharedPageDescriptor& rpDescriptor : mrpDescriptors) + pSlideSorterViewShell->GetSlideSorter().GetView().SetState(rpDescriptor, meState, + !mbOldStateValue); + } + } +} + +OUString ChangeSlideExclusionStateUndoAction::GetComment() const +{ + return maComment; +} + +RenameLayoutTemplateUndoAction::RenameLayoutTemplateUndoAction( + SdDrawDocument* pDocument, + OUString aOldLayoutName, + OUString aNewLayoutName) + : SdUndoAction(pDocument) + , maOldName(std::move(aOldLayoutName)) + , maNewName(std::move(aNewLayoutName)) + , maComment(SdResId(STR_TITLE_RENAMESLIDE)) +{ + sal_Int32 nPos = maOldName.indexOf(SD_LT_SEPARATOR); + if (nPos != -1) + maOldName = maOldName.copy(0, nPos); +} + +void RenameLayoutTemplateUndoAction::Undo() +{ + OUString aLayoutName(maNewName + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE); + mpDoc->RenameLayoutTemplate( aLayoutName, maOldName ); +} + +void RenameLayoutTemplateUndoAction::Redo() +{ + OUString aLayoutName(maOldName + SD_LT_SEPARATOR + STR_LAYOUT_OUTLINE); + mpDoc->RenameLayoutTemplate( aLayoutName, maNewName ); +} + +OUString RenameLayoutTemplateUndoAction::GetComment() const +{ + return maComment; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/viewoverlaymanager.cxx b/sd/source/ui/view/viewoverlaymanager.cxx new file mode 100644 index 0000000000..bd2e6be970 --- /dev/null +++ b/sd/source/ui/view/viewoverlaymanager.cxx @@ -0,0 +1,545 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> + +#include <vcl/help.hxx> +#include <vcl/lazydelete.hxx> +#include <vcl/ptrstyle.hxx> +#include <vcl/svapp.hxx> + +#include <svx/sdrpagewindow.hxx> +#include <svx/sdrpaintwindow.hxx> +#include <svx/sdr/overlay/overlaybitmapex.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <svx/svxids.hrc> +#include <svx/svdpagv.hxx> + +#include <view/viewoverlaymanager.hxx> + + +#include <DrawDocShell.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <sdresid.hxx> +#include <EventMultiplexer.hxx> +#include <View.hxx> +#include <ViewShellBase.hxx> +#include <ViewShell.hxx> +#include <sdpage.hxx> +#include <smarttag.hxx> + +using namespace ::com::sun::star::uno; + +namespace sd { + +namespace { + +class ImageButtonHdl; + +} + +const sal_uInt16 gButtonSlots[] = { SID_INSERT_TABLE, SID_INSERT_DIAGRAM, SID_INSERT_GRAPHIC, SID_INSERT_AVMEDIA }; +const TranslateId gButtonToolTips[] = { STR_INSERT_TABLE, STR_INSERT_CHART, STR_INSERT_PICTURE, STR_INSERT_MOVIE }; + +constexpr OUString aSmallPlaceHolders[] = +{ + BMP_PLACEHOLDER_TABLE_SMALL, + BMP_PLACEHOLDER_CHART_SMALL, + BMP_PLACEHOLDER_IMAGE_SMALL, + BMP_PLACEHOLDER_MOVIE_SMALL, + BMP_PLACEHOLDER_TABLE_SMALL_HOVER, + BMP_PLACEHOLDER_CHART_SMALL_HOVER, + BMP_PLACEHOLDER_IMAGE_SMALL_HOVER, + BMP_PLACEHOLDER_MOVIE_SMALL_HOVER +}; + +constexpr OUString aBigPlaceHolders[] = +{ + BMP_PLACEHOLDER_TABLE_LARGE, + BMP_PLACEHOLDER_CHART_LARGE, + BMP_PLACEHOLDER_IMAGE_LARGE, + BMP_PLACEHOLDER_MOVIE_LARGE, + BMP_PLACEHOLDER_TABLE_LARGE_HOVER, + BMP_PLACEHOLDER_CHART_LARGE_HOVER, + BMP_PLACEHOLDER_IMAGE_LARGE_HOVER, + BMP_PLACEHOLDER_MOVIE_LARGE_HOVER +}; + +static BitmapEx& getButtonImage( int index, bool large ) +{ + static vcl::DeleteOnDeinit< BitmapEx > gSmallButtonImages[SAL_N_ELEMENTS(aSmallPlaceHolders)] = { vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty }; + static vcl::DeleteOnDeinit< BitmapEx > gLargeButtonImages[SAL_N_ELEMENTS(aBigPlaceHolders)] = { vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty, vcl::DeleteOnDeinitFlag::Empty }; + + assert(SAL_N_ELEMENTS(aSmallPlaceHolders) == SAL_N_ELEMENTS(aBigPlaceHolders)); + + if( !gSmallButtonImages[0].get() ) + { + for (size_t i = 0; i < SAL_N_ELEMENTS(aSmallPlaceHolders); i++ ) + { + gSmallButtonImages[i].set(aSmallPlaceHolders[i]); + gLargeButtonImages[i].set(aBigPlaceHolders[i]); + } + } + + if( large ) + { + return *gLargeButtonImages[index].get(); + } + else + { + return *gSmallButtonImages[index].get(); + } +} + +const sal_uInt32 SMART_TAG_HDL_NUM = SAL_MAX_UINT32; + +namespace { + +class ChangePlaceholderTag : public SmartTag +{ + friend class ImageButtonHdl; +public: + ChangePlaceholderTag( ::sd::View& rView, SdrObject& rPlaceholderObj ); + + /** returns true if the SmartTag handled the event. */ + virtual bool MouseButtonDown( const MouseEvent&, SmartHdl& ) override; + + /** returns true if the SmartTag consumes this event. */ + virtual bool KeyInput( const KeyEvent& rKEvt ) override; + + BitmapEx createOverlayImage( int nHighlight ); + +protected: + virtual void addCustomHandles( SdrHdlList& rHandlerList ) override; + +private: + ::unotools::WeakReference<SdrObject> mxPlaceholderObj; +}; + +class ImageButtonHdl : public SmartHdl +{ +public: + ImageButtonHdl( const SmartTagReference& xTag, /* sal_uInt16 nSID, const Image& rImage, const Image& rImageMO, */ const Point& rPnt ); + virtual ~ImageButtonHdl() override; + virtual void CreateB2dIAObject() override; + virtual bool IsFocusHdl() const override; + virtual PointerStyle GetPointer() const override; + + virtual void onMouseEnter(const MouseEvent& rMEvt) override; + virtual void onHelpRequest() override; + virtual void onMouseLeave() override; + + int getHighlightId() const { return mnHighlightId; } + + void ShowTip(); + static void HideTip(); + +private: + rtl::Reference< ChangePlaceholderTag > mxChangePlaceholderTag; + + int mnHighlightId; + Size maImageSize; +}; + +} + +ImageButtonHdl::ImageButtonHdl( const SmartTagReference& xTag /*, sal_uInt16 nSID, const Image& rImage, const Image& rImageMO*/, const Point& rPnt ) +: SmartHdl( xTag, rPnt, SdrHdlKind::SmartTag ) +, mxChangePlaceholderTag( dynamic_cast< ChangePlaceholderTag* >( xTag.get() ) ) +, mnHighlightId( -1 ) +, maImageSize( 42, 42 ) +{ +} + +ImageButtonHdl::~ImageButtonHdl() +{ + HideTip(); +} + +void ImageButtonHdl::HideTip() +{ + Help::HideBalloonAndQuickHelp(); +} + +void ImageButtonHdl::ShowTip() +{ + if (!m_pHdlList || !m_pHdlList->GetView() || mnHighlightId == -1) + return; + + OutputDevice* pDev = m_pHdlList->GetView()->GetFirstOutputDevice(); + if( pDev == nullptr ) + pDev = Application::GetDefaultDevice(); + + OUString aHelpText(SdResId(gButtonToolTips[mnHighlightId])); + Point aHelpPos(pDev->LogicToPixel(GetPos())); + if (mnHighlightId == 1) + aHelpPos.Move(maImageSize.Width(), 0); + else if (mnHighlightId == 2) + aHelpPos.Move(0, maImageSize.Height()); + else if (mnHighlightId == 3) + aHelpPos.Move(maImageSize.Width(), maImageSize.Height()); + ::tools::Rectangle aLogicPix(aHelpPos, maImageSize); + vcl::Window* pWindow = m_pHdlList->GetView()->GetFirstOutputDevice()->GetOwnerWindow(); + ::tools::Rectangle aScreenRect(pWindow->OutputToScreenPixel(aLogicPix.TopLeft()), + pWindow->OutputToScreenPixel(aLogicPix.BottomRight())); + Help::ShowQuickHelp(pWindow, aScreenRect, aHelpText); +} + +void ImageButtonHdl::onHelpRequest() +{ + ShowTip(); +} + +void ImageButtonHdl::onMouseEnter(const MouseEvent& rMEvt) +{ + if( !(m_pHdlList && m_pHdlList->GetView())) + return; + + int nHighlightId = 0; + OutputDevice* pDev = m_pHdlList->GetView()->GetFirstOutputDevice(); + if( pDev == nullptr ) + pDev = Application::GetDefaultDevice(); + + Point aMDPos( rMEvt.GetPosPixel() ); + aMDPos -= pDev->LogicToPixel( GetPos() ); + + nHighlightId += aMDPos.X() > maImageSize.Width() ? 1 : 0; + nHighlightId += aMDPos.Y() > maImageSize.Height() ? 2 : 0; + + if( mnHighlightId != nHighlightId ) + { + HideTip(); + + mnHighlightId = nHighlightId; + + ShowTip(); + + Touch(); + } +} + +void ImageButtonHdl::onMouseLeave() +{ + mnHighlightId = -1; + HideTip(); + Touch(); +} + +void ImageButtonHdl::CreateB2dIAObject() +{ + // first throw away old one + GetRidOfIAObject(); + + const Point aTagPos( GetPos() ); + basegfx::B2DPoint aPosition( aTagPos.X(), aTagPos.Y() ); + + BitmapEx aBitmapEx( mxChangePlaceholderTag->createOverlayImage( mnHighlightId ) ); // maImageMO.GetBitmapEx() : maImage.GetBitmapEx() ); + maImageSize = aBitmapEx.GetSizePixel(); + maImageSize.setWidth( maImageSize.Width() >> 1 ); + maImageSize.setHeight( maImageSize.Height() >> 1 ); + + if(!m_pHdlList) + return; + + SdrMarkView* pView = m_pHdlList->GetView(); + + if(!pView || pView->areMarkHandlesHidden()) + return; + + SdrPageView* pPageView = pView->GetSdrPageView(); + + if(!pPageView) + return; + + for(sal_uInt32 b = 0; b < pPageView->PageWindowCount(); b++) + { + const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(b); + + SdrPaintWindow& rPaintWindow = rPageWindow.GetPaintWindow(); + const rtl::Reference< sdr::overlay::OverlayManager >& xManager = rPageWindow.GetOverlayManager(); + if(rPaintWindow.OutputToWindow() && xManager.is() ) + { + std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject( + new sdr::overlay::OverlayBitmapEx( aPosition, aBitmapEx, 0, 0 )); + + // OVERLAYMANAGER + insertNewlyCreatedOverlayObjectForSdrHdl( + std::move(pOverlayObject), + rPageWindow.GetObjectContact(), + *xManager); + } + } +} + +bool ImageButtonHdl::IsFocusHdl() const +{ + return false; +} + +PointerStyle ImageButtonHdl::GetPointer() const +{ + return PointerStyle::Arrow; +} + +ChangePlaceholderTag::ChangePlaceholderTag( ::sd::View& rView, SdrObject& rPlaceholderObj ) +: SmartTag( rView ) +, mxPlaceholderObj( &rPlaceholderObj ) +{ +} + +/** returns true if the ChangePlaceholderTag handled the event. */ +bool ChangePlaceholderTag::MouseButtonDown( const MouseEvent& /*rMEvt*/, SmartHdl& rHdl ) +{ + int nHighlightId = static_cast< ImageButtonHdl& >(rHdl).getHighlightId(); + if( nHighlightId >= 0 ) + { + sal_uInt16 nSID = gButtonSlots[nHighlightId]; + + if( auto pPlaceholder = mxPlaceholderObj.get() ) + { + // mark placeholder if it is not currently marked (or if also others are marked) + if( !mrView.IsObjMarked( pPlaceholder.get() ) || (mrView.GetMarkedObjectList().GetMarkCount() != 1) ) + { + SdrPageView* pPV = mrView.GetSdrPageView(); + mrView.UnmarkAllObj(pPV ); + mrView.MarkObj(pPlaceholder.get(), pPV); + } + } + + mrView.GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( nSID, SfxCallMode::ASYNCHRON); + } + return false; +} + +/** returns true if the SmartTag consumes this event. */ +bool ChangePlaceholderTag::KeyInput( const KeyEvent& rKEvt ) +{ + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + switch( nCode ) + { + case KEY_DOWN: + case KEY_UP: + case KEY_LEFT: + case KEY_RIGHT: + case KEY_ESCAPE: + case KEY_TAB: + case KEY_RETURN: + case KEY_SPACE: + default: + return false; + } +} + +BitmapEx ChangePlaceholderTag::createOverlayImage( int nHighlight ) +{ + BitmapEx aRet; + if( auto pPlaceholder = mxPlaceholderObj.get() ) + { + SmartTagReference xThis( this ); + const ::tools::Rectangle& rSnapRect = pPlaceholder->GetSnapRect(); + + OutputDevice* pDev = mrView.GetFirstOutputDevice(); + if( pDev == nullptr ) + pDev = Application::GetDefaultDevice(); + + Size aShapeSizePix = pDev->LogicToPixel(rSnapRect.GetSize()); + ::tools::Long nShapeSizePix = std::min(aShapeSizePix.Width(),aShapeSizePix.Height()); + + bool bLarge = nShapeSizePix > 250; + + Size aSize( getButtonImage( 0, bLarge ).GetSizePixel() ); + + aRet.Scale(Size(aSize.Width() << 1, aSize.Height() << 1)); + + const ::tools::Rectangle aRectSrc( Point( 0, 0 ), aSize ); + + aRet = getButtonImage((nHighlight == 0) ? 4 : 0, bLarge); + aRet.Expand( aSize.Width(), aSize.Height(), true ); + + aRet.CopyPixel( ::tools::Rectangle( Point( aSize.Width(), 0 ), aSize ), aRectSrc, getButtonImage((nHighlight == 1) ? 5 : 1, bLarge) ); + aRet.CopyPixel( ::tools::Rectangle( Point( 0, aSize.Height() ), aSize ), aRectSrc, getButtonImage((nHighlight == 2) ? 6 : 2, bLarge) ); + aRet.CopyPixel( ::tools::Rectangle( Point( aSize.Width(), aSize.Height() ), aSize ), aRectSrc, getButtonImage((nHighlight == 3) ? 7 : 3, bLarge) ); + } + + return aRet; +} + +void ChangePlaceholderTag::addCustomHandles( SdrHdlList& rHandlerList ) +{ + rtl::Reference<SdrObject> pPlaceholder = mxPlaceholderObj.get(); + if( !pPlaceholder ) + return; + + SmartTagReference xThis( this ); + const ::tools::Rectangle& rSnapRect = pPlaceholder->GetSnapRect(); + const Point aPoint; + + OutputDevice* pDev = mrView.GetFirstOutputDevice(); + if( pDev == nullptr ) + pDev = Application::GetDefaultDevice(); + + Size aShapeSizePix = pDev->LogicToPixel(rSnapRect.GetSize()); + ::tools::Long nShapeSizePix = std::min(aShapeSizePix.Width(),aShapeSizePix.Height()); + if( 50 > nShapeSizePix ) + return; + + bool bLarge = nShapeSizePix > 250; + + Size aButtonSize( pDev->PixelToLogic( getButtonImage(0, bLarge ).GetSizePixel()) ); + + const int nColumns = 2; + const int nRows = 2; + + ::tools::Long all_width = nColumns * aButtonSize.Width(); + ::tools::Long all_height = nRows * aButtonSize.Height(); + + Point aPos( rSnapRect.Center() ); + aPos.AdjustX( -(all_width >> 1) ); + aPos.AdjustY( -(all_height >> 1) ); + + std::unique_ptr<ImageButtonHdl> pHdl(new ImageButtonHdl( xThis, aPoint )); + pHdl->SetObjHdlNum( SMART_TAG_HDL_NUM ); + pHdl->SetPageView( mrView.GetSdrPageView() ); + + pHdl->SetPos( aPos ); + + rHandlerList.AddHdl( std::move(pHdl) ); +} + +ViewOverlayManager::ViewOverlayManager( ViewShellBase& rViewShellBase ) +: mrBase( rViewShellBase ) +, mnUpdateTagsEvent( nullptr ) +{ + Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,ViewOverlayManager,EventMultiplexerListener) ); + mrBase.GetEventMultiplexer()->AddEventListener(aLink); + + StartListening( *mrBase.GetDocShell() ); +} + +ViewOverlayManager::~ViewOverlayManager() +{ + Link<tools::EventMultiplexerEvent&,void> aLink( LINK(this,ViewOverlayManager,EventMultiplexerListener) ); + mrBase.GetEventMultiplexer()->RemoveEventListener( aLink ); + + if( mnUpdateTagsEvent ) + { + Application::RemoveUserEvent( mnUpdateTagsEvent ); + mnUpdateTagsEvent = nullptr; + } + + DisposeTags(); +} + +void ViewOverlayManager::Notify(SfxBroadcaster&, const SfxHint& rHint) +{ + if (rHint.GetId() == SfxHintId::DocChanged) + { + UpdateTags(); + } +} + +void ViewOverlayManager::onZoomChanged() +{ + if( !maTagVector.empty() ) + { + UpdateTags(); + } +} + +void ViewOverlayManager::UpdateTags() +{ + if( !mnUpdateTagsEvent ) + mnUpdateTagsEvent = Application::PostUserEvent( LINK( this, ViewOverlayManager, UpdateTagsHdl ) ); +} + +IMPL_LINK_NOARG(ViewOverlayManager, UpdateTagsHdl, void*, void) +{ + mnUpdateTagsEvent = nullptr; + bool bChanges = DisposeTags(); + bChanges |= CreateTags(); + + if( bChanges && mrBase.GetDrawView() ) + static_cast< ::sd::View* >( mrBase.GetDrawView() )->updateHandles(); +} + +bool ViewOverlayManager::CreateTags() +{ + bool bChanges = false; + + std::shared_ptr<ViewShell> aMainShell = mrBase.GetMainViewShell(); + + SdPage* pPage = aMainShell ? aMainShell->getCurrentPage() : nullptr; + + if( pPage && !pPage->IsMasterPage() && (pPage->GetPageKind() == PageKind::Standard) ) + { + const std::list< SdrObject* >& rShapes = pPage->GetPresentationShapeList().getList(); + + for( SdrObject* pShape : rShapes ) + { + if( pShape->IsEmptyPresObj() && (pShape->GetObjIdentifier() == SdrObjKind::OutlineText) && (mrBase.GetDrawView()->GetTextEditObject() != pShape) ) + { + rtl::Reference< SmartTag > xTag( new ChangePlaceholderTag( *mrBase.GetMainViewShell()->GetView(), *pShape ) ); + maTagVector.push_back(xTag); + bChanges = true; + } + } + } + + return bChanges; +} + +bool ViewOverlayManager::DisposeTags() +{ + if( !maTagVector.empty() ) + { + ViewTagVector vec; + vec.swap( maTagVector ); + + for (auto& rxViewTag : vec) + rxViewTag->Dispose(); + return true; + } + + return false; +} + +IMPL_LINK(ViewOverlayManager,EventMultiplexerListener, + tools::EventMultiplexerEvent&, rEvent, void) +{ + switch (rEvent.meEventId) + { + case EventMultiplexerEventId::MainViewAdded: + case EventMultiplexerEventId::ViewAdded: + case EventMultiplexerEventId::BeginTextEdit: + case EventMultiplexerEventId::EndTextEdit: + case EventMultiplexerEventId::CurrentPageChanged: + UpdateTags(); + break; + default: break; + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/viewshe2.cxx b/sd/source/ui/view/viewshe2.cxx new file mode 100644 index 0000000000..b7ae44f2c3 --- /dev/null +++ b/sd/source/ui/view/viewshe2.cxx @@ -0,0 +1,949 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/embed/EmbedVerbs.hpp> +#include <com/sun/star/embed/XEmbeddedObject.hpp> + +#include <ViewShell.hxx> +#include <ViewShellHint.hxx> + +#include <ViewShellImplementation.hxx> +#include <FactoryIds.hxx> + +#include <svx/svxids.hrc> +#include <svx/svdpagv.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/ruler.hxx> +#include <editeng/outliner.hxx> +#include <svtools/ehdl.hxx> +#include <svx/svdoole2.hxx> +#include <svtools/sfxecode.hxx> +#include <unotools/moduleoptions.hxx> +#include <comphelper/classids.hxx> +#include <osl/diagnose.h> + +#include <strings.hrc> +#include <app.hrc> +#include <unokywds.hxx> + +#include <sdundogr.hxx> +#include <FrameView.hxx> +#include <sdresid.hxx> +#include <drawdoc.hxx> +#include <View.hxx> +#include <fupoor.hxx> +#include <Client.hxx> +#include <DrawDocShell.hxx> +#include <sdpage.hxx> +#include <DrawViewShell.hxx> +#include <ViewShellBase.hxx> + +#include <Window.hxx> + +#include <sfx2/viewfrm.hxx> +#include <svtools/soerr.hxx> +#include <svx/charthelper.hxx> +#include <comphelper/lok.hxx> + +using namespace com::sun::star; + +namespace sd { + +/** + * adjust Thumbpos and VisibleSize + */ +void ViewShell::UpdateScrollBars() +{ + if (mpHorizontalScrollBar) + { + ::tools::Long nW = static_cast<::tools::Long>(mpContentWindow->GetVisibleWidth() * 32000); + ::tools::Long nX = static_cast<::tools::Long>(mpContentWindow->GetVisibleX() * 32000); + mpHorizontalScrollBar->SetVisibleSize(nW); + mpHorizontalScrollBar->SetThumbPos(nX); + nW = 32000 - nW; + ::tools::Long nLine = static_cast<::tools::Long>(mpContentWindow->GetScrlLineWidth() * nW); + ::tools::Long nPage = static_cast<::tools::Long>(mpContentWindow->GetScrlPageWidth() * nW); + mpHorizontalScrollBar->SetLineSize(nLine); + mpHorizontalScrollBar->SetPageSize(nPage); + } + + if (mpVerticalScrollBar) + { + ::tools::Long nH = static_cast<::tools::Long>(mpContentWindow->GetVisibleHeight() * 32000); + ::tools::Long nY = static_cast<::tools::Long>(mpContentWindow->GetVisibleY() * 32000); + + if(IsPageFlipMode()) // ie in zoom mode where no panning + { + SdPage* pPage = static_cast<DrawViewShell*>(this)->GetActualPage(); + sal_uInt16 nCurPage = (pPage->GetPageNum() - 1) / 2; + sal_uInt16 nTotalPages = GetDoc()->GetSdPageCount(pPage->GetPageKind()); + mpVerticalScrollBar->SetRange(Range(0,256*nTotalPages)); + mpVerticalScrollBar->SetVisibleSize(256); + mpVerticalScrollBar->SetThumbPos(256*nCurPage); + mpVerticalScrollBar->SetLineSize(256); + mpVerticalScrollBar->SetPageSize(256); + } + else + { + mpVerticalScrollBar->SetRange(Range(0,32000)); + mpVerticalScrollBar->SetVisibleSize(nH); + mpVerticalScrollBar->SetThumbPos(nY); + nH = 32000 - nH; + ::tools::Long nLine = static_cast<::tools::Long>(mpContentWindow->GetScrlLineHeight() * nH); + ::tools::Long nPage = static_cast<::tools::Long>(mpContentWindow->GetScrlPageHeight() * nH); + mpVerticalScrollBar->SetLineSize(nLine); + mpVerticalScrollBar->SetPageSize(nPage); + } + } + + if (mbHasRulers) + { + UpdateHRuler(); + UpdateVRuler(); + } + +} +/** + * Handling for horizontal Scrollbars + */ +IMPL_LINK_NOARG(ViewShell, HScrollHdl, weld::Scrollbar&, void) +{ + VirtHScrollHdl(mpHorizontalScrollBar); +} + +/** + * virtual scroll handler for horizontal Scrollbars + */ +void ViewShell::VirtHScrollHdl(ScrollAdaptor* pHScroll) +{ + double fX = static_cast<double>(pHScroll->GetThumbPos()) / pHScroll->GetRange().Len(); + + // scroll all windows of the column + ::sd::View* pView = GetView(); + OutlinerView* pOLV = nullptr; + + if (pView) + pOLV = pView->GetTextEditOutlinerView(); + + if (pOLV) + pOLV->HideCursor(); + + mpContentWindow->SetVisibleXY(fX, -1); + + ::tools::Rectangle aVisArea = GetDocSh()->GetVisArea(ASPECT_CONTENT); + Point aVisAreaPos = GetActiveWindow()->PixelToLogic( Point(0,0) ); + aVisArea.SetPos(aVisAreaPos); + GetDocSh()->SetVisArea(aVisArea); + + Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel(); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); + VisAreaChanged(aVisAreaWin); + + if (pView) + { + pView->VisAreaChanged(GetActiveWindow()->GetOutDev()); + } + + if (pOLV) + pOLV->ShowCursor(); + + if (mbHasRulers) + UpdateHRuler(); +} + +/** + * handling for vertical Scrollbars + */ +IMPL_LINK_NOARG(ViewShell, VScrollHdl, weld::Scrollbar&, void) +{ + VirtVScrollHdl(mpVerticalScrollBar); +} + +/** + * handling for vertical Scrollbars + */ +void ViewShell::VirtVScrollHdl(ScrollAdaptor* pVScroll) +{ + if(IsPageFlipMode()) + { + SdPage* pPage = static_cast<DrawViewShell*>(this)->GetActualPage(); + sal_uInt16 nCurPage = (pPage->GetPageNum() - 1) >> 1; + sal_uInt16 nNewPage = static_cast<sal_uInt16>(pVScroll->GetThumbPos())/256; + if( nCurPage != nNewPage ) + static_cast<DrawViewShell*>(this)->SwitchPage(nNewPage); + } + else //panning mode + { + double fY = static_cast<double>(pVScroll->GetThumbPos()) / pVScroll->GetRange().Len(); + + ::sd::View* pView = GetView(); + OutlinerView* pOLV = nullptr; + + if (pView) + pOLV = pView->GetTextEditOutlinerView(); + + if (pOLV) + pOLV->HideCursor(); + + mpContentWindow->SetVisibleXY(-1, fY); + + ::tools::Rectangle aVisArea = GetDocSh()->GetVisArea(ASPECT_CONTENT); + Point aVisAreaPos = GetActiveWindow()->PixelToLogic( Point(0,0) ); + aVisArea.SetPos(aVisAreaPos); + GetDocSh()->SetVisArea(aVisArea); + + Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel(); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); + VisAreaChanged(aVisAreaWin); + + if (pView) + { + pView->VisAreaChanged(GetActiveWindow()->GetOutDev()); + } + + if (pOLV) + pOLV->ShowCursor(); + + if (mbHasRulers) + UpdateVRuler(); + + } +} + +VclPtr<SvxRuler> ViewShell::CreateHRuler(::sd::Window* ) +{ + return nullptr; +} + +VclPtr<SvxRuler> ViewShell::CreateVRuler(::sd::Window* ) +{ + return nullptr; +} + +void ViewShell::UpdateHRuler() +{ +} + +void ViewShell::UpdateVRuler() +{ +} + +/** + * Scroll a specific number of lines. Is used in the automatic scrolling + * (character/drag). + */ +void ViewShell::ScrollLines(::tools::Long nLinesX, ::tools::Long nLinesY) +{ + if ( nLinesX ) + { + nLinesX *= mpHorizontalScrollBar->GetLineSize(); + } + if ( nLinesY ) + { + nLinesY *= mpVerticalScrollBar->GetLineSize(); + } + + Scroll(nLinesX, nLinesY); +} + +void ViewShell::Scroll(::tools::Long nScrollX, ::tools::Long nScrollY) +{ + if (nScrollX) + { + ::tools::Long nNewThumb = mpHorizontalScrollBar->GetThumbPos() + nScrollX; + mpHorizontalScrollBar->SetThumbPos(nNewThumb); + } + if (nScrollY) + { + ::tools::Long nNewThumb = mpVerticalScrollBar->GetThumbPos() + nScrollY; + mpVerticalScrollBar->SetThumbPos(nNewThumb); + } + double fX = static_cast<double>(mpHorizontalScrollBar->GetThumbPos()) / + mpHorizontalScrollBar->GetRange().Len(); + double fY = static_cast<double>(mpVerticalScrollBar->GetThumbPos()) / + mpVerticalScrollBar->GetRange().Len(); + + GetActiveWindow()->SetVisibleXY(fX, fY); + + ::tools::Rectangle aVisArea = GetDocSh()->GetVisArea(ASPECT_CONTENT); + Point aVisAreaPos = GetActiveWindow()->PixelToLogic( Point(0,0) ); + aVisArea.SetPos(aVisAreaPos); + GetDocSh()->SetVisArea(aVisArea); + + Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel(); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); + VisAreaChanged(aVisAreaWin); + + ::sd::View* pView = GetView(); + if (pView) + { + pView->VisAreaChanged(GetActiveWindow()->GetOutDev()); + } + + if (mbHasRulers) + { + UpdateHRuler(); + UpdateVRuler(); + } +} + +/** + * Set zoom factor for all split windows. + */ +void ViewShell::SetZoom(::tools::Long nZoom) +{ + Fraction aUIScale(nZoom, 100); + aUIScale *= GetDoc()->GetUIScale(); + + if (mpHorizontalRuler) + mpHorizontalRuler->SetZoom(aUIScale); + + if (mpVerticalRuler) + mpVerticalRuler->SetZoom(aUIScale); + + if (mpContentWindow) + { + mpContentWindow->SetZoomIntegral(nZoom); + + // #i74769# Here is a 2nd way (besides Window::Scroll) to set the visible prt + // of the window. It needs - like Scroll(ScrollFlags::Children) does - also to move + // the child windows. I am trying InvalidateFlags::Children here which makes things better, + // but does not solve the problem completely. Need to ask PL. + mpContentWindow->Invalidate(InvalidateFlags::Children); + } + + Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel(); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); + VisAreaChanged(aVisAreaWin); + + ::sd::View* pView = GetView(); + if (pView) + { + pView->VisAreaChanged(GetActiveWindow()->GetOutDev()); + } + + UpdateScrollBars(); +} + +::tools::Long ViewShell::GetZoom() const +{ + if (mpContentWindow) + { + return mpContentWindow->GetZoom(); + } + + return 0; +} + +/** + * Set zoom rectangle for active window. Sets all split windows to the same zoom + * factor. + */ +void ViewShell::SetZoomRect(const ::tools::Rectangle& rZoomRect) +{ + ::tools::Long nZoom = GetActiveWindow()->SetZoomRect(rZoomRect); + Fraction aUIScale(nZoom, 100); + aUIScale *= GetDoc()->GetUIScale(); + + Point aPos = GetActiveWindow()->GetWinViewPos(); + + if (mpHorizontalRuler) + mpHorizontalRuler->SetZoom(aUIScale); + + if (mpVerticalRuler) + mpVerticalRuler->SetZoom(aUIScale); + + if (mpContentWindow) + { + Point aNewPos = mpContentWindow->GetWinViewPos(); + aNewPos.setX( aPos.X() ); + aNewPos.setY( aPos.Y() ); + mpContentWindow->SetZoomIntegral(nZoom); + mpContentWindow->SetWinViewPos(aNewPos); + mpContentWindow->UpdateMapOrigin(); + + // When tiled rendering, UpdateMapOrigin() doesn't touch the map mode. + if (!comphelper::LibreOfficeKit::isActive()) + // #i74769# see above + mpContentWindow->Invalidate(InvalidateFlags::Children); + } + + Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel(); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); + VisAreaChanged(aVisAreaWin); + + ::sd::View* pView = GetView(); + if (pView) + { + pView->VisAreaChanged(GetActiveWindow()->GetOutDev()); + } + + UpdateScrollBars(); +} + +/** + * Initialize imaging parameters for all split windows. + */ +void ViewShell::InitWindows(const Point& rViewOrigin, const Size& rViewSize, + const Point& rWinPos, bool bUpdate) +{ + if (mpContentWindow) + { + mpContentWindow->SetViewOrigin(rViewOrigin); + mpContentWindow->SetViewSize(rViewSize); + mpContentWindow->SetWinViewPos(rWinPos); + + if ( bUpdate ) + { + mpContentWindow->UpdateMapOrigin(); + mpContentWindow->Invalidate(); + } + } + + Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel(); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); + VisAreaChanged(aVisAreaWin); + + ::sd::View* pView = GetView(); + if (pView) + { + pView->VisAreaChanged(GetActiveWindow()->GetOutDev()); + } +} + +/** + * Invalidate all split windows below the ?provided rectangle. + */ +void ViewShell::InvalidateWindows() +{ + if (mpContentWindow) + mpContentWindow->Invalidate(); +} + +/** + * Draw a selection rectangle with the ?provided pen on all split windows. + */ +void ViewShell::DrawMarkRect(const ::tools::Rectangle& rRect) const +{ + if (mpContentWindow) + { + mpContentWindow->InvertTracking(rRect, ShowTrackFlags::Object | ShowTrackFlags::TrackWindow); + } +} + +void ViewShell::SetPageSizeAndBorder(PageKind ePageKind, const Size& rNewSize, + ::tools::Long nLeft, ::tools::Long nRight, + ::tools::Long nUpper, ::tools::Long nLower, bool bScaleAll, + Orientation eOrientation, sal_uInt16 nPaperBin, + bool bBackgroundFullSize) +{ + const sal_uInt16 nMasterPageCnt(GetDoc()->GetMasterSdPageCount(ePageKind)); + const sal_uInt16 nPageCnt(GetDoc()->GetSdPageCount(ePageKind)); + + if(0 == nPageCnt && 0 == nMasterPageCnt) + { + return; + } + + std::unique_ptr<SdUndoGroup> pUndoGroup; + SfxViewShell* pViewShell(GetViewShell()); + if (pViewShell) + { + pUndoGroup.reset(new SdUndoGroup(GetDoc())); + pUndoGroup->SetComment(SdResId(STR_UNDO_CHANGE_PAGEFORMAT)); + } + Broadcast (ViewShellHint(ViewShellHint::HINT_PAGE_RESIZE_START)); + + // use Model-based method at SdDrawDocument + GetDoc()->AdaptPageSizeForAllPages( + rNewSize, + ePageKind, + pUndoGroup.get(), + nLeft, + nRight, + nUpper, + nLower, + bScaleAll, + eOrientation, + nPaperBin, + bBackgroundFullSize); + + // adjust handout page to new format of the standard page + if(0 != nPageCnt && ((ePageKind == PageKind::Standard) || (ePageKind == PageKind::Handout))) + { + GetDoc()->GetSdPage(0, PageKind::Handout)->CreateTitleAndLayout(true); + } + + // handed over undo group to undo manager + if (pViewShell) + { + pViewShell->GetViewFrame().GetObjectShell()->GetUndoManager()->AddUndoAction(std::move(pUndoGroup)); + } + + // calculate View-Sizes + SdPage* pPage(0 != nPageCnt + ? GetDoc()->GetSdPage(0, ePageKind) + : GetDoc()->GetMasterSdPage(0, ePageKind)); + const ::tools::Long nWidth(pPage->GetSize().Width()); + const ::tools::Long nHeight(pPage->GetSize().Height()); + const Point aPageOrg(nWidth, nHeight / 2); + const Size aViewSize(nWidth * 3, nHeight * 2); + Point aVisAreaPos; + ::sd::View* pView(GetView()); + const Point aNewOrigin(pPage->GetLeftBorder(), pPage->GetUpperBorder()); + + InitWindows(aPageOrg, aViewSize, Point(-1, -1), true); + + if ( GetDocSh()->GetCreateMode() == SfxObjectCreateMode::EMBEDDED ) + { + aVisAreaPos = GetDocSh()->GetVisArea(ASPECT_CONTENT).TopLeft(); + } + + if (pView) + { + pView->SetWorkArea(::tools::Rectangle(Point() - aVisAreaPos - aPageOrg, aViewSize)); + } + + UpdateScrollBars(); + + if (pView) + { + pView->GetSdrPageView()->SetPageOrigin(aNewOrigin); + } + + if(nullptr != pViewShell) + { + pViewShell->GetViewFrame().GetBindings().Invalidate(SID_RULER_NULL_OFFSET); + // zoom onto (new) page size + pViewShell->GetViewFrame().GetDispatcher()->Execute(SID_SIZE_PAGE, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); + } + + Broadcast(ViewShellHint(ViewShellHint::HINT_PAGE_RESIZE_END)); +} + +/** + * Set zoom factor for InPlace + */ +void ViewShell::SetZoomFactor(const Fraction& rZoomX, const Fraction&) +{ + ::tools::Long nZoom = static_cast<::tools::Long>(static_cast<double>(rZoomX) * 100); + SetZoom(nZoom); +} + +void ViewShell::SetActiveWindow (::sd::Window* pWin) +{ + SfxViewShell* pViewShell = GetViewShell(); + OSL_ASSERT (pViewShell!=nullptr); + + if (pViewShell->GetWindow() != pWin) + { + // #i31551# was wrong, it may have been a problem with the repaint at that time. + // For transparent form controls, it is necessary to have that flag set, all apps + // do set it. Enabling again. + if (pWin) + { + pWin->EnableChildTransparentMode(); + } + } + + if (mpActiveWindow.get() != pWin) + mpActiveWindow = pWin; + + // The rest of this function is not guarded anymore against calling this + // method with an already active window because the functions may still + // point to the old window when the new one has already been assigned to + // pWindow elsewhere. + ::sd::View* pView = GetView(); + if (pView) + { + pView->SetActualWin(pWin->GetOutDev()); + } + if(HasCurrentFunction()) + { + GetCurrentFunction()->SetWindow(pWin); + } +} + +bool ViewShell::RequestHelp(const HelpEvent& rHEvt) +{ + bool bReturn = false; + + if (bool(rHEvt.GetMode())) + { + if(HasCurrentFunction()) + { + bReturn = GetCurrentFunction()->RequestHelp(rHEvt); + } + } + + return bReturn; +} + +void ViewShell::SetFrameView (FrameView* pNewFrameView) +{ + mpFrameView = pNewFrameView; + ReadFrameViewData (mpFrameView); +} + +/************************************************************************* +|* +|* Read FrameViews data and set actual views data +|* +\************************************************************************/ + +void ViewShell::ReadFrameViewData(FrameView*) +{ +} + +/************************************************************************* +|* +|* Write actual views data to FrameView +|* +\************************************************************************/ + +void ViewShell::WriteFrameViewData() +{ +} + +bool ViewShell::ActivateObject(SdrOle2Obj* pObj, sal_Int32 nVerb) +{ + ErrCode aErrCode = ERRCODE_NONE; + + SfxErrorContext aEC(ERRCTX_SO_DOVERB, GetFrameWeld(), RID_SO_ERRCTX); + bool bAbort = false; + GetDocSh()->SetWaitCursor( true ); + SfxViewShell* pViewShell = GetViewShell(); + OSL_ASSERT (pViewShell!=nullptr); + bool bChangeDefaultsForChart = false; + + uno::Reference < embed::XEmbeddedObject > xObj = pObj->GetObjRef(); + if ( !xObj.is() ) + { + // provide OLE object to empty OLE object + OUString aName = pObj->GetProgName(); + OUString aObjName; + SvGlobalName aClass; + + if( aName == "StarChart" || aName == "StarOrg" ) + { + if( SvtModuleOptions().IsChart() ) + { + aClass = SvGlobalName( SO3_SCH_CLASSID ); + bChangeDefaultsForChart = true; + } + } + else if( aName == "StarCalc" ) + { + if( SvtModuleOptions().IsCalc() ) + aClass = SvGlobalName( SO3_SC_CLASSID ); + } + else if( aName == "StarMath" ) + { + if( SvtModuleOptions().IsMath() ) + aClass = SvGlobalName( SO3_SM_CLASSID ); + } + + if ( aClass != SvGlobalName() ) + xObj = GetDocSh()->GetEmbeddedObjectContainer().CreateEmbeddedObject( aClass.GetByteSequence(), aObjName ); + + if( !xObj.is() ) + { + aName.clear(); + + // call dialog "insert OLE object" + GetDocSh()->SetWaitCursor( false ); + pViewShell->GetViewFrame().GetDispatcher()->Execute( + SID_INSERT_OBJECT, + SfxCallMode::SYNCHRON | SfxCallMode::RECORD); + xObj = pObj->GetObjRef(); + GetDocSh()->SetWaitCursor( true ); + + if (!xObj.is()) + { + bAbort = true; + } + } + + if ( xObj.is() ) + { + // OLE object is no longer empty + pObj->SetEmptyPresObj(false); + pObj->SetOutlinerParaObject(std::nullopt); + pObj->ClearGraphic(); + + // the empty OLE object gets a new IPObj + if (!aName.isEmpty()) + { + pObj->SetObjRef(xObj); + pObj->SetName(aObjName); + pObj->SetPersistName(aObjName); + } + else + { + // insertion was done by the dialog + pObj->SetObjRef(xObj); + } + + ::tools::Rectangle aRect = pObj->GetLogicRect(); + + if ( pObj->GetAspect() != embed::Aspects::MSOLE_ICON ) + { + awt::Size aSz; + aSz.Width = aRect.GetWidth(); + aSz.Height = aRect.GetHeight(); + xObj->setVisualAreaSize( pObj->GetAspect(), aSz ); + } + + GetViewShellBase().SetVerbs( xObj->getSupportedVerbs() ); + + nVerb = embed::EmbedVerbs::MS_OLEVERB_SHOW; + } + else + { + aErrCode = ERRCODE_SFX_OLEGENERAL; + } + } + + if( aErrCode == ERRCODE_NONE ) + { + ::sd::View* pView = GetView(); + + if (pView->IsTextEdit()) + { + pView->SdrEndTextEdit(); + } + + SfxInPlaceClient* pSdClient = + pViewShell->FindIPClient(pObj->GetObjRef(), GetActiveWindow()); + + if ( !pSdClient ) + { + pSdClient = new Client(pObj, this, GetActiveWindow()); + } + + ::tools::Rectangle aRect = pObj->GetLogicRect(); + + { + // #i118485# center on BoundRect for activation, + // OLE may be sheared/rotated now + const ::tools::Rectangle& rBoundRect = pObj->GetCurrentBoundRect(); + const Point aDelta(rBoundRect.Center() - aRect.Center()); + aRect.Move(aDelta.X(), aDelta.Y()); + } + + Size aDrawSize = aRect.GetSize(); + + MapMode aMapMode( GetDoc()->GetScaleUnit() ); + Size aObjAreaSize = pObj->GetOrigObjSize( &aMapMode ); + if( pObj->IsChart() ) //charts never should be stretched see #i84323# for example + aObjAreaSize = aDrawSize; + + Fraction aScaleWidth (aDrawSize.Width(), aObjAreaSize.Width() ); + Fraction aScaleHeight(aDrawSize.Height(), aObjAreaSize.Height() ); + aScaleWidth.ReduceInaccurate(10); // compatible to the SdrOle2Obj + aScaleHeight.ReduceInaccurate(10); + pSdClient->SetSizeScale(aScaleWidth, aScaleHeight); + + // visible section is only changed in-place! + aRect.SetSize(aObjAreaSize); + // the object area size must be set after scaling, since it triggers the resizing + pSdClient->SetObjArea(aRect); + + if( bChangeDefaultsForChart && xObj.is()) + { + ChartHelper::AdaptDefaultsForChart( xObj ); + } + + pSdClient->DoVerb(nVerb); // if necessary, ErrCode is outputted by Sfx + pViewShell->GetViewFrame().GetBindings().Invalidate( + SID_NAVIGATOR_STATE, true); + } + + GetDocSh()->SetWaitCursor( false ); + + if (aErrCode != ERRCODE_NONE && !bAbort) + { + ErrorHandler::HandleError(ErrCodeMsg(aErrCode)); + } + + return aErrCode == ERRCODE_NONE; +} + +/** + * @returns enclosing rectangle of all (split-) windows. + */ +const ::tools::Rectangle& ViewShell::GetAllWindowRect() +{ + maAllWindowRectangle.SetPos( + mpContentWindow->OutputToScreenPixel(Point(0,0))); + return maAllWindowRectangle; +} + +void ViewShell::ReadUserData() +{ + // zoom onto VisArea from FrameView + GetViewShell()->GetViewFrame().GetDispatcher()->Execute(SID_SIZE_VISAREA, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); +} + +void ViewShell::WriteUserData() +{ + // writing of our data is always done in WriteFrameViewData() + WriteFrameViewData(); +} + +/** + * Switch ruler on/off + */ +void ViewShell::SetRuler(bool bRuler) +{ + mbHasRulers = ( bRuler && !GetDocSh()->IsPreview() ); // no rulers on preview mode + + if (mpHorizontalRuler) + { + if (mbHasRulers) + { + mpHorizontalRuler->Show(); + } + else + { + mpHorizontalRuler->Hide(); + } + } + + if (mpVerticalRuler) + { + if (mbHasRulers) + { + mpVerticalRuler->Show(); + } + else + { + mpVerticalRuler->Hide(); + } + } + + OSL_ASSERT(GetViewShell()!=nullptr); + if (IsMainViewShell()) + GetViewShell()->InvalidateBorder(); +} + +void ViewShell::SetScrollBarsVisible(bool bVisible) +{ + if (mpVerticalScrollBar) + mpVerticalScrollBar->Show( bVisible ); + + if (mpHorizontalScrollBar) + mpHorizontalScrollBar->Show( bVisible ); +} + +sal_Int8 ViewShell::AcceptDrop ( + const AcceptDropEvent& rEvt, + DropTargetHelper& rTargetHelper, + ::sd::Window* /*pTargetWindow*/, + sal_uInt16 /*nPage*/, + SdrLayerID nLayer) +{ + ::sd::View* pView = GetView(); + return( pView ? pView->AcceptDrop( rEvt, rTargetHelper, nLayer ) : DND_ACTION_NONE ); +} + +sal_Int8 ViewShell::ExecuteDrop ( + const ExecuteDropEvent& rEvt, + DropTargetHelper& /*rTargetHelper*/, + ::sd::Window* pTargetWindow, + sal_uInt16 nPage, + SdrLayerID nLayer) +{ + ::sd::View* pView = GetView(); + return pView ? pView->ExecuteDrop( rEvt, pTargetWindow, nPage, nLayer ) : DND_ACTION_NONE; +} + +void ViewShell::WriteUserDataSequence ( css::uno::Sequence < css::beans::PropertyValue >& rSequence ) +{ + const sal_Int32 nIndex = rSequence.getLength(); + rSequence.realloc( nIndex + 1 ); + auto pSequence = rSequence.getArray(); + + OSL_ASSERT (GetViewShell()!=nullptr); + // Get the view id from the view shell in the center pane. This will + // usually be the called view shell, but to be on the safe side we call + // the main view shell explicitly. + SfxInterfaceId nViewID (IMPRESS_FACTORY_ID); + if (GetViewShellBase().GetMainViewShell() != nullptr) + nViewID = GetViewShellBase().GetMainViewShell()->mpImpl->GetViewId(); + pSequence[nIndex].Name = sUNO_View_ViewId; + pSequence[nIndex].Value <<= "view" + OUString::number( static_cast<sal_uInt16>(nViewID)); + + mpFrameView->WriteUserDataSequence( rSequence ); +} + +void ViewShell::ReadUserDataSequence ( const css::uno::Sequence < css::beans::PropertyValue >& rSequence ) +{ + mpFrameView->ReadUserDataSequence( rSequence ); +} + +void ViewShell::VisAreaChanged(const ::tools::Rectangle& /*rRect*/) +{ + OSL_ASSERT (GetViewShell()!=nullptr); + GetViewShell()->VisAreaChanged(); +} + +void ViewShell::SetWinViewPos(const Point& rWinPos) +{ + if (mpContentWindow) + { + mpContentWindow->SetWinViewPos(rWinPos); + + mpContentWindow->UpdateMapOrigin(); + mpContentWindow->Invalidate(); + } + + if (mbHasRulers) + { + UpdateHRuler(); + UpdateVRuler(); + } + + UpdateScrollBars(); + + Size aVisSizePixel = GetActiveWindow()->GetOutputSizePixel(); + ::tools::Rectangle aVisAreaWin = GetActiveWindow()->PixelToLogic( ::tools::Rectangle( Point(0,0), aVisSizePixel) ); + VisAreaChanged(aVisAreaWin); + + ::sd::View* pView = GetView(); + if (pView) + { + pView->VisAreaChanged(GetActiveWindow()->GetOutDev()); + } +} + +Point const & ViewShell::GetWinViewPos() const +{ + return mpContentWindow->GetWinViewPos(); +} + +Point const & ViewShell::GetViewOrigin() const +{ + return mpContentWindow->GetViewOrigin(); +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/viewshe3.cxx b/sd/source/ui/view/viewshe3.cxx new file mode 100644 index 0000000000..cb76eaf998 --- /dev/null +++ b/sd/source/ui/view/viewshe3.cxx @@ -0,0 +1,386 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_features.h> + +#include <ViewShell.hxx> +#include <ViewShellBase.hxx> + +#include <sfx2/viewfrm.hxx> +#include <svtools/strings.hrc> +#include <svtools/svtresid.hxx> + +#include <app.hrc> +#include <strings.hrc> + +#include <sal/log.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/bindings.hxx> +#include <svx/svdundo.hxx> +#include <svl/intitem.hxx> +#include <svl/style.hxx> +#include <svl/stritem.hxx> +#include <stlsheet.hxx> +#include <DrawViewShell.hxx> + +#include <drawdoc.hxx> +#include <sdpage.hxx> +#include <DrawDocShell.hxx> +#include <sdresid.hxx> +#include <unokywds.hxx> + +#include <svx/svxids.hrc> +#include <sfx2/request.hxx> +#include <basic/sbstar.hxx> +#include <basic/sberrors.hxx> +#include <xmloff/autolayout.hxx> + +using namespace ::com::sun::star; + +namespace sd { + +/** + * set state (enabled/disabled) of Menu SfxSlots + */ +void ViewShell::GetMenuState( SfxItemSet &rSet ) +{ + if( SfxItemState::DEFAULT == rSet.GetItemState( SID_STYLE_FAMILY ) ) + { + SfxStyleFamily const nFamily = GetDocSh()->GetStyleFamily(); + + SdrView* pDrView = GetDrawView(); + + if( pDrView->AreObjectsMarked() ) + { + SfxStyleSheet* pStyleSheet = pDrView->GetStyleSheet(); + if( pStyleSheet ) + { + if (pStyleSheet->GetFamily() == SfxStyleFamily::Page) + pStyleSheet = static_cast<SdStyleSheet*>(pStyleSheet)->GetPseudoStyleSheet(); + + if( pStyleSheet ) + { + GetDocSh()->SetStyleFamily(pStyleSheet->GetFamily()); + } + } + } + + rSet.Put(SfxUInt16Item(SID_STYLE_FAMILY, static_cast<sal_uInt16>(nFamily))); + } + + if(SfxItemState::DEFAULT == rSet.GetItemState(SID_GETUNDOSTRINGS)) + { + ImpGetUndoStrings(rSet); + } + + if(SfxItemState::DEFAULT == rSet.GetItemState(SID_GETREDOSTRINGS)) + { + ImpGetRedoStrings(rSet); + } + + if(SfxItemState::DEFAULT == rSet.GetItemState(SID_UNDO)) + { + SfxUndoManager* pUndoManager = ImpGetUndoManager(); + if(pUndoManager) + { + if(pUndoManager->GetUndoActionCount() != 0) + { + // If another view created the first undo action, prevent redoing it from this view. + const SfxUndoAction* pAction = pUndoManager->GetUndoAction(); + if (pAction->GetViewShellId() != GetViewShellBase().GetViewShellId()) + { + rSet.Put(SfxUInt32Item(SID_UNDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE))); + } + else + { + // Set the necessary string like in + // sfx2/source/view/viewfrm.cxx ver 1.23 ln 1072 ff. + OUString aTmp = SvtResId(STR_UNDO) + + pUndoManager->GetUndoActionComment(); + rSet.Put(SfxStringItem(SID_UNDO, aTmp)); + } + } + else + { + rSet.DisableItem(SID_UNDO); + } + } + } + + if(SfxItemState::DEFAULT != rSet.GetItemState(SID_REDO)) + return; + + SfxUndoManager* pUndoManager = ImpGetUndoManager(); + if(!pUndoManager) + return; + + if(pUndoManager->GetRedoActionCount() != 0) + { + // If another view created the first undo action, prevent redoing it from this view. + const SfxUndoAction* pAction = pUndoManager->GetRedoAction(); + if (pAction->GetViewShellId() != GetViewShellBase().GetViewShellId()) + { + rSet.Put(SfxUInt32Item(SID_REDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE))); + } + else + { + // Set the necessary string like in + // sfx2/source/view/viewfrm.cxx ver 1.23 ln 1081 ff. + OUString aTmp = SvtResId(STR_REDO) + pUndoManager->GetRedoActionComment(); + rSet.Put(SfxStringItem(SID_REDO, aTmp)); + } + } + else + { + rSet.DisableItem(SID_REDO); + } +} + +/** This method consists basically of three parts: + 1. Process the arguments of the SFX request. + 2. Use the model to create a new page or duplicate an existing one. + 3. Update the tab control and switch to the new page. +*/ +SdPage* ViewShell::CreateOrDuplicatePage ( + SfxRequest& rRequest, + PageKind ePageKind, + SdPage* pPage, + const sal_Int32 nInsertPosition) +{ + sal_uInt16 nSId = rRequest.GetSlot(); + SdDrawDocument* pDocument = GetDoc(); + SdrLayerAdmin& rLayerAdmin = pDocument->GetLayerAdmin(); + SdrLayerID aBckgrnd = rLayerAdmin.GetLayerID(sUNO_LayerName_background); + SdrLayerID aBckgrndObj = rLayerAdmin.GetLayerID(sUNO_LayerName_background_objects); + SdrLayerIDSet aVisibleLayers; + // Determine the page from which to copy some values, such as layers, + // size, master page, to the new page. This is usually the given page. + // When the given page is NULL then use the first page of the document. + SdPage* pTemplatePage = pPage; + if (pTemplatePage == nullptr) + pTemplatePage = pDocument->GetSdPage(0, ePageKind); + if (pTemplatePage != nullptr && pTemplatePage->TRG_HasMasterPage()) + aVisibleLayers = pTemplatePage->TRG_GetMasterPageVisibleLayers(); + else + aVisibleLayers.SetAll(); + + OUString aStandardPageName; + OUString aNotesPageName; + AutoLayout eStandardLayout (AUTOLAYOUT_NONE); + AutoLayout eNotesLayout (AUTOLAYOUT_NOTES); + bool bIsPageBack = aVisibleLayers.IsSet(aBckgrnd); + bool bIsPageObj = aVisibleLayers.IsSet(aBckgrndObj); + + // 1. Process the arguments. + const SfxItemSet* pArgs = rRequest.GetArgs(); + const SfxUInt16Item* pInsertPos = rRequest.GetArg<SfxUInt16Item>(ID_INSERT_POS); + + if (! pArgs || (pArgs->Count() == 1 && pInsertPos)) + { + // AutoLayouts must be ready + pDocument->StopWorkStartupDelay(); + + // Use the layouts of the previous page and notes page as template. + if (pTemplatePage != nullptr) + { + eStandardLayout = pTemplatePage->GetAutoLayout(); + if( eStandardLayout == AUTOLAYOUT_TITLE ) + eStandardLayout = AUTOLAYOUT_TITLE_CONTENT; + + SdPage* pNotesTemplatePage = static_cast<SdPage*>(pDocument->GetPage(pTemplatePage->GetPageNum()+1)); + if (pNotesTemplatePage != nullptr) + eNotesLayout = pNotesTemplatePage->GetAutoLayout(); + } + } + else if (pArgs->Count() == 1 || pArgs->Count() == 2) + { + pDocument->StopWorkStartupDelay(); + const SfxUInt32Item* pLayout = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYOUT); + if( pLayout ) + { + if (ePageKind == PageKind::Notes) + { + eNotesLayout = static_cast<AutoLayout>(pLayout->GetValue ()); + } + else + { + eStandardLayout = static_cast<AutoLayout>(pLayout->GetValue ()); + } + } + } + else if (pArgs->Count() == 4 || pArgs->Count() == 5) + { + // AutoLayouts must be ready + pDocument->StopWorkStartupDelay(); + + const SfxStringItem* pPageName = rRequest.GetArg<SfxStringItem>(ID_VAL_PAGENAME); + const SfxUInt32Item* pLayout = rRequest.GetArg<SfxUInt32Item>(ID_VAL_WHATLAYOUT); + const SfxBoolItem* pIsPageBack = rRequest.GetArg<SfxBoolItem>(ID_VAL_ISPAGEBACK); + const SfxBoolItem* pIsPageObj = rRequest.GetArg<SfxBoolItem>(ID_VAL_ISPAGEOBJ); + assert(pPageName && pLayout && pIsPageBack && pIsPageObj && "must be present"); + + if (CHECK_RANGE (AUTOLAYOUT_START, static_cast<AutoLayout>(pLayout->GetValue ()), AUTOLAYOUT_END)) + { + if (ePageKind == PageKind::Notes) + { + aNotesPageName = pPageName->GetValue (); + eNotesLayout = static_cast<AutoLayout>(pLayout->GetValue ()); + } + else + { + aStandardPageName = pPageName->GetValue (); + eStandardLayout = static_cast<AutoLayout>(pLayout->GetValue ()); + } + + bIsPageBack = pIsPageBack->GetValue (); + bIsPageObj = pIsPageObj->GetValue (); + } + else + { + Cancel(); + + if(HasCurrentFunction( SID_BEZIER_EDIT ) ) + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_BAD_PROP_VALUE); +#endif + rRequest.Ignore (); + return nullptr; + } + } + else + { + Cancel(); + + if(HasCurrentFunction(SID_BEZIER_EDIT) ) + GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT, SfxCallMode::ASYNCHRON); +#if HAVE_FEATURE_SCRIPTING + StarBASIC::FatalError (ERRCODE_BASIC_WRONG_ARGS); +#endif + rRequest.Ignore (); + return nullptr; + } + + // 2. Create a new page or duplicate an existing one. + View* pDrView = GetView(); + const bool bUndo = pDrView && pDrView->IsUndoEnabled(); + if( bUndo && GetDoc()->GetDocumentType() == DocumentType::Draw) + pDrView->BegUndo(SdResId(STR_INSERT_PAGE_DRAW)); + else if (bUndo) + pDrView->BegUndo(SdResId(STR_INSERTPAGE)); + + + + sal_uInt16 nNewPageIndex = 0xffff; + switch (nSId) + { + case SID_INSERTPAGE: + case SID_INSERTPAGE_QUICK: + case SID_INSERT_MASTER_PAGE: + // There are three cases. a) pPage is not NULL: we use it as a + // template and create a new slide behind it. b) pPage is NULL + // but the document is not empty: we use the first slide/notes + // page as template, create a new slide after it and move it + // then to the head of the document. c) pPage is NULL and the + // document is empty: We use CreateFirstPages to create the + // first page of the document. + if (pPage == nullptr) + if (pTemplatePage == nullptr) + { + pDocument->CreateFirstPages(); + nNewPageIndex = 0; + } + else + { + // Create a new page with the first page as template and + // insert it after the first page. + nNewPageIndex = pDocument->CreatePage ( + pTemplatePage, + ePageKind, + aStandardPageName, + aNotesPageName, + eStandardLayout, + eNotesLayout, + bIsPageBack, + bIsPageObj, + nInsertPosition); + // Select exactly the new page. + sal_uInt16 nPageCount (pDocument->GetSdPageCount(ePageKind)); + for (sal_uInt16 i=0; i<nPageCount; i++) + { + pDocument->GetSdPage(i, PageKind::Standard)->SetSelected( + i == nNewPageIndex); + pDocument->GetSdPage(i, PageKind::Notes)->SetSelected( + i == nNewPageIndex); + } + // Move the selected page to the head of the document + pDocument->MovePages (sal_uInt16(-1)); + nNewPageIndex = 0; + } + else + nNewPageIndex = pDocument->CreatePage ( + pPage, + ePageKind, + aStandardPageName, + aNotesPageName, + eStandardLayout, + eNotesLayout, + bIsPageBack, + bIsPageObj, + nInsertPosition); + break; + + case SID_DUPLICATE_PAGE: + // Duplication makes no sense when pPage is NULL. + if (pPage != nullptr) + nNewPageIndex = pDocument->DuplicatePage ( + pPage, + ePageKind, + aStandardPageName, + aNotesPageName, + bIsPageBack, + bIsPageObj, + pInsertPos ? (pInsertPos->GetValue()*2)+1 : nInsertPosition); + break; + + default: + SAL_INFO("sd", "wrong slot id given to CreateOrDuplicatePage"); + // Try to handle another slot id gracefully. + } + SdPage* pNewPage = nullptr; + if(nNewPageIndex != 0xffff) + pNewPage = pDocument->GetSdPage(nNewPageIndex, PageKind::Standard); + + if( bUndo ) + { + if( pNewPage ) + { + pDrView->AddUndo(pDocument->GetSdrUndoFactory().CreateUndoNewPage(*pNewPage)); + pDrView->AddUndo(pDocument->GetSdrUndoFactory().CreateUndoNewPage(*pDocument->GetSdPage (nNewPageIndex, PageKind::Notes))); + } + + pDrView->EndUndo(); + } + + return pNewPage; +} + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/viewshel.cxx b/sd/source/ui/view/viewshel.cxx new file mode 100644 index 0000000000..09c1f95102 --- /dev/null +++ b/sd/source/ui/view/viewshel.cxx @@ -0,0 +1,1659 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <ViewShell.hxx> +#include <ViewShellImplementation.hxx> +#include <createtableobjectbar.hxx> + +#include <ViewShellBase.hxx> +#include <ShellFactory.hxx> +#include <DrawController.hxx> +#include <LayerTabBar.hxx> +#include <Outliner.hxx> + +#include <sal/log.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <vcl/commandevent.hxx> +#include <svl/eitem.hxx> +#include <svx/ruler.hxx> +#include <svx/svxids.hrc> +#include <svx/fmshell.hxx> +#include <WindowUpdater.hxx> +#include <sdxfer.hxx> + +#include <app.hrc> + +#include <OutlineView.hxx> +#include <DrawViewShell.hxx> +#include <DrawDocShell.hxx> +#include <slideshow.hxx> +#include <drawdoc.hxx> +#include <sdpage.hxx> +#include <zoomlist.hxx> +#include <FrameView.hxx> +#include <BezierObjectBar.hxx> +#include <TextObjectBar.hxx> +#include <GraphicObjectBar.hxx> +#include <MediaObjectBar.hxx> +#include <SlideSorter.hxx> +#include <SlideSorterViewShell.hxx> +#include <ViewShellManager.hxx> +#include <FormShellManager.hxx> +#include <svx/extrusionbar.hxx> +#include <svx/fontworkbar.hxx> +#include <svx/svdoutl.hxx> +#include <tools/svborder.hxx> +#include <comphelper/lok.hxx> + +#include <svl/slstitm.hxx> +#include <sfx2/request.hxx> +#include <SpellDialogChildWindow.hxx> +#include <controller/SlideSorterController.hxx> +#include <controller/SlsPageSelector.hxx> +#include <controller/SlsSelectionObserver.hxx> +#include <view/SlideSorterView.hxx> + +#include <basegfx/utils/zoomtools.hxx> + +#include <Window.hxx> +#include <fupoor.hxx> +#include <futext.hxx> + +#include <editeng/numitem.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editund2.hxx> +#include <svl/itempool.hxx> +#include <svl/intitem.hxx> +#include <svl/poolitem.hxx> +#include <strings.hxx> +#include <sdmod.hxx> +#include <AccessibleDocumentViewBase.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::presentation; + +namespace { + +class ViewShellObjectBarFactory + : public ::sd::ShellFactory<SfxShell> +{ +public: + explicit ViewShellObjectBarFactory (::sd::ViewShell& rViewShell); + virtual SfxShell* CreateShell( ::sd::ShellId nId ) override; + virtual void ReleaseShell (SfxShell* pShell) override; +private: + ::sd::ViewShell& mrViewShell; +}; + +} // end of anonymous namespace + +namespace sd { + +bool ViewShell::IsPageFlipMode() const +{ + return dynamic_cast< const DrawViewShell *>( this ) != nullptr && mpContentWindow && + mpContentWindow->GetVisibleHeight() >= 1.0; +} + +SfxViewFrame* ViewShell::GetViewFrame() const +{ + const SfxViewShell* pViewShell = GetViewShell(); + if (pViewShell != nullptr) + { + return &pViewShell->GetViewFrame(); + } + else + { + OSL_ASSERT (GetViewShell()!=nullptr); + return nullptr; + } +} + +/// declare SFX-Slotmap and standard interface + +ViewShell::ViewShell( vcl::Window* pParentWindow, ViewShellBase& rViewShellBase) +: SfxShell(&rViewShellBase) +, mpParentWindow(pParentWindow) +{ + construct(); +} + +ViewShell::~ViewShell() +{ + // Keep the content window from accessing in its destructor the + // WindowUpdater. + if (mpContentWindow) + suppress_fun_call_w_exception(mpContentWindow->SetViewShell(nullptr)); + + mpZoomList.reset(); + + mpLayerTabBar.disposeAndClear(); + + if (mpImpl->mpSubShellFactory) + GetViewShellBase().GetViewShellManager()->RemoveSubShellFactory( + this,mpImpl->mpSubShellFactory); + + if (mpContentWindow) + { + SAL_INFO( + "sd.view", + "destroying mpContentWindow at " << mpContentWindow.get() + << " with parent " << mpContentWindow->GetParent()); + mpContentWindow.disposeAndClear(); + } + + mpVerticalRuler.disposeAndClear(); + mpHorizontalRuler.disposeAndClear(); + mpVerticalScrollBar.disposeAndClear(); + mpHorizontalScrollBar.disposeAndClear(); +} + +/** + * common initialization part of both constructors + */ +void ViewShell::construct() +{ + mbHasRulers = false; + mpActiveWindow = nullptr; + mpView = nullptr; + mpFrameView = nullptr; + mpZoomList = nullptr; + mfLastZoomScale = 0; + mbStartShowWithDialog = false; + mnPrintedHandoutPageNum = 1; + mnPrintedHandoutPageCount = 0; + mpWindowUpdater.reset( new ::sd::WindowUpdater() ); + mpImpl.reset(new Implementation(*this)); + meShellType = ST_NONE; + + OSL_ASSERT (GetViewShell()!=nullptr); + + if (IsMainViewShell()) + GetDocSh()->Connect (this); + + mpZoomList.reset( new ZoomList( this ) ); + + mpContentWindow.reset(VclPtr< ::sd::Window >::Create(GetParentWindow())); + SetActiveWindow (mpContentWindow.get()); + + GetParentWindow()->SetBackground(Application::GetSettings().GetStyleSettings().GetFaceColor()); + mpContentWindow->SetBackground (Wallpaper()); + mpContentWindow->SetCenterAllowed(true); + mpContentWindow->SetViewShell(this); + mpContentWindow->SetPosSizePixel( + GetParentWindow()->GetPosPixel(),GetParentWindow()->GetSizePixel()); + + if ( ! GetDocSh()->IsPreview()) + { + // Create scroll bars and the filler between the scroll bars. + mpHorizontalScrollBar.reset (VclPtr<ScrollAdaptor>::Create(GetParentWindow(), true)); + mpHorizontalScrollBar->EnableRTL (false); + mpHorizontalScrollBar->SetRange(Range(0, 32000)); + mpHorizontalScrollBar->SetScrollHdl(LINK(this, ViewShell, HScrollHdl)); + + mpVerticalScrollBar.reset (VclPtr<ScrollAdaptor>::Create(GetParentWindow(), false)); + mpVerticalScrollBar->SetRange(Range(0, 32000)); + mpVerticalScrollBar->SetScrollHdl(LINK(this, ViewShell, VScrollHdl)); + } + + SetName ("ViewShell"); + + GetDoc()->StartOnlineSpelling(false); + + mpWindowUpdater->SetDocument (GetDoc()); + + // Re-initialize the spell dialog. + ::sd::SpellDialogChildWindow* pSpellDialog = + static_cast< ::sd::SpellDialogChildWindow*> ( + GetViewFrame()->GetChildWindow ( + ::sd::SpellDialogChildWindow::GetChildWindowId())); + if (pSpellDialog != nullptr) + pSpellDialog->InvalidateSpellDialog(); + + // Register the sub shell factory. + mpImpl->mpSubShellFactory = std::make_shared<ViewShellObjectBarFactory>(*this); + GetViewShellBase().GetViewShellManager()->AddSubShellFactory(this,mpImpl->mpSubShellFactory); +} + +void ViewShell::doShow() +{ + mpContentWindow->Show(); + static_cast< vcl::Window*>(mpContentWindow.get())->Resize(); + SAL_INFO( + "sd.view", + "content window has size " << mpContentWindow->GetSizePixel().Width() + << " " << mpContentWindow->GetSizePixel().Height()); + + if ( ! GetDocSh()->IsPreview()) + { + // Show scroll bars + mpHorizontalScrollBar->Show(); + + mpVerticalScrollBar->Show(); + maScrBarWH = Size( + mpVerticalScrollBar->GetSizePixel().Width(), + mpHorizontalScrollBar->GetSizePixel().Height()); + } + + GetParentWindow()->Show(); +} + +void ViewShell::Init (bool bIsMainViewShell) +{ + mpImpl->mbIsInitialized = true; + SetIsMainViewShell(bIsMainViewShell); + if (bIsMainViewShell) + SetActiveWindow (mpContentWindow.get()); +} + +void ViewShell::Exit() +{ + sd::View* pView = GetView(); + if (pView!=nullptr && pView->IsTextEdit()) + { + pView->SdrEndTextEdit(); + pView->UnmarkAll(); + } + + Deactivate (true); + + if (IsMainViewShell()) + GetDocSh()->Disconnect(this); + + SetIsMainViewShell(false); +} + +/** + * set focus to working window + */ +void ViewShell::Activate(bool bIsMDIActivate) +{ + // Do not forward to SfxShell::Activate() + + /* According to MI, nobody is allowed to call GrabFocus, who does not + exactly know from which window the focus is grabbed. Since Activate() + is sent sometimes asynchronous, it can happen, that the wrong window + gets the focus. */ + + if (mpHorizontalRuler) + mpHorizontalRuler->SetActive(); + if (mpVerticalRuler) + mpVerticalRuler->SetActive(); + + if (bIsMDIActivate) + { + // thus, the Navigator will also get a current status + SfxBoolItem aItem( SID_NAVIGATOR_INIT, true ); + if (GetDispatcher() != nullptr) + GetDispatcher()->ExecuteList( + SID_NAVIGATOR_INIT, + SfxCallMode::ASYNCHRON | SfxCallMode::RECORD, + { &aItem }); + + SfxViewShell* pViewShell = GetViewShell(); + OSL_ASSERT (pViewShell!=nullptr); + SfxBindings& rBindings = pViewShell->GetViewFrame().GetBindings(); + rBindings.Invalidate( SID_3D_STATE, true ); + + rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if (xSlideShow.is() && xSlideShow->isRunning()) + { + bool bSuccess = xSlideShow->activate(GetViewShellBase()); + assert(bSuccess && "can only return false with a PresentationViewShell"); (void)bSuccess; + } + + if(HasCurrentFunction()) + GetCurrentFunction()->Activate(); + + if(!GetDocSh()->IsUIActive()) + UpdatePreview( GetActualPage() ); + } + + ReadFrameViewData( mpFrameView ); + + if (IsMainViewShell()) + GetDocSh()->Connect(this); +} + +void ViewShell::UIActivating( SfxInPlaceClient* ) +{ + OSL_ASSERT (GetViewShell()!=nullptr); + GetViewShellBase().GetToolBarManager()->ToolBarsDestroyed(); +} + +void ViewShell::UIDeactivated( SfxInPlaceClient* ) +{ + OSL_ASSERT (GetViewShell()!=nullptr); + GetViewShellBase().GetToolBarManager()->ToolBarsDestroyed(); + if ( GetDrawView() ) + GetViewShellBase().GetToolBarManager()->SelectionHasChanged(*this, *GetDrawView()); +} + +void ViewShell::Deactivate(bool bIsMDIActivate) +{ + // remove view from a still active drag'n'drop session + SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + + if (IsMainViewShell()) + GetDocSh()->Disconnect(this); + + if( pDragTransferable ) + pDragTransferable->SetView( nullptr ); + + OSL_ASSERT (GetViewShell()!=nullptr); + + // remember view attributes of FrameView + WriteFrameViewData(); + + if (bIsMDIActivate) + { + rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if(xSlideShow.is() && xSlideShow->isRunning() ) + xSlideShow->deactivate(); + + if(HasCurrentFunction()) + GetCurrentFunction()->Deactivate(); + } + + if (mpHorizontalRuler) + mpHorizontalRuler->SetActive(false); + if (mpVerticalRuler) + mpVerticalRuler->SetActive(false); + + SfxShell::Deactivate(bIsMDIActivate); +} + +void ViewShell::Shutdown() +{ + Exit (); +} + +bool ViewShell::KeyInput(const KeyEvent& rKEvt, ::sd::Window* pWin) +{ + bool bReturn(false); + + if(pWin) + SetActiveWindow(pWin); + + // give key input first to SfxViewShell to give CTRL+Key + // (e.g. CTRL+SHIFT+'+', to front) priority. + OSL_ASSERT(GetViewShell() != nullptr); + bReturn = GetViewShell()->KeyInput(rKEvt); + + const size_t OriCount = GetView()->GetMarkedObjectList().GetMarkCount(); + if(!bReturn) + { + rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if(xSlideShow.is() && xSlideShow->isRunning()) + { + bReturn = xSlideShow->keyInput(rKEvt); + } + else + { + bool bConsumed = false; + if( GetView() ) + bConsumed = GetView()->getSmartTags().KeyInput(rKEvt); + + if( !bConsumed ) + { + rtl::Reference< sdr::SelectionController > xSelectionController( GetView()->getSelectionController() ); + if( !xSelectionController.is() || !xSelectionController->onKeyInput( rKEvt, pWin ) ) + { + if(HasCurrentFunction()) + bReturn = GetCurrentFunction()->KeyInput(rKEvt); + } + else + { + bReturn = true; + if (HasCurrentFunction()) + { + FuText* pTextFunction = dynamic_cast<FuText*>(GetCurrentFunction().get()); + if(pTextFunction != nullptr) + pTextFunction->InvalidateBindings(); + } + } + } + } + } + const size_t EndCount = GetView()->GetMarkedObjectList().GetMarkCount(); + // Here, oriCount or endCount must have one value=0, another value > 0, then to switch focus between Document and shape objects + if(bReturn && (OriCount + EndCount > 0) && (OriCount * EndCount == 0)) + SwitchActiveViewFireFocus(); + + if(!bReturn && GetActiveWindow()) + { + vcl::KeyCode aKeyCode = rKEvt.GetKeyCode(); + + if (aKeyCode.IsMod1() && aKeyCode.IsShift() + && aKeyCode.GetCode() == KEY_R) + { + InvalidateWindows(); + bReturn = true; + } + } + + return bReturn; +} + +void ViewShell::MouseButtonDown(const MouseEvent& rMEvt, ::sd::Window* pWin) +{ + // We have to lock tool bar updates while the mouse button is pressed in + // order to prevent the shape under the mouse to be moved (this happens + // when the number of docked tool bars changes as result of a changed + // selection; this changes the window size and thus the mouse position + // in model coordinates: with respect to model coordinates the mouse + // moves.) + OSL_ASSERT(mpImpl->mpUpdateLockForMouse.expired()); + mpImpl->mpUpdateLockForMouse = ViewShell::Implementation::ToolBarManagerLock::Create( + GetViewShellBase().GetToolBarManager()); + + if ( pWin && !pWin->HasFocus() ) + { + pWin->GrabFocus(); + SetActiveWindow(pWin); + } + + // insert MouseEvent into E3dView + if (GetView() != nullptr) + GetView()->SetMouseEvent(rMEvt); + + bool bConsumed = false; + if( GetView() ) + bConsumed = GetView()->getSmartTags().MouseButtonDown( rMEvt ); + + if( bConsumed ) + return; + + rtl::Reference< sdr::SelectionController > xSelectionController( GetView()->getSelectionController() ); + if( !xSelectionController.is() || !xSelectionController->onMouseButtonDown( rMEvt, pWin ) ) + { + if(HasCurrentFunction()) + GetCurrentFunction()->MouseButtonDown(rMEvt); + } + else + { + if (HasCurrentFunction()) + { + FuText* pTextFunction = dynamic_cast<FuText*>(GetCurrentFunction().get()); + if (pTextFunction != nullptr) + pTextFunction->InvalidateBindings(); + } + } +} + +void ViewShell::SetCursorMm100Position(const Point& rPosition, bool bPoint, bool bClearMark) +{ + if (SdrView* pSdrView = GetView()) + { + rtl::Reference<sdr::SelectionController> xSelectionController(GetView()->getSelectionController()); + if (!xSelectionController.is() || !xSelectionController->setCursorLogicPosition(rPosition, bPoint)) + { + if (pSdrView->GetTextEditObject()) + { + EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView(); + rEditView.SetCursorLogicPosition(rPosition, bPoint, bClearMark); + } + } + } +} + +uno::Reference<datatransfer::XTransferable> ViewShell::GetSelectionTransferable() const +{ + SdrView* pSdrView = GetView(); + if (!pSdrView) + return uno::Reference<datatransfer::XTransferable>(); + + if (!pSdrView->GetTextEditObject()) + return uno::Reference<datatransfer::XTransferable>(); + + EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView(); + return rEditView.GetEditEngine()->CreateTransferable(rEditView.GetSelection()); +} + +void ViewShell::SetGraphicMm100Position(bool bStart, const Point& rPosition) +{ + if (bStart) + { + MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT); + MouseButtonDown(aClickEvent, mpActiveWindow); + MouseEvent aMoveEvent(Point(rPosition.getX(), rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT); + MouseMove(aMoveEvent, mpActiveWindow); + } + else + { + MouseEvent aMoveEvent(Point(rPosition.getX(), rPosition.getY()), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT); + MouseMove(aMoveEvent, mpActiveWindow); + MouseEvent aClickEvent(rPosition, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT); + MouseButtonUp(aClickEvent, mpActiveWindow); + } +} + +void ViewShell::MouseMove(const MouseEvent& rMEvt, ::sd::Window* pWin) +{ + if (rMEvt.IsLeaveWindow()) + { + if ( ! mpImpl->mpUpdateLockForMouse.expired()) + { + std::shared_ptr<ViewShell::Implementation::ToolBarManagerLock> pLock( + mpImpl->mpUpdateLockForMouse); + if (pLock != nullptr) + pLock->Release(); + } + } + + if ( pWin ) + { + SetActiveWindow(pWin); + } + + // insert MouseEvent into E3dView + if (GetView() != nullptr) + GetView()->SetMouseEvent(rMEvt); + + if(HasCurrentFunction()) + { + rtl::Reference< sdr::SelectionController > xSelectionController( GetView()->getSelectionController() ); + if( !xSelectionController.is() || !xSelectionController->onMouseMove( rMEvt, pWin ) ) + { + if(HasCurrentFunction()) + GetCurrentFunction()->MouseMove(rMEvt); + } + } +} + +void ViewShell::MouseButtonUp(const MouseEvent& rMEvt, ::sd::Window* pWin) +{ + if ( pWin ) + SetActiveWindow(pWin); + + // insert MouseEvent into E3dView + if (GetView() != nullptr) + GetView()->SetMouseEvent(rMEvt); + + if( HasCurrentFunction()) + { + rtl::Reference< sdr::SelectionController > xSelectionController( GetView()->getSelectionController() ); + if( !xSelectionController.is() || !xSelectionController->onMouseButtonUp( rMEvt, pWin ) ) + { + if(HasCurrentFunction()) + GetCurrentFunction()->MouseButtonUp(rMEvt); + } + else + { + if (HasCurrentFunction()) + { + FuText* pTextFunction = dynamic_cast<FuText*>(GetCurrentFunction().get()); + if (pTextFunction != nullptr) + pTextFunction->InvalidateBindings(); + } + } + } + + if ( ! mpImpl->mpUpdateLockForMouse.expired()) + { + std::shared_ptr<ViewShell::Implementation::ToolBarManagerLock> pLock( + mpImpl->mpUpdateLockForMouse); + if (pLock != nullptr) + pLock->Release(); + } +} + +void ViewShell::Command(const CommandEvent& rCEvt, ::sd::Window* pWin) +{ + bool bDone = HandleScrollCommand (rCEvt, pWin); + + if( bDone ) + return; + + if( rCEvt.GetCommand() == CommandEventId::InputLanguageChange ) + { + //#i42732# update state of fontname if input language changes + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_CHAR_FONT ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_CHAR_FONTHEIGHT ); + } + else + { + bool bConsumed = false; + if( GetView() ) + bConsumed = GetView()->getSmartTags().Command(rCEvt); + + if( !bConsumed && HasCurrentFunction()) + GetCurrentFunction()->Command(rCEvt); + } +} + +bool ViewShell::Notify(NotifyEvent const & rNEvt, ::sd::Window* pWin) +{ + // handle scroll commands when they arrived at child windows + bool bRet = false; + if( rNEvt.GetType() == NotifyEventType::COMMAND ) + { + // note: dynamic_cast is not possible as GetData() returns a void* + CommandEvent* pCmdEvent = static_cast< CommandEvent* >(rNEvt.GetData()); + bRet = HandleScrollCommand(*pCmdEvent, pWin); + } + return bRet; +} + +bool ViewShell::HandleScrollCommand(const CommandEvent& rCEvt, ::sd::Window* pWin) +{ + bool bDone = false; + + switch( rCEvt.GetCommand() ) + { + case CommandEventId::GestureSwipe: + { + rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if (xSlideShow.is()) + { + const CommandGestureSwipeData* pSwipeData = rCEvt.GetGestureSwipeData(); + bDone = xSlideShow->swipe(*pSwipeData); + } + } + break; + case CommandEventId::GestureLongPress: + { + rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + if (xSlideShow.is()) + { + const CommandGestureLongPressData* pLongPressData = rCEvt.GetLongPressData(); + bDone = xSlideShow->longpress(*pLongPressData); + } + } + break; + + case CommandEventId::Wheel: + { + Reference< XSlideShowController > xSlideShowController( SlideShow::GetSlideShowController(GetViewShellBase() ) ); + if( xSlideShowController.is() ) + { + // We ignore zooming with control+mouse wheel. + const CommandWheelData* pData = rCEvt.GetWheelData(); + if( pData && !pData->GetModifier() && ( pData->GetMode() == CommandWheelMode::SCROLL ) && !pData->IsHorz() ) + { + ::tools::Long nDelta = pData->GetDelta(); + if( nDelta > 0 ) + xSlideShowController->gotoPreviousSlide(); + else if( nDelta < 0 ) + xSlideShowController->gotoNextEffect(); + } + break; + } + } + [[fallthrough]]; + case CommandEventId::StartAutoScroll: + case CommandEventId::AutoScroll: + { + const CommandWheelData* pData = rCEvt.GetWheelData(); + + if (pData != nullptr) + { + if (pData->IsMod1()) + { + if( !GetDocSh()->IsUIActive() ) + { + const sal_uInt16 nOldZoom = GetActiveWindow()->GetZoom(); + sal_uInt16 nNewZoom; + Point aOldMousePos = GetActiveWindow()->PixelToLogic(rCEvt.GetMousePosPixel()); + + if( pData->GetDelta() < 0 ) + nNewZoom = std::max<sal_uInt16>( pWin->GetMinZoom(), basegfx::zoomtools::zoomOut( nOldZoom )); + else + nNewZoom = std::min<sal_uInt16>( pWin->GetMaxZoom(), basegfx::zoomtools::zoomIn( nOldZoom )); + + SetZoom( nNewZoom ); + // Keep mouse at same doc point before zoom + Point aNewMousePos = GetActiveWindow()->PixelToLogic(rCEvt.GetMousePosPixel()); + SetWinViewPos(GetWinViewPos() - (aNewMousePos - aOldMousePos)); + + Invalidate( SID_ATTR_ZOOM ); + Invalidate( SID_ATTR_ZOOMSLIDER ); + + bDone = true; + } + } + else + { + if( mpContentWindow.get() == pWin ) + { + double nScrollLines = pData->GetScrollLines(); + if(IsPageFlipMode()) + nScrollLines = COMMAND_WHEEL_PAGESCROLL; + CommandWheelData aWheelData( pData->GetDelta(),pData->GetNotchDelta(), + nScrollLines,pData->GetMode(),pData->GetModifier(),pData->IsHorz() ); + CommandEvent aReWrite( rCEvt.GetMousePosPixel(),rCEvt.GetCommand(), + rCEvt.IsMouseEvent(),static_cast<const void *>(&aWheelData) ); + bDone = pWin->HandleScrollCommand( aReWrite, + mpHorizontalScrollBar.get(), + mpVerticalScrollBar.get()); + } + } + } + } + break; + + case CommandEventId::GestureZoom: + { + const CommandGestureZoomData* pData = rCEvt.GetGestureZoomData(); + + Reference<XSlideShowController> xSlideShowController(SlideShow::GetSlideShowController(GetViewShellBase())); + + if (pData->meEventType == GestureEventZoomType::Begin) + { + mfLastZoomScale = pData->mfScaleDelta; + bDone = true; + break; + } + + if (pData->meEventType == GestureEventZoomType::Update) + { + double deltaBetweenEvents = (pData->mfScaleDelta - mfLastZoomScale) / mfLastZoomScale; + mfLastZoomScale = pData->mfScaleDelta; + + if (!GetDocSh()->IsUIActive() && !xSlideShowController.is()) + { + const ::tools::Long nOldZoom = GetActiveWindow()->GetZoom(); + ::tools::Long nNewZoom; + Point aOldMousePos = GetActiveWindow()->PixelToLogic(rCEvt.GetMousePosPixel()); + + // Accumulate fractional zoom to avoid small zoom changes from being ignored + mfAccumulatedZoom += deltaBetweenEvents; + int nZoomChangePercent = mfAccumulatedZoom * 100; + mfAccumulatedZoom -= nZoomChangePercent / 100.0; + + nNewZoom = nOldZoom + nZoomChangePercent; + nNewZoom = std::max<::tools::Long>(pWin->GetMinZoom(), nNewZoom); + nNewZoom = std::min<::tools::Long>(pWin->GetMaxZoom(), nNewZoom); + + SetZoom(nNewZoom); + + // Keep mouse at same doc point before zoom + Point aNewMousePos = GetActiveWindow()->PixelToLogic(rCEvt.GetMousePosPixel()); + SetWinViewPos(GetWinViewPos() - (aNewMousePos - aOldMousePos)); + + Invalidate(SID_ATTR_ZOOM); + Invalidate(SID_ATTR_ZOOMSLIDER); + } + } + + bDone = true; + } + break; + + default: + break; + } + + return bDone; +} + +void ViewShell::SetupRulers() +{ + if(!mbHasRulers || !mpContentWindow || SlideShow::IsRunning(GetViewShellBase())) + return; + + ::tools::Long nHRulerOfs = 0; + + if ( !mpVerticalRuler ) + { + mpVerticalRuler.reset(CreateVRuler(GetActiveWindow())); + if ( mpVerticalRuler ) + { + nHRulerOfs = mpVerticalRuler->GetSizePixel().Width(); + mpVerticalRuler->SetActive(); + mpVerticalRuler->Show(); + } + } + if ( !mpHorizontalRuler ) + { + mpHorizontalRuler.reset(CreateHRuler(GetActiveWindow())); + if ( mpHorizontalRuler ) + { + mpHorizontalRuler->SetWinPos(nHRulerOfs); + mpHorizontalRuler->SetActive(); + mpHorizontalRuler->Show(); + } + } +} + +const SvxNumBulletItem* ViewShell::GetNumBulletItem(SfxItemSet& aNewAttr, TypedWhichId<SvxNumBulletItem>& nNumItemId) +{ + const SvxNumBulletItem* pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false); + if(pTmpItem) + return pTmpItem; + + nNumItemId = aNewAttr.GetPool()->GetWhich(SID_ATTR_NUMBERING_RULE); + pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false); + if(pTmpItem) + return pTmpItem; + + bool bOutliner = false; + bool bTitle = false; + + if( mpView ) + { + const SdrMarkList& rMarkList = mpView->GetMarkedObjectList(); + const size_t nCount = rMarkList.GetMarkCount(); + + for(size_t nNum = 0; nNum < nCount; ++nNum) + { + SdrObject* pObj = rMarkList.GetMark(nNum)->GetMarkedSdrObj(); + if( pObj->GetObjInventor() == SdrInventor::Default ) + { + switch(pObj->GetObjIdentifier()) + { + case SdrObjKind::TitleText: + bTitle = true; + break; + case SdrObjKind::OutlineText: + bOutliner = true; + break; + default: + break; + } + } + } + } + + const SvxNumBulletItem *pItem = nullptr; + if(bOutliner) + { + SfxStyleSheetBasePool* pSSPool = mpView->GetDocSh()->GetStyleSheetPool(); + SfxStyleSheetBase* pFirstStyleSheet = pSSPool->Find( STR_LAYOUT_OUTLINE + " 1", SfxStyleFamily::Pseudo); + if( pFirstStyleSheet ) + pItem = pFirstStyleSheet->GetItemSet().GetItemIfSet(EE_PARA_NUMBULLET, false); + } + + if( pItem == nullptr ) + pItem = aNewAttr.GetPool()->GetSecondaryPool()->GetPoolDefaultItem(EE_PARA_NUMBULLET); + + aNewAttr.Put(pItem->CloneSetWhich(EE_PARA_NUMBULLET)); + + if(bTitle && aNewAttr.GetItemState(EE_PARA_NUMBULLET) == SfxItemState::SET ) + { + const SvxNumBulletItem* pBulletItem = aNewAttr.GetItem(EE_PARA_NUMBULLET); + const SvxNumRule& rRule = pBulletItem->GetNumRule(); + SvxNumRule aNewRule( rRule ); + aNewRule.SetFeatureFlag( SvxNumRuleFlags::NO_NUMBERS ); + + SvxNumBulletItem aNewItem( std::move(aNewRule), EE_PARA_NUMBULLET ); + aNewAttr.Put(aNewItem); + } + + pTmpItem = aNewAttr.GetItemIfSet(nNumItemId, false); + + return pTmpItem; +} + +void ViewShell::Resize() +{ + SetupRulers (); + + if (mpParentWindow == nullptr) + return; + + // Make sure that the new size is not degenerate. + const Size aSize (mpParentWindow->GetSizePixel()); + if (aSize.IsEmpty()) + return; + + // Remember the new position and size. + maViewPos = Point(0,0); + maViewSize = aSize; + + // Rearrange the UI elements to take care of the new position and size. + ArrangeGUIElements (); + // end of included AdjustPosSizePixel. + + ::sd::View* pView = GetView(); + + if (pView) + pView->VisAreaChanged(GetActiveWindow()->GetOutDev()); +} + +SvBorder ViewShell::GetBorder() +{ + SvBorder aBorder; + + // Horizontal scrollbar. + if (mpHorizontalScrollBar + && mpHorizontalScrollBar->IsVisible()) + { + aBorder.Bottom() = maScrBarWH.Height(); + } + + // Vertical scrollbar. + if (mpVerticalScrollBar + && mpVerticalScrollBar->IsVisible()) + { + aBorder.Right() = maScrBarWH.Width(); + } + + // Place horizontal ruler below tab bar. + if (mbHasRulers && mpContentWindow) + { + SetupRulers(); + if (mpHorizontalRuler) + aBorder.Top() = mpHorizontalRuler->GetSizePixel().Height(); + if (mpVerticalRuler) + aBorder.Left() = mpVerticalRuler->GetSizePixel().Width(); + } + + return aBorder; +} + +void ViewShell::ArrangeGUIElements() +{ + if (mpImpl->mbArrangeActive) + return; + if (maViewSize.IsEmpty()) + return; + mpImpl->mbArrangeActive = true; + + // Calculate border for in-place editing. + ::tools::Long nLeft = maViewPos.X(); + ::tools::Long nTop = maViewPos.Y(); + ::tools::Long nRight = maViewPos.X() + maViewSize.Width(); + ::tools::Long nBottom = maViewPos.Y() + maViewSize.Height(); + + // Horizontal scrollbar. + if (mpHorizontalScrollBar + && mpHorizontalScrollBar->IsVisible()) + { + nBottom -= maScrBarWH.Height(); + if (mpLayerTabBar && mpLayerTabBar->IsVisible()) + nBottom -= mpLayerTabBar->GetSizePixel().Height(); + mpHorizontalScrollBar->SetPosSizePixel ( + Point(nLeft, nBottom), + Size(nRight - nLeft - maScrBarWH.Width(), maScrBarWH.Height())); + } + + // Vertical scrollbar. + if (mpVerticalScrollBar + && mpVerticalScrollBar->IsVisible()) + { + nRight -= maScrBarWH.Width(); + mpVerticalScrollBar->SetPosSizePixel ( + Point(nRight,nTop), + Size (maScrBarWH.Width(), nBottom-nTop)); + } + + // Place horizontal ruler below tab bar. + if (mbHasRulers && mpContentWindow) + { + if (mpHorizontalRuler) + { + Size aRulerSize = mpHorizontalRuler->GetSizePixel(); + aRulerSize.setWidth( nRight - nLeft ); + mpHorizontalRuler->SetPosSizePixel ( + Point(nLeft,nTop), aRulerSize); + if (mpVerticalRuler) + mpHorizontalRuler->SetBorderPos( + mpVerticalRuler->GetSizePixel().Width()-1); + nTop += aRulerSize.Height(); + } + if (mpVerticalRuler) + { + Size aRulerSize = mpVerticalRuler->GetSizePixel(); + aRulerSize.setHeight( nBottom - nTop ); + mpVerticalRuler->SetPosSizePixel ( + Point (nLeft,nTop), aRulerSize); + nLeft += aRulerSize.Width(); + } + } + + rtl::Reference< SlideShow > xSlideShow( SlideShow::GetSlideShow( GetViewShellBase() ) ); + + // The size of the window of the center pane is set differently from + // that of the windows in the docking windows. + bool bSlideShowActive = (xSlideShow.is() && xSlideShow->isRunning()) && !xSlideShow->isFullScreen() && xSlideShow->getAnimationMode() == ANIMATIONMODE_SHOW; + if ( !bSlideShowActive) + { + OSL_ASSERT (GetViewShell()!=nullptr); + + if (mpContentWindow) + mpContentWindow->SetPosSizePixel( + Point(nLeft,nTop), + Size(nRight-nLeft,nBottom-nTop)); + } + + // Windows in the center and rulers at the left and top side. + maAllWindowRectangle = ::tools::Rectangle( + maViewPos, + Size(maViewSize.Width()-maScrBarWH.Width(), + maViewSize.Height()-maScrBarWH.Height())); + + if (mpContentWindow) + mpContentWindow->UpdateMapOrigin(); + + UpdateScrollBars(); + + mpImpl->mbArrangeActive = false; +} + +void ViewShell::SetUIUnit(FieldUnit eUnit) +{ + // Set unit at horizontal and vertical rulers. + if (mpHorizontalRuler) + mpHorizontalRuler->SetUnit(eUnit); + + if (mpVerticalRuler) + mpVerticalRuler->SetUnit(eUnit); +} + +/** + * set DefTab at horizontal rulers + */ +void ViewShell::SetDefTabHRuler( sal_uInt16 nDefTab ) +{ + if (mpHorizontalRuler) + mpHorizontalRuler->SetDefTabDist( nDefTab ); +} + +/** Tell the FmFormShell that the view shell is closing. Give it the + opportunity to prevent that. +*/ +bool ViewShell::PrepareClose (bool bUI) +{ + bool bResult = true; + + FmFormShell* pFormShell = GetViewShellBase().GetFormShellManager()->GetFormShell(); + if (pFormShell != nullptr) + bResult = pFormShell->PrepareClose (bUI); + + return bResult; +} + +void ViewShell::UpdatePreview (SdPage*) +{ + // Do nothing. After the actual preview has been removed, + // OutlineViewShell::UpdatePreview() is the place where something + // useful is still done. +} + +SfxUndoManager* ViewShell::ImpGetUndoManager() const +{ + const ViewShell* pMainViewShell = GetViewShellBase().GetMainViewShell().get(); + + if( pMainViewShell == nullptr ) + pMainViewShell = this; + + ::sd::View* pView = pMainViewShell->GetView(); + + // check for text edit our outline view + if( pView ) + { + if( pMainViewShell->GetShellType() == ViewShell::ST_OUTLINE ) + { + OutlineView* pOlView = dynamic_cast< OutlineView* >( pView ); + if( pOlView ) + { + ::Outliner& rOutl = pOlView->GetOutliner(); + return &rOutl.GetUndoManager(); + } + } + else if( pView->IsTextEdit() ) + { + SdrOutliner* pOL = pView->GetTextEditOutliner(); + if( pOL ) + return &pOL->GetUndoManager(); + } + } + + if( GetDocSh() ) + return GetDocSh()->GetUndoManager(); + + return nullptr; +} + +void ViewShell::ImpGetUndoStrings(SfxItemSet &rSet) const +{ + SfxUndoManager* pUndoManager = ImpGetUndoManager(); + if(!pUndoManager) + return; + + sal_uInt16 nCount(pUndoManager->GetUndoActionCount()); + if(nCount) + { + // prepare list + std::vector<OUString> aStringList; + aStringList.reserve(nCount); + for (sal_uInt16 a = 0; a < nCount; ++a) + { + // generate one String in list per undo step + aStringList.push_back( pUndoManager->GetUndoActionComment(a) ); + } + + // set item + rSet.Put(SfxStringListItem(SID_GETUNDOSTRINGS, &aStringList)); + } + else + { + rSet.DisableItem(SID_GETUNDOSTRINGS); + } +} + +void ViewShell::ImpGetRedoStrings(SfxItemSet &rSet) const +{ + SfxUndoManager* pUndoManager = ImpGetUndoManager(); + if(!pUndoManager) + return; + + sal_uInt16 nCount(pUndoManager->GetRedoActionCount()); + if(nCount) + { + // prepare list + ::std::vector< OUString > aStringList; + aStringList.reserve(nCount); + for(sal_uInt16 a = 0; a < nCount; a++) + // generate one String in list per undo step + aStringList.push_back( pUndoManager->GetRedoActionComment(a) ); + + // set item + rSet.Put(SfxStringListItem(SID_GETREDOSTRINGS, &aStringList)); + } + else + { + rSet.DisableItem(SID_GETREDOSTRINGS); + } +} + +namespace { + +class KeepSlideSorterInSyncWithPageChanges +{ + sd::slidesorter::view::SlideSorterView::DrawLock m_aDrawLock; + sd::slidesorter::controller::SlideSorterController::ModelChangeLock m_aModelLock; + sd::slidesorter::controller::PageSelector::UpdateLock m_aUpdateLock; + sd::slidesorter::controller::SelectionObserver::Context m_aContext; + +public: + explicit KeepSlideSorterInSyncWithPageChanges(sd::slidesorter::SlideSorter const & rSlideSorter) + : m_aDrawLock(rSlideSorter) + , m_aModelLock(rSlideSorter.GetController()) + , m_aUpdateLock(rSlideSorter) + , m_aContext(rSlideSorter) + { + } +}; + +} + +void ViewShell::ImpSidUndo(SfxRequest& rReq) +{ + //The xWatcher keeps the SlideSorter selection in sync + //with the page insertions/deletions that Undo may introduce + std::unique_ptr<KeepSlideSorterInSyncWithPageChanges, o3tl::default_delete<KeepSlideSorterInSyncWithPageChanges>> xWatcher; + slidesorter::SlideSorterViewShell* pSlideSorterViewShell + = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase()); + if (pSlideSorterViewShell) + xWatcher.reset(new KeepSlideSorterInSyncWithPageChanges(pSlideSorterViewShell->GetSlideSorter())); + + SfxUndoManager* pUndoManager = ImpGetUndoManager(); + sal_uInt16 nNumber(1); + const SfxItemSet* pReqArgs = rReq.GetArgs(); + bool bRepair = false; + + if(pReqArgs) + { + const SfxUInt16Item* pUIntItem = static_cast<const SfxUInt16Item*>(&pReqArgs->Get(SID_UNDO)); + nNumber = pUIntItem->GetValue(); + + // Repair mode: allow undo/redo of all undo actions, even if access would + // be limited based on the view shell ID. + if (const SfxBoolItem* pRepairItem = pReqArgs->GetItemIfSet(SID_REPAIRPACKAGE, false)) + bRepair = pRepairItem->GetValue(); + } + + if(nNumber && pUndoManager) + { + sal_uInt16 nCount(pUndoManager->GetUndoActionCount()); + if(nCount >= nNumber) + { + if (comphelper::LibreOfficeKit::isActive() && !bRepair) + { + // If another view created the first undo action, prevent redoing it from this view. + const SfxUndoAction* pAction = pUndoManager->GetUndoAction(); + if (pAction->GetViewShellId() != GetViewShellBase().GetViewShellId()) + { + rReq.SetReturnValue(SfxUInt32Item(SID_UNDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE))); + return; + } + } + + try + { + // when UndoStack is cleared by ModifyPageUndoAction + // the nCount may have changed, so test GetUndoActionCount() + while(nNumber-- && pUndoManager->GetUndoActionCount()) + pUndoManager->Undo(); + } + catch( const Exception& ) + { + // no need to handle. By definition, the UndoManager handled this by clearing the + // Undo/Redo stacks + } + } + + // refresh rulers, maybe UNDO was move of TAB marker in ruler + if (mbHasRulers) + Invalidate(SID_ATTR_TABSTOP); + } + + // This one is corresponding to the default handling + // of SID_UNDO in sfx2 + GetViewFrame()->GetBindings().InvalidateAll(false); + + rReq.Done(); +} + +void ViewShell::ImpSidRedo(SfxRequest& rReq) +{ + //The xWatcher keeps the SlideSorter selection in sync + //with the page insertions/deletions that Undo may introduce + std::unique_ptr<KeepSlideSorterInSyncWithPageChanges, o3tl::default_delete<KeepSlideSorterInSyncWithPageChanges>> xWatcher; + slidesorter::SlideSorterViewShell* pSlideSorterViewShell + = slidesorter::SlideSorterViewShell::GetSlideSorter(GetViewShellBase()); + if (pSlideSorterViewShell) + xWatcher.reset(new KeepSlideSorterInSyncWithPageChanges(pSlideSorterViewShell->GetSlideSorter())); + + SfxUndoManager* pUndoManager = ImpGetUndoManager(); + sal_uInt16 nNumber(1); + const SfxItemSet* pReqArgs = rReq.GetArgs(); + bool bRepair = false; + + if(pReqArgs) + { + const SfxUInt16Item* pUIntItem = static_cast<const SfxUInt16Item*>(&pReqArgs->Get(SID_REDO)); + nNumber = pUIntItem->GetValue(); + // Repair mode: allow undo/redo of all undo actions, even if access would + // be limited based on the view shell ID. + if (const SfxBoolItem* pRepairItem = pReqArgs->GetItemIfSet(SID_REPAIRPACKAGE, false)) + bRepair = pRepairItem->GetValue(); + } + + if(nNumber && pUndoManager) + { + sal_uInt16 nCount(pUndoManager->GetRedoActionCount()); + if(nCount >= nNumber) + { + if (comphelper::LibreOfficeKit::isActive() && !bRepair) + { + // If another view created the first undo action, prevent redoing it from this view. + const SfxUndoAction* pAction = pUndoManager->GetRedoAction(); + if (pAction->GetViewShellId() != GetViewShellBase().GetViewShellId()) + { + rReq.SetReturnValue(SfxUInt32Item(SID_REDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE))); + return; + } + } + + try + { + // when UndoStack is cleared by ModifyPageRedoAction + // the nCount may have changed, so test GetRedoActionCount() + while(nNumber-- && pUndoManager->GetRedoActionCount()) + pUndoManager->Redo(); + } + catch( const Exception& ) + { + // no need to handle. By definition, the UndoManager handled this by clearing the + // Undo/Redo stacks + } + } + + // refresh rulers, maybe REDO was move of TAB marker in ruler + if (mbHasRulers) + { + Invalidate(SID_ATTR_TABSTOP); + } + } + + // This one is corresponding to the default handling + // of SID_UNDO in sfx2 + GetViewFrame()->GetBindings().InvalidateAll(false); + + rReq.Done(); +} + +void ViewShell::ExecReq( SfxRequest& rReq ) +{ + sal_uInt16 nSlot = rReq.GetSlot(); + switch( nSlot ) + { + case SID_MAIL_SCROLLBODY_PAGEDOWN: + { + rtl::Reference<FuPoor> xFunc( GetCurrentFunction() ); + if( xFunc.is() ) + ScrollLines( 0, -1 ); + + rReq.Done(); + } + break; + + case SID_OUTPUT_QUALITY_COLOR: + case SID_OUTPUT_QUALITY_GRAYSCALE: + case SID_OUTPUT_QUALITY_BLACKWHITE: + case SID_OUTPUT_QUALITY_CONTRAST: + { + DrawModeFlags nMode = OUTPUT_DRAWMODE_COLOR; + + switch( nSlot ) + { + case SID_OUTPUT_QUALITY_COLOR: nMode = OUTPUT_DRAWMODE_COLOR; break; + case SID_OUTPUT_QUALITY_GRAYSCALE: nMode = OUTPUT_DRAWMODE_GRAYSCALE; break; + case SID_OUTPUT_QUALITY_BLACKWHITE: nMode = OUTPUT_DRAWMODE_BLACKWHITE; break; + case SID_OUTPUT_QUALITY_CONTRAST: nMode = OUTPUT_DRAWMODE_CONTRAST; break; + } + + GetActiveWindow()->GetOutDev()->SetDrawMode( nMode ); + mpFrameView->SetDrawMode( nMode ); + + GetActiveWindow()->Invalidate(); + + Invalidate(); + rReq.Done(); + break; + } + } +} + +/** This default implementation returns only an empty reference. See derived + classes for more interesting examples. +*/ +css::uno::Reference<css::accessibility::XAccessible> +ViewShell::CreateAccessibleDocumentView (::sd::Window* ) +{ + OSL_FAIL("ViewShell::CreateAccessibleDocumentView should not be called!, perhaps Meyers, 3rd edition, Item 9:"); + + return css::uno::Reference<css::accessibility::XAccessible> (); +} + +::sd::WindowUpdater* ViewShell::GetWindowUpdater() const +{ + return mpWindowUpdater.get(); +} + +ViewShellBase& ViewShell::GetViewShellBase() const +{ + return *static_cast<ViewShellBase*>(GetViewShell()); +} + +ViewShell::ShellType ViewShell::GetShellType() const +{ + return meShellType; +} + +DrawDocShell* ViewShell::GetDocSh() const +{ + return GetViewShellBase().GetDocShell(); +} + +SdDrawDocument* ViewShell::GetDoc() const +{ + return GetViewShellBase().GetDocument(); +} + +ErrCode ViewShell::DoVerb(sal_Int32 /*nVerb*/) +{ + return ERRCODE_NONE; +} + +void ViewShell::SetCurrentFunction( const rtl::Reference<FuPoor>& xFunction) +{ + if( mxCurrentFunction.is() && (mxOldFunction != mxCurrentFunction) ) + mxCurrentFunction->Dispose(); + rtl::Reference<FuPoor> xDisposeAfterNewOne( mxCurrentFunction ); + mxCurrentFunction = xFunction; +} + +void ViewShell::SetOldFunction(const rtl::Reference<FuPoor>& xFunction) +{ + if( mxOldFunction.is() && (xFunction != mxOldFunction) && (mxCurrentFunction != mxOldFunction) ) + mxOldFunction->Dispose(); + + rtl::Reference<FuPoor> xDisposeAfterNewOne( mxOldFunction ); + mxOldFunction = xFunction; +} + +/** this method deactivates the current function. If an old function is + saved, this will become activated and current function. +*/ +void ViewShell::Cancel() +{ + if(mxCurrentFunction.is() && (mxCurrentFunction != mxOldFunction )) + { + rtl::Reference<FuPoor> xTemp( mxCurrentFunction ); + mxCurrentFunction.clear(); + xTemp->Deactivate(); + xTemp->Dispose(); + } + + if(mxOldFunction.is()) + { + mxCurrentFunction = mxOldFunction; + mxCurrentFunction->Activate(); + } +} + +void ViewShell::DeactivateCurrentFunction( bool bPermanent /* == false */ ) +{ + if( mxCurrentFunction.is() ) + { + if(bPermanent && (mxOldFunction == mxCurrentFunction)) + mxOldFunction.clear(); + + mxCurrentFunction->Deactivate(); + if( mxCurrentFunction != mxOldFunction ) + mxCurrentFunction->Dispose(); + + rtl::Reference<FuPoor> xDisposeAfterNewOne( mxCurrentFunction ); + mxCurrentFunction.clear(); + } +} + +void ViewShell::DisposeFunctions() +{ + if(mxCurrentFunction.is()) + { + rtl::Reference<FuPoor> xTemp( mxCurrentFunction ); + mxCurrentFunction.clear(); + xTemp->Deactivate(); + xTemp->Dispose(); + } + + if(mxOldFunction.is()) + { + rtl::Reference<FuPoor> xDisposeAfterNewOne( mxOldFunction ); + mxOldFunction->Dispose(); + mxOldFunction.clear(); + } +} + +bool ViewShell::IsMainViewShell() const +{ + return mpImpl->mbIsMainViewShell; +} + +void ViewShell::SetIsMainViewShell (bool bIsMainViewShell) +{ + if (bIsMainViewShell != mpImpl->mbIsMainViewShell) + { + mpImpl->mbIsMainViewShell = bIsMainViewShell; + if (bIsMainViewShell) + GetDocSh()->Connect (this); + else + GetDocSh()->Disconnect (this); + } +} + +void ViewShell::PrePaint() +{ +} + +void ViewShell::Paint (const ::tools::Rectangle&, ::sd::Window* ) +{ +} + +void ViewShell::ShowUIControls (bool bVisible) +{ + if (mbHasRulers) + { + if (mpHorizontalRuler) + mpHorizontalRuler->Show( bVisible ); + + if (mpVerticalRuler) + mpVerticalRuler->Show( bVisible ); + } + + if (mpVerticalScrollBar) + mpVerticalScrollBar->Show( bVisible ); + + if (mpHorizontalScrollBar) + mpHorizontalScrollBar->Show( bVisible ); + + if (mpContentWindow) + mpContentWindow->Show( bVisible ); +} + +bool ViewShell::RelocateToParentWindow (vcl::Window* pParentWindow) +{ + mpParentWindow = pParentWindow; + + mpParentWindow->SetBackground (Wallpaper()); + + if (mpContentWindow) + mpContentWindow->SetParent(pParentWindow); + + if (mpHorizontalScrollBar) + mpHorizontalScrollBar->SetParent(mpParentWindow); + if (mpVerticalScrollBar) + mpVerticalScrollBar->SetParent(mpParentWindow); + + return true; +} + +void ViewShell::SwitchViewFireFocus(const css::uno::Reference< css::accessibility::XAccessible >& xAcc ) +{ + if (xAcc) + { + ::accessibility::AccessibleDocumentViewBase* pBase = static_cast< ::accessibility::AccessibleDocumentViewBase* >(xAcc.get()); + if (pBase) + pBase->SwitchViewActivated(); + } +} +void ViewShell::SwitchActiveViewFireFocus() +{ + if (mpContentWindow) + { + SwitchViewFireFocus(mpContentWindow->GetAccessible(false)); + } +} +// move these two methods from DrawViewShell. +void ViewShell::fireSwitchCurrentPage(sal_Int32 pageIndex) +{ + GetViewShellBase().GetDrawController()->fireSwitchCurrentPage(pageIndex); +} +void ViewShell::NotifyAccUpdate( ) +{ + GetViewShellBase().GetDrawController()->NotifyAccUpdate(); +} + +weld::Window* ViewShell::GetFrameWeld() const +{ + return mpActiveWindow ? mpActiveWindow->GetFrameWeld() : nullptr; +} + +sd::Window* ViewShell::GetContentWindow() const +{ + return mpContentWindow.get(); +} + +} // end of namespace sd + +//===== ViewShellObjectBarFactory ============================================= + +namespace { + +ViewShellObjectBarFactory::ViewShellObjectBarFactory ( + ::sd::ViewShell& rViewShell) + : mrViewShell (rViewShell) +{ +} + +SfxShell* ViewShellObjectBarFactory::CreateShell( ::sd::ShellId nId ) +{ + SfxShell* pShell = nullptr; + + ::sd::View* pView = mrViewShell.GetView(); + switch (nId) + { + case ToolbarId::Bezier_Toolbox_Sd: + pShell = new ::sd::BezierObjectBar(&mrViewShell, pView); + break; + + case ToolbarId::Draw_Text_Toolbox_Sd: + pShell = new ::sd::TextObjectBar( + &mrViewShell, mrViewShell.GetDoc()->GetPool(), pView); + break; + + case ToolbarId::Draw_Graf_Toolbox: + pShell = new ::sd::GraphicObjectBar(&mrViewShell, pView); + break; + + case ToolbarId::Draw_Media_Toolbox: + pShell = new ::sd::MediaObjectBar(&mrViewShell, pView); + break; + + case ToolbarId::Draw_Table_Toolbox: + pShell = ::sd::ui::table::CreateTableObjectBar( mrViewShell, pView ); + break; + + case ToolbarId::Svx_Extrusion_Bar: + pShell = new svx::ExtrusionBar( + &mrViewShell.GetViewShellBase()); + break; + + case ToolbarId::Svx_Fontwork_Bar: + pShell = new svx::FontworkBar( + &mrViewShell.GetViewShellBase()); + break; + + default: + pShell = nullptr; + break; + } + + return pShell; +} + +void ViewShellObjectBarFactory::ReleaseShell (SfxShell* pShell) +{ + delete pShell; +} + +} // end of anonymous namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/view/zoomlist.cxx b/sd/source/ui/view/zoomlist.cxx new file mode 100644 index 0000000000..86a3de63bc --- /dev/null +++ b/sd/source/ui/view/zoomlist.cxx @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <zoomlist.hxx> + +#include <svx/svxids.hrc> +#include <sfx2/bindings.hxx> +#include <sfx2/viewfrm.hxx> + +#include <ViewShell.hxx> + +namespace sd +{ +#define MAX_ENTRIES 10 + +ZoomList::ZoomList(ViewShell* pViewShell) + : mpViewShell(pViewShell) + , mnCurPos(0) +{ +} + +void ZoomList::InsertZoomRect(const ::tools::Rectangle& rRect) +{ + size_t nRectCount = maRectangles.size(); + + if (nRectCount >= MAX_ENTRIES) + maRectangles.erase(maRectangles.begin()); + else if (nRectCount == 0) + mnCurPos = 0; + else + mnCurPos++; + + maRectangles.insert(maRectangles.begin() + mnCurPos, rRect); + + SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings(); + rBindings.Invalidate(SID_ZOOM_NEXT); + rBindings.Invalidate(SID_ZOOM_PREV); +} + +::tools::Rectangle const& ZoomList::GetNextZoomRect() +{ + mnCurPos++; + size_t nRectCount = maRectangles.size(); + + if (nRectCount > 0 && mnCurPos > nRectCount - 1) + mnCurPos = nRectCount - 1; + + SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings(); + rBindings.Invalidate(SID_ZOOM_NEXT); + rBindings.Invalidate(SID_ZOOM_PREV); + + return maRectangles[mnCurPos]; +} + +::tools::Rectangle const& ZoomList::GetPreviousZoomRect() +{ + if (mnCurPos > 0) + mnCurPos--; + + SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings(); + rBindings.Invalidate(SID_ZOOM_NEXT); + rBindings.Invalidate(SID_ZOOM_PREV); + + return maRectangles[mnCurPos]; +} + +bool ZoomList::IsNextPossible() const +{ + size_t nRectCount = maRectangles.size(); + + return nRectCount > 0 && mnCurPos < nRectCount - 1; +} + +bool ZoomList::IsPreviousPossible() const { return mnCurPos > 0; } + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |