1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <StylesPreviewWindow.hxx>
21 
22 #include <vcl/settings.hxx>
23 #include <vcl/svapp.hxx>
24 #include <sfx2/objsh.hxx>
25 #include <svl/itemset.hxx>
26 #include <sfx2/tbxctrl.hxx>
27 #include <sfx2/sfxsids.hrc>
28 #include <sfx2/tplpitem.hxx>
29 #include <sfx2/viewsh.hxx>
30 #include <vcl/virdev.hxx>
31 
32 #include <editeng/editids.hrc>
33 #include <editeng/fontitem.hxx>
34 #include <editeng/fhgtitem.hxx>
35 #include <editeng/svxfont.hxx>
36 #include <editeng/wghtitem.hxx>
37 #include <editeng/postitem.hxx>
38 #include <editeng/contouritem.hxx>
39 #include <editeng/shdditem.hxx>
40 #include <editeng/charreliefitem.hxx>
41 #include <editeng/udlnitem.hxx>
42 #include <editeng/crossedoutitem.hxx>
43 #include <editeng/colritem.hxx>
44 #include <editeng/cmapitem.hxx>
45 #include <editeng/emphasismarkitem.hxx>
46 #include <editeng/brushitem.hxx>
47 
48 #include <svx/xfillit0.hxx>
49 #include <svx/xdef.hxx>
50 #include <svx/xflclit.hxx>
51 
52 #include <com/sun/star/drawing/FillStyle.hpp>
53 #include <com/sun/star/uno/Sequence.hxx>
54 #include <cppuhelper/weak.hxx>
55 
56 #include <vcl/event.hxx>
57 #include <vcl/commandevent.hxx>
58 
StyleStatusListener(StylesPreviewWindow_Base * pPreviewControl,const css::uno::Reference<css::frame::XDispatchProvider> & xDispatchProvider)59 StyleStatusListener::StyleStatusListener(
60     StylesPreviewWindow_Base* pPreviewControl,
61     const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider)
62     : SfxStatusListener(xDispatchProvider, SID_STYLE_FAMILY2, ".uno:ParaStyle")
63     , m_pPreviewControl(pPreviewControl)
64 {
65     ReBind();
66 }
67 
StateChanged(SfxItemState,const SfxPoolItem * pState)68 void StyleStatusListener::StateChanged(SfxItemState /*eState*/, const SfxPoolItem* pState)
69 {
70     const SfxTemplateItem* pStateItem = dynamic_cast<const SfxTemplateItem*>(pState);
71     if (pStateItem)
72     {
73         if (pStateItem->GetStyleIdentifier().isEmpty())
74             m_pPreviewControl->Select(pStateItem->GetStyleName());
75         else
76             m_pPreviewControl->Select(pStateItem->GetStyleIdentifier());
77     }
78 }
79 
StylePoolChangeListener(StylesPreviewWindow_Base * pPreviewControl)80 StylePoolChangeListener::StylePoolChangeListener(StylesPreviewWindow_Base* pPreviewControl)
81     : SfxListener()
82     , m_pPreviewControl(pPreviewControl)
83 {
84     SfxObjectShell* pDocShell = SfxObjectShell::Current();
85 
86     m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
87 
88     if (m_pStyleSheetPool)
89     {
90         StartListening(*m_pStyleSheetPool);
91     }
92 }
93 
~StylePoolChangeListener()94 StylePoolChangeListener::~StylePoolChangeListener()
95 {
96     if (m_pStyleSheetPool)
97         EndListening(*m_pStyleSheetPool);
98 }
99 
Notify(SfxBroadcaster &,const SfxHint &)100 void StylePoolChangeListener::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& /*rHint*/)
101 {
102     m_pPreviewControl->UpdateStylesList();
103 }
104 
StyleItemController(const std::pair<OUString,OUString> & aStyleName)105 StyleItemController::StyleItemController(const std::pair<OUString, OUString>& aStyleName)
106     : m_eStyleFamily(SfxStyleFamily::Para)
107     , m_aStyleName(aStyleName)
108 {
109 }
110 
Paint(vcl::RenderContext & rRenderContext)111 void StyleItemController::Paint(vcl::RenderContext& rRenderContext)
112 {
113     rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::FONT | PushFlags::TEXTCOLOR);
114 
115     DrawEntry(rRenderContext);
116 
117     rRenderContext.Pop();
118 }
119 
Command(const CommandEvent & rEvent)120 bool StylesPreviewWindow_Base::Command(const CommandEvent& rEvent)
121 {
122     if (rEvent.GetCommand() != CommandEventId::ContextMenu)
123         return false;
124 
125     std::unique_ptr<weld::Builder> xBuilder(
126         Application::CreateBuilder(m_xStylesView.get(), "svx/ui/stylemenu.ui"));
127     std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu("menu"));
128     std::string_view rIdent = xMenu->popup_at_rect(
129         m_xStylesView.get(), tools::Rectangle(rEvent.GetMousePosPixel(), Size(1, 1)));
130     if (rIdent == "update" || rIdent == "edit")
131     {
132         css::uno::Sequence<css::beans::PropertyValue> aArgs(0);
133 
134         SfxToolBoxControl::Dispatch(m_xDispatchProvider,
135                                     rIdent == "update" ? OUString(".uno:StyleUpdateByExample")
136                                                        : OUString(".uno:EditStyle"),
137                                     aArgs);
138 
139         return true;
140     }
141 
142     return false;
143 }
144 
GetTextColorFromItemSet(std::unique_ptr<const SfxItemSet> const & pItemSet)145 static Color GetTextColorFromItemSet(std::unique_ptr<const SfxItemSet> const& pItemSet)
146 {
147     const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_CHAR_COLOR);
148     if (pItem)
149         return static_cast<const SvxColorItem*>(pItem)->GetValue();
150 
151     return COL_AUTO;
152 }
153 
GetHighlightColorFromItemSet(std::unique_ptr<const SfxItemSet> const & pItemSet)154 static Color GetHighlightColorFromItemSet(std::unique_ptr<const SfxItemSet> const& pItemSet)
155 {
156     const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_BRUSH_CHAR);
157     if (pItem)
158         return static_cast<const SvxBrushItem*>(pItem)->GetColor();
159 
160     return COL_AUTO;
161 }
162 
GetBackgroundColorFromItemSet(std::unique_ptr<const SfxItemSet> const & pItemSet)163 static Color GetBackgroundColorFromItemSet(std::unique_ptr<const SfxItemSet> const& pItemSet)
164 {
165     const SfxPoolItem* pItem = pItemSet->GetItem(XATTR_FILLCOLOR);
166     if (pItem)
167         return static_cast<const XFillColorItem*>(pItem)->GetColorValue();
168 
169     return COL_AUTO;
170 }
171 
172 static css::drawing::FillStyle
GetFillStyleFromItemSet(std::unique_ptr<const SfxItemSet> const & pItemSet)173 GetFillStyleFromItemSet(std::unique_ptr<const SfxItemSet> const& pItemSet)
174 {
175     const SfxPoolItem* pItem = pItemSet->GetItem(XATTR_FILLSTYLE);
176     if (pItem)
177         return static_cast<const XFillStyleItem*>(pItem)->GetValue();
178 
179     return css::drawing::FillStyle_NONE;
180 }
181 
GetFontFromItems(const SvxFontItem * pFontItem,Size aPixelFontSize,std::unique_ptr<const SfxItemSet> const & pItemSet)182 static SvxFont GetFontFromItems(const SvxFontItem* pFontItem, Size aPixelFontSize,
183                                 std::unique_ptr<const SfxItemSet> const& pItemSet)
184 {
185     SvxFont aFont;
186 
187     aFont.SetFamilyName(pFontItem->GetFamilyName());
188     aFont.SetStyleName(pFontItem->GetStyleName());
189     aFont.SetFontSize(aPixelFontSize);
190 
191     const SfxPoolItem* pItem = pItemSet->GetItem(SID_ATTR_CHAR_WEIGHT);
192     if (pItem)
193         aFont.SetWeight(static_cast<const SvxWeightItem*>(pItem)->GetWeight());
194 
195     pItem = pItemSet->GetItem(SID_ATTR_CHAR_POSTURE);
196     if (pItem)
197         aFont.SetItalic(static_cast<const SvxPostureItem*>(pItem)->GetPosture());
198 
199     pItem = pItemSet->GetItem(SID_ATTR_CHAR_CONTOUR);
200     if (pItem)
201         aFont.SetOutline(static_cast<const SvxContourItem*>(pItem)->GetValue());
202 
203     pItem = pItemSet->GetItem(SID_ATTR_CHAR_SHADOWED);
204     if (pItem)
205         aFont.SetShadow(static_cast<const SvxShadowedItem*>(pItem)->GetValue());
206 
207     pItem = pItemSet->GetItem(SID_ATTR_CHAR_RELIEF);
208     if (pItem)
209         aFont.SetRelief(static_cast<const SvxCharReliefItem*>(pItem)->GetValue());
210 
211     pItem = pItemSet->GetItem(SID_ATTR_CHAR_UNDERLINE);
212     if (pItem)
213         aFont.SetUnderline(static_cast<const SvxUnderlineItem*>(pItem)->GetLineStyle());
214 
215     pItem = pItemSet->GetItem(SID_ATTR_CHAR_OVERLINE);
216     if (pItem)
217         aFont.SetOverline(static_cast<const SvxOverlineItem*>(pItem)->GetValue());
218 
219     pItem = pItemSet->GetItem(SID_ATTR_CHAR_STRIKEOUT);
220     if (pItem)
221         aFont.SetStrikeout(static_cast<const SvxCrossedOutItem*>(pItem)->GetStrikeout());
222 
223     pItem = pItemSet->GetItem(SID_ATTR_CHAR_CASEMAP);
224     if (pItem)
225         aFont.SetCaseMap(static_cast<const SvxCaseMapItem*>(pItem)->GetCaseMap());
226 
227     pItem = pItemSet->GetItem(SID_ATTR_CHAR_EMPHASISMARK);
228     if (pItem)
229         aFont.SetEmphasisMark(static_cast<const SvxEmphasisMarkItem*>(pItem)->GetEmphasisMark());
230 
231     return aFont;
232 }
233 
DrawEntry(vcl::RenderContext & rRenderContext)234 void StyleItemController::DrawEntry(vcl::RenderContext& rRenderContext)
235 {
236     SfxObjectShell* pShell = SfxObjectShell::Current();
237     if (!pShell)
238         return;
239 
240     SfxStyleSheetBasePool* pPool = pShell->GetStyleSheetPool();
241     SfxStyleSheetBase* pStyle = nullptr;
242 
243     if (!pPool)
244         return;
245 
246     pStyle = pPool->First(m_eStyleFamily);
247     while (pStyle && pStyle->GetName() != m_aStyleName.first
248            && pStyle->GetName() != m_aStyleName.second)
249         pStyle = pPool->Next();
250 
251     if (!pStyle)
252         return;
253 
254     Size aSize(rRenderContext.GetOutputSizePixel());
255     tools::Rectangle aFullRect(Point(0, 0), aSize);
256     tools::Rectangle aContentRect(aFullRect);
257 
258     Color aOriginalColor = rRenderContext.GetFillColor();
259     Color aOriginalLineColor = rRenderContext.GetLineColor();
260 
261     DrawContentBackground(rRenderContext, aContentRect, aOriginalColor);
262 
263     std::unique_ptr<const SfxItemSet> const pItemSet(pStyle->GetItemSetForPreview());
264     if (!pItemSet)
265         return;
266 
267     Color aFontHighlight = COL_AUTO;
268 
269     const SvxFontItem* const pFontItem = pItemSet->GetItem<SvxFontItem>(SID_ATTR_CHAR_FONT);
270     const SvxFontHeightItem* const pFontHeightItem
271         = pItemSet->GetItem<SvxFontHeightItem>(SID_ATTR_CHAR_FONTHEIGHT);
272 
273     if (pFontItem && pFontHeightItem)
274     {
275         Size aFontSize(0, pFontHeightItem->GetHeight());
276         Size aPixelSize(rRenderContext.LogicToPixel(aFontSize, MapMode(pShell->GetMapUnit())));
277 
278         SvxFont aFont = GetFontFromItems(pFontItem, aPixelSize, pItemSet);
279         rRenderContext.SetFont(aFont);
280 
281         Color aFontCol = GetTextColorFromItemSet(pItemSet);
282         if (aFontCol != COL_AUTO)
283             rRenderContext.SetTextColor(aFontCol);
284 
285         aFontHighlight = GetHighlightColorFromItemSet(pItemSet);
286 
287         css::drawing::FillStyle style = GetFillStyleFromItemSet(pItemSet);
288 
289         switch (style)
290         {
291             case css::drawing::FillStyle_SOLID:
292             {
293                 Color aBackCol = GetBackgroundColorFromItemSet(pItemSet);
294                 if (aBackCol != COL_AUTO)
295                     DrawContentBackground(rRenderContext, aContentRect, aBackCol);
296             }
297             break;
298 
299             default:
300                 break;
301                 //TODO Draw the other background styles: gradient, hatching and bitmap
302         }
303     }
304 
305     if (aFontHighlight != COL_AUTO)
306         DrawHighlight(rRenderContext, aFontHighlight);
307 
308     DrawText(rRenderContext);
309 
310     rRenderContext.SetFillColor(aOriginalColor);
311     rRenderContext.SetLineColor(aOriginalLineColor);
312 }
313 
DrawContentBackground(vcl::RenderContext & rRenderContext,const tools::Rectangle & aContentRect,const Color & aColor)314 void StyleItemController::DrawContentBackground(vcl::RenderContext& rRenderContext,
315                                                 const tools::Rectangle& aContentRect,
316                                                 const Color& aColor)
317 {
318     rRenderContext.SetLineColor(aColor);
319     rRenderContext.SetFillColor(aColor);
320     rRenderContext.DrawRect(aContentRect);
321 }
322 
DrawHighlight(vcl::RenderContext & rRenderContext,Color aFontBack)323 void StyleItemController::DrawHighlight(vcl::RenderContext& rRenderContext, Color aFontBack)
324 {
325     tools::Rectangle aTextRect;
326     rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second);
327 
328     Size aSize = aTextRect.GetSize();
329     aSize.AdjustHeight(aSize.getHeight());
330     aTextRect.SetSize(aSize);
331 
332     Point aPos(0, 0);
333     aPos.AdjustX(LEFT_MARGIN);
334     aPos.AdjustY((rRenderContext.GetOutputHeightPixel() - aTextRect.Bottom()) / 2);
335     aTextRect.SetPos(aPos);
336 
337     rRenderContext.SetLineColor(aFontBack);
338     rRenderContext.SetFillColor(aFontBack);
339 
340     rRenderContext.DrawRect(aTextRect);
341 }
342 
DrawText(vcl::RenderContext & rRenderContext)343 void StyleItemController::DrawText(vcl::RenderContext& rRenderContext)
344 {
345     tools::Rectangle aTextRect;
346     rRenderContext.GetTextBoundRect(aTextRect, m_aStyleName.second);
347 
348     Point aPos(0, 0);
349     aPos.AdjustX(LEFT_MARGIN);
350     aPos.AdjustY((rRenderContext.GetOutputHeightPixel() - aTextRect.Bottom()) / 2);
351 
352     rRenderContext.DrawText(aPos, m_aStyleName.second);
353 }
354 
StylesPreviewWindow_Base(weld::Builder & xBuilder,std::vector<std::pair<OUString,OUString>> & aDefaultStyles,const css::uno::Reference<css::frame::XDispatchProvider> & xDispatchProvider)355 StylesPreviewWindow_Base::StylesPreviewWindow_Base(
356     weld::Builder& xBuilder, std::vector<std::pair<OUString, OUString>>& aDefaultStyles,
357     const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider)
358     : m_xDispatchProvider(xDispatchProvider)
359     , m_xStylesView(xBuilder.weld_icon_view("stylesview"))
360     , m_aDefaultStyles(aDefaultStyles)
361 {
362     m_xStylesView->connect_selection_changed(LINK(this, StylesPreviewWindow_Base, Selected));
363     m_xStylesView->connect_item_activated(LINK(this, StylesPreviewWindow_Base, DoubleClick));
364     m_xStylesView->connect_command(LINK(this, StylesPreviewWindow_Base, DoCommand));
365 
366     m_xStatusListener = new StyleStatusListener(this, xDispatchProvider);
367 
368     m_pStylePoolChangeListener.reset(new StylePoolChangeListener(this));
369 
370     UpdateStylesList();
371     Update();
372 }
373 
IMPL_LINK(StylesPreviewWindow_Base,Selected,weld::IconView &,rIconView,void)374 IMPL_LINK(StylesPreviewWindow_Base, Selected, weld::IconView&, rIconView, void)
375 {
376     OUString sStyleName = rIconView.get_selected_text();
377 
378     css::uno::Sequence<css::beans::PropertyValue> aArgs(2);
379     aArgs[0].Value <<= sStyleName;
380     aArgs[1].Name = "Family";
381     aArgs[1].Value <<= sal_Int16(SfxStyleFamily::Para);
382 
383     aArgs[0].Name = "Template";
384     SfxToolBoxControl::Dispatch(m_xDispatchProvider, ".uno:StyleApply", aArgs);
385 }
386 
IMPL_LINK(StylesPreviewWindow_Base,DoubleClick,weld::IconView &,rIconView,bool)387 IMPL_LINK(StylesPreviewWindow_Base, DoubleClick, weld::IconView&, rIconView, bool)
388 {
389     OUString sStyleName = rIconView.get_selected_text();
390 
391     css::uno::Sequence<css::beans::PropertyValue> aArgs(2);
392     aArgs[0].Name = "Param";
393     aArgs[0].Value <<= sStyleName;
394     aArgs[1].Name = "Family";
395     aArgs[1].Value <<= sal_Int16(SfxStyleFamily::Para);
396 
397     SfxToolBoxControl::Dispatch(m_xDispatchProvider, ".uno:EditStyle", aArgs);
398 
399     return true;
400 }
401 
IMPL_LINK(StylesPreviewWindow_Base,DoCommand,const CommandEvent &,rPos,bool)402 IMPL_LINK(StylesPreviewWindow_Base, DoCommand, const CommandEvent&, rPos, bool)
403 {
404     return Command(rPos);
405 }
406 
~StylesPreviewWindow_Base()407 StylesPreviewWindow_Base::~StylesPreviewWindow_Base()
408 {
409     m_xStatusListener->UnBind();
410 
411     try
412     {
413         m_xStatusListener->dispose();
414     }
415     catch (css::uno::Exception&)
416     {
417     }
418 
419     m_xStatusListener = nullptr;
420 }
421 
Select(const OUString & rStyleName)422 void StylesPreviewWindow_Base::Select(const OUString& rStyleName)
423 {
424     m_sSelectedStyle = rStyleName;
425 
426     Update();
427 }
428 
Update()429 void StylesPreviewWindow_Base::Update()
430 {
431     for (std::vector<std::pair<OUString, OUString>>::size_type i = 0; i < m_aAllStyles.size(); ++i)
432     {
433         if (m_aAllStyles[i].first == m_sSelectedStyle || m_aAllStyles[i].second == m_sSelectedStyle)
434         {
435             m_xStylesView->select(i);
436             break;
437         }
438     }
439 }
440 
UpdateStylesList()441 void StylesPreviewWindow_Base::UpdateStylesList()
442 {
443     m_aAllStyles = m_aDefaultStyles;
444 
445     SfxObjectShell* pDocShell = SfxObjectShell::Current();
446     SfxStyleSheetBasePool* pStyleSheetPool = nullptr;
447 
448     if (pDocShell)
449         pStyleSheetPool = pDocShell->GetStyleSheetPool();
450 
451     if (pStyleSheetPool)
452     {
453         auto xIter = pStyleSheetPool->CreateIterator(SfxStyleFamily::Para,
454                                                      SfxStyleSearchBits::UserDefined);
455 
456         SfxStyleSheetBase* pStyle = xIter->First();
457 
458         while (pStyle)
459         {
460             m_aAllStyles.push_back(std::pair<OUString, OUString>("", pStyle->GetName()));
461             pStyle = xIter->Next();
462         }
463     }
464 
465     m_xStylesView->clear();
466     for (auto& rStyle : m_aAllStyles)
467     {
468         ScopedVclPtr<VirtualDevice> pImg = VclPtr<VirtualDevice>::Create();
469         const Size aSize(100, 30);
470         pImg->SetOutputSizePixel(aSize);
471 
472         StyleItemController aStyleController(rStyle);
473         aStyleController.Paint(*pImg);
474 
475         m_xStylesView->append(rStyle.first, rStyle.second, pImg);
476     }
477 }
478 
StylesPreviewWindow_Impl(vcl::Window * pParent,std::vector<std::pair<OUString,OUString>> & aDefaultStyles,const css::uno::Reference<css::frame::XDispatchProvider> & xDispatchProvider)479 StylesPreviewWindow_Impl::StylesPreviewWindow_Impl(
480     vcl::Window* pParent, std::vector<std::pair<OUString, OUString>>& aDefaultStyles,
481     const css::uno::Reference<css::frame::XDispatchProvider>& xDispatchProvider)
482     : InterimItemWindow(pParent, "svx/ui/stylespreview.ui", "ApplyStyleBox",
483                         reinterpret_cast<sal_uInt64>(SfxViewShell::Current()))
484     , StylesPreviewWindow_Base(*m_xBuilder, aDefaultStyles, xDispatchProvider)
485 {
486     SetOptimalSize();
487 }
488 
~StylesPreviewWindow_Impl()489 StylesPreviewWindow_Impl::~StylesPreviewWindow_Impl() { disposeOnce(); }
490 
dispose()491 void StylesPreviewWindow_Impl::dispose()
492 {
493     m_xStylesView.reset();
494 
495     InterimItemWindow::dispose();
496 }
497 
SetOptimalSize()498 void StylesPreviewWindow_Impl::SetOptimalSize() { SetSizePixel(get_preferred_size()); }
499 
500 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
501