diff options
25 files changed, 1007 insertions, 0 deletions
diff --git a/include/sfx2/sfxsids.hrc b/include/sfx2/sfxsids.hrc index d9a8b14eb514..e4bf9bbbe71b 100644 --- a/include/sfx2/sfxsids.hrc +++ b/include/sfx2/sfxsids.hrc @@ -447,6 +447,7 @@ class SvxSearchItem; // Used for redaction #define SID_SHAPE_NAME (SID_SFX_START + 808) // FREE: SID_SFX_START + 809 +#define SID_GRAPHIC_SIZE_CHECK (SID_SFX_START + 809) #define SID_ACCESSIBILITY_CHECK (SID_SFX_START + 810) #define SID_ASYNCHRON (SID_SFX_START + 811) diff --git a/include/svx/GenericCheckDialog.hxx b/include/svx/GenericCheckDialog.hxx new file mode 100644 index 000000000000..ef2a41159737 --- /dev/null +++ b/include/svx/GenericCheckDialog.hxx @@ -0,0 +1,83 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <svx/svxdllapi.h> +#include <tools/link.hxx> +#include <vcl/weld.hxx> + +namespace svx +{ +class CheckData +{ +public: + virtual ~CheckData() {} + + virtual OUString getText() = 0; + + virtual bool canMarkObject() = 0; + virtual void markObject() = 0; + + virtual bool hasProperties() = 0; + virtual void runProperties() = 0; +}; + +class CheckDataCollection +{ +protected: + std::vector<std::unique_ptr<CheckData>> m_aCollection; + +public: + virtual ~CheckDataCollection() {} + + std::vector<std::unique_ptr<CheckData>>& getCollection() { return m_aCollection; } + + virtual OUString getTitle() = 0; +}; + +class GenericCheckEntry final +{ +private: + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + std::unique_ptr<weld::Label> m_xLabel; + std::unique_ptr<weld::Button> m_xMarkButton; + std::unique_ptr<weld::Button> m_xPropertiesButton; + + std::unique_ptr<CheckData>& m_pCheckData; + +public: + GenericCheckEntry(weld::Container* pParent, std::unique_ptr<CheckData>& rCheckData); + + weld::Widget* get_widget() const { return m_xContainer.get(); } + + DECL_LINK(MarkButtonClicked, weld::Button&, void); + DECL_LINK(PropertiesButtonClicked, weld::Button&, void); +}; + +class SVX_DLLPUBLIC GenericCheckDialog final : public weld::GenericDialogController +{ +private: + std::vector<std::unique_ptr<GenericCheckEntry>> m_aCheckEntries; + CheckDataCollection& m_rCheckDataCollection; + + // Controls + std::unique_ptr<weld::Box> m_xCheckBox; + +public: + GenericCheckDialog(weld::Window* pParent, CheckDataCollection& rCheckDataCollection); + virtual ~GenericCheckDialog() override; + virtual short run() override; +}; + +} // end svx namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/svx/strings.hrc b/include/svx/strings.hrc index 8505c410a3df..7a5cbba78dbd 100644 --- a/include/svx/strings.hrc +++ b/include/svx/strings.hrc @@ -1803,6 +1803,13 @@ #define RID_SVXSTR_HOR_PRESET_ONLYHOR NC_("RID_SVXSTR_HOR_PRESET_ONLYHOR", "Top and Bottom Borders, and All Inner Lines") #define RID_SVXSTR_VER_PRESET_ONLYVER NC_("RID_SVXSTR_VER_PRESET_ONLYVER", "Left and Right Borders, and All Inner Lines") +/*-------------------------------------------------------------------- + Description: GraphicSizeCheck strings + --------------------------------------------------------------------*/ +#define STR_GRAPHIC_SIZE_CHECK_DIALOG_TITLE NC_("STR_GRAPHIC_SIZE_CHECK_DIALOG_TITLE", "Graphic Size Check") +#define STR_WARNING_GRAPHIC_PIXEL_COUNT_LOW NC_("STR_WARNING_GRAPHIC_PIXEL_COUNT_LOW", "Image '%NAME%' has too few pixels for the current size (%DPIX% x %DPIY% DPI)") +#define STR_WARNING_GRAPHIC_PIXEL_COUNT_HIGH NC_("STR_WARNING_GRAPHIC_PIXEL_COUNT_HIGH", "Image '%NAME%' has too many pixels for the current size (%DPIX% x %DPIY% DPI)") + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu index 2e3bf1f57647..a51ab13d077c 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu @@ -7389,6 +7389,14 @@ bit 3 (0x8): #define UICOMMANDDESCRIPTION_PROPERTIES_TOGGLEBUTTON 8 <value>1</value> </prop> </node> + <node oor:name=".uno:GraphicSizeCheck" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Graphic Size Check...</value> + </prop> + <prop oor:name="Properties" oor:type="xs:int"> + <value>1</value> + </prop> + </node> <node oor:name=".uno:SidebarDeck.PropertyDeck" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">Open the Properties Deck</value> diff --git a/sd/Library_sd.mk b/sd/Library_sd.mk index 092dc70da1ef..8d143aaa6f5f 100644 --- a/sd/Library_sd.mk +++ b/sd/Library_sd.mk @@ -401,6 +401,7 @@ $(eval $(call gb_Library_add_exception_objects,sd,\ sd/source/ui/tools/AsynchronousCall \ sd/source/ui/tools/ConfigurationAccess \ sd/source/ui/tools/EventMultiplexer \ + sd/source/ui/tools/GraphicSizeCheck \ sd/source/ui/tools/IconCache \ sd/source/ui/tools/IdleDetection \ sd/source/ui/tools/PreviewRenderer \ diff --git a/sd/sdi/_drvwsh.sdi b/sd/sdi/_drvwsh.sdi index 7060d8dd6434..73c2181d0743 100644 --- a/sd/sdi/_drvwsh.sdi +++ b/sd/sdi/_drvwsh.sdi @@ -76,6 +76,11 @@ interface DrawView ExecMethod = FuTemporary ; StateMethod = GetMenuState ; ] + SID_GRAPHIC_SIZE_CHECK + [ + ExecMethod = FuTemporary ; + StateMethod = GetMenuState ; + ] SID_EXTERNAL_EDIT [ ExecMethod = FuTemporary ; diff --git a/sd/source/ui/inc/tools/GraphicSizeCheck.hxx b/sd/source/ui/inc/tools/GraphicSizeCheck.hxx new file mode 100644 index 000000000000..9da3d569bd3a --- /dev/null +++ b/sd/source/ui/inc/tools/GraphicSizeCheck.hxx @@ -0,0 +1,103 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <memory> +#include <drawdoc.hxx> +#include <svx/GenericCheckDialog.hxx> +#include <svx/svdograf.hxx> + +namespace sd +{ +class GraphicSizeViolation final +{ +private: + SdrGrafObj* m_pGraphicObject; + + sal_Int32 m_nLowDPILimit = 0; + sal_Int32 m_nHighDPILimit = 0; + + sal_Int32 m_nDPIX = 0; + sal_Int32 m_nDPIY = 0; + +public: + GraphicSizeViolation(sal_Int32 nDPI, SdrGrafObj* pGraphicObject); + bool check(); + + OUString getGraphicName(); + + SdrGrafObj* getObject() const { return m_pGraphicObject; } + + bool isDPITooLow() { return m_nDPIX < m_nLowDPILimit || m_nDPIY < m_nLowDPILimit; } + + bool isDPITooHigh() { return m_nDPIX > m_nHighDPILimit || m_nDPIY > m_nHighDPILimit; } + + sal_Int32 getDPIX() { return m_nDPIX; } + + sal_Int32 getDPIY() { return m_nDPIY; } +}; + +class GraphicSizeCheck final +{ +private: + SdDrawDocument* m_pDocument; + std::vector<std::unique_ptr<GraphicSizeViolation>> m_aGraphicSizeViolationList; + +public: + GraphicSizeCheck(SdDrawDocument* pDocument) + : m_pDocument(pDocument) + { + } + + void check(); + + std::vector<std::unique_ptr<GraphicSizeViolation>>& getViolationList() + { + return m_aGraphicSizeViolationList; + } +}; + +class GraphicSizeCheckGUIEntry : public svx::CheckData +{ +private: + SdDrawDocument* m_pDocument; + std::unique_ptr<GraphicSizeViolation> m_pViolation; + +public: + GraphicSizeCheckGUIEntry(SdDrawDocument* pDocument, + std::unique_ptr<GraphicSizeViolation>&& pViolation) + : m_pDocument(pDocument) + , m_pViolation(std::move(pViolation)) + { + } + + OUString getText() override; + + bool canMarkObject() override { return true; } + + void markObject() override; + + bool hasProperties() override { return true; } + + void runProperties() override; +}; + +class GraphicSizeCheckGUIResult : public svx::CheckDataCollection +{ +public: + GraphicSizeCheckGUIResult(SdDrawDocument* m_pDocument); + + OUString getTitle() override; +}; + +} // end of namespace sd + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/tools/GraphicSizeCheck.cxx b/sd/source/ui/tools/GraphicSizeCheck.cxx new file mode 100644 index 000000000000..14bfcf3353b9 --- /dev/null +++ b/sd/source/ui/tools/GraphicSizeCheck.cxx @@ -0,0 +1,213 @@ +/* -*- 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 <memory> +#include <tools/GraphicSizeCheck.hxx> +#include <svx/strings.hrc> +#include <svx/svdobj.hxx> +#include <svx/svdpage.hxx> +#include <svx/svxids.hrc> +#include <sfx2/dispatch.hxx> + +#include <sdresid.hxx> +#include <DrawViewShell.hxx> +#include <DrawDocShell.hxx> + +namespace sd +{ +namespace +{ +class ModelTraverseHandler +{ +public: + virtual ~ModelTraverseHandler() {} + + virtual void handleSdrObject(SdrObject* pObject) = 0; +}; + +class ModelTraverser +{ +private: + std::vector<std::shared_ptr<ModelTraverseHandler>> m_pNodeHandler; + SdDrawDocument* m_pDocument; + +public: + ModelTraverser(SdDrawDocument* pDocument) + : m_pDocument(pDocument) + { + } + + void traverse() + { + if (!m_pDocument) + return; + + for (sal_uInt16 nPage = 0; nPage < m_pDocument->GetPageCount(); ++nPage) + { + SdrPage* pPage = m_pDocument->GetPage(nPage); + if (pPage) + { + for (size_t nObject = 0; nObject < pPage->GetObjCount(); ++nObject) + { + SdrObject* pObject = pPage->GetObj(nObject); + if (pObject) + { + for (auto& pNodeHandler : m_pNodeHandler) + { + pNodeHandler->handleSdrObject(pObject); + } + } + } + } + } + } + + void addNodeHandler(std::shared_ptr<ModelTraverseHandler> pHandler) + { + m_pNodeHandler.push_back(pHandler); + } +}; +} + +GraphicSizeViolation::GraphicSizeViolation(sal_Int32 nDPI, SdrGrafObj* pGraphicObject) + : m_pGraphicObject(pGraphicObject) +{ + constexpr double fLowPercentage = 110; + constexpr double fHighPercentage = 50; + + m_nLowDPILimit = sal_Int32(100.0 / fLowPercentage * nDPI); + m_nHighDPILimit = sal_Int32(100.0 / fHighPercentage * nDPI); +} + +bool GraphicSizeViolation::check() +{ + Graphic aGraphic = m_pGraphicObject->GetGraphic(); + Size aSizePixel = aGraphic.GetSizePixel(); + Size aGraphicSize = m_pGraphicObject->GetLogicRect().GetSize(); + + double nSizeXInch + = o3tl::convert(double(aGraphicSize.Width()), o3tl::Length::mm100, o3tl::Length::in); + double nSizeYInch + = o3tl::convert(double(aGraphicSize.Height()), o3tl::Length::mm100, o3tl::Length::in); + + m_nDPIX = sal_Int32(aSizePixel.Width() / nSizeXInch); + m_nDPIY = sal_Int32(aSizePixel.Height() / nSizeYInch); + + return isDPITooLow() || isDPITooHigh(); +} + +OUString GraphicSizeViolation::getGraphicName() { return m_pGraphicObject->GetName(); } + +namespace +{ +class GraphicSizeCheckHandler : public ModelTraverseHandler +{ + sal_Int32 m_nDPI; + std::vector<std::unique_ptr<GraphicSizeViolation>>& m_rGraphicSizeViolationList; + +public: + GraphicSizeCheckHandler( + sal_Int32 nDPI, + std::vector<std::unique_ptr<GraphicSizeViolation>>& rGraphicSizeViolationList) + : m_nDPI(nDPI) + , m_rGraphicSizeViolationList(rGraphicSizeViolationList) + { + } + + void handleSdrObject(SdrObject* pObject) override + { + auto* pGraphicObject = dynamic_cast<SdrGrafObj*>(pObject); + if (!pGraphicObject) + return; + + auto pEntry = std::make_unique<GraphicSizeViolation>(m_nDPI, pGraphicObject); + if (pEntry->check()) + { + m_rGraphicSizeViolationList.push_back(std::move(pEntry)); + } + } +}; + +} // end anonymous namespace + +void GraphicSizeCheck::check() +{ + if (!m_pDocument) + return; + + sal_Int32 nDPI = m_pDocument->getImagePreferredDPI(); + if (nDPI == 0) + return; + + auto pHandler = std::make_shared<GraphicSizeCheckHandler>(nDPI, m_aGraphicSizeViolationList); + + ModelTraverser aModelTraverser(m_pDocument); + aModelTraverser.addNodeHandler(pHandler); + aModelTraverser.traverse(); +} + +OUString GraphicSizeCheckGUIEntry::getText() +{ + OUString sText; + + if (m_pViolation->isDPITooLow()) + { + sText = SdResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_LOW); + } + else if (m_pViolation->isDPITooHigh()) + { + sText = SdResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_HIGH); + } + + sText = sText.replaceAll("%NAME%", m_pViolation->getGraphicName()); + sText = sText.replaceAll("%DPIX%", OUString::number(m_pViolation->getDPIX())); + sText = sText.replaceAll("%DPIY%", OUString::number(m_pViolation->getDPIY())); + + return sText; +} + +void GraphicSizeCheckGUIEntry::markObject() +{ + sd::ViewShell* pViewShell = m_pDocument->GetDocSh()->GetViewShell(); + SdrView* pView = pViewShell->GetView(); + pView->ShowSdrPage(m_pViolation->getObject()->getSdrPageFromSdrObject()); + pView->UnmarkAll(); + pView->MarkObj(m_pViolation->getObject(), pView->GetSdrPageView()); +} + +void GraphicSizeCheckGUIEntry::runProperties() +{ + markObject(); + sd::ViewShell* pViewShell = m_pDocument->GetDocSh()->GetViewShell(); + pViewShell->GetDispatcher()->Execute(SID_ATTR_GRAF_CROP, SfxCallMode::SYNCHRON); +} + +GraphicSizeCheckGUIResult::GraphicSizeCheckGUIResult(SdDrawDocument* pDocument) +{ + GraphicSizeCheck aCheck(pDocument); + aCheck.check(); + + auto& rCollection = getCollection(); + for (auto& rpViolation : aCheck.getViolationList()) + { + auto rGUIEntry + = std::make_unique<GraphicSizeCheckGUIEntry>(pDocument, std::move(rpViolation)); + rCollection.push_back(std::move(rGUIEntry)); + } +} + +OUString GraphicSizeCheckGUIResult::getTitle() +{ + return SdResId(STR_GRAPHIC_SIZE_CHECK_DIALOG_TITLE); +} + +} // 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 index b951231f2c5b..87d1a34e2ebe 100644 --- a/sd/source/ui/view/drviews2.cxx +++ b/sd/source/ui/view/drviews2.cxx @@ -183,6 +183,7 @@ #include <SlideSorterViewShell.hxx> #include <controller/SlideSorterController.hxx> #include <controller/SlsPageSelector.hxx> +#include <tools/GraphicSizeCheck.hxx> #include <ViewShellBase.hxx> #include <memory> @@ -1462,6 +1463,17 @@ void DrawViewShell::FuTemporary(SfxRequest& rReq) } 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 ) ); diff --git a/sd/source/ui/view/drviewsj.cxx b/sd/source/ui/view/drviewsj.cxx index 9eebdbc57c29..6bbf88338f06 100644 --- a/sd/source/ui/view/drviewsj.cxx +++ b/sd/source/ui/view/drviewsj.cxx @@ -539,6 +539,10 @@ void DrawViewShell::GetMenuStateSel( SfxItemSet &rSet ) rSet.DisableItem(SID_SAVE_GRAPHIC); rSet.DisableItem(SID_EXTERNAL_EDIT); } + if (GetDoc()->getImagePreferredDPI() <= 0) + { + rSet.DisableItem(SID_GRAPHIC_SIZE_CHECK); + } } } // end of namespace sd diff --git a/sd/uiconfig/sdraw/menubar/menubar.xml b/sd/uiconfig/sdraw/menubar/menubar.xml index 7c8969967b0f..27f7493ce84d 100644 --- a/sd/uiconfig/sdraw/menubar/menubar.xml +++ b/sd/uiconfig/sdraw/menubar/menubar.xml @@ -417,6 +417,7 @@ <menu:menuitem menu:id=".uno:ColorSettings"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:GrafAttrCrop"/> + <menu:menuitem menu:id=".uno:GraphicSizeCheck"/> </menu:menupopup> </menu:menu> <menu:menuseparator/> diff --git a/sd/uiconfig/simpress/menubar/menubar.xml b/sd/uiconfig/simpress/menubar/menubar.xml index e0f328065ac8..8767a6331ed0 100644 --- a/sd/uiconfig/simpress/menubar/menubar.xml +++ b/sd/uiconfig/simpress/menubar/menubar.xml @@ -448,6 +448,7 @@ <menu:menuitem menu:id=".uno:ColorSettings"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:GrafAttrCrop"/> + <menu:menuitem menu:id=".uno:GraphicSizeCheck"/> </menu:menupopup> </menu:menu> <menu:menu menu:id=".uno:FormatObjectMenu"> diff --git a/svx/Library_svx.mk b/svx/Library_svx.mk index 2a9d9d097127..3a54b129ebb9 100644 --- a/svx/Library_svx.mk +++ b/svx/Library_svx.mk @@ -105,6 +105,7 @@ $(eval $(call gb_Library_add_exception_objects,svx,\ svx/source/customshapes/EnhancedCustomShapeFontWork \ svx/source/customshapes/EnhancedCustomShapeHandle \ svx/source/dialog/AccessibilityCheckDialog \ + svx/source/dialog/GenericCheckDialog \ svx/source/dialog/_bmpmask \ svx/source/dialog/charmap \ svx/source/dialog/searchcharmap \ diff --git a/svx/UIConfig_svx.mk b/svx/UIConfig_svx.mk index 2186185f10c2..33bc1797f20f 100644 --- a/svx/UIConfig_svx.mk +++ b/svx/UIConfig_svx.mk @@ -78,6 +78,8 @@ $(eval $(call gb_UIConfig_add_uifiles,svx,\ svx/uiconfig/ui/functionmenu \ svx/uiconfig/ui/gallerymenu1 \ svx/uiconfig/ui/gallerymenu2 \ + svx/uiconfig/ui/genericcheckdialog \ + svx/uiconfig/ui/genericcheckentry \ svx/uiconfig/ui/grafctrlbox \ svx/uiconfig/ui/grafmodebox \ svx/uiconfig/ui/headfootformatpage \ diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi index 1e08145d3644..f0314fe63360 100644 --- a/svx/sdi/svx.sdi +++ b/svx/sdi/svx.sdi @@ -12425,6 +12425,23 @@ SfxVoidItem SpellCheckApplySuggestion SID_SPELLCHECK_APPLY_SUGGESTION GroupId = SfxGroupId::Format; ] +SfxVoidItem GraphicSizeCheck SID_GRAPHIC_SIZE_CHECK +() +[ + AutoUpdate = FALSE, + FastCall = FALSE, + ReadOnlyDoc = TRUE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = FALSE, + MenuConfig = FALSE, + ToolBoxConfig = FALSE, + GroupId = SfxGroupId::Modify; +] + SfxVoidItem AccessibilityCheck SID_ACCESSIBILITY_CHECK () [ diff --git a/svx/source/dialog/GenericCheckDialog.cxx b/svx/source/dialog/GenericCheckDialog.cxx new file mode 100644 index 000000000000..09fc3d678769 --- /dev/null +++ b/svx/source/dialog/GenericCheckDialog.cxx @@ -0,0 +1,70 @@ +/* -*- 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 <svx/GenericCheckDialog.hxx> +#include <vcl/svapp.hxx> + +namespace svx +{ +GenericCheckEntry::GenericCheckEntry(weld::Container* pParent, + std::unique_ptr<CheckData>& pCheckData) + : m_xBuilder(Application::CreateBuilder(pParent, "svx/ui/genericcheckentry.ui")) + , m_xContainer(m_xBuilder->weld_container("checkEntryBox")) + , m_xLabel(m_xBuilder->weld_label("label")) + , m_xMarkButton(m_xBuilder->weld_button("markButton")) + , m_xPropertiesButton(m_xBuilder->weld_button("propertiesButton")) + , m_pCheckData(pCheckData) +{ + m_xLabel->set_label(m_pCheckData->getText()); + m_xMarkButton->set_visible(m_pCheckData->canMarkObject()); + m_xMarkButton->connect_clicked(LINK(this, GenericCheckEntry, MarkButtonClicked)); + m_xPropertiesButton->set_visible(m_pCheckData->hasProperties()); + m_xPropertiesButton->connect_clicked(LINK(this, GenericCheckEntry, PropertiesButtonClicked)); + + m_xContainer->show(); +} + +IMPL_LINK_NOARG(GenericCheckEntry, MarkButtonClicked, weld::Button&, void) +{ + m_pCheckData->markObject(); +} + +IMPL_LINK_NOARG(GenericCheckEntry, PropertiesButtonClicked, weld::Button&, void) +{ + m_pCheckData->runProperties(); +} + +GenericCheckDialog::GenericCheckDialog(weld::Window* pParent, + CheckDataCollection& rCheckDataCollection) + : GenericDialogController(pParent, "svx/ui/genericcheckdialog.ui", "GenericCheckDialog") + , m_rCheckDataCollection(rCheckDataCollection) + , m_xCheckBox(m_xBuilder->weld_box("checkBox")) +{ + set_title(m_rCheckDataCollection.getTitle()); +} + +GenericCheckDialog::~GenericCheckDialog() {} + +short GenericCheckDialog::run() +{ + sal_Int32 i = 0; + + for (std::unique_ptr<CheckData>& pCheckData : m_rCheckDataCollection.getCollection()) + { + auto xEntry = std::make_unique<GenericCheckEntry>(m_xCheckBox.get(), pCheckData); + m_xCheckBox->reorder_child(xEntry->get_widget(), i++); + m_aCheckEntries.push_back(std::move(xEntry)); + } + return GenericDialogController::run(); +} + +} // end svx namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/uiconfig/ui/genericcheckdialog.ui b/svx/uiconfig/ui/genericcheckdialog.ui new file mode 100644 index 000000000000..232221c0a878 --- /dev/null +++ b/svx/uiconfig/ui/genericcheckdialog.ui @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 --> +<interface domain="svx"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkDialog" id="GenericCheckDialog"> + <property name="width-request">850</property> + <property name="height-request">480</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="border-width">6</property> + <property name="modal">True</property> + <property name="type-hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialogBox1"> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialogButtons"> + <property name="can-focus">False</property> + <property name="layout-style">end</property> + <child> + <object class="GtkButton" id="ok"> + <property name="label" translatable="yes" context="stock">_OK</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="can-default">True</property> + <property name="has-default">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="cancel"> + <property name="label" translatable="yes" context="stock">_Cancel</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow-type">in</property> + <child> + <object class="GtkViewport"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <child> + <object class="GtkBox" id="checkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-5">ok</action-widget> + <action-widget response="-6">cancel</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + </object> +</interface> diff --git a/svx/uiconfig/ui/genericcheckentry.ui b/svx/uiconfig/ui/genericcheckentry.ui new file mode 100644 index 000000000000..1b02ca13eeac --- /dev/null +++ b/svx/uiconfig/ui/genericcheckentry.ui @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 --> +<interface domain="svx"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkBox" id="checkEntryBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="border-width">3</property> + <property name="spacing">6</property> + <child> + <object class="GtkLabel" id="label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="selectable">True</property> + <property name="xalign">0</property> + <child internal-child="accessible"> + <object class="AtkObject" id="label-atkobject"> + <property name="AtkObject::accessible-role">static</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="markButton"> + <property name="label" translatable="yes" context="genericcheckentry|markButton">Mark</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="propertiesButton"> + <property name="label" translatable="yes" context="genericcheckentry|propertiesButton">Properties</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </object> +</interface> diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk index 87018ce438b9..70385f964c9b 100644 --- a/sw/Library_sw.mk +++ b/sw/Library_sw.mk @@ -312,6 +312,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\ sw/source/core/frmedt/tblsel \ sw/source/core/graphic/grfatr \ sw/source/core/graphic/ndgrf \ + sw/source/core/graphic/GraphicSizeCheck \ sw/source/core/layout/anchoreddrawobject \ sw/source/core/layout/anchoredobject \ sw/source/core/layout/atrfrm \ diff --git a/sw/sdi/_basesh.sdi b/sw/sdi/_basesh.sdi index 44d6c5338e18..dd195496d1a8 100644 --- a/sw/sdi/_basesh.sdi +++ b/sw/sdi/_basesh.sdi @@ -605,4 +605,11 @@ interface BaseTextSelection ExecMethod = ExecDlg; DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; ] + + SID_GRAPHIC_SIZE_CHECK + [ + ExecMethod = ExecDlg; + StateMethod = GetState; + DisableFlags="SfxDisableFlags::SwOnProtectedCursor"; + ] } diff --git a/sw/source/core/graphic/GraphicSizeCheck.cxx b/sw/source/core/graphic/GraphicSizeCheck.cxx new file mode 100644 index 000000000000..50b1cb70a8f2 --- /dev/null +++ b/sw/source/core/graphic/GraphicSizeCheck.cxx @@ -0,0 +1,164 @@ +/* -*- 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 <GraphicSizeCheck.hxx> +#include <svx/strings.hrc> +#include <svx/svdobj.hxx> +#include <unotools/viewoptions.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> + +#include <ModelTraverser.hxx> +#include <ndgrf.hxx> +#include <IDocumentSettingAccess.hxx> +#include <fmtfsize.hxx> +#include <wrtsh.hxx> +#include <wview.hxx> +#include <cmdid.h> + +using namespace css; + +namespace sw +{ +GraphicSizeViolation::GraphicSizeViolation(sal_Int32 nDPI, const SwGrfNode* pGraphicNode) + : m_pGraphicNode(pGraphicNode) +{ + constexpr double fLowPercentage = 110; + constexpr double fHighPercentage = 50; + + m_nLowDPILimit = sal_Int32(100.0 / fLowPercentage * nDPI); + m_nHighDPILimit = sal_Int32(100.0 / fHighPercentage * nDPI); +} + +bool GraphicSizeViolation::check() +{ + auto pFrameFormat = m_pGraphicNode->GetFlyFormat(); + Graphic aGraphic = m_pGraphicNode->GetGraphic(); + Size aSizePixel = aGraphic.GetSizePixel(); + Size aFrameSize(pFrameFormat->GetFrameSize().GetSize()); + + double nSizeXInch + = o3tl::convert(double(aFrameSize.Width()), o3tl::Length::twip, o3tl::Length::in); + double nSizeYInch + = o3tl::convert(double(aFrameSize.Height()), o3tl::Length::twip, o3tl::Length::in); + + m_nDPIX = sal_Int32(aSizePixel.Width() / nSizeXInch); + m_nDPIY = sal_Int32(aSizePixel.Height() / nSizeYInch); + + return isDPITooLow() || isDPITooHigh(); +} + +OUString GraphicSizeViolation::getGraphicName() +{ + return m_pGraphicNode->GetFlyFormat()->GetName(); +} + +namespace +{ +class GraphicSizeCheckHandler : public ModelTraverseHandler +{ +private: + sal_Int32 m_nDPI; + std::vector<std::unique_ptr<GraphicSizeViolation>>& m_rGraphicSizeViolationList; + +public: + GraphicSizeCheckHandler( + sal_Int32 nDPI, + std::vector<std::unique_ptr<GraphicSizeViolation>>& rGraphicSizeViolationList) + : m_nDPI(nDPI) + , m_rGraphicSizeViolationList(rGraphicSizeViolationList) + { + } + + void handleNode(SwNode* pNode) override + { + if (!pNode->IsGrfNode()) + return; + + auto pEntry = std::make_unique<GraphicSizeViolation>(m_nDPI, pNode->GetGrfNode()); + if (pEntry->check()) + { + m_rGraphicSizeViolationList.push_back(std::move(pEntry)); + } + } + + void handleSdrObject(SdrObject* /*pObject*/) override {} +}; + +} // end anonymous namespace + +void GraphicSizeCheck::check() +{ + sal_Int32 nDPI = m_pDocument->getIDocumentSettingAccess().getImagePreferredDPI(); + if (nDPI == 0) + return; + + auto pHandler = std::make_shared<GraphicSizeCheckHandler>(nDPI, m_aGraphicSizeViolationList); + ModelTraverser aModelTraverser(m_pDocument); + aModelTraverser.addNodeHandler(pHandler); + aModelTraverser.traverse(); +} + +OUString GraphicSizeCheckGUIEntry::getText() +{ + OUString sText; + + if (m_pViolation->isDPITooLow()) + { + sText = SwResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_LOW); + } + else if (m_pViolation->isDPITooHigh()) + { + sText = SwResId(STR_WARNING_GRAPHIC_PIXEL_COUNT_HIGH); + } + + sText = sText.replaceAll("%NAME%", m_pViolation->getGraphicName()); + sText = sText.replaceAll("%DPIX%", OUString::number(m_pViolation->getDPIX())); + sText = sText.replaceAll("%DPIY%", OUString::number(m_pViolation->getDPIY())); + + return sText; +} + +void GraphicSizeCheckGUIEntry::markObject() +{ + SwWrtShell* pWrtShell = m_pDocument->GetDocShell()->GetWrtShell(); + pWrtShell->GotoFly(m_pViolation->getGraphicName(), FLYCNTTYPE_ALL, true); +} + +void GraphicSizeCheckGUIEntry::runProperties() +{ + markObject(); + SwWrtShell* pWrtShell = m_pDocument->GetDocShell()->GetWrtShell(); + pWrtShell->GetView().GetViewFrame()->GetDispatcher()->Execute(FN_FORMAT_GRAFIC_DLG, + SfxCallMode::SYNCHRON); +} + +GraphicSizeCheckGUIResult::GraphicSizeCheckGUIResult(SwDoc* pDocument) +{ + GraphicSizeCheck aCheck(pDocument); + aCheck.check(); + + auto& rCollection = getCollection(); + for (auto& rpViolation : aCheck.getViolationList()) + { + auto rGUIEntry + = std::make_unique<GraphicSizeCheckGUIEntry>(pDocument, std::move(rpViolation)); + rCollection.push_back(std::move(rGUIEntry)); + } +} + +OUString GraphicSizeCheckGUIResult::getTitle() +{ + return SwResId(STR_GRAPHIC_SIZE_CHECK_DIALOG_TITLE); +} + +} // end sw namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/GraphicSizeCheck.hxx b/sw/source/core/inc/GraphicSizeCheck.hxx new file mode 100644 index 000000000000..f708b0a5f4dc --- /dev/null +++ b/sw/source/core/inc/GraphicSizeCheck.hxx @@ -0,0 +1,99 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <doc.hxx> +#include "ModelTraverser.hxx" +#include <svx/GenericCheckDialog.hxx> + +namespace sw +{ +class GraphicSizeViolation final +{ +private: + const SwGrfNode* m_pGraphicNode; + + sal_Int32 m_nLowDPILimit = 0; + sal_Int32 m_nHighDPILimit = 0; + + sal_Int32 m_nDPIX = 0; + sal_Int32 m_nDPIY = 0; + +public: + GraphicSizeViolation(sal_Int32 nDPI, const SwGrfNode* pGraphicNode); + bool check(); + + OUString getGraphicName(); + + bool isDPITooLow() { return m_nDPIX < m_nLowDPILimit || m_nDPIY < m_nLowDPILimit; } + + bool isDPITooHigh() { return m_nDPIX > m_nHighDPILimit || m_nDPIY > m_nHighDPILimit; } + + sal_Int32 getDPIX() { return m_nDPIX; } + + sal_Int32 getDPIY() { return m_nDPIY; } +}; + +class GraphicSizeCheck final +{ +private: + SwDoc* m_pDocument; + std::vector<std::unique_ptr<GraphicSizeViolation>> m_aGraphicSizeViolationList; + +public: + GraphicSizeCheck(SwDoc* pDocument) + : m_pDocument(pDocument) + { + } + + void check(); + + std::vector<std::unique_ptr<GraphicSizeViolation>>& getViolationList() + { + return m_aGraphicSizeViolationList; + } +}; + +class GraphicSizeCheckGUIEntry : public svx::CheckData +{ +private: + SwDoc* m_pDocument; + std::unique_ptr<GraphicSizeViolation> m_pViolation; + +public: + GraphicSizeCheckGUIEntry(SwDoc* pDocument, std::unique_ptr<GraphicSizeViolation>&& pViolation) + : m_pDocument(pDocument) + , m_pViolation(std::move(pViolation)) + { + } + + OUString getText() override; + + bool canMarkObject() override { return true; } + + void markObject() override; + + bool hasProperties() override { return true; } + + void runProperties() override; +}; + +class GraphicSizeCheckGUIResult : public svx::CheckDataCollection +{ +public: + GraphicSizeCheckGUIResult(SwDoc* pDocument); + + OUString getTitle() override; +}; + +} // end sw namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx index 40c12473759f..418c77d36403 100644 --- a/sw/source/uibase/shells/basesh.cxx +++ b/sw/source/uibase/shells/basesh.cxx @@ -85,6 +85,7 @@ #include <modcfg.hxx> #include <svx/fmshell.hxx> #include <SwRewriter.hxx> +#include <GraphicSizeCheck.hxx> #include <svx/galleryitem.hxx> #include <sfx2/devtools/DevelopmentToolChildWindow.hxx> #include <com/sun/star/gallery/GalleryItemType.hpp> @@ -1962,6 +1963,13 @@ void SwBaseShell::GetState( SfxItemSet &rSet ) else rSet.Put( SfxVisibilityItem( nWhich, false ) ); break; + case SID_GRAPHIC_SIZE_CHECK: + { + sal_Int32 nDPI = rSh.GetDoc()->getIDocumentSettingAccess().getImagePreferredDPI(); + if (nDPI <= 0) + rSet.DisableItem(nWhich); + } + break; } nWhich = aIter.NextWhich(); } @@ -2784,6 +2792,15 @@ void SwBaseShell::ExecDlg(SfxRequest &rReq) aDialog.run(); } break; + + case SID_GRAPHIC_SIZE_CHECK: + { + sw::GraphicSizeCheckGUIResult aResult(rSh.GetDoc()); + svx::GenericCheckDialog aDialog(pMDI, aResult); + aDialog.run(); + } + break; + default:OSL_FAIL("wrong Dispatcher (basesh.cxx)"); } if(!bDone) diff --git a/sw/uiconfig/sglobal/menubar/menubar.xml b/sw/uiconfig/sglobal/menubar/menubar.xml index f4ee1b00f9f4..38f6708c1a55 100644 --- a/sw/uiconfig/sglobal/menubar/menubar.xml +++ b/sw/uiconfig/sglobal/menubar/menubar.xml @@ -479,6 +479,7 @@ <menu:menuitem menu:id=".uno:ColorSettings"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:GraphicDialog"/> + <menu:menuitem menu:id=".uno:GraphicSizeCheck"/> </menu:menupopup> </menu:menu> <menu:menu menu:id=".uno:FormatObjectMenu"> diff --git a/sw/uiconfig/swriter/menubar/menubar.xml b/sw/uiconfig/swriter/menubar/menubar.xml index 8c751acf9fdb..e6dc87371c22 100644 --- a/sw/uiconfig/swriter/menubar/menubar.xml +++ b/sw/uiconfig/swriter/menubar/menubar.xml @@ -490,6 +490,7 @@ <menu:menuitem menu:id=".uno:ColorSettings"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:GraphicDialog"/> + <menu:menuitem menu:id=".uno:GraphicSizeCheck"/> </menu:menupopup> </menu:menu> <menu:menu menu:id=".uno:FormatObjectMenu"> |