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