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 <unordered_map>
17 
18 namespace vcl
19 {
20 namespace
21 {
22 bool lcl_fileExists(OUString const& sFilename)
23 {
24  osl::File aFile(sFilename);
25  osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read);
26  return osl::FileBase::E_None == eRC;
27 }
28 
29 int lcl_gethex(char aChar)
30 {
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;
39 }
40 
41 bool readColor(OString const& rString, Color& rColor)
42 {
43  if (rString.getLength() != 7)
44  return false;
45 
46  const char aChar(rString[0]);
47 
48  if (aChar != '#')
49  return false;
50 
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]));
54 
55  return true;
56 }
57 
58 bool readSetting(OString const& rInputString, OString& rOutputString)
59 {
60  if (!rInputString.isEmpty())
61  rOutputString = rInputString;
62  return true;
63 }
64 
65 OString getValueOrAny(OString const& rInputString)
66 {
67  if (rInputString.isEmpty())
68  return "any";
69  return rInputString;
70 }
71 
72 ControlPart xmlStringToControlPart(OString const& sPart)
73 {
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"))
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"))
86  else if (sPart.equalsIgnoreAsciiCase("ButtonLeft"))
88  else if (sPart.equalsIgnoreAsciiCase("ButtonRight"))
90  else if (sPart.equalsIgnoreAsciiCase("AllButtons"))
92  else if (sPart.equalsIgnoreAsciiCase("SeparatorHorz"))
94  else if (sPart.equalsIgnoreAsciiCase("SeparatorVert"))
96  else if (sPart.equalsIgnoreAsciiCase("TrackHorzLeft"))
98  else if (sPart.equalsIgnoreAsciiCase("TrackVertUpper"))
100  else if (sPart.equalsIgnoreAsciiCase("TrackHorzRight"))
102  else if (sPart.equalsIgnoreAsciiCase("TrackVertLower"))
104  else if (sPart.equalsIgnoreAsciiCase("TrackHorzArea"))
106  else if (sPart.equalsIgnoreAsciiCase("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"))
118  else if (sPart.equalsIgnoreAsciiCase("MenuItemRadioMark"))
120  else if (sPart.equalsIgnoreAsciiCase("Separator"))
121  return ControlPart::Separator;
122  else if (sPart.equalsIgnoreAsciiCase("SubmenuArrow"))
124  else if (sPart.equalsIgnoreAsciiCase("SubEdit"))
125  return ControlPart::SubEdit;
126  else if (sPart.equalsIgnoreAsciiCase("DrawBackgroundHorz"))
128  else if (sPart.equalsIgnoreAsciiCase("DrawBackgroundVert"))
130  else if (sPart.equalsIgnoreAsciiCase("TabsDrawRtl"))
132  else if (sPart.equalsIgnoreAsciiCase("HasBackgroundTexture"))
134  else if (sPart.equalsIgnoreAsciiCase("HasThreeButtons"))
136  else if (sPart.equalsIgnoreAsciiCase("BackgroundWindow"))
138  else if (sPart.equalsIgnoreAsciiCase("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;
145 }
146 
147 bool getControlTypeForXmlString(OString const& rString, ControlType& reType)
148 {
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 },
174  };
175 
176  auto const& rIterator = aPartMap.find(rString);
177  if (rIterator != aPartMap.end())
178  {
179  reType = rIterator->second;
180  return true;
181  }
182  return false;
183 }
184 
185 } // end anonymous namespace
186 
187 WidgetDefinitionReader::WidgetDefinitionReader(OUString const& rDefinitionFile,
188  OUString const& rResourcePath)
189  : m_rDefinitionFile(rDefinitionFile)
190  , m_rResourcePath(rResourcePath)
191 {
192 }
193 
195  tools::XmlWalker& rWalker, const std::shared_ptr<WidgetDefinitionState>& rpState)
196 {
197  rWalker.children();
198  while (rWalker.isValid())
199  {
200  if (rWalker.name() == "rect")
201  {
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();
210 
211  sal_Int32 nRx = -1;
212  OString sRx = rWalker.attribute("rx");
213  if (!sRx.isEmpty())
214  nRx = sRx.toInt32();
215 
216  sal_Int32 nRy = -1;
217  OString sRy = rWalker.attribute("ry");
218  if (!sRy.isEmpty())
219  nRy = sRy.toInt32();
220 
221  OString sX1 = rWalker.attribute("x1");
222  float fX1 = sX1.isEmpty() ? 0.0 : sX1.toFloat();
223 
224  OString sY1 = rWalker.attribute("y1");
225  float fY1 = sY1.isEmpty() ? 0.0 : sY1.toFloat();
226 
227  OString sX2 = rWalker.attribute("x2");
228  float fX2 = sX2.isEmpty() ? 1.0 : sX2.toFloat();
229 
230  OString sY2 = rWalker.attribute("y2");
231  float fY2 = sY2.isEmpty() ? 1.0 : sY2.toFloat();
232 
233  rpState->addDrawRectangle(aStrokeColor, nStrokeWidth, aFillColor, fX1, fY1, fX2, fY2,
234  nRx, nRy);
235  }
236  else if (rWalker.name() == "line")
237  {
238  Color aStrokeColor;
239  readColor(rWalker.attribute("stroke"), aStrokeColor);
240 
241  OString sStrokeWidth = rWalker.attribute("stroke-width");
242  sal_Int32 nStrokeWidth = -1;
243  if (!sStrokeWidth.isEmpty())
244  nStrokeWidth = sStrokeWidth.toInt32();
245 
246  OString sX1 = rWalker.attribute("x1");
247  float fX1 = sX1.isEmpty() ? -1.0 : sX1.toFloat();
248 
249  OString sY1 = rWalker.attribute("y1");
250  float fY1 = sY1.isEmpty() ? -1.0 : sY1.toFloat();
251 
252  OString sX2 = rWalker.attribute("x2");
253  float fX2 = sX2.isEmpty() ? -1.0 : sX2.toFloat();
254 
255  OString sY2 = rWalker.attribute("y2");
256  float fY2 = sY2.isEmpty() ? -1.0 : sY2.toFloat();
257 
258  rpState->addDrawLine(aStrokeColor, nStrokeWidth, fX1, fY1, fX2, fY2);
259  }
260  else if (rWalker.name() == "image")
261  {
262  OString sSource = rWalker.attribute("source");
263  rpState->addDrawImage(m_rResourcePath
264  + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
265  }
266  else if (rWalker.name() == "external")
267  {
268  OString sSource = rWalker.attribute("source");
269  rpState->addDrawExternal(m_rResourcePath
270  + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
271  }
272  rWalker.next();
273  }
274  rWalker.parent();
275 }
276 
278  WidgetDefinition& rWidgetDefinition, ControlType eType)
279 {
280  rWalker.children();
281  while (rWalker.isValid())
282  {
283  if (rWalker.name() == "part")
284  {
285  OString sPart = rWalker.attribute("value");
286  ControlPart ePart = xmlStringToControlPart(sPart);
287 
288  std::shared_ptr<WidgetDefinitionPart> pPart = std::make_shared<WidgetDefinitionPart>();
289 
290  OString sWidth = rWalker.attribute("width");
291  if (!sWidth.isEmpty())
292  {
293  sal_Int32 nWidth = sWidth.isEmpty() ? 0 : sWidth.toInt32();
294  pPart->mnWidth = nWidth;
295  }
296 
297  OString sHeight = rWalker.attribute("height");
298  if (!sHeight.isEmpty())
299  {
300  sal_Int32 nHeight = sHeight.isEmpty() ? 0 : sHeight.toInt32();
301  pPart->mnHeight = nHeight;
302  }
303 
304  OString sMarginHeight = rWalker.attribute("margin-height");
305  if (!sMarginHeight.isEmpty())
306  {
307  sal_Int32 nMarginHeight = sMarginHeight.isEmpty() ? 0 : sMarginHeight.toInt32();
308  pPart->mnMarginHeight = nMarginHeight;
309  }
310 
311  OString sMarginWidth = rWalker.attribute("margin-width");
312  if (!sMarginWidth.isEmpty())
313  {
314  sal_Int32 nMarginWidth = sMarginWidth.isEmpty() ? 0 : sMarginWidth.toInt32();
315  pPart->mnMarginWidth = nMarginWidth;
316  }
317 
318  OString sOrientation = rWalker.attribute("orientation");
319  if (!sOrientation.isEmpty())
320  {
321  pPart->msOrientation = sOrientation;
322  }
323 
324  rWidgetDefinition.maDefinitions.emplace(ControlTypeAndPart(eType, ePart), pPart);
325  readPart(rWalker, pPart);
326  }
327  rWalker.next();
328  }
329  rWalker.parent();
330 }
331 
333  std::shared_ptr<WidgetDefinitionPart> rpPart)
334 {
335  rWalker.children();
336  while (rWalker.isValid())
337  {
338  if (rWalker.name() == "state")
339  {
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"));
348 
349  std::shared_ptr<WidgetDefinitionState> pState = std::make_shared<WidgetDefinitionState>(
350  sEnabled, sFocused, sPressed, sRollover, sDefault, sSelected, sButtonValue, sExtra);
351 
352  rpPart->maStates.push_back(pState);
353  readDrawingDefinition(rWalker, pState);
354  }
355  rWalker.next();
356  }
357  rWalker.parent();
358 }
359 
361 {
362  if (!lcl_fileExists(m_rDefinitionFile))
363  return false;
364 
365  auto pStyle = std::make_shared<WidgetDefinitionStyle>();
366 
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 },
421  };
422 
423  rWidgetDefinition.mpStyle = pStyle;
424 
425  auto pSettings = std::make_shared<WidgetDefinitionSettings>();
426 
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 },
436  };
437 
438  rWidgetDefinition.mpSettings = pSettings;
439 
440  SvFileStream aFileStream(m_rDefinitionFile, StreamMode::READ);
441 
442  tools::XmlWalker aWalker;
443  if (!aWalker.open(&aFileStream))
444  return false;
445 
446  if (aWalker.name() != "widgets")
447  return false;
448 
449  aWalker.children();
450  while (aWalker.isValid())
451  {
453  if (aWalker.name() == "style")
454  {
455  aWalker.children();
456  while (aWalker.isValid())
457  {
458  auto pair = aStyleColorMap.find(aWalker.name());
459  if (pair != aStyleColorMap.end())
460  {
461  readColor(aWalker.attribute("value"), *pair->second);
462  }
463  aWalker.next();
464  }
465  aWalker.parent();
466  }
467  if (aWalker.name() == "settings")
468  {
469  aWalker.children();
470  while (aWalker.isValid())
471  {
472  auto pair = aSettingMap.find(aWalker.name());
473  if (pair != aSettingMap.end())
474  {
475  readSetting(aWalker.attribute("value"), *pair->second);
476  }
477  aWalker.next();
478  }
479  aWalker.parent();
480  }
481  else if (getControlTypeForXmlString(aWalker.name(), eType))
482  {
483  readDefinition(aWalker, rWidgetDefinition, eType);
484  }
485  aWalker.next();
486  }
487  aWalker.parent();
488 
489  return true;
490 }
491 
492 } // end vcl namespace
493 
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OString attribute(const OString &sName)
void SetBlue(sal_uInt8 nBlue)
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...
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