bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / gdi / WidgetDefinitionReader.cxx
blobcdd14802f1370a3d6f2dd84cd4daf8e6e7c546d8
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(sal_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 sal_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 OString getValueOrAny(OString const& rInputString)
60 if (rInputString.isEmpty())
61 return "any";
62 return rInputString;
65 ControlPart xmlStringToControlPart(OString const& sPart)
67 if (sPart.equalsIgnoreAsciiCase("NONE"))
68 return ControlPart::NONE;
69 else if (sPart.equalsIgnoreAsciiCase("Entire"))
70 return ControlPart::Entire;
71 else if (sPart.equalsIgnoreAsciiCase("ListboxWindow"))
72 return ControlPart::ListboxWindow;
73 else if (sPart.equalsIgnoreAsciiCase("Button"))
74 return ControlPart::Button;
75 else if (sPart.equalsIgnoreAsciiCase("ButtonUp"))
76 return ControlPart::ButtonUp;
77 else if (sPart.equalsIgnoreAsciiCase("ButtonDown"))
78 return ControlPart::ButtonDown;
79 else if (sPart.equalsIgnoreAsciiCase("ButtonLeft"))
80 return ControlPart::ButtonLeft;
81 else if (sPart.equalsIgnoreAsciiCase("ButtonRight"))
82 return ControlPart::ButtonRight;
83 else if (sPart.equalsIgnoreAsciiCase("AllButtons"))
84 return ControlPart::AllButtons;
85 else if (sPart.equalsIgnoreAsciiCase("SeparatorHorz"))
86 return ControlPart::SeparatorHorz;
87 else if (sPart.equalsIgnoreAsciiCase("SeparatorVert"))
88 return ControlPart::SeparatorVert;
89 else if (sPart.equalsIgnoreAsciiCase("TrackHorzLeft"))
90 return ControlPart::TrackHorzLeft;
91 else if (sPart.equalsIgnoreAsciiCase("TrackVertUpper"))
92 return ControlPart::TrackVertUpper;
93 else if (sPart.equalsIgnoreAsciiCase("TrackHorzRight"))
94 return ControlPart::TrackHorzRight;
95 else if (sPart.equalsIgnoreAsciiCase("TrackVertLower"))
96 return ControlPart::TrackVertLower;
97 else if (sPart.equalsIgnoreAsciiCase("TrackHorzArea"))
98 return ControlPart::TrackHorzArea;
99 else if (sPart.equalsIgnoreAsciiCase("TrackVertArea"))
100 return ControlPart::TrackVertArea;
101 else if (sPart.equalsIgnoreAsciiCase("Arrow"))
102 return ControlPart::Arrow;
103 else if (sPart.equalsIgnoreAsciiCase("ThumbHorz"))
104 return ControlPart::ThumbHorz;
105 else if (sPart.equalsIgnoreAsciiCase("ThumbVert"))
106 return ControlPart::ThumbVert;
107 else if (sPart.equalsIgnoreAsciiCase("MenuItem"))
108 return ControlPart::MenuItem;
109 else if (sPart.equalsIgnoreAsciiCase("MenuItemCheckMark"))
110 return ControlPart::MenuItemCheckMark;
111 else if (sPart.equalsIgnoreAsciiCase("MenuItemRadioMark"))
112 return ControlPart::MenuItemRadioMark;
113 else if (sPart.equalsIgnoreAsciiCase("Separator"))
114 return ControlPart::Separator;
115 else if (sPart.equalsIgnoreAsciiCase("SubmenuArrow"))
116 return ControlPart::SubmenuArrow;
117 else if (sPart.equalsIgnoreAsciiCase("SubEdit"))
118 return ControlPart::SubEdit;
119 else if (sPart.equalsIgnoreAsciiCase("DrawBackgroundHorz"))
120 return ControlPart::DrawBackgroundHorz;
121 else if (sPart.equalsIgnoreAsciiCase("DrawBackgroundVert"))
122 return ControlPart::DrawBackgroundVert;
123 else if (sPart.equalsIgnoreAsciiCase("TabsDrawRtl"))
124 return ControlPart::TabsDrawRtl;
125 else if (sPart.equalsIgnoreAsciiCase("HasBackgroundTexture"))
126 return ControlPart::HasBackgroundTexture;
127 else if (sPart.equalsIgnoreAsciiCase("HasThreeButtons"))
128 return ControlPart::HasThreeButtons;
129 else if (sPart.equalsIgnoreAsciiCase("BackgroundWindow"))
130 return ControlPart::BackgroundWindow;
131 else if (sPart.equalsIgnoreAsciiCase("BackgroundDialog"))
132 return ControlPart::BackgroundDialog;
133 else if (sPart.equalsIgnoreAsciiCase("Border"))
134 return ControlPart::Border;
135 else if (sPart.equalsIgnoreAsciiCase("Focus"))
136 return ControlPart::Focus;
137 return ControlPart::NONE;
140 bool getControlTypeForXmlString(OString const& rString, ControlType& reType)
142 static std::unordered_map<OString, ControlType> aPartMap = {
143 { "pushbutton", ControlType::Pushbutton },
144 { "radiobutton", ControlType::Radiobutton },
145 { "checkbox", ControlType::Checkbox },
146 { "combobox", ControlType::Combobox },
147 { "editbox", ControlType::Editbox },
148 { "listbox", ControlType::Listbox },
149 { "scrollbar", ControlType::Scrollbar },
150 { "spinbox", ControlType::Spinbox },
151 { "slider", ControlType::Slider },
152 { "fixedline", ControlType::Fixedline },
153 { "progress", ControlType::Progress },
154 { "tabitem", ControlType::TabItem },
155 { "tabheader", ControlType::TabHeader },
156 { "tabpane", ControlType::TabPane },
157 { "tabbody", ControlType::TabBody },
158 { "frame", ControlType::Frame },
159 { "windowbackground", ControlType::WindowBackground },
160 { "toolbar", ControlType::Toolbar },
161 { "listnode", ControlType::ListNode },
162 { "listnet", ControlType::ListNet },
163 { "listheader", ControlType::ListHeader },
164 { "menubar", ControlType::Menubar },
165 { "menupopup", ControlType::MenuPopup },
166 { "tooltip", ControlType::Tooltip },
169 auto const& rIterator = aPartMap.find(rString);
170 if (rIterator != aPartMap.end())
172 reType = rIterator->second;
173 return true;
175 return false;
178 } // end anonymous namespace
180 WidgetDefinitionReader::WidgetDefinitionReader(OUString const& rDefinitionFile,
181 OUString const& rResourcePath)
182 : m_rDefinitionFile(rDefinitionFile)
183 , m_rResourcePath(rResourcePath)
187 void WidgetDefinitionReader::readDrawingDefinition(
188 tools::XmlWalker& rWalker, const std::shared_ptr<WidgetDefinitionState>& rpState)
190 rWalker.children();
191 while (rWalker.isValid())
193 if (rWalker.name() == "rect")
195 Color aStrokeColor;
196 readColor(rWalker.attribute("stroke"), aStrokeColor);
197 Color aFillColor;
198 readColor(rWalker.attribute("fill"), aFillColor);
199 OString sStrokeWidth = rWalker.attribute("stroke-width");
200 sal_Int32 nStrokeWidth = -1;
201 if (!sStrokeWidth.isEmpty())
202 nStrokeWidth = sStrokeWidth.toInt32();
204 sal_Int32 nRx = -1;
205 OString sRx = rWalker.attribute("rx");
206 if (!sRx.isEmpty())
207 nRx = sRx.toInt32();
209 sal_Int32 nRy = -1;
210 OString sRy = rWalker.attribute("ry");
211 if (!sRy.isEmpty())
212 nRy = sRy.toInt32();
214 OString sX1 = rWalker.attribute("x1");
215 float fX1 = sX1.isEmpty() ? 0.0 : sX1.toFloat();
217 OString sY1 = rWalker.attribute("y1");
218 float fY1 = sY1.isEmpty() ? 0.0 : sY1.toFloat();
220 OString sX2 = rWalker.attribute("x2");
221 float fX2 = sX2.isEmpty() ? 1.0 : sX2.toFloat();
223 OString sY2 = rWalker.attribute("y2");
224 float fY2 = sY2.isEmpty() ? 1.0 : sY2.toFloat();
226 rpState->addDrawRectangle(aStrokeColor, nStrokeWidth, aFillColor, fX1, fY1, fX2, fY2,
227 nRx, nRy);
229 else if (rWalker.name() == "line")
231 Color aStrokeColor;
232 readColor(rWalker.attribute("stroke"), aStrokeColor);
234 OString sStrokeWidth = rWalker.attribute("stroke-width");
235 sal_Int32 nStrokeWidth = -1;
236 if (!sStrokeWidth.isEmpty())
237 nStrokeWidth = sStrokeWidth.toInt32();
239 OString sX1 = rWalker.attribute("x1");
240 float fX1 = sX1.isEmpty() ? -1.0 : sX1.toFloat();
242 OString sY1 = rWalker.attribute("y1");
243 float fY1 = sY1.isEmpty() ? -1.0 : sY1.toFloat();
245 OString sX2 = rWalker.attribute("x2");
246 float fX2 = sX2.isEmpty() ? -1.0 : sX2.toFloat();
248 OString sY2 = rWalker.attribute("y2");
249 float fY2 = sY2.isEmpty() ? -1.0 : sY2.toFloat();
251 rpState->addDrawLine(aStrokeColor, nStrokeWidth, fX1, fY1, fX2, fY2);
253 else if (rWalker.name() == "image")
255 OString sSource = rWalker.attribute("source");
256 rpState->addDrawImage(m_rResourcePath
257 + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
259 else if (rWalker.name() == "external")
261 OString sSource = rWalker.attribute("source");
262 rpState->addDrawExternal(m_rResourcePath
263 + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
265 rWalker.next();
267 rWalker.parent();
270 void WidgetDefinitionReader::readDefinition(tools::XmlWalker& rWalker,
271 WidgetDefinition& rWidgetDefinition, ControlType eType)
273 rWalker.children();
274 while (rWalker.isValid())
276 if (rWalker.name() == "part")
278 OString sPart = rWalker.attribute("value");
279 ControlPart ePart = xmlStringToControlPart(sPart);
281 std::shared_ptr<WidgetDefinitionPart> pPart = std::make_shared<WidgetDefinitionPart>();
283 OString sWidth = rWalker.attribute("width");
284 if (!sWidth.isEmpty())
286 sal_Int32 nWidth = sWidth.isEmpty() ? 0 : sWidth.toInt32();
287 pPart->mnWidth = nWidth;
290 OString sHeight = rWalker.attribute("height");
291 if (!sHeight.isEmpty())
293 sal_Int32 nHeight = sHeight.isEmpty() ? 0 : sHeight.toInt32();
294 pPart->mnHeight = nHeight;
297 OString sMarginHeight = rWalker.attribute("margin-height");
298 if (!sMarginHeight.isEmpty())
300 sal_Int32 nMarginHeight = sMarginHeight.isEmpty() ? 0 : sMarginHeight.toInt32();
301 pPart->mnMarginHeight = nMarginHeight;
304 OString sMarginWidth = rWalker.attribute("margin-width");
305 if (!sMarginWidth.isEmpty())
307 sal_Int32 nMarginWidth = sMarginWidth.isEmpty() ? 0 : sMarginWidth.toInt32();
308 pPart->mnMarginWidth = nMarginWidth;
311 OString sOrientation = rWalker.attribute("orientation");
312 if (!sOrientation.isEmpty())
314 pPart->msOrientation = sOrientation;
317 rWidgetDefinition.maDefinitions.emplace(ControlTypeAndPart(eType, ePart), pPart);
318 readPart(rWalker, pPart);
320 rWalker.next();
322 rWalker.parent();
325 void WidgetDefinitionReader::readPart(tools::XmlWalker& rWalker,
326 std::shared_ptr<WidgetDefinitionPart> rpPart)
328 rWalker.children();
329 while (rWalker.isValid())
331 if (rWalker.name() == "state")
333 OString sEnabled = getValueOrAny(rWalker.attribute("enabled"));
334 OString sFocused = getValueOrAny(rWalker.attribute("focused"));
335 OString sPressed = getValueOrAny(rWalker.attribute("pressed"));
336 OString sRollover = getValueOrAny(rWalker.attribute("rollover"));
337 OString sDefault = getValueOrAny(rWalker.attribute("default"));
338 OString sSelected = getValueOrAny(rWalker.attribute("selected"));
339 OString sButtonValue = getValueOrAny(rWalker.attribute("button-value"));
340 OString sExtra = getValueOrAny(rWalker.attribute("extra"));
342 std::shared_ptr<WidgetDefinitionState> pState = std::make_shared<WidgetDefinitionState>(
343 sEnabled, sFocused, sPressed, sRollover, sDefault, sSelected, sButtonValue, sExtra);
345 rpPart->maStates.push_back(pState);
346 readDrawingDefinition(rWalker, pState);
348 rWalker.next();
350 rWalker.parent();
353 bool WidgetDefinitionReader::read(WidgetDefinition& rWidgetDefinition)
355 if (!lcl_fileExists(m_rDefinitionFile))
356 return false;
358 auto pStyle = std::make_shared<WidgetDefinitionStyle>();
360 std::unordered_map<OString, Color*> aStyleColorMap = {
361 { "faceColor", &pStyle->maFaceColor },
362 { "checkedColor", &pStyle->maCheckedColor },
363 { "lightColor", &pStyle->maLightColor },
364 { "lightBorderColor", &pStyle->maLightBorderColor },
365 { "shadowColor", &pStyle->maShadowColor },
366 { "darkShadowColor", &pStyle->maDarkShadowColor },
367 { "buttonTextColor", &pStyle->maButtonTextColor },
368 { "defaultActionButtonTextColor", &pStyle->maDefaultActionButtonTextColor },
369 { "actionButtonTextColor", &pStyle->maActionButtonTextColor },
370 { "actionButtonRolloverTextColor", &pStyle->maActionButtonRolloverTextColor },
371 { "buttonRolloverTextColor", &pStyle->maButtonRolloverTextColor },
372 { "radioCheckTextColor", &pStyle->maRadioCheckTextColor },
373 { "groupTextColor", &pStyle->maGroupTextColor },
374 { "labelTextColor", &pStyle->maLabelTextColor },
375 { "windowColor", &pStyle->maWindowColor },
376 { "windowTextColor", &pStyle->maWindowTextColor },
377 { "dialogColor", &pStyle->maDialogColor },
378 { "dialogTextColor", &pStyle->maDialogTextColor },
379 { "workspaceColor", &pStyle->maWorkspaceColor },
380 { "monoColor", &pStyle->maMonoColor },
381 { "fieldColor", &pStyle->maFieldColor },
382 { "fieldTextColor", &pStyle->maFieldTextColor },
383 { "fieldRolloverTextColor", &pStyle->maFieldRolloverTextColor },
384 { "activeColor", &pStyle->maActiveColor },
385 { "activeTextColor", &pStyle->maActiveTextColor },
386 { "activeBorderColor", &pStyle->maActiveBorderColor },
387 { "deactiveColor", &pStyle->maDeactiveColor },
388 { "deactiveTextColor", &pStyle->maDeactiveTextColor },
389 { "deactiveBorderColor", &pStyle->maDeactiveBorderColor },
390 { "menuColor", &pStyle->maMenuColor },
391 { "menuBarColor", &pStyle->maMenuBarColor },
392 { "menuBarRolloverColor", &pStyle->maMenuBarRolloverColor },
393 { "menuBorderColor", &pStyle->maMenuBorderColor },
394 { "menuTextColor", &pStyle->maMenuTextColor },
395 { "menuBarTextColor", &pStyle->maMenuBarTextColor },
396 { "menuBarRolloverTextColor", &pStyle->maMenuBarRolloverTextColor },
397 { "menuBarHighlightTextColor", &pStyle->maMenuBarHighlightTextColor },
398 { "menuHighlightColor", &pStyle->maMenuHighlightColor },
399 { "menuHighlightTextColor", &pStyle->maMenuHighlightTextColor },
400 { "highlightColor", &pStyle->maHighlightColor },
401 { "highlightTextColor", &pStyle->maHighlightTextColor },
402 { "activeTabColor", &pStyle->maActiveTabColor },
403 { "inactiveTabColor", &pStyle->maInactiveTabColor },
404 { "tabTextColor", &pStyle->maTabTextColor },
405 { "tabRolloverTextColor", &pStyle->maTabRolloverTextColor },
406 { "tabHighlightTextColor", &pStyle->maTabHighlightTextColor },
407 { "disableColor", &pStyle->maDisableColor },
408 { "helpColor", &pStyle->maHelpColor },
409 { "helpTextColor", &pStyle->maHelpTextColor },
410 { "linkColor", &pStyle->maLinkColor },
411 { "visitedLinkColor", &pStyle->maVisitedLinkColor },
412 { "toolTextColor", &pStyle->maToolTextColor },
413 { "fontColor", &pStyle->maFontColor },
415 rWidgetDefinition.mpStyle = pStyle;
417 SvFileStream aFileStream(m_rDefinitionFile, StreamMode::READ);
419 tools::XmlWalker aWalker;
420 if (!aWalker.open(&aFileStream))
421 return false;
423 if (aWalker.name() != "widgets")
424 return false;
426 aWalker.children();
427 while (aWalker.isValid())
429 ControlType eType;
430 if (aWalker.name() == "style")
432 aWalker.children();
433 while (aWalker.isValid())
435 auto pair = aStyleColorMap.find(aWalker.name());
436 if (pair != aStyleColorMap.end())
438 readColor(aWalker.attribute("value"), *pair->second);
440 aWalker.next();
442 aWalker.parent();
444 else if (getControlTypeForXmlString(aWalker.name(), eType))
446 readDefinition(aWalker, rWidgetDefinition, eType);
448 aWalker.next();
450 aWalker.parent();
452 return true;
455 } // end vcl namespace
457 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */