LibreOffice Module vcl (master) 1
WidgetDefinitionReader.cxx
Go to the documentation of this file.
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 <utility>
13
14#include <sal/config.h>
15#include <osl/file.hxx>
16#include <tools/stream.hxx>
17#include <o3tl/string_view.hxx>
18#include <unordered_map>
19
20namespace vcl
21{
22namespace
23{
24bool lcl_fileExists(OUString const& sFilename)
25{
26 osl::File aFile(sFilename);
27 osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read);
28 return osl::FileBase::E_None == eRC;
29}
30
31int lcl_gethex(char aChar)
32{
33 if (aChar >= '0' && aChar <= '9')
34 return aChar - '0';
35 else if (aChar >= 'a' && aChar <= 'f')
36 return aChar - 'a' + 10;
37 else if (aChar >= 'A' && aChar <= 'F')
38 return aChar - 'A' + 10;
39 else
40 return 0;
41}
42
43bool readColor(OString const& rString, Color& rColor)
44{
45 if (rString.getLength() != 7)
46 return false;
47
48 const char aChar(rString[0]);
49
50 if (aChar != '#')
51 return false;
52
53 rColor.SetRed((lcl_gethex(rString[1]) << 4) | lcl_gethex(rString[2]));
54 rColor.SetGreen((lcl_gethex(rString[3]) << 4) | lcl_gethex(rString[4]));
55 rColor.SetBlue((lcl_gethex(rString[5]) << 4) | lcl_gethex(rString[6]));
56
57 return true;
58}
59
60bool readSetting(OString const& rInputString, OString& rOutputString)
61{
62 if (!rInputString.isEmpty())
63 rOutputString = rInputString;
64 return true;
65}
66
67OString getValueOrAny(OString const& rInputString)
68{
69 if (rInputString.isEmpty())
70 return "any";
71 return rInputString;
72}
73
74ControlPart xmlStringToControlPart(std::string_view sPart)
75{
76 if (o3tl::equalsIgnoreAsciiCase(sPart, "NONE"))
77 return ControlPart::NONE;
78 else if (o3tl::equalsIgnoreAsciiCase(sPart, "Entire"))
80 else if (o3tl::equalsIgnoreAsciiCase(sPart, "ListboxWindow"))
82 else if (o3tl::equalsIgnoreAsciiCase(sPart, "Button"))
84 else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonUp"))
86 else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonDown"))
88 else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonLeft"))
90 else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonRight"))
92 else if (o3tl::equalsIgnoreAsciiCase(sPart, "AllButtons"))
94 else if (o3tl::equalsIgnoreAsciiCase(sPart, "SeparatorHorz"))
96 else if (o3tl::equalsIgnoreAsciiCase(sPart, "SeparatorVert"))
98 else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackHorzLeft"))
100 else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackVertUpper"))
102 else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackHorzRight"))
104 else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackVertLower"))
106 else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackHorzArea"))
108 else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackVertArea"))
110 else if (o3tl::equalsIgnoreAsciiCase(sPart, "Arrow"))
111 return ControlPart::Arrow;
112 else if (o3tl::equalsIgnoreAsciiCase(sPart, "ThumbHorz"))
114 else if (o3tl::equalsIgnoreAsciiCase(sPart, "ThumbVert"))
116 else if (o3tl::equalsIgnoreAsciiCase(sPart, "MenuItem"))
118 else if (o3tl::equalsIgnoreAsciiCase(sPart, "MenuItemCheckMark"))
120 else if (o3tl::equalsIgnoreAsciiCase(sPart, "MenuItemRadioMark"))
122 else if (o3tl::equalsIgnoreAsciiCase(sPart, "Separator"))
124 else if (o3tl::equalsIgnoreAsciiCase(sPart, "SubmenuArrow"))
126 else if (o3tl::equalsIgnoreAsciiCase(sPart, "SubEdit"))
128 else if (o3tl::equalsIgnoreAsciiCase(sPart, "DrawBackgroundHorz"))
130 else if (o3tl::equalsIgnoreAsciiCase(sPart, "DrawBackgroundVert"))
132 else if (o3tl::equalsIgnoreAsciiCase(sPart, "TabsDrawRtl"))
134 else if (o3tl::equalsIgnoreAsciiCase(sPart, "HasBackgroundTexture"))
136 else if (o3tl::equalsIgnoreAsciiCase(sPart, "HasThreeButtons"))
138 else if (o3tl::equalsIgnoreAsciiCase(sPart, "BackgroundWindow"))
140 else if (o3tl::equalsIgnoreAsciiCase(sPart, "BackgroundDialog"))
142 else if (o3tl::equalsIgnoreAsciiCase(sPart, "Border"))
143 return ControlPart::Border;
144 else if (o3tl::equalsIgnoreAsciiCase(sPart, "Focus"))
145 return ControlPart::Focus;
146 return ControlPart::NONE;
147}
148
149bool getControlTypeForXmlString(OString const& rString, ControlType& reType)
150{
151 static std::unordered_map<OString, ControlType> aPartMap = {
152 { "pushbutton", ControlType::Pushbutton },
153 { "radiobutton", ControlType::Radiobutton },
154 { "checkbox", ControlType::Checkbox },
155 { "combobox", ControlType::Combobox },
156 { "editbox", ControlType::Editbox },
157 { "listbox", ControlType::Listbox },
158 { "scrollbar", ControlType::Scrollbar },
159 { "spinbox", ControlType::Spinbox },
160 { "slider", ControlType::Slider },
161 { "fixedline", ControlType::Fixedline },
162 { "progress", ControlType::Progress },
163 { "tabitem", ControlType::TabItem },
164 { "tabheader", ControlType::TabHeader },
165 { "tabpane", ControlType::TabPane },
166 { "tabbody", ControlType::TabBody },
167 { "frame", ControlType::Frame },
168 { "windowbackground", ControlType::WindowBackground },
169 { "toolbar", ControlType::Toolbar },
170 { "listnode", ControlType::ListNode },
171 { "listnet", ControlType::ListNet },
172 { "listheader", ControlType::ListHeader },
173 { "menubar", ControlType::Menubar },
174 { "menupopup", ControlType::MenuPopup },
175 { "tooltip", ControlType::Tooltip },
176 };
177
178 auto const& rIterator = aPartMap.find(rString);
179 if (rIterator != aPartMap.end())
180 {
181 reType = rIterator->second;
182 return true;
183 }
184 return false;
185}
186
187} // end anonymous namespace
188
189WidgetDefinitionReader::WidgetDefinitionReader(OUString aDefinitionFile, OUString aResourcePath)
190 : m_rDefinitionFile(std::move(aDefinitionFile))
191 , m_rResourcePath(std::move(aResourcePath))
192{
193}
194
196 tools::XmlWalker& rWalker, const std::shared_ptr<WidgetDefinitionState>& rpState)
197{
198 rWalker.children();
199 while (rWalker.isValid())
200 {
201 if (rWalker.name() == "rect")
202 {
203 Color aStrokeColor;
204 readColor(rWalker.attribute("stroke"), aStrokeColor);
205 Color aFillColor;
206 readColor(rWalker.attribute("fill"), aFillColor);
207 OString sStrokeWidth = rWalker.attribute("stroke-width");
208 sal_Int32 nStrokeWidth = -1;
209 if (!sStrokeWidth.isEmpty())
210 nStrokeWidth = sStrokeWidth.toInt32();
211
212 sal_Int32 nRx = -1;
213 OString sRx = rWalker.attribute("rx");
214 if (!sRx.isEmpty())
215 nRx = sRx.toInt32();
216
217 sal_Int32 nRy = -1;
218 OString sRy = rWalker.attribute("ry");
219 if (!sRy.isEmpty())
220 nRy = sRy.toInt32();
221
222 OString sX1 = rWalker.attribute("x1");
223 float fX1 = sX1.isEmpty() ? 0.0 : sX1.toFloat();
224
225 OString sY1 = rWalker.attribute("y1");
226 float fY1 = sY1.isEmpty() ? 0.0 : sY1.toFloat();
227
228 OString sX2 = rWalker.attribute("x2");
229 float fX2 = sX2.isEmpty() ? 1.0 : sX2.toFloat();
230
231 OString sY2 = rWalker.attribute("y2");
232 float fY2 = sY2.isEmpty() ? 1.0 : sY2.toFloat();
233
234 rpState->addDrawRectangle(aStrokeColor, nStrokeWidth, aFillColor, fX1, fY1, fX2, fY2,
235 nRx, nRy);
236 }
237 else if (rWalker.name() == "line")
238 {
239 Color aStrokeColor;
240 readColor(rWalker.attribute("stroke"), aStrokeColor);
241
242 OString sStrokeWidth = rWalker.attribute("stroke-width");
243 sal_Int32 nStrokeWidth = -1;
244 if (!sStrokeWidth.isEmpty())
245 nStrokeWidth = sStrokeWidth.toInt32();
246
247 OString sX1 = rWalker.attribute("x1");
248 float fX1 = sX1.isEmpty() ? -1.0 : sX1.toFloat();
249
250 OString sY1 = rWalker.attribute("y1");
251 float fY1 = sY1.isEmpty() ? -1.0 : sY1.toFloat();
252
253 OString sX2 = rWalker.attribute("x2");
254 float fX2 = sX2.isEmpty() ? -1.0 : sX2.toFloat();
255
256 OString sY2 = rWalker.attribute("y2");
257 float fY2 = sY2.isEmpty() ? -1.0 : sY2.toFloat();
258
259 rpState->addDrawLine(aStrokeColor, nStrokeWidth, fX1, fY1, fX2, fY2);
260 }
261 else if (rWalker.name() == "image")
262 {
263 OString sSource = rWalker.attribute("source");
264 rpState->addDrawImage(m_rResourcePath
265 + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
266 }
267 else if (rWalker.name() == "external")
268 {
269 OString sSource = rWalker.attribute("source");
270 rpState->addDrawExternal(m_rResourcePath
271 + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
272 }
273 rWalker.next();
274 }
275 rWalker.parent();
276}
277
279 WidgetDefinition& rWidgetDefinition, ControlType eType)
280{
281 rWalker.children();
282 while (rWalker.isValid())
283 {
284 if (rWalker.name() == "part")
285 {
286 OString sPart = rWalker.attribute("value");
287 ControlPart ePart = xmlStringToControlPart(sPart);
288
289 std::shared_ptr<WidgetDefinitionPart> pPart = std::make_shared<WidgetDefinitionPart>();
290
291 OString sWidth = rWalker.attribute("width");
292 if (!sWidth.isEmpty())
293 {
294 sal_Int32 nWidth = sWidth.isEmpty() ? 0 : sWidth.toInt32();
295 pPart->mnWidth = nWidth;
296 }
297
298 OString sHeight = rWalker.attribute("height");
299 if (!sHeight.isEmpty())
300 {
301 sal_Int32 nHeight = sHeight.isEmpty() ? 0 : sHeight.toInt32();
302 pPart->mnHeight = nHeight;
303 }
304
305 OString sMarginHeight = rWalker.attribute("margin-height");
306 if (!sMarginHeight.isEmpty())
307 {
308 sal_Int32 nMarginHeight = sMarginHeight.isEmpty() ? 0 : sMarginHeight.toInt32();
309 pPart->mnMarginHeight = nMarginHeight;
310 }
311
312 OString sMarginWidth = rWalker.attribute("margin-width");
313 if (!sMarginWidth.isEmpty())
314 {
315 sal_Int32 nMarginWidth = sMarginWidth.isEmpty() ? 0 : sMarginWidth.toInt32();
316 pPart->mnMarginWidth = nMarginWidth;
317 }
318
319 OString sOrientation = rWalker.attribute("orientation");
320 if (!sOrientation.isEmpty())
321 {
322 pPart->msOrientation = sOrientation;
323 }
324
325 rWidgetDefinition.maDefinitions.emplace(ControlTypeAndPart(eType, ePart), pPart);
326 readPart(rWalker, pPart);
327 }
328 rWalker.next();
329 }
330 rWalker.parent();
331}
332
334 std::shared_ptr<WidgetDefinitionPart> rpPart)
335{
336 rWalker.children();
337 while (rWalker.isValid())
338 {
339 if (rWalker.name() == "state")
340 {
341 OString sEnabled = getValueOrAny(rWalker.attribute("enabled"));
342 OString sFocused = getValueOrAny(rWalker.attribute("focused"));
343 OString sPressed = getValueOrAny(rWalker.attribute("pressed"));
344 OString sRollover = getValueOrAny(rWalker.attribute("rollover"));
345 OString sDefault = getValueOrAny(rWalker.attribute("default"));
346 OString sSelected = getValueOrAny(rWalker.attribute("selected"));
347 OString sButtonValue = getValueOrAny(rWalker.attribute("button-value"));
348 OString sExtra = getValueOrAny(rWalker.attribute("extra"));
349
350 std::shared_ptr<WidgetDefinitionState> pState = std::make_shared<WidgetDefinitionState>(
351 sEnabled, sFocused, sPressed, sRollover, sDefault, sSelected, sButtonValue, sExtra);
352
353 rpPart->maStates.push_back(pState);
354 readDrawingDefinition(rWalker, pState);
355 }
356 rWalker.next();
357 }
358 rWalker.parent();
359}
360
362{
363 if (!lcl_fileExists(m_rDefinitionFile))
364 return false;
365
366 auto pStyle = std::make_shared<WidgetDefinitionStyle>();
367
368 std::unordered_map<OString, Color*> aStyleColorMap = {
369 { "faceColor", &pStyle->maFaceColor },
370 { "checkedColor", &pStyle->maCheckedColor },
371 { "lightColor", &pStyle->maLightColor },
372 { "lightBorderColor", &pStyle->maLightBorderColor },
373 { "shadowColor", &pStyle->maShadowColor },
374 { "darkShadowColor", &pStyle->maDarkShadowColor },
375 { "buttonTextColor", &pStyle->maButtonTextColor },
376 { "defaultActionButtonTextColor", &pStyle->maDefaultActionButtonTextColor },
377 { "actionButtonTextColor", &pStyle->maActionButtonTextColor },
378 { "actionButtonRolloverTextColor", &pStyle->maActionButtonRolloverTextColor },
379 { "buttonRolloverTextColor", &pStyle->maButtonRolloverTextColor },
380 { "radioCheckTextColor", &pStyle->maRadioCheckTextColor },
381 { "groupTextColor", &pStyle->maGroupTextColor },
382 { "labelTextColor", &pStyle->maLabelTextColor },
383 { "windowColor", &pStyle->maWindowColor },
384 { "windowTextColor", &pStyle->maWindowTextColor },
385 { "dialogColor", &pStyle->maDialogColor },
386 { "dialogTextColor", &pStyle->maDialogTextColor },
387 { "workspaceColor", &pStyle->maWorkspaceColor },
388 { "monoColor", &pStyle->maMonoColor },
389 { "fieldColor", &pStyle->maFieldColor },
390 { "fieldTextColor", &pStyle->maFieldTextColor },
391 { "fieldRolloverTextColor", &pStyle->maFieldRolloverTextColor },
392 { "activeColor", &pStyle->maActiveColor },
393 { "activeTextColor", &pStyle->maActiveTextColor },
394 { "activeBorderColor", &pStyle->maActiveBorderColor },
395 { "deactiveColor", &pStyle->maDeactiveColor },
396 { "deactiveTextColor", &pStyle->maDeactiveTextColor },
397 { "deactiveBorderColor", &pStyle->maDeactiveBorderColor },
398 { "menuColor", &pStyle->maMenuColor },
399 { "menuBarColor", &pStyle->maMenuBarColor },
400 { "menuBarRolloverColor", &pStyle->maMenuBarRolloverColor },
401 { "menuBorderColor", &pStyle->maMenuBorderColor },
402 { "menuTextColor", &pStyle->maMenuTextColor },
403 { "menuBarTextColor", &pStyle->maMenuBarTextColor },
404 { "menuBarRolloverTextColor", &pStyle->maMenuBarRolloverTextColor },
405 { "menuBarHighlightTextColor", &pStyle->maMenuBarHighlightTextColor },
406 { "menuHighlightColor", &pStyle->maMenuHighlightColor },
407 { "menuHighlightTextColor", &pStyle->maMenuHighlightTextColor },
408 { "highlightColor", &pStyle->maHighlightColor },
409 { "highlightTextColor", &pStyle->maHighlightTextColor },
410 { "activeTabColor", &pStyle->maActiveTabColor },
411 { "inactiveTabColor", &pStyle->maInactiveTabColor },
412 { "tabTextColor", &pStyle->maTabTextColor },
413 { "tabRolloverTextColor", &pStyle->maTabRolloverTextColor },
414 { "tabHighlightTextColor", &pStyle->maTabHighlightTextColor },
415 { "disableColor", &pStyle->maDisableColor },
416 { "helpColor", &pStyle->maHelpColor },
417 { "helpTextColor", &pStyle->maHelpTextColor },
418 { "linkColor", &pStyle->maLinkColor },
419 { "visitedLinkColor", &pStyle->maVisitedLinkColor },
420 { "toolTextColor", &pStyle->maToolTextColor },
421 { "fontColor", &pStyle->maFontColor },
422 };
423
424 rWidgetDefinition.mpStyle = pStyle;
425
426 auto pSettings = std::make_shared<WidgetDefinitionSettings>();
427
428 std::unordered_map<OString, OString*> aSettingMap = {
429 { "noActiveTabTextRaise", &pSettings->msNoActiveTabTextRaise },
430 { "centeredTabs", &pSettings->msCenteredTabs },
431 { "listBoxEntryMargin", &pSettings->msListBoxEntryMargin },
432 { "defaultFontSize", &pSettings->msDefaultFontSize },
433 { "titleHeight", &pSettings->msTitleHeight },
434 { "floatTitleHeight", &pSettings->msFloatTitleHeight },
435 { "listBoxPreviewDefaultLogicWidth", &pSettings->msListBoxPreviewDefaultLogicWidth },
436 { "listBoxPreviewDefaultLogicHeight", &pSettings->msListBoxPreviewDefaultLogicHeight },
437 };
438
439 rWidgetDefinition.mpSettings = pSettings;
440
441 SvFileStream aFileStream(m_rDefinitionFile, StreamMode::READ);
442
443 tools::XmlWalker aWalker;
444 if (!aWalker.open(&aFileStream))
445 return false;
446
447 if (aWalker.name() != "widgets")
448 return false;
449
450 aWalker.children();
451 while (aWalker.isValid())
452 {
454 if (aWalker.name() == "style")
455 {
456 aWalker.children();
457 while (aWalker.isValid())
458 {
459 auto pair = aStyleColorMap.find(aWalker.name());
460 if (pair != aStyleColorMap.end())
461 {
462 readColor(aWalker.attribute("value"), *pair->second);
463 }
464 aWalker.next();
465 }
466 aWalker.parent();
467 }
468 if (aWalker.name() == "settings")
469 {
470 aWalker.children();
471 while (aWalker.isValid())
472 {
473 auto pair = aSettingMap.find(aWalker.name());
474 if (pair != aSettingMap.end())
475 {
476 readSetting(aWalker.attribute("value"), *pair->second);
477 }
478 aWalker.next();
479 }
480 aWalker.parent();
481 }
482 else if (getControlTypeForXmlString(aWalker.name(), eType))
483 {
484 readDefinition(aWalker, rWidgetDefinition, eType);
485 }
486 aWalker.next();
487 }
488 aWalker.parent();
489
490 return true;
491}
492
493} // end vcl namespace
494
495/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
@ SubEdit
The edit field part of a control, e.g.
@ HasBackgroundTexture
ControlType
These types are all based on the supported variants vcl/salnativewidgets.hxx and must be kept in-sync...
void SetGreen(sal_uInt8 nGreen)
void SetRed(sal_uInt8 nRed)
void SetBlue(sal_uInt8 nBlue)
OString attribute(const OString &sName) const
bool isValid() const
bool open(SvStream *pStream)
void readDefinition(tools::XmlWalker &rWalker, WidgetDefinition &rWidgetDefinition, ControlType eType)
void readDrawingDefinition(tools::XmlWalker &rWalker, const std::shared_ptr< WidgetDefinitionState > &rStates)
void readPart(tools::XmlWalker &rWalker, std::shared_ptr< WidgetDefinitionPart > rpPart)
WidgetDefinitionReader(OUString aDefinitionFile, OUString aResourcePath)
bool read(WidgetDefinition &rWidgetDefinition)
std::unordered_map< ControlTypeAndPart, std::shared_ptr< WidgetDefinitionPart > > maDefinitions
std::shared_ptr< WidgetDefinitionStyle > mpStyle
std::shared_ptr< WidgetDefinitionSettings > mpSettings
DocumentType eType
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)