diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk index 735b357c26b3..d0cb6cf2cc08 100644 --- a/cui/Library_cui.mk +++ b/cui/Library_cui.mk @@ -219,6 +219,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\ cui/source/tabpages/textanim \ cui/source/tabpages/textattr \ cui/source/tabpages/TextColumnsPage \ + cui/source/tabpages/themepage \ cui/source/tabpages/tparea \ cui/source/tabpages/tpbitmap \ cui/source/tabpages/tpcolor \ diff --git a/cui/Module_cui.mk b/cui/Module_cui.mk index e4ff28c8fabe..53492ef291a4 100644 --- a/cui/Module_cui.mk +++ b/cui/Module_cui.mk @@ -29,6 +29,7 @@ $(eval $(call gb_Module_add_screenshot_targets,cui,\ $(eval $(call gb_Module_add_uicheck_targets,cui,\ UITest_cui_dialogs \ + UITest_cui_tabpages \ )) # vim: set noet sw=4 ts=4: diff --git a/cui/UIConfig_cui.mk b/cui/UIConfig_cui.mk index daa8a1e3d55d..25fda742ab60 100644 --- a/cui/UIConfig_cui.mk +++ b/cui/UIConfig_cui.mk @@ -212,6 +212,7 @@ $(eval $(call gb_UIConfig_add_uifiles,cui,\ cui/uiconfig/ui/textcolumnstabpage \ cui/uiconfig/ui/textdialog \ cui/uiconfig/ui/textflowpage \ + cui/uiconfig/ui/themetabpage \ cui/uiconfig/ui/thesaurus \ cui/uiconfig/ui/toolbarmodedialog \ cui/uiconfig/ui/transparencytabpage \ diff --git a/cui/UITest_cui_tabpages.mk b/cui/UITest_cui_tabpages.mk new file mode 100644 index 000000000000..4458e9859e23 --- /dev/null +++ b/cui/UITest_cui_tabpages.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_UITest_UITest,cui_tabpages)) + +$(eval $(call gb_UITest_add_modules,cui_tabpages,$(SRCDIR)/cui/qa/uitest,\ + tabpages/ \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cui/qa/uitest/tabpages/themepage.py b/cui/qa/uitest/tabpages/themepage.py new file mode 100644 index 000000000000..eb97205d19ab --- /dev/null +++ b/cui/qa/uitest/tabpages/themepage.py @@ -0,0 +1,47 @@ +# +# 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/. +# + +from libreoffice.uno.propertyvalue import convert_property_values_to_dict +from libreoffice.uno.propertyvalue import mkPropertyValues +from uitest.framework import UITestCase +from uitest.uihelper.common import get_state_as_dict +from uitest.uihelper.common import select_pos + +# Test for cui/source/tabpages/themepage.cxx. +class Test(UITestCase): + + def testThemePage(self): + # Given an Impress document with a master page that has a theme: + with self.ui_test.create_doc_in_start_center("impress") as component: + template = self.xUITest.getTopFocusWindow() + self.ui_test.close_dialog_through_button(template.getChild("close")) + doc = self.xUITest.getTopFocusWindow() + editWin = doc.getChild("impress_win") + drawPage = component.getDrawPages().getByIndex(0) + master = drawPage.MasterPage + theme = mkPropertyValues({ + "Name": "nameA" + }) + master.Theme = theme + + # When changing the name of the theme: + self.xUITest.executeCommand(".uno:SlideMasterPage") + with self.ui_test.execute_dialog_through_command(".uno:PageSetup") as xDialog: + xTabs = xDialog.getChild("tabcontrol") + # Select RID_SVXPAGE_THEME. + select_pos(xTabs, "3") + themeName = xDialog.getChild("themeName") + themeName.executeAction("TYPE", mkPropertyValues({"TEXT": "nameB"})) + + # Then make sure the doc model is updated accordingly: + # Without the accompanying fix in place, this test would have failed with: + # AssertionError: 'nameA' != 'nameB' + # i.e. the UI didn't update the theme name. + theme = convert_property_values_to_dict(master.Theme) + self.assertEqual(theme["Name"], "nameB") + + +# vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/cui/source/factory/dlgfact.cxx b/cui/source/factory/dlgfact.cxx index bd3130fd0fc7..560548e8066b 100644 --- a/cui/source/factory/dlgfact.cxx +++ b/cui/source/factory/dlgfact.cxx @@ -92,6 +92,7 @@ #include #include #include +#include using namespace ::com::sun::star; using namespace ::com::sun::star::frame; @@ -1289,6 +1290,8 @@ CreateTabPage AbstractDialogFactory_Impl::GetTabPageCreatorFunc( sal_uInt16 nId return SfxMacroTabPage::Create; case RID_SVXPAGE_TEXTCOLUMNS: return SvxTextColumnsPage::Create; + case RID_SVXPAGE_THEME: + return SvxThemePage::Create; default: break; } @@ -1354,6 +1357,8 @@ GetTabPageRanges AbstractDialogFactory_Impl::GetTabPageRangesFunc( sal_uInt16 nI return SvxAsianLayoutPage::GetRanges; case RID_SVXPAGE_TEXTCOLUMNS: return SvxTextColumnsPage::GetRanges; + case RID_SVXPAGE_THEME: + return SvxThemePage::GetRanges; default: break; } diff --git a/cui/source/inc/themepage.hxx b/cui/source/inc/themepage.hxx new file mode 100644 index 000000000000..6596cd227244 --- /dev/null +++ b/cui/source/inc/themepage.hxx @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 + +#include + +#include + +/// Tab page for themes +class SvxThemePage : public SfxTabPage +{ + static const WhichRangesContainer m_pRanges; + + std::unique_ptr m_xThemeName; + +public: + SvxThemePage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + virtual ~SvxThemePage() override; + + static std::unique_ptr + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet*); + static WhichRangesContainer GetRanges() { return m_pRanges; } + + virtual bool FillItemSet(SfxItemSet*) override; + virtual void Reset(const SfxItemSet*) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/cui/source/tabpages/themepage.cxx b/cui/source/tabpages/themepage.cxx new file mode 100644 index 000000000000..4c2cd18716b9 --- /dev/null +++ b/cui/source/tabpages/themepage.cxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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 + +#include + +#include +#include +#include +#include + +#include + +using namespace com::sun::star; + +const WhichRangesContainer + SvxThemePage::m_pRanges(svl::Items); + +SvxThemePage::SvxThemePage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "cui/ui/themetabpage.ui", "ThemePage", &rInAttrs) + , m_xThemeName(m_xBuilder->weld_entry("themeName")) +{ +} + +SvxThemePage::~SvxThemePage() = default; + +void SvxThemePage::Reset(const SfxItemSet* pAttrs) +{ + const SfxPoolItem* pItem = nullptr; + if (!pAttrs->HasItem(SID_ATTR_CHAR_GRABBAG, &pItem)) + { + SAL_WARN("cui.tabpages", "SvxThemePage::Reset: no SfxGrabBagItem"); + return; + } + + const auto& rGrabBagItem = static_cast(*pItem); + auto itTheme = rGrabBagItem.GetGrabBag().find("Theme"); + if (itTheme == rGrabBagItem.GetGrabBag().end()) + { + SAL_WARN("cui.tabpages", "SvxThemePage::Reset: no Theme"); + return; + } + + comphelper::SequenceAsHashMap aMap(itTheme->second); + auto it = aMap.find("Name"); + if (it != aMap.end()) + { + OUString aName; + it->second >>= aName; + m_xThemeName->set_text(aName); + } +} + +bool SvxThemePage::FillItemSet(SfxItemSet* pAttrs) +{ + const SfxItemSet& rOldSet = GetItemSet(); + + if (rOldSet.HasItem(SID_ATTR_CHAR_GRABBAG)) + { + SfxGrabBagItem aGrabBagItem( + static_cast(rOldSet.Get(SID_ATTR_CHAR_GRABBAG))); + + comphelper::SequenceAsHashMap aMap; + auto it = aGrabBagItem.GetGrabBag().find("Theme"); + if (it != aGrabBagItem.GetGrabBag().end()) + { + aMap << it->second; + } + + aMap["Name"] <<= m_xThemeName->get_text(); + + beans::PropertyValues aTheme = aMap.getAsConstPropertyValueList(); + aGrabBagItem.GetGrabBag()["Theme"] <<= aTheme; + pAttrs->Put(aGrabBagItem); + } + + return true; +} + +std::unique_ptr SvxThemePage::Create(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet* rAttrs) +{ + return std::make_unique(pPage, pController, *rAttrs); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/cui/uiconfig/ui/themetabpage.ui b/cui/uiconfig/ui/themetabpage.ui new file mode 100644 index 000000000000..c94c6093958b --- /dev/null +++ b/cui/uiconfig/ui/themetabpage.ui @@ -0,0 +1,72 @@ + + + + + + True + False + 6 + vertical + 12 + + + True + False + 0 + none + + + True + False + 6 + 6 + 3 + 6 + + + True + False + Name: + + + + + + 0 + 0 + + + + + True + True + + + + + + 1 + 0 + + + + + + + True + False + General + + + + + + + + False + True + 0 + + + + diff --git a/include/svx/dialogs.hrc b/include/svx/dialogs.hrc index f03600a74fe0..d3d7f6d8b17d 100644 --- a/include/svx/dialogs.hrc +++ b/include/svx/dialogs.hrc @@ -43,6 +43,7 @@ #define RID_SVXPAGE_BKG (RID_SVX_START + 57) #define RID_SVXPAGE_SHADOW (RID_SVX_START + 61) #define RID_SVXPAGE_TRANSPARENCE (RID_SVX_START + 54) +#define RID_SVXPAGE_THEME (RID_SVX_START + 55) #define RID_SVXPAGE_TEXTATTR (RID_SVX_START + 153) #define RID_SVXPAGE_TEXTANIMATION (RID_SVX_START + 184) #define RID_SVXPAGE_TEXTCOLUMNS (RID_SVX_START + 154) diff --git a/sd/inc/sdabstdlg.hxx b/sd/inc/sdabstdlg.hxx index 786c1121212a..9428325cdca0 100644 --- a/sd/inc/sdabstdlg.hxx +++ b/sd/inc/sdabstdlg.hxx @@ -171,7 +171,7 @@ public: virtual VclPtr CreateCopyDlg(weld::Window* pWindow, const SfxItemSet& rInAttrs, ::sd::View* pView ) = 0; virtual VclPtr CreateSdCustomShowDlg(weld::Window* pWindow, SdDrawDocument& rDrawDoc) = 0; virtual VclPtr CreateSdTabCharDialog(weld::Window* pWindow, const SfxItemSet* pAttr, SfxObjectShell* pDocShell) = 0; - virtual VclPtr CreateSdTabPageDialog(weld::Window* pWindow, const SfxItemSet* pAttr, SfxObjectShell* pDocShell, bool bAreaPage, bool bIsImpressDoc) = 0; + virtual VclPtr CreateSdTabPageDialog(weld::Window* pWindow, const SfxItemSet* pAttr, SfxObjectShell* pDocShell, bool bAreaPage, bool bIsImpressDoc, bool bIsImpressMaster) = 0; virtual VclPtr CreateSdModifyFieldDlg(weld::Window* pWindow, const SvxFieldData* pInField, const SfxItemSet& rSet) = 0; virtual VclPtr CreateSdSnapLineDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, ::sd::View* pView) = 0; virtual VclPtr CreateSdInsertLayerDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, bool bDeletable, const OUString& rStr) = 0; diff --git a/sd/qa/unit/dialogs-test.cxx b/sd/qa/unit/dialogs-test.cxx index 363732c75b44..c6e90419869d 100644 --- a/sd/qa/unit/dialogs-test.cxx +++ b/sd/qa/unit/dialogs-test.cxx @@ -308,7 +308,7 @@ VclPtr SdDialogsTest::createDialogByID(sal_uInt32 nID) getViewShell()->GetFrameWeld(), &getEmptyFillStyleSfxItemSet(), getDocShell(), - true, false); + true, /*bIsImpressDoc=*/false, /*bIsImpressMaster=*/false); break; } case 6: diff --git a/sd/source/ui/dlg/dlgpage.cxx b/sd/source/ui/dlg/dlgpage.cxx index b6d04173d814..e3bc5978bd8c 100644 --- a/sd/source/ui/dlg/dlgpage.cxx +++ b/sd/source/ui/dlg/dlgpage.cxx @@ -36,7 +36,7 @@ * Constructor of tab dialog: appends pages to the dialog */ SdPageDlg::SdPageDlg(SfxObjectShell const* pDocSh, weld::Window* pParent, const SfxItemSet* pAttr, - bool bAreaPage, bool bIsImpressDoc) + bool bAreaPage, bool bIsImpressDoc, bool bIsImpressMaster) : SfxTabDialogController(pParent, "modules/sdraw/ui/drawpagedialog.ui", "DrawPageDialog", pAttr) , mbIsImpressDoc(bIsImpressDoc) { @@ -58,6 +58,7 @@ SdPageDlg::SdPageDlg(SfxObjectShell const* pDocSh, weld::Window* pParent, const AddTabPage("RID_SVXPAGE_AREA", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_AREA), nullptr); AddTabPage("RID_SVXPAGE_TRANSPARENCE", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_TRANSPARENCE), nullptr); + AddTabPage("RID_SVXPAGE_THEME", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_THEME), nullptr); if (!bAreaPage) // I have to add the page before I remove it ! { @@ -65,6 +66,12 @@ SdPageDlg::SdPageDlg(SfxObjectShell const* pDocSh, weld::Window* pParent, const RemoveTabPage("RID_SVXPAGE_TRANSPARENCE"); } + if (!bIsImpressMaster) + { + // Only slide masters can have a theme. + RemoveTabPage("RID_SVXPAGE_THEME"); + } + if (mbIsImpressDoc) { set_title(SdResId(STR_SLIDE_SETUP_TITLE)); diff --git a/sd/source/ui/dlg/sddlgfact.cxx b/sd/source/ui/dlg/sddlgfact.cxx index 506b741e677d..c526df75d44f 100644 --- a/sd/source/ui/dlg/sddlgfact.cxx +++ b/sd/source/ui/dlg/sddlgfact.cxx @@ -618,9 +618,9 @@ VclPtr SdAbstractDialogFactory_Impl::CreateSdTabCharDialo return VclPtr::Create(std::make_shared(pParent, pAttr, pDocShell)); } -VclPtr SdAbstractDialogFactory_Impl::CreateSdTabPageDialog(weld::Window* pParent, const SfxItemSet* pAttr, SfxObjectShell* pDocShell, bool bAreaPage, bool bIsImpressDoc ) +VclPtr SdAbstractDialogFactory_Impl::CreateSdTabPageDialog(weld::Window* pParent, const SfxItemSet* pAttr, SfxObjectShell* pDocShell, bool bAreaPage, bool bIsImpressDoc, bool bIsImpressMaster ) { - return VclPtr::Create(std::make_shared(pDocShell, pParent, pAttr, bAreaPage, bIsImpressDoc)); + return VclPtr::Create(std::make_shared(pDocShell, pParent, pAttr, bAreaPage, bIsImpressDoc, bIsImpressMaster)); } VclPtr SdAbstractDialogFactory_Impl::CreateSdModifyFieldDlg(weld::Window* pParent, const SvxFieldData* pInField, const SfxItemSet& rSet) diff --git a/sd/source/ui/dlg/sddlgfact.hxx b/sd/source/ui/dlg/sddlgfact.hxx index 5a8637586b8e..8da5c74ddc8d 100644 --- a/sd/source/ui/dlg/sddlgfact.hxx +++ b/sd/source/ui/dlg/sddlgfact.hxx @@ -410,7 +410,7 @@ public: virtual VclPtr CreateCopyDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, ::sd::View* pView) override; virtual VclPtr CreateSdCustomShowDlg(weld::Window* pParent, SdDrawDocument& rDrawDoc) override; virtual VclPtr CreateSdTabCharDialog(weld::Window* pWindow, const SfxItemSet* pAttr, SfxObjectShell* pDocShell) override; - virtual VclPtr CreateSdTabPageDialog(weld::Window* pWindow, const SfxItemSet* pAttr, SfxObjectShell* pDocShell, bool bAreaPage, bool bIsImpressDoc) override; + virtual VclPtr CreateSdTabPageDialog(weld::Window* pWindow, const SfxItemSet* pAttr, SfxObjectShell* pDocShell, bool bAreaPage, bool bIsImpressDoc, bool bIsImpressMaster) override; virtual VclPtr CreateSdModifyFieldDlg(weld::Window* pWindow, const SvxFieldData* pInField, const SfxItemSet& rSet) override; virtual VclPtr CreateSdSnapLineDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, ::sd::View* pView) override; virtual VclPtr CreateSdInsertLayerDlg(weld::Window* pParent, const SfxItemSet& rInAttrs, bool bDeletable, const OUString& aStr) override; diff --git a/sd/source/ui/func/fupage.cxx b/sd/source/ui/func/fupage.cxx index 366e99b691ff..2c1abb8123f7 100644 --- a/sd/source/ui/func/fupage.cxx +++ b/sd/source/ui/func/fupage.cxx @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -261,6 +262,19 @@ const SfxItemSet* FuPage::ExecuteDialog(weld::Window* pParent, const SfxRequest& SfxGrabBagItem grabBag(SID_ATTR_CHAR_GRABBAG); grabBag.GetGrabBag()["BackgroundFullSize"] <<= bFullSize; + + if (mpDoc->GetDocumentType() == DocumentType::Impress && mpPage->IsMasterPage()) + { + // A master slide may have a theme. + svx::Theme* pTheme = mpPage->getSdrPageProperties().GetTheme(); + if (pTheme) + { + uno::Any aTheme; + pTheme->ToAny(aTheme); + grabBag.GetGrabBag()["Theme"] = aTheme; + } + } + aNewAttr.Put(grabBag); // Merge ItemSet for dialog @@ -350,7 +364,7 @@ const SfxItemSet* FuPage::ExecuteDialog(weld::Window* pParent, const SfxRequest& // create the dialog SdAbstractDialogFactory* pFact = SdAbstractDialogFactory::Create(); - ScopedVclPtr pDlg( pFact->CreateSdTabPageDialog(mpViewShell->GetFrameWeld(), &aMergedAttr, mpDocSh, mbDisplayBackgroundTabPage, bIsImpressDoc) ); + ScopedVclPtr pDlg( pFact->CreateSdTabPageDialog(mpViewShell->GetFrameWeld(), &aMergedAttr, mpDocSh, mbDisplayBackgroundTabPage, bIsImpressDoc, mbMasterPage) ); if( pDlg->Execute() == RET_OK ) pTempSet.emplace( *pDlg->GetOutputItemSet() ); } @@ -554,6 +568,21 @@ void FuPage::ApplyItemSet( const SfxItemSet* pArgs ) bSetPageSizeAndBorder = true; } } + + if (mpDoc->GetDocumentType() == DocumentType::Impress && mpPage->IsMasterPage()) + { + // The item set may have a theme. + auto it = pGrabBag->GetGrabBag().find("Theme"); + if (it != pGrabBag->GetGrabBag().end()) + { + std::unique_ptr pTheme = svx::Theme::FromAny(it->second); + pMasterPage->getSdrPageProperties().SetTheme(std::move(pTheme)); + } + else + { + SAL_WARN("sd.ui", "FuPage::ApplyItemSet: got no theme"); + } + } } // Paper Bin diff --git a/sd/source/ui/inc/dlgpage.hxx b/sd/source/ui/inc/dlgpage.hxx index c4cd90e6045a..718ccf0c614b 100644 --- a/sd/source/ui/inc/dlgpage.hxx +++ b/sd/source/ui/inc/dlgpage.hxx @@ -40,7 +40,7 @@ private: XPatternListRef mpPatternList; public: - SdPageDlg(SfxObjectShell const * pDocSh, weld::Window* pParent, const SfxItemSet* pAttr, bool bAreaPage, bool bIsImpressDoc); + SdPageDlg(SfxObjectShell const * pDocSh, weld::Window* pParent, const SfxItemSet* pAttr, bool bAreaPage, bool bIsImpressDoc, bool bIsImpressMaster); virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; }; diff --git a/sd/uiconfig/sdraw/ui/drawpagedialog.ui b/sd/uiconfig/sdraw/ui/drawpagedialog.ui index 36aee9ac926f..d638e0e76081 100644 --- a/sd/uiconfig/sdraw/ui/drawpagedialog.ui +++ b/sd/uiconfig/sdraw/ui/drawpagedialog.ui @@ -235,6 +235,54 @@ False + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + + + + + True + False + Theme + + + 3 + False + + False