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 <sal/config.h>
12 
13 #include "ThemePanel.hxx"
14 
15 #include <swtypes.hxx>
16 #include <cmdid.h>
17 
18 #include <svl/intitem.hxx>
19 #include <svx/svxids.hrc>
20 #include <svx/dlgutil.hxx>
21 #include <svx/rulritem.hxx>
22 
23 #include <sfx2/sidebar/ControlFactory.hxx>
24 #include <sfx2/dispatch.hxx>
25 #include <sfx2/bindings.hxx>
26 #include <sfx2/viewsh.hxx>
27 #include <sfx2/objsh.hxx>
28 
29 #include <com/sun/star/lang/IllegalArgumentException.hpp>
30 
31 #include <editeng/fontitem.hxx>
32 #include <editeng/boxitem.hxx>
33 #include <editeng/borderline.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/virdev.hxx>
36 #include <charatr.hxx>
37 #include <charfmt.hxx>
38 #include <docsh.hxx>
39 #include <docstyle.hxx>
40 #include <fmtcol.hxx>
41 #include <format.hxx>
42 
43 namespace
44 {
45 
46 class FontSet
47 {
48 public:
49     OUString maName;
50     OUString msMonoFont;
51     OUString msHeadingFont;
52     OUString msBaseFont;
53 };
54 
55 class ColorVariable
56 {
57 public:
58     long mnIndex;
59     sal_Int16 mnTintShade;
60 
ColorVariable()61     ColorVariable()
62         : mnIndex(-1)
63         , mnTintShade()
64     {}
65 
ColorVariable(long nIndex,sal_Int16 nTintShade)66     ColorVariable(long nIndex, sal_Int16 nTintShade)
67         : mnIndex(nIndex)
68         , mnTintShade(nTintShade)
69     {}
70 };
71 
72 class StyleRedefinition
73 {
74     ColorVariable maVariable;
75 
76 public:
77     OUString const maElementName;
78 
79 public:
StyleRedefinition(const OUString & aElementName)80     explicit StyleRedefinition(const OUString& aElementName)
81         : maElementName(aElementName)
82     {}
83 
setColorVariable(ColorVariable aVariable)84     void setColorVariable(ColorVariable aVariable)
85     {
86         maVariable = aVariable;
87     }
88 
getColor(svx::ColorSet const & rColorSet)89     Color getColor(svx::ColorSet const & rColorSet)
90     {
91         Color aColor;
92         if (maVariable.mnIndex > -1)
93         {
94             aColor = rColorSet.getColor(maVariable.mnIndex);
95             aColor.ApplyTintOrShade(maVariable.mnTintShade);
96         }
97         else
98         {
99             aColor = COL_BLACK;
100         }
101         return aColor;
102     }
103 };
104 
105 class StyleSet
106 {
107     std::vector<StyleRedefinition> maStyles;
108 
109 public:
StyleSet()110     explicit StyleSet()
111         : maStyles()
112     {}
113 
add(StyleRedefinition const & aRedefinition)114     void add(StyleRedefinition const & aRedefinition)
115     {
116         maStyles.push_back(aRedefinition);
117     }
118 
get(const OUString & aString)119     StyleRedefinition* get(const OUString& aString)
120     {
121         for (StyleRedefinition & rStyle : maStyles)
122         {
123             if (rStyle.maElementName == aString)
124             {
125                 return &rStyle;
126             }
127         }
128         return nullptr;
129     }
130 };
131 
setupThemes()132 StyleSet setupThemes()
133 {
134     StyleSet aSet;
135 
136     {
137         StyleRedefinition aRedefinition("Heading 1");
138         aRedefinition.setColorVariable(ColorVariable(10, -1000));
139         aSet.add(aRedefinition);
140     }
141 
142     {
143         StyleRedefinition aRedefinition("Heading 2");
144         aRedefinition.setColorVariable(ColorVariable(7, -500));
145         aSet.add(aRedefinition);
146     }
147 
148     {
149         StyleRedefinition aRedefinition("Heading 3");
150         aRedefinition.setColorVariable(ColorVariable(5, 0));
151         aSet.add(aRedefinition);
152     }
153 
154     {
155         StyleRedefinition aRedefinition("Heading 4");
156         aRedefinition.setColorVariable(ColorVariable(6, -1000));
157         aSet.add(aRedefinition);
158     }
159 
160     {
161         StyleRedefinition aRedefinition("Heading 5");
162         aRedefinition.setColorVariable(ColorVariable(4, -1500));
163         aSet.add(aRedefinition);
164     }
165 
166     {
167         StyleRedefinition aRedefinition("Heading 6");
168         aRedefinition.setColorVariable(ColorVariable(3, -2500));
169         aSet.add(aRedefinition);
170     }
171 
172     {
173         StyleRedefinition aRedefinition("Heading 7");
174         aRedefinition.setColorVariable(ColorVariable(3, -2500));
175         aSet.add(aRedefinition);
176     }
177 
178     {
179         StyleRedefinition aRedefinition("Heading 8");
180         aRedefinition.setColorVariable(ColorVariable(2, 0));
181         aSet.add(aRedefinition);
182     }
183 
184     {
185         StyleRedefinition aRedefinition("Heading 9");
186         aRedefinition.setColorVariable(ColorVariable(2, 0));
187         aSet.add(aRedefinition);
188     }
189 
190     {
191         StyleRedefinition aRedefinition("Heading 10");
192         aRedefinition.setColorVariable(ColorVariable(0, 0));
193         aSet.add(aRedefinition);
194     }
195 
196     return aSet;
197 }
198 
changeFont(SwFormat * pFormat,SwDocStyleSheet const * pStyle,FontSet const & rFontSet)199 void changeFont(SwFormat* pFormat, SwDocStyleSheet const * pStyle, FontSet const & rFontSet)
200 {
201     if (pStyle->GetName() != "Default Style" && pFormat->GetAttrSet().GetItem(RES_CHRATR_FONT, false) == nullptr)
202     {
203         return;
204     }
205 
206     SvxFontItem aFontItem(pFormat->GetFont(false));
207 
208     FontPitch ePitch = aFontItem.GetPitch();
209 
210     if (ePitch == PITCH_FIXED)
211     {
212         aFontItem.SetFamilyName(rFontSet.msMonoFont);
213     }
214     else
215     {
216         if (pStyle->GetName() == "Heading")
217         {
218             aFontItem.SetFamilyName(rFontSet.msHeadingFont);
219         }
220         else
221         {
222             aFontItem.SetFamilyName(rFontSet.msBaseFont);
223         }
224     }
225 
226     pFormat->SetFormatAttr(aFontItem);
227 }
228 
229 /*void changeBorder(SwTextFormatColl* pCollection, SwDocStyleSheet* pStyle, StyleSet& rStyleSet)
230 {
231     if (pStyle->GetName() == "Heading")
232     {
233         SvxBoxItem aBoxItem(pCollection->GetBox());
234         editeng::SvxBorderLine aBorderLine;
235         aBorderLine.SetWidth(40); //20 = 1pt
236         aBorderLine.SetColor(rColorSet.mBaseColors[0]);
237         aBoxItem.SetLine(&aBorderLine, SvxBoxItemLine::BOTTOM);
238 
239         pCollection->SetFormatAttr(aBoxItem);
240     }
241 }*/
242 
changeColor(SwTextFormatColl * pCollection,svx::ColorSet const & rColorSet,StyleRedefinition * pRedefinition)243 void changeColor(SwTextFormatColl* pCollection, svx::ColorSet const & rColorSet, StyleRedefinition* pRedefinition)
244 {
245     Color aColor = pRedefinition->getColor(rColorSet);
246 
247     SvxColorItem aColorItem(pCollection->GetColor());
248     aColorItem.SetValue(aColor);
249     pCollection->SetFormatAttr(aColorItem);
250 }
251 
initFontSets()252 std::vector<FontSet> initFontSets()
253 {
254     std::vector<FontSet> aFontSets;
255     {
256         FontSet aFontSet;
257         aFontSet.maName = "Liberation Family";
258         aFontSet.msHeadingFont = "Liberation Sans";
259         aFontSet.msBaseFont = "Liberation Serif";
260         aFontSet.msMonoFont = "Liberation Mono";
261         aFontSets.push_back(aFontSet);
262     }
263     {
264         FontSet aFontSet;
265         aFontSet.maName = "DejaVu Family";
266         aFontSet.msHeadingFont = "DejaVu Sans";
267         aFontSet.msBaseFont = "DejaVu Serif";
268         aFontSet.msMonoFont = "DejaVu Sans Mono";
269         aFontSets.push_back(aFontSet);
270     }
271     {
272         FontSet aFontSet;
273         aFontSet.maName = "Croscore Modern";
274         aFontSet.msHeadingFont = "Caladea";
275         aFontSet.msBaseFont = "Carlito";
276         aFontSet.msMonoFont = "Liberation Mono";
277         aFontSets.push_back(aFontSet);
278     }
279     {
280         FontSet aFontSet;
281         aFontSet.maName = "Carlito";
282         aFontSet.msHeadingFont = "Carlito";
283         aFontSet.msBaseFont = "Carlito";
284         aFontSet.msMonoFont = "Liberation Mono";
285         aFontSets.push_back(aFontSet);
286     }
287     {
288         FontSet aFontSet;
289         aFontSet.maName = "Source Sans Family";
290         aFontSet.msHeadingFont = "Source Sans Pro";
291         aFontSet.msBaseFont = "Source Sans Pro";
292         aFontSet.msMonoFont = "Source Code Pro";
293         aFontSets.push_back(aFontSet);
294     }
295     {
296         FontSet aFontSet;
297         aFontSet.maName = "Source Sans Family 2";
298         aFontSet.msHeadingFont = "Source Sans Pro";
299         aFontSet.msBaseFont = "Source Sans Pro Light";
300         aFontSet.msMonoFont = "Source Code Pro";
301         aFontSets.push_back(aFontSet);
302     }
303     {
304         FontSet aFontSet;
305         aFontSet.maName = "Libertine Family";
306         aFontSet.msHeadingFont = "Linux Biolinum G";
307         aFontSet.msBaseFont = "Linux Libertine G";
308         aFontSet.msMonoFont = "Liberation Mono";
309         aFontSets.push_back(aFontSet);
310     }
311     {
312         FontSet aFontSet;
313         aFontSet.maName = "Open Sans";
314         aFontSet.msHeadingFont = "Open Sans";
315         aFontSet.msBaseFont = "Open Sans";
316         aFontSet.msMonoFont = "Droid Sans Mono";
317         aFontSets.push_back(aFontSet);
318     }
319     {
320         FontSet aFontSet;
321         aFontSet.maName = "Droid Sans";
322         aFontSet.msHeadingFont = "Droid Sans";
323         aFontSet.msBaseFont = "Droid Sans";
324         aFontSet.msMonoFont = "Droid Sans Mono";
325         aFontSets.push_back(aFontSet);
326     }
327     return aFontSets;
328 }
329 
getFontSet(const OUString & rFontVariant,std::vector<FontSet> & aFontSets)330 FontSet getFontSet(const OUString& rFontVariant, std::vector<FontSet>& aFontSets)
331 {
332     for (const FontSet & rFontSet : aFontSets)
333     {
334         if (rFontSet.maName == rFontVariant)
335             return rFontSet;
336     }
337     return aFontSets[0];
338 }
339 
applyTheme(SfxStyleSheetBasePool * pPool,const OUString & sFontSetName,const OUString & sColorSetName,StyleSet & rStyleSet,svx::ColorSets & rColorSets)340 void applyTheme(SfxStyleSheetBasePool* pPool, const OUString& sFontSetName, const OUString& sColorSetName,
341                 StyleSet& rStyleSet, svx::ColorSets& rColorSets)
342 {
343     SwDocStyleSheet* pStyle;
344 
345     std::vector<FontSet> aFontSets = initFontSets();
346     FontSet aFontSet = getFontSet(sFontSetName, aFontSets);
347 
348     svx::ColorSet aColorSet = rColorSets.getColorSet(sColorSetName);
349 
350     pPool->SetSearchMask(SfxStyleFamily::Para);
351     pStyle = static_cast<SwDocStyleSheet*>(pPool->First());
352 
353     while (pStyle)
354     {
355         SwTextFormatColl* pCollection = pStyle->GetCollection();
356 
357         changeFont(pCollection, pStyle, aFontSet);
358 
359         StyleRedefinition* pRedefinition = rStyleSet.get(pStyle->GetName());
360 
361         if (pRedefinition)
362         {
363             changeColor(pCollection, aColorSet, pRedefinition);
364         }
365 
366         pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
367     }
368 
369     pPool->SetSearchMask(SfxStyleFamily::Char);
370     pStyle = static_cast<SwDocStyleSheet*>(pPool->First());
371 
372     while (pStyle)
373     {
374         SwCharFormat* pCharFormat = pStyle->GetCharFormat();
375 
376         changeFont(static_cast<SwFormat*>(pCharFormat), pStyle, aFontSet);
377 
378         pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
379     }
380 }
381 
GenerateColorPreview(const svx::ColorSet & rColorSet)382 BitmapEx GenerateColorPreview(const svx::ColorSet& rColorSet)
383 {
384     ScopedVclPtrInstance<VirtualDevice> pVirtualDev(*Application::GetDefaultDevice());
385     float fScaleFactor = pVirtualDev->GetDPIScaleFactor();
386     long BORDER = 2 * fScaleFactor;
387     long SIZE = 12 * fScaleFactor;
388 
389     Size aSize(BORDER * 7 + SIZE * 6, BORDER * 3 + SIZE * 2);
390     pVirtualDev->SetOutputSizePixel(aSize);
391 
392     long x = BORDER;
393     long y1 = BORDER;
394     long y2 = y1 + SIZE + BORDER;
395 
396     pVirtualDev->SetLineColor(COL_LIGHTGRAY);
397 
398     for (sal_uInt32 i = 0; i < 12; i += 2)
399     {
400         pVirtualDev->SetFillColor(rColorSet.getColor(i));
401         pVirtualDev->DrawRect(tools::Rectangle(x, y1, x + SIZE, y1 + SIZE));
402 
403         pVirtualDev->SetFillColor(rColorSet.getColor(i + 1));
404         pVirtualDev->DrawRect(tools::Rectangle(x, y2, x + SIZE, y2 + SIZE));
405 
406         x += SIZE + BORDER;
407     }
408 
409     return pVirtualDev->GetBitmapEx(Point(), aSize);
410 }
411 
412 } // end anonymous namespace
413 
414 namespace sw { namespace sidebar {
415 
Create(vcl::Window * pParent,const css::uno::Reference<css::frame::XFrame> & rxFrame)416 VclPtr<vcl::Window> ThemePanel::Create (vcl::Window* pParent,
417                                         const css::uno::Reference<css::frame::XFrame>& rxFrame)
418 {
419     if (pParent == nullptr)
420         throw css::lang::IllegalArgumentException("no parent Window given to PagePropertyPanel::Create", nullptr, 0);
421     if (!rxFrame.is())
422         throw css::lang::IllegalArgumentException("no XFrame given to PagePropertyPanel::Create", nullptr, 1);
423 
424     return VclPtr<ThemePanel>::Create(pParent, rxFrame);
425 }
426 
ThemePanel(vcl::Window * pParent,const css::uno::Reference<css::frame::XFrame> & rxFrame)427 ThemePanel::ThemePanel(vcl::Window* pParent,
428                        const css::uno::Reference<css::frame::XFrame>& rxFrame)
429     : PanelLayout(pParent, "ThemePanel", "modules/swriter/ui/sidebartheme.ui", rxFrame)
430     , maColorSets()
431 {
432     get(mpListBoxFonts, "listbox_fonts");
433     get(mpValueSetColors, "valueset_colors");
434     get(mpApplyButton, "apply");
435 
436     mpValueSetColors->SetColCount(2);
437     mpValueSetColors->SetLineCount(4);
438 
439     mpApplyButton->SetClickHdl(LINK(this, ThemePanel, ClickHdl));
440     mpListBoxFonts->SetDoubleClickHdl(LINK(this, ThemePanel, DoubleClickHdl));
441     mpValueSetColors->SetDoubleClickHdl(LINK(this, ThemePanel, DoubleClickValueSetHdl));
442 
443     std::vector<FontSet> aFontSets = initFontSets();
444     for (const FontSet & rFontSet : aFontSets)
445     {
446         mpListBoxFonts->InsertEntry(rFontSet.maName);
447     }
448 
449     maColorSets.init();
450 
451     const std::vector<svx::ColorSet>& aColorSets = maColorSets.getColorSets();
452     for (size_t i = 0; i < aColorSets.size(); ++i)
453     {
454         const svx::ColorSet& rColorSet = aColorSets[i];
455 
456         const OUString& aName = rColorSet.getName();
457         BitmapEx aPreview = GenerateColorPreview(rColorSet);
458         mpValueSetColors->InsertItem(i, Image(aPreview), aName);
459     }
460 }
461 
~ThemePanel()462 ThemePanel::~ThemePanel()
463 {
464     disposeOnce();
465 }
466 
dispose()467 void ThemePanel::dispose()
468 {
469     mpListBoxFonts.clear();
470     mpValueSetColors.clear();
471     mpApplyButton.clear();
472 
473     PanelLayout::dispose();
474 }
475 
IMPL_LINK_NOARG(ThemePanel,ClickHdl,Button *,void)476 IMPL_LINK_NOARG(ThemePanel, ClickHdl, Button*, void)
477 {
478     DoubleClickHdl();
479 }
IMPL_LINK_NOARG(ThemePanel,DoubleClickValueSetHdl,ValueSet *,void)480 IMPL_LINK_NOARG(ThemePanel, DoubleClickValueSetHdl, ValueSet*, void)
481 {
482     DoubleClickHdl();
483 }
IMPL_LINK_NOARG(ThemePanel,DoubleClickHdl,ListBox &,void)484 IMPL_LINK_NOARG(ThemePanel, DoubleClickHdl, ListBox&, void)
485 {
486     DoubleClickHdl();
487 }
DoubleClickHdl()488 void ThemePanel::DoubleClickHdl()
489 {
490     SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current());
491     if (pDocSh)
492     {
493         OUString sEntryFonts = mpListBoxFonts->GetSelectedEntry();
494         sal_uInt32 nItemId = mpValueSetColors->GetSelectedItemId();
495         OUString sEntryColors = maColorSets.getColorSet(nItemId).getName();
496 
497         StyleSet aStyleSet = setupThemes();
498 
499         applyTheme(pDocSh->GetStyleSheetPool(), sEntryFonts, sEntryColors, aStyleSet, maColorSets);
500     }
501 }
502 
NotifyItemUpdate(const sal_uInt16,const SfxItemState,const SfxPoolItem *)503 void ThemePanel::NotifyItemUpdate(const sal_uInt16 /*nSId*/,
504                                          const SfxItemState /*eState*/,
505                                          const SfxPoolItem* /*pState*/)
506 {
507 }
508 
509 }} // end of namespace ::sw::sidebar
510 
511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
512