From 1af58b5acec4a2de095d86feef05ac4aed3edb8f Mon Sep 17 00:00:00 2001 From: Tomaž Vajngerl Date: Fri, 6 Jan 2023 17:28:49 +0900 Subject: sw: add ThemeColorChanger that sweeps the model and changes colors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- sw/Library_sw.mk | 1 + sw/inc/swtypes.hxx | 6 +- sw/source/core/inc/ThemeColorChanger.hxx | 33 ++++ sw/source/core/inc/UndoAttribute.hxx | 2 +- sw/source/core/model/ThemeColorChanger.cxx | 271 +++++++++++++++++++++++++++++ sw/source/core/undo/unattr.cxx | 21 ++- sw/source/uibase/sidebar/ThemePanel.cxx | 44 +---- 7 files changed, 331 insertions(+), 47 deletions(-) create mode 100644 sw/source/core/inc/ThemeColorChanger.hxx create mode 100644 sw/source/core/model/ThemeColorChanger.cxx (limited to 'sw') diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk index 478136e50f54..fa2ca1663512 100644 --- a/sw/Library_sw.mk +++ b/sw/Library_sw.mk @@ -366,6 +366,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 96c0fb5008c3..b3cdfa531074 100644 --- a/sw/inc/swtypes.hxx +++ b/sw/inc/swtypes.hxx @@ -143,17 +143,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 : is_typed_flags {}; + template<> struct typed_flags : is_typed_flags {}; } namespace sw { 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 +#include + +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 c3cf4925d95a..e3c40b7f0e87 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&, 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..ff59c474748b --- /dev/null +++ b/sw/source/core/model/ThemeColorChanger.cxx @@ -0,0 +1,271 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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& xPortion) + { + if (!xPortion->getPropertySetInfo()->hasPropertyByName( + UNO_NAME_EDIT_CHAR_COLOR_THEME_REFERENCE)) + return; + + uno::Reference 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(aColor))); + } + + /// Updates the fill property colors + void updateFillColorSet(const uno::Reference& xShape) + { + if (!xShape->getPropertySetInfo()->hasPropertyByName(UNO_NAME_FILLCOLOR_THEME_REFERENCE)) + return; + + uno::Reference 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(aColor))); + } + + /// Updates the line property colors + void updateLineColorSet(const uno::Reference& xShape) + { + if (!xShape->getPropertySetInfo()->hasPropertyByName(UNO_NAME_LINECOLOR_THEME_REFERENCE)) + return; + + uno::Reference 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(aColor))); + } + + /// Updates properties of the SdrObject + void updateSdrObject(SdrObject* pObject) + { + uno::Reference xShape = pObject->getUnoShape(); + uno::Reference xShapeText(xShape, uno::UNO_QUERY); + if (xShapeText.is()) + { + // E.g. group shapes have no text. + uno::Reference xText(xShapeText->getText(), + uno::UNO_QUERY); + uno::Reference xParagraphs = xText->createEnumeration(); + while (xParagraphs->hasMoreElements()) + { + uno::Reference xParagraph(xParagraphs->nextElement(), + uno::UNO_QUERY); + uno::Reference xPortions = xParagraph->createEnumeration(); + while (xPortions->hasMoreElements()) + { + uno::Reference xPortion(xPortions->nextElement(), + uno::UNO_QUERY); + updateTextPortionColorSet(xPortion); + } + } + } + + uno::Reference 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 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(pPool->First(SfxStyleFamily::Para)); + while (pStyle) + { + SwTextFormatColl* pTextFormatCollection = pStyle->GetCollection(); + if (pTextFormatCollection) + changeColor(pTextFormatCollection, rColorSet, pDocument); + pStyle = static_cast(pPool->Next()); + } + + // Character style color change + pStyle = static_cast(pPool->First(SfxStyleFamily::Char)); + while (pStyle) + { + SwCharFormat* pCharFormat = pStyle->GetCharFormat(); + if (pCharFormat) + changeColor(pCharFormat, rColorSet, pDocument); + pStyle = static_cast(pPool->Next()); + } + + // Direct format change + auto pHandler = std::make_shared(*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 d8dc236c92e2..60df048d22b3 100644 --- a/sw/source/core/undo/unattr.cxx +++ b/sw/source/core/undo/unattr.cxx @@ -770,7 +770,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) @@ -787,10 +788,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()) @@ -826,6 +826,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 5c1f9238dc43..76fd5e59870b 100644 --- a/sw/source/uibase/sidebar/ThemePanel.cxx +++ b/sw/source/uibase/sidebar/ThemePanel.cxx @@ -13,55 +13,16 @@ #include #include -#include #include -#include -#include -#include -#include -#include #include +#include #include #include #include #include #include -#include -#include #include -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(pPool->First(SfxStyleFamily::Para)); - while (pStyle) - { - SwTextFormatColl* pCollection = pStyle->GetCollection(); - changeColor(pCollection, rColorSet); - pStyle = static_cast(pPool->Next()); - } -} - -} // end anonymous namespace - namespace sw::sidebar { @@ -147,7 +108,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*/, -- cgit