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/.
10 #include <config_feature_desktop.h>
11 #include <config_options.h>
14 #include <string_view>
15 #include <unordered_map>
16 #include <com/sun/star/accessibility/AccessibleRole.hpp>
18 #include <comphelper/lok.hxx>
19 #include <i18nutil/unicode.hxx>
20 #include <officecfg/Office/Common.hxx>
21 #include <osl/module.hxx>
22 #include <sal/log.hxx>
23 #include <unotools/localedatawrapper.hxx>
24 #include <unotools/resmgr.hxx>
25 #include <vcl/builder.hxx>
26 #include <vcl/toolkit/button.hxx>
27 #include <vcl/toolkit/dialog.hxx>
28 #include <vcl/toolkit/edit.hxx>
29 #include <vcl/toolkit/field.hxx>
30 #include <vcl/fieldvalues.hxx>
31 #include <vcl/toolkit/fmtfield.hxx>
32 #include <vcl/toolkit/fixed.hxx>
33 #include <vcl/toolkit/fixedhyper.hxx>
34 #include <vcl/headbar.hxx>
35 #include <vcl/IPrioritable.hxx>
36 #include <vcl/toolkit/ivctrl.hxx>
37 #include <vcl/layout.hxx>
38 #include <vcl/toolkit/lstbox.hxx>
39 #include <vcl/menubtn.hxx>
40 #include <vcl/mnemonic.hxx>
41 #include <vcl/toolkit/prgsbar.hxx>
42 #include <vcl/scrbar.hxx>
43 #include <vcl/split.hxx>
44 #include <vcl/svapp.hxx>
45 #include <vcl/toolkit/svtabbx.hxx>
46 #include <vcl/tabctrl.hxx>
47 #include <vcl/tabpage.hxx>
48 #include <vcl/toolkit/throbber.hxx>
49 #include <vcl/toolbox.hxx>
50 #include <vcl/toolkit/treelistentry.hxx>
51 #include <vcl/toolkit/vclmedit.hxx>
52 #include <vcl/settings.hxx>
54 #include <vcl/weld.hxx>
55 #include <vcl/weldutils.hxx>
56 #include <vcl/commandinfoprovider.hxx>
57 #include <iconview.hxx>
59 #include <bitmaps.hlst>
60 #include <messagedialog.hxx>
61 #include <OptionalBox.hxx>
63 #include <xmlreader/xmlreader.hxx>
64 #include <desktop/crashreport.hxx>
65 #include <calendar.hxx>
66 #include <menutogglebutton.hxx>
67 #include <salinst.hxx>
68 #include <strings.hrc>
69 #include <treeglue.hxx>
70 #include <tools/diagnose_ex.h>
71 #include <verticaltabctrl.hxx>
73 #include <tools/svlibrary.h>
74 #include <jsdialog/jsdialogbuilder.hxx>
76 #if defined(DISABLE_DYNLOADING) || defined(LINUX)
80 static bool toBool(std::string_view rValue
)
82 return (!rValue
.empty() && (rValue
[0] == 't' || rValue
[0] == 'T' || rValue
[0] == '1'));
87 OUString
mapStockToImageResource(const OUString
& sType
)
89 if (sType
== "gtk-index")
90 return SV_RESID_BITMAP_INDEX
;
91 else if (sType
== "gtk-refresh")
92 return SV_RESID_BITMAP_REFRESH
;
93 else if (sType
== "gtk-apply")
95 else if (sType
== "gtk-dialog-error")
97 else if (sType
== "gtk-add")
99 else if (sType
== "gtk-remove")
101 else if (sType
== "gtk-copy")
103 else if (sType
== "gtk-paste")
108 SymbolType
mapStockToSymbol(const OUString
& sType
)
110 SymbolType eRet
= SymbolType::DONTKNOW
;
111 if (sType
== "gtk-media-next")
112 eRet
= SymbolType::NEXT
;
113 else if (sType
== "gtk-media-previous")
114 eRet
= SymbolType::PREV
;
115 else if (sType
== "gtk-media-play")
116 eRet
= SymbolType::PLAY
;
117 else if (sType
== "gtk-media-stop")
118 eRet
= SymbolType::STOP
;
119 else if (sType
== "gtk-goto-first")
120 eRet
= SymbolType::FIRST
;
121 else if (sType
== "gtk-goto-last")
122 eRet
= SymbolType::LAST
;
123 else if (sType
== "gtk-go-back")
124 eRet
= SymbolType::ARROW_LEFT
;
125 else if (sType
== "gtk-go-forward")
126 eRet
= SymbolType::ARROW_RIGHT
;
127 else if (sType
== "gtk-go-up")
128 eRet
= SymbolType::ARROW_UP
;
129 else if (sType
== "gtk-go-down")
130 eRet
= SymbolType::ARROW_DOWN
;
131 else if (sType
== "gtk-missing-image")
132 eRet
= SymbolType::IMAGE
;
133 else if (sType
== "gtk-help")
134 eRet
= SymbolType::HELP
;
135 else if (sType
== "gtk-close")
136 eRet
= SymbolType::CLOSE
;
137 else if (sType
== "gtk-new")
138 eRet
= SymbolType::PLUS
;
139 else if (!mapStockToImageResource(sType
).isEmpty())
140 eRet
= SymbolType::IMAGE
;
144 void setupFromActionName(Button
*pButton
, VclBuilder::stringmap
&rMap
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
);
147 #if defined SAL_LOG_WARN
150 bool isButtonType(WindowType nType
)
152 return nType
== WindowType::PUSHBUTTON
||
153 nType
== WindowType::OKBUTTON
||
154 nType
== WindowType::CANCELBUTTON
||
155 nType
== WindowType::HELPBUTTON
||
156 nType
== WindowType::IMAGEBUTTON
||
157 nType
== WindowType::MENUBUTTON
||
158 nType
== WindowType::MOREBUTTON
||
159 nType
== WindowType::SPINBUTTON
;
164 weld::Builder
* Application::CreateBuilder(weld::Widget
* pParent
, const OUString
&rUIFile
, bool bMobile
)
166 bool bUseJSBuilder
= false;
170 if (rUIFile
== "modules/swriter/ui/wordcount-mobile.ui" ||
171 rUIFile
== "svx/ui/findreplacedialog-mobile.ui" ||
172 rUIFile
== "modules/swriter/ui/watermarkdialog.ui" ||
173 rUIFile
== "modules/scalc/ui/validationdialog.ui" ||
174 rUIFile
== "modules/scalc/ui/validationcriteriapage.ui" ||
175 rUIFile
== "modules/scalc/ui/validationhelptabpage-mobile.ui" ||
176 rUIFile
== "modules/scalc/ui/erroralerttabpage-mobile.ui" ||
177 rUIFile
== "modules/scalc/ui/validationdialog.ui")
178 bUseJSBuilder
= true;
182 return new JSInstanceBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
);
184 return ImplGetSVData()->mpDefInst
->CreateBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
);
187 weld::Builder
* Application::CreateInterimBuilder(vcl::Window
* pParent
, const OUString
&rUIFile
, bool bAllowCycleFocusOut
, sal_uInt64 nLOKWindowId
)
189 if (comphelper::LibreOfficeKit::isActive()
190 && (rUIFile
== "svx/ui/stylespreview.ui"
191 || rUIFile
== "modules/scalc/ui/numberbox.ui"))
193 return new JSInstanceBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
, css::uno::Reference
<css::frame::XFrame
>(), nLOKWindowId
);
196 return ImplGetSVData()->mpDefInst
->CreateInterimBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
, bAllowCycleFocusOut
, nLOKWindowId
);
199 weld::MessageDialog
* Application::CreateMessageDialog(weld::Widget
* pParent
, VclMessageType eMessageType
,
200 VclButtonsType eButtonType
, const OUString
& rPrimaryMessage
,
204 return JSInstanceBuilder::CreateMessageDialog(pParent
, eMessageType
, eButtonType
, rPrimaryMessage
);
206 return ImplGetSVData()->mpDefInst
->CreateMessageDialog(pParent
, eMessageType
, eButtonType
, rPrimaryMessage
);
209 weld::Window
* Application::GetFrameWeld(const css::uno::Reference
<css::awt::XWindow
>& rWindow
)
211 return ImplGetSVData()->mpDefInst
->GetFrameWeld(rWindow
);
216 OUString
MetricSpinButton::MetricToString(FieldUnit rUnit
)
218 const FieldUnitStringList
& rList
= ImplGetFieldUnits();
219 // return unit's default string (ie, the first one )
220 auto it
= std::find_if(
221 rList
.begin(), rList
.end(),
222 [&rUnit
](const std::pair
<OUString
, FieldUnit
>& rItem
) { return rItem
.second
== rUnit
; });
223 if (it
!= rList
.end())
229 IMPL_LINK_NOARG(MetricSpinButton
, spin_button_value_changed
, SpinButton
&, void)
231 signal_value_changed();
234 IMPL_LINK(MetricSpinButton
, spin_button_output
, SpinButton
&, rSpinButton
, void)
236 OUString
sNewText(format_number(rSpinButton
.get_value()));
237 if (sNewText
!= rSpinButton
.get_text())
238 rSpinButton
.set_text(sNewText
);
241 void MetricSpinButton::update_width_chars()
244 m_xSpinButton
->get_range(min
, max
);
245 auto width
= std::max(m_xSpinButton
->get_pixel_size(format_number(min
)).Width(),
246 m_xSpinButton
->get_pixel_size(format_number(max
)).Width());
247 int chars
= ceil(width
/ m_xSpinButton
->get_approximate_digit_width());
248 m_xSpinButton
->set_width_chars(chars
);
251 unsigned int SpinButton::Power10(unsigned int n
)
253 unsigned int nValue
= 1;
254 for (unsigned int i
= 0; i
< n
; ++i
)
259 int SpinButton::denormalize(int nValue
) const
261 const int nFactor
= Power10(get_digits());
263 if ((nValue
< (SAL_MIN_INT32
+ nFactor
)) || (nValue
> (SAL_MAX_INT32
- nFactor
)))
265 return nValue
/ nFactor
;
268 const int nHalf
= nFactor
/ 2;
271 return (nValue
- nHalf
) / nFactor
;
272 return (nValue
+ nHalf
) / nFactor
;
275 OUString
MetricSpinButton::format_number(int nValue
) const
279 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
281 unsigned int nDecimalDigits
= m_xSpinButton
->get_digits();
282 //pawn percent off to icu to decide whether percent is separated from its number for this locale
283 if (m_eSrcUnit
== FieldUnit::PERCENT
)
285 double fValue
= nValue
;
286 fValue
/= SpinButton::Power10(nDecimalDigits
);
287 aStr
= unicode::formatPercent(fValue
, rLocaleData
.getLanguageTag());
291 aStr
= rLocaleData
.getNum(nValue
, nDecimalDigits
, true, true);
292 OUString aSuffix
= MetricToString(m_eSrcUnit
);
293 if (m_eSrcUnit
!= FieldUnit::NONE
&& m_eSrcUnit
!= FieldUnit::DEGREE
&& m_eSrcUnit
!= FieldUnit::INCH
&& m_eSrcUnit
!= FieldUnit::FOOT
)
295 if (m_eSrcUnit
== FieldUnit::INCH
)
297 OUString sDoublePrime
= u
"\u2033";
298 if (aSuffix
!= "\"" && aSuffix
!= sDoublePrime
)
301 aSuffix
= sDoublePrime
;
303 else if (m_eSrcUnit
== FieldUnit::FOOT
)
305 OUString sPrime
= u
"\u2032";
306 if (aSuffix
!= "'" && aSuffix
!= sPrime
)
312 assert(m_eSrcUnit
!= FieldUnit::PERCENT
);
319 void MetricSpinButton::set_digits(unsigned int digits
)
322 get_increments(step
, page
, m_eSrcUnit
);
323 int value
= get_value(m_eSrcUnit
);
324 m_xSpinButton
->set_digits(digits
);
325 set_increments(step
, page
, m_eSrcUnit
);
326 set_value(value
, m_eSrcUnit
);
327 update_width_chars();
330 void MetricSpinButton::set_unit(FieldUnit eUnit
)
332 if (eUnit
!= m_eSrcUnit
)
335 get_increments(step
, page
, m_eSrcUnit
);
336 int value
= get_value(m_eSrcUnit
);
338 set_increments(step
, page
, m_eSrcUnit
);
339 set_value(value
, m_eSrcUnit
);
340 spin_button_output(*m_xSpinButton
);
341 update_width_chars();
345 int MetricSpinButton::ConvertValue(int nValue
, FieldUnit eInUnit
, FieldUnit eOutUnit
) const
347 auto nRet
= vcl::ConvertValue(nValue
, 0, m_xSpinButton
->get_digits(), eInUnit
, eOutUnit
);
348 if (nRet
> SAL_MAX_INT32
)
349 nRet
= SAL_MAX_INT32
;
350 else if (nRet
< SAL_MIN_INT32
)
351 nRet
= SAL_MIN_INT32
;
355 IMPL_LINK(MetricSpinButton
, spin_button_input
, int*, result
, bool)
357 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
359 bool bRet
= vcl::TextToValue(get_text(), fResult
, 0, m_xSpinButton
->get_digits(), rLocaleData
, m_eSrcUnit
);
362 if (fResult
> SAL_MAX_INT32
)
363 fResult
= SAL_MAX_INT32
;
364 else if (fResult
< SAL_MIN_INT32
)
365 fResult
= SAL_MIN_INT32
;
371 EntryTreeView::EntryTreeView(std::unique_ptr
<Entry
> xEntry
, std::unique_ptr
<TreeView
> xTreeView
)
372 : m_xEntry(std::move(xEntry
))
373 , m_xTreeView(std::move(xTreeView
))
375 m_xTreeView
->connect_changed(LINK(this, EntryTreeView
, ClickHdl
));
376 m_xEntry
->connect_changed(LINK(this, EntryTreeView
, ModifyHdl
));
379 IMPL_LINK(EntryTreeView
, ClickHdl
, weld::TreeView
&, rView
, void)
381 m_xEntry
->set_text(rView
.get_selected_text());
382 m_aChangeHdl
.Call(*this);
385 IMPL_LINK_NOARG(EntryTreeView
, ModifyHdl
, weld::Entry
&, void)
387 m_aChangeHdl
.Call(*this);
390 void EntryTreeView::set_height_request_by_rows(int nRows
)
392 int nHeight
= nRows
== -1 ? -1 : m_xTreeView
->get_height_rows(nRows
);
393 m_xTreeView
->set_size_request(m_xTreeView
->get_size_request().Width(), nHeight
);
396 size_t GetAbsPos(const weld::TreeView
& rTreeView
, const weld::TreeIter
& rIter
)
400 std::unique_ptr
<weld::TreeIter
> xEntry(rTreeView
.make_iterator(&rIter
));
401 if (!rTreeView
.get_iter_first(*xEntry
))
404 while (xEntry
&& rTreeView
.iter_compare(*xEntry
, rIter
) != 0)
406 if (!rTreeView
.iter_next(*xEntry
))
414 bool IsEntryVisible(const weld::TreeView
& rTreeView
, const weld::TreeIter
& rIter
)
416 // short circuit for the common case
417 if (rTreeView
.get_iter_depth(rIter
) == 0)
420 std::unique_ptr
<weld::TreeIter
> xEntry(rTreeView
.make_iterator(&rIter
));
421 bool bRetVal
= false;
424 if (rTreeView
.get_iter_depth(*xEntry
) == 0)
429 } while (rTreeView
.iter_parent(*xEntry
) && rTreeView
.get_row_expanded(*xEntry
));
434 VclBuilder::VclBuilder(vcl::Window
* pParent
, const OUString
& sUIDir
, const OUString
& sUIFile
,
435 const OString
& sID
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
,
436 bool bLegacy
, const NotebookBarAddonsItem
* pNotebookBarAddonsItem
)
437 : m_pNotebookBarAddonsItem(pNotebookBarAddonsItem
438 ? new NotebookBarAddonsItem(*pNotebookBarAddonsItem
)
439 : new NotebookBarAddonsItem
{})
441 , m_sHelpRoot(OUStringToOString(sUIFile
, RTL_TEXTENCODING_UTF8
))
442 , m_pStringReplace(Translate::GetReadStringHook())
444 , m_bToplevelParentFound(false)
446 , m_pParserState(new ParserState
)
449 m_bToplevelHasDeferredInit
= pParent
&&
450 ((pParent
->IsSystemWindow() && static_cast<SystemWindow
*>(pParent
)->isDeferredInit()) ||
451 (pParent
->IsDockingWindow() && static_cast<DockingWindow
*>(pParent
)->isDeferredInit()));
452 m_bToplevelHasDeferredProperties
= m_bToplevelHasDeferredInit
;
454 sal_Int32 nIdx
= m_sHelpRoot
.lastIndexOf('.');
456 m_sHelpRoot
= m_sHelpRoot
.copy(0, nIdx
);
457 m_sHelpRoot
+= OString('/');
459 OUString sUri
= sUIDir
+ sUIFile
;
463 xmlreader::XmlReader
reader(sUri
);
465 handleChild(pParent
, nullptr, reader
);
467 catch (const css::uno::Exception
&rExcept
)
469 DBG_UNHANDLED_EXCEPTION("vcl.builder", "Unable to read .ui file");
470 CrashReporter::addKeyValue("VclBuilderException", "Unable to read .ui file: " + rExcept
.Message
, CrashReporter::Write
);
474 //Set Mnemonic widgets when everything has been imported
475 for (auto const& mnemonicWidget
: m_pParserState
->m_aMnemonicWidgetMaps
)
477 FixedText
*pOne
= get
<FixedText
>(mnemonicWidget
.m_sID
);
478 vcl::Window
*pOther
= get(mnemonicWidget
.m_sValue
.toUtf8());
479 SAL_WARN_IF(!pOne
|| !pOther
, "vcl", "missing either source " << mnemonicWidget
.m_sID
480 << " or target " << mnemonicWidget
.m_sValue
<< " member of Mnemonic Widget Mapping");
482 pOne
->set_mnemonic_widget(pOther
);
485 //Set a11y relations and role when everything has been imported
486 for (auto const& elemAtk
: m_pParserState
->m_aAtkInfo
)
488 vcl::Window
*pSource
= elemAtk
.first
;
489 const stringmap
&rMap
= elemAtk
.second
;
491 for (auto const& elemMap
: rMap
)
493 const OString
&rType
= elemMap
.first
;
494 const OUString
&rParam
= elemMap
.second
;
497 sal_Int16 role
= BuilderUtils::getRoleFromName(rParam
.toUtf8());
498 if (role
!= com::sun::star::accessibility::AccessibleRole::UNKNOWN
)
499 pSource
->SetAccessibleRole(role
);
503 vcl::Window
*pTarget
= get(rParam
.toUtf8());
504 SAL_WARN_IF(!pTarget
, "vcl", "missing parameter of a11y relation: " << rParam
);
507 if (rType
== "labelled-by")
508 pSource
->SetAccessibleRelationLabeledBy(pTarget
);
509 else if (rType
== "label-for")
510 pSource
->SetAccessibleRelationLabelFor(pTarget
);
511 else if (rType
== "member-of")
512 pSource
->SetAccessibleRelationMemberOf(pTarget
);
515 SAL_WARN("vcl.builder", "unhandled a11y relation :" << rType
);
521 //Set radiobutton groups when everything has been imported
522 for (auto const& elem
: m_pParserState
->m_aGroupMaps
)
524 RadioButton
*pOne
= get
<RadioButton
>(elem
.m_sID
);
525 RadioButton
*pOther
= get
<RadioButton
>(elem
.m_sValue
);
526 SAL_WARN_IF(!pOne
|| !pOther
, "vcl", "missing member of radiobutton group");
530 pOne
->group(*pOther
);
533 pOther
->group(*pOne
);
534 std::stable_sort(pOther
->m_xGroup
->begin(), pOther
->m_xGroup
->end(), sortIntoBestTabTraversalOrder(this));
539 //Set ComboBox models when everything has been imported
540 for (auto const& elem
: m_pParserState
->m_aModelMaps
)
542 vcl::Window
* pTarget
= get(elem
.m_sID
);
543 ListBox
*pListBoxTarget
= dynamic_cast<ListBox
*>(pTarget
);
544 ComboBox
*pComboBoxTarget
= dynamic_cast<ComboBox
*>(pTarget
);
545 SvTabListBox
*pTreeBoxTarget
= dynamic_cast<SvTabListBox
*>(pTarget
);
546 // pStore may be empty
547 const ListStore
*pStore
= get_model_by_name(elem
.m_sValue
.toUtf8());
548 SAL_WARN_IF(!pListBoxTarget
&& !pComboBoxTarget
&& !pTreeBoxTarget
, "vcl", "missing elements of combobox");
549 if (pListBoxTarget
&& pStore
)
550 mungeModel(*pListBoxTarget
, *pStore
, elem
.m_nActiveId
);
551 else if (pComboBoxTarget
&& pStore
)
552 mungeModel(*pComboBoxTarget
, *pStore
, elem
.m_nActiveId
);
553 else if (pTreeBoxTarget
&& pStore
)
554 mungeModel(*pTreeBoxTarget
, *pStore
, elem
.m_nActiveId
);
557 //Set TextView buffers when everything has been imported
558 for (auto const& elem
: m_pParserState
->m_aTextBufferMaps
)
560 VclMultiLineEdit
*pTarget
= get
<VclMultiLineEdit
>(elem
.m_sID
);
561 const TextBuffer
*pBuffer
= get_buffer_by_name(elem
.m_sValue
.toUtf8());
562 SAL_WARN_IF(!pTarget
|| !pBuffer
, "vcl", "missing elements of textview/textbuffer");
563 if (pTarget
&& pBuffer
)
564 mungeTextBuffer(*pTarget
, *pBuffer
);
567 //Set SpinButton adjustments when everything has been imported
568 for (auto const& elem
: m_pParserState
->m_aNumericFormatterAdjustmentMaps
)
570 NumericFormatter
*pTarget
= dynamic_cast<NumericFormatter
*>(get(elem
.m_sID
));
571 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
572 SAL_WARN_IF(!pTarget
, "vcl", "missing NumericFormatter element of spinbutton/adjustment");
573 SAL_WARN_IF(!pAdjustment
, "vcl", "missing Adjustment element of spinbutton/adjustment");
574 if (pTarget
&& pAdjustment
)
575 mungeAdjustment(*pTarget
, *pAdjustment
);
578 for (auto const& elem
: m_pParserState
->m_aFormattedFormatterAdjustmentMaps
)
580 FormattedField
*pTarget
= dynamic_cast<FormattedField
*>(get(elem
.m_sID
));
581 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
582 SAL_WARN_IF(!pTarget
, "vcl", "missing FormattedField element of spinbutton/adjustment");
583 SAL_WARN_IF(!pAdjustment
, "vcl", "missing Adjustment element of spinbutton/adjustment");
584 if (pTarget
&& pAdjustment
)
585 mungeAdjustment(*pTarget
, *pAdjustment
);
588 //Set ScrollBar adjustments when everything has been imported
589 for (auto const& elem
: m_pParserState
->m_aScrollAdjustmentMaps
)
591 ScrollBar
*pTarget
= get
<ScrollBar
>(elem
.m_sID
);
592 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
593 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of scrollbar/adjustment");
594 if (pTarget
&& pAdjustment
)
595 mungeAdjustment(*pTarget
, *pAdjustment
);
598 //Set Scale(Slider) adjustments
599 for (auto const& elem
: m_pParserState
->m_aSliderAdjustmentMaps
)
601 Slider
* pTarget
= dynamic_cast<Slider
*>(get(elem
.m_sID
));
602 const Adjustment
* pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
603 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of scale(slider)/adjustment");
604 if (pTarget
&& pAdjustment
)
606 mungeAdjustment(*pTarget
, *pAdjustment
);
610 //Set size-groups when all widgets have been imported
611 for (auto const& sizeGroup
: m_pParserState
->m_aSizeGroups
)
613 std::shared_ptr
<VclSizeGroup
> xGroup(std::make_shared
<VclSizeGroup
>());
615 for (auto const& elem
: sizeGroup
.m_aProperties
)
617 const OString
&rKey
= elem
.first
;
618 const OUString
&rValue
= elem
.second
;
619 xGroup
->set_property(rKey
, rValue
);
622 for (auto const& elem
: sizeGroup
.m_aWidgets
)
624 vcl::Window
* pWindow
= get(elem
.getStr());
625 pWindow
->add_to_size_group(xGroup
);
629 //Set button images when everything has been imported
630 std::set
<OUString
> aImagesToBeRemoved
;
631 for (auto const& elem
: m_pParserState
->m_aButtonImageWidgetMaps
)
633 PushButton
*pTargetButton
= nullptr;
634 RadioButton
*pTargetRadio
= nullptr;
635 Button
*pTarget
= nullptr;
639 pTargetButton
= get
<PushButton
>(elem
.m_sID
);
640 pTarget
= pTargetButton
;
644 pTargetRadio
= get
<RadioButton
>(elem
.m_sID
);
645 pTarget
= pTargetRadio
;
648 FixedImage
*pImage
= get
<FixedImage
>(elem
.m_sValue
.toUtf8());
649 SAL_WARN_IF(!pTarget
|| !pImage
,
650 "vcl", "missing elements of button/image/stock");
651 if (!pTarget
|| !pImage
)
653 aImagesToBeRemoved
.insert(elem
.m_sValue
);
655 VclBuilder::StockMap::iterator aFind
= m_pParserState
->m_aStockMap
.find(elem
.m_sValue
.toUtf8());
656 if (aFind
== m_pParserState
->m_aStockMap
.end())
660 const Image
& rImage
= pImage
->GetImage();
661 if (rImage
.GetStock() == "pan-down-symbolic")
662 pTargetButton
->SetSymbol(SymbolType::SPIN_DOWN
);
663 else if (rImage
.GetStock() == "pan-up-symbolic")
664 pTargetButton
->SetSymbol(SymbolType::SPIN_UP
);
666 pTargetButton
->SetModeImage(rImage
);
667 if (pImage
->GetStyle() & WB_SMALLSTYLE
)
669 pTargetButton
->SetStyle(pTargetButton
->GetStyle() | WB_SMALLSTYLE
);
670 Size
aSz(pTargetButton
->GetModeImage().GetSizePixel());
673 if (pTargetButton
->get_width_request() == -1)
674 pTargetButton
->set_width_request(aSz
.Width());
675 if (pTargetButton
->get_height_request() == -1)
676 pTargetButton
->set_height_request(aSz
.Height());
680 pTargetRadio
->SetModeRadioImage(pImage
->GetImage());
684 const stockinfo
&rImageInfo
= aFind
->second
;
685 SymbolType eType
= mapStockToSymbol(rImageInfo
.m_sStock
);
686 SAL_WARN_IF(eType
== SymbolType::DONTKNOW
, "vcl", "missing stock image element for button");
687 if (eType
== SymbolType::DONTKNOW
)
691 pTargetButton
->SetSymbol(eType
);
692 //fdo#76457 keep symbol images small e.g. tools->customize->menu
693 //but images the right size. Really the PushButton::CalcMinimumSize
694 //and PushButton::ImplDrawPushButton are the better place to handle
695 //this, but its such a train-wreck
696 if (eType
!= SymbolType::IMAGE
)
697 pTargetButton
->SetStyle(pTargetButton
->GetStyle() | WB_SMALLSTYLE
);
700 SAL_WARN_IF(eType
!= SymbolType::IMAGE
, "vcl.builder", "unimplemented symbol type for radiobuttons");
701 if (eType
== SymbolType::IMAGE
)
703 Image
const aImage(StockImage::Yes
,
704 mapStockToImageResource(rImageInfo
.m_sStock
));
706 pTargetButton
->SetModeImage(aImage
);
708 pTargetRadio
->SetModeRadioImage(aImage
);
710 switch (rImageInfo
.m_nSize
)
713 pTarget
->SetSmallSymbol();
716 // large toolbar, make bigger than normal (4)
717 pTarget
->set_width_request(pTarget
->GetOptimalSize().Width() * 1.5);
718 pTarget
->set_height_request(pTarget
->GetOptimalSize().Height() * 1.5);
723 SAL_WARN("vcl.builder", "unsupported image size " << rImageInfo
.m_nSize
);
729 //There may be duplicate use of an Image, so we used a set to collect and
730 //now we can remove them from the tree after their final munge
731 for (auto const& elem
: aImagesToBeRemoved
)
733 delete_by_name(elem
.toUtf8());
736 //fill in any stock icons in surviving images
737 for (auto const& elem
: m_pParserState
->m_aStockMap
)
739 FixedImage
*pImage
= get
<FixedImage
>(elem
.first
);
740 SAL_WARN_IF(!pImage
, "vcl", "missing elements of image/stock: " << elem
.first
);
744 const stockinfo
&rImageInfo
= elem
.second
;
745 if (rImageInfo
.m_sStock
== "gtk-missing-image")
748 SymbolType eType
= mapStockToSymbol(rImageInfo
.m_sStock
);
749 SAL_WARN_IF(eType
!= SymbolType::IMAGE
, "vcl", "unimplemented symbol type for images");
750 if (eType
!= SymbolType::IMAGE
)
753 Image
const aImage(StockImage::Yes
,
754 mapStockToImageResource(rImageInfo
.m_sStock
));
755 pImage
->SetImage(aImage
);
758 //Set button menus when everything has been imported
759 for (auto const& elem
: m_pParserState
->m_aButtonMenuMaps
)
761 MenuButton
*pTarget
= get
<MenuButton
>(elem
.m_sID
);
762 PopupMenu
*pMenu
= get_menu(elem
.m_sValue
.toUtf8());
763 SAL_WARN_IF(!pTarget
|| !pMenu
,
764 "vcl", "missing elements of button/menu");
765 if (!pTarget
|| !pMenu
)
767 pTarget
->SetPopupMenu(pMenu
);
770 //Remove ScrollWindow parent widgets whose children in vcl implement scrolling
772 for (auto const& elem
: m_pParserState
->m_aRedundantParentWidgets
)
774 delete_by_window(elem
.first
);
777 //fdo#67378 merge the label into the disclosure button
778 for (auto const& elem
: m_pParserState
->m_aExpanderWidgets
)
780 vcl::Window
*pChild
= elem
->get_child();
781 vcl::Window
* pLabel
= elem
->GetWindow(GetWindowType::LastChild
);
782 if (pLabel
&& pLabel
!= pChild
&& pLabel
->GetType() == WindowType::FIXEDTEXT
)
784 FixedText
*pLabelWidget
= static_cast<FixedText
*>(pLabel
);
785 elem
->set_label(pLabelWidget
->GetText());
786 if (pLabelWidget
->IsControlFont())
787 elem
->get_label_widget()->SetControlFont(pLabelWidget
->GetControlFont());
788 delete_by_window(pLabel
);
792 // create message dialog message area now
793 for (auto const& elem
: m_pParserState
->m_aMessageDialogs
)
794 elem
->create_message_area();
796 //drop maps, etc. that we don't need again
797 m_pParserState
.reset();
799 SAL_WARN_IF(!m_sID
.isEmpty() && (!m_bToplevelParentFound
&& !get_by_name(m_sID
)), "vcl.builder",
800 "Requested top level widget \"" << m_sID
<< "\" not found in " << sUIFile
);
802 #if defined SAL_LOG_WARN
803 if (m_bToplevelParentFound
&& m_pParent
->IsDialog())
806 bool bHasDefButton
= false;
807 for (auto const& child
: m_aChildren
)
809 if (isButtonType(child
.m_pWindow
->GetType()))
812 if (child
.m_pWindow
->GetStyle() & WB_DEFBUTTON
)
814 bHasDefButton
= true;
819 SAL_WARN_IF(nButtons
&& !bHasDefButton
, "vcl.builder", "No default button defined in " << sUIFile
);
823 const bool bHideHelp
= comphelper::LibreOfficeKit::isActive() &&
824 officecfg::Office::Common::Help::HelpRootURL::get().isEmpty();
827 if (vcl::Window
*pHelpButton
= get("help"))
832 VclBuilder::~VclBuilder()
837 void VclBuilder::disposeBuilder()
839 for (std::vector
<WinAndId
>::reverse_iterator aI
= m_aChildren
.rbegin(),
840 aEnd
= m_aChildren
.rend(); aI
!= aEnd
; ++aI
)
842 aI
->m_pWindow
.disposeAndClear();
846 for (std::vector
<MenuAndId
>::reverse_iterator aI
= m_aMenus
.rbegin(),
847 aEnd
= m_aMenus
.rend(); aI
!= aEnd
; ++aI
)
849 aI
->m_pMenu
.disposeAndClear();
857 bool extractHasFrame(VclBuilder::stringmap
& rMap
)
859 bool bHasFrame
= true;
860 VclBuilder::stringmap::iterator aFind
= rMap
.find("has-frame");
861 if (aFind
!= rMap
.end())
863 bHasFrame
= toBool(aFind
->second
);
869 bool extractDrawValue(VclBuilder::stringmap
& rMap
)
871 bool bDrawValue
= true;
872 VclBuilder::stringmap::iterator aFind
= rMap
.find("draw-value");
873 if (aFind
!= rMap
.end())
875 bDrawValue
= toBool(aFind
->second
);
881 OUString
extractPopupMenu(VclBuilder::stringmap
& rMap
)
884 VclBuilder::stringmap::iterator aFind
= rMap
.find("popup");
885 if (aFind
!= rMap
.end())
887 sRet
= aFind
->second
;
893 OUString
extractWidgetName(VclBuilder::stringmap
& rMap
)
896 VclBuilder::stringmap::iterator aFind
= rMap
.find("name");
897 if (aFind
!= rMap
.end())
899 sRet
= aFind
->second
;
905 OUString
extractValuePos(VclBuilder::stringmap
& rMap
)
907 OUString
sRet("top");
908 VclBuilder::stringmap::iterator aFind
= rMap
.find("value-pos");
909 if (aFind
!= rMap
.end())
911 sRet
= aFind
->second
;
917 OUString
extractTypeHint(VclBuilder::stringmap
&rMap
)
919 OUString
sRet("normal");
920 VclBuilder::stringmap::iterator aFind
= rMap
.find("type-hint");
921 if (aFind
!= rMap
.end())
923 sRet
= aFind
->second
;
929 bool extractResizable(VclBuilder::stringmap
&rMap
)
931 bool bResizable
= true;
932 VclBuilder::stringmap::iterator aFind
= rMap
.find("resizable");
933 if (aFind
!= rMap
.end())
935 bResizable
= toBool(aFind
->second
);
941 #if HAVE_FEATURE_DESKTOP
942 bool extractModal(VclBuilder::stringmap
&rMap
)
945 VclBuilder::stringmap::iterator aFind
= rMap
.find("modal");
946 if (aFind
!= rMap
.end())
948 bModal
= toBool(aFind
->second
);
955 bool extractDecorated(VclBuilder::stringmap
&rMap
)
957 bool bDecorated
= true;
958 VclBuilder::stringmap::iterator aFind
= rMap
.find("decorated");
959 if (aFind
!= rMap
.end())
961 bDecorated
= toBool(aFind
->second
);
967 bool extractCloseable(VclBuilder::stringmap
&rMap
)
969 bool bCloseable
= true;
970 VclBuilder::stringmap::iterator aFind
= rMap
.find("deletable");
971 if (aFind
!= rMap
.end())
973 bCloseable
= toBool(aFind
->second
);
979 bool extractEntry(VclBuilder::stringmap
&rMap
)
981 bool bHasEntry
= false;
982 VclBuilder::stringmap::iterator aFind
= rMap
.find("has-entry");
983 if (aFind
!= rMap
.end())
985 bHasEntry
= toBool(aFind
->second
);
991 bool extractOrientation(VclBuilder::stringmap
&rMap
)
993 bool bVertical
= false;
994 VclBuilder::stringmap::iterator aFind
= rMap
.find("orientation");
995 if (aFind
!= rMap
.end())
997 bVertical
= aFind
->second
.equalsIgnoreAsciiCase("vertical");
1003 bool extractVerticalTabPos(VclBuilder::stringmap
&rMap
)
1005 bool bVertical
= false;
1006 VclBuilder::stringmap::iterator aFind
= rMap
.find("tab-pos");
1007 if (aFind
!= rMap
.end())
1009 bVertical
= aFind
->second
.equalsIgnoreAsciiCase("left") ||
1010 aFind
->second
.equalsIgnoreAsciiCase("right");
1016 bool extractInconsistent(VclBuilder::stringmap
&rMap
)
1018 bool bInconsistent
= false;
1019 VclBuilder::stringmap::iterator aFind
= rMap
.find("inconsistent");
1020 if (aFind
!= rMap
.end())
1022 bInconsistent
= toBool(aFind
->second
);
1025 return bInconsistent
;
1028 OUString
extractIconName(VclBuilder::stringmap
&rMap
)
1031 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("icon-name"));
1032 if (aFind
!= rMap
.end())
1034 sIconName
= aFind
->second
;
1040 OUString
extractStockId(VclBuilder::stringmap
&rMap
)
1043 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("stock-id"));
1044 if (aFind
!= rMap
.end())
1046 sIconName
= aFind
->second
;
1052 OUString
getStockText(const OUString
&rType
)
1054 if (rType
== "gtk-ok")
1055 return VclResId(SV_BUTTONTEXT_OK
);
1056 else if (rType
== "gtk-cancel")
1057 return VclResId(SV_BUTTONTEXT_CANCEL
);
1058 else if (rType
== "gtk-help")
1059 return VclResId(SV_BUTTONTEXT_HELP
);
1060 else if (rType
== "gtk-close")
1061 return VclResId(SV_BUTTONTEXT_CLOSE
);
1062 else if (rType
== "gtk-revert-to-saved")
1063 return VclResId(SV_BUTTONTEXT_RESET
);
1064 else if (rType
== "gtk-add")
1065 return VclResId(SV_BUTTONTEXT_ADD
);
1066 else if (rType
== "gtk-delete")
1067 return VclResId(SV_BUTTONTEXT_DELETE
);
1068 else if (rType
== "gtk-remove")
1069 return VclResId(SV_BUTTONTEXT_REMOVE
);
1070 else if (rType
== "gtk-new")
1071 return VclResId(SV_BUTTONTEXT_NEW
);
1072 else if (rType
== "gtk-edit")
1073 return VclResId(SV_BUTTONTEXT_EDIT
);
1074 else if (rType
== "gtk-apply")
1075 return VclResId(SV_BUTTONTEXT_APPLY
);
1076 else if (rType
== "gtk-save")
1077 return VclResId(SV_BUTTONTEXT_SAVE
);
1078 else if (rType
== "gtk-open")
1079 return VclResId(SV_BUTTONTEXT_OPEN
);
1080 else if (rType
== "gtk-undo")
1081 return VclResId(SV_BUTTONTEXT_UNDO
);
1082 else if (rType
== "gtk-paste")
1083 return VclResId(SV_BUTTONTEXT_PASTE
);
1084 else if (rType
== "gtk-media-next")
1085 return VclResId(SV_BUTTONTEXT_NEXT
);
1086 else if (rType
== "gtk-media-previous")
1087 return VclResId(SV_BUTTONTEXT_PREV
);
1088 else if (rType
== "gtk-go-up")
1089 return VclResId(SV_BUTTONTEXT_GO_UP
);
1090 else if (rType
== "gtk-go-down")
1091 return VclResId(SV_BUTTONTEXT_GO_DOWN
);
1092 else if (rType
== "gtk-clear")
1093 return VclResId(SV_BUTTONTEXT_CLEAR
);
1094 else if (rType
== "gtk-media-play")
1095 return VclResId(SV_BUTTONTEXT_PLAY
);
1096 else if (rType
== "gtk-find")
1097 return VclResId(SV_BUTTONTEXT_FIND
);
1098 else if (rType
== "gtk-stop")
1099 return VclResId(SV_BUTTONTEXT_STOP
);
1100 else if (rType
== "gtk-connect")
1101 return VclResId(SV_BUTTONTEXT_CONNECT
);
1102 else if (rType
== "gtk-yes")
1103 return VclResId(SV_BUTTONTEXT_YES
);
1104 else if (rType
== "gtk-no")
1105 return VclResId(SV_BUTTONTEXT_NO
);
1106 SAL_WARN("vcl.builder", "unknown stock type: " << rType
);
1110 bool extractStock(VclBuilder::stringmap
&rMap
)
1112 bool bIsStock
= false;
1113 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("use-stock"));
1114 if (aFind
!= rMap
.end())
1116 bIsStock
= toBool(aFind
->second
);
1122 WinBits
extractRelief(VclBuilder::stringmap
&rMap
)
1124 WinBits nBits
= WB_3DLOOK
;
1125 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("relief"));
1126 if (aFind
!= rMap
.end())
1128 if (aFind
->second
== "half")
1129 nBits
= WB_FLATBUTTON
| WB_BEVELBUTTON
;
1130 else if (aFind
->second
== "none")
1131 nBits
= WB_FLATBUTTON
;
1137 OUString
extractLabel(VclBuilder::stringmap
&rMap
)
1140 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("label"));
1141 if (aFind
!= rMap
.end())
1143 sType
= aFind
->second
;
1149 OUString
extractActionName(VclBuilder::stringmap
&rMap
)
1151 OUString sActionName
;
1152 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("action-name"));
1153 if (aFind
!= rMap
.end())
1155 sActionName
= aFind
->second
;
1161 bool extractVisible(VclBuilder::stringmap
&rMap
)
1164 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("visible"));
1165 if (aFind
!= rMap
.end())
1167 bRet
= toBool(aFind
->second
);
1173 Size
extractSizeRequest(VclBuilder::stringmap
&rMap
)
1175 OUString
sWidthRequest("0");
1176 OUString
sHeightRequest("0");
1177 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("width-request"));
1178 if (aFind
!= rMap
.end())
1180 sWidthRequest
= aFind
->second
;
1183 aFind
= rMap
.find("height-request");
1184 if (aFind
!= rMap
.end())
1186 sHeightRequest
= aFind
->second
;
1189 return Size(sWidthRequest
.toInt32(), sHeightRequest
.toInt32());
1192 OUString
extractTooltipText(VclBuilder::stringmap
&rMap
)
1194 OUString sTooltipText
;
1195 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("tooltip-text"));
1196 if (aFind
== rMap
.end())
1197 aFind
= rMap
.find(OString("tooltip-markup"));
1198 if (aFind
!= rMap
.end())
1200 sTooltipText
= aFind
->second
;
1203 return sTooltipText
;
1206 float extractAlignment(VclBuilder::stringmap
&rMap
)
1209 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("alignment"));
1210 if (aFind
!= rMap
.end())
1212 f
= aFind
->second
.toFloat();
1218 OUString
extractTitle(VclBuilder::stringmap
&rMap
)
1221 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("title"));
1222 if (aFind
!= rMap
.end())
1224 sTitle
= aFind
->second
;
1230 bool extractHeadersVisible(VclBuilder::stringmap
&rMap
)
1232 bool bHeadersVisible
= true;
1233 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("headers-visible"));
1234 if (aFind
!= rMap
.end())
1236 bHeadersVisible
= toBool(aFind
->second
);
1239 return bHeadersVisible
;
1242 bool extractSortIndicator(VclBuilder::stringmap
&rMap
)
1244 bool bSortIndicator
= false;
1245 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("sort-indicator"));
1246 if (aFind
!= rMap
.end())
1248 bSortIndicator
= toBool(aFind
->second
);
1251 return bSortIndicator
;
1254 bool extractClickable(VclBuilder::stringmap
&rMap
)
1256 bool bClickable
= false;
1257 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("clickable"));
1258 if (aFind
!= rMap
.end())
1260 bClickable
= toBool(aFind
->second
);
1266 void setupFromActionName(Button
*pButton
, VclBuilder::stringmap
&rMap
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
)
1271 OUString
aCommand(extractActionName(rMap
));
1272 if (aCommand
.isEmpty())
1275 OUString
aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame
));
1276 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(aCommand
, aModuleName
);
1277 OUString
aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties
));
1278 if (!aLabel
.isEmpty())
1279 pButton
->SetText(aLabel
);
1281 OUString
aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(aCommand
, aProperties
, rFrame
));
1282 if (!aTooltip
.isEmpty())
1283 pButton
->SetQuickHelpText(aTooltip
);
1285 Image
aImage(vcl::CommandInfoProvider::GetImageForCommand(aCommand
, rFrame
));
1286 pButton
->SetModeImage(aImage
);
1288 pButton
->SetCommandHandler(aCommand
);
1291 VclPtr
<Button
> extractStockAndBuildPushButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
, bool bToggle
, bool bLegacy
)
1293 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
;
1297 nBits
|= extractRelief(rMap
);
1299 VclPtr
<Button
> xWindow
;
1301 if (extractStock(rMap
))
1303 OUString sType
= extractLabel(rMap
);
1306 if (sType
== "gtk-ok")
1307 xWindow
= VclPtr
<OKButton
>::Create(pParent
, nBits
);
1308 else if (sType
== "gtk-cancel")
1309 xWindow
= VclPtr
<CancelButton
>::Create(pParent
, nBits
);
1310 else if (sType
== "gtk-close")
1311 xWindow
= VclPtr
<CloseButton
>::Create(pParent
, nBits
);
1312 else if (sType
== "gtk-help")
1313 xWindow
= VclPtr
<HelpButton
>::Create(pParent
, nBits
);
1317 xWindow
= VclPtr
<PushButton
>::Create(pParent
, nBits
);
1318 xWindow
->SetText(getStockText(sType
));
1323 xWindow
= VclPtr
<PushButton
>::Create(pParent
, nBits
);
1327 VclPtr
<MenuButton
> extractStockAndBuildMenuButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
)
1329 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1331 nBits
|= extractRelief(rMap
);
1333 VclPtr
<MenuButton
> xWindow
= VclPtr
<MenuButton
>::Create(pParent
, nBits
);
1335 if (extractStock(rMap
))
1337 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1343 VclPtr
<MenuButton
> extractStockAndBuildMenuToggleButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
)
1345 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1347 nBits
|= extractRelief(rMap
);
1349 VclPtr
<MenuButton
> xWindow
= VclPtr
<MenuToggleButton
>::Create(pParent
, nBits
);
1351 if (extractStock(rMap
))
1353 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1359 WinBits
extractDeferredBits(VclBuilder::stringmap
&rMap
)
1361 WinBits nBits
= WB_3DLOOK
|WB_HIDE
;
1362 if (extractResizable(rMap
))
1363 nBits
|= WB_SIZEABLE
;
1364 if (extractCloseable(rMap
))
1365 nBits
|= WB_CLOSEABLE
;
1366 if (!extractDecorated(rMap
))
1367 nBits
|= WB_OWNERDRAWDECORATION
;
1368 OUString
sType(extractTypeHint(rMap
));
1369 if (sType
== "utility")
1370 nBits
|= WB_SYSTEMWINDOW
| WB_DIALOGCONTROL
| WB_MOVEABLE
;
1371 else if (sType
== "popup-menu")
1372 nBits
|= WB_SYSTEMWINDOW
| WB_DIALOGCONTROL
| WB_POPUP
;
1373 else if (sType
== "dock")
1374 nBits
|= WB_DOCKABLE
| WB_MOVEABLE
;
1376 nBits
|= WB_MOVEABLE
;
1381 void VclBuilder::extractGroup(const OString
&id
, stringmap
&rMap
)
1383 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("group"));
1384 if (aFind
!= rMap
.end())
1386 OUString sID
= aFind
->second
;
1387 sal_Int32 nDelim
= sID
.indexOf(':');
1389 sID
= sID
.copy(0, nDelim
);
1390 m_pParserState
->m_aGroupMaps
.emplace_back(id
, sID
.toUtf8());
1395 void VclBuilder::connectNumericFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1397 if (!rAdjustment
.isEmpty())
1398 m_pParserState
->m_aNumericFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1401 void VclBuilder::connectFormattedFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1403 if (!rAdjustment
.isEmpty())
1404 m_pParserState
->m_aFormattedFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1407 bool VclBuilder::extractAdjustmentToMap(const OString
& id
, VclBuilder::stringmap
& rMap
, std::vector
<WidgetAdjustmentMap
>& rAdjustmentMap
)
1409 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("adjustment"));
1410 if (aFind
!= rMap
.end())
1412 rAdjustmentMap
.emplace_back(id
, aFind
->second
);
1421 sal_Int32
extractActive(VclBuilder::stringmap
&rMap
)
1423 sal_Int32 nActiveId
= 0;
1424 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("active"));
1425 if (aFind
!= rMap
.end())
1427 nActiveId
= aFind
->second
.toInt32();
1433 bool extractSelectable(VclBuilder::stringmap
&rMap
)
1435 bool bSelectable
= false;
1436 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("selectable"));
1437 if (aFind
!= rMap
.end())
1439 bSelectable
= toBool(aFind
->second
);
1445 OUString
extractAdjustment(VclBuilder::stringmap
&rMap
)
1447 OUString sAdjustment
;
1448 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("adjustment"));
1449 if (aFind
!= rMap
.end())
1451 sAdjustment
= aFind
->second
;
1458 bool extractDrawIndicator(VclBuilder::stringmap
&rMap
)
1460 bool bDrawIndicator
= false;
1461 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("draw-indicator"));
1462 if (aFind
!= rMap
.end())
1464 bDrawIndicator
= toBool(aFind
->second
);
1467 return bDrawIndicator
;
1471 void VclBuilder::extractModel(const OString
&id
, stringmap
&rMap
)
1473 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("model"));
1474 if (aFind
!= rMap
.end())
1476 m_pParserState
->m_aModelMaps
.emplace_back(id
, aFind
->second
,
1477 extractActive(rMap
));
1482 void VclBuilder::extractBuffer(const OString
&id
, stringmap
&rMap
)
1484 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("buffer"));
1485 if (aFind
!= rMap
.end())
1487 m_pParserState
->m_aTextBufferMaps
.emplace_back(id
, aFind
->second
);
1492 void VclBuilder::extractStock(const OString
&id
, stringmap
&rMap
)
1494 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("stock"));
1495 if (aFind
== rMap
.end())
1499 aInfo
.m_sStock
= aFind
->second
;
1501 aFind
= rMap
.find(OString("icon-size"));
1502 if (aFind
!= rMap
.end())
1504 aInfo
.m_nSize
= aFind
->second
.toInt32();
1507 m_pParserState
->m_aStockMap
[id
] = aInfo
;
1510 void VclBuilder::extractButtonImage(const OString
&id
, stringmap
&rMap
, bool bRadio
)
1512 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("image"));
1513 if (aFind
!= rMap
.end())
1515 m_pParserState
->m_aButtonImageWidgetMaps
.emplace_back(id
, aFind
->second
, bRadio
);
1520 void VclBuilder::extractMnemonicWidget(const OString
&rLabelID
, stringmap
&rMap
)
1522 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("mnemonic-widget"));
1523 if (aFind
!= rMap
.end())
1525 OUString sID
= aFind
->second
;
1526 sal_Int32 nDelim
= sID
.indexOf(':');
1528 sID
= sID
.copy(0, nDelim
);
1529 m_pParserState
->m_aMnemonicWidgetMaps
.emplace_back(rLabelID
, sID
);
1534 vcl::Window
* VclBuilder::prepareWidgetOwnScrolling(vcl::Window
*pParent
, WinBits
&rWinStyle
)
1536 //For Widgets that manage their own scrolling, if one appears as a child of
1537 //a scrolling window shoehorn that scrolling settings to this widget and
1538 //return the real parent to use
1539 if (pParent
&& pParent
->GetType() == WindowType::SCROLLWINDOW
)
1541 WinBits nScrollBits
= pParent
->GetStyle();
1542 nScrollBits
&= (WB_AUTOHSCROLL
|WB_HSCROLL
|WB_AUTOVSCROLL
|WB_VSCROLL
);
1543 rWinStyle
|= nScrollBits
;
1544 if (static_cast<VclScrolledWindow
*>(pParent
)->HasVisibleBorder())
1545 rWinStyle
|= WB_BORDER
;
1546 pParent
= pParent
->GetParent();
1552 void VclBuilder::cleanupWidgetOwnScrolling(vcl::Window
*pScrollParent
, vcl::Window
*pWindow
, stringmap
&rMap
)
1554 //remove the redundant scrolling parent
1555 sal_Int32 nWidthReq
= pScrollParent
->get_width_request();
1556 rMap
[OString("width-request")] = OUString::number(nWidthReq
);
1557 sal_Int32 nHeightReq
= pScrollParent
->get_height_request();
1558 rMap
[OString("height-request")] = OUString::number(nHeightReq
);
1560 m_pParserState
->m_aRedundantParentWidgets
[pScrollParent
] = pWindow
;
1563 #ifndef DISABLE_DYNLOADING
1565 extern "C" { static void thisModule() {} }
1569 // Don't unload the module on destruction
1570 class NoAutoUnloadModule
: public osl::Module
1573 ~NoAutoUnloadModule() { release(); }
1578 typedef std::map
<OUString
, std::shared_ptr
<NoAutoUnloadModule
>> ModuleMap
;
1579 static ModuleMap g_aModuleMap
;
1581 #if ENABLE_MERGELIBS
1582 static std::shared_ptr
<NoAutoUnloadModule
> g_pMergedLib
= std::make_shared
<NoAutoUnloadModule
>();
1585 #ifndef SAL_DLLPREFIX
1586 # define SAL_DLLPREFIX ""
1591 void VclBuilder::preload()
1593 #ifndef DISABLE_DYNLOADING
1595 #if ENABLE_MERGELIBS
1596 g_pMergedLib
->loadRelative(&thisModule
, SVLIBRARY("merged"));
1598 // find -name '*ui*' | xargs grep 'class=".*lo-' |
1599 // sed 's/.*class="//' | sed 's/-.*$//' | sort | uniq
1600 static const char *aWidgetLibs
[] = {
1603 for (const auto & lib
: aWidgetLibs
)
1605 std::unique_ptr
<NoAutoUnloadModule
> pModule(new NoAutoUnloadModule
);
1606 OUString sModule
= SAL_DLLPREFIX
+ OUString::createFromAscii(lib
) + SAL_DLLEXTENSION
;
1607 if (pModule
->loadRelative(&thisModule
, sModule
))
1608 g_aModuleMap
.insert(std::make_pair(sModule
, std::move(pModule
)));
1610 #endif // ENABLE_MERGELIBS
1611 #endif // DISABLE_DYNLOADING
1614 #if defined DISABLE_DYNLOADING && !HAVE_FEATURE_DESKTOP
1615 extern "C" VclBuilder::customMakeWidget
lo_get_custom_widget_func(const char* name
);
1620 // Takes a string like "sfxlo-NotebookbarToolBox"
1621 VclBuilder::customMakeWidget
GetCustomMakeWidget(const OString
& rName
)
1623 const OString name
= rName
== "sfxlo-SidebarToolBox" ? "sfxlo-NotebookbarToolBox" : rName
;
1624 VclBuilder::customMakeWidget pFunction
= nullptr;
1625 if (sal_Int32 nDelim
= name
.indexOf('-'); nDelim
!= -1)
1627 const OString
aFunction(OString::Concat("make") + name
.subView(nDelim
+ 1));
1628 const OUString
sFunction(OStringToOUString(aFunction
, RTL_TEXTENCODING_UTF8
));
1630 #ifndef DISABLE_DYNLOADING
1631 const OUString sModule
= SAL_DLLPREFIX
1632 + OStringToOUString(name
.copy(0, nDelim
), RTL_TEXTENCODING_UTF8
)
1634 ModuleMap::iterator aI
= g_aModuleMap
.find(sModule
);
1635 if (aI
== g_aModuleMap
.end())
1637 std::shared_ptr
<NoAutoUnloadModule
> pModule
;
1638 #if ENABLE_MERGELIBS
1639 if (!g_pMergedLib
->is())
1640 g_pMergedLib
->loadRelative(&thisModule
, SVLIBRARY("merged"));
1641 if ((pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1642 g_pMergedLib
->getFunctionSymbol(sFunction
))))
1643 pModule
= g_pMergedLib
;
1647 pModule
= std::make_shared
<NoAutoUnloadModule
>();
1648 bool ok
= pModule
->loadRelative(&thisModule
, sModule
);
1652 // in the case of preloading, we don't have eg. the
1653 // libcuilo.so, but still need to dlsym the symbols -
1654 // which are already in-process
1655 if (comphelper::LibreOfficeKit::isActive())
1657 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(dlsym(RTLD_DEFAULT
, aFunction
.getStr()));
1659 assert(ok
&& "couldn't even directly dlsym the sFunction (available via preload)");
1662 assert(ok
&& "bad module name in .ui");
1666 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1667 pModule
->getFunctionSymbol(sFunction
));
1670 g_aModuleMap
.insert(std::make_pair(sModule
, pModule
));
1673 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1674 aI
->second
->getFunctionSymbol(sFunction
));
1675 #elif !HAVE_FEATURE_DESKTOP
1676 pFunction
= lo_get_custom_widget_func(sFunction
.toUtf8().getStr());
1677 SAL_WARN_IF(!pFunction
, "vcl.builder", "Could not find " << sFunction
);
1680 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1681 osl_getFunctionSymbol((oslModule
)RTLD_DEFAULT
, sFunction
.pData
));
1688 VclPtr
<vcl::Window
> VclBuilder::makeObject(vcl::Window
*pParent
, const OString
&name
, const OString
&id
,
1691 bool bIsPlaceHolder
= name
.isEmpty();
1692 bool bVertical
= false;
1694 if (pParent
&& (pParent
->GetType() == WindowType::TABCONTROL
||
1695 pParent
->GetType() == WindowType::VERTICALTABCONTROL
))
1697 bool bTopLevel(name
== "GtkDialog" || name
== "GtkMessageDialog" ||
1698 name
== "GtkWindow" || name
== "GtkPopover" || name
== "GtkAssistant");
1701 if (pParent
->GetType() == WindowType::TABCONTROL
)
1703 //We have to add a page
1704 //make default pageid == position
1705 TabControl
*pTabControl
= static_cast<TabControl
*>(pParent
);
1706 sal_uInt16 nNewPageCount
= pTabControl
->GetPageCount()+1;
1707 sal_uInt16 nNewPageId
= nNewPageCount
;
1708 pTabControl
->InsertPage(nNewPageId
, OUString());
1709 pTabControl
->SetCurPageId(nNewPageId
);
1710 SAL_WARN_IF(bIsPlaceHolder
, "vcl.builder", "we should have no placeholders for tabpages");
1711 if (!bIsPlaceHolder
)
1713 VclPtrInstance
<TabPage
> pPage(pTabControl
);
1716 //Make up a name for it
1717 OString sTabPageId
= get_by_window(pParent
) +
1719 OString::number(nNewPageCount
);
1720 m_aChildren
.emplace_back(sTabPageId
, pPage
, false);
1721 pPage
->SetHelpId(m_sHelpRoot
+ sTabPageId
);
1725 pTabControl
->SetTabPage(nNewPageId
, pPage
);
1730 VerticalTabControl
*pTabControl
= static_cast<VerticalTabControl
*>(pParent
);
1731 SAL_WARN_IF(bIsPlaceHolder
, "vcl.builder", "we should have no placeholders for tabpages");
1732 if (!bIsPlaceHolder
)
1733 pParent
= pTabControl
->GetPageParent();
1738 if (bIsPlaceHolder
|| name
== "GtkTreeSelection")
1741 ToolBox
*pToolBox
= (pParent
&& pParent
->GetType() == WindowType::TOOLBOX
) ? static_cast<ToolBox
*>(pParent
) : nullptr;
1743 extractButtonImage(id
, rMap
, name
== "GtkRadioButton");
1745 VclPtr
<vcl::Window
> xWindow
;
1746 if (name
== "GtkDialog" || name
== "GtkAssistant")
1748 // WB_ALLOWMENUBAR because we don't know in advance if we will encounter
1749 // a menubar, and menubars need a BorderWindow in the toplevel, and
1750 // such border windows need to be in created during the dialog ctor
1751 WinBits nBits
= WB_MOVEABLE
|WB_3DLOOK
|WB_ALLOWMENUBAR
;
1752 if (extractResizable(rMap
))
1753 nBits
|= WB_SIZEABLE
;
1754 if (extractCloseable(rMap
))
1755 nBits
|= WB_CLOSEABLE
;
1756 Dialog::InitFlag eInit
= !pParent
? Dialog::InitFlag::NoParent
: Dialog::InitFlag::Default
;
1757 if (name
== "GtkAssistant")
1758 xWindow
= VclPtr
<vcl::RoadmapWizard
>::Create(pParent
, nBits
, eInit
);
1760 xWindow
= VclPtr
<Dialog
>::Create(pParent
, nBits
, eInit
);
1761 #if HAVE_FEATURE_DESKTOP
1762 if (!extractModal(rMap
))
1763 xWindow
->SetType(WindowType::MODELESSDIALOG
);
1766 else if (name
== "GtkMessageDialog")
1768 WinBits nBits
= WB_MOVEABLE
|WB_3DLOOK
|WB_CLOSEABLE
;
1769 if (extractResizable(rMap
))
1770 nBits
|= WB_SIZEABLE
;
1771 VclPtr
<MessageDialog
> xDialog(VclPtr
<MessageDialog
>::Create(pParent
, nBits
));
1772 m_pParserState
->m_aMessageDialogs
.push_back(xDialog
);
1775 xWindow
->set_border_width(3);
1777 xWindow
->set_border_width(12);
1780 else if (name
== "GtkBox" || name
== "GtkStatusbar")
1782 bVertical
= extractOrientation(rMap
);
1784 xWindow
= VclPtr
<VclVBox
>::Create(pParent
);
1786 xWindow
= VclPtr
<VclHBox
>::Create(pParent
);
1788 else if (name
== "GtkPaned")
1790 bVertical
= extractOrientation(rMap
);
1792 xWindow
= VclPtr
<VclVPaned
>::Create(pParent
);
1794 xWindow
= VclPtr
<VclHPaned
>::Create(pParent
);
1796 else if (name
== "GtkHBox")
1797 xWindow
= VclPtr
<VclHBox
>::Create(pParent
);
1798 else if (name
== "GtkVBox")
1799 xWindow
= VclPtr
<VclVBox
>::Create(pParent
);
1800 else if (name
== "GtkButtonBox")
1802 bVertical
= extractOrientation(rMap
);
1804 xWindow
= VclPtr
<VclVButtonBox
>::Create(pParent
);
1806 xWindow
= VclPtr
<VclHButtonBox
>::Create(pParent
);
1808 else if (name
== "GtkHButtonBox")
1809 xWindow
= VclPtr
<VclHButtonBox
>::Create(pParent
);
1810 else if (name
== "GtkVButtonBox")
1811 xWindow
= VclPtr
<VclVButtonBox
>::Create(pParent
);
1812 else if (name
== "GtkGrid")
1813 xWindow
= VclPtr
<VclGrid
>::Create(pParent
);
1814 else if (name
== "GtkFrame")
1815 xWindow
= VclPtr
<VclFrame
>::Create(pParent
);
1816 else if (name
== "GtkExpander")
1818 VclPtrInstance
<VclExpander
> pExpander(pParent
);
1819 m_pParserState
->m_aExpanderWidgets
.push_back(pExpander
);
1820 xWindow
= pExpander
;
1822 else if (name
== "GtkAlignment")
1823 xWindow
= VclPtr
<VclAlignment
>::Create(pParent
);
1824 else if (name
== "GtkButton" || (!m_bLegacy
&& name
== "GtkToggleButton"))
1826 VclPtr
<Button
> xButton
;
1827 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
1828 if (sMenu
.isEmpty())
1829 xButton
= extractStockAndBuildPushButton(pParent
, rMap
, name
== "GtkToggleButton", m_bLegacy
);
1832 assert(m_bLegacy
&& "use GtkMenuButton");
1833 xButton
= extractStockAndBuildMenuButton(pParent
, rMap
);
1834 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1836 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1837 setupFromActionName(xButton
, rMap
, m_xFrame
);
1840 else if (name
== "GtkMenuButton")
1842 VclPtr
<MenuButton
> xButton
;
1844 OUString sMenu
= extractPopupMenu(rMap
);
1845 if (!sMenu
.isEmpty())
1846 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1848 OUString sType
= extractWidgetName(rMap
);
1849 if (sType
.isEmpty())
1851 xButton
= extractStockAndBuildMenuButton(pParent
, rMap
);
1852 xButton
->SetAccessibleRole(css::accessibility::AccessibleRole::BUTTON_MENU
);
1856 xButton
= extractStockAndBuildMenuToggleButton(pParent
, rMap
);
1859 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1861 if (!extractDrawIndicator(rMap
))
1862 xButton
->SetDropDown(PushButtonDropdownStyle::NONE
);
1864 setupFromActionName(xButton
, rMap
, m_xFrame
);
1867 else if (name
== "GtkToggleButton" && m_bLegacy
)
1869 VclPtr
<Button
> xButton
;
1870 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
1871 assert(sMenu
.getLength() && "not implemented yet");
1872 xButton
= extractStockAndBuildMenuToggleButton(pParent
, rMap
);
1873 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1874 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1875 setupFromActionName(xButton
, rMap
, m_xFrame
);
1878 else if (name
== "GtkRadioButton")
1880 extractGroup(id
, rMap
);
1881 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1882 VclPtr
<RadioButton
> xButton
= VclPtr
<RadioButton
>::Create(pParent
, true, nBits
);
1883 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1886 if (::extractStock(rMap
))
1888 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1891 else if (name
== "GtkCheckButton")
1893 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1894 bool bIsTriState
= extractInconsistent(rMap
);
1895 VclPtr
<CheckBox
> xCheckBox
= VclPtr
<CheckBox
>::Create(pParent
, nBits
);
1898 xCheckBox
->EnableTriState(true);
1899 xCheckBox
->SetState(TRISTATE_INDET
);
1901 xCheckBox
->SetImageAlign(ImageAlign::Left
); //default to left
1903 xWindow
= xCheckBox
;
1905 if (::extractStock(rMap
))
1907 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1910 else if (name
== "GtkSpinButton")
1912 OUString sAdjustment
= extractAdjustment(rMap
);
1914 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_3DLOOK
|WB_SPIN
|WB_REPEAT
;
1915 if (extractHasFrame(rMap
))
1918 connectFormattedFormatterAdjustment(id
, sAdjustment
);
1919 VclPtrInstance
<FormattedField
> xField(pParent
, nBits
);
1920 xField
->GetFormatter().SetMinValue(0);
1923 else if (name
== "GtkLinkButton")
1924 xWindow
= VclPtr
<FixedHyperlink
>::Create(pParent
, WB_CENTER
|WB_VCENTER
|WB_3DLOOK
|WB_NOLABEL
);
1925 else if (name
== "GtkComboBox" || name
== "GtkComboBoxText")
1927 extractModel(id
, rMap
);
1929 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1931 bool bDropdown
= BuilderUtils::extractDropdown(rMap
);
1934 nBits
|= WB_DROPDOWN
;
1936 if (extractEntry(rMap
))
1938 VclPtrInstance
<ComboBox
> xComboBox(pParent
, nBits
);
1939 xComboBox
->EnableAutoSize(true);
1940 xWindow
= xComboBox
;
1944 VclPtrInstance
<ListBox
> xListBox(pParent
, nBits
|WB_SIMPLEMODE
);
1945 xListBox
->EnableAutoSize(true);
1949 else if (name
== "VclOptionalBox" || name
== "sfxlo-OptionalBox")
1951 // tdf#135495 fallback sfxlo-OptionalBox to VclOptionalBox as a stopgap
1952 xWindow
= VclPtr
<OptionalBox
>::Create(pParent
);
1954 else if (name
== "GtkIconView")
1956 assert(rMap
.find(OString("model")) != rMap
.end() && "GtkIconView must have a model");
1958 //window we want to apply the packing props for this GtkIconView to
1959 VclPtr
<vcl::Window
> xWindowForPackingProps
;
1960 extractModel(id
, rMap
);
1961 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1962 //IconView manages its own scrolling,
1963 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
1965 VclPtr
<IconView
> xBox
= VclPtr
<IconView
>::Create(pRealParent
, nWinStyle
);
1966 xWindowForPackingProps
= xBox
;
1969 xBox
->SetNoAutoCurEntry(true);
1970 xBox
->SetQuickSearch(true);
1972 if (pRealParent
!= pParent
)
1973 cleanupWidgetOwnScrolling(pParent
, xWindowForPackingProps
, rMap
);
1975 else if (name
== "GtkTreeView")
1979 assert(rMap
.find(OString("model")) != rMap
.end() && "GtkTreeView must have a model");
1982 //window we want to apply the packing props for this GtkTreeView to
1983 VclPtr
<vcl::Window
> xWindowForPackingProps
;
1985 //a) make SvHeaderTabListBox/SvTabListBox the default target for GtkTreeView
1986 //b) remove the non-drop down mode of ListBox and convert
1987 // everything over to SvHeaderTabListBox/SvTabListBox
1988 //c) remove the users of makeSvTabListBox and makeSvTreeListBox
1989 extractModel(id
, rMap
);
1990 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1993 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
1994 if (!sBorder
.isEmpty())
1995 nWinStyle
|= WB_BORDER
;
1999 nWinStyle
|= WB_HASBUTTONS
| WB_HASBUTTONSATROOT
;
2001 //ListBox/SvHeaderTabListBox manages its own scrolling,
2002 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
2005 xWindow
= VclPtr
<ListBox
>::Create(pRealParent
, nWinStyle
| WB_SIMPLEMODE
);
2006 xWindowForPackingProps
= xWindow
;
2010 VclPtr
<SvTabListBox
> xBox
;
2011 bool bHeadersVisible
= extractHeadersVisible(rMap
);
2012 if (bHeadersVisible
)
2014 VclPtr
<VclVBox
> xContainer
= VclPtr
<VclVBox
>::Create(pRealParent
);
2015 OString
containerid(id
+ "-container");
2016 xContainer
->SetHelpId(m_sHelpRoot
+ containerid
);
2017 m_aChildren
.emplace_back(containerid
, xContainer
, true);
2019 VclPtrInstance
<HeaderBar
> xHeader(xContainer
, WB_BUTTONSTYLE
| WB_BORDER
| WB_TABSTOP
| WB_3DLOOK
);
2020 xHeader
->set_width_request(0); // let the headerbar width not affect the size request
2021 OString
headerid(id
+ "-header");
2022 xHeader
->SetHelpId(m_sHelpRoot
+ headerid
);
2023 m_aChildren
.emplace_back(headerid
, xHeader
, true);
2025 VclPtr
<LclHeaderTabListBox
> xHeaderBox
= VclPtr
<LclHeaderTabListBox
>::Create(xContainer
, nWinStyle
);
2026 xHeaderBox
->InitHeaderBar(xHeader
);
2027 xContainer
->set_expand(true);
2031 xWindowForPackingProps
= xContainer
;
2035 xBox
= VclPtr
<LclTabListBox
>::Create(pRealParent
, nWinStyle
);
2036 xWindowForPackingProps
= xBox
;
2039 xBox
->SetNoAutoCurEntry(true);
2040 xBox
->SetQuickSearch(true);
2041 xBox
->SetSpaceBetweenEntries(3);
2042 xBox
->SetEntryHeight(16);
2043 xBox
->SetHighlightRange(); // select over the whole width
2045 if (pRealParent
!= pParent
)
2046 cleanupWidgetOwnScrolling(pParent
, xWindowForPackingProps
, rMap
);
2048 else if (name
== "GtkTreeViewColumn")
2052 SvHeaderTabListBox
* pTreeView
= dynamic_cast<SvHeaderTabListBox
*>(pParent
);
2053 if (HeaderBar
* pHeaderBar
= pTreeView
? pTreeView
->GetHeaderBar() : nullptr)
2055 HeaderBarItemBits nBits
= HeaderBarItemBits::LEFTIMAGE
;
2056 if (extractClickable(rMap
))
2057 nBits
|= HeaderBarItemBits::CLICKABLE
;
2058 if (extractSortIndicator(rMap
))
2059 nBits
|= HeaderBarItemBits::DOWNARROW
;
2060 float fAlign
= extractAlignment(rMap
);
2062 nBits
|= HeaderBarItemBits::LEFT
;
2063 else if (fAlign
== 1.0)
2064 nBits
|= HeaderBarItemBits::RIGHT
;
2065 else if (fAlign
== 0.5)
2066 nBits
|= HeaderBarItemBits::CENTER
;
2067 auto nItemId
= pHeaderBar
->GetItemCount() + 1;
2068 OUString
sTitle(extractTitle(rMap
));
2069 pHeaderBar
->InsertItem(nItemId
, sTitle
, 100, nBits
);
2073 else if (name
== "GtkLabel")
2075 WinBits nWinStyle
= WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
2076 extractMnemonicWidget(id
, rMap
);
2077 if (extractSelectable(rMap
))
2078 xWindow
= VclPtr
<SelectableFixedText
>::Create(pParent
, nWinStyle
);
2080 xWindow
= VclPtr
<FixedText
>::Create(pParent
, nWinStyle
);
2082 else if (name
== "GtkImage")
2084 extractStock(id
, rMap
);
2085 xWindow
= VclPtr
<FixedImage
>::Create(pParent
, WB_CENTER
|WB_VCENTER
|WB_3DLOOK
|WB_SCALE
);
2086 //such parentless GtkImages are temps used to set icons on buttons
2087 //default them to hidden to stop e.g. insert->index entry flicking temp
2088 //full screen windows
2091 rMap
["visible"] = "false";
2094 else if (name
== "GtkSeparator")
2096 bVertical
= extractOrientation(rMap
);
2097 xWindow
= VclPtr
<FixedLine
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2099 else if (name
== "GtkScrollbar")
2101 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aScrollAdjustmentMaps
);
2102 bVertical
= extractOrientation(rMap
);
2103 xWindow
= VclPtr
<ScrollBar
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2105 else if (name
== "GtkProgressBar")
2107 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aScrollAdjustmentMaps
);
2108 bVertical
= extractOrientation(rMap
);
2109 xWindow
= VclPtr
<ProgressBar
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2111 else if (name
== "GtkScrolledWindow")
2113 xWindow
= VclPtr
<VclScrolledWindow
>::Create(pParent
);
2115 else if (name
== "GtkViewport")
2117 xWindow
= VclPtr
<VclViewport
>::Create(pParent
);
2119 else if (name
== "GtkEventBox")
2121 xWindow
= VclPtr
<VclEventBox
>::Create(pParent
);
2123 else if (name
== "GtkEntry")
2125 WinBits nWinStyle
= WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
2126 if (extractHasFrame(rMap
))
2127 nWinStyle
|= WB_BORDER
;
2128 xWindow
= VclPtr
<Edit
>::Create(pParent
, nWinStyle
);
2129 BuilderUtils::ensureDefaultWidthChars(rMap
);
2131 else if (name
== "GtkNotebook")
2133 if (!extractVerticalTabPos(rMap
))
2134 xWindow
= VclPtr
<TabControl
>::Create(pParent
, WB_STDTABCONTROL
|WB_3DLOOK
);
2136 xWindow
= VclPtr
<VerticalTabControl
>::Create(pParent
);
2138 else if (name
== "GtkDrawingArea")
2140 xWindow
= VclPtr
<VclDrawingArea
>::Create(pParent
, WB_TABSTOP
);
2142 else if (name
== "GtkTextView")
2144 extractBuffer(id
, rMap
);
2146 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
;
2147 //VclMultiLineEdit manages its own scrolling,
2148 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
2149 xWindow
= VclPtr
<VclMultiLineEdit
>::Create(pRealParent
, nWinStyle
);
2150 if (pRealParent
!= pParent
)
2151 cleanupWidgetOwnScrolling(pParent
, xWindow
, rMap
);
2153 else if (name
== "GtkSpinner")
2155 xWindow
= VclPtr
<Throbber
>::Create(pParent
, WB_3DLOOK
);
2157 else if (name
== "GtkScale")
2159 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aSliderAdjustmentMaps
);
2160 bool bDrawValue
= extractDrawValue(rMap
);
2163 OUString sValuePos
= extractValuePos(rMap
);
2166 bVertical
= extractOrientation(rMap
);
2168 WinBits nWinStyle
= bVertical
? WB_VERT
: WB_HORZ
;
2170 xWindow
= VclPtr
<Slider
>::Create(pParent
, nWinStyle
);
2172 else if (name
== "GtkToolbar")
2174 xWindow
= VclPtr
<ToolBox
>::Create(pParent
, WB_3DLOOK
| WB_TABSTOP
);
2176 else if(name
== "NotebookBarAddonsToolMergePoint")
2178 customMakeWidget pFunction
= GetCustomMakeWidget("sfxlo-NotebookbarToolBox");
2179 if(pFunction
!= nullptr)
2180 NotebookBarAddonsMerger::MergeNotebookBarAddons(pParent
, pFunction
, m_xFrame
, *m_pNotebookBarAddonsItem
, rMap
);
2183 else if (name
== "GtkToolButton" || name
== "GtkMenuToolButton" ||
2184 name
== "GtkToggleToolButton" || name
== "GtkRadioToolButton" || name
== "GtkToolItem")
2188 OUString
aCommand(extractActionName(rMap
));
2190 sal_uInt16 nItemId
= 0;
2191 ToolBoxItemBits nBits
= ToolBoxItemBits::NONE
;
2192 if (name
== "GtkMenuToolButton")
2193 nBits
|= ToolBoxItemBits::DROPDOWN
;
2194 else if (name
== "GtkToggleToolButton")
2195 nBits
|= ToolBoxItemBits::AUTOCHECK
| ToolBoxItemBits::CHECKABLE
;
2196 else if (name
== "GtkRadioToolButton")
2197 nBits
|= ToolBoxItemBits::AUTOCHECK
| ToolBoxItemBits::RADIOCHECK
;
2199 if (!aCommand
.isEmpty() && m_xFrame
.is())
2201 pToolBox
->InsertItem(aCommand
, m_xFrame
, nBits
, extractSizeRequest(rMap
));
2202 nItemId
= pToolBox
->GetItemId(aCommand
);
2206 nItemId
= pToolBox
->GetItemCount() + 1;
2207 //TODO: ImplToolItems::size_type -> sal_uInt16!
2208 pToolBox
->InsertItem(nItemId
, extractLabel(rMap
), nBits
);
2209 if (aCommand
.isEmpty() && !m_bLegacy
)
2210 aCommand
= OUString::fromUtf8(id
);
2211 pToolBox
->SetItemCommand(nItemId
, aCommand
);
2214 pToolBox
->SetHelpId(nItemId
, m_sHelpRoot
+ id
);
2215 OUString
sTooltip(extractTooltipText(rMap
));
2216 if (!sTooltip
.isEmpty())
2217 pToolBox
->SetQuickHelpText(nItemId
, sTooltip
);
2219 OUString
sIconName(extractIconName(rMap
));
2220 if (sIconName
.isEmpty())
2221 sIconName
= mapStockToImageResource(extractStockId(rMap
));
2222 if (!sIconName
.isEmpty())
2223 pToolBox
->SetItemImage(nItemId
, FixedImage::loadThemeImage(sIconName
));
2225 if (!extractVisible(rMap
))
2226 pToolBox
->HideItem(nItemId
);
2228 m_pParserState
->m_nLastToolbarId
= nItemId
;
2230 return nullptr; // no widget to be created
2233 else if (name
== "GtkSeparatorToolItem")
2237 pToolBox
->InsertSeparator();
2238 return nullptr; // no widget to be created
2241 else if (name
== "GtkWindow")
2243 WinBits nBits
= extractDeferredBits(rMap
);
2244 if (nBits
& WB_DOCKABLE
)
2245 xWindow
= VclPtr
<DockingWindow
>::Create(pParent
, nBits
|WB_MOVEABLE
);
2247 xWindow
= VclPtr
<FloatingWindow
>::Create(pParent
, nBits
|WB_MOVEABLE
);
2249 else if (name
== "GtkPopover")
2251 WinBits nBits
= extractDeferredBits(rMap
);
2252 xWindow
= VclPtr
<DockingWindow
>::Create(pParent
, nBits
|WB_DOCKABLE
|WB_MOVEABLE
);
2254 else if (name
== "GtkCalendar")
2256 WinBits nBits
= extractDeferredBits(rMap
);
2257 xWindow
= VclPtr
<Calendar
>::Create(pParent
, nBits
);
2261 if (customMakeWidget pFunction
= GetCustomMakeWidget(name
))
2263 pFunction(xWindow
, pParent
, rMap
);
2264 if (xWindow
->GetType() == WindowType::PUSHBUTTON
)
2265 setupFromActionName(static_cast<Button
*>(xWindow
.get()), rMap
, m_xFrame
);
2266 else if (xWindow
->GetType() == WindowType::MENUBUTTON
)
2268 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
2269 if (!sMenu
.isEmpty())
2270 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
2271 setupFromActionName(static_cast<Button
*>(xWindow
.get()), rMap
, m_xFrame
);
2276 SAL_INFO_IF(!xWindow
, "vcl.builder", "probably need to implement " << name
<< " or add a make" << name
<< " function");
2279 // child windows of disabled windows are made disabled by vcl by default, we don't want that
2280 WindowImpl
*pWindowImpl
= xWindow
->ImplGetWindowImpl();
2281 pWindowImpl
->mbDisabled
= false;
2283 xWindow
->SetHelpId(m_sHelpRoot
+ id
);
2284 SAL_INFO("vcl.builder", "for name '" << name
<< "' and id '" << id
<<
2285 "', created " << xWindow
.get() << " child of " <<
2286 pParent
<< "(" << xWindow
->ImplGetWindowImpl()->mpParent
.get() << "/" <<
2287 xWindow
->ImplGetWindowImpl()->mpRealParent
.get() << "/" <<
2288 xWindow
->ImplGetWindowImpl()->mpBorderWindow
.get() << ") with helpid " <<
2289 xWindow
->GetHelpId());
2290 m_aChildren
.emplace_back(id
, xWindow
, bVertical
);
2292 // if the parent was a toolbox set it as an itemwindow for the latest itemid
2295 Size
aSize(xWindow
->GetSizePixel());
2296 aSize
.setHeight(xWindow
->get_preferred_size().Height());
2297 xWindow
->SetSizePixel(aSize
);
2298 pToolBox
->SetItemWindow(m_pParserState
->m_nLastToolbarId
, xWindow
);
2299 pToolBox
->SetItemExpand(m_pParserState
->m_nLastToolbarId
, true);
2307 //return true for window types which exist in vcl but are not themselves
2308 //represented in the .ui format, i.e. only their children exist.
2309 bool isConsideredGtkPseudo(vcl::Window
const *pWindow
)
2311 return pWindow
->GetType() == WindowType::TABPAGE
;
2315 //Any properties from .ui load we couldn't set because of potential virtual methods
2316 //during ctor are applied here
2317 void VclBuilder::setDeferredProperties()
2319 if (!m_bToplevelHasDeferredProperties
)
2321 stringmap aDeferredProperties
;
2322 aDeferredProperties
.swap(m_aDeferredProperties
);
2323 m_bToplevelHasDeferredProperties
= false;
2324 BuilderUtils::set_properties(m_pParent
, aDeferredProperties
);
2327 namespace BuilderUtils
2329 void set_properties(vcl::Window
*pWindow
, const VclBuilder::stringmap
&rProps
)
2331 for (auto const& prop
: rProps
)
2333 const OString
&rKey
= prop
.first
;
2334 const OUString
&rValue
= prop
.second
;
2335 pWindow
->set_property(rKey
, rValue
);
2339 OUString
convertMnemonicMarkup(const OUString
&rIn
)
2341 OUStringBuffer
aRet(rIn
);
2342 for (sal_Int32 nI
= 0; nI
< aRet
.getLength(); ++nI
)
2344 if (aRet
[nI
] == '_' && nI
+1 < aRet
.getLength())
2346 if (aRet
[nI
+1] != '_')
2347 aRet
[nI
] = MNEMONIC_CHAR
;
2353 return aRet
.makeStringAndClear();
2356 OUString
extractCustomProperty(VclBuilder::stringmap
&rMap
)
2358 OUString sCustomProperty
;
2359 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("customproperty"));
2360 if (aFind
!= rMap
.end())
2362 sCustomProperty
= aFind
->second
;
2365 return sCustomProperty
;
2368 void ensureDefaultWidthChars(VclBuilder::stringmap
&rMap
)
2370 OString
sWidthChars("width-chars");
2371 VclBuilder::stringmap::iterator aFind
= rMap
.find(sWidthChars
);
2372 if (aFind
== rMap
.end())
2373 rMap
[sWidthChars
] = "25";
2376 bool extractDropdown(VclBuilder::stringmap
&rMap
)
2378 bool bDropdown
= true;
2379 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("dropdown"));
2380 if (aFind
!= rMap
.end())
2382 bDropdown
= toBool(aFind
->second
);
2388 void reorderWithinParent(vcl::Window
&rWindow
, sal_uInt16 nNewPosition
)
2390 WindowImpl
*pWindowImpl
= rWindow
.ImplGetWindowImpl();
2391 if (pWindowImpl
->mpParent
!= pWindowImpl
->mpRealParent
)
2393 assert(pWindowImpl
->mpBorderWindow
== pWindowImpl
->mpParent
);
2394 assert(pWindowImpl
->mpBorderWindow
->ImplGetWindowImpl()->mpParent
== pWindowImpl
->mpRealParent
);
2395 reorderWithinParent(*pWindowImpl
->mpBorderWindow
, nNewPosition
);
2398 rWindow
.reorderWithinParent(nNewPosition
);
2401 void reorderWithinParent(std::vector
<vcl::Window
*>& rChilds
, bool bIsButtonBox
)
2403 for (size_t i
= 0; i
< rChilds
.size(); ++i
)
2405 reorderWithinParent(*rChilds
[i
], i
);
2410 //The first member of the group for legacy code needs WB_GROUP set and the
2412 WinBits nBits
= rChilds
[i
]->GetStyle();
2416 rChilds
[i
]->SetStyle(nBits
);
2420 sal_Int16
getRoleFromName(const OString
& roleName
)
2422 using namespace com::sun::star::accessibility
;
2424 static const std::unordered_map
<OString
, sal_Int16
> aAtkRoleToAccessibleRole
= {
2425 /* This is in atkobject.h's AtkRole order */
2426 { "invalid", AccessibleRole::UNKNOWN
},
2427 { "accelerator label", AccessibleRole::UNKNOWN
},
2428 { "alert", AccessibleRole::ALERT
},
2429 { "animation", AccessibleRole::UNKNOWN
},
2430 { "arrow", AccessibleRole::UNKNOWN
},
2431 { "calendar", AccessibleRole::UNKNOWN
},
2432 { "canvas", AccessibleRole::CANVAS
},
2433 { "check box", AccessibleRole::CHECK_BOX
},
2434 { "check menu item", AccessibleRole::CHECK_MENU_ITEM
},
2435 { "color chooser", AccessibleRole::COLOR_CHOOSER
},
2436 { "column header", AccessibleRole::COLUMN_HEADER
},
2437 { "combo box", AccessibleRole::COMBO_BOX
},
2438 { "date editor", AccessibleRole::DATE_EDITOR
},
2439 { "desktop icon", AccessibleRole::DESKTOP_ICON
},
2440 { "desktop frame", AccessibleRole::DESKTOP_PANE
}, // ?
2441 { "dial", AccessibleRole::UNKNOWN
},
2442 { "dialog", AccessibleRole::DIALOG
},
2443 { "directory pane", AccessibleRole::DIRECTORY_PANE
},
2444 { "drawing area", AccessibleRole::UNKNOWN
},
2445 { "file chooser", AccessibleRole::FILE_CHOOSER
},
2446 { "filler", AccessibleRole::FILLER
},
2447 { "font chooser", AccessibleRole::FONT_CHOOSER
},
2448 { "frame", AccessibleRole::FRAME
},
2449 { "glass pane", AccessibleRole::GLASS_PANE
},
2450 { "html container", AccessibleRole::UNKNOWN
},
2451 { "icon", AccessibleRole::ICON
},
2452 { "image", AccessibleRole::GRAPHIC
},
2453 { "internal frame", AccessibleRole::INTERNAL_FRAME
},
2454 { "label", AccessibleRole::LABEL
},
2455 { "layered pane", AccessibleRole::LAYERED_PANE
},
2456 { "list", AccessibleRole::LIST
},
2457 { "list item", AccessibleRole::LIST_ITEM
},
2458 { "menu", AccessibleRole::MENU
},
2459 { "menu bar", AccessibleRole::MENU_BAR
},
2460 { "menu item", AccessibleRole::MENU_ITEM
},
2461 { "option pane", AccessibleRole::OPTION_PANE
},
2462 { "page tab", AccessibleRole::PAGE_TAB
},
2463 { "page tab list", AccessibleRole::PAGE_TAB_LIST
},
2464 { "panel", AccessibleRole::PANEL
}, // or SHAPE or TEXT_FRAME ?
2465 { "password text", AccessibleRole::PASSWORD_TEXT
},
2466 { "popup menu", AccessibleRole::POPUP_MENU
},
2467 { "progress bar", AccessibleRole::PROGRESS_BAR
},
2468 { "push button", AccessibleRole::PUSH_BUTTON
}, // or BUTTON_DROPDOWN or BUTTON_MENU
2469 { "radio button", AccessibleRole::RADIO_BUTTON
},
2470 { "radio menu item", AccessibleRole::RADIO_MENU_ITEM
},
2471 { "root pane", AccessibleRole::ROOT_PANE
},
2472 { "row header", AccessibleRole::ROW_HEADER
},
2473 { "scroll bar", AccessibleRole::SCROLL_BAR
},
2474 { "scroll pane", AccessibleRole::SCROLL_PANE
},
2475 { "separator", AccessibleRole::SEPARATOR
},
2476 { "slider", AccessibleRole::SLIDER
},
2477 { "split pane", AccessibleRole::SPLIT_PANE
},
2478 { "spin button", AccessibleRole::SPIN_BOX
}, // ?
2479 { "statusbar", AccessibleRole::STATUS_BAR
},
2480 { "table", AccessibleRole::TABLE
},
2481 { "table cell", AccessibleRole::TABLE_CELL
},
2482 { "table column header", AccessibleRole::COLUMN_HEADER
}, // approximate
2483 { "table row header", AccessibleRole::ROW_HEADER
}, // approximate
2484 { "tear off menu item", AccessibleRole::UNKNOWN
},
2485 { "terminal", AccessibleRole::UNKNOWN
},
2486 { "text", AccessibleRole::TEXT
},
2487 { "toggle button", AccessibleRole::TOGGLE_BUTTON
},
2488 { "tool bar", AccessibleRole::TOOL_BAR
},
2489 { "tool tip", AccessibleRole::TOOL_TIP
},
2490 { "tree", AccessibleRole::TREE
},
2491 { "tree table", AccessibleRole::TREE_TABLE
},
2492 { "unknown", AccessibleRole::UNKNOWN
},
2493 { "viewport", AccessibleRole::VIEW_PORT
},
2494 { "window", AccessibleRole::WINDOW
},
2495 { "header", AccessibleRole::HEADER
},
2496 { "footer", AccessibleRole::FOOTER
},
2497 { "paragraph", AccessibleRole::PARAGRAPH
},
2498 { "ruler", AccessibleRole::RULER
},
2499 { "application", AccessibleRole::UNKNOWN
},
2500 { "autocomplete", AccessibleRole::UNKNOWN
},
2501 { "edit bar", AccessibleRole::EDIT_BAR
},
2502 { "embedded", AccessibleRole::EMBEDDED_OBJECT
},
2503 { "entry", AccessibleRole::UNKNOWN
},
2504 { "chart", AccessibleRole::CHART
},
2505 { "caption", AccessibleRole::CAPTION
},
2506 { "document frame", AccessibleRole::DOCUMENT
},
2507 { "heading", AccessibleRole::HEADING
},
2508 { "page", AccessibleRole::PAGE
},
2509 { "section", AccessibleRole::SECTION
},
2510 { "redundant object", AccessibleRole::UNKNOWN
},
2511 { "form", AccessibleRole::FORM
},
2512 { "link", AccessibleRole::HYPER_LINK
},
2513 { "input method window", AccessibleRole::UNKNOWN
},
2514 { "table row", AccessibleRole::UNKNOWN
},
2515 { "tree item", AccessibleRole::TREE_ITEM
},
2516 { "document spreadsheet", AccessibleRole::DOCUMENT_SPREADSHEET
},
2517 { "document presentation", AccessibleRole::DOCUMENT_PRESENTATION
},
2518 { "document text", AccessibleRole::DOCUMENT_TEXT
},
2519 { "document web", AccessibleRole::DOCUMENT
}, // approximate
2520 { "document email", AccessibleRole::DOCUMENT
}, // approximate
2521 { "comment", AccessibleRole::COMMENT
}, // or NOTE or END_NOTE or FOOTNOTE or SCROLL_PANE
2522 { "list box", AccessibleRole::UNKNOWN
},
2523 { "grouping", AccessibleRole::GROUP_BOX
},
2524 { "image map", AccessibleRole::IMAGE_MAP
},
2525 { "notification", AccessibleRole::UNKNOWN
},
2526 { "info bar", AccessibleRole::UNKNOWN
},
2527 { "level bar", AccessibleRole::UNKNOWN
},
2528 { "title bar", AccessibleRole::UNKNOWN
},
2529 { "block quote", AccessibleRole::UNKNOWN
},
2530 { "audio", AccessibleRole::UNKNOWN
},
2531 { "video", AccessibleRole::UNKNOWN
},
2532 { "definition", AccessibleRole::UNKNOWN
},
2533 { "article", AccessibleRole::UNKNOWN
},
2534 { "landmark", AccessibleRole::UNKNOWN
},
2535 { "log", AccessibleRole::UNKNOWN
},
2536 { "marquee", AccessibleRole::UNKNOWN
},
2537 { "math", AccessibleRole::UNKNOWN
},
2538 { "rating", AccessibleRole::UNKNOWN
},
2539 { "timer", AccessibleRole::UNKNOWN
},
2540 { "description list", AccessibleRole::UNKNOWN
},
2541 { "description term", AccessibleRole::UNKNOWN
},
2542 { "description value", AccessibleRole::UNKNOWN
},
2543 { "static", AccessibleRole::STATIC
},
2544 { "math fraction", AccessibleRole::UNKNOWN
},
2545 { "math root", AccessibleRole::UNKNOWN
},
2546 { "subscript", AccessibleRole::UNKNOWN
},
2547 { "superscript", AccessibleRole::UNKNOWN
},
2548 { "footnote", AccessibleRole::FOOTNOTE
},
2551 auto it
= aAtkRoleToAccessibleRole
.find(roleName
);
2552 if (it
== aAtkRoleToAccessibleRole
.end())
2553 return AccessibleRole::UNKNOWN
;
2558 VclPtr
<vcl::Window
> VclBuilder::insertObject(vcl::Window
*pParent
, const OString
&rClass
,
2559 const OString
&rID
, stringmap
&rProps
, stringmap
&rPango
, stringmap
&rAtk
)
2561 VclPtr
<vcl::Window
> pCurrentChild
;
2563 if (m_pParent
&& !isConsideredGtkPseudo(m_pParent
) && !m_sID
.isEmpty() && rID
== m_sID
)
2565 pCurrentChild
= m_pParent
;
2567 //toplevels default to resizable and apparently you can't change them
2568 //afterwards, so we need to wait until now before we can truly
2569 //initialize the dialog.
2570 if (pParent
&& pParent
->IsSystemWindow())
2572 SystemWindow
*pSysWin
= static_cast<SystemWindow
*>(pCurrentChild
.get());
2573 pSysWin
->doDeferredInit(extractDeferredBits(rProps
));
2574 m_bToplevelHasDeferredInit
= false;
2576 else if (pParent
&& pParent
->IsDockingWindow())
2578 DockingWindow
*pDockWin
= static_cast<DockingWindow
*>(pCurrentChild
.get());
2579 pDockWin
->doDeferredInit(extractDeferredBits(rProps
));
2580 m_bToplevelHasDeferredInit
= false;
2583 if (pCurrentChild
->GetHelpId().isEmpty())
2585 pCurrentChild
->SetHelpId(m_sHelpRoot
+ m_sID
);
2586 SAL_INFO("vcl.builder", "for toplevel dialog " << this << " " <<
2587 rID
<< ", set helpid " << pCurrentChild
->GetHelpId());
2589 m_bToplevelParentFound
= true;
2593 //if we're being inserting under a toplevel dialog whose init is
2594 //deferred due to waiting to encounter it in this .ui, and it hasn't
2595 //been seen yet, then make unattached widgets parent-less toplevels
2596 if (pParent
== m_pParent
.get() && m_bToplevelHasDeferredInit
)
2598 pCurrentChild
= makeObject(pParent
, rClass
, rID
, rProps
);
2603 pCurrentChild
->set_id(OStringToOUString(rID
, RTL_TEXTENCODING_UTF8
));
2604 if (pCurrentChild
== m_pParent
.get() && m_bToplevelHasDeferredProperties
)
2605 m_aDeferredProperties
= rProps
;
2607 BuilderUtils::set_properties(pCurrentChild
, rProps
);
2609 for (auto const& elem
: rPango
)
2611 const OString
&rKey
= elem
.first
;
2612 const OUString
&rValue
= elem
.second
;
2613 pCurrentChild
->set_font_attribute(rKey
, rValue
);
2616 m_pParserState
->m_aAtkInfo
[pCurrentChild
] = rAtk
;
2625 bool bToolbarParent
= (pParent
&& pParent
->GetType() == WindowType::TOOLBOX
);
2626 pCurrentChild
= (m_aChildren
.empty() || bToolbarParent
) ? pParent
: m_aChildren
.back().m_pWindow
.get();
2628 return pCurrentChild
;
2631 void VclBuilder::handleTabChild(vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
2633 TabControl
*pTabControl
= pParent
&& pParent
->GetType() == WindowType::TABCONTROL
?
2634 static_cast<TabControl
*>(pParent
) : nullptr;
2636 std::vector
<OString
> sIDs
;
2639 stringmap aProperties
;
2640 stringmap aAtkProperties
;
2641 std::vector
<vcl::EnumContext::Context
> context
;
2645 xmlreader::Span name
;
2648 xmlreader::XmlReader::Result res
= reader
.nextItem(
2649 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
2651 if (res
== xmlreader::XmlReader::Result::Begin
)
2654 if (name
== "object")
2656 while (reader
.nextAttribute(&nsId
, &name
))
2660 name
= reader
.getAttributeValue(false);
2661 OString
sID(name
.begin
, name
.length
);
2662 sal_Int32 nDelim
= sID
.indexOf(':');
2665 OString sPattern
= sID
.copy(nDelim
+1);
2666 aProperties
[OString("customproperty")] = OUString::fromUtf8(sPattern
);
2667 sID
= sID
.copy(0, nDelim
);
2669 sIDs
.push_back(sID
);
2673 else if (name
== "style")
2676 context
= handleStyle(reader
, nPriority
);
2679 else if (name
== "property")
2680 collectProperty(reader
, aProperties
);
2681 else if (pTabControl
&& name
== "child")
2683 // just to collect the atk properties (if any) for the label
2684 handleChild(nullptr, &aAtkProperties
, reader
);
2689 if (res
== xmlreader::XmlReader::Result::End
)
2695 if (res
== xmlreader::XmlReader::Result::Done
)
2702 VerticalTabControl
*pVerticalTabControl
= pParent
->GetType() == WindowType::VERTICALTABCONTROL
?
2703 static_cast<VerticalTabControl
*>(pParent
) : nullptr;
2704 assert(pTabControl
|| pVerticalTabControl
);
2705 VclBuilder::stringmap::iterator aFind
= aProperties
.find(OString("label"));
2706 if (aFind
!= aProperties
.end())
2710 sal_uInt16 nPageId
= pTabControl
->GetCurPageId();
2711 pTabControl
->SetPageText(nPageId
, aFind
->second
);
2712 pTabControl
->SetPageName(nPageId
, sIDs
.back());
2713 if (!context
.empty())
2715 TabPage
* pPage
= pTabControl
->GetTabPage(nPageId
);
2716 pPage
->SetContext(context
);
2719 for (auto const& prop
: aAtkProperties
)
2721 const OString
&rKey
= prop
.first
;
2722 const OUString
&rValue
= prop
.second
;
2724 if (rKey
== "AtkObject::accessible-name")
2725 pTabControl
->SetAccessibleName(nPageId
, rValue
);
2726 else if (rKey
== "AtkObject::accessible-description")
2727 pTabControl
->SetAccessibleDescription(nPageId
, rValue
);
2729 SAL_INFO("vcl.builder", "unhandled atk property: " << rKey
);
2735 OUString
sLabel(aFind
->second
);
2736 OUString
sIconName(extractIconName(aProperties
));
2737 OUString
sTooltip(extractTooltipText(aProperties
));
2738 pVerticalTabControl
->InsertPage(sIDs
.front(), sLabel
, FixedImage::loadThemeImage(sIconName
), sTooltip
,
2739 pVerticalTabControl
->GetPageParent()->GetWindow(GetWindowType::LastChild
));
2745 pTabControl
->RemovePage(pTabControl
->GetCurPageId());
2749 //so that tabbing between controls goes in a visually sensible sequence
2750 //we sort these into a best-tab-order sequence
2751 bool VclBuilder::sortIntoBestTabTraversalOrder::operator()(const vcl::Window
*pA
, const vcl::Window
*pB
) const
2753 //sort child order within parent list by grid position
2754 sal_Int32 nTopA
= pA
->get_grid_top_attach();
2755 sal_Int32 nTopB
= pB
->get_grid_top_attach();
2760 sal_Int32 nLeftA
= pA
->get_grid_left_attach();
2761 sal_Int32 nLeftB
= pB
->get_grid_left_attach();
2762 if (nLeftA
< nLeftB
)
2764 if (nLeftA
> nLeftB
)
2766 //sort into two groups of pack start and pack end
2767 VclPackType ePackA
= pA
->get_pack_type();
2768 VclPackType ePackB
= pB
->get_pack_type();
2769 if (ePackA
< ePackB
)
2771 if (ePackA
> ePackB
)
2773 bool bVerticalContainer
= m_pBuilder
->get_window_packing_data(pA
->GetParent()).m_bVerticalOrient
;
2774 bool bPackA
= pA
->get_secondary();
2775 bool bPackB
= pB
->get_secondary();
2776 if (!bVerticalContainer
)
2778 //for horizontal boxes group secondaries before primaries
2779 if (bPackA
> bPackB
)
2781 if (bPackA
< bPackB
)
2786 //for vertical boxes group secondaries after primaries
2787 if (bPackA
< bPackB
)
2789 if (bPackA
> bPackB
)
2792 //honour relative box positions with pack group, (numerical order is reversed
2793 //for VclPackType::End, they are packed from the end back, but here we need
2794 //them in visual layout order so that tabbing works as expected)
2795 sal_Int32 nPackA
= m_pBuilder
->get_window_packing_data(pA
).m_nPosition
;
2796 sal_Int32 nPackB
= m_pBuilder
->get_window_packing_data(pB
).m_nPosition
;
2797 if (nPackA
< nPackB
)
2798 return ePackA
== VclPackType::Start
;
2799 if (nPackA
> nPackB
)
2800 return ePackA
!= VclPackType::Start
;
2801 //sort labels of Frames before body
2802 if (pA
->GetParent() == pB
->GetParent())
2804 const VclFrame
*pFrameParent
= dynamic_cast<const VclFrame
*>(pA
->GetParent());
2807 const vcl::Window
*pLabel
= pFrameParent
->get_label_widget();
2808 int nFramePosA
= (pA
== pLabel
) ? 0 : 1;
2809 int nFramePosB
= (pB
== pLabel
) ? 0 : 1;
2810 return nFramePosA
< nFramePosB
;
2816 void VclBuilder::handleChild(vcl::Window
*pParent
, stringmap
* pAtkProps
, xmlreader::XmlReader
&reader
)
2818 vcl::Window
*pCurrentChild
= nullptr;
2820 xmlreader::Span name
;
2822 OString sType
, sInternalChild
;
2824 while (reader
.nextAttribute(&nsId
, &name
))
2828 name
= reader
.getAttributeValue(false);
2829 sType
= OString(name
.begin
, name
.length
);
2831 else if (name
== "internal-child")
2833 name
= reader
.getAttributeValue(false);
2834 sInternalChild
= OString(name
.begin
, name
.length
);
2840 handleTabChild(pParent
, reader
);
2847 xmlreader::XmlReader::Result res
= reader
.nextItem(
2848 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
2850 if (res
== xmlreader::XmlReader::Result::Begin
)
2852 if (name
== "object" || name
== "placeholder")
2854 pCurrentChild
= handleObject(pParent
, pAtkProps
, reader
).get();
2856 bool bObjectInserted
= pCurrentChild
&& pParent
!= pCurrentChild
;
2858 if (bObjectInserted
)
2860 //Internal-children default in glade to not having their visible bits set
2861 //even though they are visible (generally anyway)
2862 if (!sInternalChild
.isEmpty())
2863 pCurrentChild
->Show();
2865 //Select the first page if it's a notebook
2866 if (pCurrentChild
->GetType() == WindowType::TABCONTROL
)
2868 TabControl
*pTabControl
= static_cast<TabControl
*>(pCurrentChild
);
2869 pTabControl
->SetCurPageId(pTabControl
->GetPageId(0));
2871 //To-Do add reorder capability to the TabControl
2875 // We want to sort labels before contents of frames
2876 // for keyboard traversal, especially if there
2877 // are multiple widgets using the same mnemonic
2878 if (sType
== "label")
2880 if (VclFrame
*pFrameParent
= dynamic_cast<VclFrame
*>(pParent
))
2881 pFrameParent
->designate_label(pCurrentChild
);
2883 if (sInternalChild
.startsWith("vbox") || sInternalChild
.startsWith("messagedialog-vbox"))
2885 if (Dialog
*pBoxParent
= dynamic_cast<Dialog
*>(pParent
))
2886 pBoxParent
->set_content_area(static_cast<VclBox
*>(pCurrentChild
)); // FIXME-VCLPTR
2888 else if (sInternalChild
.startsWith("action_area") || sInternalChild
.startsWith("messagedialog-action_area"))
2890 vcl::Window
*pContentArea
= pCurrentChild
->GetParent();
2891 if (Dialog
*pBoxParent
= dynamic_cast<Dialog
*>(pContentArea
? pContentArea
->GetParent() : nullptr))
2893 pBoxParent
->set_action_area(static_cast<VclButtonBox
*>(pCurrentChild
)); // FIXME-VCLPTR
2897 bool bIsButtonBox
= dynamic_cast<VclButtonBox
*>(pCurrentChild
) != nullptr;
2899 //To-Do make reorder a virtual in Window, move this foo
2900 //there and see above
2901 std::vector
<vcl::Window
*> aChilds
;
2902 for (vcl::Window
* pChild
= pCurrentChild
->GetWindow(GetWindowType::FirstChild
); pChild
;
2903 pChild
= pChild
->GetWindow(GetWindowType::Next
))
2907 if (PushButton
* pPushButton
= dynamic_cast<PushButton
*>(pChild
))
2908 pPushButton
->setAction(true);
2911 aChilds
.push_back(pChild
);
2914 //sort child order within parent so that tabbing
2915 //between controls goes in a visually sensible sequence
2916 std::stable_sort(aChilds
.begin(), aChilds
.end(), sortIntoBestTabTraversalOrder(this));
2917 BuilderUtils::reorderWithinParent(aChilds
, bIsButtonBox
);
2921 else if (name
== "packing")
2923 handlePacking(pCurrentChild
, pParent
, reader
);
2925 else if (name
== "interface")
2927 while (reader
.nextAttribute(&nsId
, &name
))
2929 if (name
== "domain")
2931 name
= reader
.getAttributeValue(false);
2932 sType
= OString(name
.begin
, name
.length
);
2933 m_pParserState
->m_aResLocale
= Translate::Create(sType
.getStr());
2942 if (res
== xmlreader::XmlReader::Result::End
)
2948 if (res
== xmlreader::XmlReader::Result::Done
)
2953 void VclBuilder::collectPangoAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
2955 xmlreader::Span span
;
2961 while (reader
.nextAttribute(&nsId
, &span
))
2965 span
= reader
.getAttributeValue(false);
2966 sProperty
= OString(span
.begin
, span
.length
);
2968 else if (span
== "value")
2970 span
= reader
.getAttributeValue(false);
2971 sValue
= OString(span
.begin
, span
.length
);
2975 if (!sProperty
.isEmpty())
2976 rMap
[sProperty
] = OUString::fromUtf8(sValue
);
2979 void VclBuilder::collectAtkRelationAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
2981 xmlreader::Span span
;
2987 while (reader
.nextAttribute(&nsId
, &span
))
2991 span
= reader
.getAttributeValue(false);
2992 sProperty
= OString(span
.begin
, span
.length
);
2994 else if (span
== "target")
2996 span
= reader
.getAttributeValue(false);
2997 sValue
= OString(span
.begin
, span
.length
);
2998 sal_Int32 nDelim
= sValue
.indexOf(':');
3000 sValue
= sValue
.copy(0, nDelim
);
3004 if (!sProperty
.isEmpty())
3005 rMap
[sProperty
] = OUString::fromUtf8(sValue
);
3008 void VclBuilder::collectAtkRoleAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
3010 xmlreader::Span span
;
3015 while (reader
.nextAttribute(&nsId
, &span
))
3019 span
= reader
.getAttributeValue(false);
3020 sProperty
= OString(span
.begin
, span
.length
);
3024 if (!sProperty
.isEmpty())
3025 rMap
["role"] = OUString::fromUtf8(sProperty
);
3028 void VclBuilder::handleRow(xmlreader::XmlReader
&reader
, const OString
&rID
)
3032 ListStore::row aRow
;
3036 xmlreader::Span name
;
3039 xmlreader::XmlReader::Result res
= reader
.nextItem(
3040 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3042 if (res
== xmlreader::XmlReader::Result::Done
)
3045 if (res
== xmlreader::XmlReader::Result::Begin
)
3050 bool bTranslated
= false;
3054 while (reader
.nextAttribute(&nsId
, &name
))
3058 name
= reader
.getAttributeValue(false);
3059 nId
= OString(name
.begin
, name
.length
).toUInt32();
3061 else if (nId
== 0 && name
== "translatable" && reader
.getAttributeValue(false) == "yes")
3065 else if (name
== "context")
3067 name
= reader
.getAttributeValue(false);
3068 sContext
= OString(name
.begin
, name
.length
);
3072 (void)reader
.nextItem(
3073 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3075 OString
sValue(name
.begin
, name
.length
);
3076 OUString sFinalValue
;
3079 if (!sContext
.isEmpty())
3080 sValue
= sContext
+ "\004" + sValue
;
3081 sFinalValue
= Translate::get(sValue
.getStr(), m_pParserState
->m_aResLocale
);
3084 sFinalValue
= OUString::fromUtf8(sValue
);
3087 if (aRow
.size() < nId
+1)
3089 aRow
[nId
] = sFinalValue
;
3093 if (res
== xmlreader::XmlReader::Result::End
)
3102 m_pParserState
->m_aModels
[rID
].m_aEntries
.push_back(aRow
);
3105 void VclBuilder::handleListStore(xmlreader::XmlReader
&reader
, const OString
&rID
, const OString
&rClass
)
3111 xmlreader::Span name
;
3114 xmlreader::XmlReader::Result res
= reader
.nextItem(
3115 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3117 if (res
== xmlreader::XmlReader::Result::Done
)
3120 if (res
== xmlreader::XmlReader::Result::Begin
)
3124 bool bNotTreeStore
= rClass
!= "GtkTreeStore";
3126 handleRow(reader
, rID
);
3127 assert(bNotTreeStore
&& "gtk, as the time of writing, doesn't support data in GtkTreeStore serialization");
3133 if (res
== xmlreader::XmlReader::Result::End
)
3143 VclBuilder::stringmap
VclBuilder::handleAtkObject(xmlreader::XmlReader
&reader
)
3147 stringmap aProperties
;
3151 xmlreader::Span name
;
3154 xmlreader::XmlReader::Result res
= reader
.nextItem(
3155 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3157 if (res
== xmlreader::XmlReader::Result::Done
)
3160 if (res
== xmlreader::XmlReader::Result::Begin
)
3163 if (name
== "property")
3164 collectProperty(reader
, aProperties
);
3167 if (res
== xmlreader::XmlReader::Result::End
)
3179 void VclBuilder::applyAtkProperties(vcl::Window
*pWindow
, const stringmap
& rProperties
)
3182 for (auto const& prop
: rProperties
)
3184 const OString
&rKey
= prop
.first
;
3185 const OUString
&rValue
= prop
.second
;
3187 if (pWindow
&& rKey
.match("AtkObject::"))
3188 pWindow
->set_property(rKey
.copy(RTL_CONSTASCII_LENGTH("AtkObject::")), rValue
);
3190 SAL_WARN("vcl.builder", "unhandled atk prop: " << rKey
);
3194 std::vector
<ComboBoxTextItem
> VclBuilder::handleItems(xmlreader::XmlReader
&reader
) const
3198 std::vector
<ComboBoxTextItem
> aItems
;
3202 xmlreader::Span name
;
3205 xmlreader::XmlReader::Result res
= reader
.nextItem(
3206 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3208 if (res
== xmlreader::XmlReader::Result::Done
)
3211 if (res
== xmlreader::XmlReader::Result::Begin
)
3216 bool bTranslated
= false;
3217 OString sContext
, sId
;
3219 while (reader
.nextAttribute(&nsId
, &name
))
3221 if (name
== "translatable" && reader
.getAttributeValue(false) == "yes")
3225 else if (name
== "context")
3227 name
= reader
.getAttributeValue(false);
3228 sContext
= OString(name
.begin
, name
.length
);
3230 else if (name
== "id")
3232 name
= reader
.getAttributeValue(false);
3233 sId
= OString(name
.begin
, name
.length
);
3237 (void)reader
.nextItem(
3238 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3240 OString
sValue(name
.begin
, name
.length
);
3241 OUString sFinalValue
;
3244 if (!sContext
.isEmpty())
3245 sValue
= sContext
+ "\004" + sValue
;
3246 sFinalValue
= Translate::get(sValue
.getStr(), m_pParserState
->m_aResLocale
);
3249 sFinalValue
= OUString::fromUtf8(sValue
);
3251 if (m_pStringReplace
)
3252 sFinalValue
= (*m_pStringReplace
)(sFinalValue
);
3254 aItems
.emplace_back(sFinalValue
, sId
);
3258 if (res
== xmlreader::XmlReader::Result::End
)
3270 VclPtr
<Menu
> VclBuilder::handleMenu(xmlreader::XmlReader
&reader
, const OString
&rID
, bool bMenuBar
)
3272 VclPtr
<Menu
> pCurrentMenu
;
3274 pCurrentMenu
= VclPtr
<MenuBar
>::Create();
3276 pCurrentMenu
= VclPtr
<PopupMenu
>::Create();
3280 stringmap aProperties
;
3284 xmlreader::Span name
;
3287 xmlreader::XmlReader::Result res
= reader
.nextItem(
3288 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3290 if (res
== xmlreader::XmlReader::Result::Done
)
3293 if (res
== xmlreader::XmlReader::Result::Begin
)
3295 if (name
== "child")
3297 handleMenuChild(pCurrentMenu
, reader
);
3302 if (name
== "property")
3303 collectProperty(reader
, aProperties
);
3307 if (res
== xmlreader::XmlReader::Result::End
)
3316 m_aMenus
.emplace_back(rID
, pCurrentMenu
);
3318 return pCurrentMenu
;
3321 void VclBuilder::handleMenuChild(Menu
*pParent
, xmlreader::XmlReader
&reader
)
3323 xmlreader::Span name
;
3329 xmlreader::XmlReader::Result res
= reader
.nextItem(
3330 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3332 if (res
== xmlreader::XmlReader::Result::Begin
)
3334 if (name
== "object" || name
== "placeholder")
3336 handleMenuObject(pParent
, reader
);
3342 if (res
== xmlreader::XmlReader::Result::End
)
3348 if (res
== xmlreader::XmlReader::Result::Done
)
3353 void VclBuilder::handleMenuObject(Menu
*pParent
, xmlreader::XmlReader
&reader
)
3357 OUString sCustomProperty
;
3358 PopupMenu
*pSubMenu
= nullptr;
3360 xmlreader::Span name
;
3363 while (reader
.nextAttribute(&nsId
, &name
))
3365 if (name
== "class")
3367 name
= reader
.getAttributeValue(false);
3368 sClass
= OString(name
.begin
, name
.length
);
3370 else if (name
== "id")
3372 name
= reader
.getAttributeValue(false);
3373 sID
= OString(name
.begin
, name
.length
);
3374 sal_Int32 nDelim
= sID
.indexOf(':');
3377 sCustomProperty
= OUString::fromUtf8(sID
.copy(nDelim
+1));
3378 sID
= sID
.copy(0, nDelim
);
3385 stringmap aProperties
;
3386 stringmap aAtkProperties
;
3387 accelmap aAccelerators
;
3389 if (!sCustomProperty
.isEmpty())
3390 aProperties
[OString("customproperty")] = sCustomProperty
;
3394 xmlreader::XmlReader::Result res
= reader
.nextItem(
3395 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3397 if (res
== xmlreader::XmlReader::Result::Done
)
3400 if (res
== xmlreader::XmlReader::Result::Begin
)
3402 if (name
== "child")
3404 size_t nChildMenuIdx
= m_aMenus
.size();
3405 handleChild(nullptr, &aAtkProperties
, reader
);
3406 bool bSubMenuInserted
= m_aMenus
.size() > nChildMenuIdx
;
3407 if (bSubMenuInserted
)
3408 pSubMenu
= dynamic_cast<PopupMenu
*>(m_aMenus
[nChildMenuIdx
].m_pMenu
.get());
3413 if (name
== "property")
3414 collectProperty(reader
, aProperties
);
3415 else if (name
== "accelerator")
3416 collectAccelerator(reader
, aAccelerators
);
3420 if (res
== xmlreader::XmlReader::Result::End
)
3429 insertMenuObject(pParent
, pSubMenu
, sClass
, sID
, aProperties
, aAtkProperties
, aAccelerators
);
3432 void VclBuilder::handleSizeGroup(xmlreader::XmlReader
&reader
)
3434 m_pParserState
->m_aSizeGroups
.emplace_back();
3435 SizeGroup
&rSizeGroup
= m_pParserState
->m_aSizeGroups
.back();
3441 xmlreader::Span name
;
3444 xmlreader::XmlReader::Result res
= reader
.nextItem(
3445 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3447 if (res
== xmlreader::XmlReader::Result::Done
)
3450 if (res
== xmlreader::XmlReader::Result::Begin
)
3453 if (name
== "widget")
3455 while (reader
.nextAttribute(&nsId
, &name
))
3459 name
= reader
.getAttributeValue(false);
3460 OString
sWidget(name
.begin
, name
.length
);
3461 sal_Int32 nDelim
= sWidget
.indexOf(':');
3463 sWidget
= sWidget
.copy(0, nDelim
);
3464 rSizeGroup
.m_aWidgets
.push_back(sWidget
);
3470 if (name
== "property")
3471 collectProperty(reader
, rSizeGroup
.m_aProperties
);
3475 if (res
== xmlreader::XmlReader::Result::End
)
3487 vcl::KeyCode
makeKeyCode(const std::pair
<OString
,OString
> &rKey
)
3489 bool bShift
= rKey
.second
.indexOf("GDK_SHIFT_MASK") != -1;
3490 bool bMod1
= rKey
.second
.indexOf("GDK_CONTROL_MASK") != -1;
3491 bool bMod2
= rKey
.second
.indexOf("GDK_MOD1_MASK") != -1;
3492 bool bMod3
= rKey
.second
.indexOf("GDK_MOD2_MASK") != -1;
3494 if (rKey
.first
== "Insert")
3495 return vcl::KeyCode(KEY_INSERT
, bShift
, bMod1
, bMod2
, bMod3
);
3496 else if (rKey
.first
== "Delete")
3497 return vcl::KeyCode(KEY_DELETE
, bShift
, bMod1
, bMod2
, bMod3
);
3498 else if (rKey
.first
== "Return")
3499 return vcl::KeyCode(KEY_RETURN
, bShift
, bMod1
, bMod2
, bMod3
);
3500 else if (rKey
.first
== "Up")
3501 return vcl::KeyCode(KEY_UP
, bShift
, bMod1
, bMod2
, bMod3
);
3502 else if (rKey
.first
== "Down")
3503 return vcl::KeyCode(KEY_DOWN
, bShift
, bMod1
, bMod2
, bMod3
);
3504 else if (rKey
.first
== "Left")
3505 return vcl::KeyCode(KEY_LEFT
, bShift
, bMod1
, bMod2
, bMod3
);
3506 else if (rKey
.first
== "Right")
3507 return vcl::KeyCode(KEY_RIGHT
, bShift
, bMod1
, bMod2
, bMod3
);
3508 else if (rKey
.first
== "asterisk")
3509 return vcl::KeyCode(KEY_MULTIPLY
, bShift
, bMod1
, bMod2
, bMod3
);
3510 else if (rKey
.first
.getLength() > 1 && rKey
.first
[0] == 'F')
3512 sal_uInt32 nIndex
= rKey
.first
.copy(1).toUInt32();
3513 assert(nIndex
>= 1 && nIndex
<= 26);
3514 return vcl::KeyCode(KEY_F1
+ nIndex
- 1, bShift
, bMod1
, bMod2
, bMod3
);
3517 assert (rKey
.first
.getLength() == 1);
3518 char cChar
= rKey
.first
.toChar();
3520 if (cChar
>= 'a' && cChar
<= 'z')
3521 return vcl::KeyCode(KEY_A
+ (cChar
- 'a'), bShift
, bMod1
, bMod2
, bMod3
);
3522 else if (cChar
>= 'A' && cChar
<= 'Z')
3523 return vcl::KeyCode(KEY_A
+ (cChar
- 'A'), bShift
, bMod1
, bMod2
, bMod3
);
3524 else if (cChar
>= '0' && cChar
<= '9')
3525 return vcl::KeyCode(KEY_0
+ (cChar
- 'A'), bShift
, bMod1
, bMod2
, bMod3
);
3527 return vcl::KeyCode(cChar
, bShift
, bMod1
, bMod2
, bMod3
);
3531 void VclBuilder::insertMenuObject(Menu
*pParent
, PopupMenu
*pSubMenu
, const OString
&rClass
, const OString
&rID
,
3532 stringmap
&rProps
, stringmap
&rAtkProps
, accelmap
&rAccels
)
3534 sal_uInt16 nOldCount
= pParent
->GetItemCount();
3535 sal_uInt16 nNewId
= ++m_pParserState
->m_nLastMenuItemId
;
3537 if(rClass
== "NotebookBarAddonsMenuMergePoint")
3539 NotebookBarAddonsMerger::MergeNotebookBarMenuAddons(pParent
, nNewId
, rID
, *m_pNotebookBarAddonsItem
);
3540 m_pParserState
->m_nLastMenuItemId
= pParent
->GetItemCount();
3542 else if (rClass
== "GtkMenuItem")
3544 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3545 OUString
aCommand(extractActionName(rProps
));
3546 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::NONE
, rID
);
3547 pParent
->SetItemCommand(nNewId
, aCommand
);
3549 pParent
->SetPopupMenu(nNewId
, pSubMenu
);
3551 else if (rClass
== "GtkCheckMenuItem")
3553 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3554 OUString
aCommand(extractActionName(rProps
));
3555 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::CHECKABLE
, rID
);
3556 pParent
->SetItemCommand(nNewId
, aCommand
);
3558 else if (rClass
== "GtkRadioMenuItem")
3560 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3561 OUString
aCommand(extractActionName(rProps
));
3562 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::AUTOCHECK
| MenuItemBits::RADIOCHECK
, rID
);
3563 pParent
->SetItemCommand(nNewId
, aCommand
);
3565 else if (rClass
== "GtkSeparatorMenuItem")
3567 pParent
->InsertSeparator(rID
);
3570 SAL_WARN_IF(nOldCount
== pParent
->GetItemCount(), "vcl.builder", "probably need to implement " << rClass
);
3572 if (nOldCount
!= pParent
->GetItemCount())
3574 pParent
->SetHelpId(nNewId
, m_sHelpRoot
+ rID
);
3575 if (!extractVisible(rProps
))
3576 pParent
->HideItem(nNewId
);
3578 for (auto const& prop
: rProps
)
3580 const OString
&rKey
= prop
.first
;
3581 const OUString
&rValue
= prop
.second
;
3583 if (rKey
== "tooltip-markup")
3584 pParent
->SetTipHelpText(nNewId
, rValue
);
3585 else if (rKey
== "tooltip-text")
3586 pParent
->SetTipHelpText(nNewId
, rValue
);
3588 SAL_INFO("vcl.builder", "unhandled property: " << rKey
);
3591 for (auto const& prop
: rAtkProps
)
3593 const OString
&rKey
= prop
.first
;
3594 const OUString
&rValue
= prop
.second
;
3596 if (rKey
== "AtkObject::accessible-name")
3597 pParent
->SetAccessibleName(nNewId
, rValue
);
3598 else if (rKey
== "AtkObject::accessible-description")
3599 pParent
->SetAccessibleDescription(nNewId
, rValue
);
3601 SAL_INFO("vcl.builder", "unhandled atk property: " << rKey
);
3604 for (auto const& accel
: rAccels
)
3606 const OString
&rSignal
= accel
.first
;
3607 const auto &rValue
= accel
.second
;
3609 if (rSignal
== "activate")
3610 pParent
->SetAccelKey(nNewId
, makeKeyCode(rValue
));
3612 SAL_INFO("vcl.builder", "unhandled accelerator for: " << rSignal
);
3619 /// Insert items to a ComboBox or a ListBox.
3620 /// They have no common ancestor that would have 'InsertEntry()', so use a template.
3621 template<typename T
> static bool insertItems(vcl::Window
*pWindow
, VclBuilder::stringmap
&rMap
,
3622 std::vector
<std::unique_ptr
<OUString
>>& rUserData
,
3623 const std::vector
<ComboBoxTextItem
> &rItems
)
3625 T
*pContainer
= dynamic_cast<T
*>(pWindow
);
3629 sal_uInt16 nActiveId
= extractActive(rMap
);
3630 for (auto const& item
: rItems
)
3632 sal_Int32 nPos
= pContainer
->InsertEntry(item
.m_sItem
);
3633 if (!item
.m_sId
.isEmpty())
3635 rUserData
.emplace_back(std::make_unique
<OUString
>(OUString::fromUtf8(item
.m_sId
)));
3636 pContainer
->SetEntryData(nPos
, rUserData
.back().get());
3639 if (nActiveId
< rItems
.size())
3640 pContainer
->SelectEntryPos(nActiveId
);
3645 VclPtr
<vcl::Window
> VclBuilder::handleObject(vcl::Window
*pParent
, stringmap
*pAtkProps
, xmlreader::XmlReader
&reader
)
3649 OUString sCustomProperty
;
3651 xmlreader::Span name
;
3654 while (reader
.nextAttribute(&nsId
, &name
))
3656 if (name
== "class")
3658 name
= reader
.getAttributeValue(false);
3659 sClass
= OString(name
.begin
, name
.length
);
3661 else if (name
== "id")
3663 name
= reader
.getAttributeValue(false);
3664 sID
= OString(name
.begin
, name
.length
);
3667 sal_Int32 nDelim
= sID
.indexOf(':');
3670 sCustomProperty
= OUString::fromUtf8(sID
.copy(nDelim
+1));
3671 sID
= sID
.copy(0, nDelim
);
3677 if (sClass
== "GtkListStore" || sClass
== "GtkTreeStore")
3679 handleListStore(reader
, sID
, sClass
);
3682 else if (sClass
== "GtkMenu")
3684 handleMenu(reader
, sID
, false);
3687 else if (sClass
== "GtkMenuBar")
3689 VclPtr
<Menu
> xMenu
= handleMenu(reader
, sID
, true);
3690 if (SystemWindow
* pTopLevel
= pParent
? pParent
->GetSystemWindow() : nullptr)
3691 pTopLevel
->SetMenuBar(dynamic_cast<MenuBar
*>(xMenu
.get()));
3694 else if (sClass
== "GtkSizeGroup")
3696 handleSizeGroup(reader
);
3699 else if (sClass
== "AtkObject")
3701 assert((pParent
|| pAtkProps
) && "must have one set");
3702 assert(!(pParent
&& pAtkProps
) && "must not have both");
3703 auto aAtkProperties
= handleAtkObject(reader
);
3705 applyAtkProperties(pParent
, aAtkProperties
);
3707 *pAtkProps
= aAtkProperties
;
3713 stringmap aProperties
, aPangoAttributes
;
3714 stringmap aAtkAttributes
;
3715 std::vector
<ComboBoxTextItem
> aItems
;
3717 if (!sCustomProperty
.isEmpty())
3718 aProperties
[OString("customproperty")] = sCustomProperty
;
3720 VclPtr
<vcl::Window
> pCurrentChild
;
3723 xmlreader::XmlReader::Result res
= reader
.nextItem(
3724 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3726 if (res
== xmlreader::XmlReader::Result::Done
)
3729 if (res
== xmlreader::XmlReader::Result::Begin
)
3731 if (name
== "child")
3735 pCurrentChild
= insertObject(pParent
, sClass
, sID
,
3736 aProperties
, aPangoAttributes
, aAtkAttributes
);
3738 handleChild(pCurrentChild
, nullptr, reader
);
3740 else if (name
== "items")
3741 aItems
= handleItems(reader
);
3742 else if (name
== "style")
3745 std::vector
<vcl::EnumContext::Context
> aContext
= handleStyle(reader
, nPriority
);
3748 vcl::IPrioritable
* pPrioritable
= dynamic_cast<vcl::IPrioritable
*>(pCurrentChild
.get());
3749 SAL_WARN_IF(!pPrioritable
, "vcl", "priority set for not supported item");
3751 pPrioritable
->SetPriority(nPriority
);
3753 if (!aContext
.empty())
3755 vcl::IContext
* pContextControl
= dynamic_cast<vcl::IContext
*>(pCurrentChild
.get());
3756 SAL_WARN_IF(!pContextControl
, "vcl", "context set for not supported item");
3757 if (pContextControl
)
3758 pContextControl
->SetContext(aContext
);
3764 if (name
== "property")
3765 collectProperty(reader
, aProperties
);
3766 else if (name
== "attribute")
3767 collectPangoAttribute(reader
, aPangoAttributes
);
3768 else if (name
== "relation")
3769 collectAtkRelationAttribute(reader
, aAtkAttributes
);
3770 else if (name
== "role")
3771 collectAtkRoleAttribute(reader
, aAtkAttributes
);
3772 else if (name
== "action-widget")
3773 handleActionWidget(reader
);
3777 if (res
== xmlreader::XmlReader::Result::End
)
3786 if (sClass
== "GtkAdjustment")
3788 m_pParserState
->m_aAdjustments
[sID
] = aProperties
;
3791 else if (sClass
== "GtkTextBuffer")
3793 m_pParserState
->m_aTextBuffers
[sID
] = aProperties
;
3799 pCurrentChild
= insertObject(pParent
, sClass
, sID
, aProperties
,
3800 aPangoAttributes
, aAtkAttributes
);
3803 if (!aItems
.empty())
3805 // try to fill-in the items
3806 if (!insertItems
<ComboBox
>(pCurrentChild
, aProperties
, m_aUserData
, aItems
))
3807 insertItems
<ListBox
>(pCurrentChild
, aProperties
, m_aUserData
, aItems
);
3810 return pCurrentChild
;
3813 void VclBuilder::handlePacking(vcl::Window
*pCurrent
, vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
3815 xmlreader::Span name
;
3822 xmlreader::XmlReader::Result res
= reader
.nextItem(
3823 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3825 if (res
== xmlreader::XmlReader::Result::Done
)
3828 if (res
== xmlreader::XmlReader::Result::Begin
)
3831 if (name
== "property")
3832 applyPackingProperty(pCurrent
, pParent
, reader
);
3835 if (res
== xmlreader::XmlReader::Result::End
)
3845 void VclBuilder::applyPackingProperty(vcl::Window
*pCurrent
,
3846 vcl::Window
*pParent
,
3847 xmlreader::XmlReader
&reader
)
3852 //ToolBoxItems are not true widgets just elements
3853 //of the ToolBox itself
3854 ToolBox
*pToolBoxParent
= nullptr;
3855 if (pCurrent
== pParent
)
3856 pToolBoxParent
= dynamic_cast<ToolBox
*>(pParent
);
3858 xmlreader::Span name
;
3861 if (pCurrent
->GetType() == WindowType::SCROLLWINDOW
)
3863 auto aFind
= m_pParserState
->m_aRedundantParentWidgets
.find(VclPtr
<vcl::Window
>(pCurrent
));
3864 if (aFind
!= m_pParserState
->m_aRedundantParentWidgets
.end())
3866 pCurrent
= aFind
->second
;
3871 while (reader
.nextAttribute(&nsId
, &name
))
3875 name
= reader
.getAttributeValue(false);
3876 OString
sKey(name
.begin
, name
.length
);
3877 sKey
= sKey
.replace('_', '-');
3878 (void)reader
.nextItem(
3879 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3880 OString
sValue(name
.begin
, name
.length
);
3882 if (sKey
== "expand" || sKey
== "resize")
3884 bool bTrue
= (!sValue
.isEmpty() && (sValue
[0] == 't' || sValue
[0] == 'T' || sValue
[0] == '1'));
3886 pToolBoxParent
->SetItemExpand(m_pParserState
->m_nLastToolbarId
, bTrue
);
3888 pCurrent
->set_expand(bTrue
);
3897 bool bTrue
= (!sValue
.isEmpty() && (sValue
[0] == 't' || sValue
[0] == 'T' || sValue
[0] == '1'));
3898 pCurrent
->set_fill(bTrue
);
3900 else if (sKey
== "pack-type")
3902 VclPackType ePackType
= (!sValue
.isEmpty() && (sValue
[0] == 'e' || sValue
[0] == 'E')) ? VclPackType::End
: VclPackType::Start
;
3903 pCurrent
->set_pack_type(ePackType
);
3905 else if (sKey
== "left-attach")
3907 pCurrent
->set_grid_left_attach(sValue
.toInt32());
3909 else if (sKey
== "top-attach")
3911 pCurrent
->set_grid_top_attach(sValue
.toInt32());
3913 else if (sKey
== "width")
3915 pCurrent
->set_grid_width(sValue
.toInt32());
3917 else if (sKey
== "height")
3919 pCurrent
->set_grid_height(sValue
.toInt32());
3921 else if (sKey
== "padding")
3923 pCurrent
->set_padding(sValue
.toInt32());
3925 else if (sKey
== "position")
3927 set_window_packing_position(pCurrent
, sValue
.toInt32());
3929 else if (sKey
== "secondary")
3931 pCurrent
->set_secondary(toBool(sValue
));
3933 else if (sKey
== "non-homogeneous")
3935 pCurrent
->set_non_homogeneous(toBool(sValue
));
3937 else if (sKey
== "homogeneous")
3939 pCurrent
->set_non_homogeneous(!toBool(sValue
));
3943 SAL_WARN("vcl.builder", "unknown packing: " << sKey
);
3949 std::vector
<vcl::EnumContext::Context
> VclBuilder::handleStyle(xmlreader::XmlReader
&reader
, int &nPriority
)
3951 std::vector
<vcl::EnumContext::Context
> aContext
;
3953 xmlreader::Span name
;
3960 xmlreader::XmlReader::Result res
= reader
.nextItem(
3961 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3963 if (res
== xmlreader::XmlReader::Result::Done
)
3966 if (res
== xmlreader::XmlReader::Result::Begin
)
3969 if (name
== "class")
3971 OString classStyle
= getStyleClass(reader
);
3973 if (classStyle
.startsWith("context-"))
3975 OString sContext
= classStyle
.copy(classStyle
.indexOf('-') + 1);
3976 OUString
sContext2(sContext
.getStr(), sContext
.getLength(), RTL_TEXTENCODING_UTF8
);
3977 aContext
.push_back(vcl::EnumContext::GetContextEnum(sContext2
));
3979 else if (classStyle
.startsWith("priority-"))
3981 OString aPriority
= classStyle
.copy(classStyle
.indexOf('-') + 1);
3982 OUString
aPriority2(aPriority
.getStr(), aPriority
.getLength(), RTL_TEXTENCODING_UTF8
);
3983 nPriority
= aPriority2
.toInt32();
3985 else if (classStyle
!= "small-button")
3987 SAL_WARN("vcl.builder", "unknown class: " << classStyle
);
3992 if (res
== xmlreader::XmlReader::Result::End
)
4004 OString
VclBuilder::getStyleClass(xmlreader::XmlReader
&reader
)
4006 xmlreader::Span name
;
4010 while (reader
.nextAttribute(&nsId
, &name
))
4014 name
= reader
.getAttributeValue(false);
4015 aRet
= OString (name
.begin
, name
.length
);
4022 void VclBuilder::collectProperty(xmlreader::XmlReader
&reader
, stringmap
&rMap
) const
4024 xmlreader::Span name
;
4027 OString sProperty
, sContext
;
4029 bool bTranslated
= false;
4031 while (reader
.nextAttribute(&nsId
, &name
))
4035 name
= reader
.getAttributeValue(false);
4036 sProperty
= OString(name
.begin
, name
.length
);
4038 else if (name
== "context")
4040 name
= reader
.getAttributeValue(false);
4041 sContext
= OString(name
.begin
, name
.length
);
4043 else if (name
== "translatable" && reader
.getAttributeValue(false) == "yes")
4049 (void)reader
.nextItem(xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
4050 OString
sValue(name
.begin
, name
.length
);
4051 OUString sFinalValue
;
4054 if (!sContext
.isEmpty())
4055 sValue
= sContext
+ "\004" + sValue
;
4056 sFinalValue
= Translate::get(sValue
.getStr(), m_pParserState
->m_aResLocale
);
4059 sFinalValue
= OUString::fromUtf8(sValue
);
4061 if (!sProperty
.isEmpty())
4063 sProperty
= sProperty
.replace('_', '-');
4064 if (m_pStringReplace
)
4065 sFinalValue
= (*m_pStringReplace
)(sFinalValue
);
4066 rMap
[sProperty
] = sFinalValue
;
4070 void VclBuilder::handleActionWidget(xmlreader::XmlReader
&reader
)
4072 xmlreader::Span name
;
4077 while (reader
.nextAttribute(&nsId
, &name
))
4079 if (name
== "response")
4081 name
= reader
.getAttributeValue(false);
4082 sResponse
= OString(name
.begin
, name
.length
);
4086 (void)reader
.nextItem(xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
4087 OString
sID(name
.begin
, name
.length
);
4088 sal_Int32 nDelim
= sID
.indexOf(':');
4090 sID
= sID
.copy(0, nDelim
);
4091 set_response(sID
, sResponse
.toInt32());
4094 void VclBuilder::collectAccelerator(xmlreader::XmlReader
&reader
, accelmap
&rMap
)
4096 xmlreader::Span name
;
4103 while (reader
.nextAttribute(&nsId
, &name
))
4107 name
= reader
.getAttributeValue(false);
4108 sValue
= OString(name
.begin
, name
.length
);
4110 else if (name
== "signal")
4112 name
= reader
.getAttributeValue(false);
4113 sProperty
= OString(name
.begin
, name
.length
);
4115 else if (name
== "modifiers")
4117 name
= reader
.getAttributeValue(false);
4118 sModifiers
= OString(name
.begin
, name
.length
);
4122 if (!sProperty
.isEmpty() && !sValue
.isEmpty())
4124 rMap
[sProperty
] = std::make_pair(sValue
, sModifiers
);
4128 vcl::Window
*VclBuilder::get_widget_root()
4130 return m_aChildren
.empty() ? nullptr : m_aChildren
[0].m_pWindow
.get();
4133 vcl::Window
*VclBuilder::get_by_name(const OString
& sID
)
4135 for (auto const& child
: m_aChildren
)
4137 if (child
.m_sID
== sID
)
4138 return child
.m_pWindow
;
4144 PopupMenu
*VclBuilder::get_menu(const OString
& sID
)
4146 for (auto const& menu
: m_aMenus
)
4148 if (menu
.m_sID
== sID
)
4149 return dynamic_cast<PopupMenu
*>(menu
.m_pMenu
.get());
4155 void VclBuilder::set_response(const OString
& sID
, short nResponse
)
4163 nResponse
= RET_CANCEL
;
4166 nResponse
= RET_CLOSE
;
4169 nResponse
= RET_YES
;
4175 nResponse
= RET_HELP
;
4178 assert(nResponse
>= 100 && "keep non-canned responses in range 100+ to avoid collision with vcl RET_*");
4182 for (const auto & child
: m_aChildren
)
4184 if (child
.m_sID
== sID
)
4186 PushButton
* pPushButton
= dynamic_cast<PushButton
*>(child
.m_pWindow
.get());
4187 assert(pPushButton
);
4188 Dialog
* pDialog
= pPushButton
->GetParentDialog();
4190 pDialog
->add_button(pPushButton
, nResponse
, false);
4198 void VclBuilder::delete_by_name(const OString
& sID
)
4200 auto aI
= std::find_if(m_aChildren
.begin(), m_aChildren
.end(),
4201 [&sID
](WinAndId
& rItem
) { return rItem
.m_sID
== sID
; });
4202 if (aI
!= m_aChildren
.end())
4204 aI
->m_pWindow
.disposeAndClear();
4205 m_aChildren
.erase(aI
);
4209 void VclBuilder::delete_by_window(vcl::Window
*pWindow
)
4211 drop_ownership(pWindow
);
4212 pWindow
->disposeOnce();
4215 void VclBuilder::drop_ownership(const vcl::Window
*pWindow
)
4217 auto aI
= std::find_if(m_aChildren
.begin(), m_aChildren
.end(),
4218 [&pWindow
](WinAndId
& rItem
) { return rItem
.m_pWindow
== pWindow
; });
4219 if (aI
!= m_aChildren
.end())
4220 m_aChildren
.erase(aI
);
4223 OString
VclBuilder::get_by_window(const vcl::Window
*pWindow
) const
4225 for (auto const& child
: m_aChildren
)
4227 if (child
.m_pWindow
== pWindow
)
4234 VclBuilder::PackingData
VclBuilder::get_window_packing_data(const vcl::Window
*pWindow
) const
4236 //We've stored the return of new Control, some of these get
4237 //border windows placed around them which are what you get
4238 //from GetChild, so scoot up a level if necessary to get the
4239 //window whose position value we have
4240 const vcl::Window
*pPropHolder
= pWindow
->ImplGetWindow();
4242 for (auto const& child
: m_aChildren
)
4244 if (child
.m_pWindow
== pPropHolder
)
4245 return child
.m_aPackingData
;
4248 return PackingData();
4251 void VclBuilder::set_window_packing_position(const vcl::Window
*pWindow
, sal_Int32 nPosition
)
4253 for (auto & child
: m_aChildren
)
4255 if (child
.m_pWindow
== pWindow
)
4256 child
.m_aPackingData
.m_nPosition
= nPosition
;
4260 const VclBuilder::ListStore
*VclBuilder::get_model_by_name(const OString
& sID
) const
4262 std::map
<OString
, ListStore
>::const_iterator aI
= m_pParserState
->m_aModels
.find(sID
);
4263 if (aI
!= m_pParserState
->m_aModels
.end())
4264 return &(aI
->second
);
4268 const VclBuilder::TextBuffer
*VclBuilder::get_buffer_by_name(const OString
& sID
) const
4270 std::map
<OString
, TextBuffer
>::const_iterator aI
= m_pParserState
->m_aTextBuffers
.find(sID
);
4271 if (aI
!= m_pParserState
->m_aTextBuffers
.end())
4272 return &(aI
->second
);
4276 const VclBuilder::Adjustment
*VclBuilder::get_adjustment_by_name(const OString
& sID
) const
4278 std::map
<OString
, Adjustment
>::const_iterator aI
= m_pParserState
->m_aAdjustments
.find(sID
);
4279 if (aI
!= m_pParserState
->m_aAdjustments
.end())
4280 return &(aI
->second
);
4284 void VclBuilder::mungeModel(ComboBox
&rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4286 for (auto const& entry
: rStore
.m_aEntries
)
4288 const ListStore::row
&rRow
= entry
;
4289 sal_uInt16 nEntry
= rTarget
.InsertEntry(rRow
[0]);
4290 if (rRow
.size() > 1)
4294 sal_IntPtr nValue
= rRow
[1].toInt32();
4295 rTarget
.SetEntryData(nEntry
, reinterpret_cast<void*>(nValue
));
4299 if (!rRow
[1].isEmpty())
4301 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4302 rTarget
.SetEntryData(nEntry
, m_aUserData
.back().get());
4307 if (nActiveId
< rStore
.m_aEntries
.size())
4308 rTarget
.SelectEntryPos(nActiveId
);
4311 void VclBuilder::mungeModel(ListBox
&rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4313 for (auto const& entry
: rStore
.m_aEntries
)
4315 const ListStore::row
&rRow
= entry
;
4316 sal_uInt16 nEntry
= rTarget
.InsertEntry(rRow
[0]);
4317 if (rRow
.size() > 1)
4321 sal_IntPtr nValue
= rRow
[1].toInt32();
4322 rTarget
.SetEntryData(nEntry
, reinterpret_cast<void*>(nValue
));
4326 if (!rRow
[1].isEmpty())
4328 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4329 rTarget
.SetEntryData(nEntry
, m_aUserData
.back().get());
4334 if (nActiveId
< rStore
.m_aEntries
.size())
4335 rTarget
.SelectEntryPos(nActiveId
);
4338 void VclBuilder::mungeModel(SvTabListBox
& rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4340 for (auto const& entry
: rStore
.m_aEntries
)
4342 const ListStore::row
&rRow
= entry
;
4343 auto pEntry
= rTarget
.InsertEntry(rRow
[0]);
4344 if (rRow
.size() > 1)
4348 sal_IntPtr nValue
= rRow
[1].toInt32();
4349 pEntry
->SetUserData(reinterpret_cast<void*>(nValue
));
4353 if (!rRow
[1].isEmpty())
4355 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4356 pEntry
->SetUserData(m_aUserData
.back().get());
4361 if (nActiveId
< rStore
.m_aEntries
.size())
4363 SvTreeListEntry
* pEntry
= rTarget
.GetEntry(nullptr, nActiveId
);
4364 rTarget
.Select(pEntry
);
4368 void VclBuilder::mungeAdjustment(NumericFormatter
&rTarget
, const Adjustment
&rAdjustment
)
4370 int nMul
= rtl_math_pow10Exp(1, rTarget
.GetDecimalDigits());
4372 for (auto const& elem
: rAdjustment
)
4374 const OString
&rKey
= elem
.first
;
4375 const OUString
&rValue
= elem
.second
;
4377 if (rKey
== "upper")
4379 sal_Int64 nUpper
= rValue
.toDouble() * nMul
;
4380 rTarget
.SetMax(nUpper
);
4381 rTarget
.SetLast(nUpper
);
4383 else if (rKey
== "lower")
4385 sal_Int64 nLower
= rValue
.toDouble() * nMul
;
4386 rTarget
.SetMin(nLower
);
4387 rTarget
.SetFirst(nLower
);
4389 else if (rKey
== "value")
4391 sal_Int64 nValue
= rValue
.toDouble() * nMul
;
4392 rTarget
.SetValue(nValue
);
4394 else if (rKey
== "step-increment")
4396 sal_Int64 nSpinSize
= rValue
.toDouble() * nMul
;
4397 rTarget
.SetSpinSize(nSpinSize
);
4401 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4406 void VclBuilder::mungeAdjustment(FormattedField
&rTarget
, const Adjustment
&rAdjustment
)
4408 double nMaxValue
= 0, nMinValue
= 0, nValue
= 0, nSpinSize
= 0;
4410 for (auto const& elem
: rAdjustment
)
4412 const OString
&rKey
= elem
.first
;
4413 const OUString
&rValue
= elem
.second
;
4415 if (rKey
== "upper")
4416 nMaxValue
= rValue
.toDouble();
4417 else if (rKey
== "lower")
4418 nMinValue
= rValue
.toDouble();
4419 else if (rKey
== "value")
4420 nValue
= rValue
.toDouble();
4421 else if (rKey
== "step-increment")
4422 nSpinSize
= rValue
.toDouble();
4424 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4427 Formatter
& rFormatter
= rTarget
.GetFormatter();
4428 rFormatter
.SetMinValue(nMinValue
);
4429 rFormatter
.SetMaxValue(nMaxValue
);
4430 rFormatter
.SetValue(nValue
);
4431 rFormatter
.SetSpinSize(nSpinSize
);
4434 void VclBuilder::mungeAdjustment(ScrollBar
&rTarget
, const Adjustment
&rAdjustment
)
4436 for (auto const& elem
: rAdjustment
)
4438 const OString
&rKey
= elem
.first
;
4439 const OUString
&rValue
= elem
.second
;
4441 if (rKey
== "upper")
4442 rTarget
.SetRangeMax(rValue
.toInt32());
4443 else if (rKey
== "lower")
4444 rTarget
.SetRangeMin(rValue
.toInt32());
4445 else if (rKey
== "value")
4446 rTarget
.SetThumbPos(rValue
.toInt32());
4447 else if (rKey
== "step-increment")
4448 rTarget
.SetLineSize(rValue
.toInt32());
4449 else if (rKey
== "page-increment")
4450 rTarget
.SetPageSize(rValue
.toInt32());
4453 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4458 void VclBuilder::mungeAdjustment(Slider
& rTarget
, const Adjustment
& rAdjustment
)
4460 for (auto const& elem
: rAdjustment
)
4462 const OString
&rKey
= elem
.first
;
4463 const OUString
&rValue
= elem
.second
;
4465 if (rKey
== "upper")
4466 rTarget
.SetRangeMax(rValue
.toInt32());
4467 else if (rKey
== "lower")
4468 rTarget
.SetRangeMin(rValue
.toInt32());
4469 else if (rKey
== "value")
4470 rTarget
.SetThumbPos(rValue
.toInt32());
4471 else if (rKey
== "step-increment")
4472 rTarget
.SetLineSize(rValue
.toInt32());
4473 else if (rKey
== "page-increment")
4474 rTarget
.SetPageSize(rValue
.toInt32());
4477 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4482 void VclBuilder::mungeTextBuffer(VclMultiLineEdit
&rTarget
, const TextBuffer
&rTextBuffer
)
4484 for (auto const& elem
: rTextBuffer
)
4486 const OString
&rKey
= elem
.first
;
4487 const OUString
&rValue
= elem
.second
;
4490 rTarget
.SetText(rValue
);
4493 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4498 VclBuilder::ParserState::ParserState()
4499 : m_nLastToolbarId(0)
4500 , m_nLastMenuItemId(0)
4503 VclBuilder::MenuAndId::MenuAndId(const OString
&rId
, Menu
*pMenu
)
4508 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */