1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <svx/dialmgr.hxx>
23 #include <svx/strings.hrc>
24 #include <tools/diagnose_ex.h>
25 #include <i18nlangtag/mslangid.hxx>
26 #include <svtools/valueset.hxx>
27 #include <editeng/numitem.hxx>
28 #include <svx/gallery.hxx>
29 #include <vcl/event.hxx>
30 #include <vcl/graph.hxx>
31 #include <vcl/virdev.hxx>
32 #include <svx/numvset.hxx>
33 #include <com/sun/star/style/NumberingType.hpp>
34 #include <com/sun/star/container/XIndexAccess.hpp>
35 #include <com/sun/star/text/XNumberingFormatter.hpp>
36 #include <com/sun/star/beans/PropertyValue.hpp>
40 #include <uiobject.hxx>
42 using namespace com::sun::star::uno
;
43 using namespace com::sun::star::beans
;
44 using namespace com::sun::star::lang
;
45 using namespace com::sun::star::text
;
46 using namespace com::sun::star::container
;
47 using namespace com::sun::star::style
;
50 // The selection of bullets from the star symbol
51 const sal_Unicode aBulletTypes
[] =
63 static vcl::Font
& lcl_GetDefaultBulletFont()
65 static vcl::Font aDefBulletFont
= [&]()
67 static vcl::Font
tmp("OpenSymbol", "", Size(0, 14));
68 tmp
.SetCharSet( RTL_TEXTENCODING_SYMBOL
);
69 tmp
.SetFamily( FAMILY_DONTKNOW
);
70 tmp
.SetPitch( PITCH_DONTKNOW
);
71 tmp
.SetWeight( WEIGHT_DONTKNOW
);
72 tmp
.SetTransparent( true );
75 return aDefBulletFont
;
78 static void lcl_PaintLevel(OutputDevice
* pVDev
, sal_Int16 nNumberingType
,
79 const OUString
& rBulletChar
, const OUString
& rText
, const OUString
& rFontName
,
80 Point
& rLeft
, vcl::Font
& rRuleFont
, const vcl::Font
& rTextFont
)
83 if(NumberingType::CHAR_SPECIAL
== nNumberingType
)
85 rRuleFont
.SetStyleName(rFontName
);
86 pVDev
->SetFont(rRuleFont
);
87 pVDev
->DrawText(rLeft
, rBulletChar
);
88 rLeft
.AdjustX(pVDev
->GetTextWidth(rBulletChar
) );
92 pVDev
->SetFont(rTextFont
);
93 pVDev
->DrawText(rLeft
, rText
);
94 rLeft
.AdjustX(pVDev
->GetTextWidth(rText
) );
98 static const char* RID_SVXSTR_BULLET_DESCRIPTIONS
[] =
100 RID_SVXSTR_BULLET_DESCRIPTION_0
,
101 RID_SVXSTR_BULLET_DESCRIPTION_1
,
102 RID_SVXSTR_BULLET_DESCRIPTION_2
,
103 RID_SVXSTR_BULLET_DESCRIPTION_3
,
104 RID_SVXSTR_BULLET_DESCRIPTION_4
,
105 RID_SVXSTR_BULLET_DESCRIPTION_5
,
106 RID_SVXSTR_BULLET_DESCRIPTION_6
,
107 RID_SVXSTR_BULLET_DESCRIPTION_7
110 static const char* RID_SVXSTR_SINGLENUM_DESCRIPTIONS
[] =
112 RID_SVXSTR_SINGLENUM_DESCRIPTION_0
,
113 RID_SVXSTR_SINGLENUM_DESCRIPTION_1
,
114 RID_SVXSTR_SINGLENUM_DESCRIPTION_2
,
115 RID_SVXSTR_SINGLENUM_DESCRIPTION_3
,
116 RID_SVXSTR_SINGLENUM_DESCRIPTION_4
,
117 RID_SVXSTR_SINGLENUM_DESCRIPTION_5
,
118 RID_SVXSTR_SINGLENUM_DESCRIPTION_6
,
119 RID_SVXSTR_SINGLENUM_DESCRIPTION_7
122 static const char* RID_SVXSTR_OUTLINENUM_DESCRIPTIONS
[] =
124 RID_SVXSTR_OUTLINENUM_DESCRIPTION_0
,
125 RID_SVXSTR_OUTLINENUM_DESCRIPTION_1
,
126 RID_SVXSTR_OUTLINENUM_DESCRIPTION_2
,
127 RID_SVXSTR_OUTLINENUM_DESCRIPTION_3
,
128 RID_SVXSTR_OUTLINENUM_DESCRIPTION_4
,
129 RID_SVXSTR_OUTLINENUM_DESCRIPTION_5
,
130 RID_SVXSTR_OUTLINENUM_DESCRIPTION_6
,
131 RID_SVXSTR_OUTLINENUM_DESCRIPTION_7
134 void SvxNumValueSet::UserDraw( const UserDrawEvent
& rUDEvt
)
136 static const sal_uInt16 aLinesArr
[] =
142 35, 90, // up to here line positions
143 5, 10, // character positions
150 const Color
aBackColor(COL_WHITE
);
151 const Color
aTextColor(COL_BLACK
);
153 vcl::RenderContext
* pDev
= rUDEvt
.GetRenderContext();
154 tools::Rectangle aRect
= rUDEvt
.GetRect();
155 sal_uInt16 nItemId
= rUDEvt
.GetItemId();
157 tools::Long nRectWidth
= aRect
.GetWidth();
158 tools::Long nRectHeight
= aRect
.GetHeight();
159 Size
aRectSize(nRectWidth
, aRect
.GetHeight());
160 Point aBLPos
= aRect
.TopLeft();
161 vcl::Font aOldFont
= pDev
->GetFont();
162 Color aOldColor
= pDev
->GetLineColor();
163 pDev
->SetLineColor(aTextColor
);
164 vcl::Font
aFont(OutputDevice::GetDefaultFont(
165 DefaultFontType::UI_SANS
, MsLangId::getSystemLanguage(), GetDefaultFontFlags::OnlyOne
));
167 Size aSize
= aFont
.GetFontSize();
169 vcl::Font
aRuleFont( lcl_GetDefaultBulletFont() );
170 aSize
.setHeight( nRectHeight
/6 );
171 aRuleFont
.SetFontSize(aSize
);
172 aRuleFont
.SetColor(aTextColor
);
173 aRuleFont
.SetFillColor(aBackColor
);
174 if(ePageType
== NumberingPageType::BULLET
)
176 else if(ePageType
== NumberingPageType::OUTLINE
)
178 aSize
.setHeight( nRectHeight
/8 );
180 aFont
.SetColor(aTextColor
);
181 aFont
.SetFillColor(aBackColor
);
182 aFont
.SetFontSize( aSize
);
183 pDev
->SetFont(aFont
);
187 // The lines are only one time in the virtual device, only the outline
188 // page is currently done
189 pVDev
= VclPtr
<VirtualDevice
>::Create(*pDev
);
190 pVDev
->SetMapMode(pDev
->GetMapMode());
191 pVDev
->EnableRTL( IsRTLEnabled() );
192 pVDev
->SetOutputSize( aRectSize
);
194 pVDev
->SetFillColor( aBackColor
);
195 pVDev
->SetLineColor(COL_LIGHTGRAY
);
196 // Draw line only once
197 if(ePageType
!= NumberingPageType::OUTLINE
)
199 Point
aStart(aBLPos
.X() + nRectWidth
*25 / 100,0);
200 Point
aEnd(aBLPos
.X() + nRectWidth
* 9 / 10,0);
201 for( sal_uInt16 i
= 11; i
< 100; i
+= 33)
203 aStart
.setY( aBLPos
.Y() + nRectHeight
* i
/ 100 );
204 aEnd
.setY( aStart
.Y() );
205 pVDev
->DrawLine(aStart
, aEnd
);
206 aStart
.setY( aBLPos
.Y() + nRectHeight
* (i
+ 11) / 100 );
207 aEnd
.setY( aStart
.Y() );
208 pVDev
->DrawLine(aStart
, aEnd
);
212 pDev
->DrawOutDev( aRect
.TopLeft(), aRectSize
,
213 aOrgRect
.TopLeft(), aRectSize
,
215 // Now comes the text
216 const OUString
sValue("Value");
217 if( NumberingPageType::SINGLENUM
== ePageType
||
218 NumberingPageType::BULLET
== ePageType
)
220 Point
aStart(aBLPos
.X() + nRectWidth
/ 9,0);
221 for( sal_uInt16 i
= 0; i
< 3; i
++ )
223 sal_uInt16 nY
= 11 + i
* 33;
224 aStart
.setY( aBLPos
.Y() + nRectHeight
* nY
/ 100 );
226 if(ePageType
== NumberingPageType::BULLET
)
228 sText
= OUString( aBulletTypes
[nItemId
- 1] );
229 aStart
.AdjustY( -(pDev
->GetTextHeight()/2) );
230 aStart
.setX( aBLPos
.X() + 5 );
234 if(xFormatter
.is() && aNumSettings
.getLength() > nItemId
- 1)
236 Sequence
<PropertyValue
> aLevel
= aNumSettings
.getConstArray()[nItemId
- 1];
239 aLevel
.realloc(aLevel
.getLength() + 1);
240 PropertyValue
& rValue
= aLevel
.getArray()[aLevel
.getLength() - 1];
241 rValue
.Name
= sValue
;
242 rValue
.Value
<<= static_cast<sal_Int32
>(i
+ 1);
243 sText
= xFormatter
->makeNumberingString( aLevel
, aLocale
);
247 TOOLS_WARN_EXCEPTION("svx.dialog", "");
250 // start just next to the left edge
251 aStart
.setX( aBLPos
.X() + 2 );
252 aStart
.AdjustY( -(pDev
->GetTextHeight()/2) );
254 pDev
->DrawText(aStart
, sText
);
257 else if(NumberingPageType::OUTLINE
== ePageType
)
259 // Outline numbering has to be painted into the virtual device
260 // to get correct lines
261 // has to be made again
262 pVDev
->SetLineColor(aBackColor
);
263 pVDev
->DrawRect(aOrgRect
);
264 tools::Long nStartX
= aOrgRect
.TopLeft().X();
265 tools::Long nStartY
= aOrgRect
.TopLeft().Y();
267 if(xFormatter
.is() && aOutlineSettings
.getLength() > nItemId
- 1)
269 Reference
<XIndexAccess
> xLevel
= aOutlineSettings
.getArray()[nItemId
- 1];
272 OUString sLevelTexts
[5];
273 OUString sFontNames
[5];
274 OUString sBulletChars
[5];
275 sal_Int16 aNumberingTypes
[5];
276 OUString sPrefixes
[5];
277 OUString sSuffixes
[5];
278 sal_Int16 aParentNumberings
[5];
280 sal_Int32 nLevelCount
= xLevel
->getCount();
283 for( sal_Int32 i
= 0; i
< nLevelCount
; i
++)
285 tools::Long nTop
= nStartY
+ nRectHeight
* (aLinesArr
[2 * i
+ 11])/100 ;
286 Point
aLeft(nStartX
+ nRectWidth
* (aLinesArr
[2 * i
+ 10])/ 100, nTop
);
288 Any aLevelAny
= xLevel
->getByIndex(i
);
289 Sequence
<PropertyValue
> aLevel
;
290 aLevelAny
>>= aLevel
;
291 aNumberingTypes
[i
] = 0;
292 aParentNumberings
[i
] = 0;
293 for(const PropertyValue
& rProp
: std::as_const(aLevel
))
295 if ( rProp
.Name
== "NumberingType" )
296 rProp
.Value
>>= aNumberingTypes
[i
];
297 else if ( rProp
.Name
== "BulletFontName" )
298 rProp
.Value
>>= sFontNames
[i
];
299 else if ( rProp
.Name
== "BulletChar" )
300 rProp
.Value
>>= sBulletChars
[i
];
301 else if ( rProp
.Name
== "Prefix" )
302 rProp
.Value
>>= sPrefixes
[i
];
303 else if ( rProp
.Name
== "Suffix" )
304 rProp
.Value
>>= sSuffixes
[i
];
305 else if ( rProp
.Name
== "ParentNumbering" )
306 rProp
.Value
>>= aParentNumberings
[i
];
308 Sequence
< PropertyValue
> aProperties(2);
309 PropertyValue
* pProperties
= aProperties
.getArray();
310 pProperties
[0].Name
= "NumberingType";
311 pProperties
[0].Value
<<= aNumberingTypes
[i
];
312 pProperties
[1].Name
= "Value";
313 pProperties
[1].Value
<<= sal_Int32(1);
316 sLevelTexts
[i
] = xFormatter
->makeNumberingString( aProperties
, aLocale
);
320 TOOLS_WARN_EXCEPTION("svx.dialog", "");
323 aLeft
.AdjustY( -(pDev
->GetTextHeight()/2) );
324 if(!sPrefixes
[i
].isEmpty() &&
327 pVDev
->SetFont(aFont
);
328 pVDev
->DrawText(aLeft
, sPrefixes
[i
]);
329 aLeft
.AdjustX(pDev
->GetTextWidth(sPrefixes
[i
]) );
331 if(aParentNumberings
[i
])
333 //insert old numberings here
334 sal_Int32 nStartLevel
= std::min(static_cast<sal_Int32
>(aParentNumberings
[i
]), i
);
335 for(sal_Int32 nParentLevel
= i
- nStartLevel
; nParentLevel
< i
; nParentLevel
++)
337 OUString sTmp
= sLevelTexts
[nParentLevel
] + ".";
338 lcl_PaintLevel(pVDev
,
339 aNumberingTypes
[nParentLevel
],
340 sBulletChars
[nParentLevel
],
342 sFontNames
[nParentLevel
],
348 lcl_PaintLevel(pVDev
,
356 if(!sSuffixes
[i
].isEmpty() &&
357 !sSuffixes
[i
].startsWith(" "))
359 pVDev
->SetFont(aFont
);
360 pVDev
->DrawText(aLeft
, sSuffixes
[i
]);
361 aLeft
.AdjustX(pDev
->GetTextWidth(sSuffixes
[i
]) );
364 tools::Long nLineTop
= nStartY
+ nRectHeight
* aLinesArr
[2 * i
+ 1]/100 ;
365 Point
aLineLeft(aLeft
.X(), nLineTop
);
366 Point
aLineRight(nStartX
+ nRectWidth
* 90 /100, nLineTop
);
367 pVDev
->SetLineColor(COL_LIGHTGRAY
);
368 pVDev
->DrawLine(aLineLeft
, aLineRight
);
375 static bool bAssert
= false;
378 TOOLS_WARN_EXCEPTION("svx.dialog", "");
388 pDev
->DrawOutDev( aRect
.TopLeft(), aRectSize
,
389 aOrgRect
.TopLeft(), aRectSize
,
393 pDev
->SetFont(aOldFont
);
394 pDev
->SetLineColor(aOldColor
);
397 SvxNumValueSet::SvxNumValueSet(std::unique_ptr
<weld::ScrolledWindow
> pScrolledWindow
)
398 : ValueSet(std::move(pScrolledWindow
))
399 , ePageType(NumberingPageType::BULLET
)
404 FactoryFunction
SvxNumValueSet::GetUITestFactory() const
406 return SvxNumValueSetUIObject::create
;
409 void SvxNumValueSet::init(NumberingPageType eType
)
416 SetStyle( GetStyle() | WB_ITEMBORDER
| WB_DOUBLEBORDER
);
417 if(NumberingPageType::BULLET
== eType
)
419 for ( sal_uInt16 i
= 0; i
< 8; i
++ )
421 InsertItem( i
+ 1, i
);
422 SetItemText(i
+ 1, SvxResId(RID_SVXSTR_BULLET_DESCRIPTIONS
[i
]));
427 SvxNumValueSet::~SvxNumValueSet()
431 void SvxNumValueSet::SetNumberingSettings(
432 const Sequence
<Sequence
<PropertyValue
> >& aNum
,
433 Reference
<XNumberingFormatter
> const & xFormat
,
434 const Locale
& rLocale
)
437 xFormatter
= xFormat
;
439 if(aNum
.getLength() > 8)
440 SetStyle( GetStyle()|WB_VSCROLL
);
441 for ( sal_Int32 i
= 0; i
< aNum
.getLength(); i
++ )
443 InsertItem( i
+ 1, i
);
445 SetItemText(i
+ 1, SvxResId(RID_SVXSTR_SINGLENUM_DESCRIPTIONS
[i
]));
449 void SvxNumValueSet::SetOutlineNumberingSettings(
450 Sequence
<Reference
<XIndexAccess
> > const & rOutline
,
451 Reference
<XNumberingFormatter
> const & xFormat
,
452 const Locale
& rLocale
)
454 aOutlineSettings
= rOutline
;
455 xFormatter
= xFormat
;
457 if(aOutlineSettings
.getLength() > 8)
458 SetStyle( GetStyle() | WB_VSCROLL
);
459 for ( sal_Int32 i
= 0; i
< aOutlineSettings
.getLength(); i
++ )
461 InsertItem( i
+ 1, i
);
463 SetItemText(i
+ 1, SvxResId(RID_SVXSTR_OUTLINENUM_DESCRIPTIONS
[i
]));
467 SvxBmpNumValueSet::SvxBmpNumValueSet(std::unique_ptr
<weld::ScrolledWindow
> pScrolledWindow
)
468 : SvxNumValueSet(std::move(pScrolledWindow
))
469 , aFormatIdle("SvxBmpNumValueSet FormatIdle")
470 , bGrfNotFound(false)
474 void SvxBmpNumValueSet::init()
476 SvxNumValueSet::init(NumberingPageType::BITMAP
);
477 bGrfNotFound
= false;
478 GalleryExplorer::BeginLocking(GALLERY_THEME_BULLETS
);
479 SetStyle( GetStyle() | WB_VSCROLL
);
481 aFormatIdle
.SetPriority(TaskPriority::LOWEST
);
482 aFormatIdle
.SetInvokeHandler(LINK(this, SvxBmpNumValueSet
, FormatHdl_Impl
));
486 SvxBmpNumValueSet::~SvxBmpNumValueSet()
488 GalleryExplorer::EndLocking(GALLERY_THEME_BULLETS
);
492 void SvxBmpNumValueSet::UserDraw(const UserDrawEvent
& rUDEvt
)
494 SvxNumValueSet::UserDraw(rUDEvt
);
496 tools::Rectangle aRect
= rUDEvt
.GetRect();
497 vcl::RenderContext
* pDev
= rUDEvt
.GetRenderContext();
498 sal_uInt16 nItemId
= rUDEvt
.GetItemId();
499 Point aBLPos
= aRect
.TopLeft();
501 tools::Long nRectHeight
= aRect
.GetHeight();
502 Size
aSize(nRectHeight
/8, nRectHeight
/8);
505 if(!GalleryExplorer::GetGraphicObj( GALLERY_THEME_BULLETS
, nItemId
- 1,
512 Point
aPos(aBLPos
.X() + 5, 0);
513 for( sal_uInt16 i
= 0; i
< 3; i
++ )
515 sal_uInt16 nY
= 11 + i
* 33;
516 aPos
.setY( aBLPos
.Y() + nRectHeight
* nY
/ 100 );
517 aGraphic
.Draw( pDev
, aPos
, aSize
);
522 IMPL_LINK_NOARG(SvxBmpNumValueSet
, FormatHdl_Impl
, Timer
*, void)
524 // only when a graphics was not there, it needs to be formatted
528 bGrfNotFound
= false;
533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */