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(sal_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 sal_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 OString getValueOrAny(OString const& rInputString)
59 {
60  if (rInputString.isEmpty())
61  return "any";
62  return rInputString;
63 }
64 
65 ControlPart xmlStringToControlPart(OString const& sPart)
66 {
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"))
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"))
79  else if (sPart.equalsIgnoreAsciiCase("ButtonLeft"))
81  else if (sPart.equalsIgnoreAsciiCase("ButtonRight"))
83  else if (sPart.equalsIgnoreAsciiCase("AllButtons"))
85  else if (sPart.equalsIgnoreAsciiCase("SeparatorHorz"))
87  else if (sPart.equalsIgnoreAsciiCase("SeparatorVert"))
89  else if (sPart.equalsIgnoreAsciiCase("TrackHorzLeft"))
91  else if (sPart.equalsIgnoreAsciiCase("TrackVertUpper"))
93  else if (sPart.equalsIgnoreAsciiCase("TrackHorzRight"))
95  else if (sPart.equalsIgnoreAsciiCase("TrackVertLower"))
97  else if (sPart.equalsIgnoreAsciiCase("TrackHorzArea"))
99  else if (sPart.equalsIgnoreAsciiCase("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"))
111  else if (sPart.equalsIgnoreAsciiCase("MenuItemRadioMark"))
113  else if (sPart.equalsIgnoreAsciiCase("Separator"))
114  return ControlPart::Separator;
115  else if (sPart.equalsIgnoreAsciiCase("SubmenuArrow"))
117  else if (sPart.equalsIgnoreAsciiCase("SubEdit"))
118  return ControlPart::SubEdit;
119  else if (sPart.equalsIgnoreAsciiCase("DrawBackgroundHorz"))
121  else if (sPart.equalsIgnoreAsciiCase("DrawBackgroundVert"))
123  else if (sPart.equalsIgnoreAsciiCase("TabsDrawRtl"))
125  else if (sPart.equalsIgnoreAsciiCase("HasBackgroundTexture"))
127  else if (sPart.equalsIgnoreAsciiCase("HasThreeButtons"))
129  else if (sPart.equalsIgnoreAsciiCase("BackgroundWindow"))
131  else if (sPart.equalsIgnoreAsciiCase("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;
138 }
139 
140 bool getControlTypeForXmlString(OString const& rString, ControlType& reType)
141 {
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 },
167  };
168 
169  auto const& rIterator = aPartMap.find(rString);
170  if (rIterator != aPartMap.end())
171  {
172  reType = rIterator->second;
173  return true;
174  }
175  return false;
176 }
177 
178 } // end anonymous namespace
179 
180 WidgetDefinitionReader::WidgetDefinitionReader(OUString const& rDefinitionFile,
181  OUString const& rResourcePath)
182  : m_rDefinitionFile(rDefinitionFile)
183  , m_rResourcePath(rResourcePath)
184 {
185 }
186 
188  tools::XmlWalker& rWalker, const std::shared_ptr<WidgetDefinitionState>& rpState)
189 {
190  rWalker.children();
191  while (rWalker.isValid())
192  {
193  if (rWalker.name() == "rect")
194  {
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();
203 
204  sal_Int32 nRx = -1;
205  OString sRx = rWalker.attribute("rx");
206  if (!sRx.isEmpty())
207  nRx = sRx.toInt32();
208 
209  sal_Int32 nRy = -1;
210  OString sRy = rWalker.attribute("ry");
211  if (!sRy.isEmpty())
212  nRy = sRy.toInt32();
213 
214  OString sX1 = rWalker.attribute("x1");
215  float fX1 = sX1.isEmpty() ? 0.0 : sX1.toFloat();
216 
217  OString sY1 = rWalker.attribute("y1");
218  float fY1 = sY1.isEmpty() ? 0.0 : sY1.toFloat();
219 
220  OString sX2 = rWalker.attribute("x2");
221  float fX2 = sX2.isEmpty() ? 1.0 : sX2.toFloat();
222 
223  OString sY2 = rWalker.attribute("y2");
224  float fY2 = sY2.isEmpty() ? 1.0 : sY2.toFloat();
225 
226  rpState->addDrawRectangle(aStrokeColor, nStrokeWidth, aFillColor, fX1, fY1, fX2, fY2,
227  nRx, nRy);
228  }
229  else if (rWalker.name() == "line")
230  {
231  Color aStrokeColor;
232  readColor(rWalker.attribute("stroke"), aStrokeColor);
233 
234  OString sStrokeWidth = rWalker.attribute("stroke-width");
235  sal_Int32 nStrokeWidth = -1;
236  if (!sStrokeWidth.isEmpty())
237  nStrokeWidth = sStrokeWidth.toInt32();
238 
239  OString sX1 = rWalker.attribute("x1");
240  float fX1 = sX1.isEmpty() ? -1.0 : sX1.toFloat();
241 
242  OString sY1 = rWalker.attribute("y1");
243  float fY1 = sY1.isEmpty() ? -1.0 : sY1.toFloat();
244 
245  OString sX2 = rWalker.attribute("x2");
246  float fX2 = sX2.isEmpty() ? -1.0 : sX2.toFloat();
247 
248  OString sY2 = rWalker.attribute("y2");
249  float fY2 = sY2.isEmpty() ? -1.0 : sY2.toFloat();
250 
251  rpState->addDrawLine(aStrokeColor, nStrokeWidth, fX1, fY1, fX2, fY2);
252  }
253  else if (rWalker.name() == "image")
254  {
255  OString sSource = rWalker.attribute("source");
256  rpState->addDrawImage(m_rResourcePath
257  + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
258  }
259  else if (rWalker.name() == "external")
260  {
261  OString sSource = rWalker.attribute("source");
262  rpState->addDrawExternal(m_rResourcePath
263  + OStringToOUString(sSource, RTL_TEXTENCODING_UTF8));
264  }
265  rWalker.next();
266  }
267  rWalker.parent();
268 }
269 
271  WidgetDefinition& rWidgetDefinition, ControlType eType)
272 {
273  rWalker.children();
274  while (rWalker.isValid())
275  {
276  if (rWalker.name() == "part")
277  {
278  OString sPart = rWalker.attribute("value");
279  ControlPart ePart = xmlStringToControlPart(sPart);
280 
281  std::shared_ptr<WidgetDefinitionPart> pPart = std::make_shared<WidgetDefinitionPart>();
282 
283  OString sWidth = rWalker.attribute("width");
284  if (!sWidth.isEmpty())
285  {
286  sal_Int32 nWidth = sWidth.isEmpty() ? 0 : sWidth.toInt32();
287  pPart->mnWidth = nWidth;
288  }
289 
290  OString sHeight = rWalker.attribute("height");
291  if (!sHeight.isEmpty())
292  {
293  sal_Int32 nHeight = sHeight.isEmpty() ? 0 : sHeight.toInt32();
294  pPart->mnHeight = nHeight;
295  }
296 
297  OString sMarginHeight = rWalker.attribute("margin-height");
298  if (!sMarginHeight.isEmpty())
299  {
300  sal_Int32 nMarginHeight = sMarginHeight.isEmpty() ? 0 : sMarginHeight.toInt32();
301  pPart->mnMarginHeight = nMarginHeight;
302  }
303 
304  OString sMarginWidth = rWalker.attribute("margin-width");
305  if (!sMarginWidth.isEmpty())
306  {
307  sal_Int32 nMarginWidth = sMarginWidth.isEmpty() ? 0 : sMarginWidth.toInt32();
308  pPart->mnMarginWidth = nMarginWidth;
309  }
310 
311  OString sOrientation = rWalker.attribute("orientation");
312  if (!sOrientation.isEmpty())
313  {
314  pPart->msOrientation = sOrientation;
315  }
316 
317  rWidgetDefinition.maDefinitions.emplace(ControlTypeAndPart(eType, ePart), pPart);
318  readPart(rWalker, pPart);
319  }
320  rWalker.next();
321  }
322  rWalker.parent();
323 }
324 
326  std::shared_ptr<WidgetDefinitionPart> rpPart)
327 {
328  rWalker.children();
329  while (rWalker.isValid())
330  {
331  if (rWalker.name() == "state")
332  {
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"));
341 
342  std::shared_ptr<WidgetDefinitionState> pState = std::make_shared<WidgetDefinitionState>(
343  sEnabled, sFocused, sPressed, sRollover, sDefault, sSelected, sButtonValue, sExtra);
344 
345  rpPart->maStates.push_back(pState);
346  readDrawingDefinition(rWalker, pState);
347  }
348  rWalker.next();
349  }
350  rWalker.parent();
351 }
352 
354 {
355  if (!lcl_fileExists(m_rDefinitionFile))
356  return false;
357 
358  auto pStyle = std::make_shared<WidgetDefinitionStyle>();
359 
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 },
414  };
415  rWidgetDefinition.mpStyle = pStyle;
416 
417  SvFileStream aFileStream(m_rDefinitionFile, StreamMode::READ);
418 
419  tools::XmlWalker aWalker;
420  if (!aWalker.open(&aFileStream))
421  return false;
422 
423  if (aWalker.name() != "widgets")
424  return false;
425 
426  aWalker.children();
427  while (aWalker.isValid())
428  {
430  if (aWalker.name() == "style")
431  {
432  aWalker.children();
433  while (aWalker.isValid())
434  {
435  auto pair = aStyleColorMap.find(aWalker.name());
436  if (pair != aStyleColorMap.end())
437  {
438  readColor(aWalker.attribute("value"), *pair->second);
439  }
440  aWalker.next();
441  }
442  aWalker.parent();
443  }
444  else if (getControlTypeForXmlString(aWalker.name(), eType))
445  {
446  readDefinition(aWalker, rWidgetDefinition, eType);
447  }
448  aWalker.next();
449  }
450  aWalker.parent();
451 
452  return true;
453 }
454 
455 } // end vcl namespace
456 
457 /* 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)
char sal_Char
WidgetDefinitionReader(OUString const &rDefinitionFile, OUString const &rResourcePath)
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)
DocumentType const eType
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