xref: /core/svx/source/dialog/svxbmpnumvalueset.cxx (revision 18b7d1895d5ca160761955fd70a09ce0de1171c8)
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  * 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 <sal/config.h>
21 
22 #include <svx/dialmgr.hxx>
23 #include <svx/strings.hrc>
24 #include <comphelper/diagnose_ex.hxx>
25 #include <i18nlangtag/mslangid.hxx>
26 #include <svtools/valueset.hxx>
27 #include <editeng/numitem.hxx>
28 #include <officecfg/Office/Common.hxx>
29 #include <svx/gallery.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/graph.hxx>
32 #include <vcl/virdev.hxx>
33 #include <svx/numvset.hxx>
34 #include <com/sun/star/style/NumberingType.hpp>
35 #include <com/sun/star/container/XIndexAccess.hpp>
36 #include <com/sun/star/text/XNumberingFormatter.hpp>
37 #include <com/sun/star/beans/PropertyValue.hpp>
38 
39 #include <algorithm>
40 
41 #include <uiobject.hxx>
42 
43 using namespace com::sun::star::uno;
44 using namespace com::sun::star::beans;
45 using namespace com::sun::star::lang;
46 using namespace com::sun::star::text;
47 using namespace com::sun::star::container;
48 using namespace com::sun::star::style;
49 
lcl_GetDefaultBulletFont()50 static vcl::Font& lcl_GetDefaultBulletFont()
51 {
52     static vcl::Font aDefBulletFont = []()
53     {
54         static vcl::Font tmp(u"OpenSymbol"_ustr, u""_ustr, Size(0, 14));
55         tmp.SetCharSet( RTL_TEXTENCODING_SYMBOL );
56         tmp.SetFamily( FAMILY_DONTKNOW );
57         tmp.SetPitch( PITCH_DONTKNOW );
58         tmp.SetWeight( WEIGHT_DONTKNOW );
59         tmp.SetTransparent( true );
60         return tmp;
61     }();
62     return aDefBulletFont;
63 }
64 
lcl_PaintLevel(OutputDevice * pVDev,sal_Int16 nNumberingType,const OUString & rBulletChar,const OUString & rText,const OUString & rFontName,Point & rLeft,vcl::Font & rRuleFont,const vcl::Font & rTextFont)65 static void lcl_PaintLevel(OutputDevice* pVDev, sal_Int16 nNumberingType,
66                         const OUString& rBulletChar, const OUString& rText, const OUString& rFontName,
67                         Point& rLeft, vcl::Font& rRuleFont, const vcl::Font& rTextFont)
68 {
69 
70     if(NumberingType::CHAR_SPECIAL == nNumberingType )
71     {
72         rRuleFont.SetStyleName(rFontName);
73         pVDev->SetFont(rRuleFont);
74         pVDev->DrawText(rLeft, rBulletChar);
75         rLeft.AdjustX(pVDev->GetTextWidth(rBulletChar) );
76     }
77     else
78     {
79         pVDev->SetFont(rTextFont);
80         pVDev->DrawText(rLeft, rText);
81         rLeft.AdjustX(pVDev->GetTextWidth(rText) );
82     }
83 }
84 
85 const TranslateId RID_SVXSTR_SINGLENUM_DESCRIPTIONS[] =
86 {
87     RID_SVXSTR_SINGLENUM_DESCRIPTION_0,
88     RID_SVXSTR_SINGLENUM_DESCRIPTION_1,
89     RID_SVXSTR_SINGLENUM_DESCRIPTION_2,
90     RID_SVXSTR_SINGLENUM_DESCRIPTION_3,
91     RID_SVXSTR_SINGLENUM_DESCRIPTION_4,
92     RID_SVXSTR_SINGLENUM_DESCRIPTION_5,
93     RID_SVXSTR_SINGLENUM_DESCRIPTION_6,
94     RID_SVXSTR_SINGLENUM_DESCRIPTION_7
95 };
96 
97 const TranslateId RID_SVXSTR_OUTLINENUM_DESCRIPTIONS[] =
98 {
99     RID_SVXSTR_OUTLINENUM_DESCRIPTION_0,
100     RID_SVXSTR_OUTLINENUM_DESCRIPTION_1,
101     RID_SVXSTR_OUTLINENUM_DESCRIPTION_2,
102     RID_SVXSTR_OUTLINENUM_DESCRIPTION_3,
103     RID_SVXSTR_OUTLINENUM_DESCRIPTION_4,
104     RID_SVXSTR_OUTLINENUM_DESCRIPTION_5,
105     RID_SVXSTR_OUTLINENUM_DESCRIPTION_6,
106     RID_SVXSTR_OUTLINENUM_DESCRIPTION_7
107 };
108 
UserDraw(const UserDrawEvent & rUDEvt)109 void SvxNumValueSet::UserDraw( const UserDrawEvent& rUDEvt )
110 {
111     static const sal_uInt16 aLinesArr[] =
112     {
113         15, 10,
114         20, 30,
115         25, 50,
116         30, 70,
117         35, 90, // up to here line positions
118          5, 10, // character positions
119         10, 30,
120         15, 50,
121         20, 70,
122         25, 90,
123     };
124 
125     const Color aBackColor(COL_WHITE);
126     const Color aTextColor(COL_BLACK);
127 
128     vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
129     tools::Rectangle aRect = rUDEvt.GetRect();
130     sal_uInt16 nIndex = rUDEvt.GetItemId() - 1;
131 
132 
133     tools::Long nRectWidth = aRect.GetWidth();
134     tools::Long nRectHeight = aRect.GetHeight();
135     Size aRectSize(nRectWidth, aRect.GetHeight());
136     Point aBLPos = aRect.TopLeft();
137     vcl::Font aOldFont = pDev->GetFont();
138     Color aOldColor = pDev->GetLineColor();
139     pDev->SetLineColor(aTextColor);
140     vcl::Font aFont(OutputDevice::GetDefaultFont(
141                 DefaultFontType::UI_SANS, MsLangId::getConfiguredSystemLanguage(), GetDefaultFontFlags::OnlyOne));
142 
143     Size aSize = aFont.GetFontSize();
144 
145     vcl::Font aRuleFont( lcl_GetDefaultBulletFont() );
146     aSize.setHeight( nRectHeight/6 );
147     aRuleFont.SetFontSize(aSize);
148     aRuleFont.SetColor(aTextColor);
149     aRuleFont.SetFillColor(aBackColor);
150     css::uno::Sequence< OUString > aBulletSymbols;
151 
152     if(ePageType == NumberingPageType::BULLET || ePageType == NumberingPageType::DOCBULLET)
153     {
154         aBulletSymbols = officecfg::Office::Common::BulletsNumbering::DefaultBullets::get();
155         css::uno::Sequence< OUString > aBulletFonts(officecfg::Office::Common::BulletsNumbering::DefaultBulletsFonts::get());
156         aRuleFont.SetFamilyName(aBulletFonts[nIndex]);
157         aFont = aRuleFont;
158     }
159     else if (ePageType == NumberingPageType::DOCBULLET)
160     {
161         aRuleFont.SetFamilyName(maCustomBullets[nIndex].second);
162         aFont = aRuleFont;
163     }
164     else if(ePageType == NumberingPageType::OUTLINE)
165     {
166         aSize.setHeight( nRectHeight/8 );
167     }
168     aFont.SetColor(aTextColor);
169     aFont.SetFillColor(aBackColor);
170     aFont.SetFontSize( aSize );
171     pDev->SetFont(aFont);
172 
173     if(!pVDev)
174     {
175         // The lines are only one time in the virtual device, only the outline
176         // page is currently done
177         pVDev = VclPtr<VirtualDevice>::Create(*pDev);
178         pVDev->SetMapMode(pDev->GetMapMode());
179         pVDev->EnableRTL( IsRTLEnabled() );
180         pVDev->SetOutputSize( aRectSize );
181         aOrgRect = aRect;
182         pVDev->SetFillColor( aBackColor );
183         pVDev->SetLineColor(COL_LIGHTGRAY);
184         // Draw line only once
185         if(ePageType != NumberingPageType::OUTLINE)
186         {
187             Point aStart(aBLPos.X() + nRectWidth *25 / 100,0);
188             Point aEnd(aBLPos.X() + nRectWidth * 9 / 10,0);
189             for( sal_uInt16 i = 11; i < 100; i += 33)
190             {
191                 aStart.setY( aBLPos.Y() + nRectHeight  * i / 100 );
192                 aEnd.setY( aStart.Y() );
193                 pVDev->DrawLine(aStart, aEnd);
194                 aStart.setY( aBLPos.Y() + nRectHeight  * (i + 11) / 100 );
195                 aEnd.setY( aStart.Y() );
196                 pVDev->DrawLine(aStart, aEnd);
197             }
198         }
199     }
200     pDev->DrawOutDev(   aRect.TopLeft(), aRectSize,
201                         aOrgRect.TopLeft(), aRectSize,
202                         *pVDev );
203     // Now comes the text
204     static constexpr OUStringLiteral sValue(u"Value");
205     if( NumberingPageType::SINGLENUM == ePageType ||
206            NumberingPageType::BULLET == ePageType ||
207            NumberingPageType::DOCBULLET == ePageType)
208     {
209         Point aStart(aBLPos.X() + nRectWidth / 9,0);
210         for( sal_uInt16 i = 0; i < 3; i++ )
211         {
212             sal_uInt16 nY = 11 + i * 33;
213             aStart.setY( aBLPos.Y() + nRectHeight  * nY / 100 );
214             OUString sText;
215             if(ePageType == NumberingPageType::BULLET)
216             {
217                 sText = aBulletSymbols[nIndex];
218                 aStart.AdjustY( -(pDev->GetTextHeight()/2) );
219                 aStart.setX( aBLPos.X() + 5 );
220             }
221             else if (ePageType == NumberingPageType::DOCBULLET)
222             {
223                 sText = maCustomBullets[nIndex].first;
224                 aStart.AdjustY( -(pDev->GetTextHeight()/2) );
225                 aStart.setX( aBLPos.X() + 5 );
226             }
227             else
228             {
229                 if(xFormatter.is() && aNumSettings.getLength() > nIndex)
230                 {
231                     Sequence<PropertyValue> aLevel = aNumSettings.getConstArray()[nIndex];
232                     try
233                     {
234                         aLevel.realloc(aLevel.getLength() + 1);
235                         PropertyValue& rValue = aLevel.getArray()[aLevel.getLength() - 1];
236                         rValue.Name = sValue;
237                         rValue.Value <<= static_cast<sal_Int32>(i + 1);
238                         sText = xFormatter->makeNumberingString( aLevel, aLocale );
239                     }
240                     catch(Exception&)
241                     {
242                         TOOLS_WARN_EXCEPTION("svx.dialog", "");
243                     }
244                 }
245                 // start just next to the left edge
246                 aStart.setX( aBLPos.X() + 2 );
247                 aStart.AdjustY( -(pDev->GetTextHeight()/2) );
248             }
249             pDev->DrawText(aStart, sText);
250         }
251     }
252     else if(NumberingPageType::OUTLINE == ePageType )
253     {
254         // Outline numbering has to be painted into the virtual device
255         // to get correct lines
256         // has to be made again
257         pVDev->SetLineColor(aBackColor);
258         pVDev->DrawRect(aOrgRect);
259         tools::Long nStartX = aOrgRect.Left();
260         tools::Long nStartY = aOrgRect.Top();
261 
262         if(xFormatter.is() && aOutlineSettings.getLength() > nIndex)
263         {
264             Reference<XIndexAccess> xLevel = aOutlineSettings.getArray()[nIndex];
265             try
266             {
267                 OUString sLevelTexts[5];
268                 OUString sFontNames[5];
269                 OUString sBulletChars[5];
270                 sal_Int16 aNumberingTypes[5];
271                 OUString sPrefixes[5];
272                 OUString sSuffixes[5];
273                 sal_Int16 aParentNumberings[5];
274 
275                 sal_Int32 nLevelCount = xLevel->getCount();
276                 if(nLevelCount > 5)
277                     nLevelCount = 5;
278                 for( sal_Int32 i = 0; i < nLevelCount; i++)
279                 {
280                     tools::Long nTop = nStartY + nRectHeight * (aLinesArr[2 * i + 11])/100 ;
281                     Point aLeft(nStartX + nRectWidth *  (aLinesArr[2 * i + 10])/ 100, nTop );
282 
283                     Any aLevelAny = xLevel->getByIndex(i);
284                     Sequence<PropertyValue> aLevel;
285                     aLevelAny >>= aLevel;
286                     aNumberingTypes[i] = 0;
287                     aParentNumberings[i] = 0;
288                     for (const PropertyValue& rProp : aLevel)
289                     {
290                         if ( rProp.Name == "NumberingType" )
291                             rProp.Value >>= aNumberingTypes[i];
292                         else if ( rProp.Name == "BulletFontName" )
293                             rProp.Value >>= sFontNames[i];
294                         else if ( rProp.Name == "BulletChar" )
295                             rProp.Value >>= sBulletChars[i];
296                         else if ( rProp.Name == "Prefix" )
297                             rProp.Value >>= sPrefixes[i];
298                         else if ( rProp.Name == "Suffix" )
299                             rProp.Value >>= sSuffixes[i];
300                         else if ( rProp.Name == "ParentNumbering" )
301                             rProp.Value >>= aParentNumberings[i];
302                     }
303                     Sequence< PropertyValue > aProperties(2);
304                     PropertyValue* pProperties = aProperties.getArray();
305                     pProperties[0].Name = "NumberingType";
306                     pProperties[0].Value <<= aNumberingTypes[i];
307                     pProperties[1].Name = "Value";
308                     pProperties[1].Value <<= sal_Int32(1);
309                     try
310                     {
311                         sLevelTexts[i] = xFormatter->makeNumberingString( aProperties, aLocale );
312                     }
313                     catch(Exception&)
314                     {
315                         TOOLS_WARN_EXCEPTION("svx.dialog", "");
316                     }
317 
318                     aLeft.AdjustY( -(pDev->GetTextHeight()/2) );
319                     if(!sPrefixes[i].isEmpty() &&
320                         sPrefixes[i] != " ")
321                     {
322                         pVDev->SetFont(aFont);
323                         pVDev->DrawText(aLeft, sPrefixes[i]);
324                         aLeft.AdjustX(pDev->GetTextWidth(sPrefixes[i]) );
325                     }
326                     if(aParentNumberings[i])
327                     {
328                         //insert old numberings here
329                         sal_Int32 nStartLevel = std::min(static_cast<sal_Int32>(aParentNumberings[i]), i);
330                         for(sal_Int32 nParentLevel = i - nStartLevel; nParentLevel < i; nParentLevel++)
331                         {
332                             OUString sTmp = sLevelTexts[nParentLevel] + ".";
333                             lcl_PaintLevel(pVDev,
334                                     aNumberingTypes[nParentLevel],
335                                     sBulletChars[nParentLevel],
336                                     sTmp,
337                                     sFontNames[nParentLevel],
338                                     aLeft,
339                                     aRuleFont,
340                                     aFont);
341                         }
342                     }
343                     lcl_PaintLevel(pVDev,
344                                     aNumberingTypes[i],
345                                     sBulletChars[i],
346                                     sLevelTexts[i],
347                                     sFontNames[i],
348                                     aLeft,
349                                     aRuleFont,
350                                     aFont);
351                     if(!sSuffixes[i].isEmpty() &&
352                        !sSuffixes[i].startsWith(" "))
353                     {
354                         pVDev->SetFont(aFont);
355                         pVDev->DrawText(aLeft, sSuffixes[i]);
356                         aLeft.AdjustX(pDev->GetTextWidth(sSuffixes[i]) );
357                     }
358 
359                     tools::Long nLineTop = nStartY + nRectHeight * aLinesArr[2 * i + 1]/100 ;
360                     Point aLineLeft(aLeft.X(), nLineTop );
361                     Point aLineRight(nStartX + nRectWidth * 90 /100, nLineTop );
362                     pVDev->SetLineColor(COL_LIGHTGRAY);
363                     pVDev->DrawLine(aLineLeft,  aLineRight);
364                 }
365 
366             }
367 #ifdef DBG_UTIL
368             catch(Exception&)
369             {
370                 static bool bAssert = false;
371                 if(!bAssert)
372                 {
373                     TOOLS_WARN_EXCEPTION("svx.dialog", "");
374                     bAssert = true;
375                 }
376             }
377 #else
378             catch(Exception&)
379             {
380             }
381 #endif
382         }
383         pDev->DrawOutDev(   aRect.TopLeft(), aRectSize,
384                             aOrgRect.TopLeft(), aRectSize,
385                             *pVDev );
386     }
387 
388     pDev->SetFont(aOldFont);
389     pDev->SetLineColor(aOldColor);
390 }
391 
SvxNumValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)392 SvxNumValueSet::SvxNumValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
393     : ValueSet(std::move(pScrolledWindow))
394     , ePageType(NumberingPageType::BULLET)
395     , pVDev(nullptr)
396 {
397 }
398 
GetUITestFactory() const399 FactoryFunction SvxNumValueSet::GetUITestFactory() const
400 {
401     return SvxNumValueSetUIObject::create;
402 }
403 
init(NumberingPageType eType)404 void SvxNumValueSet::init(NumberingPageType eType)
405 {
406     ePageType = eType;
407     pVDev = nullptr;
408 
409     SetColCount( 4 );
410     SetLineCount( 2 );
411     SetStyle( GetStyle() | WB_ITEMBORDER | WB_DOUBLEBORDER );
412     if(NumberingPageType::BULLET == eType)
413     {
414         for ( sal_uInt16 i = 0; i < 8; i++ )
415         {
416             InsertItem( i + 1, i );
417         }
418     }
419 }
420 
~SvxNumValueSet()421 SvxNumValueSet::~SvxNumValueSet()
422 {
423 }
424 
SetNumberingSettings(const Sequence<Sequence<PropertyValue>> & aNum,Reference<XNumberingFormatter> const & xFormat,const Locale & rLocale)425 void SvxNumValueSet::SetNumberingSettings(
426     const Sequence<Sequence<PropertyValue> >& aNum,
427     Reference<XNumberingFormatter> const & xFormat,
428     const Locale& rLocale   )
429 {
430     aNumSettings = aNum;
431     xFormatter = xFormat;
432     aLocale = rLocale;
433     if(aNum.getLength() > 8)
434             SetStyle( GetStyle()|WB_VSCROLL);
435     for ( sal_Int32 i = 0; i < aNum.getLength(); i++ )
436     {
437         InsertItem(i + 1, i);
438         if (i < 8)
439             SetItemText(i + 1, SvxResId(RID_SVXSTR_SINGLENUM_DESCRIPTIONS[i]));
440     }
441 }
442 
SetOutlineNumberingSettings(Sequence<Reference<XIndexAccess>> const & rOutline,Reference<XNumberingFormatter> const & xFormat,const Locale & rLocale)443 void SvxNumValueSet::SetOutlineNumberingSettings(
444             Sequence<Reference<XIndexAccess> > const & rOutline,
445             Reference<XNumberingFormatter> const & xFormat,
446             const Locale& rLocale)
447 {
448     aOutlineSettings = rOutline;
449     xFormatter = xFormat;
450     aLocale = rLocale;
451     if(aOutlineSettings.getLength() > 8)
452         SetStyle( GetStyle() | WB_VSCROLL );
453     for ( sal_Int32 i = 0; i < aOutlineSettings.getLength(); i++ )
454     {
455         InsertItem( i + 1, i );
456         if( i < 8 )
457             SetItemText(i + 1, SvxResId(RID_SVXSTR_OUTLINENUM_DESCRIPTIONS[i]));
458     }
459 }
460 
SetCustomBullets(const std::vector<std::pair<OUString,OUString>> & rCustomBullets)461 void SvxNumValueSet::SetCustomBullets(const std::vector<std::pair<OUString, OUString>>& rCustomBullets)
462 {
463     Clear();
464     maCustomBullets = rCustomBullets;
465     for (size_t i = 0; i < rCustomBullets.size(); i++)
466     {
467         InsertItem(i + 1, i);
468     }
469 }
470 
SvxBmpNumValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)471 SvxBmpNumValueSet::SvxBmpNumValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow)
472     : SvxNumValueSet(std::move(pScrolledWindow))
473     , aFormatIdle("SvxBmpNumValueSet FormatIdle")
474     , bGrfNotFound(false)
475 {
476 }
477 
init()478 void SvxBmpNumValueSet::init()
479 {
480     SvxNumValueSet::init(NumberingPageType::BITMAP);
481     bGrfNotFound = false;
482     GalleryExplorer::BeginLocking(GALLERY_THEME_BULLETS);
483     SetStyle( GetStyle() | WB_VSCROLL );
484     SetLineCount( 3 );
485     aFormatIdle.SetPriority(TaskPriority::LOWEST);
486     aFormatIdle.SetInvokeHandler(LINK(this, SvxBmpNumValueSet, FormatHdl_Impl));
487 }
488 
489 
~SvxBmpNumValueSet()490 SvxBmpNumValueSet::~SvxBmpNumValueSet()
491 {
492     GalleryExplorer::EndLocking(GALLERY_THEME_BULLETS);
493     aFormatIdle.Stop();
494 }
495 
UserDraw(const UserDrawEvent & rUDEvt)496 void SvxBmpNumValueSet::UserDraw(const UserDrawEvent& rUDEvt)
497 {
498     SvxNumValueSet::UserDraw(rUDEvt);
499 
500     tools::Rectangle aRect = rUDEvt.GetRect();
501     vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
502     sal_uInt16  nItemId = rUDEvt.GetItemId();
503     Point aBLPos = aRect.TopLeft();
504 
505     tools::Long nRectHeight = aRect.GetHeight();
506     Size aSize(nRectHeight/8, nRectHeight/8);
507 
508     Graphic aGraphic;
509     if(!GalleryExplorer::GetGraphicObj( GALLERY_THEME_BULLETS, nItemId - 1,
510                         &aGraphic))
511     {
512         bGrfNotFound = true;
513     }
514     else
515     {
516         Point aPos(aBLPos.X() + 5, 0);
517         for( sal_uInt16 i = 0; i < 3; i++ )
518         {
519             sal_uInt16 nY = 11 + i * 33;
520             aPos.setY( aBLPos.Y() + nRectHeight  * nY / 100 );
521             aGraphic.Draw(*pDev, aPos, aSize);
522         }
523     }
524 }
525 
IMPL_LINK_NOARG(SvxBmpNumValueSet,FormatHdl_Impl,Timer *,void)526 IMPL_LINK_NOARG(SvxBmpNumValueSet, FormatHdl_Impl, Timer *, void)
527 {
528     // only when a graphics was not there, it needs to be formatted
529     if (bGrfNotFound)
530     {
531         SetFormat();
532         bGrfNotFound = false;
533     }
534     Invalidate();
535 }
536 
537 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
538