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 
12 
13 #include <sal/config.h>
14 #include <osl/file.hxx>
15 #include <tools/stream.hxx>
16 #include <o3tl/string_view.hxx>
17 #include <unordered_map>
18 
19 namespace vcl
20 {
21 namespace
22 {
23 bool lcl_fileExists(OUString const& sFilename)
24 {
25  osl::File aFile(sFilename);
26  osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read);
27  return osl::FileBase::E_None == eRC;
28 }
29 
30 int lcl_gethex(char aChar)
31 {
32  if (aChar >= '0' && aChar <= '9')
33  return aChar - '0';
34  else if (aChar >= 'a' && aChar <= 'f')
35  return aChar - 'a' + 10;
36  else if (aChar >= 'A' && aChar <= 'F')
37  return aChar - 'A' + 10;
38  else
39  return 0;
40 }
41 
42 bool readColor(OString const& rString, Color& rColor)
43 {
44  if (rString.getLength() != 7)
45  return false;
46 
47  const char aChar(rString[0]);
48 
49  if (aChar != '#')
50  return false;
51 
52  rColor.SetRed((lcl_gethex(rString[1]) << 4) | lcl_gethex(rString[2]));
53  rColor.SetGreen((lcl_gethex(rString[3]) << 4) | lcl_gethex(rString[4]));
54  rColor.SetBlue((lcl_gethex(rString[5]) << 4) | lcl_gethex(rString[6]));
55 
56  return true;
57 }
58 
59 bool readSetting(OString const& rInputString, OString& rOutputString)
60 {
61  if (!rInputString.isEmpty())
62  rOutputString = rInputString;
63  return true;
64 }
65 
66 OString getValueOrAny(OString const& rInputString)
67 {
68  if (rInputString.isEmpty())
69  return "any";
70  return rInputString;
71 }
72 
73 ControlPart xmlStringToControlPart(std::string_view sPart)
74 {
75  if (o3tl::equalsIgnoreAsciiCase(sPart, "NONE"))
76  return ControlPart::NONE;
77  else if (o3tl::equalsIgnoreAsciiCase(sPart, "Entire"))
78  return ControlPart::Entire;
79  else if (o3tl::equalsIgnoreAsciiCase(sPart, "ListboxWindow"))
81  else if (o3tl::equalsIgnoreAsciiCase(sPart, "Button"))
82  return ControlPart::Button;
83  else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonUp"))
84  return ControlPart::ButtonUp;
85  else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonDown"))
87  else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonLeft"))
89  else if (o3tl::equalsIgnoreAsciiCase(sPart, "ButtonRight"))
91  else if (o3tl::equalsIgnoreAsciiCase(sPart, "AllButtons"))
93  else if (o3tl::equalsIgnoreAsciiCase(sPart, "SeparatorHorz"))
95  else if (o3tl::equalsIgnoreAsciiCase(sPart, "SeparatorVert"))
97  else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackHorzLeft"))
99  else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackVertUpper"))
101  else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackHorzRight"))
103  else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackVertLower"))
105  else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackHorzArea"))
107  else if (o3tl::equalsIgnoreAsciiCase(sPart, "TrackVertArea"))
109  else if (o3tl::equalsIgnoreAsciiCase(sPart, "Arrow"))
110  return ControlPart::Arrow;
111  else if (o3tl::equalsIgnoreAsciiCase(sPart, "ThumbHorz"))
112  return ControlPart::ThumbHorz;
113  else if (o3tl::equalsIgnoreAsciiCase(sPart, "ThumbVert"))
114  return ControlPart::ThumbVert;
115  else if (o3tl::equalsIgnoreAsciiCase(sPart, "MenuItem"))
116  return ControlPart::MenuItem;
117  else if (o3tl::equalsIgnoreAsciiCase(sPart, "MenuItemCheckMark"))
119  else if (o3tl::equalsIgnoreAsciiCase(sPart, "MenuItemRadioMark"))
121  else if (o3tl::equalsIgnoreAsciiCase(sPart, "Separator"))
122  return ControlPart::Separator;
123  else if (o3tl::equalsIgnoreAsciiCase(sPart, "SubmenuArrow"))
125  else if (o3tl::equalsIgnoreAsciiCase(sPart, "SubEdit"))
126  return ControlPart::SubEdit;
127  else if (o3tl::equalsIgnoreAsciiCase(sPart, "DrawBackgroundHorz"))
129  else if (o3tl::equalsIgnoreAsciiCase(sPart, "DrawBackgroundVert"))
131  else if (o3tl::equalsIgnoreAsciiCase(sPart, "TabsDrawRtl"))
133  else if (o3tl::equalsIgnoreAsciiCase(sPart, "HasBackgroundTexture"))
135  else if (o3tl::equalsIgnoreAsciiCase(sPart, "HasThreeButtons"))
137  else if (o3tl::equalsIgnoreAsciiCase(sPart, "BackgroundWindow"))
139  else if (o3tl::equalsIgnoreAsciiCase(sPart, "BackgroundDialog"))
141  else if (o3tl::equalsIgnoreAsciiCase(sPart, "Border"))
142  return ControlPart::Border;
143  else if (o3tl::equalsIgnoreAsciiCase(sPart, "Focus"))
144  return ControlPart::Focus;
145  return ControlPart::NONE;
146 }
147 
148 bool getControlTypeForXmlString(OString const& rString, ControlType& reType)
149 {
150  static std::unordered_map<OString, ControlType> aPartMap = {
151  { "pushbutton", ControlType::Pushbutton },
152  { "radiobutton", ControlType::Radiobutton },
153  { "checkbox", ControlType::Checkbox },
154  { "combobox", ControlType::Combobox },
155  { "editbox", ControlType::Editbox },
156  { "listbox", ControlType::Listbox },
157  { "scrollbar", ControlType::Scrollbar },
158  { "spinbox", ControlType::Spinbox },
159  { "slider", ControlType::Slider },
160  { "fixedline", ControlType::Fixedline },
161  { "progress", ControlType::Progress },
162  { "tabitem", ControlType::TabItem },
163  { "tabheader", ControlType::TabHeader },
164  { "tabpane", ControlType::TabPane },
165  { "tabbody", ControlType::TabBody },
166  { "frame", ControlType::Frame },
167  { "windowbackground", ControlType::WindowBackground },
168  { "toolbar", ControlType::Toolbar },
169  { "listnode", ControlType::ListNode },
170  { "listnet", ControlType::ListNet },
171  { "listheader", ControlType::ListHeader },
172  { "menubar", ControlType::Menubar },
173  { "menupopup", ControlType::MenuPopup },
174  { "tooltip", ControlType::Tooltip },
175  };
176 
177  auto const& rIterator = aPartMap.find(rString);
178  if (rIterator != aPartMap.end())
179  {
180  reType = rIterator->second;
181  return true;
182  }
183  return false;
184 }
185 
186 } // end anonymous namespace
187 
188 WidgetDefinitionReader::WidgetDefinitionReader(OUString const& rDefinitionFile,
189  OUString const& rResourcePath)
190  : m_rDefinitionFile(rDefinitionFile)
191  , m_rResourcePath(rResourcePath)
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: */
void SetBlue(sal_uInt8 nBlue)
OString attribute(const OString &sName) const
void readDrawingDefinition(tools::XmlWalker &rWalker, const std::shared_ptr< WidgetDefinitionState > &rStates)
std::shared_ptr< WidgetDefinitionSettings > mpSettings
WidgetDefinitionReader(OUString const &rDefinitionFile, OUString const &rResourcePath)
DocumentType eType
The edit field part of a control, e.g.
bool isValid() const
void readDefinition(tools::XmlWalker &rWalker, WidgetDefinition &rWidgetDefinition, ControlType eType)
void SetRed(sal_uInt8 nRed)
bool open(SvStream *pStream)
bool read(WidgetDefinition &rWidgetDefinition)
ControlType
These types are all based on the supported variants vcl/salnativewidgets.hxx and must be kept in-sync...
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
std::unordered_map< ControlTypeAndPart, std::shared_ptr< WidgetDefinitionPart > > maDefinitions
void SetGreen(sal_uInt8 nGreen)
void readPart(tools::XmlWalker &rWalker, std::shared_ptr< WidgetDefinitionPart > rpPart)
std::shared_ptr< WidgetDefinitionStyle > mpStyle