summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2023-01-06 17:28:49 +0900
committerTomaž Vajngerl <quikee@gmail.com>2023-01-18 12:58:50 +0000
commit9eb7ca0059c912c16c994bda0ca16494a3121c8f (patch)
tree5cfbd0b65eaca17dc81020a04d04f72e3afc05f3
parent424855cc772d9759e1846f2460390eb91f4e7370 (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.hxx17
-rw-r--r--sw/Library_sw.mk1
-rw-r--r--sw/inc/swtypes.hxx6
-rw-r--r--sw/source/core/inc/ThemeColorChanger.hxx33
-rw-r--r--sw/source/core/inc/UndoAttribute.hxx2
-rw-r--r--sw/source/core/model/ThemeColorChanger.cxx272
-rw-r--r--sw/source/core/undo/unattr.cxx21
-rw-r--r--sw/source/uibase/sidebar/ThemePanel.cxx44
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*/,