diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2023-01-06 17:28:49 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2023-01-18 12:58:50 +0000 |
commit | 9eb7ca0059c912c16c994bda0ca16494a3121c8f (patch) | |
tree | 5cfbd0b65eaca17dc81020a04d04f72e3afc05f3 | |
parent | 424855cc772d9759e1846f2460390eb91f4e7370 (diff) |
sw: add ThemeColorChanger that sweeps the model and changes colors
The ThemeColorChanger responisiblity is to recalculate and change
all the theme colors in the model. This includes styles and direct
formatting changes. It uses ModelTraverser for direct formatting
changes as it already implements traversing through nodes.
The ThemeColorChanger replaces the code to change the colors in
ThemePanel.
Also modify undo/redo for changing of attributes to not move
the cursor and selection when undoing and redoing (new flag
NO_CURSOR_CHANGE), as in this case it is very distrcting.
Change-Id: Ida1912bd0697307daad9244d474862830ab2686f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145263
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
(cherry picked from commit 1af58b5acec4a2de095d86feef05ac4aed3edb8f)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145694
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
-rw-r--r-- | include/svl/itemset.hxx | 17 | ||||
-rw-r--r-- | sw/Library_sw.mk | 1 | ||||
-rw-r--r-- | sw/inc/swtypes.hxx | 6 | ||||
-rw-r--r-- | sw/source/core/inc/ThemeColorChanger.hxx | 33 | ||||
-rw-r--r-- | sw/source/core/inc/UndoAttribute.hxx | 2 | ||||
-rw-r--r-- | sw/source/core/model/ThemeColorChanger.cxx | 272 | ||||
-rw-r--r-- | sw/source/core/undo/unattr.cxx | 21 | ||||
-rw-r--r-- | sw/source/uibase/sidebar/ThemePanel.cxx | 44 |
8 files changed, 349 insertions, 47 deletions
diff --git a/include/svl/itemset.hxx b/include/svl/itemset.hxx index 5ce13bb1f4c8..cf26d10a0e99 100644 --- a/include/svl/itemset.hxx +++ b/include/svl/itemset.hxx @@ -145,6 +145,23 @@ public: bool bSrchInParent = true, const SfxPoolItem **ppItem = nullptr ) const; + template <class T> + SfxItemState GetItemState( TypedWhichId<T> nWhich, + bool bSrchInParent = true, + const T **ppItem = nullptr ) const + { return GetItemState(sal_uInt16(nWhich), bSrchInParent, reinterpret_cast<SfxPoolItem const**>(ppItem)); } + + /// Templatized version of GetItemState() to directly return the correct type. + template<class T> + const T * GetItemIfSet( TypedWhichId<T> nWhich, + bool bSrchInParent = true ) const + { + const SfxPoolItem * pItem = nullptr; + if( SfxItemState::SET == GetItemState(sal_uInt16(nWhich), bSrchInParent, &pItem) ) + return static_cast<const T*>(pItem); + return nullptr; + } + bool HasItem(sal_uInt16 nWhich, const SfxPoolItem** ppItem = nullptr) const; void DisableItem(sal_uInt16 nWhich); diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk index 999c2e7a0419..df31cb18d150 100644 --- a/sw/Library_sw.mk +++ b/sw/Library_sw.mk @@ -359,6 +359,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\ sw/source/core/layout/wsfrm \ sw/source/core/model/ModelTraverser \ sw/source/core/model/SearchResultLocator \ + sw/source/core/model/ThemeColorChanger \ sw/source/core/objectpositioning/anchoredobjectposition \ sw/source/core/objectpositioning/ascharanchoredobjectposition \ sw/source/core/objectpositioning/environmentofanchoredobject \ diff --git a/sw/inc/swtypes.hxx b/sw/inc/swtypes.hxx index d6de8697ab5d..02bd3704f773 100644 --- a/sw/inc/swtypes.hxx +++ b/sw/inc/swtypes.hxx @@ -144,17 +144,19 @@ enum class SetAttrMode NOHINTADJUST = 0x0008, // No merging of ranges. NOFORMATATTR = 0x0010, // Do not change into format attribute. APICALL = 0x0020, // Called from API (all UI related - // functionality will be disabled). + // functionality will be disabled). /// Force hint expand (only matters for hints with CH_TXTATR). FORCEHINTEXPAND = 0x0040, /// The inserted item is a copy -- intended for use in ndtxt.cxx. IS_COPY = 0x0080, /// for Undo, translated to SwInsertFlags::NOHINTEXPAND NOHINTEXPAND = 0x0100, + /// don't change the cursor position + NO_CURSOR_CHANGE = 0x0200 }; namespace o3tl { - template<> struct typed_flags<SetAttrMode> : is_typed_flags<SetAttrMode, 0x1ff> {}; + template<> struct typed_flags<SetAttrMode> : is_typed_flags<SetAttrMode, 0x3ff> {}; } constexpr bool SW_ISPRINTABLE(sal_Unicode c) { return c >= ' ' && 127 != c; } diff --git a/sw/source/core/inc/ThemeColorChanger.hxx b/sw/source/core/inc/ThemeColorChanger.hxx new file mode 100644 index 000000000000..0698126da3e9 --- /dev/null +++ b/sw/source/core/inc/ThemeColorChanger.hxx @@ -0,0 +1,33 @@ +/* -*- 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 <docsh.hxx> +#include <svx/ColorSets.hxx> + +namespace sw +{ +class ThemeColorChanger +{ +private: + SwDocShell* mpDocSh; + +public: + ThemeColorChanger(SwDocShell* pDocSh) + : mpDocSh(pDocSh) + { + } + + void apply(svx::ColorSet const& rColorSet); +}; + +} // end sw namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/UndoAttribute.hxx b/sw/source/core/inc/UndoAttribute.hxx index ffe4c4f3206d..3ac09d7f9c06 100644 --- a/sw/source/core/inc/UndoAttribute.hxx +++ b/sw/source/core/inc/UndoAttribute.hxx @@ -45,7 +45,7 @@ class SwUndoAttr final : public SwUndo, private SwUndRng OUString m_aChrFormatName; void RemoveIdx( SwDoc& rDoc ); - + void redoAttribute(SwPaM& rPam, sw::UndoRedoContext& rContext); public: SwUndoAttr( const SwPaM&, const SfxItemSet &, const SetAttrMode nFlags ); SwUndoAttr( const SwPaM&, const SfxPoolItem&, const SetAttrMode nFlags ); diff --git a/sw/source/core/model/ThemeColorChanger.cxx b/sw/source/core/model/ThemeColorChanger.cxx new file mode 100644 index 000000000000..7cc88c4cac83 --- /dev/null +++ b/sw/source/core/model/ThemeColorChanger.cxx @@ -0,0 +1,272 @@ +/* -*- 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 <ThemeColorChanger.hxx> +#include <ModelTraverser.hxx> +#include <txtftn.hxx> +#include <txtfrm.hxx> +#include <docstyle.hxx> +#include <drawdoc.hxx> +#include <ndnotxt.hxx> +#include <ndtxt.hxx> +#include <format.hxx> +#include <charatr.hxx> +#include <pam.hxx> +#include <DocumentContentOperationsManager.hxx> +#include <IDocumentUndoRedo.hxx> + +#include <sal/config.h> +#include <svx/svdpage.hxx> +#include <svx/svditer.hxx> +#include <docmodel/uno/UnoThemeColor.hxx> +#include <editeng/unoprnms.hxx> +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +namespace sw +{ +namespace +{ +/** Handler for ModelTraverser that recalculates and updates the theme colors. + * + * It checks all the SdrObjects and updates fill, line and text theme colors. + * For writer nodes it checks all the text nodes and updates the direct + * formatting in all hints. + * + */ +class ThemeColorHandler : public sw::ModelTraverseHandler +{ + SwDoc& mrDocument; + svx::ColorSet const& mrColorSet; + +public: + ThemeColorHandler(SwDoc& rDocument, svx::ColorSet const& rColorSet) + : mrDocument(rDocument) + , mrColorSet(rColorSet) + { + } + + /// Updates hints for a text node + void updateHints(SwTextNode* pTextNode) + { + if (!pTextNode->HasHints()) + return; + + SwpHints& rHints = pTextNode->GetSwpHints(); + for (size_t i = 0; i < rHints.Count(); ++i) + { + const SwTextAttr* pTextAttr = rHints.Get(i); + if (pTextAttr->Which() == RES_TXTATR_AUTOFMT) + { + SwFormatAutoFormat const& rAutoFormatPool(pTextAttr->GetAutoFormat()); + std::shared_ptr<SfxItemSet> pStyleHandle(rAutoFormatPool.GetStyleHandle()); + if (const SvxColorItem* pItem = pStyleHandle->GetItemIfSet(RES_CHRATR_COLOR)) + { + model::ThemeColor const& rThemeColor = pItem->GetThemeColor(); + auto eThemeType = rThemeColor.getType(); + if (eThemeType != model::ThemeColorType::Unknown) + { + Color aNewColor = mrColorSet.resolveColor(rThemeColor); + auto pNew = pItem->Clone(); + pNew->SetValue(aNewColor); + + SwPaM aPam(*pTextNode, pTextAttr->GetStart(), *pTextNode, + pTextAttr->GetAnyEnd()); + mrDocument.GetDocumentContentOperationsManager().InsertPoolItem( + aPam, *pNew, SetAttrMode::APICALL | SetAttrMode::NO_CURSOR_CHANGE); + } + } + } + } + } + + void handleNode(SwNode* pNode) override + { + if (!pNode->IsTextNode()) + return; + + updateHints(pNode->GetTextNode()); + } + + /// Updates text portion property colors + void updateTextPortionColorSet(const uno::Reference<beans::XPropertySet>& xPortion) + { + if (!xPortion->getPropertySetInfo()->hasPropertyByName( + UNO_NAME_EDIT_CHAR_COLOR_THEME_REFERENCE)) + return; + + uno::Reference<util::XThemeColor> xThemeColor; + xPortion->getPropertyValue(UNO_NAME_EDIT_CHAR_COLOR_THEME_REFERENCE) >>= xThemeColor; + if (!xThemeColor.is()) + return; + + model::ThemeColor aThemeColor; + model::theme::setFromXThemeColor(aThemeColor, xThemeColor); + + if (aThemeColor.getType() == model::ThemeColorType::Unknown) + return; + + Color aColor = mrColorSet.resolveColor(aThemeColor); + xPortion->setPropertyValue(UNO_NAME_EDIT_CHAR_COLOR, + uno::Any(static_cast<sal_Int32>(aColor))); + } + + /// Updates the fill property colors + void updateFillColorSet(const uno::Reference<beans::XPropertySet>& xShape) + { + if (!xShape->getPropertySetInfo()->hasPropertyByName(UNO_NAME_FILLCOLOR_THEME_REFERENCE)) + return; + + uno::Reference<util::XThemeColor> xThemeColor; + xShape->getPropertyValue(UNO_NAME_FILLCOLOR_THEME_REFERENCE) >>= xThemeColor; + if (!xThemeColor.is()) + return; + + model::ThemeColor aThemeColor; + model::theme::setFromXThemeColor(aThemeColor, xThemeColor); + + if (aThemeColor.getType() == model::ThemeColorType::Unknown) + return; + + Color aColor = mrColorSet.resolveColor(aThemeColor); + xShape->setPropertyValue(UNO_NAME_FILLCOLOR, uno::Any(static_cast<sal_Int32>(aColor))); + } + + /// Updates the line property colors + void updateLineColorSet(const uno::Reference<beans::XPropertySet>& xShape) + { + if (!xShape->getPropertySetInfo()->hasPropertyByName(UNO_NAME_LINECOLOR_THEME_REFERENCE)) + return; + + uno::Reference<util::XThemeColor> xThemeColor; + xShape->getPropertyValue(UNO_NAME_LINECOLOR_THEME_REFERENCE) >>= xThemeColor; + if (!xThemeColor.is()) + return; + + model::ThemeColor aThemeColor; + model::theme::setFromXThemeColor(aThemeColor, xThemeColor); + + if (aThemeColor.getType() == model::ThemeColorType::Unknown) + return; + + Color aColor = mrColorSet.resolveColor(aThemeColor); + xShape->setPropertyValue(UNO_NAME_LINECOLOR, uno::Any(static_cast<sal_Int32>(aColor))); + } + + /// Updates properties of the SdrObject + void updateSdrObject(SdrObject* pObject) + { + uno::Reference<drawing::XShape> xShape = pObject->getUnoShape(); + uno::Reference<text::XTextRange> xShapeText(xShape, uno::UNO_QUERY); + if (xShapeText.is()) + { + // E.g. group shapes have no text. + uno::Reference<container::XEnumerationAccess> xText(xShapeText->getText(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xParagraphs = xText->createEnumeration(); + while (xParagraphs->hasMoreElements()) + { + uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration(); + while (xPortions->hasMoreElements()) + { + uno::Reference<beans::XPropertySet> xPortion(xPortions->nextElement(), + uno::UNO_QUERY); + updateTextPortionColorSet(xPortion); + } + } + } + + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + updateFillColorSet(xShapeProps); + updateLineColorSet(xShapeProps); + } + + void handleSdrObject(SdrObject* pObject) override + { + // update current object + updateSdrObject(pObject); + + // update child objects + SdrObjList* pList = pObject->GetSubList(); + if (pList) + { + SdrObjListIter aIter(pList, SdrIterMode::DeepWithGroups); + while (aIter.IsMore()) + { + updateSdrObject(aIter.Next()); + } + } + } +}; + +void changeColor(SwFormat* pFormat, svx::ColorSet const& rColorSet, SwDoc* pDocument) +{ + const SwAttrSet& rAttrSet = pFormat->GetAttrSet(); + std::unique_ptr<SfxItemSet> pNewSet = rAttrSet.Clone(); + + SvxColorItem aColorItem(rAttrSet.GetColor()); + model::ThemeColor const& rThemeColor = aColorItem.GetThemeColor(); + auto eThemeType = rThemeColor.getType(); + if (eThemeType != model::ThemeColorType::Unknown) + { + Color aColor = rColorSet.getColor(eThemeType); + aColor = rThemeColor.applyTransformations(aColor); + aColorItem.SetValue(aColor); + pNewSet->Put(aColorItem); + pDocument->ChgFormat(*pFormat, *pNewSet); + } +} + +} // end anonymous namespace + +void ThemeColorChanger::apply(svx::ColorSet const& rColorSet) +{ + SwDoc* pDocument = mpDocSh->GetDoc(); + pDocument->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr); + + SfxStyleSheetBasePool* pPool = mpDocSh->GetStyleSheetPool(); + SwDocStyleSheet* pStyle; + + // Paragraph style color change + pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Para)); + while (pStyle) + { + SwTextFormatColl* pTextFormatCollection = pStyle->GetCollection(); + if (pTextFormatCollection) + changeColor(pTextFormatCollection, rColorSet, pDocument); + pStyle = static_cast<SwDocStyleSheet*>(pPool->Next()); + } + + // Character style color change + pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Char)); + while (pStyle) + { + SwCharFormat* pCharFormat = pStyle->GetCharFormat(); + if (pCharFormat) + changeColor(pCharFormat, rColorSet, pDocument); + pStyle = static_cast<SwDocStyleSheet*>(pPool->Next()); + } + + // Direct format change + auto pHandler = std::make_shared<ThemeColorHandler>(*pDocument, rColorSet); + sw::ModelTraverser aModelTraverser(pDocument); + aModelTraverser.addNodeHandler(pHandler); + aModelTraverser.traverse(); + + pDocument->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr); +} + +} // end sw namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/unattr.cxx b/sw/source/core/undo/unattr.cxx index bb2cdcaa34bb..13977d5479f3 100644 --- a/sw/source/core/undo/unattr.cxx +++ b/sw/source/core/undo/unattr.cxx @@ -776,7 +776,8 @@ void SwUndoAttr::UndoImpl(::sw::UndoRedoContext & rContext) m_pHistory->SetTmpEnd( m_pHistory->Count() ); // set cursor onto Undo area - AddUndoRedoPaM(rContext); + if (!(m_nInsertFlags & SetAttrMode::NO_CURSOR_CHANGE)) + AddUndoRedoPaM(rContext); } void SwUndoAttr::RepeatImpl(::sw::RepeatContext & rContext) @@ -793,10 +794,9 @@ void SwUndoAttr::RepeatImpl(::sw::RepeatContext & rContext) } } -void SwUndoAttr::RedoImpl(::sw::UndoRedoContext & rContext) +void SwUndoAttr::redoAttribute(SwPaM& rPam, sw::UndoRedoContext & rContext) { SwDoc & rDoc = rContext.GetDoc(); - SwPaM & rPam = AddUndoRedoPaM(rContext); // Restore pointer to char format from name if (!m_aChrFormatName.isEmpty()) @@ -832,6 +832,21 @@ void SwUndoAttr::RedoImpl(::sw::UndoRedoContext & rContext) } } +void SwUndoAttr::RedoImpl(sw::UndoRedoContext & rContext) +{ + if (m_nInsertFlags & SetAttrMode::NO_CURSOR_CHANGE) + { + SwPaM aPam(rContext.GetDoc().GetNodes().GetEndOfContent()); + SetPaM(aPam, false); + redoAttribute(aPam, rContext); + } + else + { + SwPaM& rPam = AddUndoRedoPaM(rContext); + redoAttribute(rPam, rContext); + } +} + void SwUndoAttr::RemoveIdx( SwDoc& rDoc ) { if ( SfxItemState::SET != m_AttrSet.GetItemState( RES_TXTATR_FTN, false )) diff --git a/sw/source/uibase/sidebar/ThemePanel.cxx b/sw/source/uibase/sidebar/ThemePanel.cxx index 86846b50286d..7f2dd73fdbf2 100644 --- a/sw/source/uibase/sidebar/ThemePanel.cxx +++ b/sw/source/uibase/sidebar/ThemePanel.cxx @@ -27,55 +27,16 @@ #include <charfmt.hxx> #include <doc.hxx> #include <docsh.hxx> -#include <docstyle.hxx> #include <drawdoc.hxx> -#include <ndnotxt.hxx> -#include <ndtxt.hxx> -#include <fmtcol.hxx> -#include <format.hxx> -#include <charatr.hxx> #include <IDocumentDrawModelAccess.hxx> +#include <ThemeColorChanger.hxx> #include <vcl/settings.hxx> #include <vcl/svapp.hxx> #include <svx/svdpage.hxx> #include <svx/ColorSets.hxx> #include <svx/dialog/ThemeColorValueSet.hxx> -#include <sfx2/objsh.hxx> -#include <editeng/colritem.hxx> #include <com/sun/star/lang/IllegalArgumentException.hpp> -namespace -{ - -void changeColor(SwTextFormatColl* pCollection, svx::ColorSet const& rColorSet) -{ - SvxColorItem aColorItem(pCollection->GetColor()); - model::ThemeColor const& rThemeColor = aColorItem.GetThemeColor(); - auto eThemeType = rThemeColor.getType(); - if (eThemeType != model::ThemeColorType::Unknown) - { - Color aColor = rColorSet.getColor(eThemeType); - aColor = rThemeColor.applyTransformations(aColor); - aColorItem.SetValue(aColor); - pCollection->SetFormatAttr(aColorItem); - } -} - -void applyTheme(SfxStyleSheetBasePool* pPool, svx::ColorSet const& rColorSet) -{ - SwDocStyleSheet* pStyle; - - pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Para)); - while (pStyle) - { - SwTextFormatColl* pCollection = pStyle->GetCollection(); - changeColor(pCollection, rColorSet); - pStyle = static_cast<SwDocStyleSheet*>(pPool->Next()); - } -} - -} // end anonymous namespace - namespace sw::sidebar { @@ -161,7 +122,8 @@ void ThemePanel::DoubleClickHdl() svx::ColorSet const& rColorSet = maColorSets.getColorSet(nIndex); - applyTheme(pDocSh->GetStyleSheetPool(), rColorSet); + ThemeColorChanger aChanger(pDocSh); + aChanger.apply(rColorSet); } void ThemePanel::NotifyItemUpdate(const sal_uInt16 /*nSId*/, |