1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
11 #include <widgetdraw/WidgetDefinitionReader.hxx>
13 #include <sal/config.h>
14 #include <osl/file.hxx>
15 #include <tools/stream.hxx>
16 #include <unordered_map>
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')
33 else if (aChar
>= 'a' && aChar
<= 'f')
34 return aChar
- 'a' + 10;
35 else if (aChar
>= 'A' && aChar
<= 'F')
36 return aChar
- 'A' + 10;
41 bool readColor(OString
const& rString
, Color
& rColor
)
43 if (rString
.getLength() != 7)
46 const char aChar(rString
[0]);
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]));
58 bool readSetting(OString
const& rInputString
, OString
& rOutputString
)
60 if (!rInputString
.isEmpty())
61 rOutputString
= rInputString
;
65 OString
getValueOrAny(OString
const& rInputString
)
67 if (rInputString
.isEmpty())
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
;
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
)
198 while (rWalker
.isValid())
200 if (rWalker
.name() == "rect")
203 readColor(rWalker
.attribute("stroke"), aStrokeColor
);
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();
212 OString sRx
= rWalker
.attribute("rx");
217 OString sRy
= rWalker
.attribute("ry");
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
,
236 else if (rWalker
.name() == "line")
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
));
277 void WidgetDefinitionReader::readDefinition(tools::XmlWalker
& rWalker
,
278 WidgetDefinition
& rWidgetDefinition
, ControlType eType
)
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
);
332 void WidgetDefinitionReader::readPart(tools::XmlWalker
& rWalker
,
333 std::shared_ptr
<WidgetDefinitionPart
> rpPart
)
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
);
360 bool WidgetDefinitionReader::read(WidgetDefinition
& rWidgetDefinition
)
362 if (!lcl_fileExists(m_rDefinitionFile
))
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
))
446 if (aWalker
.name() != "widgets")
450 while (aWalker
.isValid())
453 if (aWalker
.name() == "style")
456 while (aWalker
.isValid())
458 auto pair
= aStyleColorMap
.find(aWalker
.name());
459 if (pair
!= aStyleColorMap
.end())
461 readColor(aWalker
.attribute("value"), *pair
->second
);
467 if (aWalker
.name() == "settings")
470 while (aWalker
.isValid())
472 auto pair
= aSettingMap
.find(aWalker
.name());
473 if (pair
!= aSettingMap
.end())
475 readSetting(aWalker
.attribute("value"), *pair
->second
);
481 else if (getControlTypeForXmlString(aWalker
.name(), eType
))
483 readDefinition(aWalker
, rWidgetDefinition
, eType
);
492 } // end vcl namespace
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */