bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / gdi / WidgetDefinitionReader.cxx
blob7d3fb7c4c8f34e554e6e94161e89ad9e048d4323
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 */
11 #include <widgetdraw/WidgetDefinitionReader.hxx>
13 #include <sal/config.h>
14 #include <osl/file.hxx>
15 #include <tools/stream.hxx>
16 #include <unordered_map>
18 namespace vcl
20 namespace
22 bool lcl_fileExists(OUString const& sFilename)
24 osl::File aFile(sFilename);
25 osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read);
26 return osl::FileBase::E_None == eRC;
29 int lcl_gethex(char aChar)
31 if (aChar >= '0' && aChar <= '9')
32 return aChar - '0';
33 else if (aChar >= 'a' && aChar <= 'f')
34 return aChar - 'a' + 10;
35 else if (aChar >= 'A' && aChar <= 'F')
36 return aChar - 'A' + 10;
37 else
38 return 0;
41 bool readColor(OString const& rString, Color& rColor)
43 if (rString.getLength() != 7)
44 return false;
46 const char aChar(rString[0]);
48 if (aChar != '#')
49 return false;
51 rColor.SetRed((lcl_gethex(rString[1]) << 4) | lcl_gethex(rString[2]));
52 rColor.SetGreen((lcl_gethex(rString[3]) << 4) | lcl_gethex(rString[4]));
53 rColor.SetBlue((lcl_gethex(rString[5]) << 4) | lcl_gethex(rString[6]));
55 return true;
58 bool readSetting(OString const& rInputString, OString& rOutputString)
60 if (!rInputString.isEmpty())
61 rOutputString = rInputString;
62 return true;
65 OString getValueOrAny(OString const& rInputString)
67 if (rInputString.isEmpty())
68 return "any";
69 return rInputString;
72 ControlPart xmlStringToControlPart(OString const& sPart)
74 if (sPart.equalsIgnoreAsciiCase("NONE"))
75 return ControlPart::NONE;
76 else if (sPart.equalsIgnoreAsciiCase("Entire"))
77 return ControlPart::Entire;
78 else if (sPart.equalsIgnoreAsciiCase("ListboxWindow"))
79 return ControlPart::ListboxWindow;
80 else if (sPart.equalsIgnoreAsciiCase("Button"))
81 return ControlPart::Button;
82 else if (sPart.equalsIgnoreAsciiCase("ButtonUp"))
83 return ControlPart::ButtonUp;
84 else if (sPart.equalsIgnoreAsciiCase("ButtonDown"))
85 return ControlPart::ButtonDown;
86 else if (sPart.equalsIgnoreAsciiCase("ButtonLeft"))
87 return ControlPart::ButtonLeft;
88 else if (sPart.equalsIgnoreAsciiCase("ButtonRight"))
89 return ControlPart::ButtonRight;
90 else if (sPart.equalsIgnoreAsciiCase("AllButtons"))
91 return ControlPart::AllButtons;
92 else if (sPart.equalsIgnoreAsciiCase("SeparatorHorz"))
93 return ControlPart::SeparatorHorz;
94 else if (sPart.equalsIgnoreAsciiCase("SeparatorVert"))
95 return ControlPart::SeparatorVert;
96 else if (sPart.equalsIgnoreAsciiCase("TrackHorzLeft"))
97 return ControlPart::TrackHorzLeft;
98 else if (sPart.equalsIgnoreAsciiCase("TrackVertUpper"))
99 return ControlPart::TrackVertUpper;
100 else if (sPart.equalsIgnoreAsciiCase("TrackHorzRight"))
101 return ControlPart::TrackHorzRight;
102 else if (sPart.equalsIgnoreAsciiCase("TrackVertLower"))
103 return ControlPart::TrackVertLower;
104 else if (sPart.equalsIgnoreAsciiCase("TrackHorzArea"))
105 return ControlPart::TrackHorzArea;
106 else if (sPart.equalsIgnoreAsciiCase("TrackVertArea"))
107 return ControlPart::TrackVertArea;
108 else if (sPart.equalsIgnoreAsciiCase("Arrow"))
109 return ControlPart::Arrow;
110 else if (sPart.equalsIgnoreAsciiCase("ThumbHorz"))
111 return ControlPart::ThumbHorz;
112 else if (sPart.equalsIgnoreAsciiCase("ThumbVert"))
113 return ControlPart::ThumbVert;
114 else if (sPart.equalsIgnoreAsciiCase("MenuItem"))
115 return ControlPart::MenuItem;
116 else if (sPart.equalsIgnoreAsciiCase("MenuItemCheckMark"))
117 return ControlPart::MenuItemCheckMark;
118 else if (sPart.equalsIgnoreAsciiCase("MenuItemRadioMark"))
119 return ControlPart::MenuItemRadioMark;
120 else if (sPart.equalsIgnoreAsciiCase("Separator"))
121 return ControlPart::Separator;
122 else if (sPart.equalsIgnoreAsciiCase("SubmenuArrow"))
123 return ControlPart::SubmenuArrow;
124 else if (sPart.equalsIgnoreAsciiCase("SubEdit"))
125 return ControlPart::SubEdit;
126 else if (sPart.equalsIgnoreAsciiCase("DrawBackgroundHorz"))
127 return ControlPart::DrawBackgroundHorz;
128 else if (sPart.equalsIgnoreAsciiCase("DrawBackgroundVert"))
129 return ControlPart::DrawBackgroundVert;
130 else if (sPart.equalsIgnoreAsciiCase("TabsDrawRtl"))
131 return ControlPart::TabsDrawRtl;
132 else if (sPart.equalsIgnoreAsciiCase("HasBackgroundTexture"))
133 return ControlPart::HasBackgroundTexture;
134 else if (sPart.equalsIgnoreAsciiCase("HasThreeButtons"))
135 return ControlPart::HasThreeButtons;
136 else if (sPart.equalsIgnoreAsciiCase("BackgroundWindow"))
137 return ControlPart::BackgroundWindow;
138 else if (sPart.equalsIgnoreAsciiCase("BackgroundDialog"))
139 return ControlPart::BackgroundDialog;
140 else if (sPart.equalsIgnoreAsciiCase("Border"))
141 return ControlPart::Border;
142 else if (sPart.equalsIgnoreAsciiCase("Focus"))
143 return ControlPart::Focus;
144 return ControlPart::NONE;
147 bool getControlTypeForXmlString(OString const& rString, ControlType& reType)
149 static std::unordered_map<OString, ControlType> aPartMap = {
150 { "pushbutton", ControlType::Pushbutton },
151 { "radiobutton", ControlType::Radiobutton },
152 { "checkbox", ControlType::Checkbox },
153 { "combobox", ControlType::Combobox },
154 { "editbox", ControlType::Editbox },
155 { "listbox", ControlType::Listbox },
156 { "scrollbar", ControlType::Scrollbar },
157 { "spinbox", ControlType::Spinbox },
158 { "slider", ControlType::Slider },
159 { "fixedline", ControlType::Fixedline },
160 { "progress", ControlType::Progress },
161 { "tabitem", ControlType::TabItem },
162 { "tabheader", ControlType::TabHeader },
163 { "tabpane", ControlType::TabPane },
164 { "tabbody", ControlType::TabBody },
165 { "frame", ControlType::Frame },
166 { "windowbackground", ControlType::WindowBackground },
167 { "toolbar", ControlType::Toolbar },
168 { "listnode", ControlType::ListNode },
169 { "listnet", ControlType::ListNet },
170 { "listheader", ControlType::ListHeader },
171 { "menubar", ControlType::Menubar },
172 { "menupopup", ControlType::MenuPopup },
173 { "tooltip", ControlType::Tooltip },
176 auto const& rIterator = aPartMap.find(rString);
177 if (rIterator != aPartMap.end())
179 reType = rIterator->second;
180 return true;
182 return false;
185 } // end anonymous namespace
187 WidgetDefinitionReader::WidgetDefinitionReader(OUString const& rDefinitionFile,
188 OUString const& rResourcePath)
189 : m_rDefinitionFile(rDefinitionFile)
190 , m_rResourcePath(rResourcePath)
194 void WidgetDefinitionReader::readDrawingDefinition(
195 tools::XmlWalker& rWalker, const std::shared_ptr<WidgetDefinitionState>& rpState)
197 rWalker.children();
198 while (rWalker.isValid())
200 if (rWalker.name() == "rect")
202 Color aStrokeColor;
203 readColor(rWalker.attribute("stroke"), aStrokeColor);
204 Color aFillColor;
205 readColor(rWalker.attribute("fill"), aFillColor);
206 OString sStrokeWidth = rWalker.attribute("stroke-width");
207 sal_Int32 nStrokeWidth = -1;
208 if (!sStrokeWidth.isEmpty())
209 nStrokeWidth = sStrokeWidth.toInt32();
211 sal_Int32 nRx = -1;
212 OString sRx = rWalker.attribute("rx");
213 if (!sRx.isEmpty())
214 nRx = sRx.toInt32();
216 sal_Int32 nRy = -1;
217 OString sRy = rWalker.attribute("ry");
218 if (!sRy.isEmpty())
219 nRy = sRy.toInt32();
221 OString sX1 = rWalker.attribute("x1");
222 float fX1 = sX1.isEmpty() ? 0.0 : sX1.toFloat();
224 OString sY1 = rWalker.attribute("y1");
225 float fY1 = sY1.isEmpty() ? 0.0 : sY1.toFloat();
227 OString sX2 = rWalker.attribute("x2");
228 float fX2 = sX2.isEmpty() ? 1.0 : sX2.toFloat();
230 OString sY2 = rWalker.attribute("y2");
231 float fY2 = sY2.isEmpty() ? 1.0 : sY2.toFloat();
233 rpState->addDrawRectangle(aStrokeColor, nStrokeWidth, aFillColor, fX1, fY1, fX2, fY2,
234 nRx, nRy);
236 else if (rWalker.name() == "line")
238 Color aStrokeColor;
239 readColor(rWalker.attribute("stroke"), aStrokeColor);
241 OString sStrokeWidth = rWalker.attribute("stroke-width");
242 sal_Int32 nStrokeWidth = -1;
243 if (!sStrokeWidth.isEmpty())
244 nStrokeWidth = sStrokeWidth.toInt32();
246 OString sX1 = rWalker.attribute("x1");
247 float fX1 = sX1.isEmpty() ? -1.0 : sX1.toFloat();
249 OString sY1 = rWalker.attribute("y1");
250 float fY1 = sY1.isEmpty() ? -1.0 : sY1.toFloat();
252 OString sX2 = rWalker.attribute("x2");
253 float fX2 = sX2.isEmpty() ? -1.0 : sX2.toFloat();
255 OString sY2 = rWalker.attribute("y2");
256 float fY2 = sY2.isEmpty() ? -1.0 : sY2.toFloat();
258 rpState->addDrawLine(aStrokeColor, nStrokeWidth, fX1, fY1, fX2, fY2);
260 else if (rWalker.name() == "image")
262 OString sSource = rWalker.attribute("source");
263 rpState->addDrawImage(m_rResourcePath
264 + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
266 else if (rWalker.name() == "external")
268 OString sSource = rWalker.attribute("source");
269 rpState->addDrawExternal(m_rResourcePath
270 + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
272 rWalker.next();
274 rWalker.parent();
277 void WidgetDefinitionReader::readDefinition(tools::XmlWalker& rWalker,
278 WidgetDefinition& rWidgetDefinition, ControlType eType)
280 rWalker.children();
281 while (rWalker.isValid())
283 if (rWalker.name() == "part")
285 OString sPart = rWalker.attribute("value");
286 ControlPart ePart = xmlStringToControlPart(sPart);
288 std::shared_ptr<WidgetDefinitionPart> pPart = std::make_shared<WidgetDefinitionPart>();
290 OString sWidth = rWalker.attribute("width");
291 if (!sWidth.isEmpty())
293 sal_Int32 nWidth = sWidth.isEmpty() ? 0 : sWidth.toInt32();
294 pPart->mnWidth = nWidth;
297 OString sHeight = rWalker.attribute("height");
298 if (!sHeight.isEmpty())
300 sal_Int32 nHeight = sHeight.isEmpty() ? 0 : sHeight.toInt32();
301 pPart->mnHeight = nHeight;
304 OString sMarginHeight = rWalker.attribute("margin-height");
305 if (!sMarginHeight.isEmpty())
307 sal_Int32 nMarginHeight = sMarginHeight.isEmpty() ? 0 : sMarginHeight.toInt32();
308 pPart->mnMarginHeight = nMarginHeight;
311 OString sMarginWidth = rWalker.attribute("margin-width");
312 if (!sMarginWidth.isEmpty())
314 sal_Int32 nMarginWidth = sMarginWidth.isEmpty() ? 0 : sMarginWidth.toInt32();
315 pPart->mnMarginWidth = nMarginWidth;
318 OString sOrientation = rWalker.attribute("orientation");
319 if (!sOrientation.isEmpty())
321 pPart->msOrientation = sOrientation;
324 rWidgetDefinition.maDefinitions.emplace(ControlTypeAndPart(eType, ePart), pPart);
325 readPart(rWalker, pPart);
327 rWalker.next();
329 rWalker.parent();
332 void WidgetDefinitionReader::readPart(tools::XmlWalker& rWalker,
333 std::shared_ptr<WidgetDefinitionPart> rpPart)
335 rWalker.children();
336 while (rWalker.isValid())
338 if (rWalker.name() == "state")
340 OString sEnabled = getValueOrAny(rWalker.attribute("enabled"));
341 OString sFocused = getValueOrAny(rWalker.attribute("focused"));
342 OString sPressed = getValueOrAny(rWalker.attribute("pressed"));
343 OString sRollover = getValueOrAny(rWalker.attribute("rollover"));
344 OString sDefault = getValueOrAny(rWalker.attribute("default"));
345 OString sSelected = getValueOrAny(rWalker.attribute("selected"));
346 OString sButtonValue = getValueOrAny(rWalker.attribute("button-value"));
347 OString sExtra = getValueOrAny(rWalker.attribute("extra"));
349 std::shared_ptr<WidgetDefinitionState> pState = std::make_shared<WidgetDefinitionState>(
350 sEnabled, sFocused, sPressed, sRollover, sDefault, sSelected, sButtonValue, sExtra);
352 rpPart->maStates.push_back(pState);
353 readDrawingDefinition(rWalker, pState);
355 rWalker.next();
357 rWalker.parent();
360 bool WidgetDefinitionReader::read(WidgetDefinition& rWidgetDefinition)
362 if (!lcl_fileExists(m_rDefinitionFile))
363 return false;
365 auto pStyle = std::make_shared<WidgetDefinitionStyle>();
367 std::unordered_map<OString, Color*> aStyleColorMap = {
368 { "faceColor", &pStyle->maFaceColor },
369 { "checkedColor", &pStyle->maCheckedColor },
370 { "lightColor", &pStyle->maLightColor },
371 { "lightBorderColor", &pStyle->maLightBorderColor },
372 { "shadowColor", &pStyle->maShadowColor },
373 { "darkShadowColor", &pStyle->maDarkShadowColor },
374 { "buttonTextColor", &pStyle->maButtonTextColor },
375 { "defaultActionButtonTextColor", &pStyle->maDefaultActionButtonTextColor },
376 { "actionButtonTextColor", &pStyle->maActionButtonTextColor },
377 { "actionButtonRolloverTextColor", &pStyle->maActionButtonRolloverTextColor },
378 { "buttonRolloverTextColor", &pStyle->maButtonRolloverTextColor },
379 { "radioCheckTextColor", &pStyle->maRadioCheckTextColor },
380 { "groupTextColor", &pStyle->maGroupTextColor },
381 { "labelTextColor", &pStyle->maLabelTextColor },
382 { "windowColor", &pStyle->maWindowColor },
383 { "windowTextColor", &pStyle->maWindowTextColor },
384 { "dialogColor", &pStyle->maDialogColor },
385 { "dialogTextColor", &pStyle->maDialogTextColor },
386 { "workspaceColor", &pStyle->maWorkspaceColor },
387 { "monoColor", &pStyle->maMonoColor },
388 { "fieldColor", &pStyle->maFieldColor },
389 { "fieldTextColor", &pStyle->maFieldTextColor },
390 { "fieldRolloverTextColor", &pStyle->maFieldRolloverTextColor },
391 { "activeColor", &pStyle->maActiveColor },
392 { "activeTextColor", &pStyle->maActiveTextColor },
393 { "activeBorderColor", &pStyle->maActiveBorderColor },
394 { "deactiveColor", &pStyle->maDeactiveColor },
395 { "deactiveTextColor", &pStyle->maDeactiveTextColor },
396 { "deactiveBorderColor", &pStyle->maDeactiveBorderColor },
397 { "menuColor", &pStyle->maMenuColor },
398 { "menuBarColor", &pStyle->maMenuBarColor },
399 { "menuBarRolloverColor", &pStyle->maMenuBarRolloverColor },
400 { "menuBorderColor", &pStyle->maMenuBorderColor },
401 { "menuTextColor", &pStyle->maMenuTextColor },
402 { "menuBarTextColor", &pStyle->maMenuBarTextColor },
403 { "menuBarRolloverTextColor", &pStyle->maMenuBarRolloverTextColor },
404 { "menuBarHighlightTextColor", &pStyle->maMenuBarHighlightTextColor },
405 { "menuHighlightColor", &pStyle->maMenuHighlightColor },
406 { "menuHighlightTextColor", &pStyle->maMenuHighlightTextColor },
407 { "highlightColor", &pStyle->maHighlightColor },
408 { "highlightTextColor", &pStyle->maHighlightTextColor },
409 { "activeTabColor", &pStyle->maActiveTabColor },
410 { "inactiveTabColor", &pStyle->maInactiveTabColor },
411 { "tabTextColor", &pStyle->maTabTextColor },
412 { "tabRolloverTextColor", &pStyle->maTabRolloverTextColor },
413 { "tabHighlightTextColor", &pStyle->maTabHighlightTextColor },
414 { "disableColor", &pStyle->maDisableColor },
415 { "helpColor", &pStyle->maHelpColor },
416 { "helpTextColor", &pStyle->maHelpTextColor },
417 { "linkColor", &pStyle->maLinkColor },
418 { "visitedLinkColor", &pStyle->maVisitedLinkColor },
419 { "toolTextColor", &pStyle->maToolTextColor },
420 { "fontColor", &pStyle->maFontColor },
423 rWidgetDefinition.mpStyle = pStyle;
425 auto pSettings = std::make_shared<WidgetDefinitionSettings>();
427 std::unordered_map<OString, OString*> aSettingMap = {
428 { "noActiveTabTextRaise", &pSettings->msNoActiveTabTextRaise },
429 { "centeredTabs", &pSettings->msCenteredTabs },
430 { "listBoxEntryMargin", &pSettings->msListBoxEntryMargin },
431 { "defaultFontSize", &pSettings->msDefaultFontSize },
432 { "titleHeight", &pSettings->msTitleHeight },
433 { "floatTitleHeight", &pSettings->msFloatTitleHeight },
434 { "listBoxPreviewDefaultLogicWidth", &pSettings->msListBoxPreviewDefaultLogicWidth },
435 { "listBoxPreviewDefaultLogicHeight", &pSettings->msListBoxPreviewDefaultLogicHeight },
438 rWidgetDefinition.mpSettings = pSettings;
440 SvFileStream aFileStream(m_rDefinitionFile, StreamMode::READ);
442 tools::XmlWalker aWalker;
443 if (!aWalker.open(&aFileStream))
444 return false;
446 if (aWalker.name() != "widgets")
447 return false;
449 aWalker.children();
450 while (aWalker.isValid())
452 ControlType eType;
453 if (aWalker.name() == "style")
455 aWalker.children();
456 while (aWalker.isValid())
458 auto pair = aStyleColorMap.find(aWalker.name());
459 if (pair != aStyleColorMap.end())
461 readColor(aWalker.attribute("value"), *pair->second);
463 aWalker.next();
465 aWalker.parent();
467 if (aWalker.name() == "settings")
469 aWalker.children();
470 while (aWalker.isValid())
472 auto pair = aSettingMap.find(aWalker.name());
473 if (pair != aSettingMap.end())
475 readSetting(aWalker.attribute("value"), *pair->second);
477 aWalker.next();
479 aWalker.parent();
481 else if (getControlTypeForXmlString(aWalker.name(), eType))
483 readDefinition(aWalker, rWidgetDefinition, eType);
485 aWalker.next();
487 aWalker.parent();
489 return true;
492 } // end vcl namespace
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */