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>
13 #include <unordered_map>
14 #include <com/sun/star/accessibility/AccessibleRole.hpp>
16 #include <comphelper/lok.hxx>
17 #include <i18nutil/unicode.hxx>
18 #include <officecfg/Office/Common.hxx>
19 #include <osl/module.hxx>
20 #include <sal/log.hxx>
21 #include <unotools/localedatawrapper.hxx>
22 #include <unotools/resmgr.hxx>
23 #include <vcl/builder.hxx>
24 #include <vcl/button.hxx>
25 #include <vcl/calendar.hxx>
26 #include <vcl/dialog.hxx>
27 #include <vcl/edit.hxx>
28 #include <vcl/field.hxx>
29 #include <vcl/fmtfield.hxx>
30 #include <vcl/fixed.hxx>
31 #include <vcl/toolkit/fixedhyper.hxx>
32 #include <vcl/headbar.hxx>
33 #include <vcl/IPrioritable.hxx>
34 #include <vcl/ivctrl.hxx>
35 #include <vcl/layout.hxx>
36 #include <vcl/lstbox.hxx>
37 #include <vcl/menubtn.hxx>
38 #include <vcl/mnemonic.hxx>
39 #include <vcl/toolkit/prgsbar.hxx>
40 #include <vcl/scrbar.hxx>
41 #include <vcl/svapp.hxx>
42 #include <vcl/svtabbx.hxx>
43 #include <vcl/tabctrl.hxx>
44 #include <vcl/tabpage.hxx>
45 #include <vcl/toolkit/throbber.hxx>
46 #include <vcl/toolbox.hxx>
47 #include <vcl/treelistentry.hxx>
48 #include <vcl/vclmedit.hxx>
49 #include <vcl/settings.hxx>
50 #include <vcl/slider.hxx>
51 #include <vcl/weld.hxx>
52 #include <vcl/commandinfoprovider.hxx>
53 #include <iconview.hxx>
55 #include <bitmaps.hlst>
56 #include <messagedialog.hxx>
58 #include <xmlreader/xmlreader.hxx>
59 #include <desktop/crashreport.hxx>
60 #include <salinst.hxx>
61 #include <strings.hrc>
62 #include <aboutdialog.hxx>
63 #include <treeglue.hxx>
64 #include <tools/diagnose_ex.h>
66 #include <tools/svlibrary.h>
68 #ifdef DISABLE_DYNLOADING
72 static bool toBool(const OString
&rValue
)
74 return (!rValue
.isEmpty() && (rValue
[0] == 't' || rValue
[0] == 'T' || rValue
[0] == '1'));
79 OUString
mapStockToImageResource(const OUString
& sType
)
81 if (sType
== "gtk-index")
82 return SV_RESID_BITMAP_INDEX
;
83 else if (sType
== "gtk-refresh")
84 return SV_RESID_BITMAP_REFRESH
;
85 else if (sType
== "gtk-apply")
87 else if (sType
== "gtk-dialog-error")
89 else if (sType
== "gtk-add")
91 else if (sType
== "gtk-remove")
96 SymbolType
mapStockToSymbol(const OUString
& sType
)
98 SymbolType eRet
= SymbolType::DONTKNOW
;
99 if (sType
== "gtk-media-next")
100 eRet
= SymbolType::NEXT
;
101 else if (sType
== "gtk-media-previous")
102 eRet
= SymbolType::PREV
;
103 else if (sType
== "gtk-media-play")
104 eRet
= SymbolType::PLAY
;
105 else if (sType
== "gtk-media-stop")
106 eRet
= SymbolType::STOP
;
107 else if (sType
== "gtk-goto-first")
108 eRet
= SymbolType::FIRST
;
109 else if (sType
== "gtk-goto-last")
110 eRet
= SymbolType::LAST
;
111 else if (sType
== "gtk-go-back")
112 eRet
= SymbolType::ARROW_LEFT
;
113 else if (sType
== "gtk-go-forward")
114 eRet
= SymbolType::ARROW_RIGHT
;
115 else if (sType
== "gtk-go-up")
116 eRet
= SymbolType::ARROW_UP
;
117 else if (sType
== "gtk-go-down")
118 eRet
= SymbolType::ARROW_DOWN
;
119 else if (sType
== "gtk-missing-image")
120 eRet
= SymbolType::IMAGE
;
121 else if (sType
== "gtk-help")
122 eRet
= SymbolType::HELP
;
123 else if (sType
== "gtk-close")
124 eRet
= SymbolType::CLOSE
;
125 else if (!mapStockToImageResource(sType
).isEmpty())
126 eRet
= SymbolType::IMAGE
;
130 void setupFromActionName(Button
*pButton
, VclBuilder::stringmap
&rMap
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
);
133 #if defined SAL_LOG_WARN
136 bool isButtonType(WindowType nType
)
138 return nType
== WindowType::PUSHBUTTON
||
139 nType
== WindowType::OKBUTTON
||
140 nType
== WindowType::CANCELBUTTON
||
141 nType
== WindowType::HELPBUTTON
||
142 nType
== WindowType::IMAGEBUTTON
||
143 nType
== WindowType::MENUBUTTON
||
144 nType
== WindowType::MOREBUTTON
||
145 nType
== WindowType::SPINBUTTON
;
150 weld::Builder
* Application::CreateBuilder(weld::Widget
* pParent
, const OUString
&rUIFile
)
152 return ImplGetSVData()->mpDefInst
->CreateBuilder(pParent
, VclBuilderContainer::getUIRootDir(), rUIFile
);
155 weld::Builder
* Application::CreateInterimBuilder(vcl::Window
* pParent
, const OUString
&rUIFile
)
157 return SalInstance::CreateInterimBuilder(pParent
, VclBuilderContainer::getUIRootDir(), rUIFile
);
160 weld::MessageDialog
* Application::CreateMessageDialog(weld::Widget
* pParent
, VclMessageType eMessageType
,
161 VclButtonsType eButtonType
, const OUString
& rPrimaryMessage
)
163 return ImplGetSVData()->mpDefInst
->CreateMessageDialog(pParent
, eMessageType
, eButtonType
, rPrimaryMessage
);
166 weld::Window
* Application::GetFrameWeld(const css::uno::Reference
<css::awt::XWindow
>& rWindow
)
168 return ImplGetSVData()->mpDefInst
->GetFrameWeld(rWindow
);
173 OUString
MetricSpinButton::MetricToString(FieldUnit rUnit
)
175 const FieldUnitStringList
& rList
= ImplGetFieldUnits();
176 // return unit's default string (ie, the first one )
177 auto it
= std::find_if(
178 rList
.begin(), rList
.end(),
179 [&rUnit
](const std::pair
<OUString
, FieldUnit
>& rItem
) { return rItem
.second
== rUnit
; });
180 if (it
!= rList
.end())
186 IMPL_LINK_NOARG(MetricSpinButton
, spin_button_value_changed
, SpinButton
&, void)
188 signal_value_changed();
191 IMPL_LINK(MetricSpinButton
, spin_button_output
, SpinButton
&, rSpinButton
, void)
193 OUString
sNewText(format_number(rSpinButton
.get_value()));
194 if (sNewText
!= rSpinButton
.get_text())
195 rSpinButton
.set_text(sNewText
);
198 void MetricSpinButton::update_width_chars()
201 m_xSpinButton
->get_range(min
, max
);
202 auto width
= std::max(m_xSpinButton
->get_pixel_size(format_number(min
)).Width(),
203 m_xSpinButton
->get_pixel_size(format_number(max
)).Width());
204 int chars
= ceil(width
/ m_xSpinButton
->get_approximate_digit_width());
205 m_xSpinButton
->set_width_chars(chars
);
208 unsigned int SpinButton::Power10(unsigned int n
)
210 unsigned int nValue
= 1;
211 for (unsigned int i
= 0; i
< n
; ++i
)
216 int SpinButton::denormalize(int nValue
) const
218 const int nFactor
= Power10(get_digits());
220 if ((nValue
< (SAL_MIN_INT32
+ nFactor
)) || (nValue
> (SAL_MAX_INT32
- nFactor
)))
222 return nValue
/ nFactor
;
225 const int nHalf
= nFactor
/ 2;
228 return (nValue
- nHalf
) / nFactor
;
229 return (nValue
+ nHalf
) / nFactor
;
232 OUString
MetricSpinButton::format_number(int nValue
) const
236 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
238 unsigned int nDecimalDigits
= m_xSpinButton
->get_digits();
239 //pawn percent off to icu to decide whether percent is separated from its number for this locale
240 if (m_eSrcUnit
== FieldUnit::PERCENT
)
242 double fValue
= nValue
;
243 fValue
/= SpinButton::Power10(nDecimalDigits
);
244 aStr
= unicode::formatPercent(fValue
, rLocaleData
.getLanguageTag());
248 aStr
= rLocaleData
.getNum(nValue
, nDecimalDigits
, true, true);
249 OUString aSuffix
= MetricToString(m_eSrcUnit
);
250 if (m_eSrcUnit
!= FieldUnit::NONE
&& m_eSrcUnit
!= FieldUnit::DEGREE
&& m_eSrcUnit
!= FieldUnit::INCH
)
252 if (m_eSrcUnit
== FieldUnit::INCH
)
254 OUString sDoublePrime
= u
"\u2033";
255 if (aSuffix
!= "\"" && aSuffix
!= sDoublePrime
)
258 aSuffix
= sDoublePrime
;
260 assert(m_eSrcUnit
!= FieldUnit::PERCENT
);
267 void MetricSpinButton::set_digits(unsigned int digits
)
270 get_increments(step
, page
, m_eSrcUnit
);
271 int value
= get_value(m_eSrcUnit
);
272 m_xSpinButton
->set_digits(digits
);
273 set_increments(step
, page
, m_eSrcUnit
);
274 set_value(value
, m_eSrcUnit
);
275 update_width_chars();
278 void MetricSpinButton::set_unit(FieldUnit eUnit
)
280 if (eUnit
!= m_eSrcUnit
)
283 get_increments(step
, page
, m_eSrcUnit
);
284 int value
= get_value(m_eSrcUnit
);
286 set_increments(step
, page
, m_eSrcUnit
);
287 set_value(value
, m_eSrcUnit
);
288 spin_button_output(*m_xSpinButton
);
289 update_width_chars();
293 int MetricSpinButton::ConvertValue(int nValue
, FieldUnit eInUnit
, FieldUnit eOutUnit
) const
295 return MetricField::ConvertValue(nValue
, 0, m_xSpinButton
->get_digits(), eInUnit
, eOutUnit
);
298 IMPL_LINK(MetricSpinButton
, spin_button_input
, int*, result
, bool)
300 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
302 bool bRet
= MetricFormatter::TextToValue(get_text(), fResult
, 0, m_xSpinButton
->get_digits(), rLocaleData
, m_eSrcUnit
);
305 if (fResult
> SAL_MAX_INT32
)
306 fResult
= SAL_MAX_INT32
;
307 else if (fResult
< SAL_MIN_INT32
)
308 fResult
= SAL_MIN_INT32
;
314 IMPL_LINK_NOARG(TimeSpinButton
, spin_button_cursor_position
, Entry
&, void)
316 int nStartPos
, nEndPos
;
317 m_xSpinButton
->get_selection_bounds(nStartPos
, nEndPos
);
319 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
320 const int nTimeArea
= TimeFormatter::GetTimeArea(m_eFormat
, m_xSpinButton
->get_text(), nEndPos
,
326 nIncrements
= 1000 * 60 * 60;
327 else if (nTimeArea
== 2)
328 nIncrements
= 1000 * 60;
329 else if (nTimeArea
== 3)
332 m_xSpinButton
->set_increments(nIncrements
, nIncrements
* 10);
335 IMPL_LINK_NOARG(TimeSpinButton
, spin_button_value_changed
, SpinButton
&, void)
337 signal_value_changed();
340 IMPL_LINK(TimeSpinButton
, spin_button_output
, SpinButton
&, rSpinButton
, void)
342 int nStartPos
, nEndPos
;
343 rSpinButton
.get_selection_bounds(nStartPos
, nEndPos
);
344 rSpinButton
.set_text(format_number(rSpinButton
.get_value()));
345 rSpinButton
.set_position(nEndPos
);
348 IMPL_LINK(TimeSpinButton
, spin_button_input
, int*, result
, bool)
350 int nStartPos
, nEndPos
;
351 m_xSpinButton
->get_selection_bounds(nStartPos
, nEndPos
);
353 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
354 tools::Time
aResult(0);
355 bool bRet
= TimeFormatter::TextToTime(m_xSpinButton
->get_text(), aResult
, m_eFormat
, true, rLocaleData
);
357 *result
= ConvertValue(aResult
);
361 void TimeSpinButton::update_width_chars()
364 m_xSpinButton
->get_range(min
, max
);
365 auto width
= std::max(m_xSpinButton
->get_pixel_size(format_number(min
)).Width(),
366 m_xSpinButton
->get_pixel_size(format_number(max
)).Width());
367 int chars
= ceil(width
/ m_xSpinButton
->get_approximate_digit_width());
368 m_xSpinButton
->set_width_chars(chars
);
371 tools::Time
TimeSpinButton::ConvertValue(int nValue
)
373 tools::Time
aTime(0);
374 aTime
.MakeTimeFromMS(nValue
);
378 int TimeSpinButton::ConvertValue(const tools::Time
& rTime
)
380 return rTime
.GetMSFromTime();
383 OUString
TimeSpinButton::format_number(int nValue
) const
385 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
386 return TimeFormatter::FormatTime(ConvertValue(nValue
), m_eFormat
, TimeFormat::Hour24
, true, rLocaleData
);
389 EntryTreeView::EntryTreeView(std::unique_ptr
<Entry
> xEntry
, std::unique_ptr
<TreeView
> xTreeView
)
390 : m_xEntry(std::move(xEntry
))
391 , m_xTreeView(std::move(xTreeView
))
393 m_xTreeView
->connect_changed(LINK(this, EntryTreeView
, ClickHdl
));
394 m_xEntry
->connect_changed(LINK(this, EntryTreeView
, ModifyHdl
));
397 IMPL_LINK(EntryTreeView
, ClickHdl
, weld::TreeView
&, rView
, void)
399 m_xEntry
->set_text(rView
.get_selected_text());
400 m_aChangeHdl
.Call(*this);
403 IMPL_LINK_NOARG(EntryTreeView
, ModifyHdl
, weld::Entry
&, void)
405 m_aChangeHdl
.Call(*this);
408 void EntryTreeView::set_height_request_by_rows(int nRows
)
410 int nHeight
= nRows
== -1 ? -1 : m_xTreeView
->get_height_rows(nRows
);
411 m_xTreeView
->set_size_request(m_xTreeView
->get_size_request().Width(), nHeight
);
415 VclBuilder::VclBuilder(vcl::Window
* pParent
, const OUString
& sUIDir
, const OUString
& sUIFile
,
416 const OString
& sID
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
,
417 bool bLegacy
, const NotebookBarAddonsItem
* pNotebookBarAddonsItem
)
418 : m_pNotebookBarAddonsItem(pNotebookBarAddonsItem
419 ? new NotebookBarAddonsItem(*pNotebookBarAddonsItem
)
420 : new NotebookBarAddonsItem
{})
422 , m_sHelpRoot(OUStringToOString(sUIFile
, RTL_TEXTENCODING_UTF8
))
423 , m_pStringReplace(Translate::GetReadStringHook())
425 , m_bToplevelParentFound(false)
427 , m_pParserState(new ParserState
)
430 m_bToplevelHasDeferredInit
= pParent
&&
431 ((pParent
->IsSystemWindow() && static_cast<SystemWindow
*>(pParent
)->isDeferredInit()) ||
432 (pParent
->IsDockingWindow() && static_cast<DockingWindow
*>(pParent
)->isDeferredInit()));
433 m_bToplevelHasDeferredProperties
= m_bToplevelHasDeferredInit
;
435 sal_Int32 nIdx
= m_sHelpRoot
.lastIndexOf('.');
437 m_sHelpRoot
= m_sHelpRoot
.copy(0, nIdx
);
438 m_sHelpRoot
+= OString('/');
440 OUString sUri
= sUIDir
+ sUIFile
;
444 xmlreader::XmlReader
reader(sUri
);
446 handleChild(pParent
, reader
);
448 catch (const css::uno::Exception
&rExcept
)
450 DBG_UNHANDLED_EXCEPTION("vcl.layout", "Unable to read .ui file");
451 CrashReporter::addKeyValue("VclBuilderException", "Unable to read .ui file: " + rExcept
.Message
, CrashReporter::Write
);
455 //Set Mnemonic widgets when everything has been imported
456 for (auto const& mnemonicWidget
: m_pParserState
->m_aMnemonicWidgetMaps
)
458 FixedText
*pOne
= get
<FixedText
>(mnemonicWidget
.m_sID
);
459 vcl::Window
*pOther
= get
<vcl::Window
>(mnemonicWidget
.m_sValue
.toUtf8());
460 SAL_WARN_IF(!pOne
|| !pOther
, "vcl", "missing either source " << mnemonicWidget
.m_sID
461 << " or target " << mnemonicWidget
.m_sValue
<< " member of Mnemonic Widget Mapping");
463 pOne
->set_mnemonic_widget(pOther
);
466 //Set a11y relations and role when everything has been imported
467 for (auto const& elemAtk
: m_pParserState
->m_aAtkInfo
)
469 vcl::Window
*pSource
= elemAtk
.first
;
470 const stringmap
&rMap
= elemAtk
.second
;
472 for (auto const& elemMap
: rMap
)
474 const OString
&rType
= elemMap
.first
;
475 const OUString
&rParam
= elemMap
.second
;
478 sal_Int16 role
= BuilderUtils::getRoleFromName(rParam
.toUtf8());
479 if (role
!= com::sun::star::accessibility::AccessibleRole::UNKNOWN
)
480 pSource
->SetAccessibleRole(role
);
484 vcl::Window
*pTarget
= get
<vcl::Window
>(rParam
.toUtf8());
485 SAL_WARN_IF(!pTarget
, "vcl", "missing parameter of a11y relation: " << rParam
);
488 if (rType
== "labelled-by")
489 pSource
->SetAccessibleRelationLabeledBy(pTarget
);
490 else if (rType
== "label-for")
491 pSource
->SetAccessibleRelationLabelFor(pTarget
);
492 else if (rType
== "member-of")
493 pSource
->SetAccessibleRelationMemberOf(pTarget
);
496 SAL_WARN("vcl.layout", "unhandled a11y relation :" << rType
);
502 //Set radiobutton groups when everything has been imported
503 for (auto const& elem
: m_pParserState
->m_aGroupMaps
)
505 RadioButton
*pOne
= get
<RadioButton
>(elem
.m_sID
);
506 RadioButton
*pOther
= get
<RadioButton
>(elem
.m_sValue
);
507 SAL_WARN_IF(!pOne
|| !pOther
, "vcl", "missing member of radiobutton group");
511 pOne
->group(*pOther
);
514 pOther
->group(*pOne
);
515 std::stable_sort(pOther
->m_xGroup
->begin(), pOther
->m_xGroup
->end(), sortIntoBestTabTraversalOrder(this));
520 //Set ComboBox models when everything has been imported
521 for (auto const& elem
: m_pParserState
->m_aModelMaps
)
523 vcl::Window
* pTarget
= get
<vcl::Window
>(elem
.m_sID
);
524 ListBox
*pListBoxTarget
= dynamic_cast<ListBox
*>(pTarget
);
525 ComboBox
*pComboBoxTarget
= dynamic_cast<ComboBox
*>(pTarget
);
526 SvTabListBox
*pTreeBoxTarget
= dynamic_cast<SvTabListBox
*>(pTarget
);
527 // pStore may be empty
528 const ListStore
*pStore
= get_model_by_name(elem
.m_sValue
.toUtf8());
529 SAL_WARN_IF(!pListBoxTarget
&& !pComboBoxTarget
&& !pTreeBoxTarget
, "vcl", "missing elements of combobox");
530 if (pListBoxTarget
&& pStore
)
531 mungeModel(*pListBoxTarget
, *pStore
, elem
.m_nActiveId
);
532 else if (pComboBoxTarget
&& pStore
)
533 mungeModel(*pComboBoxTarget
, *pStore
, elem
.m_nActiveId
);
534 else if (pTreeBoxTarget
&& pStore
)
535 mungeModel(*pTreeBoxTarget
, *pStore
, elem
.m_nActiveId
);
538 //Set TextView buffers when everything has been imported
539 for (auto const& elem
: m_pParserState
->m_aTextBufferMaps
)
541 VclMultiLineEdit
*pTarget
= get
<VclMultiLineEdit
>(elem
.m_sID
);
542 const TextBuffer
*pBuffer
= get_buffer_by_name(elem
.m_sValue
.toUtf8());
543 SAL_WARN_IF(!pTarget
|| !pBuffer
, "vcl", "missing elements of textview/textbuffer");
544 if (pTarget
&& pBuffer
)
545 mungeTextBuffer(*pTarget
, *pBuffer
);
548 //Set SpinButton adjustments when everything has been imported
549 for (auto const& elem
: m_pParserState
->m_aNumericFormatterAdjustmentMaps
)
551 NumericFormatter
*pTarget
= dynamic_cast<NumericFormatter
*>(get
<vcl::Window
>(elem
.m_sID
));
552 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
553 SAL_WARN_IF(!pTarget
, "vcl", "missing NumericFormatter element of spinbutton/adjustment");
554 SAL_WARN_IF(!pAdjustment
, "vcl", "missing Adjustment element of spinbutton/adjustment");
555 if (pTarget
&& pAdjustment
)
556 mungeAdjustment(*pTarget
, *pAdjustment
);
559 for (auto const& elem
: m_pParserState
->m_aFormattedFormatterAdjustmentMaps
)
561 FormattedField
*pTarget
= dynamic_cast<FormattedField
*>(get
<vcl::Window
>(elem
.m_sID
));
562 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
563 SAL_WARN_IF(!pTarget
, "vcl", "missing FormattedField element of spinbutton/adjustment");
564 SAL_WARN_IF(!pAdjustment
, "vcl", "missing Adjustment element of spinbutton/adjustment");
565 if (pTarget
&& pAdjustment
)
566 mungeAdjustment(*pTarget
, *pAdjustment
);
569 for (auto const& elem
: m_pParserState
->m_aTimeFormatterAdjustmentMaps
)
571 TimeField
*pTarget
= dynamic_cast<TimeField
*>(get
<vcl::Window
>(elem
.m_sID
));
572 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
573 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of spinbutton/adjustment");
574 if (pTarget
&& pAdjustment
)
575 mungeAdjustment(*pTarget
, *pAdjustment
);
578 for (auto const& elem
: m_pParserState
->m_aDateFormatterAdjustmentMaps
)
580 DateField
*pTarget
= dynamic_cast<DateField
*>(get
<vcl::Window
>(elem
.m_sID
));
581 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
582 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of spinbutton/adjustment");
583 if (pTarget
&& pAdjustment
)
584 mungeAdjustment(*pTarget
, *pAdjustment
);
587 //Set ScrollBar adjustments when everything has been imported
588 for (auto const& elem
: m_pParserState
->m_aScrollAdjustmentMaps
)
590 ScrollBar
*pTarget
= get
<ScrollBar
>(elem
.m_sID
);
591 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
592 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of scrollbar/adjustment");
593 if (pTarget
&& pAdjustment
)
594 mungeAdjustment(*pTarget
, *pAdjustment
);
597 //Set Scale(Slider) adjustments
598 for (auto const& elem
: m_pParserState
->m_aSliderAdjustmentMaps
)
600 Slider
* pTarget
= dynamic_cast<Slider
*>(get
<vcl::Window
>(elem
.m_sID
));
601 const Adjustment
* pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
602 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of scale(slider)/adjustment");
603 if (pTarget
&& pAdjustment
)
605 mungeAdjustment(*pTarget
, *pAdjustment
);
609 //Set size-groups when all widgets have been imported
610 for (auto const& sizeGroup
: m_pParserState
->m_aSizeGroups
)
612 std::shared_ptr
<VclSizeGroup
> xGroup(std::make_shared
<VclSizeGroup
>());
614 for (auto const& elem
: sizeGroup
.m_aProperties
)
616 const OString
&rKey
= elem
.first
;
617 const OUString
&rValue
= elem
.second
;
618 xGroup
->set_property(rKey
, rValue
);
621 for (auto const& elem
: sizeGroup
.m_aWidgets
)
623 vcl::Window
* pWindow
= get
<vcl::Window
>(elem
.getStr());
624 pWindow
->add_to_size_group(xGroup
);
628 //Set button images when everything has been imported
629 std::set
<OUString
> aImagesToBeRemoved
;
630 for (auto const& elem
: m_pParserState
->m_aButtonImageWidgetMaps
)
632 PushButton
*pTargetButton
= nullptr;
633 RadioButton
*pTargetRadio
= nullptr;
634 Button
*pTarget
= nullptr;
638 pTargetButton
= get
<PushButton
>(elem
.m_sID
);
639 pTarget
= pTargetButton
;
643 pTargetRadio
= get
<RadioButton
>(elem
.m_sID
);
644 pTarget
= pTargetRadio
;
647 FixedImage
*pImage
= get
<FixedImage
>(elem
.m_sValue
.toUtf8());
648 SAL_WARN_IF(!pTarget
|| !pImage
,
649 "vcl", "missing elements of button/image/stock");
650 if (!pTarget
|| !pImage
)
652 aImagesToBeRemoved
.insert(elem
.m_sValue
);
654 VclBuilder::StockMap::iterator aFind
= m_pParserState
->m_aStockMap
.find(elem
.m_sValue
.toUtf8());
655 if (aFind
== m_pParserState
->m_aStockMap
.end())
658 pTargetButton
->SetModeImage(pImage
->GetImage());
660 pTargetRadio
->SetModeRadioImage(pImage
->GetImage());
664 const stockinfo
&rImageInfo
= aFind
->second
;
665 SymbolType eType
= mapStockToSymbol(rImageInfo
.m_sStock
);
666 SAL_WARN_IF(eType
== SymbolType::DONTKNOW
, "vcl", "missing stock image element for button");
667 if (eType
== SymbolType::DONTKNOW
)
671 pTargetButton
->SetSymbol(eType
);
672 //fdo#76457 keep symbol images small e.g. tools->customize->menu
673 //but images the right size. Really the PushButton::CalcMinimumSize
674 //and PushButton::ImplDrawPushButton are the better place to handle
675 //this, but its such a train-wreck
676 if (eType
!= SymbolType::IMAGE
)
677 pTargetButton
->SetStyle(pTargetButton
->GetStyle() | WB_SMALLSTYLE
);
680 SAL_WARN_IF(eType
!= SymbolType::IMAGE
, "vcl.layout", "unimplemented symbol type for radiobuttons");
681 if (eType
== SymbolType::IMAGE
)
683 Image
const aImage(StockImage::Yes
,
684 mapStockToImageResource(rImageInfo
.m_sStock
));
686 pTargetButton
->SetModeImage(aImage
);
688 pTargetRadio
->SetModeRadioImage(aImage
);
690 switch (rImageInfo
.m_nSize
)
693 pTarget
->SetSmallSymbol();
696 // large toolbar, make bigger than normal (4)
697 pTarget
->set_width_request(pTarget
->GetOptimalSize().Width() * 1.5);
698 pTarget
->set_height_request(pTarget
->GetOptimalSize().Height() * 1.5);
703 SAL_WARN("vcl.layout", "unsupported image size " << rImageInfo
.m_nSize
);
709 //There may be duplicate use of an Image, so we used a set to collect and
710 //now we can remove them from the tree after their final munge
711 for (auto const& elem
: aImagesToBeRemoved
)
713 delete_by_name(elem
.toUtf8());
716 //fill in any stock icons in surviving images
717 for (auto const& elem
: m_pParserState
->m_aStockMap
)
719 FixedImage
*pImage
= get
<FixedImage
>(elem
.first
);
720 SAL_WARN_IF(!pImage
, "vcl", "missing elements of image/stock: " << elem
.first
);
724 const stockinfo
&rImageInfo
= elem
.second
;
725 if (rImageInfo
.m_sStock
== "gtk-missing-image")
728 SymbolType eType
= mapStockToSymbol(rImageInfo
.m_sStock
);
729 SAL_WARN_IF(eType
!= SymbolType::IMAGE
, "vcl", "unimplemented symbol type for images");
730 if (eType
!= SymbolType::IMAGE
)
733 Image
const aImage(StockImage::Yes
,
734 mapStockToImageResource(rImageInfo
.m_sStock
));
735 pImage
->SetImage(aImage
);
738 //Set button menus when everything has been imported
739 for (auto const& elem
: m_pParserState
->m_aButtonMenuMaps
)
741 MenuButton
*pTarget
= get
<MenuButton
>(elem
.m_sID
);
742 PopupMenu
*pMenu
= get_menu(elem
.m_sValue
.toUtf8());
743 SAL_WARN_IF(!pTarget
|| !pMenu
,
744 "vcl", "missing elements of button/menu");
745 if (!pTarget
|| !pMenu
)
747 pTarget
->SetPopupMenu(pMenu
);
750 //Remove ScrollWindow parent widgets whose children in vcl implement scrolling
752 for (auto const& elem
: m_pParserState
->m_aRedundantParentWidgets
)
754 delete_by_window(elem
.first
);
757 //fdo#67378 merge the label into the disclosure button
758 for (auto const& elem
: m_pParserState
->m_aExpanderWidgets
)
760 vcl::Window
*pChild
= elem
->get_child();
761 vcl::Window
* pLabel
= elem
->GetWindow(GetWindowType::LastChild
);
762 if (pLabel
&& pLabel
!= pChild
&& pLabel
->GetType() == WindowType::FIXEDTEXT
)
764 FixedText
*pLabelWidget
= static_cast<FixedText
*>(pLabel
);
765 elem
->set_label(pLabelWidget
->GetText());
766 delete_by_window(pLabel
);
770 // create message dialog message area now
771 for (auto const& elem
: m_pParserState
->m_aMessageDialogs
)
772 elem
->create_message_area();
774 //drop maps, etc. that we don't need again
775 m_pParserState
.reset();
777 SAL_WARN_IF(!m_sID
.isEmpty() && (!m_bToplevelParentFound
&& !get_by_name(m_sID
)), "vcl.layout",
778 "Requested top level widget \"" << m_sID
<< "\" not found in " << sUIFile
);
780 #if defined SAL_LOG_WARN
781 if (m_bToplevelParentFound
&& m_pParent
->IsDialog())
784 bool bHasDefButton
= false;
785 for (auto const& child
: m_aChildren
)
787 if (isButtonType(child
.m_pWindow
->GetType()))
790 if (child
.m_pWindow
->GetStyle() & WB_DEFBUTTON
)
792 bHasDefButton
= true;
797 SAL_WARN_IF(nButtons
&& !bHasDefButton
, "vcl.layout", "No default button defined in " << sUIFile
);
801 const bool bHideHelp
= comphelper::LibreOfficeKit::isActive() &&
802 officecfg::Office::Common::Help::HelpRootURL::get().isEmpty();
805 if (vcl::Window
*pHelpButton
= get
<vcl::Window
>("help"))
810 VclBuilder::~VclBuilder()
815 void VclBuilder::disposeBuilder()
817 for (std::vector
<WinAndId
>::reverse_iterator aI
= m_aChildren
.rbegin(),
818 aEnd
= m_aChildren
.rend(); aI
!= aEnd
; ++aI
)
820 aI
->m_pWindow
.disposeAndClear();
824 for (std::vector
<MenuAndId
>::reverse_iterator aI
= m_aMenus
.rbegin(),
825 aEnd
= m_aMenus
.rend(); aI
!= aEnd
; ++aI
)
827 aI
->m_pMenu
.disposeAndClear();
835 bool extractDrawValue(VclBuilder::stringmap
& rMap
)
837 bool bDrawValue
= true;
838 VclBuilder::stringmap::iterator aFind
= rMap
.find("draw_value");
839 if (aFind
!= rMap
.end())
841 bDrawValue
= toBool(aFind
->second
);
847 OUString
extractPopupMenu(VclBuilder::stringmap
& rMap
)
850 VclBuilder::stringmap::iterator aFind
= rMap
.find("popup");
851 if (aFind
!= rMap
.end())
853 sRet
= aFind
->second
;
859 OUString
extractValuePos(VclBuilder::stringmap
& rMap
)
861 OUString
sRet("top");
862 VclBuilder::stringmap::iterator aFind
= rMap
.find("value_pos");
863 if (aFind
!= rMap
.end())
865 sRet
= aFind
->second
;
871 OUString
extractTypeHint(VclBuilder::stringmap
&rMap
)
873 OUString
sRet("normal");
874 VclBuilder::stringmap::iterator aFind
= rMap
.find("type-hint");
875 if (aFind
!= rMap
.end())
877 sRet
= aFind
->second
;
883 bool extractResizable(VclBuilder::stringmap
&rMap
)
885 bool bResizable
= true;
886 VclBuilder::stringmap::iterator aFind
= rMap
.find("resizable");
887 if (aFind
!= rMap
.end())
889 bResizable
= toBool(aFind
->second
);
895 #if HAVE_FEATURE_DESKTOP
896 bool extractModal(VclBuilder::stringmap
&rMap
)
899 VclBuilder::stringmap::iterator aFind
= rMap
.find("modal");
900 if (aFind
!= rMap
.end())
902 bModal
= toBool(aFind
->second
);
909 bool extractDecorated(VclBuilder::stringmap
&rMap
)
911 bool bDecorated
= true;
912 VclBuilder::stringmap::iterator aFind
= rMap
.find("decorated");
913 if (aFind
!= rMap
.end())
915 bDecorated
= toBool(aFind
->second
);
921 bool extractCloseable(VclBuilder::stringmap
&rMap
)
923 bool bCloseable
= true;
924 VclBuilder::stringmap::iterator aFind
= rMap
.find("deletable");
925 if (aFind
!= rMap
.end())
927 bCloseable
= toBool(aFind
->second
);
933 bool extractEntry(VclBuilder::stringmap
&rMap
)
935 bool bHasEntry
= false;
936 VclBuilder::stringmap::iterator aFind
= rMap
.find("has-entry");
937 if (aFind
!= rMap
.end())
939 bHasEntry
= toBool(aFind
->second
);
945 bool extractOrientation(VclBuilder::stringmap
&rMap
)
947 bool bVertical
= false;
948 VclBuilder::stringmap::iterator aFind
= rMap
.find("orientation");
949 if (aFind
!= rMap
.end())
951 bVertical
= aFind
->second
.equalsIgnoreAsciiCase("vertical");
957 bool extractVerticalTabPos(VclBuilder::stringmap
&rMap
)
959 bool bVertical
= false;
960 VclBuilder::stringmap::iterator aFind
= rMap
.find("tab-pos");
961 if (aFind
!= rMap
.end())
963 bVertical
= aFind
->second
.equalsIgnoreAsciiCase("left") ||
964 aFind
->second
.equalsIgnoreAsciiCase("right");
970 bool extractInconsistent(VclBuilder::stringmap
&rMap
)
972 bool bInconsistent
= false;
973 VclBuilder::stringmap::iterator aFind
= rMap
.find("inconsistent");
974 if (aFind
!= rMap
.end())
976 bInconsistent
= toBool(aFind
->second
);
979 return bInconsistent
;
982 OUString
extractIconName(VclBuilder::stringmap
&rMap
)
985 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("icon-name"));
986 if (aFind
!= rMap
.end())
988 sIconName
= aFind
->second
;
994 OUString
getStockText(const OUString
&rType
)
996 if (rType
== "gtk-ok")
997 return VclResId(SV_BUTTONTEXT_OK
);
998 else if (rType
== "gtk-cancel")
999 return VclResId(SV_BUTTONTEXT_CANCEL
);
1000 else if (rType
== "gtk-help")
1001 return VclResId(SV_BUTTONTEXT_HELP
);
1002 else if (rType
== "gtk-close")
1003 return VclResId(SV_BUTTONTEXT_CLOSE
);
1004 else if (rType
== "gtk-revert-to-saved")
1005 return VclResId(SV_BUTTONTEXT_RESET
);
1006 else if (rType
== "gtk-add")
1007 return VclResId(SV_BUTTONTEXT_ADD
);
1008 else if (rType
== "gtk-delete")
1009 return VclResId(SV_BUTTONTEXT_DELETE
);
1010 else if (rType
== "gtk-remove")
1011 return VclResId(SV_BUTTONTEXT_REMOVE
);
1012 else if (rType
== "gtk-new")
1013 return VclResId(SV_BUTTONTEXT_NEW
);
1014 else if (rType
== "gtk-edit")
1015 return VclResId(SV_BUTTONTEXT_EDIT
);
1016 else if (rType
== "gtk-apply")
1017 return VclResId(SV_BUTTONTEXT_APPLY
);
1018 else if (rType
== "gtk-save")
1019 return VclResId(SV_BUTTONTEXT_SAVE
);
1020 else if (rType
== "gtk-open")
1021 return VclResId(SV_BUTTONTEXT_OPEN
);
1022 else if (rType
== "gtk-undo")
1023 return VclResId(SV_BUTTONTEXT_UNDO
);
1024 else if (rType
== "gtk-paste")
1025 return VclResId(SV_BUTTONTEXT_PASTE
);
1026 else if (rType
== "gtk-media-next")
1027 return VclResId(SV_BUTTONTEXT_NEXT
);
1028 else if (rType
== "gtk-media-previous")
1029 return VclResId(SV_BUTTONTEXT_PREV
);
1030 else if (rType
== "gtk-go-up")
1031 return VclResId(SV_BUTTONTEXT_GO_UP
);
1032 else if (rType
== "gtk-go-down")
1033 return VclResId(SV_BUTTONTEXT_GO_DOWN
);
1034 else if (rType
== "gtk-clear")
1035 return VclResId(SV_BUTTONTEXT_CLEAR
);
1036 else if (rType
== "gtk-media-play")
1037 return VclResId(SV_BUTTONTEXT_PLAY
);
1038 else if (rType
== "gtk-find")
1039 return VclResId(SV_BUTTONTEXT_FIND
);
1040 else if (rType
== "gtk-stop")
1041 return VclResId(SV_BUTTONTEXT_STOP
);
1042 else if (rType
== "gtk-connect")
1043 return VclResId(SV_BUTTONTEXT_CONNECT
);
1044 else if (rType
== "gtk-yes")
1045 return VclResId(SV_BUTTONTEXT_YES
);
1046 else if (rType
== "gtk-no")
1047 return VclResId(SV_BUTTONTEXT_NO
);
1048 SAL_WARN("vcl.layout", "unknown stock type: " << rType
);
1052 bool extractStock(VclBuilder::stringmap
&rMap
)
1054 bool bIsStock
= false;
1055 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("use-stock"));
1056 if (aFind
!= rMap
.end())
1058 bIsStock
= toBool(aFind
->second
);
1064 WinBits
extractRelief(VclBuilder::stringmap
&rMap
)
1066 WinBits nBits
= WB_3DLOOK
;
1067 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("relief"));
1068 if (aFind
!= rMap
.end())
1070 if (aFind
->second
== "half")
1071 nBits
= WB_FLATBUTTON
| WB_BEVELBUTTON
;
1072 else if (aFind
->second
== "none")
1073 nBits
= WB_FLATBUTTON
;
1079 OUString
extractLabel(VclBuilder::stringmap
&rMap
)
1082 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("label"));
1083 if (aFind
!= rMap
.end())
1085 sType
= aFind
->second
;
1091 OUString
extractActionName(VclBuilder::stringmap
&rMap
)
1093 OUString sActionName
;
1094 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("action-name"));
1095 if (aFind
!= rMap
.end())
1097 sActionName
= aFind
->second
;
1103 bool extractVisible(VclBuilder::stringmap
&rMap
)
1105 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("visible"));
1106 if (aFind
!= rMap
.end())
1108 return toBool(aFind
->second
);
1113 Size
extractSizeRequest(VclBuilder::stringmap
&rMap
)
1115 OUString
sWidthRequest("0");
1116 OUString
sHeightRequest("0");
1117 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("width-request"));
1118 if (aFind
!= rMap
.end())
1120 sWidthRequest
= aFind
->second
;
1123 aFind
= rMap
.find("height-request");
1124 if (aFind
!= rMap
.end())
1126 sHeightRequest
= aFind
->second
;
1129 return Size(sWidthRequest
.toInt32(), sHeightRequest
.toInt32());
1132 OUString
extractTooltipText(VclBuilder::stringmap
&rMap
)
1134 OUString sTooltipText
;
1135 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("tooltip-text"));
1136 if (aFind
== rMap
.end())
1137 aFind
= rMap
.find(OString("tooltip-markup"));
1138 if (aFind
!= rMap
.end())
1140 sTooltipText
= aFind
->second
;
1143 return sTooltipText
;
1146 float extractAlignment(VclBuilder::stringmap
&rMap
)
1149 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("alignment"));
1150 if (aFind
!= rMap
.end())
1152 f
= aFind
->second
.toFloat();
1158 OUString
extractTitle(VclBuilder::stringmap
&rMap
)
1161 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("title"));
1162 if (aFind
!= rMap
.end())
1164 sTitle
= aFind
->second
;
1170 bool extractHeadersVisible(VclBuilder::stringmap
&rMap
)
1172 bool bHeadersVisible
= true;
1173 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("headers-visible"));
1174 if (aFind
!= rMap
.end())
1176 bHeadersVisible
= toBool(aFind
->second
);
1179 return bHeadersVisible
;
1182 bool extractSortIndicator(VclBuilder::stringmap
&rMap
)
1184 bool bSortIndicator
= false;
1185 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("sort-indicator"));
1186 if (aFind
!= rMap
.end())
1188 bSortIndicator
= toBool(aFind
->second
);
1191 return bSortIndicator
;
1194 bool extractClickable(VclBuilder::stringmap
&rMap
)
1196 bool bClickable
= false;
1197 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("clickable"));
1198 if (aFind
!= rMap
.end())
1200 bClickable
= toBool(aFind
->second
);
1206 void setupFromActionName(Button
*pButton
, VclBuilder::stringmap
&rMap
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
)
1211 OUString
aCommand(extractActionName(rMap
));
1212 if (aCommand
.isEmpty())
1215 OUString
aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame
));
1216 auto aProperties
= vcl::CommandInfoProvider::GetCommandProperties(aCommand
, aModuleName
);
1217 OUString
aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties
));
1218 if (!aLabel
.isEmpty())
1219 pButton
->SetText(aLabel
);
1221 OUString
aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(aCommand
, aProperties
, rFrame
));
1222 if (!aTooltip
.isEmpty())
1223 pButton
->SetQuickHelpText(aTooltip
);
1225 Image
aImage(vcl::CommandInfoProvider::GetImageForCommand(aCommand
, rFrame
));
1226 pButton
->SetModeImage(aImage
);
1228 pButton
->SetCommandHandler(aCommand
);
1231 VclPtr
<Button
> extractStockAndBuildPushButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
, bool bToggle
, bool bLegacy
)
1233 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
;
1237 nBits
|= extractRelief(rMap
);
1239 VclPtr
<Button
> xWindow
;
1241 if (extractStock(rMap
))
1243 OUString sType
= extractLabel(rMap
);
1246 if (sType
== "gtk-ok")
1247 xWindow
= VclPtr
<OKButton
>::Create(pParent
, nBits
);
1248 else if (sType
== "gtk-cancel")
1249 xWindow
= VclPtr
<CancelButton
>::Create(pParent
, nBits
);
1250 else if (sType
== "gtk-close")
1251 xWindow
= VclPtr
<CloseButton
>::Create(pParent
, nBits
);
1252 else if (sType
== "gtk-help")
1253 xWindow
= VclPtr
<HelpButton
>::Create(pParent
, nBits
);
1257 xWindow
= VclPtr
<PushButton
>::Create(pParent
, nBits
);
1258 xWindow
->SetText(getStockText(sType
));
1263 xWindow
= VclPtr
<PushButton
>::Create(pParent
, nBits
);
1267 VclPtr
<MenuButton
> extractStockAndBuildMenuButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
)
1269 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1271 nBits
|= extractRelief(rMap
);
1273 VclPtr
<MenuButton
> xWindow
= VclPtr
<MenuButton
>::Create(pParent
, nBits
);
1275 if (extractStock(rMap
))
1277 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1283 VclPtr
<Button
> extractStockAndBuildMenuToggleButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
)
1285 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1287 nBits
|= extractRelief(rMap
);
1289 VclPtr
<Button
> xWindow
= VclPtr
<MenuToggleButton
>::Create(pParent
, nBits
);
1291 if (extractStock(rMap
))
1293 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1299 OUString
extractUnit(const OUString
& sPattern
)
1301 OUString
sUnit(sPattern
);
1302 for (sal_Int32 i
= 0; i
< sPattern
.getLength(); ++i
)
1304 if (sPattern
[i
] != '.' && sPattern
[i
] != ',' && sPattern
[i
] != '0')
1306 sUnit
= sPattern
.copy(i
);
1313 int extractDecimalDigits(const OUString
& sPattern
)
1316 bool bAfterPoint
= false;
1317 for (sal_Int32 i
= 0; i
< sPattern
.getLength(); ++i
)
1319 if (sPattern
[i
] == '.' || sPattern
[i
] == ',')
1321 else if (sPattern
[i
] == '0')
1332 FieldUnit
detectMetricUnit(const OUString
& sUnit
)
1334 FieldUnit eUnit
= FieldUnit::NONE
;
1337 eUnit
= FieldUnit::MM
;
1338 else if (sUnit
== "cm")
1339 eUnit
= FieldUnit::CM
;
1340 else if (sUnit
== "m")
1341 eUnit
= FieldUnit::M
;
1342 else if (sUnit
== "km")
1343 eUnit
= FieldUnit::KM
;
1344 else if ((sUnit
== "twips") || (sUnit
== "twip"))
1345 eUnit
= FieldUnit::TWIP
;
1346 else if (sUnit
== "pt")
1347 eUnit
= FieldUnit::POINT
;
1348 else if (sUnit
== "pc")
1349 eUnit
= FieldUnit::PICA
;
1350 else if (sUnit
== "\"" || (sUnit
== "in") || (sUnit
== "inch"))
1351 eUnit
= FieldUnit::INCH
;
1352 else if ((sUnit
== "'") || (sUnit
== "ft") || (sUnit
== "foot") || (sUnit
== "feet"))
1353 eUnit
= FieldUnit::FOOT
;
1354 else if (sUnit
== "mile" || (sUnit
== "miles"))
1355 eUnit
= FieldUnit::MILE
;
1356 else if (sUnit
== "ch")
1357 eUnit
= FieldUnit::CHAR
;
1358 else if (sUnit
== "line")
1359 eUnit
= FieldUnit::LINE
;
1360 else if (sUnit
== "%")
1361 eUnit
= FieldUnit::PERCENT
;
1362 else if ((sUnit
== "pixels") || (sUnit
== "pixel") || (sUnit
== "px"))
1363 eUnit
= FieldUnit::PIXEL
;
1364 else if ((sUnit
== "degrees") || (sUnit
== "degree"))
1365 eUnit
= FieldUnit::DEGREE
;
1366 else if ((sUnit
== "sec") || (sUnit
== "seconds") || (sUnit
== "second"))
1367 eUnit
= FieldUnit::SECOND
;
1368 else if ((sUnit
== "ms") || (sUnit
== "milliseconds") || (sUnit
== "millisecond"))
1369 eUnit
= FieldUnit::MILLISECOND
;
1370 else if (sUnit
!= "0")
1371 eUnit
= FieldUnit::CUSTOM
;
1376 WinBits
extractDeferredBits(VclBuilder::stringmap
&rMap
)
1378 WinBits nBits
= WB_3DLOOK
|WB_HIDE
;
1379 if (extractResizable(rMap
))
1380 nBits
|= WB_SIZEABLE
;
1381 if (extractCloseable(rMap
))
1382 nBits
|= WB_CLOSEABLE
;
1383 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
1384 if (!sBorder
.isEmpty())
1386 if (!extractDecorated(rMap
))
1387 nBits
|= WB_OWNERDRAWDECORATION
;
1388 OUString
sType(extractTypeHint(rMap
));
1389 if (sType
== "utility")
1390 nBits
|= WB_SYSTEMWINDOW
| WB_DIALOGCONTROL
| WB_MOVEABLE
;
1391 else if (sType
== "popup-menu")
1392 nBits
|= WB_SYSTEMWINDOW
| WB_DIALOGCONTROL
| WB_POPUP
;
1393 else if (sType
== "dock")
1394 nBits
|= WB_DOCKABLE
| WB_MOVEABLE
;
1396 nBits
|= WB_MOVEABLE
;
1401 void VclBuilder::extractGroup(const OString
&id
, stringmap
&rMap
)
1403 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("group"));
1404 if (aFind
!= rMap
.end())
1406 OUString sID
= aFind
->second
;
1407 sal_Int32 nDelim
= sID
.indexOf(':');
1409 sID
= sID
.copy(0, nDelim
);
1410 m_pParserState
->m_aGroupMaps
.emplace_back(id
, sID
.toUtf8());
1415 void VclBuilder::connectNumericFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1417 if (!rAdjustment
.isEmpty())
1418 m_pParserState
->m_aNumericFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1421 void VclBuilder::connectFormattedFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1423 if (!rAdjustment
.isEmpty())
1424 m_pParserState
->m_aFormattedFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1427 void VclBuilder::connectTimeFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1429 if (!rAdjustment
.isEmpty())
1430 m_pParserState
->m_aTimeFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1433 void VclBuilder::connectDateFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1435 if (!rAdjustment
.isEmpty())
1436 m_pParserState
->m_aDateFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1439 bool VclBuilder::extractAdjustmentToMap(const OString
& id
, VclBuilder::stringmap
& rMap
, std::vector
<WidgetAdjustmentMap
>& rAdjustmentMap
)
1441 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("adjustment"));
1442 if (aFind
!= rMap
.end())
1444 rAdjustmentMap
.emplace_back(id
, aFind
->second
);
1453 sal_Int32
extractActive(VclBuilder::stringmap
&rMap
)
1455 sal_Int32 nActiveId
= 0;
1456 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("active"));
1457 if (aFind
!= rMap
.end())
1459 nActiveId
= aFind
->second
.toInt32();
1465 bool extractSelectable(VclBuilder::stringmap
&rMap
)
1467 bool bSelectable
= false;
1468 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("selectable"));
1469 if (aFind
!= rMap
.end())
1471 bSelectable
= toBool(aFind
->second
);
1477 OUString
extractAdjustment(VclBuilder::stringmap
&rMap
)
1479 OUString sAdjustment
;
1480 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("adjustment"));
1481 if (aFind
!= rMap
.end())
1483 sAdjustment
= aFind
->second
;
1490 bool extractDrawIndicator(VclBuilder::stringmap
&rMap
)
1492 bool bDrawIndicator
= false;
1493 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("draw-indicator"));
1494 if (aFind
!= rMap
.end())
1496 bDrawIndicator
= toBool(aFind
->second
);
1499 return bDrawIndicator
;
1503 void VclBuilder::extractModel(const OString
&id
, stringmap
&rMap
)
1505 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("model"));
1506 if (aFind
!= rMap
.end())
1508 m_pParserState
->m_aModelMaps
.emplace_back(id
, aFind
->second
,
1509 extractActive(rMap
));
1514 void VclBuilder::extractBuffer(const OString
&id
, stringmap
&rMap
)
1516 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("buffer"));
1517 if (aFind
!= rMap
.end())
1519 m_pParserState
->m_aTextBufferMaps
.emplace_back(id
, aFind
->second
);
1524 void VclBuilder::extractStock(const OString
&id
, stringmap
&rMap
)
1526 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("stock"));
1527 if (aFind
!= rMap
.end())
1530 aInfo
.m_sStock
= aFind
->second
;
1532 aFind
= rMap
.find(OString("icon-size"));
1533 if (aFind
!= rMap
.end())
1535 aInfo
.m_nSize
= aFind
->second
.toInt32();
1538 m_pParserState
->m_aStockMap
[id
] = aInfo
;
1542 void VclBuilder::extractButtonImage(const OString
&id
, stringmap
&rMap
, bool bRadio
)
1544 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("image"));
1545 if (aFind
!= rMap
.end())
1547 m_pParserState
->m_aButtonImageWidgetMaps
.emplace_back(id
, aFind
->second
, bRadio
);
1552 void VclBuilder::extractMnemonicWidget(const OString
&rLabelID
, stringmap
&rMap
)
1554 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("mnemonic-widget"));
1555 if (aFind
!= rMap
.end())
1557 OUString sID
= aFind
->second
;
1558 sal_Int32 nDelim
= sID
.indexOf(':');
1560 sID
= sID
.copy(0, nDelim
);
1561 m_pParserState
->m_aMnemonicWidgetMaps
.emplace_back(rLabelID
, sID
);
1566 vcl::Window
* VclBuilder::prepareWidgetOwnScrolling(vcl::Window
*pParent
, WinBits
&rWinStyle
)
1568 //For Widgets that manage their own scrolling, if one appears as a child of
1569 //a scrolling window shoehorn that scrolling settings to this widget and
1570 //return the real parent to use
1571 if (pParent
&& pParent
->GetType() == WindowType::SCROLLWINDOW
)
1573 WinBits nScrollBits
= pParent
->GetStyle();
1574 nScrollBits
&= (WB_AUTOHSCROLL
|WB_HSCROLL
|WB_AUTOVSCROLL
|WB_VSCROLL
);
1575 rWinStyle
|= nScrollBits
| WB_BORDER
;
1576 pParent
= pParent
->GetParent();
1582 void VclBuilder::cleanupWidgetOwnScrolling(vcl::Window
*pScrollParent
, vcl::Window
*pWindow
, stringmap
&rMap
)
1584 //remove the redundant scrolling parent
1585 sal_Int32 nWidthReq
= pScrollParent
->get_width_request();
1586 rMap
[OString("width-request")] = OUString::number(nWidthReq
);
1587 sal_Int32 nHeightReq
= pScrollParent
->get_height_request();
1588 rMap
[OString("height-request")] = OUString::number(nHeightReq
);
1590 m_pParserState
->m_aRedundantParentWidgets
[pScrollParent
] = pWindow
;
1593 #ifndef DISABLE_DYNLOADING
1595 extern "C" { static void thisModule() {} }
1597 // Don't unload the module on destruction
1598 class NoAutoUnloadModule
: public osl::Module
1601 ~NoAutoUnloadModule() { release(); }
1604 typedef std::map
<OUString
, std::shared_ptr
<NoAutoUnloadModule
>> ModuleMap
;
1605 static ModuleMap g_aModuleMap
;
1607 #if ENABLE_MERGELIBS
1608 static std::shared_ptr
<NoAutoUnloadModule
> g_pMergedLib
= std::make_shared
<NoAutoUnloadModule
>();
1611 #ifndef SAL_DLLPREFIX
1612 # define SAL_DLLPREFIX ""
1617 void VclBuilder::preload()
1619 #ifndef DISABLE_DYNLOADING
1621 #if ENABLE_MERGELIBS
1622 g_pMergedLib
->loadRelative(&thisModule
, SVLIBRARY("merged"));
1624 // find -name '*ui*' | xargs grep 'class=".*lo-' |
1625 // sed 's/.*class="//' | sed 's/-.*$//' | sort | uniq
1626 static const char *aWidgetLibs
[] = {
1627 "sfxlo", "svtlo", "svxcorelo", "foruilo",
1628 "vcllo", "svxlo", "cuilo", "swlo",
1629 "swuilo", "sclo", "sdlo", "chartcontrollerlo",
1630 "smlo", "scuilo", "basctllo", "sduilo",
1631 "scnlo", "xsltdlglo", "pcrlo" // "dbulo"
1633 for (const auto & lib
: aWidgetLibs
)
1635 std::unique_ptr
<NoAutoUnloadModule
> pModule(new NoAutoUnloadModule
);
1636 OUString sModule
= SAL_DLLPREFIX
+ OUString::createFromAscii(lib
) + SAL_DLLEXTENSION
;
1637 if (pModule
->loadRelative(&thisModule
, sModule
))
1638 g_aModuleMap
.insert(std::make_pair(sModule
, std::move(pModule
)));
1640 #endif // ENABLE_MERGELIBS
1641 #endif // DISABLE_DYNLOADING
1644 #if defined DISABLE_DYNLOADING && !HAVE_FEATURE_DESKTOP
1645 extern "C" VclBuilder::customMakeWidget
lo_get_custom_widget_func(const char* name
);
1650 // Takes a string like "sfxlo-SidebarToolBox"
1651 VclBuilder::customMakeWidget
GetCustomMakeWidget(const OString
& name
)
1653 VclBuilder::customMakeWidget pFunction
= nullptr;
1654 if (sal_Int32 nDelim
= name
.indexOf('-'); nDelim
!= -1)
1656 const OUString
sFunction("make"
1657 + OStringToOUString(name
.copy(nDelim
+ 1), RTL_TEXTENCODING_UTF8
));
1659 #ifndef DISABLE_DYNLOADING
1660 const OUString sModule
= SAL_DLLPREFIX
1661 + OStringToOUString(name
.copy(0, nDelim
), RTL_TEXTENCODING_UTF8
)
1663 ModuleMap::iterator aI
= g_aModuleMap
.find(sModule
);
1664 if (aI
== g_aModuleMap
.end())
1666 std::shared_ptr
<NoAutoUnloadModule
> pModule
;
1667 #if ENABLE_MERGELIBS
1668 if (!g_pMergedLib
->is())
1669 g_pMergedLib
->loadRelative(&thisModule
, SVLIBRARY("merged"));
1670 if ((pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1671 g_pMergedLib
->getFunctionSymbol(sFunction
))))
1672 pModule
= g_pMergedLib
;
1676 pModule
.reset(new NoAutoUnloadModule
);
1677 bool ok
= pModule
->loadRelative(&thisModule
, sModule
);
1678 assert(ok
&& "bad module name in .ui");
1680 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1681 pModule
->getFunctionSymbol(sFunction
));
1683 g_aModuleMap
.insert(std::make_pair(sModule
, pModule
));
1686 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1687 aI
->second
->getFunctionSymbol(sFunction
));
1688 #elif !HAVE_FEATURE_DESKTOP
1689 pFunction
= lo_get_custom_widget_func(sFunction
.toUtf8().getStr());
1690 SAL_WARN_IF(!pFunction
, "vcl.layout", "Could not find " << sFunction
);
1693 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1694 osl_getFunctionSymbol((oslModule
)RTLD_DEFAULT
, sFunction
.pData
));
1701 VclPtr
<vcl::Window
> VclBuilder::makeObject(vcl::Window
*pParent
, const OString
&name
, const OString
&id
,
1704 bool bIsPlaceHolder
= name
.isEmpty();
1705 bool bVertical
= false;
1707 if (pParent
&& (pParent
->GetType() == WindowType::TABCONTROL
||
1708 pParent
->GetType() == WindowType::VERTICALTABCONTROL
))
1710 bool bTopLevel(name
== "GtkDialog" || name
== "GtkMessageDialog" ||
1711 name
== "GtkWindow" || name
== "GtkPopover" || name
== "GtkAssistant");
1714 if (pParent
->GetType() == WindowType::TABCONTROL
)
1716 //We have to add a page
1717 //make default pageid == position
1718 TabControl
*pTabControl
= static_cast<TabControl
*>(pParent
);
1719 sal_uInt16 nNewPageCount
= pTabControl
->GetPageCount()+1;
1720 sal_uInt16 nNewPageId
= nNewPageCount
;
1721 pTabControl
->InsertPage(nNewPageId
, OUString());
1722 pTabControl
->SetCurPageId(nNewPageId
);
1723 SAL_WARN_IF(bIsPlaceHolder
, "vcl.layout", "we should have no placeholders for tabpages");
1724 if (!bIsPlaceHolder
)
1726 VclPtrInstance
<TabPage
> pPage(pTabControl
);
1729 //Make up a name for it
1730 OString sTabPageId
= get_by_window(pParent
) +
1732 OString::number(nNewPageCount
);
1733 m_aChildren
.emplace_back(sTabPageId
, pPage
, false);
1734 pPage
->SetHelpId(m_sHelpRoot
+ sTabPageId
);
1738 pTabControl
->SetTabPage(nNewPageId
, pPage
);
1743 VerticalTabControl
*pTabControl
= static_cast<VerticalTabControl
*>(pParent
);
1744 SAL_WARN_IF(bIsPlaceHolder
, "vcl.layout", "we should have no placeholders for tabpages");
1745 if (!bIsPlaceHolder
)
1746 pParent
= pTabControl
->GetPageParent();
1751 if (bIsPlaceHolder
|| name
== "GtkTreeSelection")
1754 extractButtonImage(id
, rMap
, name
== "GtkRadioButton");
1756 VclPtr
<vcl::Window
> xWindow
;
1757 if (name
== "GtkDialog" || name
== "GtkAboutDialog" || name
== "GtkAssistant")
1759 // WB_ALLOWMENUBAR because we don't know in advance if we will encounter
1760 // a menubar, and menubars need a BorderWindow in the toplevel, and
1761 // such border windows need to be in created during the dialog ctor
1762 WinBits nBits
= WB_MOVEABLE
|WB_3DLOOK
|WB_ALLOWMENUBAR
;
1763 if (extractResizable(rMap
))
1764 nBits
|= WB_SIZEABLE
;
1765 if (extractCloseable(rMap
))
1766 nBits
|= WB_CLOSEABLE
;
1767 Dialog::InitFlag eInit
= !pParent
? Dialog::InitFlag::NoParent
: Dialog::InitFlag::Default
;
1768 if (name
== "GtkAssistant")
1769 xWindow
= VclPtr
<vcl::RoadmapWizard
>::Create(pParent
, nBits
, eInit
);
1770 else if (name
== "GtkAboutDialog")
1771 xWindow
= VclPtr
<vcl::AboutDialog
>::Create(pParent
, nBits
, eInit
);
1773 xWindow
= VclPtr
<Dialog
>::Create(pParent
, nBits
, eInit
);
1774 #if HAVE_FEATURE_DESKTOP
1775 if (!m_bLegacy
&& !extractModal(rMap
))
1776 xWindow
->SetType(WindowType::MODELESSDIALOG
);
1779 else if (name
== "GtkMessageDialog")
1781 WinBits nBits
= WB_MOVEABLE
|WB_3DLOOK
|WB_CLOSEABLE
;
1782 if (extractResizable(rMap
))
1783 nBits
|= WB_SIZEABLE
;
1784 VclPtr
<MessageDialog
> xDialog(VclPtr
<MessageDialog
>::Create(pParent
, nBits
));
1785 m_pParserState
->m_aMessageDialogs
.push_back(xDialog
);
1788 xWindow
->set_border_width(3);
1790 xWindow
->set_border_width(12);
1793 else if (name
== "GtkBox" || name
== "GtkStatusbar")
1795 bVertical
= extractOrientation(rMap
);
1797 xWindow
= VclPtr
<VclVBox
>::Create(pParent
);
1799 xWindow
= VclPtr
<VclHBox
>::Create(pParent
);
1801 else if (name
== "GtkPaned")
1803 bVertical
= extractOrientation(rMap
);
1805 xWindow
= VclPtr
<VclVPaned
>::Create(pParent
);
1807 xWindow
= VclPtr
<VclHPaned
>::Create(pParent
);
1809 else if (name
== "GtkHBox")
1810 xWindow
= VclPtr
<VclHBox
>::Create(pParent
);
1811 else if (name
== "GtkVBox")
1812 xWindow
= VclPtr
<VclVBox
>::Create(pParent
);
1813 else if (name
== "GtkButtonBox")
1815 bVertical
= extractOrientation(rMap
);
1817 xWindow
= VclPtr
<VclVButtonBox
>::Create(pParent
);
1819 xWindow
= VclPtr
<VclHButtonBox
>::Create(pParent
);
1821 else if (name
== "GtkHButtonBox")
1822 xWindow
= VclPtr
<VclHButtonBox
>::Create(pParent
);
1823 else if (name
== "GtkVButtonBox")
1824 xWindow
= VclPtr
<VclVButtonBox
>::Create(pParent
);
1825 else if (name
== "GtkGrid")
1826 xWindow
= VclPtr
<VclGrid
>::Create(pParent
);
1827 else if (name
== "GtkFrame")
1828 xWindow
= VclPtr
<VclFrame
>::Create(pParent
);
1829 else if (name
== "GtkExpander")
1831 VclPtrInstance
<VclExpander
> pExpander(pParent
);
1832 m_pParserState
->m_aExpanderWidgets
.push_back(pExpander
);
1833 xWindow
= pExpander
;
1835 else if (name
== "GtkAlignment")
1836 xWindow
= VclPtr
<VclAlignment
>::Create(pParent
);
1837 else if (name
== "GtkButton" || (!m_bLegacy
&& name
== "GtkToggleButton"))
1839 VclPtr
<Button
> xButton
;
1840 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
1841 if (sMenu
.isEmpty())
1842 xButton
= extractStockAndBuildPushButton(pParent
, rMap
, name
== "GtkToggleButton", m_bLegacy
);
1845 assert(m_bLegacy
&& "use GtkMenuButton");
1846 xButton
= extractStockAndBuildMenuButton(pParent
, rMap
);
1847 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1849 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1850 setupFromActionName(xButton
, rMap
, m_xFrame
);
1853 else if (name
== "GtkMenuButton")
1855 VclPtr
<MenuButton
> xButton
= extractStockAndBuildMenuButton(pParent
, rMap
);
1856 OUString sMenu
= extractPopupMenu(rMap
);
1857 if (!sMenu
.isEmpty())
1858 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1859 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1860 xButton
->SetAccessibleRole(css::accessibility::AccessibleRole::BUTTON_MENU
);
1862 if (!extractDrawIndicator(rMap
))
1863 xButton
->SetDropDown(PushButtonDropdownStyle::NONE
);
1865 setupFromActionName(xButton
, rMap
, m_xFrame
);
1868 else if (name
== "GtkToggleButton" && m_bLegacy
)
1870 VclPtr
<Button
> xButton
;
1871 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
1872 assert(sMenu
.getLength() && "not implemented yet");
1873 xButton
= extractStockAndBuildMenuToggleButton(pParent
, rMap
);
1874 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1875 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1876 setupFromActionName(xButton
, rMap
, m_xFrame
);
1879 else if (name
== "GtkRadioButton")
1881 extractGroup(id
, rMap
);
1882 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1883 OUString sWrap
= BuilderUtils::extractCustomProperty(rMap
);
1884 if (!sWrap
.isEmpty())
1885 nBits
|= WB_WORDBREAK
;
1886 VclPtr
<RadioButton
> xButton
= VclPtr
<RadioButton
>::Create(pParent
, nBits
);
1887 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1890 if (::extractStock(rMap
))
1892 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1895 else if (name
== "GtkCheckButton")
1897 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1898 OUString sWrap
= BuilderUtils::extractCustomProperty(rMap
);
1899 if (!sWrap
.isEmpty())
1900 nBits
|= WB_WORDBREAK
;
1901 //maybe always import as TriStateBox and enable/disable tristate
1902 bool bIsTriState
= extractInconsistent(rMap
);
1903 VclPtr
<CheckBox
> xCheckBox
;
1904 if (bIsTriState
&& m_bLegacy
)
1905 xCheckBox
= VclPtr
<TriStateBox
>::Create(pParent
, nBits
);
1907 xCheckBox
= VclPtr
<CheckBox
>::Create(pParent
, nBits
);
1910 xCheckBox
->EnableTriState(true);
1911 xCheckBox
->SetState(TRISTATE_INDET
);
1913 xCheckBox
->SetImageAlign(ImageAlign::Left
); //default to left
1915 xWindow
= xCheckBox
;
1917 if (::extractStock(rMap
))
1919 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1922 else if (name
== "GtkSpinButton")
1924 OUString sAdjustment
= extractAdjustment(rMap
);
1925 OUString sPattern
= BuilderUtils::extractCustomProperty(rMap
);
1926 OUString sUnit
= extractUnit(sPattern
);
1928 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_BORDER
|WB_3DLOOK
;
1929 if (!id
.endsWith("-nospin"))
1930 nBits
|= WB_SPIN
| WB_REPEAT
;
1932 if (sPattern
.isEmpty())
1934 SAL_INFO("vcl.layout", "making numeric field for " << name
<< " " << sUnit
);
1937 connectNumericFormatterAdjustment(id
, sAdjustment
);
1938 xWindow
= VclPtr
<NumericField
>::Create(pParent
, nBits
);
1942 connectFormattedFormatterAdjustment(id
, sAdjustment
);
1943 VclPtrInstance
<FormattedField
> xField(pParent
, nBits
);
1944 xField
->SetMinValue(0);
1950 if (sPattern
== "hh:mm")
1952 connectTimeFormatterAdjustment(id
, sAdjustment
);
1953 SAL_INFO("vcl.layout", "making time field for " << name
<< " " << sUnit
);
1954 xWindow
= VclPtr
<TimeField
>::Create(pParent
, nBits
);
1956 else if (sPattern
== "yy:mm:dd")
1958 connectDateFormatterAdjustment(id
, sAdjustment
);
1959 SAL_INFO("vcl.layout", "making date field for " << name
<< " " << sUnit
);
1960 xWindow
= VclPtr
<DateField
>::Create(pParent
, nBits
);
1964 connectNumericFormatterAdjustment(id
, sAdjustment
);
1965 FieldUnit eUnit
= detectMetricUnit(sUnit
);
1966 SAL_INFO("vcl.layout", "making metric field for " << name
<< " " << sUnit
);
1967 VclPtrInstance
<MetricField
> xField(pParent
, nBits
);
1968 xField
->SetUnit(eUnit
);
1969 if (eUnit
== FieldUnit::CUSTOM
)
1970 xField
->SetCustomUnitText(sUnit
);
1975 else if (name
== "GtkLinkButton")
1976 xWindow
= VclPtr
<FixedHyperlink
>::Create(pParent
, WB_CENTER
|WB_VCENTER
|WB_3DLOOK
|WB_NOLABEL
);
1977 else if (name
== "GtkComboBox" || name
== "GtkComboBoxText")
1979 OUString sPattern
= BuilderUtils::extractCustomProperty(rMap
);
1980 extractModel(id
, rMap
);
1982 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1984 bool bDropdown
= BuilderUtils::extractDropdown(rMap
);
1987 nBits
|= WB_DROPDOWN
;
1989 if (!sPattern
.isEmpty())
1991 OUString sAdjustment
= extractAdjustment(rMap
);
1992 connectNumericFormatterAdjustment(id
, sAdjustment
);
1993 OUString sUnit
= extractUnit(sPattern
);
1994 FieldUnit eUnit
= detectMetricUnit(sUnit
);
1995 SAL_WARN("vcl.layout", "making metric box for type: " << name
1996 << " unit: " << sUnit
1998 << " use a VclComboBoxNumeric instead");
1999 VclPtrInstance
<MetricBox
> xBox(pParent
, nBits
);
2000 xBox
->EnableAutoSize(true);
2001 xBox
->SetUnit(eUnit
);
2002 xBox
->SetDecimalDigits(extractDecimalDigits(sPattern
));
2003 if (eUnit
== FieldUnit::CUSTOM
)
2004 xBox
->SetCustomUnitText(sUnit
);
2007 else if (extractEntry(rMap
))
2009 VclPtrInstance
<ComboBox
> xComboBox(pParent
, nBits
);
2010 xComboBox
->EnableAutoSize(true);
2011 xWindow
= xComboBox
;
2015 VclPtrInstance
<ListBox
> xListBox(pParent
, nBits
|WB_SIMPLEMODE
);
2016 xListBox
->EnableAutoSize(true);
2020 else if (name
== "VclComboBoxNumeric")
2022 OUString sPattern
= BuilderUtils::extractCustomProperty(rMap
);
2023 OUString sAdjustment
= extractAdjustment(rMap
);
2024 extractModel(id
, rMap
);
2026 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
2028 bool bDropdown
= BuilderUtils::extractDropdown(rMap
);
2031 nBits
|= WB_DROPDOWN
;
2033 if (!sPattern
.isEmpty())
2035 connectNumericFormatterAdjustment(id
, sAdjustment
);
2036 OUString sUnit
= extractUnit(sPattern
);
2037 FieldUnit eUnit
= detectMetricUnit(sUnit
);
2038 SAL_INFO("vcl.layout", "making metric box for " << name
<< " " << sUnit
);
2039 VclPtrInstance
<MetricBox
> xBox(pParent
, nBits
);
2040 xBox
->EnableAutoSize(true);
2041 xBox
->SetUnit(eUnit
);
2042 xBox
->SetDecimalDigits(extractDecimalDigits(sPattern
));
2043 if (eUnit
== FieldUnit::CUSTOM
)
2044 xBox
->SetCustomUnitText(sUnit
);
2049 SAL_INFO("vcl.layout", "making numeric box for " << name
);
2050 connectNumericFormatterAdjustment(id
, sAdjustment
);
2051 VclPtrInstance
<NumericBox
> xBox(pParent
, nBits
);
2053 xBox
->EnableAutoSize(true);
2057 else if (name
== "GtkIconView")
2059 assert(rMap
.find(OString("model")) != rMap
.end() && "GtkIconView must have a model");
2061 //window we want to apply the packing props for this GtkIconView to
2062 VclPtr
<vcl::Window
> xWindowForPackingProps
;
2063 extractModel(id
, rMap
);
2064 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
2065 //IconView manages its own scrolling,
2066 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
2067 if (pRealParent
!= pParent
)
2068 nWinStyle
|= WB_BORDER
;
2070 VclPtr
<IconView
> xBox
= VclPtr
<IconView
>::Create(pRealParent
, nWinStyle
);
2071 xWindowForPackingProps
= xBox
;
2074 xBox
->SetNoAutoCurEntry(true);
2075 xBox
->SetQuickSearch(true);
2077 if (pRealParent
!= pParent
)
2078 cleanupWidgetOwnScrolling(pParent
, xWindowForPackingProps
, rMap
);
2080 else if (name
== "GtkTreeView")
2084 assert(rMap
.find(OString("model")) != rMap
.end() && "GtkTreeView must have a model");
2087 //window we want to apply the packing props for this GtkTreeView to
2088 VclPtr
<vcl::Window
> xWindowForPackingProps
;
2090 //a) make SvHeaderTabListBox/SvTabListBox the default target for GtkTreeView
2091 //b) remove the non-drop down mode of ListBox and convert
2092 // everything over to SvHeaderTabListBox/SvTabListBox
2093 //c) remove the users of makeSvTabListBox and makeSvTreeListBox
2094 extractModel(id
, rMap
);
2095 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
2098 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
2099 if (!sBorder
.isEmpty())
2100 nWinStyle
|= WB_BORDER
;
2104 nWinStyle
|= WB_HASBUTTONS
| WB_HASBUTTONSATROOT
;
2106 //ListBox/SvHeaderTabListBox manages its own scrolling,
2107 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
2108 if (pRealParent
!= pParent
)
2109 nWinStyle
|= WB_BORDER
;
2112 xWindow
= VclPtr
<ListBox
>::Create(pRealParent
, nWinStyle
| WB_SIMPLEMODE
);
2113 xWindowForPackingProps
= xWindow
;
2117 VclPtr
<SvTabListBox
> xBox
;
2118 bool bHeadersVisible
= extractHeadersVisible(rMap
);
2119 if (bHeadersVisible
)
2121 VclPtr
<VclVBox
> xContainer
= VclPtr
<VclVBox
>::Create(pRealParent
);
2122 OString
containerid(id
+ "-container");
2123 xContainer
->SetHelpId(m_sHelpRoot
+ containerid
);
2124 m_aChildren
.emplace_back(containerid
, xContainer
, true);
2126 VclPtrInstance
<HeaderBar
> xHeader(xContainer
, WB_BUTTONSTYLE
| WB_BORDER
| WB_TABSTOP
| WB_3DLOOK
);
2127 xHeader
->set_width_request(0); // let the headerbar width not affect the size request
2128 OString
headerid(id
+ "-header");
2129 xHeader
->SetHelpId(m_sHelpRoot
+ headerid
);
2130 m_aChildren
.emplace_back(headerid
, xHeader
, true);
2132 VclPtr
<LclHeaderTabListBox
> xHeaderBox
= VclPtr
<LclHeaderTabListBox
>::Create(xContainer
, nWinStyle
);
2133 xHeaderBox
->InitHeaderBar(xHeader
);
2134 xContainer
->set_expand(true);
2138 xWindowForPackingProps
= xContainer
;
2142 xBox
= VclPtr
<LclTabListBox
>::Create(pRealParent
, nWinStyle
);
2143 xWindowForPackingProps
= xBox
;
2146 xBox
->SetNoAutoCurEntry(true);
2147 xBox
->SetQuickSearch(true);
2148 xBox
->SetSpaceBetweenEntries(3);
2149 xBox
->SetEntryHeight(16);
2150 xBox
->SetHighlightRange(); // select over the whole width
2152 if (pRealParent
!= pParent
)
2153 cleanupWidgetOwnScrolling(pParent
, xWindowForPackingProps
, rMap
);
2155 else if (name
== "GtkTreeViewColumn")
2159 SvHeaderTabListBox
* pTreeView
= dynamic_cast<SvHeaderTabListBox
*>(pParent
);
2160 if (HeaderBar
* pHeaderBar
= pTreeView
? pTreeView
->GetHeaderBar() : nullptr)
2162 HeaderBarItemBits nBits
= HeaderBarItemBits::LEFTIMAGE
;
2163 if (extractClickable(rMap
))
2164 nBits
|= HeaderBarItemBits::CLICKABLE
;
2165 if (extractSortIndicator(rMap
))
2166 nBits
|= HeaderBarItemBits::DOWNARROW
;
2167 float fAlign
= extractAlignment(rMap
);
2169 nBits
|= HeaderBarItemBits::LEFT
;
2170 else if (fAlign
== 1.0)
2171 nBits
|= HeaderBarItemBits::RIGHT
;
2172 else if (fAlign
== 0.5)
2173 nBits
|= HeaderBarItemBits::CENTER
;
2174 auto nItemId
= pHeaderBar
->GetItemCount() + 1;
2175 OUString
sTitle(extractTitle(rMap
));
2176 pHeaderBar
->InsertItem(nItemId
, sTitle
, 100, nBits
);
2180 else if (name
== "GtkLabel")
2182 WinBits nWinStyle
= WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
2183 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
2184 if (!sBorder
.isEmpty())
2185 nWinStyle
|= WB_BORDER
;
2186 extractMnemonicWidget(id
, rMap
);
2187 if (extractSelectable(rMap
))
2188 xWindow
= VclPtr
<SelectableFixedText
>::Create(pParent
, nWinStyle
);
2190 xWindow
= VclPtr
<FixedText
>::Create(pParent
, nWinStyle
);
2192 else if (name
== "GtkImage")
2194 extractStock(id
, rMap
);
2195 xWindow
= VclPtr
<FixedImage
>::Create(pParent
, WB_CENTER
|WB_VCENTER
|WB_3DLOOK
|WB_SCALE
);
2196 //such parentless GtkImages are temps used to set icons on buttons
2197 //default them to hidden to stop e.g. insert->index entry flicking temp
2198 //full screen windows
2201 rMap
["visible"] = "false";
2204 else if (name
== "GtkSeparator")
2206 bVertical
= extractOrientation(rMap
);
2207 xWindow
= VclPtr
<FixedLine
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2209 else if (name
== "GtkScrollbar")
2211 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aScrollAdjustmentMaps
);
2212 bVertical
= extractOrientation(rMap
);
2213 xWindow
= VclPtr
<ScrollBar
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2215 else if (name
== "GtkProgressBar")
2217 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aScrollAdjustmentMaps
);
2218 bVertical
= extractOrientation(rMap
);
2219 xWindow
= VclPtr
<ProgressBar
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2221 else if (name
== "GtkScrolledWindow")
2223 xWindow
= VclPtr
<VclScrolledWindow
>::Create(pParent
);
2225 else if (name
== "GtkViewport")
2227 xWindow
= VclPtr
<VclViewport
>::Create(pParent
);
2229 else if (name
== "GtkEventBox")
2231 xWindow
= VclPtr
<VclEventBox
>::Create(pParent
);
2233 else if (name
== "GtkEntry")
2235 xWindow
= VclPtr
<Edit
>::Create(pParent
, WB_LEFT
|WB_VCENTER
|WB_BORDER
|WB_3DLOOK
);
2236 BuilderUtils::ensureDefaultWidthChars(rMap
);
2238 else if (name
== "GtkNotebook")
2240 if (!extractVerticalTabPos(rMap
))
2241 xWindow
= VclPtr
<TabControl
>::Create(pParent
, WB_STDTABCONTROL
|WB_3DLOOK
);
2243 xWindow
= VclPtr
<VerticalTabControl
>::Create(pParent
);
2245 else if (name
== "GtkDrawingArea")
2247 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
2248 xWindow
= VclPtr
<VclDrawingArea
>::Create(pParent
, sBorder
.isEmpty() ? WB_TABSTOP
: WB_BORDER
| WB_TABSTOP
);
2250 else if (name
== "GtkTextView")
2252 extractBuffer(id
, rMap
);
2254 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
;
2257 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
2258 if (!sBorder
.isEmpty())
2259 nWinStyle
|= WB_BORDER
;
2261 //VclMultiLineEdit manages its own scrolling,
2262 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
2263 if (pRealParent
!= pParent
)
2264 nWinStyle
|= WB_BORDER
;
2265 xWindow
= VclPtr
<VclMultiLineEdit
>::Create(pRealParent
, nWinStyle
);
2266 if (pRealParent
!= pParent
)
2267 cleanupWidgetOwnScrolling(pParent
, xWindow
, rMap
);
2269 else if (name
== "GtkSpinner")
2271 xWindow
= VclPtr
<Throbber
>::Create(pParent
, WB_3DLOOK
);
2273 else if (name
== "GtkScale")
2275 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aSliderAdjustmentMaps
);
2276 bool bDrawValue
= extractDrawValue(rMap
);
2279 OUString sValuePos
= extractValuePos(rMap
);
2282 bVertical
= extractOrientation(rMap
);
2284 WinBits nWinStyle
= bVertical
? WB_VERT
: WB_HORZ
;
2286 xWindow
= VclPtr
<Slider
>::Create(pParent
, nWinStyle
);
2288 else if (name
== "GtkToolbar")
2290 xWindow
= VclPtr
<ToolBox
>::Create(pParent
, WB_3DLOOK
| WB_TABSTOP
);
2292 else if(name
== "NotebookBarAddonsToolMergePoint")
2294 customMakeWidget pFunction
= GetCustomMakeWidget("sfxlo-NotebookbarToolBox");
2295 if(pFunction
!= nullptr)
2296 NotebookBarAddonsMerger::MergeNotebookBarAddons(pParent
, pFunction
, m_xFrame
, *m_pNotebookBarAddonsItem
, rMap
);
2299 else if (name
== "GtkToolButton" || name
== "GtkMenuToolButton" ||
2300 name
== "GtkToggleToolButton" || name
== "GtkRadioToolButton")
2302 ToolBox
*pToolBox
= dynamic_cast<ToolBox
*>(pParent
);
2305 OUString
aCommand(extractActionName(rMap
));
2307 sal_uInt16 nItemId
= 0;
2308 ToolBoxItemBits nBits
= ToolBoxItemBits::NONE
;
2309 if (name
== "GtkMenuToolButton")
2310 nBits
|= ToolBoxItemBits::DROPDOWN
;
2311 else if (name
== "GtkToggleToolButton")
2312 nBits
|= ToolBoxItemBits::AUTOCHECK
| ToolBoxItemBits::CHECKABLE
;
2313 else if (name
== "GtkRadioToolButton")
2314 nBits
|= ToolBoxItemBits::AUTOCHECK
| ToolBoxItemBits::RADIOCHECK
;
2316 if (!aCommand
.isEmpty() && m_xFrame
.is())
2318 pToolBox
->InsertItem(aCommand
, m_xFrame
, nBits
, extractSizeRequest(rMap
));
2319 nItemId
= pToolBox
->GetItemId(aCommand
);
2323 nItemId
= pToolBox
->GetItemCount() + 1;
2324 //TODO: ImplToolItems::size_type -> sal_uInt16!
2325 pToolBox
->InsertItem(nItemId
, extractLabel(rMap
), nBits
);
2326 if (aCommand
.isEmpty() && !m_bLegacy
)
2327 aCommand
= OUString::fromUtf8(id
);
2328 pToolBox
->SetItemCommand(nItemId
, aCommand
);
2331 pToolBox
->SetHelpId(nItemId
, m_sHelpRoot
+ id
);
2332 OUString
sTooltip(extractTooltipText(rMap
));
2333 if (!sTooltip
.isEmpty())
2334 pToolBox
->SetQuickHelpText(nItemId
, sTooltip
);
2336 OUString
sIconName(extractIconName(rMap
));
2337 if (!sIconName
.isEmpty())
2338 pToolBox
->SetItemImage(nItemId
, FixedImage::loadThemeImage(sIconName
));
2340 if (!extractVisible(rMap
))
2341 pToolBox
->HideItem(nItemId
);
2343 m_pParserState
->m_nLastToolbarId
= nItemId
;
2345 return nullptr; // no widget to be created
2348 else if (name
== "GtkSeparatorToolItem")
2350 ToolBox
*pToolBox
= dynamic_cast<ToolBox
*>(pParent
);
2353 pToolBox
->InsertSeparator();
2354 return nullptr; // no widget to be created
2357 else if (name
== "GtkWindow")
2359 WinBits nBits
= extractDeferredBits(rMap
);
2360 if (nBits
& WB_DOCKABLE
)
2361 xWindow
= VclPtr
<DockingWindow
>::Create(pParent
, nBits
|WB_MOVEABLE
);
2363 xWindow
= VclPtr
<FloatingWindow
>::Create(pParent
, nBits
|WB_MOVEABLE
);
2365 else if (name
== "GtkPopover")
2367 WinBits nBits
= extractDeferredBits(rMap
);
2368 xWindow
= VclPtr
<DockingWindow
>::Create(pParent
, nBits
|WB_DOCKABLE
|WB_MOVEABLE
);
2370 else if (name
== "GtkCalendar")
2372 WinBits nBits
= extractDeferredBits(rMap
);
2373 xWindow
= VclPtr
<Calendar
>::Create(pParent
, nBits
);
2377 if (customMakeWidget pFunction
= GetCustomMakeWidget(name
))
2379 pFunction(xWindow
, pParent
, rMap
);
2380 if (xWindow
->GetType() == WindowType::PUSHBUTTON
)
2381 setupFromActionName(static_cast<Button
*>(xWindow
.get()), rMap
, m_xFrame
);
2382 else if (xWindow
->GetType() == WindowType::MENUBUTTON
)
2384 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
2385 if (!sMenu
.isEmpty())
2386 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
2387 setupFromActionName(static_cast<Button
*>(xWindow
.get()), rMap
, m_xFrame
);
2391 SAL_INFO_IF(!xWindow
, "vcl.layout", "probably need to implement " << name
<< " or add a make" << name
<< " function");
2394 xWindow
->SetHelpId(m_sHelpRoot
+ id
);
2395 SAL_INFO("vcl.layout", "for " << name
<<
2396 ", created " << xWindow
.get() << " child of " <<
2397 pParent
<< "(" << xWindow
->ImplGetWindowImpl()->mpParent
.get() << "/" <<
2398 xWindow
->ImplGetWindowImpl()->mpRealParent
.get() << "/" <<
2399 xWindow
->ImplGetWindowImpl()->mpBorderWindow
.get() << ") with helpid " <<
2400 xWindow
->GetHelpId());
2401 m_aChildren
.emplace_back(id
, xWindow
, bVertical
);
2408 //return true for window types which exist in vcl but are not themselves
2409 //represented in the .ui format, i.e. only their children exist.
2410 bool isConsideredGtkPseudo(vcl::Window
const *pWindow
)
2412 return pWindow
->GetType() == WindowType::TABPAGE
;
2416 //Any properties from .ui load we couldn't set because of potential virtual methods
2417 //during ctor are applied here
2418 void VclBuilder::setDeferredProperties()
2420 if (!m_bToplevelHasDeferredProperties
)
2422 stringmap aDeferredProperties
;
2423 aDeferredProperties
.swap(m_aDeferredProperties
);
2424 m_bToplevelHasDeferredProperties
= false;
2425 BuilderUtils::set_properties(m_pParent
, aDeferredProperties
);
2428 namespace BuilderUtils
2430 void set_properties(vcl::Window
*pWindow
, const VclBuilder::stringmap
&rProps
)
2432 for (auto const& prop
: rProps
)
2434 const OString
&rKey
= prop
.first
;
2435 const OUString
&rValue
= prop
.second
;
2436 pWindow
->set_property(rKey
, rValue
);
2440 OUString
convertMnemonicMarkup(const OUString
&rIn
)
2442 OUStringBuffer
aRet(rIn
);
2443 for (sal_Int32 nI
= 0; nI
< aRet
.getLength(); ++nI
)
2445 if (aRet
[nI
] == '_' && nI
+1 < aRet
.getLength())
2447 if (aRet
[nI
+1] != '_')
2448 aRet
[nI
] = MNEMONIC_CHAR
;
2454 return aRet
.makeStringAndClear();
2457 OUString
extractCustomProperty(VclBuilder::stringmap
&rMap
)
2459 OUString sCustomProperty
;
2460 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("customproperty"));
2461 if (aFind
!= rMap
.end())
2463 sCustomProperty
= aFind
->second
;
2466 return sCustomProperty
;
2469 FieldUnit
detectUnit(OUString
const& rString
)
2471 OUString
const unit(extractUnit(rString
));
2472 return detectMetricUnit(unit
);
2475 void ensureDefaultWidthChars(VclBuilder::stringmap
&rMap
)
2477 OString
sWidthChars("width-chars");
2478 VclBuilder::stringmap::iterator aFind
= rMap
.find(sWidthChars
);
2479 if (aFind
== rMap
.end())
2480 rMap
[sWidthChars
] = "25";
2483 bool extractDropdown(VclBuilder::stringmap
&rMap
)
2485 bool bDropdown
= true;
2486 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("dropdown"));
2487 if (aFind
!= rMap
.end())
2489 bDropdown
= toBool(aFind
->second
);
2495 void reorderWithinParent(vcl::Window
&rWindow
, sal_uInt16 nNewPosition
)
2497 WindowImpl
*pWindowImpl
= rWindow
.ImplGetWindowImpl();
2498 if (pWindowImpl
->mpParent
!= pWindowImpl
->mpRealParent
)
2500 assert(pWindowImpl
->mpBorderWindow
== pWindowImpl
->mpParent
);
2501 assert(pWindowImpl
->mpBorderWindow
->ImplGetWindowImpl()->mpParent
== pWindowImpl
->mpRealParent
);
2502 reorderWithinParent(*pWindowImpl
->mpBorderWindow
, nNewPosition
);
2505 rWindow
.reorderWithinParent(nNewPosition
);
2508 void reorderWithinParent(std::vector
<vcl::Window
*>& rChilds
, bool bIsButtonBox
)
2510 for (size_t i
= 0; i
< rChilds
.size(); ++i
)
2512 reorderWithinParent(*rChilds
[i
], i
);
2517 //The first member of the group for legacy code needs WB_GROUP set and the
2519 WinBits nBits
= rChilds
[i
]->GetStyle();
2523 rChilds
[i
]->SetStyle(nBits
);
2527 sal_Int16
getRoleFromName(const OString
& roleName
)
2529 using namespace com::sun::star::accessibility
;
2531 static const std::unordered_map
<OString
, sal_Int16
> aAtkRoleToAccessibleRole
= {
2532 /* This is in atkobject.h's AtkRole order */
2533 { "invalid", AccessibleRole::UNKNOWN
},
2534 { "accelerator label", AccessibleRole::UNKNOWN
},
2535 { "alert", AccessibleRole::ALERT
},
2536 { "animation", AccessibleRole::UNKNOWN
},
2537 { "arrow", AccessibleRole::UNKNOWN
},
2538 { "calendar", AccessibleRole::UNKNOWN
},
2539 { "canvas", AccessibleRole::CANVAS
},
2540 { "check box", AccessibleRole::CHECK_BOX
},
2541 { "check menu item", AccessibleRole::CHECK_MENU_ITEM
},
2542 { "color chooser", AccessibleRole::COLOR_CHOOSER
},
2543 { "column header", AccessibleRole::COLUMN_HEADER
},
2544 { "combo box", AccessibleRole::COMBO_BOX
},
2545 { "date editor", AccessibleRole::DATE_EDITOR
},
2546 { "desktop icon", AccessibleRole::DESKTOP_ICON
},
2547 { "desktop frame", AccessibleRole::DESKTOP_PANE
}, // ?
2548 { "dial", AccessibleRole::UNKNOWN
},
2549 { "dialog", AccessibleRole::DIALOG
},
2550 { "directory pane", AccessibleRole::DIRECTORY_PANE
},
2551 { "drawing area", AccessibleRole::UNKNOWN
},
2552 { "file chooser", AccessibleRole::FILE_CHOOSER
},
2553 { "filler", AccessibleRole::FILLER
},
2554 { "font chooser", AccessibleRole::FONT_CHOOSER
},
2555 { "frame", AccessibleRole::FRAME
},
2556 { "glass pane", AccessibleRole::GLASS_PANE
},
2557 { "html container", AccessibleRole::UNKNOWN
},
2558 { "icon", AccessibleRole::ICON
},
2559 { "image", AccessibleRole::GRAPHIC
},
2560 { "internal frame", AccessibleRole::INTERNAL_FRAME
},
2561 { "label", AccessibleRole::LABEL
},
2562 { "layered pane", AccessibleRole::LAYERED_PANE
},
2563 { "list", AccessibleRole::LIST
},
2564 { "list item", AccessibleRole::LIST_ITEM
},
2565 { "menu", AccessibleRole::MENU
},
2566 { "menu bar", AccessibleRole::MENU_BAR
},
2567 { "menu item", AccessibleRole::MENU_ITEM
},
2568 { "option pane", AccessibleRole::OPTION_PANE
},
2569 { "page tab", AccessibleRole::PAGE_TAB
},
2570 { "page tab list", AccessibleRole::PAGE_TAB_LIST
},
2571 { "panel", AccessibleRole::PANEL
}, // or SHAPE or TEXT_FRAME ?
2572 { "password text", AccessibleRole::PASSWORD_TEXT
},
2573 { "popup menu", AccessibleRole::POPUP_MENU
},
2574 { "progress bar", AccessibleRole::PROGRESS_BAR
},
2575 { "push button", AccessibleRole::PUSH_BUTTON
}, // or BUTTON_DROPDOWN or BUTTON_MENU
2576 { "radio button", AccessibleRole::RADIO_BUTTON
},
2577 { "radio menu item", AccessibleRole::RADIO_MENU_ITEM
},
2578 { "root pane", AccessibleRole::ROOT_PANE
},
2579 { "row header", AccessibleRole::ROW_HEADER
},
2580 { "scroll bar", AccessibleRole::SCROLL_BAR
},
2581 { "scroll pane", AccessibleRole::SCROLL_PANE
},
2582 { "separator", AccessibleRole::SEPARATOR
},
2583 { "slider", AccessibleRole::SLIDER
},
2584 { "split pane", AccessibleRole::SPLIT_PANE
},
2585 { "spin button", AccessibleRole::SPIN_BOX
}, // ?
2586 { "statusbar", AccessibleRole::STATUS_BAR
},
2587 { "table", AccessibleRole::TABLE
},
2588 { "table cell", AccessibleRole::TABLE_CELL
},
2589 { "table column header", AccessibleRole::COLUMN_HEADER
}, // approximate
2590 { "table row header", AccessibleRole::ROW_HEADER
}, // approximate
2591 { "tear off menu item", AccessibleRole::UNKNOWN
},
2592 { "terminal", AccessibleRole::UNKNOWN
},
2593 { "text", AccessibleRole::TEXT
},
2594 { "toggle button", AccessibleRole::TOGGLE_BUTTON
},
2595 { "tool bar", AccessibleRole::TOOL_BAR
},
2596 { "tool tip", AccessibleRole::TOOL_TIP
},
2597 { "tree", AccessibleRole::TREE
},
2598 { "tree table", AccessibleRole::TREE_TABLE
},
2599 { "unknown", AccessibleRole::UNKNOWN
},
2600 { "viewport", AccessibleRole::VIEW_PORT
},
2601 { "window", AccessibleRole::WINDOW
},
2602 { "header", AccessibleRole::HEADER
},
2603 { "footer", AccessibleRole::FOOTER
},
2604 { "paragraph", AccessibleRole::PARAGRAPH
},
2605 { "ruler", AccessibleRole::RULER
},
2606 { "application", AccessibleRole::UNKNOWN
},
2607 { "autocomplete", AccessibleRole::UNKNOWN
},
2608 { "edit bar", AccessibleRole::EDIT_BAR
},
2609 { "embedded", AccessibleRole::EMBEDDED_OBJECT
},
2610 { "entry", AccessibleRole::UNKNOWN
},
2611 { "chart", AccessibleRole::CHART
},
2612 { "caption", AccessibleRole::CAPTION
},
2613 { "document frame", AccessibleRole::DOCUMENT
},
2614 { "heading", AccessibleRole::HEADING
},
2615 { "page", AccessibleRole::PAGE
},
2616 { "section", AccessibleRole::SECTION
},
2617 { "redundant object", AccessibleRole::UNKNOWN
},
2618 { "form", AccessibleRole::FORM
},
2619 { "link", AccessibleRole::HYPER_LINK
},
2620 { "input method window", AccessibleRole::UNKNOWN
},
2621 { "table row", AccessibleRole::UNKNOWN
},
2622 { "tree item", AccessibleRole::TREE_ITEM
},
2623 { "document spreadsheet", AccessibleRole::DOCUMENT_SPREADSHEET
},
2624 { "document presentation", AccessibleRole::DOCUMENT_PRESENTATION
},
2625 { "document text", AccessibleRole::DOCUMENT_TEXT
},
2626 { "document web", AccessibleRole::DOCUMENT
}, // approximate
2627 { "document email", AccessibleRole::DOCUMENT
}, // approximate
2628 { "comment", AccessibleRole::COMMENT
}, // or NOTE or END_NOTE or FOOTNOTE or SCROLL_PANE
2629 { "list box", AccessibleRole::UNKNOWN
},
2630 { "grouping", AccessibleRole::GROUP_BOX
},
2631 { "image map", AccessibleRole::IMAGE_MAP
},
2632 { "notification", AccessibleRole::UNKNOWN
},
2633 { "info bar", AccessibleRole::UNKNOWN
},
2634 { "level bar", AccessibleRole::UNKNOWN
},
2635 { "title bar", AccessibleRole::UNKNOWN
},
2636 { "block quote", AccessibleRole::UNKNOWN
},
2637 { "audio", AccessibleRole::UNKNOWN
},
2638 { "video", AccessibleRole::UNKNOWN
},
2639 { "definition", AccessibleRole::UNKNOWN
},
2640 { "article", AccessibleRole::UNKNOWN
},
2641 { "landmark", AccessibleRole::UNKNOWN
},
2642 { "log", AccessibleRole::UNKNOWN
},
2643 { "marquee", AccessibleRole::UNKNOWN
},
2644 { "math", AccessibleRole::UNKNOWN
},
2645 { "rating", AccessibleRole::UNKNOWN
},
2646 { "timer", AccessibleRole::UNKNOWN
},
2647 { "description list", AccessibleRole::UNKNOWN
},
2648 { "description term", AccessibleRole::UNKNOWN
},
2649 { "description value", AccessibleRole::UNKNOWN
},
2650 { "static", AccessibleRole::STATIC
},
2651 { "math fraction", AccessibleRole::UNKNOWN
},
2652 { "math root", AccessibleRole::UNKNOWN
},
2653 { "subscript", AccessibleRole::UNKNOWN
},
2654 { "superscript", AccessibleRole::UNKNOWN
},
2655 { "footnote", AccessibleRole::FOOTNOTE
},
2658 auto it
= aAtkRoleToAccessibleRole
.find(roleName
);
2659 if (it
== aAtkRoleToAccessibleRole
.end())
2660 return AccessibleRole::UNKNOWN
;
2665 VclPtr
<vcl::Window
> VclBuilder::insertObject(vcl::Window
*pParent
, const OString
&rClass
,
2666 const OString
&rID
, stringmap
&rProps
, stringmap
&rPango
, stringmap
&rAtk
)
2668 VclPtr
<vcl::Window
> pCurrentChild
;
2670 if (m_pParent
&& !isConsideredGtkPseudo(m_pParent
) && !m_sID
.isEmpty() && rID
== m_sID
)
2672 pCurrentChild
= m_pParent
;
2674 //toplevels default to resizable and apparently you can't change them
2675 //afterwards, so we need to wait until now before we can truly
2676 //initialize the dialog.
2677 if (pParent
&& pParent
->IsSystemWindow())
2679 SystemWindow
*pSysWin
= static_cast<SystemWindow
*>(pCurrentChild
.get());
2680 pSysWin
->doDeferredInit(extractDeferredBits(rProps
));
2681 m_bToplevelHasDeferredInit
= false;
2683 else if (pParent
&& pParent
->IsDockingWindow())
2685 DockingWindow
*pDockWin
= static_cast<DockingWindow
*>(pCurrentChild
.get());
2686 pDockWin
->doDeferredInit(extractDeferredBits(rProps
));
2687 m_bToplevelHasDeferredInit
= false;
2690 if (pCurrentChild
->GetHelpId().isEmpty())
2692 pCurrentChild
->SetHelpId(m_sHelpRoot
+ m_sID
);
2693 SAL_INFO("vcl.layout", "for toplevel dialog " << this << " " <<
2694 rID
<< ", set helpid " << pCurrentChild
->GetHelpId());
2696 m_bToplevelParentFound
= true;
2700 //if we're being inserting under a toplevel dialog whose init is
2701 //deferred due to waiting to encounter it in this .ui, and it hasn't
2702 //been seen yet, then make unattached widgets parent-less toplevels
2703 if (pParent
== m_pParent
.get() && m_bToplevelHasDeferredInit
)
2705 pCurrentChild
= makeObject(pParent
, rClass
, rID
, rProps
);
2710 pCurrentChild
->set_id(OStringToOUString(rID
, RTL_TEXTENCODING_UTF8
));
2711 if (pCurrentChild
== m_pParent
.get() && m_bToplevelHasDeferredProperties
)
2712 m_aDeferredProperties
= rProps
;
2714 BuilderUtils::set_properties(pCurrentChild
, rProps
);
2716 for (auto const& elem
: rPango
)
2718 const OString
&rKey
= elem
.first
;
2719 const OUString
&rValue
= elem
.second
;
2720 pCurrentChild
->set_font_attribute(rKey
, rValue
);
2723 m_pParserState
->m_aAtkInfo
[pCurrentChild
] = rAtk
;
2731 pCurrentChild
= m_aChildren
.empty() ? pParent
: m_aChildren
.back().m_pWindow
.get();
2732 return pCurrentChild
;
2735 void VclBuilder::handleTabChild(vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
2737 std::vector
<OString
> sIDs
;
2740 stringmap aProperties
;
2741 std::vector
<vcl::EnumContext::Context
> context
;
2745 xmlreader::Span name
;
2748 xmlreader::XmlReader::Result res
= reader
.nextItem(
2749 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
2751 if (res
== xmlreader::XmlReader::Result::Begin
)
2754 if (name
== "object")
2756 while (reader
.nextAttribute(&nsId
, &name
))
2760 name
= reader
.getAttributeValue(false);
2761 OString
sID(name
.begin
, name
.length
);
2762 sal_Int32 nDelim
= sID
.indexOf(':');
2765 OString sPattern
= sID
.copy(nDelim
+1);
2766 aProperties
[OString("customproperty")] = OUString::fromUtf8(sPattern
);
2767 sID
= sID
.copy(0, nDelim
);
2769 sIDs
.push_back(sID
);
2773 else if (name
== "style")
2776 context
= handleStyle(reader
, nPriority
);
2779 else if (name
== "property")
2780 collectProperty(reader
, aProperties
);
2783 if (res
== xmlreader::XmlReader::Result::End
)
2789 if (res
== xmlreader::XmlReader::Result::Done
)
2796 TabControl
*pTabControl
= pParent
->GetType() == WindowType::TABCONTROL
?
2797 static_cast<TabControl
*>(pParent
) : nullptr;
2798 VerticalTabControl
*pVerticalTabControl
= pParent
->GetType() == WindowType::VERTICALTABCONTROL
?
2799 static_cast<VerticalTabControl
*>(pParent
) : nullptr;
2800 assert(pTabControl
|| pVerticalTabControl
);
2801 VclBuilder::stringmap::iterator aFind
= aProperties
.find(OString("label"));
2802 if (aFind
!= aProperties
.end())
2806 sal_uInt16 nPageId
= pTabControl
->GetCurPageId();
2807 pTabControl
->SetPageText(nPageId
, aFind
->second
);
2808 pTabControl
->SetPageName(nPageId
, sIDs
.back());
2809 if (!context
.empty())
2811 TabPage
* pPage
= pTabControl
->GetTabPage(nPageId
);
2812 pPage
->SetContext(context
);
2817 OUString
sLabel(aFind
->second
);
2818 OUString
sIconName(extractIconName(aProperties
));
2819 OUString
sTooltip(extractTooltipText(aProperties
));
2820 pVerticalTabControl
->InsertPage(sIDs
.front(), sLabel
, FixedImage::loadThemeImage(sIconName
), sTooltip
,
2821 pVerticalTabControl
->GetPageParent()->GetWindow(GetWindowType::LastChild
));
2827 pTabControl
->RemovePage(pTabControl
->GetCurPageId());
2831 //so that tabbing between controls goes in a visually sensible sequence
2832 //we sort these into a best-tab-order sequence
2833 bool VclBuilder::sortIntoBestTabTraversalOrder::operator()(const vcl::Window
*pA
, const vcl::Window
*pB
) const
2835 //sort child order within parent list by grid position
2836 sal_Int32 nTopA
= pA
->get_grid_top_attach();
2837 sal_Int32 nTopB
= pB
->get_grid_top_attach();
2842 sal_Int32 nLeftA
= pA
->get_grid_left_attach();
2843 sal_Int32 nLeftB
= pB
->get_grid_left_attach();
2844 if (nLeftA
< nLeftB
)
2846 if (nLeftA
> nLeftB
)
2848 //sort into two groups of pack start and pack end
2849 VclPackType ePackA
= pA
->get_pack_type();
2850 VclPackType ePackB
= pB
->get_pack_type();
2851 if (ePackA
< ePackB
)
2853 if (ePackA
> ePackB
)
2855 bool bVerticalContainer
= m_pBuilder
->get_window_packing_data(pA
->GetParent()).m_bVerticalOrient
;
2856 bool bPackA
= pA
->get_secondary();
2857 bool bPackB
= pB
->get_secondary();
2858 if (!bVerticalContainer
)
2860 //for horizontal boxes group secondaries before primaries
2861 if (bPackA
> bPackB
)
2863 if (bPackA
< bPackB
)
2868 //for vertical boxes group secondaries after primaries
2869 if (bPackA
< bPackB
)
2871 if (bPackA
> bPackB
)
2874 //honour relative box positions with pack group, (numerical order is reversed
2875 //for VclPackType::End, they are packed from the end back, but here we need
2876 //them in visual layout order so that tabbing works as expected)
2877 sal_Int32 nPackA
= m_pBuilder
->get_window_packing_data(pA
).m_nPosition
;
2878 sal_Int32 nPackB
= m_pBuilder
->get_window_packing_data(pB
).m_nPosition
;
2879 if (nPackA
< nPackB
)
2880 return ePackA
== VclPackType::Start
;
2881 if (nPackA
> nPackB
)
2882 return ePackA
!= VclPackType::Start
;
2883 //sort labels of Frames before body
2884 if (pA
->GetParent() == pB
->GetParent())
2886 const VclFrame
*pFrameParent
= dynamic_cast<const VclFrame
*>(pA
->GetParent());
2889 const vcl::Window
*pLabel
= pFrameParent
->get_label_widget();
2890 int nFramePosA
= (pA
== pLabel
) ? 0 : 1;
2891 int nFramePosB
= (pB
== pLabel
) ? 0 : 1;
2892 return nFramePosA
< nFramePosB
;
2898 void VclBuilder::handleChild(vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
2900 vcl::Window
*pCurrentChild
= nullptr;
2902 xmlreader::Span name
;
2904 OString sType
, sInternalChild
;
2906 while (reader
.nextAttribute(&nsId
, &name
))
2910 name
= reader
.getAttributeValue(false);
2911 sType
= OString(name
.begin
, name
.length
);
2913 else if (name
== "internal-child")
2915 name
= reader
.getAttributeValue(false);
2916 sInternalChild
= OString(name
.begin
, name
.length
);
2922 handleTabChild(pParent
, reader
);
2929 xmlreader::XmlReader::Result res
= reader
.nextItem(
2930 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
2932 if (res
== xmlreader::XmlReader::Result::Begin
)
2934 if (name
== "object" || name
== "placeholder")
2936 pCurrentChild
= handleObject(pParent
, reader
).get();
2938 bool bObjectInserted
= pCurrentChild
&& pParent
!= pCurrentChild
;
2940 if (bObjectInserted
)
2942 //Internal-children default in glade to not having their visible bits set
2943 //even though they are visible (generally anyway)
2944 if (!sInternalChild
.isEmpty())
2945 pCurrentChild
->Show();
2947 //Select the first page if it's a notebook
2948 if (pCurrentChild
->GetType() == WindowType::TABCONTROL
)
2950 TabControl
*pTabControl
= static_cast<TabControl
*>(pCurrentChild
);
2951 pTabControl
->SetCurPageId(pTabControl
->GetPageId(0));
2953 //To-Do add reorder capability to the TabControl
2957 // We want to sort labels before contents of frames
2958 // for keyboard traversal, especially if there
2959 // are multiple widgets using the same mnemonic
2960 if (sType
== "label")
2962 if (VclFrame
*pFrameParent
= dynamic_cast<VclFrame
*>(pParent
))
2963 pFrameParent
->designate_label(pCurrentChild
);
2965 if (sInternalChild
.startsWith("vbox") || sInternalChild
.startsWith("messagedialog-vbox"))
2967 if (Dialog
*pBoxParent
= dynamic_cast<Dialog
*>(pParent
))
2968 pBoxParent
->set_content_area(static_cast<VclBox
*>(pCurrentChild
)); // FIXME-VCLPTR
2970 else if (sInternalChild
.startsWith("action_area") || sInternalChild
.startsWith("messagedialog-action_area"))
2972 vcl::Window
*pContentArea
= pCurrentChild
->GetParent();
2973 if (Dialog
*pBoxParent
= dynamic_cast<Dialog
*>(pContentArea
? pContentArea
->GetParent() : nullptr))
2975 pBoxParent
->set_action_area(static_cast<VclButtonBox
*>(pCurrentChild
)); // FIXME-VCLPTR
2979 bool bIsButtonBox
= dynamic_cast<VclButtonBox
*>(pCurrentChild
) != nullptr;
2981 //To-Do make reorder a virtual in Window, move this foo
2982 //there and see above
2983 std::vector
<vcl::Window
*> aChilds
;
2984 for (vcl::Window
* pChild
= pCurrentChild
->GetWindow(GetWindowType::FirstChild
); pChild
;
2985 pChild
= pChild
->GetWindow(GetWindowType::Next
))
2989 if (PushButton
* pPushButton
= dynamic_cast<PushButton
*>(pChild
))
2990 pPushButton
->setAction(true);
2993 aChilds
.push_back(pChild
);
2996 //sort child order within parent so that tabbing
2997 //between controls goes in a visually sensible sequence
2998 std::stable_sort(aChilds
.begin(), aChilds
.end(), sortIntoBestTabTraversalOrder(this));
2999 BuilderUtils::reorderWithinParent(aChilds
, bIsButtonBox
);
3003 else if (name
== "packing")
3005 handlePacking(pCurrentChild
, pParent
, reader
);
3007 else if (name
== "interface")
3009 while (reader
.nextAttribute(&nsId
, &name
))
3011 if (name
== "domain")
3013 name
= reader
.getAttributeValue(false);
3014 sType
= OString(name
.begin
, name
.length
);
3015 m_pParserState
->m_aResLocale
= Translate::Create(sType
.getStr());
3024 if (res
== xmlreader::XmlReader::Result::End
)
3030 if (res
== xmlreader::XmlReader::Result::Done
)
3035 void VclBuilder::collectPangoAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
3037 xmlreader::Span span
;
3043 while (reader
.nextAttribute(&nsId
, &span
))
3047 span
= reader
.getAttributeValue(false);
3048 sProperty
= OString(span
.begin
, span
.length
);
3050 else if (span
== "value")
3052 span
= reader
.getAttributeValue(false);
3053 sValue
= OString(span
.begin
, span
.length
);
3057 if (!sProperty
.isEmpty())
3058 rMap
[sProperty
] = OUString::fromUtf8(sValue
);
3061 void VclBuilder::collectAtkRelationAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
3063 xmlreader::Span span
;
3069 while (reader
.nextAttribute(&nsId
, &span
))
3073 span
= reader
.getAttributeValue(false);
3074 sProperty
= OString(span
.begin
, span
.length
);
3076 else if (span
== "target")
3078 span
= reader
.getAttributeValue(false);
3079 sValue
= OString(span
.begin
, span
.length
);
3080 sal_Int32 nDelim
= sValue
.indexOf(':');
3082 sValue
= sValue
.copy(0, nDelim
);
3086 if (!sProperty
.isEmpty())
3087 rMap
[sProperty
] = OUString::fromUtf8(sValue
);
3090 void VclBuilder::collectAtkRoleAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
3092 xmlreader::Span span
;
3097 while (reader
.nextAttribute(&nsId
, &span
))
3101 span
= reader
.getAttributeValue(false);
3102 sProperty
= OString(span
.begin
, span
.length
);
3106 if (!sProperty
.isEmpty())
3107 rMap
["role"] = OUString::fromUtf8(sProperty
);
3110 void VclBuilder::handleRow(xmlreader::XmlReader
&reader
, const OString
&rID
)
3114 ListStore::row aRow
;
3118 xmlreader::Span name
;
3121 xmlreader::XmlReader::Result res
= reader
.nextItem(
3122 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3124 if (res
== xmlreader::XmlReader::Result::Done
)
3127 if (res
== xmlreader::XmlReader::Result::Begin
)
3132 bool bTranslated
= false;
3136 while (reader
.nextAttribute(&nsId
, &name
))
3140 name
= reader
.getAttributeValue(false);
3141 nId
= OString(name
.begin
, name
.length
).toInt32();
3143 else if (nId
== 0 && name
== "translatable" && reader
.getAttributeValue(false) == "yes")
3147 else if (name
== "context")
3149 name
= reader
.getAttributeValue(false);
3150 sContext
= OString(name
.begin
, name
.length
);
3155 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3157 OString
sValue(name
.begin
, name
.length
);
3158 OUString sFinalValue
;
3161 if (!sContext
.isEmpty())
3162 sValue
= sContext
+ "\004" + sValue
;
3163 sFinalValue
= Translate::get(sValue
.getStr(), m_pParserState
->m_aResLocale
);
3166 sFinalValue
= OUString::fromUtf8(sValue
);
3169 if (aRow
.size() < nId
+1)
3171 aRow
[nId
] = sFinalValue
;
3175 if (res
== xmlreader::XmlReader::Result::End
)
3184 m_pParserState
->m_aModels
[rID
].m_aEntries
.push_back(aRow
);
3187 void VclBuilder::handleListStore(xmlreader::XmlReader
&reader
, const OString
&rID
, const OString
&rClass
)
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
)
3206 bool bNotTreeStore
= rClass
!= "GtkTreeStore";
3208 handleRow(reader
, rID
);
3209 assert(bNotTreeStore
&& "gtk, as the time of writing, doesn't support data in GtkTreeStore serialization");
3215 if (res
== xmlreader::XmlReader::Result::End
)
3225 void VclBuilder::handleAtkObject(xmlreader::XmlReader
&reader
, vcl::Window
*pWindow
)
3231 stringmap aProperties
;
3235 xmlreader::Span name
;
3238 xmlreader::XmlReader::Result res
= reader
.nextItem(
3239 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3241 if (res
== xmlreader::XmlReader::Result::Done
)
3244 if (res
== xmlreader::XmlReader::Result::Begin
)
3247 if (name
== "property")
3248 collectProperty(reader
, aProperties
);
3251 if (res
== xmlreader::XmlReader::Result::End
)
3260 for (auto const& prop
: aProperties
)
3262 const OString
&rKey
= prop
.first
;
3263 const OUString
&rValue
= prop
.second
;
3265 if (pWindow
&& rKey
.match("AtkObject::"))
3266 pWindow
->set_property(rKey
.copy(RTL_CONSTASCII_LENGTH("AtkObject::")), rValue
);
3268 SAL_WARN("vcl.layout", "unhandled atk prop: " << rKey
);
3272 std::vector
<ComboBoxTextItem
> VclBuilder::handleItems(xmlreader::XmlReader
&reader
) const
3276 std::vector
<ComboBoxTextItem
> aItems
;
3280 xmlreader::Span name
;
3283 xmlreader::XmlReader::Result res
= reader
.nextItem(
3284 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3286 if (res
== xmlreader::XmlReader::Result::Done
)
3289 if (res
== xmlreader::XmlReader::Result::Begin
)
3294 bool bTranslated
= false;
3295 OString sContext
, sId
;
3297 while (reader
.nextAttribute(&nsId
, &name
))
3299 if (name
== "translatable" && reader
.getAttributeValue(false) == "yes")
3303 else if (name
== "context")
3305 name
= reader
.getAttributeValue(false);
3306 sContext
= OString(name
.begin
, name
.length
);
3308 else if (name
== "id")
3310 name
= reader
.getAttributeValue(false);
3311 sId
= OString(name
.begin
, name
.length
);
3316 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3318 OString
sValue(name
.begin
, name
.length
);
3319 OUString sFinalValue
;
3322 if (!sContext
.isEmpty())
3323 sValue
= sContext
+ "\004" + sValue
;
3324 sFinalValue
= Translate::get(sValue
.getStr(), m_pParserState
->m_aResLocale
);
3327 sFinalValue
= OUString::fromUtf8(sValue
);
3329 if (m_pStringReplace
)
3330 sFinalValue
= (*m_pStringReplace
)(sFinalValue
);
3332 aItems
.emplace_back(sFinalValue
, sId
);
3336 if (res
== xmlreader::XmlReader::Result::End
)
3348 VclPtr
<Menu
> VclBuilder::handleMenu(xmlreader::XmlReader
&reader
, const OString
&rID
, bool bMenuBar
)
3350 VclPtr
<Menu
> pCurrentMenu
;
3352 pCurrentMenu
= VclPtr
<MenuBar
>::Create();
3354 pCurrentMenu
= VclPtr
<PopupMenu
>::Create();
3358 stringmap aProperties
;
3362 xmlreader::Span name
;
3365 xmlreader::XmlReader::Result res
= reader
.nextItem(
3366 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3368 if (res
== xmlreader::XmlReader::Result::Done
)
3371 if (res
== xmlreader::XmlReader::Result::Begin
)
3373 if (name
== "child")
3375 handleMenuChild(pCurrentMenu
, reader
);
3380 if (name
== "property")
3381 collectProperty(reader
, aProperties
);
3385 if (res
== xmlreader::XmlReader::Result::End
)
3394 m_aMenus
.emplace_back(rID
, pCurrentMenu
);
3396 return pCurrentMenu
;
3399 void VclBuilder::handleMenuChild(Menu
*pParent
, xmlreader::XmlReader
&reader
)
3401 xmlreader::Span name
;
3407 xmlreader::XmlReader::Result res
= reader
.nextItem(
3408 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3410 if (res
== xmlreader::XmlReader::Result::Begin
)
3412 if (name
== "object" || name
== "placeholder")
3414 handleMenuObject(pParent
, reader
);
3420 if (res
== xmlreader::XmlReader::Result::End
)
3426 if (res
== xmlreader::XmlReader::Result::Done
)
3431 void VclBuilder::handleMenuObject(Menu
*pParent
, xmlreader::XmlReader
&reader
)
3435 OUString sCustomProperty
;
3436 PopupMenu
*pSubMenu
= nullptr;
3438 xmlreader::Span name
;
3441 while (reader
.nextAttribute(&nsId
, &name
))
3443 if (name
== "class")
3445 name
= reader
.getAttributeValue(false);
3446 sClass
= OString(name
.begin
, name
.length
);
3448 else if (name
== "id")
3450 name
= reader
.getAttributeValue(false);
3451 sID
= OString(name
.begin
, name
.length
);
3452 sal_Int32 nDelim
= sID
.indexOf(':');
3455 sCustomProperty
= OUString::fromUtf8(sID
.copy(nDelim
+1));
3456 sID
= sID
.copy(0, nDelim
);
3463 stringmap aProperties
;
3464 accelmap aAccelerators
;
3466 if (!sCustomProperty
.isEmpty())
3467 aProperties
[OString("customproperty")] = sCustomProperty
;
3471 xmlreader::XmlReader::Result res
= reader
.nextItem(
3472 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3474 if (res
== xmlreader::XmlReader::Result::Done
)
3477 if (res
== xmlreader::XmlReader::Result::Begin
)
3479 if (name
== "child")
3481 size_t nChildMenuIdx
= m_aMenus
.size();
3482 handleChild(nullptr, reader
);
3483 assert(m_aMenus
.size() > nChildMenuIdx
&& "menu not inserted");
3484 pSubMenu
= dynamic_cast<PopupMenu
*>(m_aMenus
[nChildMenuIdx
].m_pMenu
.get());
3489 if (name
== "property")
3490 collectProperty(reader
, aProperties
);
3491 else if (name
== "accelerator")
3492 collectAccelerator(reader
, aAccelerators
);
3496 if (res
== xmlreader::XmlReader::Result::End
)
3505 insertMenuObject(pParent
, pSubMenu
, sClass
, sID
, aProperties
, aAccelerators
);
3508 void VclBuilder::handleSizeGroup(xmlreader::XmlReader
&reader
)
3510 m_pParserState
->m_aSizeGroups
.emplace_back();
3511 SizeGroup
&rSizeGroup
= m_pParserState
->m_aSizeGroups
.back();
3517 xmlreader::Span name
;
3520 xmlreader::XmlReader::Result res
= reader
.nextItem(
3521 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3523 if (res
== xmlreader::XmlReader::Result::Done
)
3526 if (res
== xmlreader::XmlReader::Result::Begin
)
3529 if (name
== "widget")
3531 while (reader
.nextAttribute(&nsId
, &name
))
3535 name
= reader
.getAttributeValue(false);
3536 OString
sWidget(name
.begin
, name
.length
);
3537 sal_Int32 nDelim
= sWidget
.indexOf(':');
3539 sWidget
= sWidget
.copy(0, nDelim
);
3540 rSizeGroup
.m_aWidgets
.push_back(sWidget
);
3546 if (name
== "property")
3547 collectProperty(reader
, rSizeGroup
.m_aProperties
);
3551 if (res
== xmlreader::XmlReader::Result::End
)
3563 vcl::KeyCode
makeKeyCode(const std::pair
<OString
,OString
> &rKey
)
3565 bool bShift
= rKey
.second
.indexOf("GDK_SHIFT_MASK") != -1;
3566 bool bMod1
= rKey
.second
.indexOf("GDK_CONTROL_MASK") != -1;
3567 bool bMod2
= rKey
.second
.indexOf("GDK_MOD1_MASK") != -1;
3568 bool bMod3
= rKey
.second
.indexOf("GDK_MOD2_MASK") != -1;
3570 if (rKey
.first
== "Insert")
3571 return vcl::KeyCode(KEY_INSERT
, bShift
, bMod1
, bMod2
, bMod3
);
3572 else if (rKey
.first
== "Delete")
3573 return vcl::KeyCode(KEY_DELETE
, bShift
, bMod1
, bMod2
, bMod3
);
3575 assert (rKey
.first
.getLength() == 1);
3576 sal_Char cChar
= rKey
.first
.toChar();
3578 if (cChar
>= 'a' && cChar
<= 'z')
3579 return vcl::KeyCode(KEY_A
+ (cChar
- 'a'), bShift
, bMod1
, bMod2
, bMod3
);
3580 else if (cChar
>= 'A' && cChar
<= 'Z')
3581 return vcl::KeyCode(KEY_A
+ (cChar
- 'A'), bShift
, bMod1
, bMod2
, bMod3
);
3582 else if (cChar
>= '0' && cChar
<= '9')
3583 return vcl::KeyCode(KEY_0
+ (cChar
- 'A'), bShift
, bMod1
, bMod2
, bMod3
);
3585 return vcl::KeyCode(cChar
, bShift
, bMod1
, bMod2
, bMod3
);
3589 void VclBuilder::insertMenuObject(Menu
*pParent
, PopupMenu
*pSubMenu
, const OString
&rClass
, const OString
&rID
,
3590 stringmap
&rProps
, accelmap
&rAccels
)
3592 sal_uInt16 nOldCount
= pParent
->GetItemCount();
3593 sal_uInt16 nNewId
= ++m_pParserState
->m_nLastMenuItemId
;
3595 if(rClass
== "NotebookBarAddonsMenuMergePoint")
3597 NotebookBarAddonsMerger::MergeNotebookBarMenuAddons(pParent
, nNewId
, rID
, *m_pNotebookBarAddonsItem
);
3598 m_pParserState
->m_nLastMenuItemId
= pParent
->GetItemCount();
3600 else if (rClass
== "GtkMenuItem")
3602 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3603 OUString
aCommand(extractActionName(rProps
));
3604 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::NONE
, rID
);
3605 pParent
->SetItemCommand(nNewId
, aCommand
);
3607 pParent
->SetPopupMenu(nNewId
, pSubMenu
);
3609 else if (rClass
== "GtkCheckMenuItem")
3611 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3612 OUString
aCommand(extractActionName(rProps
));
3613 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::CHECKABLE
, rID
);
3614 pParent
->SetItemCommand(nNewId
, aCommand
);
3616 else if (rClass
== "GtkRadioMenuItem")
3618 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3619 OUString
aCommand(extractActionName(rProps
));
3620 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::AUTOCHECK
| MenuItemBits::RADIOCHECK
, rID
);
3621 pParent
->SetItemCommand(nNewId
, aCommand
);
3623 else if (rClass
== "GtkSeparatorMenuItem")
3625 pParent
->InsertSeparator(rID
);
3628 SAL_WARN_IF(nOldCount
== pParent
->GetItemCount(), "vcl.layout", "probably need to implement " << rClass
);
3630 if (nOldCount
!= pParent
->GetItemCount())
3632 pParent
->SetHelpId(nNewId
, m_sHelpRoot
+ rID
);
3634 for (auto const& prop
: rProps
)
3636 const OString
&rKey
= prop
.first
;
3637 const OUString
&rValue
= prop
.second
;
3639 if (rKey
== "tooltip-markup")
3640 pParent
->SetTipHelpText(nNewId
, rValue
);
3641 else if (rKey
== "tooltip-text")
3642 pParent
->SetTipHelpText(nNewId
, rValue
);
3643 else if (rKey
== "visible")
3644 pParent
->ShowItem(nNewId
, toBool(rValue
));
3646 SAL_INFO("vcl.layout", "unhandled property: " << rKey
);
3649 for (auto const& accel
: rAccels
)
3651 const OString
&rSignal
= accel
.first
;
3652 const auto &rValue
= accel
.second
;
3654 if (rSignal
== "activate")
3655 pParent
->SetAccelKey(nNewId
, makeKeyCode(rValue
));
3657 SAL_INFO("vcl.layout", "unhandled accelerator for: " << rSignal
);
3664 /// Insert items to a ComboBox or a ListBox.
3665 /// They have no common ancestor that would have 'InsertEntry()', so use a template.
3666 template<typename T
> static bool insertItems(vcl::Window
*pWindow
, VclBuilder::stringmap
&rMap
,
3667 std::vector
<std::unique_ptr
<OUString
>>& rUserData
,
3668 const std::vector
<ComboBoxTextItem
> &rItems
)
3670 T
*pContainer
= dynamic_cast<T
*>(pWindow
);
3674 sal_uInt16 nActiveId
= extractActive(rMap
);
3675 for (auto const& item
: rItems
)
3677 sal_Int32 nPos
= pContainer
->InsertEntry(item
.m_sItem
);
3678 if (!item
.m_sId
.isEmpty())
3680 rUserData
.emplace_back(std::make_unique
<OUString
>(OUString::fromUtf8(item
.m_sId
)));
3681 pContainer
->SetEntryData(nPos
, rUserData
.back().get());
3684 if (nActiveId
< rItems
.size())
3685 pContainer
->SelectEntryPos(nActiveId
);
3690 VclPtr
<vcl::Window
> VclBuilder::handleObject(vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
3694 OUString sCustomProperty
;
3696 xmlreader::Span name
;
3699 while (reader
.nextAttribute(&nsId
, &name
))
3701 if (name
== "class")
3703 name
= reader
.getAttributeValue(false);
3704 sClass
= OString(name
.begin
, name
.length
);
3706 else if (name
== "id")
3708 name
= reader
.getAttributeValue(false);
3709 sID
= OString(name
.begin
, name
.length
);
3712 sal_Int32 nDelim
= sID
.indexOf(':');
3715 sCustomProperty
= OUString::fromUtf8(sID
.copy(nDelim
+1));
3716 sID
= sID
.copy(0, nDelim
);
3722 if (sClass
== "GtkListStore" || sClass
== "GtkTreeStore")
3724 handleListStore(reader
, sID
, sClass
);
3727 else if (sClass
== "GtkMenu")
3729 handleMenu(reader
, sID
, false);
3732 else if (sClass
== "GtkMenuBar")
3734 VclPtr
<Menu
> xMenu
= handleMenu(reader
, sID
, true);
3735 if (SystemWindow
* pTopLevel
= pParent
? pParent
->GetSystemWindow() : nullptr)
3736 pTopLevel
->SetMenuBar(dynamic_cast<MenuBar
*>(xMenu
.get()));
3739 else if (sClass
== "GtkSizeGroup")
3741 handleSizeGroup(reader
);
3744 else if (sClass
== "AtkObject")
3746 handleAtkObject(reader
, pParent
);
3752 stringmap aProperties
, aPangoAttributes
;
3753 stringmap aAtkAttributes
;
3754 std::vector
<ComboBoxTextItem
> aItems
;
3756 if (!sCustomProperty
.isEmpty())
3757 aProperties
[OString("customproperty")] = sCustomProperty
;
3759 VclPtr
<vcl::Window
> pCurrentChild
;
3762 xmlreader::XmlReader::Result res
= reader
.nextItem(
3763 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3765 if (res
== xmlreader::XmlReader::Result::Done
)
3768 if (res
== xmlreader::XmlReader::Result::Begin
)
3770 if (name
== "child")
3774 pCurrentChild
= insertObject(pParent
, sClass
, sID
,
3775 aProperties
, aPangoAttributes
, aAtkAttributes
);
3777 handleChild(pCurrentChild
, reader
);
3779 else if (name
== "items")
3780 aItems
= handleItems(reader
);
3781 else if (name
== "style")
3784 std::vector
<vcl::EnumContext::Context
> aContext
= handleStyle(reader
, nPriority
);
3787 vcl::IPrioritable
* pPrioritable
= dynamic_cast<vcl::IPrioritable
*>(pCurrentChild
.get());
3788 SAL_WARN_IF(!pPrioritable
, "vcl", "priority set for not supported item");
3790 pPrioritable
->SetPriority(nPriority
);
3792 if (!aContext
.empty())
3794 vcl::IContext
* pContextControl
= dynamic_cast<vcl::IContext
*>(pCurrentChild
.get());
3795 SAL_WARN_IF(!pContextControl
, "vcl", "context set for not supported item");
3796 if (pContextControl
)
3797 pContextControl
->SetContext(aContext
);
3803 if (name
== "property")
3804 collectProperty(reader
, aProperties
);
3805 else if (name
== "attribute")
3806 collectPangoAttribute(reader
, aPangoAttributes
);
3807 else if (name
== "relation")
3808 collectAtkRelationAttribute(reader
, aAtkAttributes
);
3809 else if (name
== "role")
3810 collectAtkRoleAttribute(reader
, aAtkAttributes
);
3811 else if (name
== "action-widget")
3812 handleActionWidget(reader
);
3816 if (res
== xmlreader::XmlReader::Result::End
)
3825 if (sClass
== "GtkAdjustment")
3827 m_pParserState
->m_aAdjustments
[sID
] = aProperties
;
3830 else if (sClass
== "GtkTextBuffer")
3832 m_pParserState
->m_aTextBuffers
[sID
] = aProperties
;
3838 pCurrentChild
= insertObject(pParent
, sClass
, sID
, aProperties
,
3839 aPangoAttributes
, aAtkAttributes
);
3842 if (!aItems
.empty())
3844 // try to fill-in the items
3845 if (!insertItems
<ComboBox
>(pCurrentChild
, aProperties
, m_aUserData
, aItems
))
3846 insertItems
<ListBox
>(pCurrentChild
, aProperties
, m_aUserData
, aItems
);
3849 return pCurrentChild
;
3852 void VclBuilder::handlePacking(vcl::Window
*pCurrent
, vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
3854 xmlreader::Span name
;
3861 xmlreader::XmlReader::Result res
= reader
.nextItem(
3862 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3864 if (res
== xmlreader::XmlReader::Result::Done
)
3867 if (res
== xmlreader::XmlReader::Result::Begin
)
3870 if (name
== "property")
3871 applyPackingProperty(pCurrent
, pParent
, reader
);
3874 if (res
== xmlreader::XmlReader::Result::End
)
3884 void VclBuilder::applyPackingProperty(vcl::Window
*pCurrent
,
3885 vcl::Window
*pParent
,
3886 xmlreader::XmlReader
&reader
)
3891 //ToolBoxItems are not true widgets just elements
3892 //of the ToolBox itself
3893 ToolBox
*pToolBoxParent
= nullptr;
3894 if (pCurrent
== pParent
)
3895 pToolBoxParent
= dynamic_cast<ToolBox
*>(pParent
);
3897 xmlreader::Span name
;
3900 if (pCurrent
->GetType() == WindowType::SCROLLWINDOW
)
3902 auto aFind
= m_pParserState
->m_aRedundantParentWidgets
.find(VclPtr
<vcl::Window
>(pCurrent
));
3903 if (aFind
!= m_pParserState
->m_aRedundantParentWidgets
.end())
3905 pCurrent
= aFind
->second
;
3910 while (reader
.nextAttribute(&nsId
, &name
))
3914 name
= reader
.getAttributeValue(false);
3915 OString
sKey(name
.begin
, name
.length
);
3916 sKey
= sKey
.replace('_', '-');
3918 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3919 OString
sValue(name
.begin
, name
.length
);
3921 if (sKey
== "expand" || sKey
== "resize")
3923 bool bTrue
= (!sValue
.isEmpty() && (sValue
[0] == 't' || sValue
[0] == 'T' || sValue
[0] == '1'));
3925 pToolBoxParent
->SetItemExpand(m_pParserState
->m_nLastToolbarId
, bTrue
);
3927 pCurrent
->set_expand(bTrue
);
3936 bool bTrue
= (!sValue
.isEmpty() && (sValue
[0] == 't' || sValue
[0] == 'T' || sValue
[0] == '1'));
3937 pCurrent
->set_fill(bTrue
);
3939 else if (sKey
== "pack-type")
3941 VclPackType ePackType
= (!sValue
.isEmpty() && (sValue
[0] == 'e' || sValue
[0] == 'E')) ? VclPackType::End
: VclPackType::Start
;
3942 pCurrent
->set_pack_type(ePackType
);
3944 else if (sKey
== "left-attach")
3946 pCurrent
->set_grid_left_attach(sValue
.toInt32());
3948 else if (sKey
== "top-attach")
3950 pCurrent
->set_grid_top_attach(sValue
.toInt32());
3952 else if (sKey
== "width")
3954 pCurrent
->set_grid_width(sValue
.toInt32());
3956 else if (sKey
== "height")
3958 pCurrent
->set_grid_height(sValue
.toInt32());
3960 else if (sKey
== "padding")
3962 pCurrent
->set_padding(sValue
.toInt32());
3964 else if (sKey
== "position")
3966 set_window_packing_position(pCurrent
, sValue
.toInt32());
3968 else if (sKey
== "secondary")
3970 pCurrent
->set_secondary(toBool(sValue
));
3972 else if (sKey
== "non-homogeneous")
3974 pCurrent
->set_non_homogeneous(toBool(sValue
));
3976 else if (sKey
== "homogeneous")
3978 pCurrent
->set_non_homogeneous(!toBool(sValue
));
3982 SAL_WARN("vcl.layout", "unknown packing: " << sKey
);
3988 std::vector
<vcl::EnumContext::Context
> VclBuilder::handleStyle(xmlreader::XmlReader
&reader
, int &nPriority
)
3990 std::vector
<vcl::EnumContext::Context
> aContext
;
3992 xmlreader::Span name
;
3999 xmlreader::XmlReader::Result res
= reader
.nextItem(
4000 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
4002 if (res
== xmlreader::XmlReader::Result::Done
)
4005 if (res
== xmlreader::XmlReader::Result::Begin
)
4008 if (name
== "class")
4010 OString classStyle
= getStyleClass(reader
);
4012 if (classStyle
.startsWith("context-"))
4014 OString sContext
= classStyle
.copy(classStyle
.indexOf('-') + 1);
4015 OUString
sContext2(sContext
.getStr(), sContext
.getLength(), RTL_TEXTENCODING_UTF8
);
4016 aContext
.push_back(vcl::EnumContext::GetContextEnum(sContext2
));
4018 else if (classStyle
.startsWith("priority-"))
4020 OString aPriority
= classStyle
.copy(classStyle
.indexOf('-') + 1);
4021 OUString
aPriority2(aPriority
.getStr(), aPriority
.getLength(), RTL_TEXTENCODING_UTF8
);
4022 nPriority
= aPriority2
.toInt32();
4026 SAL_WARN("vcl.layout", "unknown class: " << classStyle
);
4031 if (res
== xmlreader::XmlReader::Result::End
)
4043 OString
VclBuilder::getStyleClass(xmlreader::XmlReader
&reader
)
4045 xmlreader::Span name
;
4049 while (reader
.nextAttribute(&nsId
, &name
))
4053 name
= reader
.getAttributeValue(false);
4054 aRet
= OString (name
.begin
, name
.length
);
4061 void VclBuilder::collectProperty(xmlreader::XmlReader
&reader
, stringmap
&rMap
) const
4063 xmlreader::Span name
;
4066 OString sProperty
, sContext
;
4068 bool bTranslated
= false;
4070 while (reader
.nextAttribute(&nsId
, &name
))
4074 name
= reader
.getAttributeValue(false);
4075 sProperty
= OString(name
.begin
, name
.length
);
4077 else if (name
== "context")
4079 name
= reader
.getAttributeValue(false);
4080 sContext
= OString(name
.begin
, name
.length
);
4082 else if (name
== "translatable" && reader
.getAttributeValue(false) == "yes")
4088 reader
.nextItem(xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
4089 OString
sValue(name
.begin
, name
.length
);
4090 OUString sFinalValue
;
4093 if (!sContext
.isEmpty())
4094 sValue
= sContext
+ "\004" + sValue
;
4095 sFinalValue
= Translate::get(sValue
.getStr(), m_pParserState
->m_aResLocale
);
4098 sFinalValue
= OUString::fromUtf8(sValue
);
4100 if (!sProperty
.isEmpty())
4102 sProperty
= sProperty
.replace('_', '-');
4103 if (m_pStringReplace
)
4104 sFinalValue
= (*m_pStringReplace
)(sFinalValue
);
4105 rMap
[sProperty
] = sFinalValue
;
4109 void VclBuilder::handleActionWidget(xmlreader::XmlReader
&reader
)
4111 xmlreader::Span name
;
4116 while (reader
.nextAttribute(&nsId
, &name
))
4118 if (name
== "response")
4120 name
= reader
.getAttributeValue(false);
4121 sResponse
= OString(name
.begin
, name
.length
);
4125 reader
.nextItem(xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
4126 OString
sID(name
.begin
, name
.length
);
4127 sal_Int32 nDelim
= sID
.indexOf(':');
4129 sID
= sID
.copy(0, nDelim
);
4130 set_response(sID
, sResponse
.toInt32());
4133 void VclBuilder::collectAccelerator(xmlreader::XmlReader
&reader
, accelmap
&rMap
)
4135 xmlreader::Span name
;
4142 while (reader
.nextAttribute(&nsId
, &name
))
4146 name
= reader
.getAttributeValue(false);
4147 sValue
= OString(name
.begin
, name
.length
);
4149 else if (name
== "signal")
4151 name
= reader
.getAttributeValue(false);
4152 sProperty
= OString(name
.begin
, name
.length
);
4154 else if (name
== "modifiers")
4156 name
= reader
.getAttributeValue(false);
4157 sModifiers
= OString(name
.begin
, name
.length
);
4161 if (!sProperty
.isEmpty() && !sValue
.isEmpty())
4163 rMap
[sProperty
] = std::make_pair(sValue
, sModifiers
);
4167 vcl::Window
*VclBuilder::get_widget_root()
4169 return m_aChildren
.empty() ? nullptr : m_aChildren
[0].m_pWindow
.get();
4172 vcl::Window
*VclBuilder::get_by_name(const OString
& sID
)
4174 for (auto const& child
: m_aChildren
)
4176 if (child
.m_sID
== sID
)
4177 return child
.m_pWindow
;
4183 PopupMenu
*VclBuilder::get_menu(const OString
& sID
)
4185 for (auto const& menu
: m_aMenus
)
4187 if (menu
.m_sID
== sID
)
4188 return dynamic_cast<PopupMenu
*>(menu
.m_pMenu
.get());
4194 void VclBuilder::set_response(const OString
& sID
, short nResponse
)
4202 nResponse
= RET_CANCEL
;
4205 nResponse
= RET_CLOSE
;
4208 nResponse
= RET_YES
;
4214 nResponse
= RET_HELP
;
4217 assert(nResponse
>= 100 && "keep non-canned responses in range 100+ to avoid collision with vcl RET_*");
4221 for (const auto & child
: m_aChildren
)
4223 if (child
.m_sID
== sID
)
4225 PushButton
* pPushButton
= dynamic_cast<PushButton
*>(child
.m_pWindow
.get());
4226 assert(pPushButton
);
4227 Dialog
* pDialog
= pPushButton
->GetParentDialog();
4229 pDialog
->add_button(pPushButton
, nResponse
, false);
4237 void VclBuilder::delete_by_name(const OString
& sID
)
4239 auto aI
= std::find_if(m_aChildren
.begin(), m_aChildren
.end(),
4240 [&sID
](WinAndId
& rItem
) { return rItem
.m_sID
== sID
; });
4241 if (aI
!= m_aChildren
.end())
4243 aI
->m_pWindow
.disposeAndClear();
4244 m_aChildren
.erase(aI
);
4248 void VclBuilder::delete_by_window(vcl::Window
*pWindow
)
4250 drop_ownership(pWindow
);
4251 pWindow
->disposeOnce();
4254 void VclBuilder::drop_ownership(const vcl::Window
*pWindow
)
4256 auto aI
= std::find_if(m_aChildren
.begin(), m_aChildren
.end(),
4257 [&pWindow
](WinAndId
& rItem
) { return rItem
.m_pWindow
== pWindow
; });
4258 if (aI
!= m_aChildren
.end())
4259 m_aChildren
.erase(aI
);
4262 OString
VclBuilder::get_by_window(const vcl::Window
*pWindow
) const
4264 for (auto const& child
: m_aChildren
)
4266 if (child
.m_pWindow
== pWindow
)
4273 VclBuilder::PackingData
VclBuilder::get_window_packing_data(const vcl::Window
*pWindow
) const
4275 //We've stored the return of new Control, some of these get
4276 //border windows placed around them which are what you get
4277 //from GetChild, so scoot up a level if necessary to get the
4278 //window whose position value we have
4279 const vcl::Window
*pPropHolder
= pWindow
->ImplGetWindow();
4281 for (auto const& child
: m_aChildren
)
4283 if (child
.m_pWindow
== pPropHolder
)
4284 return child
.m_aPackingData
;
4287 return PackingData();
4290 void VclBuilder::set_window_packing_position(const vcl::Window
*pWindow
, sal_Int32 nPosition
)
4292 for (auto & child
: m_aChildren
)
4294 if (child
.m_pWindow
== pWindow
)
4295 child
.m_aPackingData
.m_nPosition
= nPosition
;
4299 const VclBuilder::ListStore
*VclBuilder::get_model_by_name(const OString
& sID
) const
4301 std::map
<OString
, ListStore
>::const_iterator aI
= m_pParserState
->m_aModels
.find(sID
);
4302 if (aI
!= m_pParserState
->m_aModels
.end())
4303 return &(aI
->second
);
4307 const VclBuilder::TextBuffer
*VclBuilder::get_buffer_by_name(const OString
& sID
) const
4309 std::map
<OString
, TextBuffer
>::const_iterator aI
= m_pParserState
->m_aTextBuffers
.find(sID
);
4310 if (aI
!= m_pParserState
->m_aTextBuffers
.end())
4311 return &(aI
->second
);
4315 const VclBuilder::Adjustment
*VclBuilder::get_adjustment_by_name(const OString
& sID
) const
4317 std::map
<OString
, Adjustment
>::const_iterator aI
= m_pParserState
->m_aAdjustments
.find(sID
);
4318 if (aI
!= m_pParserState
->m_aAdjustments
.end())
4319 return &(aI
->second
);
4323 void VclBuilder::mungeModel(ComboBox
&rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4325 for (auto const& entry
: rStore
.m_aEntries
)
4327 const ListStore::row
&rRow
= entry
;
4328 sal_uInt16 nEntry
= rTarget
.InsertEntry(rRow
[0]);
4329 if (rRow
.size() > 1)
4333 sal_IntPtr nValue
= rRow
[1].toInt32();
4334 rTarget
.SetEntryData(nEntry
, reinterpret_cast<void*>(nValue
));
4338 if (!rRow
[1].isEmpty())
4340 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4341 rTarget
.SetEntryData(nEntry
, m_aUserData
.back().get());
4346 if (nActiveId
< rStore
.m_aEntries
.size())
4347 rTarget
.SelectEntryPos(nActiveId
);
4350 void VclBuilder::mungeModel(ListBox
&rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4352 for (auto const& entry
: rStore
.m_aEntries
)
4354 const ListStore::row
&rRow
= entry
;
4355 sal_uInt16 nEntry
= rTarget
.InsertEntry(rRow
[0]);
4356 if (rRow
.size() > 1)
4360 sal_IntPtr nValue
= rRow
[1].toInt32();
4361 rTarget
.SetEntryData(nEntry
, reinterpret_cast<void*>(nValue
));
4365 if (!rRow
[1].isEmpty())
4367 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4368 rTarget
.SetEntryData(nEntry
, m_aUserData
.back().get());
4373 if (nActiveId
< rStore
.m_aEntries
.size())
4374 rTarget
.SelectEntryPos(nActiveId
);
4377 void VclBuilder::mungeModel(SvTabListBox
& rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4379 for (auto const& entry
: rStore
.m_aEntries
)
4381 const ListStore::row
&rRow
= entry
;
4382 auto pEntry
= rTarget
.InsertEntry(rRow
[0]);
4383 if (rRow
.size() > 1)
4387 sal_IntPtr nValue
= rRow
[1].toInt32();
4388 pEntry
->SetUserData(reinterpret_cast<void*>(nValue
));
4392 if (!rRow
[1].isEmpty())
4394 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4395 pEntry
->SetUserData(m_aUserData
.back().get());
4400 if (nActiveId
< rStore
.m_aEntries
.size())
4402 SvTreeListEntry
* pEntry
= rTarget
.GetEntry(nullptr, nActiveId
);
4403 rTarget
.Select(pEntry
);
4407 void VclBuilder::mungeAdjustment(NumericFormatter
&rTarget
, const Adjustment
&rAdjustment
)
4409 int nMul
= rtl_math_pow10Exp(1, rTarget
.GetDecimalDigits());
4411 for (auto const& elem
: rAdjustment
)
4413 const OString
&rKey
= elem
.first
;
4414 const OUString
&rValue
= elem
.second
;
4416 if (rKey
== "upper")
4418 sal_Int64 nUpper
= rValue
.toDouble() * nMul
;
4419 rTarget
.SetMax(nUpper
);
4420 rTarget
.SetLast(nUpper
);
4422 else if (rKey
== "lower")
4424 sal_Int64 nLower
= rValue
.toDouble() * nMul
;
4425 rTarget
.SetMin(nLower
);
4426 rTarget
.SetFirst(nLower
);
4428 else if (rKey
== "value")
4430 sal_Int64 nValue
= rValue
.toDouble() * nMul
;
4431 rTarget
.SetValue(nValue
);
4433 else if (rKey
== "step-increment")
4435 sal_Int64 nSpinSize
= rValue
.toDouble() * nMul
;
4436 rTarget
.SetSpinSize(nSpinSize
);
4440 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4445 void VclBuilder::mungeAdjustment(FormattedField
&rTarget
, const Adjustment
&rAdjustment
)
4447 for (auto const& elem
: rAdjustment
)
4449 const OString
&rKey
= elem
.first
;
4450 const OUString
&rValue
= elem
.second
;
4452 if (rKey
== "upper")
4454 rTarget
.SetMaxValue(rValue
.toDouble());
4456 else if (rKey
== "lower")
4458 rTarget
.SetMinValue(rValue
.toDouble());
4460 else if (rKey
== "value")
4462 rTarget
.SetValue(rValue
.toDouble());
4464 else if (rKey
== "step-increment")
4466 rTarget
.SetSpinSize(rValue
.toDouble());
4470 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4475 void VclBuilder::mungeAdjustment(TimeField
&rTarget
, const Adjustment
&rAdjustment
)
4477 for (auto const& elem
: rAdjustment
)
4479 const OString
&rKey
= elem
.first
;
4480 const OUString
&rValue
= elem
.second
;
4482 if (rKey
== "upper")
4484 tools::Time
aUpper(rValue
.toInt32());
4485 rTarget
.SetMax(aUpper
);
4486 rTarget
.SetLast(aUpper
);
4488 else if (rKey
== "lower")
4490 tools::Time
aLower(rValue
.toInt32());
4491 rTarget
.SetMin(aLower
);
4492 rTarget
.SetFirst(aLower
);
4494 else if (rKey
== "value")
4496 tools::Time
aValue(rValue
.toInt32());
4497 rTarget
.SetTime(aValue
);
4501 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4506 void VclBuilder::mungeAdjustment(DateField
&rTarget
, const Adjustment
&rAdjustment
)
4508 for (auto const& elem
: rAdjustment
)
4510 const OString
&rKey
= elem
.first
;
4511 const OUString
&rValue
= elem
.second
;
4513 if (rKey
== "upper")
4515 Date
aUpper(rValue
.toInt32());
4516 rTarget
.SetMax(aUpper
);
4517 rTarget
.SetLast(aUpper
);
4519 else if (rKey
== "lower")
4521 Date
aLower(rValue
.toInt32());
4522 rTarget
.SetMin(aLower
);
4523 rTarget
.SetFirst(aLower
);
4525 else if (rKey
== "value")
4527 Date
aValue(rValue
.toInt32());
4528 rTarget
.SetDate(aValue
);
4532 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4537 void VclBuilder::mungeAdjustment(ScrollBar
&rTarget
, const Adjustment
&rAdjustment
)
4539 for (auto const& elem
: rAdjustment
)
4541 const OString
&rKey
= elem
.first
;
4542 const OUString
&rValue
= elem
.second
;
4544 if (rKey
== "upper")
4545 rTarget
.SetRangeMax(rValue
.toInt32());
4546 else if (rKey
== "lower")
4547 rTarget
.SetRangeMin(rValue
.toInt32());
4548 else if (rKey
== "value")
4549 rTarget
.SetThumbPos(rValue
.toInt32());
4550 else if (rKey
== "step-increment")
4551 rTarget
.SetLineSize(rValue
.toInt32());
4552 else if (rKey
== "page-increment")
4553 rTarget
.SetPageSize(rValue
.toInt32());
4556 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4561 void VclBuilder::mungeAdjustment(Slider
& rTarget
, const Adjustment
& rAdjustment
)
4563 for (auto const& elem
: rAdjustment
)
4565 const OString
&rKey
= elem
.first
;
4566 const OUString
&rValue
= elem
.second
;
4568 if (rKey
== "upper")
4569 rTarget
.SetRangeMax(rValue
.toInt32());
4570 else if (rKey
== "lower")
4571 rTarget
.SetRangeMin(rValue
.toInt32());
4572 else if (rKey
== "value")
4573 rTarget
.SetThumbPos(rValue
.toInt32());
4574 else if (rKey
== "step-increment")
4575 rTarget
.SetLineSize(rValue
.toInt32());
4576 else if (rKey
== "page-increment")
4577 rTarget
.SetPageSize(rValue
.toInt32());
4580 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4585 void VclBuilder::mungeTextBuffer(VclMultiLineEdit
&rTarget
, const TextBuffer
&rTextBuffer
)
4587 for (auto const& elem
: rTextBuffer
)
4589 const OString
&rKey
= elem
.first
;
4590 const OUString
&rValue
= elem
.second
;
4593 rTarget
.SetText(rValue
);
4596 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4601 VclBuilder::ParserState::ParserState()
4602 : m_nLastToolbarId(0)
4603 , m_nLastMenuItemId(0)
4606 VclBuilder::MenuAndId::MenuAndId(const OString
&rId
, Menu
*pMenu
)
4611 VclBuilder::MenuAndId::~MenuAndId() {}
4613 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */