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>
12 #include <config_vclplug.h>
15 #include <string_view>
16 #include <unordered_map>
17 #include <com/sun/star/accessibility/AccessibleRole.hpp>
19 #include <comphelper/lok.hxx>
20 #include <i18nutil/unicode.hxx>
21 #include <jsdialog/enabled.hxx>
22 #include <o3tl/string_view.hxx>
23 #include <officecfg/Office/Common.hxx>
24 #include <osl/module.hxx>
25 #include <sal/log.hxx>
26 #include <unotools/localedatawrapper.hxx>
27 #include <unotools/resmgr.hxx>
29 #include <vcl/builder.hxx>
30 #include <vcl/dialoghelper.hxx>
31 #include <vcl/menu.hxx>
32 #include <vcl/toolkit/button.hxx>
33 #include <vcl/toolkit/dialog.hxx>
34 #include <vcl/toolkit/edit.hxx>
35 #include <vcl/toolkit/field.hxx>
36 #include <vcl/fieldvalues.hxx>
37 #include <vcl/toolkit/fmtfield.hxx>
38 #include <vcl/toolkit/fixed.hxx>
39 #include <vcl/toolkit/fixedhyper.hxx>
40 #include <vcl/headbar.hxx>
41 #include <vcl/notebookbar/NotebookBarAddonsMerger.hxx>
42 #include <vcl/toolkit/ivctrl.hxx>
43 #include <vcl/layout.hxx>
44 #include <vcl/toolkit/lstbox.hxx>
45 #include <vcl/toolkit/menubtn.hxx>
46 #include <vcl/mnemonic.hxx>
47 #include <vcl/toolkit/prgsbar.hxx>
48 #include <vcl/toolkit/scrbar.hxx>
49 #include <vcl/split.hxx>
50 #include <vcl/svapp.hxx>
51 #include <vcl/toolkit/svtabbx.hxx>
52 #include <vcl/tabctrl.hxx>
53 #include <vcl/tabpage.hxx>
54 #include <vcl/toolkit/throbber.hxx>
55 #include <vcl/toolbox.hxx>
56 #include <vcl/toolkit/treelistentry.hxx>
57 #include <vcl/toolkit/vclmedit.hxx>
58 #include <vcl/settings.hxx>
60 #include <vcl/weld.hxx>
61 #include <vcl/weldutils.hxx>
62 #include <vcl/commandinfoprovider.hxx>
63 #include <iconview.hxx>
65 #include <bitmaps.hlst>
66 #include <managedmenubutton.hxx>
67 #include <messagedialog.hxx>
68 #include <ContextVBox.hxx>
69 #include <DropdownBox.hxx>
70 #include <IPrioritable.hxx>
71 #include <OptionalBox.hxx>
72 #include <PriorityMergedHBox.hxx>
73 #include <PriorityHBox.hxx>
75 #include <xmlreader/xmlreader.hxx>
76 #include <desktop/crashreport.hxx>
77 #include <calendar.hxx>
78 #include <menutogglebutton.hxx>
79 #include <salinst.hxx>
80 #include <strings.hrc>
81 #include <treeglue.hxx>
82 #include <comphelper/diagnose_ex.hxx>
83 #include <verticaltabctrl.hxx>
85 #include <tools/svlibrary.h>
86 #include <jsdialog/jsdialogbuilder.hxx>
88 #if defined(DISABLE_DYNLOADING) || defined(LINUX)
92 static bool toBool(std::string_view rValue
)
94 return (!rValue
.empty() && (rValue
[0] == 't' || rValue
[0] == 'T' || rValue
[0] == '1'));
99 OUString
mapStockToImageResource(std::u16string_view sType
)
101 if (sType
== u
"view-refresh")
102 return SV_RESID_BITMAP_REFRESH
;
103 else if (sType
== u
"dialog-error")
105 else if (sType
== u
"list-add")
107 else if (sType
== u
"list-remove")
109 else if (sType
== u
"edit-copy")
111 else if (sType
== u
"edit-paste")
113 else if (sType
== u
"document-open")
115 else if (sType
== u
"open-menu-symbolic")
117 else if (sType
== u
"window-close-symbolic")
118 return SV_RESID_BITMAP_CLOSEDOC
;
119 else if (sType
== u
"x-office-calendar")
126 SymbolType
VclBuilder::mapStockToSymbol(std::u16string_view sType
)
128 SymbolType eRet
= SymbolType::DONTKNOW
;
129 if (sType
== u
"media-skip-forward")
130 eRet
= SymbolType::NEXT
;
131 else if (sType
== u
"media-skip-backward")
132 eRet
= SymbolType::PREV
;
133 else if (sType
== u
"media-playback-start")
134 eRet
= SymbolType::PLAY
;
135 else if (sType
== u
"media-playback-stop")
136 eRet
= SymbolType::STOP
;
137 else if (sType
== u
"go-first")
138 eRet
= SymbolType::FIRST
;
139 else if (sType
== u
"go-last")
140 eRet
= SymbolType::LAST
;
141 else if (sType
== u
"go-previous")
142 eRet
= SymbolType::ARROW_LEFT
;
143 else if (sType
== u
"go-next")
144 eRet
= SymbolType::ARROW_RIGHT
;
145 else if (sType
== u
"go-up")
146 eRet
= SymbolType::ARROW_UP
;
147 else if (sType
== u
"go-down")
148 eRet
= SymbolType::ARROW_DOWN
;
149 else if (sType
== u
"missing-image")
150 eRet
= SymbolType::IMAGE
;
151 else if (sType
== u
"help-browser" || sType
== u
"help-browser-symbolic")
152 eRet
= SymbolType::HELP
;
153 else if (sType
== u
"window-close")
154 eRet
= SymbolType::CLOSE
;
155 else if (sType
== u
"document-new")
156 eRet
= SymbolType::PLUS
;
157 else if (sType
== u
"pan-down-symbolic")
158 eRet
= SymbolType::SPIN_DOWN
;
159 else if (sType
== u
"pan-up-symbolic")
160 eRet
= SymbolType::SPIN_UP
;
161 else if (!mapStockToImageResource(sType
).isEmpty())
162 eRet
= SymbolType::IMAGE
;
168 void setupFromActionName(Button
*pButton
, VclBuilder::stringmap
&rMap
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
);
170 #if defined SAL_LOG_WARN
171 bool isButtonType(WindowType nType
)
173 return nType
== WindowType::PUSHBUTTON
||
174 nType
== WindowType::OKBUTTON
||
175 nType
== WindowType::CANCELBUTTON
||
176 nType
== WindowType::HELPBUTTON
||
177 nType
== WindowType::IMAGEBUTTON
||
178 nType
== WindowType::MENUBUTTON
||
179 nType
== WindowType::MOREBUTTON
||
180 nType
== WindowType::SPINBUTTON
;
186 std::unique_ptr
<weld::Builder
> Application::CreateBuilder(weld::Widget
* pParent
, const OUString
&rUIFile
, bool bMobile
, sal_uInt64 nLOKWindowId
)
188 if (comphelper::LibreOfficeKit::isActive())
190 if (jsdialog::isBuilderEnabledForSidebar(rUIFile
))
191 return JSInstanceBuilder::CreateSidebarBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
, nLOKWindowId
);
192 else if (jsdialog::isBuilderEnabledForPopup(rUIFile
))
193 return JSInstanceBuilder::CreatePopupBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
);
194 else if (jsdialog::isBuilderEnabled(rUIFile
, bMobile
))
195 return JSInstanceBuilder::CreateDialogBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
);
198 return ImplGetSVData()->mpDefInst
->CreateBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
);
201 std::unique_ptr
<weld::Builder
> Application::CreateInterimBuilder(vcl::Window
* pParent
, const OUString
&rUIFile
, bool bAllowCycleFocusOut
, sal_uInt64 nLOKWindowId
)
203 if (comphelper::LibreOfficeKit::isActive())
205 // Notebookbar sub controls
206 if (jsdialog::isInterimBuilderEnabledForNotebookbar(rUIFile
))
207 return JSInstanceBuilder::CreateNotebookbarBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
, css::uno::Reference
<css::frame::XFrame
>(), nLOKWindowId
);
208 else if (rUIFile
== u
"modules/scalc/ui/inputbar.ui")
209 return JSInstanceBuilder::CreateFormulabarBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
, nLOKWindowId
);
212 return ImplGetSVData()->mpDefInst
->CreateInterimBuilder(pParent
, AllSettings::GetUIRootDir(), rUIFile
, bAllowCycleFocusOut
, nLOKWindowId
);
215 weld::MessageDialog
* Application::CreateMessageDialog(weld::Widget
* pParent
, VclMessageType eMessageType
,
216 VclButtonsType eButtonType
, const OUString
& rPrimaryMessage
,
217 const ILibreOfficeKitNotifier
* pNotifier
)
219 if (comphelper::LibreOfficeKit::isActive())
220 return JSInstanceBuilder::CreateMessageDialog(pParent
, eMessageType
, eButtonType
, rPrimaryMessage
, pNotifier
);
222 return ImplGetSVData()->mpDefInst
->CreateMessageDialog(pParent
, eMessageType
, eButtonType
, rPrimaryMessage
);
225 weld::Window
* Application::GetFrameWeld(const css::uno::Reference
<css::awt::XWindow
>& rWindow
)
227 return ImplGetSVData()->mpDefInst
->GetFrameWeld(rWindow
);
232 OUString
MetricSpinButton::MetricToString(FieldUnit rUnit
)
234 const FieldUnitStringList
& rList
= ImplGetFieldUnits();
235 // return unit's default string (ie, the first one )
236 auto it
= std::find_if(
237 rList
.begin(), rList
.end(),
238 [&rUnit
](const std::pair
<OUString
, FieldUnit
>& rItem
) { return rItem
.second
== rUnit
; });
239 if (it
!= rList
.end())
245 IMPL_LINK_NOARG(MetricSpinButton
, spin_button_value_changed
, SpinButton
&, void)
247 signal_value_changed();
250 IMPL_LINK(MetricSpinButton
, spin_button_output
, SpinButton
&, rSpinButton
, void)
252 OUString
sNewText(format_number(rSpinButton
.get_value()));
253 if (sNewText
!= rSpinButton
.get_text())
254 rSpinButton
.set_text(sNewText
);
257 void MetricSpinButton::update_width_chars()
260 m_xSpinButton
->get_range(min
, max
);
261 auto width
= std::max(m_xSpinButton
->get_pixel_size(format_number(min
)).Width(),
262 m_xSpinButton
->get_pixel_size(format_number(max
)).Width());
263 int chars
= ceil(width
/ m_xSpinButton
->get_approximate_digit_width());
264 m_xSpinButton
->set_width_chars(chars
);
267 unsigned int SpinButton::Power10(unsigned int n
)
269 unsigned int nValue
= 1;
270 for (unsigned int i
= 0; i
< n
; ++i
)
275 sal_Int64
SpinButton::denormalize(sal_Int64 nValue
) const
277 const int nFactor
= Power10(get_digits());
279 if ((nValue
< (std::numeric_limits
<sal_Int64
>::min() + nFactor
)) ||
280 (nValue
> (std::numeric_limits
<sal_Int64
>::max() - nFactor
)))
282 return nValue
/ nFactor
;
285 const int nHalf
= nFactor
/ 2;
288 return (nValue
- nHalf
) / nFactor
;
289 return (nValue
+ nHalf
) / nFactor
;
292 OUString
MetricSpinButton::format_number(sal_Int64 nValue
) const
296 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
298 unsigned int nDecimalDigits
= m_xSpinButton
->get_digits();
299 //pawn percent off to icu to decide whether percent is separated from its number for this locale
300 if (m_eSrcUnit
== FieldUnit::PERCENT
)
302 double fValue
= nValue
;
303 fValue
/= SpinButton::Power10(nDecimalDigits
);
304 aStr
= unicode::formatPercent(fValue
, rLocaleData
.getLanguageTag());
308 aStr
= rLocaleData
.getNum(nValue
, nDecimalDigits
, true, true);
309 OUString aSuffix
= MetricToString(m_eSrcUnit
);
310 if (m_eSrcUnit
!= FieldUnit::NONE
&& m_eSrcUnit
!= FieldUnit::DEGREE
&& m_eSrcUnit
!= FieldUnit::INCH
&& m_eSrcUnit
!= FieldUnit::FOOT
)
312 if (m_eSrcUnit
== FieldUnit::INCH
)
314 OUString sDoublePrime
= u
"\u2033";
315 if (aSuffix
!= "\"" && aSuffix
!= sDoublePrime
)
318 aSuffix
= sDoublePrime
;
320 else if (m_eSrcUnit
== FieldUnit::FOOT
)
322 OUString sPrime
= u
"\u2032";
323 if (aSuffix
!= "'" && aSuffix
!= sPrime
)
329 assert(m_eSrcUnit
!= FieldUnit::PERCENT
);
336 void MetricSpinButton::set_digits(unsigned int digits
)
339 get_increments(step
, page
, m_eSrcUnit
);
340 sal_Int64 value
= get_value(m_eSrcUnit
);
341 m_xSpinButton
->set_digits(digits
);
342 set_increments(step
, page
, m_eSrcUnit
);
343 set_value(value
, m_eSrcUnit
);
344 update_width_chars();
347 void MetricSpinButton::set_unit(FieldUnit eUnit
)
349 if (eUnit
!= m_eSrcUnit
)
352 get_increments(step
, page
, m_eSrcUnit
);
353 sal_Int64 value
= get_value(m_eSrcUnit
);
355 set_increments(step
, page
, m_eSrcUnit
);
356 set_value(value
, m_eSrcUnit
);
357 spin_button_output(*m_xSpinButton
);
358 update_width_chars();
362 sal_Int64
MetricSpinButton::ConvertValue(sal_Int64 nValue
, FieldUnit eInUnit
, FieldUnit eOutUnit
) const
364 return vcl::ConvertValue(nValue
, 0, m_xSpinButton
->get_digits(), eInUnit
, eOutUnit
);
367 IMPL_LINK(MetricSpinButton
, spin_button_input
, int*, result
, bool)
369 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
371 bool bRet
= vcl::TextToValue(get_text(), fResult
, 0, m_xSpinButton
->get_digits(), rLocaleData
, m_eSrcUnit
);
374 if (fResult
> SAL_MAX_INT32
)
375 fResult
= SAL_MAX_INT32
;
376 else if (fResult
< SAL_MIN_INT32
)
377 fResult
= SAL_MIN_INT32
;
383 EntryTreeView::EntryTreeView(std::unique_ptr
<Entry
> xEntry
, std::unique_ptr
<TreeView
> xTreeView
)
384 : m_xEntry(std::move(xEntry
))
385 , m_xTreeView(std::move(xTreeView
))
387 m_xTreeView
->connect_changed(LINK(this, EntryTreeView
, ClickHdl
));
388 m_xEntry
->connect_changed(LINK(this, EntryTreeView
, ModifyHdl
));
391 IMPL_LINK(EntryTreeView
, ClickHdl
, weld::TreeView
&, rView
, void)
393 m_xEntry
->set_text(rView
.get_selected_text());
394 m_aChangeHdl
.Call(*this);
397 IMPL_LINK_NOARG(EntryTreeView
, ModifyHdl
, weld::Entry
&, void)
399 m_aChangeHdl
.Call(*this);
402 void EntryTreeView::set_height_request_by_rows(int nRows
)
404 int nHeight
= nRows
== -1 ? -1 : m_xTreeView
->get_height_rows(nRows
);
405 m_xTreeView
->set_size_request(m_xTreeView
->get_size_request().Width(), nHeight
);
408 size_t GetAbsPos(const weld::TreeView
& rTreeView
, const weld::TreeIter
& rIter
)
412 std::unique_ptr
<weld::TreeIter
> xEntry(rTreeView
.make_iterator(&rIter
));
413 if (!rTreeView
.get_iter_first(*xEntry
))
416 while (xEntry
&& rTreeView
.iter_compare(*xEntry
, rIter
) != 0)
418 if (!rTreeView
.iter_next(*xEntry
))
426 bool IsEntryVisible(const weld::TreeView
& rTreeView
, const weld::TreeIter
& rIter
)
428 // short circuit for the common case
429 if (rTreeView
.get_iter_depth(rIter
) == 0)
432 std::unique_ptr
<weld::TreeIter
> xEntry(rTreeView
.make_iterator(&rIter
));
433 bool bRetVal
= false;
436 if (rTreeView
.get_iter_depth(*xEntry
) == 0)
441 } while (rTreeView
.iter_parent(*xEntry
) && rTreeView
.get_row_expanded(*xEntry
));
446 VclBuilder::VclBuilder(vcl::Window
* pParent
, const OUString
& sUIDir
, const OUString
& sUIFile
,
447 OUString sID
, css::uno::Reference
<css::frame::XFrame
> xFrame
,
448 bool bLegacy
, const NotebookBarAddonsItem
* pNotebookBarAddonsItem
)
449 : m_pNotebookBarAddonsItem(pNotebookBarAddonsItem
450 ? new NotebookBarAddonsItem(*pNotebookBarAddonsItem
)
451 : new NotebookBarAddonsItem
{})
452 , m_sID(std::move(sID
))
453 , m_sHelpRoot(sUIFile
)
454 , m_pStringReplace(Translate::GetReadStringHook())
456 , m_bToplevelParentFound(false)
458 , m_pParserState(new ParserState
)
459 , m_xFrame(std::move(xFrame
))
461 m_bToplevelHasDeferredInit
= pParent
&&
462 ((pParent
->IsSystemWindow() && static_cast<SystemWindow
*>(pParent
)->isDeferredInit()) ||
463 (pParent
->IsDockingWindow() && static_cast<DockingWindow
*>(pParent
)->isDeferredInit()));
464 m_bToplevelHasDeferredProperties
= m_bToplevelHasDeferredInit
;
466 sal_Int32 nIdx
= m_sHelpRoot
.lastIndexOf('.');
468 m_sHelpRoot
= m_sHelpRoot
.copy(0, nIdx
);
471 OUString sUri
= sUIDir
+ sUIFile
;
475 xmlreader::XmlReader
reader(sUri
);
477 handleChild(pParent
, nullptr, reader
);
479 catch (const css::uno::Exception
&rExcept
)
481 DBG_UNHANDLED_EXCEPTION("vcl.builder", "Unable to read .ui file");
482 CrashReporter::addKeyValue("VclBuilderException", "Unable to read .ui file: " + rExcept
.Message
, CrashReporter::Write
);
486 //Set Mnemonic widgets when everything has been imported
487 for (auto const& mnemonicWidget
: m_pParserState
->m_aMnemonicWidgetMaps
)
489 FixedText
*pOne
= get
<FixedText
>(mnemonicWidget
.m_sID
);
490 vcl::Window
*pOther
= get(mnemonicWidget
.m_sValue
);
491 SAL_WARN_IF(!pOne
|| !pOther
, "vcl", "missing either source " << mnemonicWidget
.m_sID
492 << " or target " << mnemonicWidget
.m_sValue
<< " member of Mnemonic Widget Mapping");
494 pOne
->set_mnemonic_widget(pOther
);
497 //Set a11y relations and role when everything has been imported
498 for (auto const& elemAtk
: m_pParserState
->m_aAtkInfo
)
500 vcl::Window
*pSource
= elemAtk
.first
;
501 const stringmap
&rMap
= elemAtk
.second
;
503 for (auto const& [ rType
, rParam
] : rMap
)
507 sal_Int16 role
= BuilderUtils::getRoleFromName(rParam
);
508 if (role
!= com::sun::star::accessibility::AccessibleRole::UNKNOWN
)
509 pSource
->SetAccessibleRole(role
);
513 vcl::Window
*pTarget
= get(rParam
);
514 SAL_WARN_IF(!pTarget
, "vcl", "missing parameter of a11y relation: " << rParam
);
517 if (rType
== "labelled-by")
518 pSource
->SetAccessibleRelationLabeledBy(pTarget
);
519 else if (rType
== "label-for")
520 pSource
->SetAccessibleRelationLabelFor(pTarget
);
523 SAL_WARN("vcl.builder", "unhandled a11y relation :" << rType
);
529 //Set radiobutton groups when everything has been imported
530 for (auto const& elem
: m_pParserState
->m_aGroupMaps
)
532 RadioButton
*pOne
= get
<RadioButton
>(elem
.m_sID
);
533 RadioButton
*pOther
= get
<RadioButton
>(elem
.m_sValue
);
534 SAL_WARN_IF(!pOne
|| !pOther
, "vcl", "missing member of radiobutton group");
538 pOne
->group(*pOther
);
541 pOther
->group(*pOne
);
542 std::stable_sort(pOther
->m_xGroup
->begin(), pOther
->m_xGroup
->end(), sortIntoBestTabTraversalOrder(this));
548 o3tl::sorted_vector
<OUString
> models
;
550 //Set ComboBox models when everything has been imported
551 for (auto const& elem
: m_pParserState
->m_aModelMaps
)
553 assert(models
.insert(elem
.m_sValue
).second
&& "a liststore or treestore is used in duplicate widgets");
554 vcl::Window
* pTarget
= get(elem
.m_sID
);
555 ListBox
*pListBoxTarget
= dynamic_cast<ListBox
*>(pTarget
);
556 ComboBox
*pComboBoxTarget
= dynamic_cast<ComboBox
*>(pTarget
);
557 SvTabListBox
*pTreeBoxTarget
= dynamic_cast<SvTabListBox
*>(pTarget
);
558 // pStore may be empty
559 const ListStore
*pStore
= get_model_by_name(elem
.m_sValue
);
560 SAL_WARN_IF(!pListBoxTarget
&& !pComboBoxTarget
&& !pTreeBoxTarget
&& !dynamic_cast<IconView
*>(pTarget
), "vcl", "missing elements of combobox");
561 if (pListBoxTarget
&& pStore
)
562 mungeModel(*pListBoxTarget
, *pStore
, elem
.m_nActiveId
);
563 else if (pComboBoxTarget
&& pStore
)
564 mungeModel(*pComboBoxTarget
, *pStore
, elem
.m_nActiveId
);
565 else if (pTreeBoxTarget
&& pStore
)
566 mungeModel(*pTreeBoxTarget
, *pStore
, elem
.m_nActiveId
);
569 //Set TextView buffers when everything has been imported
570 for (auto const& elem
: m_pParserState
->m_aTextBufferMaps
)
572 VclMultiLineEdit
*pTarget
= get
<VclMultiLineEdit
>(elem
.m_sID
);
573 const TextBuffer
*pBuffer
= get_buffer_by_name(elem
.m_sValue
);
574 SAL_WARN_IF(!pTarget
|| !pBuffer
, "vcl", "missing elements of textview/textbuffer");
575 if (pTarget
&& pBuffer
)
576 mungeTextBuffer(*pTarget
, *pBuffer
);
579 //Set SpinButton adjustments when everything has been imported
580 for (auto const& elem
: m_pParserState
->m_aNumericFormatterAdjustmentMaps
)
582 NumericFormatter
*pTarget
= dynamic_cast<NumericFormatter
*>(get(elem
.m_sID
));
583 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
);
584 SAL_WARN_IF(!pTarget
, "vcl", "missing NumericFormatter element of spinbutton/adjustment");
585 SAL_WARN_IF(!pAdjustment
, "vcl", "missing Adjustment element of spinbutton/adjustment");
586 if (pTarget
&& pAdjustment
)
587 mungeAdjustment(*pTarget
, *pAdjustment
);
590 for (auto const& elem
: m_pParserState
->m_aFormattedFormatterAdjustmentMaps
)
592 FormattedField
*pTarget
= dynamic_cast<FormattedField
*>(get(elem
.m_sID
));
593 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
);
594 SAL_WARN_IF(!pTarget
, "vcl", "missing FormattedField element of spinbutton/adjustment");
595 SAL_WARN_IF(!pAdjustment
, "vcl", "missing Adjustment element of spinbutton/adjustment");
596 if (pTarget
&& pAdjustment
)
597 mungeAdjustment(*pTarget
, *pAdjustment
);
600 //Set ScrollBar adjustments when everything has been imported
601 for (auto const& elem
: m_pParserState
->m_aScrollAdjustmentMaps
)
603 ScrollBar
*pTarget
= get
<ScrollBar
>(elem
.m_sID
);
604 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
);
605 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of scrollbar/adjustment");
606 if (pTarget
&& pAdjustment
)
607 mungeAdjustment(*pTarget
, *pAdjustment
);
610 //Set Scale(Slider) adjustments
611 for (auto const& elem
: m_pParserState
->m_aSliderAdjustmentMaps
)
613 Slider
* pTarget
= dynamic_cast<Slider
*>(get(elem
.m_sID
));
614 const Adjustment
* pAdjustment
= get_adjustment_by_name(elem
.m_sValue
);
615 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of scale(slider)/adjustment");
616 if (pTarget
&& pAdjustment
)
618 mungeAdjustment(*pTarget
, *pAdjustment
);
622 //Set size-groups when all widgets have been imported
623 for (auto const& sizeGroup
: m_pParserState
->m_aSizeGroups
)
625 std::shared_ptr
<VclSizeGroup
> xGroup(std::make_shared
<VclSizeGroup
>());
627 for (auto const& [ rKey
, rValue
] : sizeGroup
.m_aProperties
)
628 xGroup
->set_property(rKey
, rValue
);
630 for (auto const& elem
: sizeGroup
.m_aWidgets
)
632 vcl::Window
* pWindow
= get(elem
);
633 pWindow
->add_to_size_group(xGroup
);
637 //Set button images when everything has been imported
638 std::set
<OUString
> aImagesToBeRemoved
;
639 for (auto const& elem
: m_pParserState
->m_aButtonImageWidgetMaps
)
641 PushButton
*pTargetButton
= nullptr;
642 RadioButton
*pTargetRadio
= nullptr;
643 Button
*pTarget
= nullptr;
647 pTargetButton
= get
<PushButton
>(elem
.m_sID
);
648 pTarget
= pTargetButton
;
652 pTargetRadio
= get
<RadioButton
>(elem
.m_sID
);
653 pTarget
= pTargetRadio
;
656 FixedImage
*pImage
= get
<FixedImage
>(elem
.m_sValue
);
657 SAL_WARN_IF(!pTarget
|| !pImage
,
658 "vcl", "missing elements of button/image/stock");
659 if (!pTarget
|| !pImage
)
661 aImagesToBeRemoved
.insert(elem
.m_sValue
);
665 const Image
& rImage
= pImage
->GetImage();
666 SymbolType eSymbol
= mapStockToSymbol(rImage
.GetStock());
667 if (eSymbol
!= SymbolType::IMAGE
&& eSymbol
!= SymbolType::DONTKNOW
)
669 pTargetButton
->SetSymbol(eSymbol
);
670 //fdo#76457 keep symbol images small e.g. tools->customize->menu
671 //but images the right size. Really the PushButton::CalcMinimumSize
672 //and PushButton::ImplDrawPushButton are the better place to handle
673 //this, but its such a train-wreck
674 pTargetButton
->SetStyle(pTargetButton
->GetStyle() | WB_SMALLSTYLE
);
678 pTargetButton
->SetModeImage(rImage
);
679 if (pImage
->GetStyle() & WB_SMALLSTYLE
)
681 Size
aSz(rImage
.GetSizePixel());
684 if (pTargetButton
->get_width_request() == -1)
685 pTargetButton
->set_width_request(aSz
.Width());
686 if (pTargetButton
->get_height_request() == -1)
687 pTargetButton
->set_height_request(aSz
.Height());
692 pTargetRadio
->SetModeRadioImage(pImage
->GetImage());
694 auto aFind
= m_pParserState
->m_aImageSizeMap
.find(elem
.m_sValue
);
695 if (aFind
!= m_pParserState
->m_aImageSizeMap
.end())
697 switch (aFind
->second
)
700 pTarget
->SetSmallSymbol();
703 assert(pImage
->GetStyle() & WB_SMALLSTYLE
);
704 pTarget
->SetStyle(pTarget
->GetStyle() | WB_SMALLSTYLE
);
707 pTarget
->SetStyle(pTarget
->GetStyle() | WB_SMALLSTYLE
);
708 // large toolbar, make bigger than normal (4)
709 pTarget
->set_width_request(pTarget
->GetOptimalSize().Width() * 1.5);
710 pTarget
->set_height_request(pTarget
->GetOptimalSize().Height() * 1.5);
715 SAL_WARN("vcl.builder", "unsupported image size " << aFind
->second
);
718 m_pParserState
->m_aImageSizeMap
.erase(aFind
);
722 //There may be duplicate use of an Image, so we used a set to collect and
723 //now we can remove them from the tree after their final munge
724 for (auto const& elem
: aImagesToBeRemoved
)
726 delete_by_name(elem
);
729 //Set button menus when everything has been imported
730 for (auto const& elem
: m_pParserState
->m_aButtonMenuMaps
)
732 MenuButton
*pTarget
= get
<MenuButton
>(elem
.m_sID
);
733 PopupMenu
*pMenu
= get_menu(elem
.m_sValue
);
734 SAL_WARN_IF(!pTarget
|| !pMenu
,
735 "vcl", "missing elements of button/menu");
736 if (!pTarget
|| !pMenu
)
738 pTarget
->SetPopupMenu(pMenu
);
741 //Remove ScrollWindow parent widgets whose children in vcl implement scrolling
743 for (auto const& elem
: m_pParserState
->m_aRedundantParentWidgets
)
745 delete_by_window(elem
.first
);
748 //fdo#67378 merge the label into the disclosure button
749 for (auto const& elem
: m_pParserState
->m_aExpanderWidgets
)
751 vcl::Window
*pChild
= elem
->get_child();
752 vcl::Window
* pLabel
= elem
->GetWindow(GetWindowType::LastChild
);
753 if (pLabel
&& pLabel
!= pChild
&& pLabel
->GetType() == WindowType::FIXEDTEXT
)
755 FixedText
*pLabelWidget
= static_cast<FixedText
*>(pLabel
);
756 elem
->set_label(pLabelWidget
->GetText());
757 if (pLabelWidget
->IsControlFont())
758 elem
->get_label_widget()->SetControlFont(pLabelWidget
->GetControlFont());
759 delete_by_window(pLabel
);
763 // create message dialog message area now
764 for (auto const& elem
: m_pParserState
->m_aMessageDialogs
)
765 elem
->create_message_area();
767 //drop maps, etc. that we don't need again
768 m_pParserState
.reset();
770 SAL_WARN_IF(!m_sID
.isEmpty() && (!m_bToplevelParentFound
&& !get_by_name(m_sID
)), "vcl.builder",
771 "Requested top level widget \"" << m_sID
<< "\" not found in " << sUIFile
);
773 #if defined SAL_LOG_WARN
774 if (m_bToplevelParentFound
&& m_pParent
->IsDialog())
777 bool bHasDefButton
= false;
778 for (auto const& child
: m_aChildren
)
780 if (isButtonType(child
.m_pWindow
->GetType()))
783 if (child
.m_pWindow
->GetStyle() & WB_DEFBUTTON
)
785 bHasDefButton
= true;
790 SAL_WARN_IF(nButtons
&& !bHasDefButton
, "vcl.builder", "No default button defined in " << sUIFile
);
794 const bool bHideHelp
= comphelper::LibreOfficeKit::isActive() &&
795 officecfg::Office::Common::Help::HelpRootURL::get().isEmpty();
798 if (vcl::Window
*pHelpButton
= get("help"))
803 VclBuilder::~VclBuilder()
808 void VclBuilder::disposeBuilder()
810 for (std::vector
<WinAndId
>::reverse_iterator aI
= m_aChildren
.rbegin(),
811 aEnd
= m_aChildren
.rend(); aI
!= aEnd
; ++aI
)
813 aI
->m_pWindow
.disposeAndClear();
817 for (std::vector
<MenuAndId
>::reverse_iterator aI
= m_aMenus
.rbegin(),
818 aEnd
= m_aMenus
.rend(); aI
!= aEnd
; ++aI
)
820 aI
->m_pMenu
.disposeAndClear();
828 bool extractHasFrame(VclBuilder::stringmap
& rMap
)
830 bool bHasFrame
= true;
831 VclBuilder::stringmap::iterator aFind
= rMap
.find("has-frame");
832 if (aFind
!= rMap
.end())
834 bHasFrame
= toBool(aFind
->second
);
840 bool extractDrawValue(VclBuilder::stringmap
& rMap
)
842 bool bDrawValue
= true;
843 VclBuilder::stringmap::iterator aFind
= rMap
.find("draw-value");
844 if (aFind
!= rMap
.end())
846 bDrawValue
= toBool(aFind
->second
);
852 OUString
extractPopupMenu(VclBuilder::stringmap
& rMap
)
855 VclBuilder::stringmap::iterator aFind
= rMap
.find("popup");
856 if (aFind
!= rMap
.end())
858 sRet
= aFind
->second
;
864 OUString
extractWidgetName(VclBuilder::stringmap
& rMap
)
867 VclBuilder::stringmap::iterator aFind
= rMap
.find("name");
868 if (aFind
!= rMap
.end())
870 sRet
= aFind
->second
;
876 OUString
extractValuePos(VclBuilder::stringmap
& rMap
)
878 OUString
sRet("top");
879 VclBuilder::stringmap::iterator aFind
= rMap
.find("value-pos");
880 if (aFind
!= rMap
.end())
882 sRet
= aFind
->second
;
888 OUString
extractTypeHint(VclBuilder::stringmap
&rMap
)
890 OUString
sRet("normal");
891 VclBuilder::stringmap::iterator aFind
= rMap
.find("type-hint");
892 if (aFind
!= rMap
.end())
894 sRet
= aFind
->second
;
900 bool extractResizable(VclBuilder::stringmap
&rMap
)
902 bool bResizable
= true;
903 VclBuilder::stringmap::iterator aFind
= rMap
.find("resizable");
904 if (aFind
!= rMap
.end())
906 bResizable
= toBool(aFind
->second
);
912 #if HAVE_FEATURE_DESKTOP
913 bool extractModal(VclBuilder::stringmap
&rMap
)
916 VclBuilder::stringmap::iterator aFind
= rMap
.find("modal");
917 if (aFind
!= rMap
.end())
919 bModal
= toBool(aFind
->second
);
926 bool extractDecorated(VclBuilder::stringmap
&rMap
)
928 bool bDecorated
= true;
929 VclBuilder::stringmap::iterator aFind
= rMap
.find("decorated");
930 if (aFind
!= rMap
.end())
932 bDecorated
= toBool(aFind
->second
);
938 bool extractCloseable(VclBuilder::stringmap
&rMap
)
940 bool bCloseable
= true;
941 VclBuilder::stringmap::iterator aFind
= rMap
.find("deletable");
942 if (aFind
!= rMap
.end())
944 bCloseable
= toBool(aFind
->second
);
950 bool extractEntry(VclBuilder::stringmap
&rMap
)
952 bool bHasEntry
= false;
953 VclBuilder::stringmap::iterator aFind
= rMap
.find("has-entry");
954 if (aFind
!= rMap
.end())
956 bHasEntry
= toBool(aFind
->second
);
962 bool extractOrientation(VclBuilder::stringmap
&rMap
)
964 bool bVertical
= false;
965 VclBuilder::stringmap::iterator aFind
= rMap
.find("orientation");
966 if (aFind
!= rMap
.end())
968 bVertical
= aFind
->second
.equalsIgnoreAsciiCase("vertical");
974 bool extractVerticalTabPos(VclBuilder::stringmap
&rMap
)
976 bool bVertical
= false;
977 VclBuilder::stringmap::iterator aFind
= rMap
.find("tab-pos");
978 if (aFind
!= rMap
.end())
980 bVertical
= aFind
->second
.equalsIgnoreAsciiCase("left") ||
981 aFind
->second
.equalsIgnoreAsciiCase("right");
987 bool extractInconsistent(VclBuilder::stringmap
&rMap
)
989 bool bInconsistent
= false;
990 VclBuilder::stringmap::iterator aFind
= rMap
.find("inconsistent");
991 if (aFind
!= rMap
.end())
993 bInconsistent
= toBool(aFind
->second
);
996 return bInconsistent
;
999 OUString
extractIconName(VclBuilder::stringmap
&rMap
)
1002 // allow pixbuf, but prefer icon-name
1004 VclBuilder::stringmap::iterator aFind
= rMap
.find("pixbuf");
1005 if (aFind
!= rMap
.end())
1007 sIconName
= aFind
->second
;
1012 VclBuilder::stringmap::iterator aFind
= rMap
.find("icon-name");
1013 if (aFind
!= rMap
.end())
1015 sIconName
= aFind
->second
;
1019 if (sIconName
== "missing-image")
1021 OUString sReplace
= mapStockToImageResource(sIconName
);
1022 return !sReplace
.isEmpty() ? sReplace
: sIconName
;
1025 WinBits
extractRelief(VclBuilder::stringmap
&rMap
)
1027 WinBits nBits
= WB_3DLOOK
;
1028 VclBuilder::stringmap::iterator aFind
= rMap
.find("relief");
1029 if (aFind
!= rMap
.end())
1031 assert(aFind
->second
!= "half" && "relief of 'half' unsupported");
1032 if (aFind
->second
== "none")
1033 nBits
= WB_FLATBUTTON
;
1039 OUString
extractLabel(VclBuilder::stringmap
&rMap
)
1042 VclBuilder::stringmap::iterator aFind
= rMap
.find("label");
1043 if (aFind
!= rMap
.end())
1045 sType
= aFind
->second
;
1051 OUString
extractActionName(VclBuilder::stringmap
&rMap
)
1053 OUString sActionName
;
1054 VclBuilder::stringmap::iterator aFind
= rMap
.find("action-name");
1055 if (aFind
!= rMap
.end())
1057 sActionName
= aFind
->second
;
1063 bool extractVisible(VclBuilder::stringmap
&rMap
)
1066 VclBuilder::stringmap::iterator aFind
= rMap
.find("visible");
1067 if (aFind
!= rMap
.end())
1069 bRet
= toBool(aFind
->second
);
1075 Size
extractSizeRequest(VclBuilder::stringmap
&rMap
)
1077 OUString
sWidthRequest("0");
1078 OUString
sHeightRequest("0");
1079 VclBuilder::stringmap::iterator aFind
= rMap
.find("width-request");
1080 if (aFind
!= rMap
.end())
1082 sWidthRequest
= aFind
->second
;
1085 aFind
= rMap
.find("height-request");
1086 if (aFind
!= rMap
.end())
1088 sHeightRequest
= aFind
->second
;
1091 return Size(sWidthRequest
.toInt32(), sHeightRequest
.toInt32());
1094 OUString
extractTooltipText(VclBuilder::stringmap
&rMap
)
1096 OUString sTooltipText
;
1097 VclBuilder::stringmap::iterator aFind
= rMap
.find("tooltip-text");
1098 if (aFind
== rMap
.end())
1099 aFind
= rMap
.find("tooltip-markup");
1100 if (aFind
!= rMap
.end())
1102 sTooltipText
= aFind
->second
;
1105 return sTooltipText
;
1108 float extractAlignment(VclBuilder::stringmap
&rMap
)
1111 VclBuilder::stringmap::iterator aFind
= rMap
.find("alignment");
1112 if (aFind
!= rMap
.end())
1114 f
= aFind
->second
.toFloat();
1120 OUString
extractTitle(VclBuilder::stringmap
&rMap
)
1123 VclBuilder::stringmap::iterator aFind
= rMap
.find("title");
1124 if (aFind
!= rMap
.end())
1126 sTitle
= aFind
->second
;
1132 bool extractHeadersVisible(VclBuilder::stringmap
&rMap
)
1134 bool bHeadersVisible
= true;
1135 VclBuilder::stringmap::iterator aFind
= rMap
.find("headers-visible");
1136 if (aFind
!= rMap
.end())
1138 bHeadersVisible
= toBool(aFind
->second
);
1141 return bHeadersVisible
;
1144 bool extractSortIndicator(VclBuilder::stringmap
&rMap
)
1146 bool bSortIndicator
= false;
1147 VclBuilder::stringmap::iterator aFind
= rMap
.find("sort-indicator");
1148 if (aFind
!= rMap
.end())
1150 bSortIndicator
= toBool(aFind
->second
);
1153 return bSortIndicator
;
1156 bool extractClickable(VclBuilder::stringmap
&rMap
)
1158 bool bClickable
= false;
1159 VclBuilder::stringmap::iterator aFind
= rMap
.find("clickable");
1160 if (aFind
!= rMap
.end())
1162 bClickable
= toBool(aFind
->second
);
1168 void setupFromActionName(Button
*pButton
, VclBuilder::stringmap
&rMap
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
)
1173 OUString
aCommand(extractActionName(rMap
));
1174 if (aCommand
.isEmpty())
1177 OUString
aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame
));
1178 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(aCommand
, aModuleName
);
1179 OUString
aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties
));
1180 if (!aLabel
.isEmpty())
1181 pButton
->SetText(aLabel
);
1183 OUString
aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(aCommand
, aProperties
, rFrame
));
1184 if (!aTooltip
.isEmpty())
1185 pButton
->SetQuickHelpText(aTooltip
);
1187 Image
aImage(vcl::CommandInfoProvider::GetImageForCommand(aCommand
, rFrame
));
1188 pButton
->SetModeImage(aImage
);
1190 pButton
->SetCommandHandler(aCommand
, rFrame
);
1193 VclPtr
<Button
> extractStockAndBuildPushButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
, bool bToggle
)
1195 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
;
1199 nBits
|= extractRelief(rMap
);
1201 VclPtr
<Button
> xWindow
= VclPtr
<PushButton
>::Create(pParent
, nBits
);
1205 VclPtr
<MenuButton
> extractStockAndBuildMenuButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
)
1207 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1209 nBits
|= extractRelief(rMap
);
1211 VclPtr
<MenuButton
> xWindow
= VclPtr
<MenuButton
>::Create(pParent
, nBits
);
1215 VclPtr
<MenuButton
> extractStockAndBuildMenuToggleButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
)
1217 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1219 nBits
|= extractRelief(rMap
);
1221 VclPtr
<MenuButton
> xWindow
= VclPtr
<MenuToggleButton
>::Create(pParent
, nBits
);
1225 WinBits
extractDeferredBits(VclBuilder::stringmap
&rMap
)
1227 WinBits nBits
= WB_3DLOOK
|WB_HIDE
;
1228 if (extractResizable(rMap
))
1229 nBits
|= WB_SIZEABLE
;
1230 if (extractCloseable(rMap
))
1231 nBits
|= WB_CLOSEABLE
;
1232 if (!extractDecorated(rMap
))
1233 nBits
|= WB_OWNERDRAWDECORATION
;
1234 OUString
sType(extractTypeHint(rMap
));
1235 if (sType
== "utility")
1236 nBits
|= WB_SYSTEMWINDOW
| WB_DIALOGCONTROL
| WB_MOVEABLE
;
1237 else if (sType
== "popup-menu")
1238 nBits
|= WB_SYSTEMWINDOW
| WB_DIALOGCONTROL
| WB_POPUP
;
1239 else if (sType
== "dock")
1240 nBits
|= WB_DOCKABLE
| WB_MOVEABLE
;
1242 nBits
|= WB_MOVEABLE
;
1247 void VclBuilder::extractGroup(const OUString
&id
, stringmap
&rMap
)
1249 VclBuilder::stringmap::iterator aFind
= rMap
.find("group");
1250 if (aFind
!= rMap
.end())
1252 OUString sID
= aFind
->second
;
1253 sal_Int32 nDelim
= sID
.indexOf(':');
1255 sID
= sID
.copy(0, nDelim
);
1256 m_pParserState
->m_aGroupMaps
.emplace_back(id
, sID
);
1261 void VclBuilder::connectNumericFormatterAdjustment(const OUString
&id
, const OUString
&rAdjustment
)
1263 if (!rAdjustment
.isEmpty())
1264 m_pParserState
->m_aNumericFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1267 void VclBuilder::connectFormattedFormatterAdjustment(const OUString
&id
, const OUString
&rAdjustment
)
1269 if (!rAdjustment
.isEmpty())
1270 m_pParserState
->m_aFormattedFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1273 bool VclBuilder::extractAdjustmentToMap(const OUString
& id
, VclBuilder::stringmap
& rMap
, std::vector
<WidgetAdjustmentMap
>& rAdjustmentMap
)
1275 VclBuilder::stringmap::iterator aFind
= rMap
.find("adjustment");
1276 if (aFind
!= rMap
.end())
1278 rAdjustmentMap
.emplace_back(id
, aFind
->second
);
1287 sal_Int32
extractActive(VclBuilder::stringmap
&rMap
)
1289 sal_Int32 nActiveId
= 0;
1290 VclBuilder::stringmap::iterator aFind
= rMap
.find("active");
1291 if (aFind
!= rMap
.end())
1293 nActiveId
= aFind
->second
.toInt32();
1299 bool extractSelectable(VclBuilder::stringmap
&rMap
)
1301 bool bSelectable
= false;
1302 VclBuilder::stringmap::iterator aFind
= rMap
.find("selectable");
1303 if (aFind
!= rMap
.end())
1305 bSelectable
= toBool(aFind
->second
);
1311 OUString
extractAdjustment(VclBuilder::stringmap
&rMap
)
1313 OUString sAdjustment
;
1314 VclBuilder::stringmap::iterator aFind
= rMap
.find("adjustment");
1315 if (aFind
!= rMap
.end())
1317 sAdjustment
= aFind
->second
;
1324 bool extractDrawIndicator(VclBuilder::stringmap
&rMap
)
1326 bool bDrawIndicator
= false;
1327 VclBuilder::stringmap::iterator aFind
= rMap
.find("draw-indicator");
1328 if (aFind
!= rMap
.end())
1330 bDrawIndicator
= toBool(aFind
->second
);
1333 return bDrawIndicator
;
1337 void VclBuilder::extractModel(const OUString
&id
, stringmap
&rMap
)
1339 VclBuilder::stringmap::iterator aFind
= rMap
.find("model");
1340 if (aFind
!= rMap
.end())
1342 m_pParserState
->m_aModelMaps
.emplace_back(id
, aFind
->second
,
1343 extractActive(rMap
));
1348 void VclBuilder::extractBuffer(const OUString
&id
, stringmap
&rMap
)
1350 VclBuilder::stringmap::iterator aFind
= rMap
.find("buffer");
1351 if (aFind
!= rMap
.end())
1353 m_pParserState
->m_aTextBufferMaps
.emplace_back(id
, aFind
->second
);
1358 int VclBuilder::getImageSize(const stringmap
&rMap
)
1361 auto aFind
= rMap
.find("icon-size");
1362 if (aFind
!= rMap
.end())
1363 nSize
= aFind
->second
.toInt32();
1367 void VclBuilder::extractButtonImage(const OUString
&id
, stringmap
&rMap
, bool bRadio
)
1369 VclBuilder::stringmap::iterator aFind
= rMap
.find("image");
1370 if (aFind
!= rMap
.end())
1372 m_pParserState
->m_aButtonImageWidgetMaps
.emplace_back(id
, aFind
->second
, bRadio
);
1377 void VclBuilder::extractMnemonicWidget(const OUString
&rLabelID
, stringmap
&rMap
)
1379 VclBuilder::stringmap::iterator aFind
= rMap
.find("mnemonic-widget");
1380 if (aFind
!= rMap
.end())
1382 OUString sID
= aFind
->second
;
1383 sal_Int32 nDelim
= sID
.indexOf(':');
1385 sID
= sID
.copy(0, nDelim
);
1386 m_pParserState
->m_aMnemonicWidgetMaps
.emplace_back(rLabelID
, sID
);
1391 vcl::Window
* VclBuilder::prepareWidgetOwnScrolling(vcl::Window
*pParent
, WinBits
&rWinStyle
)
1393 //For Widgets that manage their own scrolling, if one appears as a child of
1394 //a scrolling window shoehorn that scrolling settings to this widget and
1395 //return the real parent to use
1396 if (pParent
&& pParent
->GetType() == WindowType::SCROLLWINDOW
)
1398 WinBits nScrollBits
= pParent
->GetStyle();
1399 nScrollBits
&= (WB_AUTOHSCROLL
|WB_HSCROLL
|WB_AUTOVSCROLL
|WB_VSCROLL
);
1400 rWinStyle
|= nScrollBits
;
1401 if (static_cast<VclScrolledWindow
*>(pParent
)->HasVisibleBorder())
1402 rWinStyle
|= WB_BORDER
;
1403 pParent
= pParent
->GetParent();
1409 void VclBuilder::cleanupWidgetOwnScrolling(vcl::Window
*pScrollParent
, vcl::Window
*pWindow
, stringmap
&rMap
)
1411 //remove the redundant scrolling parent
1412 sal_Int32 nWidthReq
= pScrollParent
->get_width_request();
1413 rMap
["width-request"] = OUString::number(nWidthReq
);
1414 sal_Int32 nHeightReq
= pScrollParent
->get_height_request();
1415 rMap
["height-request"] = OUString::number(nHeightReq
);
1417 m_pParserState
->m_aRedundantParentWidgets
[pScrollParent
] = pWindow
;
1420 #ifndef DISABLE_DYNLOADING
1422 extern "C" { static void thisModule() {} }
1426 // Don't unload the module on destruction
1427 class NoAutoUnloadModule
: public osl::Module
1430 ~NoAutoUnloadModule() { release(); }
1435 typedef std::map
<OUString
, std::shared_ptr
<NoAutoUnloadModule
>> ModuleMap
;
1436 static ModuleMap g_aModuleMap
;
1438 #if ENABLE_MERGELIBS
1439 static std::shared_ptr
<NoAutoUnloadModule
> g_pMergedLib
= std::make_shared
<NoAutoUnloadModule
>();
1442 #ifndef SAL_DLLPREFIX
1443 # define SAL_DLLPREFIX ""
1450 void VclBuilderPreload()
1452 #ifndef DISABLE_DYNLOADING
1454 #if ENABLE_MERGELIBS
1455 g_pMergedLib
->loadRelative(&thisModule
, SVLIBRARY("merged"));
1457 // find -name '*ui*' | xargs grep 'class=".*lo-' |
1458 // sed 's/.*class="//' | sed 's/-.*$//' | sort | uniq
1459 static const char *aWidgetLibs
[] = {
1462 for (const auto & lib
: aWidgetLibs
)
1464 std::unique_ptr
<NoAutoUnloadModule
> pModule(new NoAutoUnloadModule
);
1465 OUString sModule
= SAL_DLLPREFIX
+ OUString::createFromAscii(lib
) + SAL_DLLEXTENSION
;
1466 if (pModule
->loadRelative(&thisModule
, sModule
))
1467 g_aModuleMap
.insert(std::make_pair(sModule
, std::move(pModule
)));
1469 #endif // ENABLE_MERGELIBS
1470 #endif // DISABLE_DYNLOADING
1475 #if defined DISABLE_DYNLOADING && !HAVE_FEATURE_DESKTOP
1477 // This ifdef branch is mainly for building for the Collabora Online
1478 // -based mobile apps for Android and iOS.
1480 extern "C" VclBuilder::customMakeWidget
lo_get_custom_widget_func(const char* name
);
1482 #elif defined EMSCRIPTEN && !ENABLE_QT5
1484 // This branch is mainly for building for WASM, and especially for
1485 // Collabora Online in the browser, where code from core and Collabora
1486 // Online is compiled to WASM and linked into a single WASM binary.
1487 // (Not for Allotropia's Qt-based LibreOffice in the browser.)
1489 // When building core for WASM it doesn't use the same
1490 // solenv/bin/native-code.py thing as the mobile apps, even if in both
1491 // cases everything is linked statically. So there is no generated
1492 // native-code.h, and we can't use lo_get_custom_widget_func() from
1493 // that. So cheat and duplicate the code from an existing generated
1494 // native-code.h. It's just a handful of lines anyway.
1496 extern "C" void makeNotebookbarTabControl(VclPtr
<vcl::Window
> &rRet
, const VclPtr
<vcl::Window
> &pParent
, VclBuilder::stringmap
&rVec
);
1497 extern "C" void makeNotebookbarToolBox(VclPtr
<vcl::Window
> &rRet
, const VclPtr
<vcl::Window
> &pParent
, VclBuilder::stringmap
&rVec
);
1499 static struct { const char *name
; VclBuilder::customMakeWidget func
; } custom_widgets
[] = {
1500 { "makeNotebookbarTabControl", makeNotebookbarTabControl
},
1501 { "makeNotebookbarToolBox", makeNotebookbarToolBox
},
1504 static VclBuilder::customMakeWidget
lo_get_custom_widget_func(const char* name
)
1506 for (size_t i
= 0; i
< sizeof(custom_widgets
) / sizeof(custom_widgets
[0]); i
++)
1507 if (strcmp(name
, custom_widgets
[i
].name
) == 0)
1508 return custom_widgets
[i
].func
;
1516 // Takes a string like "sfxlo-NotebookbarToolBox"
1517 VclBuilder::customMakeWidget
GetCustomMakeWidget(const OUString
& rName
)
1519 const OUString name
= rName
== "sfxlo-SidebarToolBox" ? "sfxlo-NotebookbarToolBox" : rName
;
1520 VclBuilder::customMakeWidget pFunction
= nullptr;
1521 if (sal_Int32 nDelim
= name
.indexOf('-'); nDelim
!= -1)
1523 const OUString
sFunction(OUString::Concat("make") + name
.subView(nDelim
+ 1));
1525 #ifndef DISABLE_DYNLOADING
1526 const OUString sModule
= OUString::Concat(SAL_DLLPREFIX
)
1527 + name
.subView(0, nDelim
)
1529 ModuleMap::iterator aI
= g_aModuleMap
.find(sModule
);
1530 if (aI
== g_aModuleMap
.end())
1532 std::shared_ptr
<NoAutoUnloadModule
> pModule
;
1533 #if ENABLE_MERGELIBS
1534 if (!g_pMergedLib
->is())
1535 g_pMergedLib
->loadRelative(&thisModule
, SVLIBRARY("merged"));
1536 if ((pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1537 g_pMergedLib
->getFunctionSymbol(sFunction
))))
1538 pModule
= g_pMergedLib
;
1542 pModule
= std::make_shared
<NoAutoUnloadModule
>();
1543 bool ok
= pModule
->loadRelative(&thisModule
, sModule
);
1547 // in the case of preloading, we don't have eg. the
1548 // libcuilo.so, but still need to dlsym the symbols -
1549 // which are already in-process
1550 if (comphelper::LibreOfficeKit::isActive())
1552 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(dlsym(RTLD_DEFAULT
, OUStringToOString(sFunction
, RTL_TEXTENCODING_UTF8
).getStr()));
1554 assert(ok
&& "couldn't even directly dlsym the sFunction (available via preload)");
1557 assert(ok
&& "bad module name in .ui");
1561 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1562 pModule
->getFunctionSymbol(sFunction
));
1565 g_aModuleMap
.insert(std::make_pair(sModule
, pModule
));
1568 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1569 aI
->second
->getFunctionSymbol(sFunction
));
1570 #elif !HAVE_FEATURE_DESKTOP || (defined EMSCRIPTEN && !ENABLE_QT5)
1571 // This ifdef branch is mainly for building for either the
1572 // Android or iOS apps, or the Collabora Online as WASM thing.
1573 pFunction
= lo_get_custom_widget_func(sFunction
.toUtf8().getStr());
1574 SAL_WARN_IF(!pFunction
, "vcl.builder", "Could not find " << sFunction
);
1577 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1578 osl_getFunctionSymbol((oslModule
)RTLD_DEFAULT
, sFunction
.pData
));
1585 VclPtr
<vcl::Window
> VclBuilder::makeObject(vcl::Window
*pParent
, const OUString
&name
, const OUString
&id
,
1588 bool bIsPlaceHolder
= name
.isEmpty();
1589 bool bVertical
= false;
1591 if (pParent
&& (pParent
->GetType() == WindowType::TABCONTROL
||
1592 pParent
->GetType() == WindowType::VERTICALTABCONTROL
))
1594 bool bTopLevel(name
== "GtkDialog" || name
== "GtkMessageDialog" ||
1595 name
== "GtkWindow" || name
== "GtkPopover" || name
== "GtkAssistant");
1598 if (pParent
->GetType() == WindowType::TABCONTROL
)
1600 //We have to add a page
1601 //make default pageid == position
1602 TabControl
*pTabControl
= static_cast<TabControl
*>(pParent
);
1603 sal_uInt16 nNewPageCount
= pTabControl
->GetPageCount()+1;
1604 sal_uInt16 nNewPageId
= nNewPageCount
;
1605 pTabControl
->InsertPage(nNewPageId
, OUString());
1606 pTabControl
->SetCurPageId(nNewPageId
);
1607 SAL_WARN_IF(bIsPlaceHolder
, "vcl.builder", "we should have no placeholders for tabpages");
1608 if (!bIsPlaceHolder
)
1610 VclPtrInstance
<TabPage
> pPage(pTabControl
);
1613 //Make up a name for it
1614 OUString sTabPageId
= get_by_window(pParent
) +
1616 OUString::number(nNewPageCount
);
1617 m_aChildren
.emplace_back(sTabPageId
, pPage
, false);
1618 pPage
->SetHelpId(m_sHelpRoot
+ sTabPageId
);
1622 pTabControl
->SetTabPage(nNewPageId
, pPage
);
1627 VerticalTabControl
*pTabControl
= static_cast<VerticalTabControl
*>(pParent
);
1628 SAL_WARN_IF(bIsPlaceHolder
, "vcl.builder", "we should have no placeholders for tabpages");
1629 if (!bIsPlaceHolder
)
1630 pParent
= pTabControl
->GetPageParent();
1635 if (bIsPlaceHolder
|| name
== "GtkTreeSelection")
1638 ToolBox
*pToolBox
= (pParent
&& pParent
->GetType() == WindowType::TOOLBOX
) ? static_cast<ToolBox
*>(pParent
) : nullptr;
1640 extractButtonImage(id
, rMap
, name
== "GtkRadioButton");
1642 VclPtr
<vcl::Window
> xWindow
;
1643 if (name
== "GtkDialog" || name
== "GtkAssistant")
1645 // WB_ALLOWMENUBAR because we don't know in advance if we will encounter
1646 // a menubar, and menubars need a BorderWindow in the toplevel, and
1647 // such border windows need to be in created during the dialog ctor
1648 WinBits nBits
= WB_MOVEABLE
|WB_3DLOOK
|WB_ALLOWMENUBAR
;
1649 if (extractResizable(rMap
))
1650 nBits
|= WB_SIZEABLE
;
1651 if (extractCloseable(rMap
))
1652 nBits
|= WB_CLOSEABLE
;
1653 Dialog::InitFlag eInit
= !pParent
? Dialog::InitFlag::NoParent
: Dialog::InitFlag::Default
;
1654 if (name
== "GtkAssistant")
1655 xWindow
= VclPtr
<vcl::RoadmapWizard
>::Create(pParent
, nBits
, eInit
);
1657 xWindow
= VclPtr
<Dialog
>::Create(pParent
, nBits
, eInit
);
1658 #if HAVE_FEATURE_DESKTOP
1659 if (!extractModal(rMap
))
1660 xWindow
->SetType(WindowType::MODELESSDIALOG
);
1663 else if (name
== "GtkMessageDialog")
1665 WinBits nBits
= WB_MOVEABLE
|WB_3DLOOK
|WB_CLOSEABLE
;
1666 if (extractResizable(rMap
))
1667 nBits
|= WB_SIZEABLE
;
1668 VclPtr
<MessageDialog
> xDialog(VclPtr
<MessageDialog
>::Create(pParent
, nBits
));
1669 m_pParserState
->m_aMessageDialogs
.push_back(xDialog
);
1672 xWindow
->set_border_width(3);
1674 xWindow
->set_border_width(12);
1677 else if (name
== "GtkBox" || name
== "GtkStatusbar")
1679 bVertical
= extractOrientation(rMap
);
1681 xWindow
= VclPtr
<VclVBox
>::Create(pParent
);
1683 xWindow
= VclPtr
<VclHBox
>::Create(pParent
);
1685 else if (name
== "GtkPaned")
1687 bVertical
= extractOrientation(rMap
);
1689 xWindow
= VclPtr
<VclVPaned
>::Create(pParent
);
1691 xWindow
= VclPtr
<VclHPaned
>::Create(pParent
);
1693 else if (name
== "GtkHBox")
1694 xWindow
= VclPtr
<VclHBox
>::Create(pParent
);
1695 else if (name
== "GtkVBox")
1696 xWindow
= VclPtr
<VclVBox
>::Create(pParent
);
1697 else if (name
== "GtkButtonBox")
1699 bVertical
= extractOrientation(rMap
);
1701 xWindow
= VclPtr
<VclVButtonBox
>::Create(pParent
);
1703 xWindow
= VclPtr
<VclHButtonBox
>::Create(pParent
);
1705 else if (name
== "GtkHButtonBox")
1706 xWindow
= VclPtr
<VclHButtonBox
>::Create(pParent
);
1707 else if (name
== "GtkVButtonBox")
1708 xWindow
= VclPtr
<VclVButtonBox
>::Create(pParent
);
1709 else if (name
== "GtkGrid")
1710 xWindow
= VclPtr
<VclGrid
>::Create(pParent
);
1711 else if (name
== "GtkFrame")
1712 xWindow
= VclPtr
<VclFrame
>::Create(pParent
);
1713 else if (name
== "GtkExpander")
1715 VclPtrInstance
<VclExpander
> pExpander(pParent
);
1716 m_pParserState
->m_aExpanderWidgets
.push_back(pExpander
);
1717 xWindow
= pExpander
;
1719 else if (name
== "GtkButton" || (!m_bLegacy
&& name
== "GtkToggleButton"))
1721 VclPtr
<Button
> xButton
;
1722 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
1723 if (sMenu
.isEmpty())
1724 xButton
= extractStockAndBuildPushButton(pParent
, rMap
, name
== "GtkToggleButton");
1727 assert(m_bLegacy
&& "use GtkMenuButton");
1728 xButton
= extractStockAndBuildMenuButton(pParent
, rMap
);
1729 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1731 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1732 setupFromActionName(xButton
, rMap
, m_xFrame
);
1735 else if (name
== "GtkMenuButton")
1737 VclPtr
<MenuButton
> xButton
;
1739 OUString sMenu
= extractPopupMenu(rMap
);
1740 if (!sMenu
.isEmpty())
1741 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1743 OUString sType
= extractWidgetName(rMap
);
1744 if (sType
.isEmpty())
1746 xButton
= extractStockAndBuildMenuButton(pParent
, rMap
);
1747 xButton
->SetAccessibleRole(css::accessibility::AccessibleRole::BUTTON_MENU
);
1751 xButton
= extractStockAndBuildMenuToggleButton(pParent
, rMap
);
1754 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1756 if (!extractDrawIndicator(rMap
))
1757 xButton
->SetDropDown(PushButtonDropdownStyle::NONE
);
1759 setupFromActionName(xButton
, rMap
, m_xFrame
);
1762 else if (name
== "GtkToggleButton" && m_bLegacy
)
1764 VclPtr
<Button
> xButton
;
1765 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
1766 assert(sMenu
.getLength() && "not implemented yet");
1767 xButton
= extractStockAndBuildMenuToggleButton(pParent
, rMap
);
1768 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1769 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1770 setupFromActionName(xButton
, rMap
, m_xFrame
);
1773 else if (name
== "GtkRadioButton")
1775 extractGroup(id
, rMap
);
1776 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1777 VclPtr
<RadioButton
> xButton
= VclPtr
<RadioButton
>::Create(pParent
, true, nBits
);
1778 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1781 else if (name
== "GtkCheckButton")
1783 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1784 bool bIsTriState
= extractInconsistent(rMap
);
1785 VclPtr
<CheckBox
> xCheckBox
= VclPtr
<CheckBox
>::Create(pParent
, nBits
);
1788 xCheckBox
->EnableTriState(true);
1789 xCheckBox
->SetState(TRISTATE_INDET
);
1791 xCheckBox
->SetImageAlign(ImageAlign::Left
); //default to left
1793 xWindow
= xCheckBox
;
1795 else if (name
== "GtkSpinButton")
1797 OUString sAdjustment
= extractAdjustment(rMap
);
1799 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_3DLOOK
|WB_SPIN
|WB_REPEAT
;
1800 if (extractHasFrame(rMap
))
1803 connectFormattedFormatterAdjustment(id
, sAdjustment
);
1804 VclPtrInstance
<FormattedField
> xField(pParent
, nBits
);
1805 xField
->GetFormatter().SetMinValue(0);
1808 else if (name
== "GtkLinkButton")
1809 xWindow
= VclPtr
<FixedHyperlink
>::Create(pParent
, WB_CENTER
|WB_VCENTER
|WB_3DLOOK
|WB_NOLABEL
);
1810 else if (name
== "GtkComboBox" || name
== "GtkComboBoxText")
1812 extractModel(id
, rMap
);
1814 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1816 bool bDropdown
= BuilderUtils::extractDropdown(rMap
);
1819 nBits
|= WB_DROPDOWN
;
1821 if (extractEntry(rMap
))
1823 VclPtrInstance
<ComboBox
> xComboBox(pParent
, nBits
);
1824 xComboBox
->EnableAutoSize(true);
1825 xWindow
= xComboBox
;
1829 VclPtrInstance
<ListBox
> xListBox(pParent
, nBits
|WB_SIMPLEMODE
);
1830 xListBox
->EnableAutoSize(true);
1834 else if (name
== "VclOptionalBox" || name
== "sfxlo-OptionalBox")
1836 // tdf#135495 fallback sfxlo-OptionalBox to VclOptionalBox as a stopgap
1837 xWindow
= VclPtr
<OptionalBox
>::Create(pParent
);
1839 else if (name
== "svtlo-ManagedMenuButton")
1841 // like tdf#135495 keep the name svtlo-ManagedMenuButton even though it's a misnomer
1842 // and is not dlsymed from the svt library
1843 xWindow
= VclPtr
<ManagedMenuButton
>::Create(pParent
, WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_FLATBUTTON
);
1844 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
1845 if (!sMenu
.isEmpty())
1846 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1847 setupFromActionName(static_cast<Button
*>(xWindow
.get()), rMap
, m_xFrame
);
1849 else if (name
== "sfxlo-PriorityMergedHBox")
1851 // like tdf#135495 above, keep the sfxlo-PriorityMergedHBox even though its not in sfx anymore
1852 xWindow
= VclPtr
<PriorityMergedHBox
>::Create(pParent
);
1854 else if (name
== "sfxlo-PriorityHBox")
1856 // like tdf#135495 above, keep the sfxlo-PriorityMergedHBox even though its not in sfx anymore
1857 xWindow
= VclPtr
<PriorityHBox
>::Create(pParent
);
1859 else if (name
== "sfxlo-DropdownBox")
1861 // like tdf#135495 above, keep the sfxlo-PriorityMergedHBox even though its not in sfx anymore
1862 xWindow
= VclPtr
<DropdownBox
>::Create(pParent
);
1864 else if (name
== "sfxlo-ContextVBox")
1866 // like tdf#135495 above, keep the sfxlo-PriorityMergedHBox even though its not in sfx anymore
1867 xWindow
= VclPtr
<ContextVBox
>::Create(pParent
);
1869 else if (name
== "GtkIconView")
1871 assert(rMap
.find("model") != rMap
.end() && "GtkIconView must have a model");
1873 //window we want to apply the packing props for this GtkIconView to
1874 VclPtr
<vcl::Window
> xWindowForPackingProps
;
1875 extractModel(id
, rMap
);
1876 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1877 //IconView manages its own scrolling,
1878 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
1880 VclPtr
<IconView
> xBox
= VclPtr
<IconView
>::Create(pRealParent
, nWinStyle
);
1881 xWindowForPackingProps
= xBox
;
1884 xBox
->SetNoAutoCurEntry(true);
1885 xBox
->SetQuickSearch(true);
1887 if (pRealParent
!= pParent
)
1888 cleanupWidgetOwnScrolling(pParent
, xWindowForPackingProps
, rMap
);
1890 else if (name
== "GtkTreeView")
1894 assert(rMap
.find("model") != rMap
.end() && "GtkTreeView must have a model");
1897 //window we want to apply the packing props for this GtkTreeView to
1898 VclPtr
<vcl::Window
> xWindowForPackingProps
;
1900 //a) make SvHeaderTabListBox/SvTabListBox the default target for GtkTreeView
1901 //b) remove the non-drop down mode of ListBox and convert
1902 // everything over to SvHeaderTabListBox/SvTabListBox
1903 extractModel(id
, rMap
);
1904 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1907 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
1908 if (!sBorder
.isEmpty())
1909 nWinStyle
|= WB_BORDER
;
1913 nWinStyle
|= WB_HASBUTTONS
| WB_HASBUTTONSATROOT
;
1915 //ListBox/SvHeaderTabListBox manages its own scrolling,
1916 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
1919 xWindow
= VclPtr
<ListBox
>::Create(pRealParent
, nWinStyle
| WB_SIMPLEMODE
);
1920 xWindowForPackingProps
= xWindow
;
1924 VclPtr
<SvTabListBox
> xBox
;
1925 bool bHeadersVisible
= extractHeadersVisible(rMap
);
1926 if (bHeadersVisible
)
1928 VclPtr
<VclVBox
> xContainer
= VclPtr
<VclVBox
>::Create(pRealParent
);
1929 OUString
containerid(id
+ "-container");
1930 xContainer
->SetHelpId(m_sHelpRoot
+ containerid
);
1931 m_aChildren
.emplace_back(containerid
, xContainer
, true);
1933 VclPtrInstance
<HeaderBar
> xHeader(xContainer
, WB_BUTTONSTYLE
| WB_BORDER
| WB_TABSTOP
| WB_3DLOOK
);
1934 xHeader
->set_width_request(0); // let the headerbar width not affect the size request
1935 OUString
headerid(id
+ "-header");
1936 xHeader
->SetHelpId(m_sHelpRoot
+ headerid
);
1937 m_aChildren
.emplace_back(headerid
, xHeader
, true);
1939 VclPtr
<LclHeaderTabListBox
> xHeaderBox
= VclPtr
<LclHeaderTabListBox
>::Create(xContainer
, nWinStyle
);
1940 xHeaderBox
->InitHeaderBar(xHeader
);
1941 xContainer
->set_expand(true);
1945 xWindowForPackingProps
= xContainer
;
1949 xBox
= VclPtr
<LclTabListBox
>::Create(pRealParent
, nWinStyle
);
1950 xWindowForPackingProps
= xBox
;
1953 xBox
->SetNoAutoCurEntry(true);
1954 xBox
->SetQuickSearch(true);
1955 xBox
->SetSpaceBetweenEntries(3);
1956 xBox
->SetEntryHeight(16);
1957 xBox
->SetHighlightRange(); // select over the whole width
1959 if (pRealParent
!= pParent
)
1960 cleanupWidgetOwnScrolling(pParent
, xWindowForPackingProps
, rMap
);
1962 else if (name
== "GtkTreeViewColumn")
1966 SvHeaderTabListBox
* pTreeView
= dynamic_cast<SvHeaderTabListBox
*>(pParent
);
1967 if (HeaderBar
* pHeaderBar
= pTreeView
? pTreeView
->GetHeaderBar() : nullptr)
1969 HeaderBarItemBits nBits
= HeaderBarItemBits::LEFTIMAGE
;
1970 if (extractClickable(rMap
))
1971 nBits
|= HeaderBarItemBits::CLICKABLE
;
1972 if (extractSortIndicator(rMap
))
1973 nBits
|= HeaderBarItemBits::DOWNARROW
;
1974 float fAlign
= extractAlignment(rMap
);
1976 nBits
|= HeaderBarItemBits::LEFT
;
1977 else if (fAlign
== 1.0)
1978 nBits
|= HeaderBarItemBits::RIGHT
;
1979 else if (fAlign
== 0.5)
1980 nBits
|= HeaderBarItemBits::CENTER
;
1981 auto nItemId
= pHeaderBar
->GetItemCount() + 1;
1982 OUString
sTitle(extractTitle(rMap
));
1983 pHeaderBar
->InsertItem(nItemId
, sTitle
, 100, nBits
);
1987 else if (name
== "GtkLabel")
1989 WinBits nWinStyle
= WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1990 extractMnemonicWidget(id
, rMap
);
1991 if (extractSelectable(rMap
))
1992 xWindow
= VclPtr
<SelectableFixedText
>::Create(pParent
, nWinStyle
);
1994 xWindow
= VclPtr
<FixedText
>::Create(pParent
, nWinStyle
);
1996 else if (name
== "GtkImage")
1998 VclPtr
<FixedImage
> xFixedImage
= VclPtr
<FixedImage
>::Create(pParent
, WB_CENTER
|WB_VCENTER
|WB_3DLOOK
|WB_SCALE
);
1999 OUString sIconName
= extractIconName(rMap
);
2000 if (!sIconName
.isEmpty())
2001 xFixedImage
->SetImage(FixedImage::loadThemeImage(sIconName
));
2002 m_pParserState
->m_aImageSizeMap
[id
] = getImageSize(rMap
);
2003 xWindow
= xFixedImage
;
2004 //such parentless GtkImages are temps used to set icons on buttons
2005 //default them to hidden to stop e.g. insert->index entry flicking temp
2006 //full screen windows
2009 rMap
["visible"] = "false";
2012 else if (name
== "GtkSeparator")
2014 bVertical
= extractOrientation(rMap
);
2015 xWindow
= VclPtr
<FixedLine
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2017 else if (name
== "GtkScrollbar")
2019 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aScrollAdjustmentMaps
);
2020 bVertical
= extractOrientation(rMap
);
2021 xWindow
= VclPtr
<ScrollBar
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2023 else if (name
== "GtkProgressBar")
2025 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aScrollAdjustmentMaps
);
2026 bVertical
= extractOrientation(rMap
);
2027 xWindow
= VclPtr
<ProgressBar
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2029 else if (name
== "GtkScrolledWindow")
2031 xWindow
= VclPtr
<VclScrolledWindow
>::Create(pParent
);
2033 else if (name
== "GtkViewport")
2035 xWindow
= VclPtr
<VclViewport
>::Create(pParent
);
2037 else if (name
== "GtkEventBox")
2039 xWindow
= VclPtr
<VclEventBox
>::Create(pParent
);
2041 else if (name
== "GtkEntry")
2043 WinBits nWinStyle
= WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
2044 if (extractHasFrame(rMap
))
2045 nWinStyle
|= WB_BORDER
;
2046 xWindow
= VclPtr
<Edit
>::Create(pParent
, nWinStyle
);
2047 BuilderUtils::ensureDefaultWidthChars(rMap
);
2049 else if (name
== "GtkNotebook")
2051 if (!extractVerticalTabPos(rMap
))
2052 xWindow
= VclPtr
<TabControl
>::Create(pParent
, WB_STDTABCONTROL
|WB_3DLOOK
);
2054 xWindow
= VclPtr
<VerticalTabControl
>::Create(pParent
);
2056 else if (name
== "GtkDrawingArea")
2058 xWindow
= VclPtr
<VclDrawingArea
>::Create(pParent
, WB_TABSTOP
);
2060 else if (name
== "GtkTextView")
2062 extractBuffer(id
, rMap
);
2064 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
;
2065 //VclMultiLineEdit manages its own scrolling,
2066 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
2067 xWindow
= VclPtr
<VclMultiLineEdit
>::Create(pRealParent
, nWinStyle
);
2068 if (pRealParent
!= pParent
)
2069 cleanupWidgetOwnScrolling(pParent
, xWindow
, rMap
);
2071 else if (name
== "GtkSpinner")
2073 xWindow
= VclPtr
<Throbber
>::Create(pParent
, WB_3DLOOK
);
2075 else if (name
== "GtkScale")
2077 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aSliderAdjustmentMaps
);
2078 bool bDrawValue
= extractDrawValue(rMap
);
2081 OUString sValuePos
= extractValuePos(rMap
);
2084 bVertical
= extractOrientation(rMap
);
2086 WinBits nWinStyle
= bVertical
? WB_VERT
: WB_HORZ
;
2088 xWindow
= VclPtr
<Slider
>::Create(pParent
, nWinStyle
);
2090 else if (name
== "GtkToolbar")
2092 xWindow
= VclPtr
<ToolBox
>::Create(pParent
, WB_3DLOOK
| WB_TABSTOP
);
2094 else if(name
== "NotebookBarAddonsToolMergePoint")
2096 customMakeWidget pFunction
= GetCustomMakeWidget("sfxlo-NotebookbarToolBox");
2097 if(pFunction
!= nullptr)
2098 NotebookBarAddonsMerger::MergeNotebookBarAddons(pParent
, pFunction
, m_xFrame
, *m_pNotebookBarAddonsItem
, rMap
);
2101 else if (name
== "GtkToolButton" || name
== "GtkMenuToolButton" ||
2102 name
== "GtkToggleToolButton" || name
== "GtkRadioToolButton" || name
== "GtkToolItem")
2106 OUString
aCommand(extractActionName(rMap
));
2108 ToolBoxItemId
nItemId(0);
2109 ToolBoxItemBits nBits
= ToolBoxItemBits::NONE
;
2110 if (name
== "GtkMenuToolButton")
2111 nBits
|= ToolBoxItemBits::DROPDOWN
;
2112 else if (name
== "GtkToggleToolButton")
2113 nBits
|= ToolBoxItemBits::AUTOCHECK
| ToolBoxItemBits::CHECKABLE
;
2114 else if (name
== "GtkRadioToolButton")
2115 nBits
|= ToolBoxItemBits::AUTOCHECK
| ToolBoxItemBits::RADIOCHECK
;
2117 if (!aCommand
.isEmpty() && m_xFrame
.is())
2119 pToolBox
->InsertItem(aCommand
, m_xFrame
, nBits
, extractSizeRequest(rMap
));
2120 nItemId
= pToolBox
->GetItemId(aCommand
);
2124 nItemId
= ToolBoxItemId(pToolBox
->GetItemCount() + 1);
2125 //TODO: ImplToolItems::size_type -> sal_uInt16!
2126 if (aCommand
.isEmpty() && !m_bLegacy
)
2128 pToolBox
->InsertItem(nItemId
, extractLabel(rMap
), aCommand
, nBits
);
2131 pToolBox
->SetHelpId(nItemId
, m_sHelpRoot
+ id
);
2132 OUString
sTooltip(extractTooltipText(rMap
));
2133 if (!sTooltip
.isEmpty())
2134 pToolBox
->SetQuickHelpText(nItemId
, sTooltip
);
2136 OUString
sIconName(extractIconName(rMap
));
2137 if (!sIconName
.isEmpty())
2138 pToolBox
->SetItemImage(nItemId
, FixedImage::loadThemeImage(sIconName
));
2140 if (!extractVisible(rMap
))
2141 pToolBox
->HideItem(nItemId
);
2143 m_pParserState
->m_nLastToolbarId
= nItemId
;
2145 return nullptr; // no widget to be created
2148 else if (name
== "GtkSeparatorToolItem")
2152 pToolBox
->InsertSeparator();
2153 return nullptr; // no widget to be created
2156 else if (name
== "GtkWindow")
2158 WinBits nBits
= extractDeferredBits(rMap
);
2159 if (nBits
& WB_DOCKABLE
)
2160 xWindow
= VclPtr
<DockingWindow
>::Create(pParent
, nBits
|WB_MOVEABLE
);
2162 xWindow
= VclPtr
<FloatingWindow
>::Create(pParent
, nBits
|WB_MOVEABLE
);
2164 else if (name
== "GtkPopover")
2166 WinBits nBits
= extractDeferredBits(rMap
);
2167 xWindow
= VclPtr
<DockingWindow
>::Create(pParent
, nBits
|WB_DOCKABLE
|WB_MOVEABLE
);
2169 else if (name
== "GtkCalendar")
2171 WinBits nBits
= extractDeferredBits(rMap
);
2172 xWindow
= VclPtr
<Calendar
>::Create(pParent
, nBits
);
2176 if (customMakeWidget pFunction
= GetCustomMakeWidget(name
))
2178 pFunction(xWindow
, pParent
, rMap
);
2179 if (xWindow
->GetType() == WindowType::PUSHBUTTON
)
2180 setupFromActionName(static_cast<Button
*>(xWindow
.get()), rMap
, m_xFrame
);
2181 else if (xWindow
->GetType() == WindowType::MENUBUTTON
)
2183 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
2184 if (!sMenu
.isEmpty())
2185 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
2186 setupFromActionName(static_cast<Button
*>(xWindow
.get()), rMap
, m_xFrame
);
2191 SAL_INFO_IF(!xWindow
, "vcl.builder", "probably need to implement " << name
<< " or add a make" << name
<< " function");
2194 // child windows of disabled windows are made disabled by vcl by default, we don't want that
2195 WindowImpl
*pWindowImpl
= xWindow
->ImplGetWindowImpl();
2196 pWindowImpl
->mbDisabled
= false;
2198 xWindow
->SetHelpId(m_sHelpRoot
+ id
);
2199 SAL_INFO("vcl.builder", "for name '" << name
<< "' and id '" << id
<<
2200 "', created " << xWindow
.get() << " child of " <<
2201 pParent
<< "(" << xWindow
->ImplGetWindowImpl()->mpParent
.get() << "/" <<
2202 xWindow
->ImplGetWindowImpl()->mpRealParent
.get() << "/" <<
2203 xWindow
->ImplGetWindowImpl()->mpBorderWindow
.get() << ") with helpid " <<
2204 xWindow
->GetHelpId());
2205 m_aChildren
.emplace_back(id
, xWindow
, bVertical
);
2207 // if the parent was a toolbox set it as an itemwindow for the latest itemid
2210 Size
aSize(xWindow
->GetSizePixel());
2211 aSize
.setHeight(xWindow
->get_preferred_size().Height());
2212 xWindow
->SetSizePixel(aSize
);
2213 pToolBox
->SetItemWindow(m_pParserState
->m_nLastToolbarId
, xWindow
);
2214 pToolBox
->SetItemExpand(m_pParserState
->m_nLastToolbarId
, true);
2222 //return true for window types which exist in vcl but are not themselves
2223 //represented in the .ui format, i.e. only their children exist.
2224 bool isConsideredGtkPseudo(vcl::Window
const *pWindow
)
2226 return pWindow
->GetType() == WindowType::TABPAGE
;
2230 //Any properties from .ui load we couldn't set because of potential virtual methods
2231 //during ctor are applied here
2232 void VclBuilder::setDeferredProperties()
2234 if (!m_bToplevelHasDeferredProperties
)
2236 stringmap aDeferredProperties
;
2237 aDeferredProperties
.swap(m_aDeferredProperties
);
2238 m_bToplevelHasDeferredProperties
= false;
2239 BuilderUtils::set_properties(m_pParent
, aDeferredProperties
);
2242 namespace BuilderUtils
2244 void set_properties(vcl::Window
*pWindow
, const VclBuilder::stringmap
&rProps
)
2246 for (auto const& [rKey
, rValue
] : rProps
)
2247 pWindow
->set_property(rKey
, rValue
);
2250 OUString
convertMnemonicMarkup(std::u16string_view rIn
)
2252 OUStringBuffer
aRet(rIn
);
2253 for (sal_Int32 nI
= 0; nI
< aRet
.getLength(); ++nI
)
2255 if (aRet
[nI
] == '_' && nI
+1 < aRet
.getLength())
2257 if (aRet
[nI
+1] != '_')
2258 aRet
[nI
] = MNEMONIC_CHAR
;
2264 return aRet
.makeStringAndClear();
2267 OUString
extractCustomProperty(VclBuilder::stringmap
&rMap
)
2269 OUString sCustomProperty
;
2270 VclBuilder::stringmap::iterator aFind
= rMap
.find("customproperty");
2271 if (aFind
!= rMap
.end())
2273 sCustomProperty
= aFind
->second
;
2276 return sCustomProperty
;
2279 void ensureDefaultWidthChars(VclBuilder::stringmap
&rMap
)
2281 OUString
sWidthChars("width-chars");
2282 VclBuilder::stringmap::iterator aFind
= rMap
.find(sWidthChars
);
2283 if (aFind
== rMap
.end())
2284 rMap
[sWidthChars
] = "20";
2287 bool extractDropdown(VclBuilder::stringmap
&rMap
)
2289 bool bDropdown
= true;
2290 VclBuilder::stringmap::iterator aFind
= rMap
.find("dropdown");
2291 if (aFind
!= rMap
.end())
2293 bDropdown
= toBool(aFind
->second
);
2299 void reorderWithinParent(vcl::Window
&rWindow
, sal_uInt16 nNewPosition
)
2301 WindowImpl
*pWindowImpl
= rWindow
.ImplGetWindowImpl();
2302 if (pWindowImpl
->mpParent
!= pWindowImpl
->mpRealParent
)
2304 assert(pWindowImpl
->mpBorderWindow
== pWindowImpl
->mpParent
);
2305 assert(pWindowImpl
->mpBorderWindow
->ImplGetWindowImpl()->mpParent
== pWindowImpl
->mpRealParent
);
2306 reorderWithinParent(*pWindowImpl
->mpBorderWindow
, nNewPosition
);
2309 rWindow
.reorderWithinParent(nNewPosition
);
2312 void reorderWithinParent(std::vector
<vcl::Window
*>& rChilds
, bool bIsButtonBox
)
2314 for (size_t i
= 0; i
< rChilds
.size(); ++i
)
2316 reorderWithinParent(*rChilds
[i
], i
);
2321 //The first member of the group for legacy code needs WB_GROUP set and the
2323 WinBits nBits
= rChilds
[i
]->GetStyle();
2327 rChilds
[i
]->SetStyle(nBits
);
2331 sal_Int16
getRoleFromName(const OUString
& roleName
)
2333 using namespace com::sun::star::accessibility
;
2335 static const std::unordered_map
<OUString
, sal_Int16
> aAtkRoleToAccessibleRole
= {
2336 /* This is in atkobject.h's AtkRole order */
2337 { "invalid", AccessibleRole::UNKNOWN
},
2338 { "accelerator label", AccessibleRole::UNKNOWN
},
2339 { "alert", AccessibleRole::ALERT
},
2340 { "animation", AccessibleRole::UNKNOWN
},
2341 { "arrow", AccessibleRole::UNKNOWN
},
2342 { "calendar", AccessibleRole::UNKNOWN
},
2343 { "canvas", AccessibleRole::CANVAS
},
2344 { "check box", AccessibleRole::CHECK_BOX
},
2345 { "check menu item", AccessibleRole::CHECK_MENU_ITEM
},
2346 { "color chooser", AccessibleRole::COLOR_CHOOSER
},
2347 { "column header", AccessibleRole::COLUMN_HEADER
},
2348 { "combo box", AccessibleRole::COMBO_BOX
},
2349 { "date editor", AccessibleRole::DATE_EDITOR
},
2350 { "desktop icon", AccessibleRole::DESKTOP_ICON
},
2351 { "desktop frame", AccessibleRole::DESKTOP_PANE
}, // ?
2352 { "dial", AccessibleRole::UNKNOWN
},
2353 { "dialog", AccessibleRole::DIALOG
},
2354 { "directory pane", AccessibleRole::DIRECTORY_PANE
},
2355 { "drawing area", AccessibleRole::UNKNOWN
},
2356 { "file chooser", AccessibleRole::FILE_CHOOSER
},
2357 { "filler", AccessibleRole::FILLER
},
2358 { "font chooser", AccessibleRole::FONT_CHOOSER
},
2359 { "frame", AccessibleRole::FRAME
},
2360 { "glass pane", AccessibleRole::GLASS_PANE
},
2361 { "html container", AccessibleRole::UNKNOWN
},
2362 { "icon", AccessibleRole::ICON
},
2363 { "image", AccessibleRole::GRAPHIC
},
2364 { "internal frame", AccessibleRole::INTERNAL_FRAME
},
2365 { "label", AccessibleRole::LABEL
},
2366 { "layered pane", AccessibleRole::LAYERED_PANE
},
2367 { "list", AccessibleRole::LIST
},
2368 { "list item", AccessibleRole::LIST_ITEM
},
2369 { "menu", AccessibleRole::MENU
},
2370 { "menu bar", AccessibleRole::MENU_BAR
},
2371 { "menu item", AccessibleRole::MENU_ITEM
},
2372 { "option pane", AccessibleRole::OPTION_PANE
},
2373 { "page tab", AccessibleRole::PAGE_TAB
},
2374 { "page tab list", AccessibleRole::PAGE_TAB_LIST
},
2375 { "panel", AccessibleRole::PANEL
}, // or SHAPE or TEXT_FRAME ?
2376 { "password text", AccessibleRole::PASSWORD_TEXT
},
2377 { "popup menu", AccessibleRole::POPUP_MENU
},
2378 { "progress bar", AccessibleRole::PROGRESS_BAR
},
2379 { "push button", AccessibleRole::PUSH_BUTTON
}, // or BUTTON_DROPDOWN or BUTTON_MENU
2380 { "radio button", AccessibleRole::RADIO_BUTTON
},
2381 { "radio menu item", AccessibleRole::RADIO_MENU_ITEM
},
2382 { "root pane", AccessibleRole::ROOT_PANE
},
2383 { "row header", AccessibleRole::ROW_HEADER
},
2384 { "scroll bar", AccessibleRole::SCROLL_BAR
},
2385 { "scroll pane", AccessibleRole::SCROLL_PANE
},
2386 { "separator", AccessibleRole::SEPARATOR
},
2387 { "slider", AccessibleRole::SLIDER
},
2388 { "split pane", AccessibleRole::SPLIT_PANE
},
2389 { "spin button", AccessibleRole::SPIN_BOX
}, // ?
2390 { "statusbar", AccessibleRole::STATUS_BAR
},
2391 { "table", AccessibleRole::TABLE
},
2392 { "table cell", AccessibleRole::TABLE_CELL
},
2393 { "table column header", AccessibleRole::COLUMN_HEADER
}, // approximate
2394 { "table row header", AccessibleRole::ROW_HEADER
}, // approximate
2395 { "tear off menu item", AccessibleRole::UNKNOWN
},
2396 { "terminal", AccessibleRole::UNKNOWN
},
2397 { "text", AccessibleRole::TEXT
},
2398 { "toggle button", AccessibleRole::TOGGLE_BUTTON
},
2399 { "tool bar", AccessibleRole::TOOL_BAR
},
2400 { "tool tip", AccessibleRole::TOOL_TIP
},
2401 { "tree", AccessibleRole::TREE
},
2402 { "tree table", AccessibleRole::TREE_TABLE
},
2403 { "unknown", AccessibleRole::UNKNOWN
},
2404 { "viewport", AccessibleRole::VIEW_PORT
},
2405 { "window", AccessibleRole::WINDOW
},
2406 { "header", AccessibleRole::HEADER
},
2407 { "footer", AccessibleRole::FOOTER
},
2408 { "paragraph", AccessibleRole::PARAGRAPH
},
2409 { "ruler", AccessibleRole::RULER
},
2410 { "application", AccessibleRole::UNKNOWN
},
2411 { "autocomplete", AccessibleRole::UNKNOWN
},
2412 { "edit bar", AccessibleRole::EDIT_BAR
},
2413 { "embedded", AccessibleRole::EMBEDDED_OBJECT
},
2414 { "entry", AccessibleRole::UNKNOWN
},
2415 { "chart", AccessibleRole::CHART
},
2416 { "caption", AccessibleRole::CAPTION
},
2417 { "document frame", AccessibleRole::DOCUMENT
},
2418 { "heading", AccessibleRole::HEADING
},
2419 { "page", AccessibleRole::PAGE
},
2420 { "section", AccessibleRole::SECTION
},
2421 { "redundant object", AccessibleRole::UNKNOWN
},
2422 { "form", AccessibleRole::FORM
},
2423 { "link", AccessibleRole::HYPER_LINK
},
2424 { "input method window", AccessibleRole::UNKNOWN
},
2425 { "table row", AccessibleRole::UNKNOWN
},
2426 { "tree item", AccessibleRole::TREE_ITEM
},
2427 { "document spreadsheet", AccessibleRole::DOCUMENT_SPREADSHEET
},
2428 { "document presentation", AccessibleRole::DOCUMENT_PRESENTATION
},
2429 { "document text", AccessibleRole::DOCUMENT_TEXT
},
2430 { "document web", AccessibleRole::DOCUMENT
}, // approximate
2431 { "document email", AccessibleRole::DOCUMENT
}, // approximate
2432 { "comment", AccessibleRole::COMMENT
}, // or NOTE or END_NOTE or FOOTNOTE or SCROLL_PANE
2433 { "list box", AccessibleRole::UNKNOWN
},
2434 { "grouping", AccessibleRole::GROUP_BOX
},
2435 { "image map", AccessibleRole::IMAGE_MAP
},
2436 { "notification", AccessibleRole::NOTIFICATION
},
2437 { "info bar", AccessibleRole::UNKNOWN
},
2438 { "level bar", AccessibleRole::UNKNOWN
},
2439 { "title bar", AccessibleRole::UNKNOWN
},
2440 { "block quote", AccessibleRole::UNKNOWN
},
2441 { "audio", AccessibleRole::UNKNOWN
},
2442 { "video", AccessibleRole::UNKNOWN
},
2443 { "definition", AccessibleRole::UNKNOWN
},
2444 { "article", AccessibleRole::UNKNOWN
},
2445 { "landmark", AccessibleRole::UNKNOWN
},
2446 { "log", AccessibleRole::UNKNOWN
},
2447 { "marquee", AccessibleRole::UNKNOWN
},
2448 { "math", AccessibleRole::UNKNOWN
},
2449 { "rating", AccessibleRole::UNKNOWN
},
2450 { "timer", AccessibleRole::UNKNOWN
},
2451 { "description list", AccessibleRole::UNKNOWN
},
2452 { "description term", AccessibleRole::UNKNOWN
},
2453 { "description value", AccessibleRole::UNKNOWN
},
2454 { "static", AccessibleRole::STATIC
},
2455 { "math fraction", AccessibleRole::UNKNOWN
},
2456 { "math root", AccessibleRole::UNKNOWN
},
2457 { "subscript", AccessibleRole::UNKNOWN
},
2458 { "superscript", AccessibleRole::UNKNOWN
},
2459 { "footnote", AccessibleRole::FOOTNOTE
},
2462 auto it
= aAtkRoleToAccessibleRole
.find(roleName
);
2463 if (it
== aAtkRoleToAccessibleRole
.end())
2464 return AccessibleRole::UNKNOWN
;
2469 VclPtr
<vcl::Window
> VclBuilder::insertObject(vcl::Window
*pParent
, const OUString
&rClass
,
2470 const OUString
&rID
, stringmap
&rProps
, stringmap
&rPango
, stringmap
&rAtk
)
2472 VclPtr
<vcl::Window
> pCurrentChild
;
2474 if (m_pParent
&& !isConsideredGtkPseudo(m_pParent
) && !m_sID
.isEmpty() && rID
== m_sID
)
2476 pCurrentChild
= m_pParent
;
2478 //toplevels default to resizable and apparently you can't change them
2479 //afterwards, so we need to wait until now before we can truly
2480 //initialize the dialog.
2481 if (pParent
&& pParent
->IsSystemWindow())
2483 SystemWindow
*pSysWin
= static_cast<SystemWindow
*>(pCurrentChild
.get());
2484 pSysWin
->doDeferredInit(extractDeferredBits(rProps
));
2485 m_bToplevelHasDeferredInit
= false;
2487 else if (pParent
&& pParent
->IsDockingWindow())
2489 DockingWindow
*pDockWin
= static_cast<DockingWindow
*>(pCurrentChild
.get());
2490 pDockWin
->doDeferredInit(extractDeferredBits(rProps
));
2491 m_bToplevelHasDeferredInit
= false;
2494 if (pCurrentChild
->GetHelpId().isEmpty())
2496 pCurrentChild
->SetHelpId(m_sHelpRoot
+ m_sID
);
2497 SAL_INFO("vcl.builder", "for toplevel dialog " << this << " " <<
2498 rID
<< ", set helpid " << pCurrentChild
->GetHelpId());
2500 m_bToplevelParentFound
= true;
2504 //if we're being inserting under a toplevel dialog whose init is
2505 //deferred due to waiting to encounter it in this .ui, and it hasn't
2506 //been seen yet, then make unattached widgets parent-less toplevels
2507 if (pParent
== m_pParent
.get() && m_bToplevelHasDeferredInit
)
2509 pCurrentChild
= makeObject(pParent
, rClass
, rID
, rProps
);
2514 pCurrentChild
->set_id(rID
);
2515 if (pCurrentChild
== m_pParent
.get() && m_bToplevelHasDeferredProperties
)
2516 m_aDeferredProperties
= rProps
;
2518 BuilderUtils::set_properties(pCurrentChild
, rProps
);
2520 // tdf#119827 handle size before scale so we can trivially
2521 // scale on the current font size whether size is present
2523 VclBuilder::stringmap::iterator aSize
= rPango
.find("size");
2524 if (aSize
!= rPango
.end())
2526 pCurrentChild
->set_font_attribute(aSize
->first
, aSize
->second
);
2527 rPango
.erase(aSize
);
2529 for (auto const& [ rKey
, rValue
] : rPango
)
2530 pCurrentChild
->set_font_attribute(rKey
, rValue
);
2532 m_pParserState
->m_aAtkInfo
[pCurrentChild
] = rAtk
;
2541 bool bToolbarParent
= (pParent
&& pParent
->GetType() == WindowType::TOOLBOX
);
2542 pCurrentChild
= (m_aChildren
.empty() || bToolbarParent
) ? pParent
: m_aChildren
.back().m_pWindow
.get();
2544 return pCurrentChild
;
2547 void VclBuilder::handleTabChild(vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
2549 TabControl
*pTabControl
= pParent
&& pParent
->GetType() == WindowType::TABCONTROL
?
2550 static_cast<TabControl
*>(pParent
) : nullptr;
2552 std::vector
<OUString
> sIDs
;
2555 stringmap aProperties
;
2556 stringmap aAtkProperties
;
2557 std::vector
<vcl::EnumContext::Context
> context
;
2561 xmlreader::Span name
;
2564 xmlreader::XmlReader::Result res
= reader
.nextItem(
2565 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
2567 if (res
== xmlreader::XmlReader::Result::Begin
)
2570 if (name
== "object")
2572 while (reader
.nextAttribute(&nsId
, &name
))
2576 name
= reader
.getAttributeValue(false);
2577 OUString
sID(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
2578 sal_Int32 nDelim
= sID
.indexOf(':');
2581 aProperties
["customproperty"] = sID
.copy(nDelim
+ 1);
2582 sID
= sID
.copy(0, nDelim
);
2584 sIDs
.push_back(sID
);
2588 else if (name
== "style")
2591 context
= handleStyle(reader
, nPriority
);
2594 else if (name
== "property")
2595 collectProperty(reader
, aProperties
);
2596 else if (pTabControl
&& name
== "child")
2598 // just to collect the atk properties (if any) for the label
2599 handleChild(nullptr, &aAtkProperties
, reader
);
2604 if (res
== xmlreader::XmlReader::Result::End
)
2610 if (res
== xmlreader::XmlReader::Result::Done
)
2617 VerticalTabControl
*pVerticalTabControl
= pParent
->GetType() == WindowType::VERTICALTABCONTROL
?
2618 static_cast<VerticalTabControl
*>(pParent
) : nullptr;
2619 assert(pTabControl
|| pVerticalTabControl
);
2620 VclBuilder::stringmap::iterator aFind
= aProperties
.find("label");
2621 if (aFind
!= aProperties
.end())
2623 OUString
sTooltip(extractTooltipText(aProperties
));
2626 sal_uInt16 nPageId
= pTabControl
->GetCurPageId();
2627 pTabControl
->SetPageText(nPageId
, aFind
->second
);
2628 pTabControl
->SetPageName(nPageId
, sIDs
.back());
2629 pTabControl
->SetHelpText(nPageId
, sTooltip
);
2630 if (!context
.empty())
2632 TabPage
* pPage
= pTabControl
->GetTabPage(nPageId
);
2633 pPage
->SetContext(std::move(context
));
2636 for (auto const& [ rKey
, rValue
] : aAtkProperties
)
2638 if (rKey
== "AtkObject::accessible-name")
2639 pTabControl
->SetAccessibleName(nPageId
, rValue
);
2640 else if (rKey
== "AtkObject::accessible-description")
2641 pTabControl
->SetAccessibleDescription(nPageId
, rValue
);
2643 SAL_INFO("vcl.builder", "unhandled atk property: " << rKey
);
2649 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(aFind
->second
));
2650 OUString
sIconName(extractIconName(aProperties
));
2651 pVerticalTabControl
->InsertPage(sIDs
.front(), sLabel
, FixedImage::loadThemeImage(sIconName
), sTooltip
,
2652 pVerticalTabControl
->GetPageParent()->GetWindow(GetWindowType::LastChild
));
2658 pTabControl
->RemovePage(pTabControl
->GetCurPageId());
2662 //so that tabbing between controls goes in a visually sensible sequence
2663 //we sort these into a best-tab-order sequence
2664 bool VclBuilder::sortIntoBestTabTraversalOrder::operator()(const vcl::Window
*pA
, const vcl::Window
*pB
) const
2666 //sort child order within parent list by grid position
2667 sal_Int32 nTopA
= pA
->get_grid_top_attach();
2668 sal_Int32 nTopB
= pB
->get_grid_top_attach();
2673 sal_Int32 nLeftA
= pA
->get_grid_left_attach();
2674 sal_Int32 nLeftB
= pB
->get_grid_left_attach();
2675 if (nLeftA
< nLeftB
)
2677 if (nLeftA
> nLeftB
)
2679 //sort into two groups of pack start and pack end
2680 VclPackType ePackA
= pA
->get_pack_type();
2681 VclPackType ePackB
= pB
->get_pack_type();
2682 if (ePackA
< ePackB
)
2684 if (ePackA
> ePackB
)
2686 bool bVerticalContainer
= m_pBuilder
->get_window_packing_data(pA
->GetParent()).m_bVerticalOrient
;
2687 bool bPackA
= pA
->get_secondary();
2688 bool bPackB
= pB
->get_secondary();
2689 if (!bVerticalContainer
)
2691 //for horizontal boxes group secondaries before primaries
2692 if (bPackA
> bPackB
)
2694 if (bPackA
< bPackB
)
2699 //for vertical boxes group secondaries after primaries
2700 if (bPackA
< bPackB
)
2702 if (bPackA
> bPackB
)
2705 //honour relative box positions with pack group, (numerical order is reversed
2706 //for VclPackType::End, they are packed from the end back, but here we need
2707 //them in visual layout order so that tabbing works as expected)
2708 sal_Int32 nPackA
= m_pBuilder
->get_window_packing_data(pA
).m_nPosition
;
2709 sal_Int32 nPackB
= m_pBuilder
->get_window_packing_data(pB
).m_nPosition
;
2710 if (nPackA
< nPackB
)
2711 return ePackA
== VclPackType::Start
;
2712 if (nPackA
> nPackB
)
2713 return ePackA
!= VclPackType::Start
;
2714 //sort labels of Frames before body
2715 if (pA
->GetParent() == pB
->GetParent())
2717 const VclFrame
*pFrameParent
= dynamic_cast<const VclFrame
*>(pA
->GetParent());
2720 const vcl::Window
*pLabel
= pFrameParent
->get_label_widget();
2721 int nFramePosA
= (pA
== pLabel
) ? 0 : 1;
2722 int nFramePosB
= (pB
== pLabel
) ? 0 : 1;
2723 return nFramePosA
< nFramePosB
;
2729 void VclBuilder::handleChild(vcl::Window
*pParent
, stringmap
* pAtkProps
, xmlreader::XmlReader
&reader
)
2731 vcl::Window
*pCurrentChild
= nullptr;
2733 xmlreader::Span name
;
2735 OString sType
, sInternalChild
;
2737 while (reader
.nextAttribute(&nsId
, &name
))
2741 name
= reader
.getAttributeValue(false);
2742 sType
= OString(name
.begin
, name
.length
);
2744 else if (name
== "internal-child")
2746 name
= reader
.getAttributeValue(false);
2747 sInternalChild
= OString(name
.begin
, name
.length
);
2753 handleTabChild(pParent
, reader
);
2760 xmlreader::XmlReader::Result res
= reader
.nextItem(
2761 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
2763 if (res
== xmlreader::XmlReader::Result::Begin
)
2765 if (name
== "object" || name
== "placeholder")
2767 pCurrentChild
= handleObject(pParent
, pAtkProps
, reader
).get();
2769 bool bObjectInserted
= pCurrentChild
&& pParent
!= pCurrentChild
;
2771 if (bObjectInserted
)
2773 //Internal-children default in glade to not having their visible bits set
2774 //even though they are visible (generally anyway)
2775 if (!sInternalChild
.isEmpty())
2776 pCurrentChild
->Show();
2778 //Select the first page if it's a notebook
2779 if (pCurrentChild
->GetType() == WindowType::TABCONTROL
)
2781 TabControl
*pTabControl
= static_cast<TabControl
*>(pCurrentChild
);
2782 pTabControl
->SetCurPageId(pTabControl
->GetPageId(0));
2784 //To-Do add reorder capability to the TabControl
2788 // We want to sort labels before contents of frames
2789 // for keyboard traversal, especially if there
2790 // are multiple widgets using the same mnemonic
2791 if (sType
== "label")
2793 if (VclFrame
*pFrameParent
= dynamic_cast<VclFrame
*>(pParent
))
2794 pFrameParent
->designate_label(pCurrentChild
);
2796 if (sInternalChild
.startsWith("vbox") || sInternalChild
.startsWith("messagedialog-vbox"))
2798 if (Dialog
*pBoxParent
= dynamic_cast<Dialog
*>(pParent
))
2799 pBoxParent
->set_content_area(static_cast<VclBox
*>(pCurrentChild
)); // FIXME-VCLPTR
2801 else if (sInternalChild
.startsWith("action_area") || sInternalChild
.startsWith("messagedialog-action_area"))
2803 vcl::Window
*pContentArea
= pCurrentChild
->GetParent();
2804 if (Dialog
*pBoxParent
= dynamic_cast<Dialog
*>(pContentArea
? pContentArea
->GetParent() : nullptr))
2806 pBoxParent
->set_action_area(static_cast<VclButtonBox
*>(pCurrentChild
)); // FIXME-VCLPTR
2810 bool bIsButtonBox
= dynamic_cast<VclButtonBox
*>(pCurrentChild
) != nullptr;
2812 //To-Do make reorder a virtual in Window, move this foo
2813 //there and see above
2814 std::vector
<vcl::Window
*> aChilds
;
2815 for (vcl::Window
* pChild
= pCurrentChild
->GetWindow(GetWindowType::FirstChild
); pChild
;
2816 pChild
= pChild
->GetWindow(GetWindowType::Next
))
2820 if (PushButton
* pPushButton
= dynamic_cast<PushButton
*>(pChild
))
2821 pPushButton
->setAction(true);
2824 aChilds
.push_back(pChild
);
2827 //sort child order within parent so that tabbing
2828 //between controls goes in a visually sensible sequence
2829 std::stable_sort(aChilds
.begin(), aChilds
.end(), sortIntoBestTabTraversalOrder(this));
2830 BuilderUtils::reorderWithinParent(aChilds
, bIsButtonBox
);
2834 else if (name
== "packing")
2836 handlePacking(pCurrentChild
, pParent
, reader
);
2838 else if (name
== "interface")
2840 while (reader
.nextAttribute(&nsId
, &name
))
2842 if (name
== "domain")
2844 name
= reader
.getAttributeValue(false);
2845 sType
= OString(name
.begin
, name
.length
);
2846 m_pParserState
->m_aResLocale
= Translate::Create(sType
);
2855 if (res
== xmlreader::XmlReader::Result::End
)
2861 if (res
== xmlreader::XmlReader::Result::Done
)
2866 void VclBuilder::collectPangoAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
2868 xmlreader::Span span
;
2874 while (reader
.nextAttribute(&nsId
, &span
))
2878 span
= reader
.getAttributeValue(false);
2879 sProperty
= OUString(span
.begin
, span
.length
, RTL_TEXTENCODING_UTF8
);
2881 else if (span
== "value")
2883 span
= reader
.getAttributeValue(false);
2884 sValue
= OUString(span
.begin
, span
.length
, RTL_TEXTENCODING_UTF8
);
2888 if (!sProperty
.isEmpty())
2889 rMap
[sProperty
] = sValue
;
2892 void VclBuilder::collectAtkRelationAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
2894 xmlreader::Span span
;
2900 while (reader
.nextAttribute(&nsId
, &span
))
2904 span
= reader
.getAttributeValue(false);
2905 sProperty
= OUString(span
.begin
, span
.length
, RTL_TEXTENCODING_UTF8
);
2907 else if (span
== "target")
2909 span
= reader
.getAttributeValue(false);
2910 sValue
= OUString(span
.begin
, span
.length
, RTL_TEXTENCODING_UTF8
);
2911 sal_Int32 nDelim
= sValue
.indexOf(':');
2913 sValue
= sValue
.copy(0, nDelim
);
2917 if (!sProperty
.isEmpty())
2918 rMap
[sProperty
] = sValue
;
2921 void VclBuilder::collectAtkRoleAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
2923 xmlreader::Span span
;
2928 while (reader
.nextAttribute(&nsId
, &span
))
2932 span
= reader
.getAttributeValue(false);
2933 sProperty
= OUString(span
.begin
, span
.length
, RTL_TEXTENCODING_UTF8
);
2937 if (!sProperty
.isEmpty())
2938 rMap
["role"] = sProperty
;
2941 void VclBuilder::handleRow(xmlreader::XmlReader
&reader
, const OUString
&rID
)
2945 ListStore::row aRow
;
2949 xmlreader::Span name
;
2952 xmlreader::XmlReader::Result res
= reader
.nextItem(
2953 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
2955 if (res
== xmlreader::XmlReader::Result::Done
)
2958 if (res
== xmlreader::XmlReader::Result::Begin
)
2963 bool bTranslated
= false;
2967 while (reader
.nextAttribute(&nsId
, &name
))
2971 name
= reader
.getAttributeValue(false);
2972 nId
= OString(name
.begin
, name
.length
).toUInt32();
2974 else if (nId
== 0 && name
== "translatable" && reader
.getAttributeValue(false) == "yes")
2978 else if (name
== "context")
2980 name
= reader
.getAttributeValue(false);
2981 sContext
= OString(name
.begin
, name
.length
);
2985 (void)reader
.nextItem(
2986 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
2988 OString
sValue(name
.begin
, name
.length
);
2989 OUString sFinalValue
;
2992 sFinalValue
= Translate::get(TranslateId
{sContext
.getStr(), sValue
.getStr()}, m_pParserState
->m_aResLocale
);
2995 sFinalValue
= OUString::fromUtf8(sValue
);
2998 if (aRow
.size() < nId
+1)
3000 aRow
[nId
] = sFinalValue
;
3004 if (res
== xmlreader::XmlReader::Result::End
)
3013 m_pParserState
->m_aModels
[rID
].m_aEntries
.push_back(aRow
);
3016 void VclBuilder::handleListStore(xmlreader::XmlReader
&reader
, const OUString
&rID
, std::u16string_view rClass
)
3022 xmlreader::Span name
;
3025 xmlreader::XmlReader::Result res
= reader
.nextItem(
3026 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3028 if (res
== xmlreader::XmlReader::Result::Done
)
3031 if (res
== xmlreader::XmlReader::Result::Begin
)
3035 bool bNotTreeStore
= rClass
!= u
"GtkTreeStore";
3037 handleRow(reader
, rID
);
3038 assert(bNotTreeStore
&& "gtk, as the time of writing, doesn't support data in GtkTreeStore serialization");
3044 if (res
== xmlreader::XmlReader::Result::End
)
3054 VclBuilder::stringmap
VclBuilder::handleAtkObject(xmlreader::XmlReader
&reader
) const
3058 stringmap aProperties
;
3062 xmlreader::Span name
;
3065 xmlreader::XmlReader::Result res
= reader
.nextItem(
3066 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3068 if (res
== xmlreader::XmlReader::Result::Done
)
3071 if (res
== xmlreader::XmlReader::Result::Begin
)
3074 if (name
== "property")
3075 collectProperty(reader
, aProperties
);
3078 if (res
== xmlreader::XmlReader::Result::End
)
3090 void VclBuilder::applyAtkProperties(vcl::Window
*pWindow
, const stringmap
& rProperties
)
3093 for (auto const& [ rKey
, rValue
] : rProperties
)
3095 if (pWindow
&& rKey
.match("AtkObject::"))
3096 pWindow
->set_property(rKey
.copy(RTL_CONSTASCII_LENGTH("AtkObject::")), rValue
);
3098 SAL_WARN("vcl.builder", "unhandled atk prop: " << rKey
);
3102 std::vector
<ComboBoxTextItem
> VclBuilder::handleItems(xmlreader::XmlReader
&reader
) const
3106 std::vector
<ComboBoxTextItem
> aItems
;
3110 xmlreader::Span name
;
3113 xmlreader::XmlReader::Result res
= reader
.nextItem(
3114 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3116 if (res
== xmlreader::XmlReader::Result::Done
)
3119 if (res
== xmlreader::XmlReader::Result::Begin
)
3124 bool bTranslated
= false;
3128 while (reader
.nextAttribute(&nsId
, &name
))
3130 if (name
== "translatable" && reader
.getAttributeValue(false) == "yes")
3134 else if (name
== "context")
3136 name
= reader
.getAttributeValue(false);
3137 sContext
= OString(name
.begin
, name
.length
);
3139 else if (name
== "id")
3141 name
= reader
.getAttributeValue(false);
3142 sId
= OUString(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
3146 (void)reader
.nextItem(
3147 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3149 OString
sValue(name
.begin
, name
.length
);
3150 OUString sFinalValue
;
3153 sFinalValue
= Translate::get(TranslateId
{sContext
.getStr(), sValue
.getStr()}, m_pParserState
->m_aResLocale
);
3156 sFinalValue
= OUString::fromUtf8(sValue
);
3158 if (m_pStringReplace
)
3159 sFinalValue
= (*m_pStringReplace
)(sFinalValue
);
3161 aItems
.emplace_back(sFinalValue
, sId
);
3165 if (res
== xmlreader::XmlReader::Result::End
)
3177 VclPtr
<Menu
> VclBuilder::handleMenu(xmlreader::XmlReader
&reader
, const OUString
&rID
, bool bMenuBar
)
3179 VclPtr
<Menu
> pCurrentMenu
;
3181 pCurrentMenu
= VclPtr
<MenuBar
>::Create();
3183 pCurrentMenu
= VclPtr
<PopupMenu
>::Create();
3185 pCurrentMenu
->set_id(rID
);
3189 stringmap aProperties
;
3193 xmlreader::Span name
;
3196 xmlreader::XmlReader::Result res
= reader
.nextItem(
3197 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3199 if (res
== xmlreader::XmlReader::Result::Done
)
3202 if (res
== xmlreader::XmlReader::Result::Begin
)
3204 if (name
== "child")
3206 handleMenuChild(pCurrentMenu
, reader
);
3211 if (name
== "property")
3212 collectProperty(reader
, aProperties
);
3216 if (res
== xmlreader::XmlReader::Result::End
)
3225 m_aMenus
.emplace_back(rID
, pCurrentMenu
);
3227 return pCurrentMenu
;
3230 void VclBuilder::handleMenuChild(Menu
*pParent
, xmlreader::XmlReader
&reader
)
3232 xmlreader::Span name
;
3238 xmlreader::XmlReader::Result res
= reader
.nextItem(
3239 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3241 if (res
== xmlreader::XmlReader::Result::Begin
)
3243 if (name
== "object" || name
== "placeholder")
3245 handleMenuObject(pParent
, reader
);
3251 if (res
== xmlreader::XmlReader::Result::End
)
3257 if (res
== xmlreader::XmlReader::Result::Done
)
3262 void VclBuilder::handleMenuObject(Menu
*pParent
, xmlreader::XmlReader
&reader
)
3266 OUString sCustomProperty
;
3267 PopupMenu
*pSubMenu
= nullptr;
3269 xmlreader::Span name
;
3272 while (reader
.nextAttribute(&nsId
, &name
))
3274 if (name
== "class")
3276 name
= reader
.getAttributeValue(false);
3277 sClass
= OUString(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
3279 else if (name
== "id")
3281 name
= reader
.getAttributeValue(false);
3282 sID
= OUString(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
3285 sal_Int32 nDelim
= sID
.indexOf(':');
3288 sCustomProperty
= sID
.subView(nDelim
+1);
3289 sID
= sID
.copy(0, nDelim
);
3297 stringmap aProperties
;
3298 stringmap aAtkProperties
;
3299 accelmap aAccelerators
;
3301 if (!sCustomProperty
.isEmpty())
3302 aProperties
["customproperty"] = sCustomProperty
;
3306 xmlreader::XmlReader::Result res
= reader
.nextItem(
3307 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3309 if (res
== xmlreader::XmlReader::Result::Done
)
3312 if (res
== xmlreader::XmlReader::Result::Begin
)
3314 if (name
== "child")
3316 size_t nChildMenuIdx
= m_aMenus
.size();
3317 handleChild(nullptr, &aAtkProperties
, reader
);
3318 bool bSubMenuInserted
= m_aMenus
.size() > nChildMenuIdx
;
3319 if (bSubMenuInserted
)
3320 pSubMenu
= dynamic_cast<PopupMenu
*>(m_aMenus
[nChildMenuIdx
].m_pMenu
.get());
3325 if (name
== "property")
3326 collectProperty(reader
, aProperties
);
3327 else if (name
== "accelerator")
3328 collectAccelerator(reader
, aAccelerators
);
3332 if (res
== xmlreader::XmlReader::Result::End
)
3341 insertMenuObject(pParent
, pSubMenu
, sClass
, sID
, aProperties
, aAtkProperties
, aAccelerators
);
3344 void VclBuilder::handleSizeGroup(xmlreader::XmlReader
&reader
)
3346 m_pParserState
->m_aSizeGroups
.emplace_back();
3347 SizeGroup
&rSizeGroup
= m_pParserState
->m_aSizeGroups
.back();
3353 xmlreader::Span name
;
3356 xmlreader::XmlReader::Result res
= reader
.nextItem(
3357 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3359 if (res
== xmlreader::XmlReader::Result::Done
)
3362 if (res
== xmlreader::XmlReader::Result::Begin
)
3365 if (name
== "widget")
3367 while (reader
.nextAttribute(&nsId
, &name
))
3371 name
= reader
.getAttributeValue(false);
3372 OUString
sWidget(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
3373 sal_Int32 nDelim
= sWidget
.indexOf(':');
3375 sWidget
= sWidget
.copy(0, nDelim
);
3376 rSizeGroup
.m_aWidgets
.push_back(sWidget
);
3382 if (name
== "property")
3383 collectProperty(reader
, rSizeGroup
.m_aProperties
);
3387 if (res
== xmlreader::XmlReader::Result::End
)
3399 vcl::KeyCode
makeKeyCode(const std::pair
<OUString
,OUString
> &rKey
)
3401 bool bShift
= rKey
.second
.indexOf("GDK_SHIFT_MASK") != -1;
3402 bool bMod1
= rKey
.second
.indexOf("GDK_CONTROL_MASK") != -1;
3403 bool bMod2
= rKey
.second
.indexOf("GDK_ALT_MASK") != -1;
3404 bool bMod3
= rKey
.second
.indexOf("GDK_MOD2_MASK") != -1;
3406 if (rKey
.first
== "Insert")
3407 return vcl::KeyCode(KEY_INSERT
, bShift
, bMod1
, bMod2
, bMod3
);
3408 else if (rKey
.first
== "Delete")
3409 return vcl::KeyCode(KEY_DELETE
, bShift
, bMod1
, bMod2
, bMod3
);
3410 else if (rKey
.first
== "Return")
3411 return vcl::KeyCode(KEY_RETURN
, bShift
, bMod1
, bMod2
, bMod3
);
3412 else if (rKey
.first
== "Up")
3413 return vcl::KeyCode(KEY_UP
, bShift
, bMod1
, bMod2
, bMod3
);
3414 else if (rKey
.first
== "Down")
3415 return vcl::KeyCode(KEY_DOWN
, bShift
, bMod1
, bMod2
, bMod3
);
3416 else if (rKey
.first
== "Left")
3417 return vcl::KeyCode(KEY_LEFT
, bShift
, bMod1
, bMod2
, bMod3
);
3418 else if (rKey
.first
== "Right")
3419 return vcl::KeyCode(KEY_RIGHT
, bShift
, bMod1
, bMod2
, bMod3
);
3420 else if (rKey
.first
== "asterisk")
3421 return vcl::KeyCode(KEY_MULTIPLY
, bShift
, bMod1
, bMod2
, bMod3
);
3422 else if (rKey
.first
.getLength() > 1 && rKey
.first
[0] == 'F')
3424 sal_uInt32 nIndex
= o3tl::toUInt32(rKey
.first
.subView(1));
3425 assert(nIndex
>= 1 && nIndex
<= 26);
3426 return vcl::KeyCode(KEY_F1
+ nIndex
- 1, bShift
, bMod1
, bMod2
, bMod3
);
3429 assert (rKey
.first
.getLength() == 1);
3430 sal_Unicode cChar
= rKey
.first
.toChar();
3432 if (cChar
>= 'a' && cChar
<= 'z')
3433 return vcl::KeyCode(KEY_A
+ (cChar
- 'a'), bShift
, bMod1
, bMod2
, bMod3
);
3434 else if (cChar
>= 'A' && cChar
<= 'Z')
3435 return vcl::KeyCode(KEY_A
+ (cChar
- 'A'), bShift
, bMod1
, bMod2
, bMod3
);
3436 else if (cChar
>= '0' && cChar
<= '9')
3437 return vcl::KeyCode(KEY_0
+ (cChar
- 'A'), bShift
, bMod1
, bMod2
, bMod3
);
3439 return vcl::KeyCode(cChar
, bShift
, bMod1
, bMod2
, bMod3
);
3443 void VclBuilder::insertMenuObject(Menu
*pParent
, PopupMenu
*pSubMenu
, const OUString
&rClass
, const OUString
&rID
,
3444 stringmap
&rProps
, stringmap
&rAtkProps
, accelmap
&rAccels
)
3446 sal_uInt16 nOldCount
= pParent
->GetItemCount();
3447 sal_uInt16 nNewId
= ++m_pParserState
->m_nLastMenuItemId
;
3449 if(rClass
== "NotebookBarAddonsMenuMergePoint")
3451 NotebookBarAddonsMerger::MergeNotebookBarMenuAddons(pParent
, nNewId
, rID
, *m_pNotebookBarAddonsItem
);
3452 m_pParserState
->m_nLastMenuItemId
= pParent
->GetItemCount();
3454 else if (rClass
== "GtkMenuItem")
3456 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3457 OUString
aCommand(extractActionName(rProps
));
3458 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::NONE
, rID
);
3459 pParent
->SetItemCommand(nNewId
, aCommand
);
3461 pParent
->SetPopupMenu(nNewId
, pSubMenu
);
3463 else if (rClass
== "GtkCheckMenuItem")
3465 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3466 OUString
aCommand(extractActionName(rProps
));
3467 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::CHECKABLE
, rID
);
3468 pParent
->SetItemCommand(nNewId
, aCommand
);
3470 else if (rClass
== "GtkRadioMenuItem")
3472 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3473 OUString
aCommand(extractActionName(rProps
));
3474 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::AUTOCHECK
| MenuItemBits::RADIOCHECK
, rID
);
3475 pParent
->SetItemCommand(nNewId
, aCommand
);
3477 else if (rClass
== "GtkSeparatorMenuItem")
3479 pParent
->InsertSeparator(rID
);
3482 SAL_WARN_IF(nOldCount
== pParent
->GetItemCount(), "vcl.builder", "probably need to implement " << rClass
);
3484 if (nOldCount
!= pParent
->GetItemCount())
3486 pParent
->SetHelpId(nNewId
, m_sHelpRoot
+ rID
);
3487 if (!extractVisible(rProps
))
3488 pParent
->HideItem(nNewId
);
3490 for (auto const& [ rKey
, rValue
] : rProps
)
3492 if (rKey
== "tooltip-markup")
3493 pParent
->SetTipHelpText(nNewId
, rValue
);
3494 else if (rKey
== "tooltip-text")
3495 pParent
->SetTipHelpText(nNewId
, rValue
);
3497 SAL_INFO("vcl.builder", "unhandled property: " << rKey
);
3500 for (auto const& [ rKey
, rValue
] : rAtkProps
)
3502 if (rKey
== "AtkObject::accessible-name")
3503 pParent
->SetAccessibleName(nNewId
, rValue
);
3504 else if (rKey
== "AtkObject::accessible-description")
3505 pParent
->SetAccessibleDescription(nNewId
, rValue
);
3507 SAL_INFO("vcl.builder", "unhandled atk property: " << rKey
);
3510 for (auto const& [ rSignal
, rValue
] : rAccels
)
3512 if (rSignal
== "activate")
3513 pParent
->SetAccelKey(nNewId
, makeKeyCode(rValue
));
3515 SAL_INFO("vcl.builder", "unhandled accelerator for: " << rSignal
);
3522 /// Insert items to a ComboBox or a ListBox.
3523 /// They have no common ancestor that would have 'InsertEntry()', so use a template.
3524 template<typename T
> static bool insertItems(vcl::Window
*pWindow
, VclBuilder::stringmap
&rMap
,
3525 std::vector
<std::unique_ptr
<OUString
>>& rUserData
,
3526 const std::vector
<ComboBoxTextItem
> &rItems
)
3528 T
*pContainer
= dynamic_cast<T
*>(pWindow
);
3532 sal_uInt16 nActiveId
= extractActive(rMap
);
3533 for (auto const& item
: rItems
)
3535 sal_Int32 nPos
= pContainer
->InsertEntry(item
.m_sItem
);
3536 if (!item
.m_sId
.isEmpty())
3538 rUserData
.emplace_back(std::make_unique
<OUString
>(item
.m_sId
));
3539 pContainer
->SetEntryData(nPos
, rUserData
.back().get());
3542 if (nActiveId
< rItems
.size())
3543 pContainer
->SelectEntryPos(nActiveId
);
3548 VclPtr
<vcl::Window
> VclBuilder::handleObject(vcl::Window
*pParent
, stringmap
*pAtkProps
, xmlreader::XmlReader
&reader
)
3552 OUString sCustomProperty
;
3554 xmlreader::Span name
;
3557 while (reader
.nextAttribute(&nsId
, &name
))
3559 if (name
== "class")
3561 name
= reader
.getAttributeValue(false);
3562 sClass
= OUString(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
3564 else if (name
== "id")
3566 name
= reader
.getAttributeValue(false);
3567 sID
= OUString(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
3570 sal_Int32 nDelim
= sID
.indexOf(':');
3573 sCustomProperty
= sID
.subView(nDelim
+1);
3574 sID
= sID
.copy(0, nDelim
);
3580 if (sClass
== "GtkListStore" || sClass
== "GtkTreeStore")
3582 handleListStore(reader
, sID
, sClass
);
3585 else if (sClass
== "GtkMenu")
3587 handleMenu(reader
, sID
, false);
3590 else if (sClass
== "GtkMenuBar")
3592 VclPtr
<Menu
> xMenu
= handleMenu(reader
, sID
, true);
3593 if (SystemWindow
* pTopLevel
= pParent
? pParent
->GetSystemWindow() : nullptr)
3594 pTopLevel
->SetMenuBar(dynamic_cast<MenuBar
*>(xMenu
.get()));
3597 else if (sClass
== "GtkSizeGroup")
3599 handleSizeGroup(reader
);
3602 else if (sClass
== "AtkObject")
3604 assert((pParent
|| pAtkProps
) && "must have one set");
3605 assert(!(pParent
&& pAtkProps
) && "must not have both");
3606 auto aAtkProperties
= handleAtkObject(reader
);
3608 applyAtkProperties(pParent
, aAtkProperties
);
3610 *pAtkProps
= aAtkProperties
;
3616 stringmap aProperties
, aPangoAttributes
;
3617 stringmap aAtkAttributes
;
3618 std::vector
<ComboBoxTextItem
> aItems
;
3620 if (!sCustomProperty
.isEmpty())
3621 aProperties
["customproperty"] = sCustomProperty
;
3623 VclPtr
<vcl::Window
> pCurrentChild
;
3626 xmlreader::XmlReader::Result res
= reader
.nextItem(
3627 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3629 if (res
== xmlreader::XmlReader::Result::Done
)
3632 if (res
== xmlreader::XmlReader::Result::Begin
)
3634 if (name
== "child")
3638 pCurrentChild
= insertObject(pParent
, sClass
, sID
,
3639 aProperties
, aPangoAttributes
, aAtkAttributes
);
3641 handleChild(pCurrentChild
, nullptr, reader
);
3643 else if (name
== "items")
3644 aItems
= handleItems(reader
);
3645 else if (name
== "style")
3648 std::vector
<vcl::EnumContext::Context
> aContext
= handleStyle(reader
, nPriority
);
3651 vcl::IPrioritable
* pPrioritable
= dynamic_cast<vcl::IPrioritable
*>(pCurrentChild
.get());
3652 SAL_WARN_IF(!pPrioritable
, "vcl", "priority set for not supported item");
3654 pPrioritable
->SetPriority(nPriority
);
3656 if (!aContext
.empty())
3658 vcl::IContext
* pContextControl
= dynamic_cast<vcl::IContext
*>(pCurrentChild
.get());
3659 SAL_WARN_IF(!pContextControl
, "vcl", "context set for not supported item");
3660 if (pContextControl
)
3661 pContextControl
->SetContext(std::move(aContext
));
3667 if (name
== "property")
3668 collectProperty(reader
, aProperties
);
3669 else if (name
== "attribute")
3670 collectPangoAttribute(reader
, aPangoAttributes
);
3671 else if (name
== "relation")
3672 collectAtkRelationAttribute(reader
, aAtkAttributes
);
3673 else if (name
== "role")
3674 collectAtkRoleAttribute(reader
, aAtkAttributes
);
3675 else if (name
== "action-widget")
3676 handleActionWidget(reader
);
3680 if (res
== xmlreader::XmlReader::Result::End
)
3689 if (sClass
== "GtkAdjustment")
3691 m_pParserState
->m_aAdjustments
[sID
] = aProperties
;
3694 else if (sClass
== "GtkTextBuffer")
3696 m_pParserState
->m_aTextBuffers
[sID
] = aProperties
;
3702 pCurrentChild
= insertObject(pParent
, sClass
, sID
, aProperties
,
3703 aPangoAttributes
, aAtkAttributes
);
3706 if (!aItems
.empty())
3708 // try to fill-in the items
3709 if (!insertItems
<ComboBox
>(pCurrentChild
, aProperties
, m_aUserData
, aItems
))
3710 insertItems
<ListBox
>(pCurrentChild
, aProperties
, m_aUserData
, aItems
);
3713 return pCurrentChild
;
3716 void VclBuilder::handlePacking(vcl::Window
*pCurrent
, vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
3718 xmlreader::Span name
;
3725 xmlreader::XmlReader::Result res
= reader
.nextItem(
3726 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3728 if (res
== xmlreader::XmlReader::Result::Done
)
3731 if (res
== xmlreader::XmlReader::Result::Begin
)
3734 if (name
== "property")
3735 applyPackingProperty(pCurrent
, pParent
, reader
);
3738 if (res
== xmlreader::XmlReader::Result::End
)
3748 void VclBuilder::applyPackingProperty(vcl::Window
*pCurrent
,
3749 vcl::Window
*pParent
,
3750 xmlreader::XmlReader
&reader
)
3755 //ToolBoxItems are not true widgets just elements
3756 //of the ToolBox itself
3757 ToolBox
*pToolBoxParent
= nullptr;
3758 if (pCurrent
== pParent
)
3759 pToolBoxParent
= dynamic_cast<ToolBox
*>(pParent
);
3761 xmlreader::Span name
;
3764 if (pCurrent
->GetType() == WindowType::SCROLLWINDOW
)
3766 auto aFind
= m_pParserState
->m_aRedundantParentWidgets
.find(VclPtr
<vcl::Window
>(pCurrent
));
3767 if (aFind
!= m_pParserState
->m_aRedundantParentWidgets
.end())
3769 pCurrent
= aFind
->second
;
3774 while (reader
.nextAttribute(&nsId
, &name
))
3778 name
= reader
.getAttributeValue(false);
3779 OString
sKey(name
.begin
, name
.length
);
3780 sKey
= sKey
.replace('_', '-');
3781 (void)reader
.nextItem(
3782 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3783 OString
sValue(name
.begin
, name
.length
);
3785 if (sKey
== "expand" || sKey
== "resize")
3787 bool bTrue
= (!sValue
.isEmpty() && (sValue
[0] == 't' || sValue
[0] == 'T' || sValue
[0] == '1'));
3789 pToolBoxParent
->SetItemExpand(m_pParserState
->m_nLastToolbarId
, bTrue
);
3791 pCurrent
->set_expand(bTrue
);
3800 bool bTrue
= (!sValue
.isEmpty() && (sValue
[0] == 't' || sValue
[0] == 'T' || sValue
[0] == '1'));
3801 pCurrent
->set_fill(bTrue
);
3803 else if (sKey
== "pack-type")
3805 VclPackType ePackType
= (!sValue
.isEmpty() && (sValue
[0] == 'e' || sValue
[0] == 'E')) ? VclPackType::End
: VclPackType::Start
;
3806 pCurrent
->set_pack_type(ePackType
);
3808 else if (sKey
== "left-attach")
3810 pCurrent
->set_grid_left_attach(sValue
.toInt32());
3812 else if (sKey
== "top-attach")
3814 pCurrent
->set_grid_top_attach(sValue
.toInt32());
3816 else if (sKey
== "width")
3818 pCurrent
->set_grid_width(sValue
.toInt32());
3820 else if (sKey
== "height")
3822 pCurrent
->set_grid_height(sValue
.toInt32());
3824 else if (sKey
== "padding")
3826 pCurrent
->set_padding(sValue
.toInt32());
3828 else if (sKey
== "position")
3830 set_window_packing_position(pCurrent
, sValue
.toInt32());
3832 else if (sKey
== "secondary")
3834 pCurrent
->set_secondary(toBool(sValue
));
3836 else if (sKey
== "non-homogeneous")
3838 pCurrent
->set_non_homogeneous(toBool(sValue
));
3840 else if (sKey
== "homogeneous")
3842 pCurrent
->set_non_homogeneous(!toBool(sValue
));
3846 SAL_WARN_IF(sKey
!= "shrink", "vcl.builder", "unknown packing: " << sKey
);
3852 std::vector
<vcl::EnumContext::Context
> VclBuilder::handleStyle(xmlreader::XmlReader
&reader
, int &nPriority
)
3854 std::vector
<vcl::EnumContext::Context
> aContext
;
3856 xmlreader::Span name
;
3863 xmlreader::XmlReader::Result res
= reader
.nextItem(
3864 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3866 if (res
== xmlreader::XmlReader::Result::Done
)
3869 if (res
== xmlreader::XmlReader::Result::Begin
)
3872 if (name
== "class")
3874 OUString classStyle
= getStyleClass(reader
);
3877 if (classStyle
.startsWith("context-", &rest
))
3879 aContext
.push_back(vcl::EnumContext::GetContextEnum(rest
));
3881 else if (classStyle
.startsWith("priority-", &rest
))
3883 nPriority
= rest
.toInt32();
3885 else if (classStyle
!= "small-button" && classStyle
!= "destructive-action" && classStyle
!= "suggested-action")
3887 SAL_WARN("vcl.builder", "unknown class: " << classStyle
);
3892 if (res
== xmlreader::XmlReader::Result::End
)
3904 OUString
VclBuilder::getStyleClass(xmlreader::XmlReader
&reader
)
3906 xmlreader::Span name
;
3910 while (reader
.nextAttribute(&nsId
, &name
))
3914 name
= reader
.getAttributeValue(false);
3915 aRet
= OUString (name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
3922 void VclBuilder::collectProperty(xmlreader::XmlReader
&reader
, stringmap
&rMap
) const
3924 xmlreader::Span name
;
3930 bool bTranslated
= false;
3932 while (reader
.nextAttribute(&nsId
, &name
))
3936 name
= reader
.getAttributeValue(false);
3937 sProperty
= OUString(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
3939 else if (name
== "context")
3941 name
= reader
.getAttributeValue(false);
3942 sContext
= OString(name
.begin
, name
.length
);
3944 else if (name
== "translatable" && reader
.getAttributeValue(false) == "yes")
3950 (void)reader
.nextItem(xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3951 OString
sValue(name
.begin
, name
.length
);
3952 OUString sFinalValue
;
3955 sFinalValue
= Translate::get(TranslateId
{sContext
.getStr(), sValue
.getStr()}, m_pParserState
->m_aResLocale
);
3958 sFinalValue
= OUString::fromUtf8(sValue
);
3960 if (!sProperty
.isEmpty())
3962 sProperty
= sProperty
.replace('_', '-');
3963 if (m_pStringReplace
)
3964 sFinalValue
= (*m_pStringReplace
)(sFinalValue
);
3965 rMap
[sProperty
] = sFinalValue
;
3969 void VclBuilder::handleActionWidget(xmlreader::XmlReader
&reader
)
3971 xmlreader::Span name
;
3976 while (reader
.nextAttribute(&nsId
, &name
))
3978 if (name
== "response")
3980 name
= reader
.getAttributeValue(false);
3981 sResponse
= OString(name
.begin
, name
.length
);
3985 (void)reader
.nextItem(xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3986 OUString
sID(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
3987 sal_Int32 nDelim
= sID
.indexOf(':');
3989 sID
= sID
.copy(0, nDelim
);
3990 set_response(sID
, sResponse
.toInt32());
3993 void VclBuilder::collectAccelerator(xmlreader::XmlReader
&reader
, accelmap
&rMap
)
3995 xmlreader::Span name
;
4000 OUString sModifiers
;
4002 while (reader
.nextAttribute(&nsId
, &name
))
4006 name
= reader
.getAttributeValue(false);
4007 sValue
= OUString(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
4009 else if (name
== "signal")
4011 name
= reader
.getAttributeValue(false);
4012 sProperty
= OUString(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
4014 else if (name
== "modifiers")
4016 name
= reader
.getAttributeValue(false);
4017 sModifiers
= OUString(name
.begin
, name
.length
, RTL_TEXTENCODING_UTF8
);
4021 if (!sProperty
.isEmpty() && !sValue
.isEmpty())
4023 rMap
[sProperty
] = std::make_pair(sValue
, sModifiers
);
4027 vcl::Window
*VclBuilder::get_widget_root()
4029 return m_aChildren
.empty() ? nullptr : m_aChildren
[0].m_pWindow
.get();
4032 vcl::Window
*VclBuilder::get_by_name(std::u16string_view sID
)
4034 for (auto const& child
: m_aChildren
)
4036 if (child
.m_sID
== sID
)
4037 return child
.m_pWindow
;
4043 PopupMenu
*VclBuilder::get_menu(std::u16string_view sID
)
4045 for (auto const& menu
: m_aMenus
)
4047 if (menu
.m_sID
== sID
)
4048 return dynamic_cast<PopupMenu
*>(menu
.m_pMenu
.get());
4054 void VclBuilder::set_response(std::u16string_view sID
, short nResponse
)
4062 nResponse
= RET_CANCEL
;
4065 nResponse
= RET_CLOSE
;
4068 nResponse
= RET_YES
;
4074 nResponse
= RET_HELP
;
4077 assert(nResponse
>= 100 && "keep non-canned responses in range 100+ to avoid collision with vcl RET_*");
4081 for (const auto & child
: m_aChildren
)
4083 if (child
.m_sID
== sID
)
4085 PushButton
* pPushButton
= dynamic_cast<PushButton
*>(child
.m_pWindow
.get());
4086 assert(pPushButton
);
4087 Dialog
* pDialog
= pPushButton
->GetParentDialog();
4089 pDialog
->add_button(pPushButton
, nResponse
, false);
4097 void VclBuilder::delete_by_name(const OUString
& sID
)
4099 auto aI
= std::find_if(m_aChildren
.begin(), m_aChildren
.end(),
4100 [&sID
](WinAndId
& rItem
) { return rItem
.m_sID
== sID
; });
4101 if (aI
!= m_aChildren
.end())
4103 aI
->m_pWindow
.disposeAndClear();
4104 m_aChildren
.erase(aI
);
4108 void VclBuilder::delete_by_window(vcl::Window
*pWindow
)
4110 drop_ownership(pWindow
);
4111 pWindow
->disposeOnce();
4114 void VclBuilder::drop_ownership(const vcl::Window
*pWindow
)
4116 auto aI
= std::find_if(m_aChildren
.begin(), m_aChildren
.end(),
4117 [&pWindow
](WinAndId
& rItem
) { return rItem
.m_pWindow
== pWindow
; });
4118 if (aI
!= m_aChildren
.end())
4119 m_aChildren
.erase(aI
);
4122 OUString
VclBuilder::get_by_window(const vcl::Window
*pWindow
) const
4124 for (auto const& child
: m_aChildren
)
4126 if (child
.m_pWindow
== pWindow
)
4133 VclBuilder::PackingData
VclBuilder::get_window_packing_data(const vcl::Window
*pWindow
) const
4135 //We've stored the return of new Control, some of these get
4136 //border windows placed around them which are what you get
4137 //from GetChild, so scoot up a level if necessary to get the
4138 //window whose position value we have
4139 const vcl::Window
*pPropHolder
= pWindow
->ImplGetWindow();
4141 for (auto const& child
: m_aChildren
)
4143 if (child
.m_pWindow
== pPropHolder
)
4144 return child
.m_aPackingData
;
4147 return PackingData();
4150 void VclBuilder::set_window_packing_position(const vcl::Window
*pWindow
, sal_Int32 nPosition
)
4152 for (auto & child
: m_aChildren
)
4154 if (child
.m_pWindow
== pWindow
)
4155 child
.m_aPackingData
.m_nPosition
= nPosition
;
4159 const VclBuilder::ListStore
*VclBuilder::get_model_by_name(const OUString
& sID
) const
4161 const auto aI
= m_pParserState
->m_aModels
.find(sID
);
4162 if (aI
!= m_pParserState
->m_aModels
.end())
4163 return &(aI
->second
);
4167 const VclBuilder::TextBuffer
*VclBuilder::get_buffer_by_name(const OUString
& sID
) const
4169 const auto aI
= m_pParserState
->m_aTextBuffers
.find(sID
);
4170 if (aI
!= m_pParserState
->m_aTextBuffers
.end())
4171 return &(aI
->second
);
4175 const VclBuilder::Adjustment
*VclBuilder::get_adjustment_by_name(const OUString
& sID
) const
4177 const auto aI
= m_pParserState
->m_aAdjustments
.find(sID
);
4178 if (aI
!= m_pParserState
->m_aAdjustments
.end())
4179 return &(aI
->second
);
4183 void VclBuilder::mungeModel(ComboBox
&rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4185 for (auto const& entry
: rStore
.m_aEntries
)
4187 const ListStore::row
&rRow
= entry
;
4188 sal_uInt16 nEntry
= rTarget
.InsertEntry(rRow
[0]);
4189 if (rRow
.size() > 1)
4193 sal_Int32 nValue
= rRow
[1].toInt32();
4194 rTarget
.SetEntryData(nEntry
, reinterpret_cast<void*>(nValue
));
4198 if (!rRow
[1].isEmpty())
4200 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4201 rTarget
.SetEntryData(nEntry
, m_aUserData
.back().get());
4206 if (nActiveId
< rStore
.m_aEntries
.size())
4207 rTarget
.SelectEntryPos(nActiveId
);
4210 void VclBuilder::mungeModel(ListBox
&rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4212 for (auto const& entry
: rStore
.m_aEntries
)
4214 const ListStore::row
&rRow
= entry
;
4215 sal_uInt16 nEntry
= rTarget
.InsertEntry(rRow
[0]);
4216 if (rRow
.size() > 1)
4220 sal_Int32 nValue
= rRow
[1].toInt32();
4221 rTarget
.SetEntryData(nEntry
, reinterpret_cast<void*>(nValue
));
4225 if (!rRow
[1].isEmpty())
4227 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4228 rTarget
.SetEntryData(nEntry
, m_aUserData
.back().get());
4233 if (nActiveId
< rStore
.m_aEntries
.size())
4234 rTarget
.SelectEntryPos(nActiveId
);
4237 void VclBuilder::mungeModel(SvTabListBox
& rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4239 for (auto const& entry
: rStore
.m_aEntries
)
4241 const ListStore::row
&rRow
= entry
;
4242 auto pEntry
= rTarget
.InsertEntry(rRow
[0]);
4243 if (rRow
.size() > 1)
4247 sal_Int32 nValue
= rRow
[1].toInt32();
4248 pEntry
->SetUserData(reinterpret_cast<void*>(nValue
));
4252 if (!rRow
[1].isEmpty())
4254 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4255 pEntry
->SetUserData(m_aUserData
.back().get());
4260 if (nActiveId
< rStore
.m_aEntries
.size())
4262 SvTreeListEntry
* pEntry
= rTarget
.GetEntry(nullptr, nActiveId
);
4263 rTarget
.Select(pEntry
);
4267 void VclBuilder::mungeAdjustment(NumericFormatter
&rTarget
, const Adjustment
&rAdjustment
)
4269 int nMul
= rtl_math_pow10Exp(1, rTarget
.GetDecimalDigits());
4271 for (auto const& [ rKey
, rValue
] : rAdjustment
)
4273 if (rKey
== "upper")
4275 sal_Int64 nUpper
= rValue
.toDouble() * nMul
;
4276 rTarget
.SetMax(nUpper
);
4277 rTarget
.SetLast(nUpper
);
4279 else if (rKey
== "lower")
4281 sal_Int64 nLower
= rValue
.toDouble() * nMul
;
4282 rTarget
.SetMin(nLower
);
4283 rTarget
.SetFirst(nLower
);
4285 else if (rKey
== "value")
4287 sal_Int64 nValue
= rValue
.toDouble() * nMul
;
4288 rTarget
.SetValue(nValue
);
4290 else if (rKey
== "step-increment")
4292 sal_Int64 nSpinSize
= rValue
.toDouble() * nMul
;
4293 rTarget
.SetSpinSize(nSpinSize
);
4297 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4302 void VclBuilder::mungeAdjustment(FormattedField
&rTarget
, const Adjustment
&rAdjustment
)
4304 double nMaxValue
= 0, nMinValue
= 0, nValue
= 0, nSpinSize
= 0;
4306 for (auto const& [ rKey
, rValue
] : rAdjustment
)
4308 if (rKey
== "upper")
4309 nMaxValue
= rValue
.toDouble();
4310 else if (rKey
== "lower")
4311 nMinValue
= rValue
.toDouble();
4312 else if (rKey
== "value")
4313 nValue
= rValue
.toDouble();
4314 else if (rKey
== "step-increment")
4315 nSpinSize
= rValue
.toDouble();
4317 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4320 Formatter
& rFormatter
= rTarget
.GetFormatter();
4321 rFormatter
.SetMinValue(nMinValue
);
4322 rFormatter
.SetMaxValue(nMaxValue
);
4323 rFormatter
.SetValue(nValue
);
4324 rFormatter
.SetSpinSize(nSpinSize
);
4327 void VclBuilder::mungeAdjustment(ScrollBar
&rTarget
, const Adjustment
&rAdjustment
)
4329 for (auto const& [ rKey
, rValue
] : rAdjustment
)
4331 if (rKey
== "upper")
4332 rTarget
.SetRangeMax(rValue
.toInt32());
4333 else if (rKey
== "lower")
4334 rTarget
.SetRangeMin(rValue
.toInt32());
4335 else if (rKey
== "value")
4336 rTarget
.SetThumbPos(rValue
.toInt32());
4337 else if (rKey
== "step-increment")
4338 rTarget
.SetLineSize(rValue
.toInt32());
4339 else if (rKey
== "page-increment")
4340 rTarget
.SetPageSize(rValue
.toInt32());
4343 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4348 void VclBuilder::mungeAdjustment(Slider
& rTarget
, const Adjustment
& rAdjustment
)
4350 for (auto const& [ rKey
, rValue
] : rAdjustment
)
4352 if (rKey
== "upper")
4353 rTarget
.SetRangeMax(rValue
.toInt32());
4354 else if (rKey
== "lower")
4355 rTarget
.SetRangeMin(rValue
.toInt32());
4356 else if (rKey
== "value")
4357 rTarget
.SetThumbPos(rValue
.toInt32());
4358 else if (rKey
== "step-increment")
4359 rTarget
.SetLineSize(rValue
.toInt32());
4360 else if (rKey
== "page-increment")
4361 rTarget
.SetPageSize(rValue
.toInt32());
4364 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4369 void VclBuilder::mungeTextBuffer(VclMultiLineEdit
&rTarget
, const TextBuffer
&rTextBuffer
)
4371 for (auto const& [ rKey
, rValue
] : rTextBuffer
)
4374 rTarget
.SetText(rValue
);
4377 SAL_INFO("vcl.builder", "unhandled property :" << rKey
);
4382 VclBuilder::ParserState::ParserState()
4383 : m_nLastToolbarId(0)
4384 , m_nLastMenuItemId(0)
4387 VclBuilder::MenuAndId::MenuAndId(OUString aId
, Menu
*pMenu
)
4388 : m_sID(std::move(aId
))
4392 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */