LibreOffice Module sw (master) 1
ThemeColorChanger.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 */
10
11#include <ThemeColorChanger.hxx>
12#include <ModelTraverser.hxx>
13#include <txtftn.hxx>
14#include <txtfrm.hxx>
15#include <docstyle.hxx>
16#include <drawdoc.hxx>
17#include <ndnotxt.hxx>
18#include <ndtxt.hxx>
19#include <format.hxx>
20#include <charatr.hxx>
21#include <paratr.hxx>
22#include <frmatr.hxx>
25#include <IDocumentUndoRedo.hxx>
26#include <UndoThemeChange.hxx>
27
28#include <svx/xflclit.hxx>
29
30#include <sal/config.h>
31#include <svx/svdpage.hxx>
32#include <svx/svditer.hxx>
35#include <editeng/unoprnms.hxx>
36#include <editeng/boxitem.hxx>
37#include <com/sun/star/text/XTextRange.hpp>
38#include <com/sun/star/container/XEnumerationAccess.hpp>
39#include <com/sun/star/container/XEnumeration.hpp>
40#include <com/sun/star/beans/XPropertySet.hpp>
41
42namespace sw
43{
44namespace
45{
46bool changeBorderLine(editeng::SvxBorderLine* pBorderLine, model::ColorSet const& rColorSet)
47{
48 if (!pBorderLine)
49 return false;
50
51 model::ComplexColor const& rComplexColor = pBorderLine->getComplexColor();
52 if (rComplexColor.meType == model::ColorType::Scheme)
53 {
54 auto eThemeType = rComplexColor.meSchemeType;
55 if (eThemeType != model::ThemeColorType::Unknown)
56 {
57 Color aColor = rColorSet.resolveColor(rComplexColor);
58 pBorderLine->SetColor(aColor);
59 return true;
60 }
61 }
62 return false;
63}
64
72class ThemeColorHandler : public sw::ModelTraverseHandler
73{
74 SwDoc& mrDocument;
75 model::ColorSet const& mrColorSet;
76
77public:
78 ThemeColorHandler(SwDoc& rDocument, model::ColorSet const& rColorSet)
79 : mrDocument(rDocument)
80 , mrColorSet(rColorSet)
81 {
82 }
83
85 void updateHints(SwTextNode* pTextNode)
86 {
87 if (!pTextNode->HasHints())
88 return;
89
90 SwpHints& rHints = pTextNode->GetSwpHints();
91 for (size_t i = 0; i < rHints.Count(); ++i)
92 {
93 const SwTextAttr* pTextAttr = rHints.Get(i);
94 SwPaM aPam(*pTextNode, pTextAttr->GetStart(), *pTextNode, pTextAttr->GetAnyEnd());
95 if (pTextAttr->Which() == RES_TXTATR_AUTOFMT)
96 {
97 SwFormatAutoFormat const& rAutoFormatPool(pTextAttr->GetAutoFormat());
98 std::shared_ptr<SfxItemSet> pStyleHandle(rAutoFormatPool.GetStyleHandle());
99 if (const SvxColorItem* pItem = pStyleHandle->GetItemIfSet(RES_CHRATR_COLOR))
100 {
101 model::ComplexColor const& rComplexColor = pItem->getComplexColor();
102 auto eSchemeType = rComplexColor.meSchemeType;
103 if (eSchemeType != model::ThemeColorType::Unknown)
104 {
105 Color aNewColor = mrColorSet.resolveColor(rComplexColor);
106 auto pNew = pItem->Clone();
107 pNew->SetValue(aNewColor);
108
111 }
112 }
113 if (const SvxUnderlineItem* pItem
114 = pStyleHandle->GetItemIfSet(RES_CHRATR_UNDERLINE))
115 {
116 model::ComplexColor const& rComplexColor = pItem->getComplexColor();
117 auto eSchemeType = rComplexColor.meSchemeType;
118 if (eSchemeType != model::ThemeColorType::Unknown)
119 {
120 Color aNewColor = mrColorSet.resolveColor(rComplexColor);
121 auto pNew = pItem->Clone();
122 pNew->SetColor(aNewColor);
123
126 }
127 }
128 if (const SvxOverlineItem* pItem = pStyleHandle->GetItemIfSet(RES_CHRATR_OVERLINE))
129 {
130 model::ComplexColor const& rComplexColor = pItem->getComplexColor();
131 auto eSchemeType = rComplexColor.meSchemeType;
132 if (eSchemeType != model::ThemeColorType::Unknown)
133 {
134 Color aNewColor = mrColorSet.resolveColor(rComplexColor);
135 auto pNew = pItem->Clone();
136 pNew->SetColor(aNewColor);
137
140 }
141 }
142 }
143 }
144 }
145
146 void updateParagraphAttributes(SwTextNode* pTextNode)
147 {
148 if (!pTextNode->HasSwAttrSet())
149 return;
150
151 SwAttrSet const& aAttrSet = pTextNode->GetSwAttrSet();
152
153 if (const SvxColorItem* pItem = aAttrSet.GetItemIfSet(RES_CHRATR_COLOR, false))
154 {
155 model::ComplexColor const& rComplexColor = pItem->getComplexColor();
156 if (rComplexColor.meType == model::ColorType::Scheme)
157 {
158 auto eSchemeType = rComplexColor.meSchemeType;
159 if (eSchemeType != model::ThemeColorType::Unknown)
160 {
161 Color aNewColor = mrColorSet.resolveColor(rComplexColor);
162 std::unique_ptr<SvxColorItem> pNewItem(pItem->Clone());
163 pNewItem->setColor(aNewColor);
164 pTextNode->SetAttr(*pNewItem);
165 }
166 }
167 }
168
169 if (const SvxUnderlineItem* pItem = aAttrSet.GetItemIfSet(RES_CHRATR_UNDERLINE, false))
170 {
171 model::ComplexColor const& rComplexColor = pItem->getComplexColor();
172 if (rComplexColor.meType == model::ColorType::Scheme)
173 {
174 auto eSchemeType = rComplexColor.meSchemeType;
175 if (eSchemeType != model::ThemeColorType::Unknown)
176 {
177 Color aNewColor = mrColorSet.resolveColor(rComplexColor);
178 std::unique_ptr<SvxUnderlineItem> pNewItem(pItem->Clone());
179 pNewItem->SetColor(aNewColor);
180 pTextNode->SetAttr(*pNewItem);
181 }
182 }
183 }
184
185 if (const SvxOverlineItem* pItem = aAttrSet.GetItemIfSet(RES_CHRATR_OVERLINE, false))
186 {
187 model::ComplexColor const& rComplexColor = pItem->getComplexColor();
188 if (rComplexColor.meType == model::ColorType::Scheme)
189 {
190 auto eSchemeType = rComplexColor.meSchemeType;
191 if (eSchemeType != model::ThemeColorType::Unknown)
192 {
193 Color aNewColor = mrColorSet.resolveColor(rComplexColor);
194 std::unique_ptr<SvxOverlineItem> pNewItem(pItem->Clone());
195 pNewItem->SetColor(aNewColor);
196 pTextNode->SetAttr(*pNewItem);
197 }
198 }
199 }
200
201 if (const XFillColorItem* pItem = aAttrSet.GetItemIfSet(XATTR_FILLCOLOR, false))
202 {
203 model::ComplexColor const& rComplexColor = pItem->getComplexColor();
204 if (rComplexColor.meType == model::ColorType::Scheme)
205 {
206 auto eSchemeType = rComplexColor.meSchemeType;
207 if (eSchemeType != model::ThemeColorType::Unknown)
208 {
209 Color aNewColor = mrColorSet.resolveColor(rComplexColor);
210 std::unique_ptr<XFillColorItem> pNewItem(pItem->Clone());
211 pNewItem->SetColorValue(aNewColor);
212 pTextNode->SetAttr(*pNewItem);
213 }
214 }
215 }
216
217 if (const SvxBoxItem* pItem = aAttrSet.GetItemIfSet(RES_BOX, false))
218 {
219 std::unique_ptr<SvxBoxItem> pNewItem(pItem->Clone());
220
221 bool bChanged = false;
222
223 bChanged = changeBorderLine(pNewItem->GetBottom(), mrColorSet) || bChanged;
224 bChanged = changeBorderLine(pNewItem->GetTop(), mrColorSet) || bChanged;
225 bChanged = changeBorderLine(pNewItem->GetLeft(), mrColorSet) || bChanged;
226 bChanged = changeBorderLine(pNewItem->GetRight(), mrColorSet) || bChanged;
227
228 if (bChanged)
229 {
230 pTextNode->SetAttr(*pNewItem);
231 }
232 }
233 }
234
235 void handleNode(SwNode* pNode) override
236 {
237 if (!pNode->IsTextNode())
238 return;
239
240 updateHints(pNode->GetTextNode());
241 updateParagraphAttributes(pNode->GetTextNode());
242 }
243
244 void handleSdrObject(SdrObject* pObject) override
245 {
246 // update current object
247 svx::theme::updateSdrObject(mrColorSet, pObject);
248
249 // update child objects
250 SdrObjList* pList = pObject->GetSubList();
251 if (pList)
252 {
253 SdrObjListIter aIter(pList, SdrIterMode::DeepWithGroups);
254 while (aIter.IsMore())
255 {
256 svx::theme::updateSdrObject(mrColorSet, aIter.Next());
257 }
258 }
259 }
260};
261
262bool changeOverlineColor(SwAttrSet const& rSet, SfxItemSet& rNewSet,
263 model::ColorSet const& rColorSet)
264{
266 model::ComplexColor const& rComplexColor = aItem.getComplexColor();
267 if (rComplexColor.meType != model::ColorType::Scheme)
268 return false;
269 auto eThemeType = rComplexColor.meSchemeType;
270 if (eThemeType == model::ThemeColorType::Unknown)
271 return false;
272 Color aColor = rColorSet.resolveColor(rComplexColor);
273 aItem.SetColor(aColor);
274 rNewSet.Put(aItem);
275 return true;
276}
277
278bool changeUnderlineColor(SwAttrSet const& rSet, SfxItemSet& rNewSet,
279 model::ColorSet const& rColorSet)
280{
282 model::ComplexColor const& rComplexColor = aItem.getComplexColor();
283 if (rComplexColor.meType != model::ColorType::Scheme)
284 return false;
285 auto eThemeType = rComplexColor.meSchemeType;
286 if (eThemeType == model::ThemeColorType::Unknown)
287 return false;
288 Color aColor = rColorSet.resolveColor(rComplexColor);
289 aItem.SetColor(aColor);
290 rNewSet.Put(aItem);
291 return true;
292}
293
294bool changeColor(SwAttrSet const& rSet, SfxItemSet& rNewSet, model::ColorSet const& rColorSet)
295{
296 SvxColorItem aColorItem(rSet.GetColor(false));
297 model::ComplexColor const& rComplexColor = aColorItem.getComplexColor();
298 if (rComplexColor.meType != model::ColorType::Scheme)
299 return false;
300 auto eThemeType = rComplexColor.meSchemeType;
301 if (eThemeType == model::ThemeColorType::Unknown)
302 return false;
303 Color aColor = rColorSet.resolveColor(rComplexColor);
304 aColorItem.SetValue(aColor);
305 rNewSet.Put(aColorItem);
306 return true;
307}
308
309bool changeBackground(SwAttrSet const& rSet, SfxItemSet& rNewSet, model::ColorSet const& rColorSet)
310{
311 XFillColorItem aFillItem(rSet.Get(XATTR_FILLCOLOR, false));
312 model::ComplexColor const& rComplexColor = aFillItem.getComplexColor();
313 if (rComplexColor.meType != model::ColorType::Scheme)
314 return false;
315 auto eThemeType = rComplexColor.getSchemeType();
316 if (eThemeType == model::ThemeColorType::Unknown)
317 return false;
318 Color aColor = rColorSet.resolveColor(rComplexColor);
319 aFillItem.SetColorValue(aColor);
320 rNewSet.Put(aFillItem);
321 return true;
322}
323
324bool changeBox(SwAttrSet const& rSet, SfxItemSet& rNewSet, model::ColorSet const& rColorSet)
325{
326 SvxBoxItem aBoxItem(rSet.GetBox(false));
327 bool bChange = false;
328
329 bChange = changeBorderLine(aBoxItem.GetBottom(), rColorSet) || bChange;
330 bChange = changeBorderLine(aBoxItem.GetTop(), rColorSet) || bChange;
331 bChange = changeBorderLine(aBoxItem.GetLeft(), rColorSet) || bChange;
332 bChange = changeBorderLine(aBoxItem.GetRight(), rColorSet) || bChange;
333
334 if (bChange)
335 rNewSet.Put(aBoxItem);
336 return bChange;
337}
338
339} // end anonymous namespace
340
342 : mpDocSh(pDocSh)
343{
344}
345
347
348void ThemeColorChanger::apply(std::shared_ptr<model::ColorSet> const& pColorSet)
349{
350 SwDoc* pDocument = mpDocSh->GetDoc();
351 if (!pDocument)
352 return;
353
354 pDocument->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
355
356 SdrPage* pPage = pDocument->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
357
358 auto pTheme = pPage->getSdrPageProperties().GetTheme();
359 if (!pTheme)
360 {
361 pTheme = std::make_shared<model::Theme>("Office");
362 pPage->getSdrPageProperties().SetTheme(pTheme);
363 }
364
365 std::shared_ptr<model::ColorSet> pNewColorSet = pColorSet;
366 std::shared_ptr<model::ColorSet> pOldColorSet = pTheme->getColorSet();
367 pTheme->setColorSet(pNewColorSet);
368
369 auto pUndoThemeChange
370 = std::make_unique<sw::UndoThemeChange>(*pDocument, pOldColorSet, pNewColorSet);
371 pDocument->GetIDocumentUndoRedo().AppendUndo(std::move(pUndoThemeChange));
372
373 // Page styles
374 for (size_t nIndex = 0; nIndex < pDocument->GetPageDescCnt(); ++nIndex)
375 {
376 auto& rPageDesc = pDocument->GetPageDesc(nIndex);
377 SwFrameFormat& rPageFormat = rPageDesc.GetMaster();
378 const SwAttrSet& rAttrSet = rPageFormat.GetAttrSet();
379 std::unique_ptr<SfxItemSet> pNewSet = rAttrSet.Clone();
380
381 bool bChanged = false;
382 bChanged = bChanged || changeBackground(rAttrSet, *pNewSet, *pColorSet);
383 bChanged = bChanged || changeBox(rAttrSet, *pNewSet, *pColorSet);
384
385 if (bChanged)
386 {
387 rPageFormat.SetFormatAttr(*pNewSet);
388 pDocument->ChgPageDesc(nIndex, rPageDesc);
389 }
390 }
391
393 SwDocStyleSheet* pStyle;
394
395 // Frame style color change
396 pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Frame));
397 while (pStyle)
398 {
399 SwFrameFormat* pFrameFormat = pStyle->GetFrameFormat();
400 if (pFrameFormat)
401 {
402 const SwAttrSet& rAttrSet = pFrameFormat->GetAttrSet();
403 std::unique_ptr<SfxItemSet> pNewSet = rAttrSet.Clone();
404
405 bool bChanged = false;
406 bChanged = changeBackground(rAttrSet, *pNewSet, *pColorSet) || bChanged;
407 bChanged = changeBox(rAttrSet, *pNewSet, *pColorSet) || bChanged;
408
409 if (bChanged)
410 pDocument->ChgFormat(*pFrameFormat, *pNewSet);
411 }
412 pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
413 }
414
415 // Paragraph style color change
416 pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Para));
417 while (pStyle)
418 {
419 SwTextFormatColl* pTextFormatCollection = pStyle->GetCollection();
420 if (pTextFormatCollection)
421 {
422 const SwAttrSet& rAttrSet = pTextFormatCollection->GetAttrSet();
423 std::unique_ptr<SfxItemSet> pNewSet = rAttrSet.Clone();
424
425 bool bChanged = false;
426 bChanged = changeColor(rAttrSet, *pNewSet, *pColorSet) || bChanged;
427 bChanged = changeOverlineColor(rAttrSet, *pNewSet, *pColorSet) || bChanged;
428 bChanged = changeUnderlineColor(rAttrSet, *pNewSet, *pColorSet) || bChanged;
429 bChanged = changeBox(rAttrSet, *pNewSet, *pColorSet) || bChanged;
430 bChanged = changeBackground(rAttrSet, *pNewSet, *pColorSet) || bChanged;
431
432 if (bChanged)
433 {
434 pDocument->ChgFormat(*pTextFormatCollection, *pNewSet);
435 pPool->Broadcast(SfxStyleSheetHint(SfxHintId::StyleSheetModified, *pStyle));
436 }
437 }
438 pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
439 }
440
441 // Character style color change
442 pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Char));
443 while (pStyle)
444 {
445 SwCharFormat* pCharFormat = pStyle->GetCharFormat();
446 if (pCharFormat)
447 {
448 const SwAttrSet& rAttrSet = pCharFormat->GetAttrSet();
449 std::unique_ptr<SfxItemSet> pNewSet = rAttrSet.Clone();
450
451 bool bChanged = false;
452 bChanged = changeColor(rAttrSet, *pNewSet, *pColorSet) || bChanged;
453 bChanged = changeOverlineColor(rAttrSet, *pNewSet, *pColorSet) || bChanged;
454 bChanged = changeUnderlineColor(rAttrSet, *pNewSet, *pColorSet) || bChanged;
455 if (bChanged)
456 pDocument->ChgFormat(*pCharFormat, *pNewSet);
457 }
458 pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
459 }
460
461 // Direct format change
462 auto pHandler = std::make_shared<ThemeColorHandler>(*pDocument, *pColorSet);
463 sw::ModelTraverser aModelTraverser(pDocument);
464 aModelTraverser.addNodeHandler(pHandler);
465 aModelTraverser.traverse();
466
467 pDocument->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
468}
469
470} // end sw namespace
471
472/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual bool InsertPoolItem(const SwPaM &rRg, const SfxPoolItem &, const SetAttrMode nFlags=SetAttrMode::DEFAULT, SwRootFrame const *pLayout=nullptr, SwTextAttr **ppNewTextAttr=nullptr)=0
Insert an attribute.
virtual const SwDrawModel * GetDrawModel() const =0
Draw Model and id accessors.
const SdrPage * GetPage(sal_uInt16 nPgNum) const
std::shared_ptr< model::Theme > const & GetTheme() const
void SetTheme(std::shared_ptr< model::Theme > const &pTheme)
SdrPageProperties & getSdrPageProperties()
void Broadcast(const SfxHint &rHint)
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
SfxStyleSheetBase * First(SfxStyleFamily eFamily, SfxStyleSearchBits eMask=SfxStyleSearchBits::All)
SfxStyleSheetBase * Next()
virtual std::unique_ptr< SfxItemSet > Clone(bool bItems=true, SfxItemPool *pToPool=nullptr) const override
Definition: swatrset.cxx:111
Represents the style of a text portion.
Definition: charfmt.hxx:27
bool HasSwAttrSet() const
Definition: node.hxx:494
const SwAttrSet & GetSwAttrSet() const
Does node has already its own auto-attributes? Access to SwAttrSet.
Definition: node.hxx:727
virtual SfxStyleSheetBasePool * GetStyleSheetPool() override
For Style PI.
Definition: docsh.cxx:1152
SwDoc * GetDoc()
returns Doc. But be careful!
Definition: docsh.hxx:204
SwFrameFormat * GetFrameFormat()
Definition: docstyle.cxx:2421
SwCharFormat * GetCharFormat()
Definition: docstyle.cxx:2355
SwTextFormatColl * GetCollection()
Definition: docstyle.cxx:2362
Definition: doc.hxx:197
void ChgFormat(SwFormat &rFormat, const SfxItemSet &rSet)
Definition: docfmt.cxx:1890
size_t GetPageDescCnt() const
Definition: doc.hxx:895
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:329
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:158
void ChgPageDesc(const OUString &rName, const SwPageDesc &)
Definition: docdesc.cxx:978
IDocumentDrawModelAccess const & getIDocumentDrawModelAccess() const
Definition: doc.cxx:169
const SwPageDesc & GetPageDesc(const size_t i) const
Definition: doc.hxx:896
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:136
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:447
Style of a layout element.
Definition: frmfmt.hxx:72
Base class of the Writer document model elements.
Definition: node.hxx:98
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:901
bool IsTextNode() const
Definition: node.hxx:190
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:188
A wrapper around SfxPoolItem to store the start position of (usually) a text portion,...
Definition: txatbase.hxx:44
sal_Int32 GetAnyEnd() const
end (if available), else start
Definition: txatbase.hxx:161
sal_Int32 GetStart() const
Definition: txatbase.hxx:88
const SwFormatAutoFormat & GetAutoFormat() const
Definition: txatbase.hxx:193
sal_uInt16 Which() const
Definition: txatbase.hxx:116
Represents the style of a paragraph.
Definition: fmtcol.hxx:61
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:112
virtual bool SetAttr(const SfxPoolItem &) override
overriding to handle change of certain paragraph attributes
Definition: ndtxt.cxx:5066
bool HasHints() const
Definition: ndtxt.hxx:254
SwpHints & GetSwpHints()
getters for SwpHints
Definition: ndtxt.hxx:867
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:68
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:144
size_t Count() const
Definition: ndhints.hxx:142
void SetColor(const Color &rColor)
model::ComplexColor const & getComplexColor() const
Color resolveColor(model::ComplexColor const &rComplexColor) const
ThemeColorType meSchemeType
ThemeColorType getSchemeType() const
void addNodeHandler(std::shared_ptr< ModelTraverseHandler > pHandler)
void apply(std::shared_ptr< model::ColorSet > const &pColorSet) override
ThemeColorChanger(SwDocShell *pDocSh)
virtual ~ThemeColorChanger() override
EmbeddedObjectRef * pObject
constexpr TypedWhichId< SvxUnderlineItem > RES_CHRATR_UNDERLINE(14)
constexpr TypedWhichId< SwFormatAutoFormat > RES_TXTATR_AUTOFMT(50)
constexpr TypedWhichId< SvxOverlineItem > RES_CHRATR_OVERLINE(38)
constexpr TypedWhichId< SvxBoxItem > RES_BOX(112)
constexpr TypedWhichId< SvxColorItem > RES_CHRATR_COLOR(3)
sal_Int32 nIndex
int i
void updateSdrObject(model::ColorSet const &rColorSet, SdrObject *pObject)
Dialog to specify the properties of date form field.
static SfxItemSet & rSet
@ NO_CURSOR_CHANGE
don't change the cursor position