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 <i18nutil/unicode.hxx>
17 #include <osl/module.hxx>
18 #include <sal/log.hxx>
19 #include <unotools/localedatawrapper.hxx>
20 #include <unotools/resmgr.hxx>
21 #include <vcl/builder.hxx>
22 #include <vcl/button.hxx>
23 #include <vcl/calendar.hxx>
24 #include <vcl/dialog.hxx>
25 #include <vcl/edit.hxx>
26 #include <vcl/field.hxx>
27 #include <vcl/fmtfield.hxx>
28 #include <vcl/fixed.hxx>
29 #include <vcl/toolkit/fixedhyper.hxx>
30 #include <vcl/headbar.hxx>
31 #include <vcl/IPrioritable.hxx>
32 #include <vcl/ivctrl.hxx>
33 #include <vcl/layout.hxx>
34 #include <vcl/lstbox.hxx>
35 #include <vcl/menubtn.hxx>
36 #include <vcl/mnemonic.hxx>
37 #include <vcl/toolkit/prgsbar.hxx>
38 #include <vcl/scrbar.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/svtabbx.hxx>
41 #include <vcl/tabctrl.hxx>
42 #include <vcl/tabpage.hxx>
43 #include <vcl/toolkit/throbber.hxx>
44 #include <vcl/toolbox.hxx>
45 #include <vcl/treelistentry.hxx>
46 #include <vcl/vclmedit.hxx>
47 #include <vcl/settings.hxx>
48 #include <vcl/slider.hxx>
49 #include <vcl/weld.hxx>
50 #include <vcl/commandinfoprovider.hxx>
51 #include <iconview.hxx>
53 #include <bitmaps.hlst>
54 #include <messagedialog.hxx>
56 #include <xmlreader/xmlreader.hxx>
57 #include <desktop/crashreport.hxx>
58 #include <salinst.hxx>
59 #include <strings.hrc>
60 #include <aboutdialog.hxx>
61 #include <treeglue.hxx>
62 #include <tools/diagnose_ex.h>
64 #include <tools/svlibrary.h>
66 #ifdef DISABLE_DYNLOADING
70 static bool toBool(const OString
&rValue
)
72 return (!rValue
.isEmpty() && (rValue
[0] == 't' || rValue
[0] == 'T' || rValue
[0] == '1'));
77 OUString
mapStockToImageResource(const OUString
& sType
)
79 if (sType
== "gtk-index")
80 return SV_RESID_BITMAP_INDEX
;
81 else if (sType
== "gtk-refresh")
82 return SV_RESID_BITMAP_REFRESH
;
83 else if (sType
== "gtk-apply")
85 else if (sType
== "gtk-dialog-error")
87 else if (sType
== "gtk-add")
89 else if (sType
== "gtk-remove")
94 SymbolType
mapStockToSymbol(const OUString
& sType
)
96 SymbolType eRet
= SymbolType::DONTKNOW
;
97 if (sType
== "gtk-media-next")
98 eRet
= SymbolType::NEXT
;
99 else if (sType
== "gtk-media-previous")
100 eRet
= SymbolType::PREV
;
101 else if (sType
== "gtk-media-play")
102 eRet
= SymbolType::PLAY
;
103 else if (sType
== "gtk-media-stop")
104 eRet
= SymbolType::STOP
;
105 else if (sType
== "gtk-goto-first")
106 eRet
= SymbolType::FIRST
;
107 else if (sType
== "gtk-goto-last")
108 eRet
= SymbolType::LAST
;
109 else if (sType
== "gtk-go-back")
110 eRet
= SymbolType::ARROW_LEFT
;
111 else if (sType
== "gtk-go-forward")
112 eRet
= SymbolType::ARROW_RIGHT
;
113 else if (sType
== "gtk-go-up")
114 eRet
= SymbolType::ARROW_UP
;
115 else if (sType
== "gtk-go-down")
116 eRet
= SymbolType::ARROW_DOWN
;
117 else if (sType
== "gtk-missing-image")
118 eRet
= SymbolType::IMAGE
;
119 else if (sType
== "gtk-help")
120 eRet
= SymbolType::HELP
;
121 else if (sType
== "gtk-close")
122 eRet
= SymbolType::CLOSE
;
123 else if (!mapStockToImageResource(sType
).isEmpty())
124 eRet
= SymbolType::IMAGE
;
128 void setupFromActionName(Button
*pButton
, VclBuilder::stringmap
&rMap
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
);
131 #if defined SAL_LOG_WARN
134 bool isButtonType(WindowType nType
)
136 return nType
== WindowType::PUSHBUTTON
||
137 nType
== WindowType::OKBUTTON
||
138 nType
== WindowType::CANCELBUTTON
||
139 nType
== WindowType::HELPBUTTON
||
140 nType
== WindowType::IMAGEBUTTON
||
141 nType
== WindowType::MENUBUTTON
||
142 nType
== WindowType::MOREBUTTON
||
143 nType
== WindowType::SPINBUTTON
;
148 weld::Builder
* Application::CreateBuilder(weld::Widget
* pParent
, const OUString
&rUIFile
)
150 return ImplGetSVData()->mpDefInst
->CreateBuilder(pParent
, VclBuilderContainer::getUIRootDir(), rUIFile
);
153 weld::Builder
* Application::CreateInterimBuilder(vcl::Window
* pParent
, const OUString
&rUIFile
)
155 return SalInstance::CreateInterimBuilder(pParent
, VclBuilderContainer::getUIRootDir(), rUIFile
);
158 weld::MessageDialog
* Application::CreateMessageDialog(weld::Widget
* pParent
, VclMessageType eMessageType
,
159 VclButtonsType eButtonType
, const OUString
& rPrimaryMessage
)
161 return ImplGetSVData()->mpDefInst
->CreateMessageDialog(pParent
, eMessageType
, eButtonType
, rPrimaryMessage
);
164 weld::Window
* Application::GetFrameWeld(const css::uno::Reference
<css::awt::XWindow
>& rWindow
)
166 return ImplGetSVData()->mpDefInst
->GetFrameWeld(rWindow
);
171 OUString
MetricSpinButton::MetricToString(FieldUnit rUnit
)
173 const FieldUnitStringList
& rList
= ImplGetFieldUnits();
174 // return unit's default string (ie, the first one )
175 auto it
= std::find_if(
176 rList
.begin(), rList
.end(),
177 [&rUnit
](const std::pair
<OUString
, FieldUnit
>& rItem
) { return rItem
.second
== rUnit
; });
178 if (it
!= rList
.end())
184 IMPL_LINK_NOARG(MetricSpinButton
, spin_button_value_changed
, SpinButton
&, void)
186 signal_value_changed();
189 IMPL_LINK(MetricSpinButton
, spin_button_output
, SpinButton
&, rSpinButton
, void)
191 OUString
sNewText(format_number(rSpinButton
.get_value()));
192 if (sNewText
!= rSpinButton
.get_text())
193 rSpinButton
.set_text(sNewText
);
196 void MetricSpinButton::update_width_chars()
199 m_xSpinButton
->get_range(min
, max
);
200 auto width
= std::max(m_xSpinButton
->get_pixel_size(format_number(min
)).Width(),
201 m_xSpinButton
->get_pixel_size(format_number(max
)).Width());
202 int chars
= ceil(width
/ m_xSpinButton
->get_approximate_digit_width());
203 m_xSpinButton
->set_width_chars(chars
);
206 unsigned int SpinButton::Power10(unsigned int n
)
208 unsigned int nValue
= 1;
209 for (unsigned int i
= 0; i
< n
; ++i
)
214 int SpinButton::denormalize(int nValue
) const
216 const int nFactor
= Power10(get_digits());
218 if ((nValue
< (SAL_MIN_INT32
+ nFactor
)) || (nValue
> (SAL_MAX_INT32
- nFactor
)))
220 return nValue
/ nFactor
;
223 const int nHalf
= nFactor
/ 2;
226 return (nValue
- nHalf
) / nFactor
;
227 return (nValue
+ nHalf
) / nFactor
;
230 OUString
MetricSpinButton::format_number(int nValue
) const
234 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
236 unsigned int nDecimalDigits
= m_xSpinButton
->get_digits();
237 //pawn percent off to icu to decide whether percent is separated from its number for this locale
238 if (m_eSrcUnit
== FieldUnit::PERCENT
)
240 double fValue
= nValue
;
241 fValue
/= SpinButton::Power10(nDecimalDigits
);
242 aStr
= unicode::formatPercent(fValue
, rLocaleData
.getLanguageTag());
246 aStr
= rLocaleData
.getNum(nValue
, nDecimalDigits
, true, true);
247 OUString aSuffix
= MetricToString(m_eSrcUnit
);
248 if (m_eSrcUnit
!= FieldUnit::NONE
&& m_eSrcUnit
!= FieldUnit::DEGREE
&& m_eSrcUnit
!= FieldUnit::INCH
)
250 if (m_eSrcUnit
== FieldUnit::INCH
)
252 OUString sDoublePrime
= u
"\u2033";
253 if (aSuffix
!= "\"" && aSuffix
!= sDoublePrime
)
256 aSuffix
= sDoublePrime
;
258 assert(m_eSrcUnit
!= FieldUnit::PERCENT
);
265 void MetricSpinButton::set_digits(unsigned int digits
)
268 get_increments(step
, page
, m_eSrcUnit
);
269 int value
= get_value(m_eSrcUnit
);
270 m_xSpinButton
->set_digits(digits
);
271 set_increments(step
, page
, m_eSrcUnit
);
272 set_value(value
, m_eSrcUnit
);
273 update_width_chars();
276 void MetricSpinButton::set_unit(FieldUnit eUnit
)
278 if (eUnit
!= m_eSrcUnit
)
281 get_increments(step
, page
, m_eSrcUnit
);
282 int value
= get_value(m_eSrcUnit
);
284 set_increments(step
, page
, m_eSrcUnit
);
285 set_value(value
, m_eSrcUnit
);
286 spin_button_output(*m_xSpinButton
);
287 update_width_chars();
291 int MetricSpinButton::ConvertValue(int nValue
, FieldUnit eInUnit
, FieldUnit eOutUnit
) const
293 return MetricField::ConvertValue(nValue
, 0, m_xSpinButton
->get_digits(), eInUnit
, eOutUnit
);
296 IMPL_LINK(MetricSpinButton
, spin_button_input
, int*, result
, bool)
298 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
300 bool bRet
= MetricFormatter::TextToValue(get_text(), fResult
, 0, m_xSpinButton
->get_digits(), rLocaleData
, m_eSrcUnit
);
303 if (fResult
> SAL_MAX_INT32
)
304 fResult
= SAL_MAX_INT32
;
305 else if (fResult
< SAL_MIN_INT32
)
306 fResult
= SAL_MIN_INT32
;
312 IMPL_LINK_NOARG(TimeSpinButton
, spin_button_cursor_position
, Entry
&, void)
314 int nStartPos
, nEndPos
;
315 m_xSpinButton
->get_selection_bounds(nStartPos
, nEndPos
);
317 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
318 const int nTimeArea
= TimeFormatter::GetTimeArea(m_eFormat
, m_xSpinButton
->get_text(), nEndPos
,
324 nIncrements
= 1000 * 60 * 60;
325 else if (nTimeArea
== 2)
326 nIncrements
= 1000 * 60;
327 else if (nTimeArea
== 3)
330 m_xSpinButton
->set_increments(nIncrements
, nIncrements
* 10);
333 IMPL_LINK_NOARG(TimeSpinButton
, spin_button_value_changed
, SpinButton
&, void)
335 signal_value_changed();
338 IMPL_LINK(TimeSpinButton
, spin_button_output
, SpinButton
&, rSpinButton
, void)
340 int nStartPos
, nEndPos
;
341 rSpinButton
.get_selection_bounds(nStartPos
, nEndPos
);
342 rSpinButton
.set_text(format_number(rSpinButton
.get_value()));
343 rSpinButton
.set_position(nEndPos
);
346 IMPL_LINK(TimeSpinButton
, spin_button_input
, int*, result
, bool)
348 int nStartPos
, nEndPos
;
349 m_xSpinButton
->get_selection_bounds(nStartPos
, nEndPos
);
351 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
352 tools::Time
aResult(0);
353 bool bRet
= TimeFormatter::TextToTime(m_xSpinButton
->get_text(), aResult
, m_eFormat
, true, rLocaleData
);
355 *result
= ConvertValue(aResult
);
359 void TimeSpinButton::update_width_chars()
362 m_xSpinButton
->get_range(min
, max
);
363 auto width
= std::max(m_xSpinButton
->get_pixel_size(format_number(min
)).Width(),
364 m_xSpinButton
->get_pixel_size(format_number(max
)).Width());
365 int chars
= ceil(width
/ m_xSpinButton
->get_approximate_digit_width());
366 m_xSpinButton
->set_width_chars(chars
);
369 tools::Time
TimeSpinButton::ConvertValue(int nValue
)
371 tools::Time
aTime(0);
372 aTime
.MakeTimeFromMS(nValue
);
376 int TimeSpinButton::ConvertValue(const tools::Time
& rTime
)
378 return rTime
.GetMSFromTime();
381 OUString
TimeSpinButton::format_number(int nValue
) const
383 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
384 return TimeFormatter::FormatTime(ConvertValue(nValue
), m_eFormat
, TimeFormat::Hour24
, true, rLocaleData
);
387 EntryTreeView::EntryTreeView(std::unique_ptr
<Entry
> xEntry
, std::unique_ptr
<TreeView
> xTreeView
)
388 : m_xEntry(std::move(xEntry
))
389 , m_xTreeView(std::move(xTreeView
))
391 m_xTreeView
->connect_changed(LINK(this, EntryTreeView
, ClickHdl
));
392 m_xEntry
->connect_changed(LINK(this, EntryTreeView
, ModifyHdl
));
395 IMPL_LINK(EntryTreeView
, ClickHdl
, weld::TreeView
&, rView
, void)
397 m_xEntry
->set_text(rView
.get_selected_text());
398 m_aChangeHdl
.Call(*this);
401 IMPL_LINK_NOARG(EntryTreeView
, ModifyHdl
, weld::Entry
&, void)
403 m_aChangeHdl
.Call(*this);
406 void EntryTreeView::set_height_request_by_rows(int nRows
)
408 int nHeight
= nRows
== -1 ? -1 : m_xTreeView
->get_height_rows(nRows
);
409 m_xTreeView
->set_size_request(m_xTreeView
->get_size_request().Width(), nHeight
);
413 VclBuilder::VclBuilder(vcl::Window
* pParent
, const OUString
& sUIDir
, const OUString
& sUIFile
,
414 const OString
& sID
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
,
415 bool bLegacy
, const NotebookBarAddonsItem
* pNotebookBarAddonsItem
)
416 : m_pNotebookBarAddonsItem(pNotebookBarAddonsItem
417 ? new NotebookBarAddonsItem(*pNotebookBarAddonsItem
)
418 : new NotebookBarAddonsItem
{})
420 , m_sHelpRoot(OUStringToOString(sUIFile
, RTL_TEXTENCODING_UTF8
))
421 , m_pStringReplace(Translate::GetReadStringHook())
423 , m_bToplevelParentFound(false)
425 , m_pParserState(new ParserState
)
428 m_bToplevelHasDeferredInit
= pParent
&&
429 ((pParent
->IsSystemWindow() && static_cast<SystemWindow
*>(pParent
)->isDeferredInit()) ||
430 (pParent
->IsDockingWindow() && static_cast<DockingWindow
*>(pParent
)->isDeferredInit()));
431 m_bToplevelHasDeferredProperties
= m_bToplevelHasDeferredInit
;
433 sal_Int32 nIdx
= m_sHelpRoot
.lastIndexOf('.');
435 m_sHelpRoot
= m_sHelpRoot
.copy(0, nIdx
);
436 m_sHelpRoot
+= OString('/');
438 OUString sUri
= sUIDir
+ sUIFile
;
442 xmlreader::XmlReader
reader(sUri
);
444 handleChild(pParent
, reader
);
446 catch (const css::uno::Exception
&rExcept
)
448 DBG_UNHANDLED_EXCEPTION("vcl.layout", "Unable to read .ui file");
449 CrashReporter::addKeyValue("VclBuilderException", "Unable to read .ui file: " + rExcept
.Message
, CrashReporter::Write
);
453 //Set Mnemonic widgets when everything has been imported
454 for (auto const& mnemonicWidget
: m_pParserState
->m_aMnemonicWidgetMaps
)
456 FixedText
*pOne
= get
<FixedText
>(mnemonicWidget
.m_sID
);
457 vcl::Window
*pOther
= get
<vcl::Window
>(mnemonicWidget
.m_sValue
.toUtf8());
458 SAL_WARN_IF(!pOne
|| !pOther
, "vcl", "missing either source " << mnemonicWidget
.m_sID
459 << " or target " << mnemonicWidget
.m_sValue
<< " member of Mnemonic Widget Mapping");
461 pOne
->set_mnemonic_widget(pOther
);
464 //Set a11y relations and role when everything has been imported
465 for (auto const& elemAtk
: m_pParserState
->m_aAtkInfo
)
467 vcl::Window
*pSource
= elemAtk
.first
;
468 const stringmap
&rMap
= elemAtk
.second
;
470 for (auto const& elemMap
: rMap
)
472 const OString
&rType
= elemMap
.first
;
473 const OUString
&rParam
= elemMap
.second
;
476 sal_Int16 role
= BuilderUtils::getRoleFromName(rParam
.toUtf8());
477 if (role
!= com::sun::star::accessibility::AccessibleRole::UNKNOWN
)
478 pSource
->SetAccessibleRole(role
);
482 vcl::Window
*pTarget
= get
<vcl::Window
>(rParam
.toUtf8());
483 SAL_WARN_IF(!pTarget
, "vcl", "missing parameter of a11y relation: " << rParam
);
486 if (rType
== "labelled-by")
487 pSource
->SetAccessibleRelationLabeledBy(pTarget
);
488 else if (rType
== "label-for")
489 pSource
->SetAccessibleRelationLabelFor(pTarget
);
490 else if (rType
== "member-of")
491 pSource
->SetAccessibleRelationMemberOf(pTarget
);
494 SAL_WARN("vcl.layout", "unhandled a11y relation :" << rType
);
500 //Set radiobutton groups when everything has been imported
501 for (auto const& elem
: m_pParserState
->m_aGroupMaps
)
503 RadioButton
*pOne
= get
<RadioButton
>(elem
.m_sID
);
504 RadioButton
*pOther
= get
<RadioButton
>(elem
.m_sValue
);
505 SAL_WARN_IF(!pOne
|| !pOther
, "vcl", "missing member of radiobutton group");
509 pOne
->group(*pOther
);
512 pOther
->group(*pOne
);
513 std::stable_sort(pOther
->m_xGroup
->begin(), pOther
->m_xGroup
->end(), sortIntoBestTabTraversalOrder(this));
518 //Set ComboBox models when everything has been imported
519 for (auto const& elem
: m_pParserState
->m_aModelMaps
)
521 vcl::Window
* pTarget
= get
<vcl::Window
>(elem
.m_sID
);
522 ListBox
*pListBoxTarget
= dynamic_cast<ListBox
*>(pTarget
);
523 ComboBox
*pComboBoxTarget
= dynamic_cast<ComboBox
*>(pTarget
);
524 SvTabListBox
*pTreeBoxTarget
= dynamic_cast<SvTabListBox
*>(pTarget
);
525 // pStore may be empty
526 const ListStore
*pStore
= get_model_by_name(elem
.m_sValue
.toUtf8());
527 SAL_WARN_IF(!pListBoxTarget
&& !pComboBoxTarget
&& !pTreeBoxTarget
, "vcl", "missing elements of combobox");
528 if (pListBoxTarget
&& pStore
)
529 mungeModel(*pListBoxTarget
, *pStore
, elem
.m_nActiveId
);
530 else if (pComboBoxTarget
&& pStore
)
531 mungeModel(*pComboBoxTarget
, *pStore
, elem
.m_nActiveId
);
532 else if (pTreeBoxTarget
&& pStore
)
533 mungeModel(*pTreeBoxTarget
, *pStore
, elem
.m_nActiveId
);
536 //Set TextView buffers when everything has been imported
537 for (auto const& elem
: m_pParserState
->m_aTextBufferMaps
)
539 VclMultiLineEdit
*pTarget
= get
<VclMultiLineEdit
>(elem
.m_sID
);
540 const TextBuffer
*pBuffer
= get_buffer_by_name(elem
.m_sValue
.toUtf8());
541 SAL_WARN_IF(!pTarget
|| !pBuffer
, "vcl", "missing elements of textview/textbuffer");
542 if (pTarget
&& pBuffer
)
543 mungeTextBuffer(*pTarget
, *pBuffer
);
546 //Set SpinButton adjustments when everything has been imported
547 for (auto const& elem
: m_pParserState
->m_aNumericFormatterAdjustmentMaps
)
549 NumericFormatter
*pTarget
= dynamic_cast<NumericFormatter
*>(get
<vcl::Window
>(elem
.m_sID
));
550 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
551 SAL_WARN_IF(!pTarget
, "vcl", "missing NumericFormatter element of spinbutton/adjustment");
552 SAL_WARN_IF(!pAdjustment
, "vcl", "missing Adjustment element of spinbutton/adjustment");
553 if (pTarget
&& pAdjustment
)
554 mungeAdjustment(*pTarget
, *pAdjustment
);
557 for (auto const& elem
: m_pParserState
->m_aFormattedFormatterAdjustmentMaps
)
559 FormattedField
*pTarget
= dynamic_cast<FormattedField
*>(get
<vcl::Window
>(elem
.m_sID
));
560 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
561 SAL_WARN_IF(!pTarget
, "vcl", "missing FormattedField element of spinbutton/adjustment");
562 SAL_WARN_IF(!pAdjustment
, "vcl", "missing Adjustment element of spinbutton/adjustment");
563 if (pTarget
&& pAdjustment
)
564 mungeAdjustment(*pTarget
, *pAdjustment
);
567 for (auto const& elem
: m_pParserState
->m_aTimeFormatterAdjustmentMaps
)
569 TimeField
*pTarget
= dynamic_cast<TimeField
*>(get
<vcl::Window
>(elem
.m_sID
));
570 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
571 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of spinbutton/adjustment");
572 if (pTarget
&& pAdjustment
)
573 mungeAdjustment(*pTarget
, *pAdjustment
);
576 for (auto const& elem
: m_pParserState
->m_aDateFormatterAdjustmentMaps
)
578 DateField
*pTarget
= dynamic_cast<DateField
*>(get
<vcl::Window
>(elem
.m_sID
));
579 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
580 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of spinbutton/adjustment");
581 if (pTarget
&& pAdjustment
)
582 mungeAdjustment(*pTarget
, *pAdjustment
);
585 //Set ScrollBar adjustments when everything has been imported
586 for (auto const& elem
: m_pParserState
->m_aScrollAdjustmentMaps
)
588 ScrollBar
*pTarget
= get
<ScrollBar
>(elem
.m_sID
);
589 const Adjustment
*pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
590 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of scrollbar/adjustment");
591 if (pTarget
&& pAdjustment
)
592 mungeAdjustment(*pTarget
, *pAdjustment
);
595 //Set Scale(Slider) adjustments
596 for (auto const& elem
: m_pParserState
->m_aSliderAdjustmentMaps
)
598 Slider
* pTarget
= dynamic_cast<Slider
*>(get
<vcl::Window
>(elem
.m_sID
));
599 const Adjustment
* pAdjustment
= get_adjustment_by_name(elem
.m_sValue
.toUtf8());
600 SAL_WARN_IF(!pTarget
|| !pAdjustment
, "vcl", "missing elements of scale(slider)/adjustment");
601 if (pTarget
&& pAdjustment
)
603 mungeAdjustment(*pTarget
, *pAdjustment
);
607 //Set size-groups when all widgets have been imported
608 for (auto const& sizeGroup
: m_pParserState
->m_aSizeGroups
)
610 std::shared_ptr
<VclSizeGroup
> xGroup(std::make_shared
<VclSizeGroup
>());
612 for (auto const& elem
: sizeGroup
.m_aProperties
)
614 const OString
&rKey
= elem
.first
;
615 const OUString
&rValue
= elem
.second
;
616 xGroup
->set_property(rKey
, rValue
);
619 for (auto const& elem
: sizeGroup
.m_aWidgets
)
621 vcl::Window
* pWindow
= get
<vcl::Window
>(elem
.getStr());
622 pWindow
->add_to_size_group(xGroup
);
626 //Set button images when everything has been imported
627 std::set
<OUString
> aImagesToBeRemoved
;
628 for (auto const& elem
: m_pParserState
->m_aButtonImageWidgetMaps
)
630 PushButton
*pTargetButton
= nullptr;
631 RadioButton
*pTargetRadio
= nullptr;
632 Button
*pTarget
= nullptr;
636 pTargetButton
= get
<PushButton
>(elem
.m_sID
);
637 pTarget
= pTargetButton
;
641 pTargetRadio
= get
<RadioButton
>(elem
.m_sID
);
642 pTarget
= pTargetRadio
;
645 FixedImage
*pImage
= get
<FixedImage
>(elem
.m_sValue
.toUtf8());
646 SAL_WARN_IF(!pTarget
|| !pImage
,
647 "vcl", "missing elements of button/image/stock");
648 if (!pTarget
|| !pImage
)
650 aImagesToBeRemoved
.insert(elem
.m_sValue
);
652 VclBuilder::StockMap::iterator aFind
= m_pParserState
->m_aStockMap
.find(elem
.m_sValue
.toUtf8());
653 if (aFind
== m_pParserState
->m_aStockMap
.end())
656 pTargetButton
->SetModeImage(pImage
->GetImage());
658 pTargetRadio
->SetModeRadioImage(pImage
->GetImage());
662 const stockinfo
&rImageInfo
= aFind
->second
;
663 SymbolType eType
= mapStockToSymbol(rImageInfo
.m_sStock
);
664 SAL_WARN_IF(eType
== SymbolType::DONTKNOW
, "vcl", "missing stock image element for button");
665 if (eType
== SymbolType::DONTKNOW
)
669 pTargetButton
->SetSymbol(eType
);
670 //fdo#76457 keep symbol images small e.g. tools->customize->menu
671 //but images the right size. Really the PushButton::CalcMinimumSize
672 //and PushButton::ImplDrawPushButton are the better place to handle
673 //this, but its such a train-wreck
674 if (eType
!= SymbolType::IMAGE
)
675 pTargetButton
->SetStyle(pTargetButton
->GetStyle() | WB_SMALLSTYLE
);
678 SAL_WARN_IF(eType
!= SymbolType::IMAGE
, "vcl.layout", "unimplemented symbol type for radiobuttons");
679 if (eType
== SymbolType::IMAGE
)
681 Image
const aImage(StockImage::Yes
,
682 mapStockToImageResource(rImageInfo
.m_sStock
));
684 pTargetButton
->SetModeImage(aImage
);
686 pTargetRadio
->SetModeRadioImage(aImage
);
688 switch (rImageInfo
.m_nSize
)
691 pTarget
->SetSmallSymbol();
694 // large toolbar, make bigger than normal (4)
695 pTarget
->set_width_request(pTarget
->GetOptimalSize().Width() * 1.5);
696 pTarget
->set_height_request(pTarget
->GetOptimalSize().Height() * 1.5);
701 SAL_WARN("vcl.layout", "unsupported image size " << rImageInfo
.m_nSize
);
707 //There may be duplicate use of an Image, so we used a set to collect and
708 //now we can remove them from the tree after their final munge
709 for (auto const& elem
: aImagesToBeRemoved
)
711 delete_by_name(elem
.toUtf8());
714 //fill in any stock icons in surviving images
715 for (auto const& elem
: m_pParserState
->m_aStockMap
)
717 FixedImage
*pImage
= get
<FixedImage
>(elem
.first
);
718 SAL_WARN_IF(!pImage
, "vcl", "missing elements of image/stock: " << elem
.first
);
722 const stockinfo
&rImageInfo
= elem
.second
;
723 if (rImageInfo
.m_sStock
== "gtk-missing-image")
726 SymbolType eType
= mapStockToSymbol(rImageInfo
.m_sStock
);
727 SAL_WARN_IF(eType
!= SymbolType::IMAGE
, "vcl", "unimplemented symbol type for images");
728 if (eType
!= SymbolType::IMAGE
)
731 Image
const aImage(StockImage::Yes
,
732 mapStockToImageResource(rImageInfo
.m_sStock
));
733 pImage
->SetImage(aImage
);
736 //Set button menus when everything has been imported
737 for (auto const& elem
: m_pParserState
->m_aButtonMenuMaps
)
739 MenuButton
*pTarget
= get
<MenuButton
>(elem
.m_sID
);
740 PopupMenu
*pMenu
= get_menu(elem
.m_sValue
.toUtf8());
741 SAL_WARN_IF(!pTarget
|| !pMenu
,
742 "vcl", "missing elements of button/menu");
743 if (!pTarget
|| !pMenu
)
745 pTarget
->SetPopupMenu(pMenu
);
748 //Remove ScrollWindow parent widgets whose children in vcl implement scrolling
750 for (auto const& elem
: m_pParserState
->m_aRedundantParentWidgets
)
752 delete_by_window(elem
.first
);
755 //fdo#67378 merge the label into the disclosure button
756 for (auto const& elem
: m_pParserState
->m_aExpanderWidgets
)
758 vcl::Window
*pChild
= elem
->get_child();
759 vcl::Window
* pLabel
= elem
->GetWindow(GetWindowType::LastChild
);
760 if (pLabel
&& pLabel
!= pChild
&& pLabel
->GetType() == WindowType::FIXEDTEXT
)
762 FixedText
*pLabelWidget
= static_cast<FixedText
*>(pLabel
);
763 elem
->set_label(pLabelWidget
->GetText());
764 delete_by_window(pLabel
);
768 // create message dialog message area now
769 for (auto const& elem
: m_pParserState
->m_aMessageDialogs
)
770 elem
->create_message_area();
772 //drop maps, etc. that we don't need again
773 m_pParserState
.reset();
775 SAL_WARN_IF(!m_sID
.isEmpty() && (!m_bToplevelParentFound
&& !get_by_name(m_sID
)), "vcl.layout",
776 "Requested top level widget \"" << m_sID
<< "\" not found in " << sUIFile
);
778 #if defined SAL_LOG_WARN
779 if (m_bToplevelParentFound
&& m_pParent
->IsDialog())
782 bool bHasDefButton
= false;
783 for (auto const& child
: m_aChildren
)
785 if (isButtonType(child
.m_pWindow
->GetType()))
788 if (child
.m_pWindow
->GetStyle() & WB_DEFBUTTON
)
790 bHasDefButton
= true;
795 SAL_WARN_IF(nButtons
&& !bHasDefButton
, "vcl.layout", "No default button defined in " << sUIFile
);
800 VclBuilder::~VclBuilder()
805 void VclBuilder::disposeBuilder()
807 for (std::vector
<WinAndId
>::reverse_iterator aI
= m_aChildren
.rbegin(),
808 aEnd
= m_aChildren
.rend(); aI
!= aEnd
; ++aI
)
810 aI
->m_pWindow
.disposeAndClear();
814 for (std::vector
<MenuAndId
>::reverse_iterator aI
= m_aMenus
.rbegin(),
815 aEnd
= m_aMenus
.rend(); aI
!= aEnd
; ++aI
)
817 aI
->m_pMenu
.disposeAndClear();
825 bool extractDrawValue(VclBuilder::stringmap
& rMap
)
827 bool bDrawValue
= true;
828 VclBuilder::stringmap::iterator aFind
= rMap
.find("draw_value");
829 if (aFind
!= rMap
.end())
831 bDrawValue
= toBool(aFind
->second
);
837 OUString
extractPopupMenu(VclBuilder::stringmap
& rMap
)
840 VclBuilder::stringmap::iterator aFind
= rMap
.find("popup");
841 if (aFind
!= rMap
.end())
843 sRet
= aFind
->second
;
849 OUString
extractValuePos(VclBuilder::stringmap
& rMap
)
851 OUString
sRet("top");
852 VclBuilder::stringmap::iterator aFind
= rMap
.find("value_pos");
853 if (aFind
!= rMap
.end())
855 sRet
= aFind
->second
;
861 OUString
extractTypeHint(VclBuilder::stringmap
&rMap
)
863 OUString
sRet("normal");
864 VclBuilder::stringmap::iterator aFind
= rMap
.find("type-hint");
865 if (aFind
!= rMap
.end())
867 sRet
= aFind
->second
;
873 bool extractResizable(VclBuilder::stringmap
&rMap
)
875 bool bResizable
= true;
876 VclBuilder::stringmap::iterator aFind
= rMap
.find("resizable");
877 if (aFind
!= rMap
.end())
879 bResizable
= toBool(aFind
->second
);
885 #if HAVE_FEATURE_DESKTOP
886 bool extractModal(VclBuilder::stringmap
&rMap
)
889 VclBuilder::stringmap::iterator aFind
= rMap
.find("modal");
890 if (aFind
!= rMap
.end())
892 bModal
= toBool(aFind
->second
);
899 bool extractDecorated(VclBuilder::stringmap
&rMap
)
901 bool bDecorated
= true;
902 VclBuilder::stringmap::iterator aFind
= rMap
.find("decorated");
903 if (aFind
!= rMap
.end())
905 bDecorated
= toBool(aFind
->second
);
911 bool extractCloseable(VclBuilder::stringmap
&rMap
)
913 bool bCloseable
= true;
914 VclBuilder::stringmap::iterator aFind
= rMap
.find("deletable");
915 if (aFind
!= rMap
.end())
917 bCloseable
= toBool(aFind
->second
);
923 bool extractEntry(VclBuilder::stringmap
&rMap
)
925 bool bHasEntry
= false;
926 VclBuilder::stringmap::iterator aFind
= rMap
.find("has-entry");
927 if (aFind
!= rMap
.end())
929 bHasEntry
= toBool(aFind
->second
);
935 bool extractOrientation(VclBuilder::stringmap
&rMap
)
937 bool bVertical
= false;
938 VclBuilder::stringmap::iterator aFind
= rMap
.find("orientation");
939 if (aFind
!= rMap
.end())
941 bVertical
= aFind
->second
.equalsIgnoreAsciiCase("vertical");
947 bool extractVerticalTabPos(VclBuilder::stringmap
&rMap
)
949 bool bVertical
= false;
950 VclBuilder::stringmap::iterator aFind
= rMap
.find("tab-pos");
951 if (aFind
!= rMap
.end())
953 bVertical
= aFind
->second
.equalsIgnoreAsciiCase("left") ||
954 aFind
->second
.equalsIgnoreAsciiCase("right");
960 bool extractInconsistent(VclBuilder::stringmap
&rMap
)
962 bool bInconsistent
= false;
963 VclBuilder::stringmap::iterator aFind
= rMap
.find("inconsistent");
964 if (aFind
!= rMap
.end())
966 bInconsistent
= toBool(aFind
->second
);
969 return bInconsistent
;
972 OUString
extractIconName(VclBuilder::stringmap
&rMap
)
975 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("icon-name"));
976 if (aFind
!= rMap
.end())
978 sIconName
= aFind
->second
;
984 OUString
getStockText(const OUString
&rType
)
986 if (rType
== "gtk-ok")
987 return VclResId(SV_BUTTONTEXT_OK
);
988 else if (rType
== "gtk-cancel")
989 return VclResId(SV_BUTTONTEXT_CANCEL
);
990 else if (rType
== "gtk-help")
991 return VclResId(SV_BUTTONTEXT_HELP
);
992 else if (rType
== "gtk-close")
993 return VclResId(SV_BUTTONTEXT_CLOSE
);
994 else if (rType
== "gtk-revert-to-saved")
995 return VclResId(SV_BUTTONTEXT_RESET
);
996 else if (rType
== "gtk-add")
997 return VclResId(SV_BUTTONTEXT_ADD
);
998 else if (rType
== "gtk-delete")
999 return VclResId(SV_BUTTONTEXT_DELETE
);
1000 else if (rType
== "gtk-remove")
1001 return VclResId(SV_BUTTONTEXT_REMOVE
);
1002 else if (rType
== "gtk-new")
1003 return VclResId(SV_BUTTONTEXT_NEW
);
1004 else if (rType
== "gtk-edit")
1005 return VclResId(SV_BUTTONTEXT_EDIT
);
1006 else if (rType
== "gtk-apply")
1007 return VclResId(SV_BUTTONTEXT_APPLY
);
1008 else if (rType
== "gtk-save")
1009 return VclResId(SV_BUTTONTEXT_SAVE
);
1010 else if (rType
== "gtk-open")
1011 return VclResId(SV_BUTTONTEXT_OPEN
);
1012 else if (rType
== "gtk-undo")
1013 return VclResId(SV_BUTTONTEXT_UNDO
);
1014 else if (rType
== "gtk-paste")
1015 return VclResId(SV_BUTTONTEXT_PASTE
);
1016 else if (rType
== "gtk-media-next")
1017 return VclResId(SV_BUTTONTEXT_NEXT
);
1018 else if (rType
== "gtk-media-previous")
1019 return VclResId(SV_BUTTONTEXT_PREV
);
1020 else if (rType
== "gtk-go-up")
1021 return VclResId(SV_BUTTONTEXT_GO_UP
);
1022 else if (rType
== "gtk-go-down")
1023 return VclResId(SV_BUTTONTEXT_GO_DOWN
);
1024 else if (rType
== "gtk-clear")
1025 return VclResId(SV_BUTTONTEXT_CLEAR
);
1026 else if (rType
== "gtk-media-play")
1027 return VclResId(SV_BUTTONTEXT_PLAY
);
1028 else if (rType
== "gtk-find")
1029 return VclResId(SV_BUTTONTEXT_FIND
);
1030 else if (rType
== "gtk-stop")
1031 return VclResId(SV_BUTTONTEXT_STOP
);
1032 else if (rType
== "gtk-connect")
1033 return VclResId(SV_BUTTONTEXT_CONNECT
);
1034 else if (rType
== "gtk-yes")
1035 return VclResId(SV_BUTTONTEXT_YES
);
1036 else if (rType
== "gtk-no")
1037 return VclResId(SV_BUTTONTEXT_NO
);
1038 SAL_WARN("vcl.layout", "unknown stock type: " << rType
);
1042 bool extractStock(VclBuilder::stringmap
&rMap
)
1044 bool bIsStock
= false;
1045 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("use-stock"));
1046 if (aFind
!= rMap
.end())
1048 bIsStock
= toBool(aFind
->second
);
1054 WinBits
extractRelief(VclBuilder::stringmap
&rMap
)
1056 WinBits nBits
= WB_3DLOOK
;
1057 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("relief"));
1058 if (aFind
!= rMap
.end())
1060 if (aFind
->second
== "half")
1061 nBits
= WB_FLATBUTTON
| WB_BEVELBUTTON
;
1062 else if (aFind
->second
== "none")
1063 nBits
= WB_FLATBUTTON
;
1069 OUString
extractLabel(VclBuilder::stringmap
&rMap
)
1072 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("label"));
1073 if (aFind
!= rMap
.end())
1075 sType
= aFind
->second
;
1081 OUString
extractActionName(VclBuilder::stringmap
&rMap
)
1083 OUString sActionName
;
1084 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("action-name"));
1085 if (aFind
!= rMap
.end())
1087 sActionName
= aFind
->second
;
1093 bool extractVisible(VclBuilder::stringmap
&rMap
)
1095 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("visible"));
1096 if (aFind
!= rMap
.end())
1098 return toBool(aFind
->second
);
1103 Size
extractSizeRequest(VclBuilder::stringmap
&rMap
)
1105 OUString
sWidthRequest("0");
1106 OUString
sHeightRequest("0");
1107 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("width-request"));
1108 if (aFind
!= rMap
.end())
1110 sWidthRequest
= aFind
->second
;
1113 aFind
= rMap
.find("height-request");
1114 if (aFind
!= rMap
.end())
1116 sHeightRequest
= aFind
->second
;
1119 return Size(sWidthRequest
.toInt32(), sHeightRequest
.toInt32());
1122 OUString
extractTooltipText(VclBuilder::stringmap
&rMap
)
1124 OUString sTooltipText
;
1125 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("tooltip-text"));
1126 if (aFind
== rMap
.end())
1127 aFind
= rMap
.find(OString("tooltip-markup"));
1128 if (aFind
!= rMap
.end())
1130 sTooltipText
= aFind
->second
;
1133 return sTooltipText
;
1136 float extractAlignment(VclBuilder::stringmap
&rMap
)
1139 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("alignment"));
1140 if (aFind
!= rMap
.end())
1142 f
= aFind
->second
.toFloat();
1148 OUString
extractTitle(VclBuilder::stringmap
&rMap
)
1151 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("title"));
1152 if (aFind
!= rMap
.end())
1154 sTitle
= aFind
->second
;
1160 bool extractHeadersVisible(VclBuilder::stringmap
&rMap
)
1162 bool bHeadersVisible
= true;
1163 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("headers-visible"));
1164 if (aFind
!= rMap
.end())
1166 bHeadersVisible
= toBool(aFind
->second
);
1169 return bHeadersVisible
;
1172 bool extractSortIndicator(VclBuilder::stringmap
&rMap
)
1174 bool bSortIndicator
= false;
1175 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("sort-indicator"));
1176 if (aFind
!= rMap
.end())
1178 bSortIndicator
= toBool(aFind
->second
);
1181 return bSortIndicator
;
1184 bool extractClickable(VclBuilder::stringmap
&rMap
)
1186 bool bClickable
= false;
1187 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("clickable"));
1188 if (aFind
!= rMap
.end())
1190 bClickable
= toBool(aFind
->second
);
1196 void setupFromActionName(Button
*pButton
, VclBuilder::stringmap
&rMap
, const css::uno::Reference
<css::frame::XFrame
>& rFrame
)
1201 OUString
aCommand(extractActionName(rMap
));
1202 if (aCommand
.isEmpty())
1205 OUString
aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame
));
1206 OUString
aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aCommand
, aModuleName
));
1207 if (!aLabel
.isEmpty())
1208 pButton
->SetText(aLabel
);
1210 OUString
aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(aCommand
, rFrame
));
1211 if (!aTooltip
.isEmpty())
1212 pButton
->SetQuickHelpText(aTooltip
);
1214 Image
aImage(vcl::CommandInfoProvider::GetImageForCommand(aCommand
, rFrame
));
1215 pButton
->SetModeImage(aImage
);
1217 pButton
->SetCommandHandler(aCommand
);
1220 VclPtr
<Button
> extractStockAndBuildPushButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
, bool bToggle
, bool bLegacy
)
1222 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
;
1226 nBits
|= extractRelief(rMap
);
1228 VclPtr
<Button
> xWindow
;
1230 if (extractStock(rMap
))
1232 OUString sType
= extractLabel(rMap
);
1235 if (sType
== "gtk-ok")
1236 xWindow
= VclPtr
<OKButton
>::Create(pParent
, nBits
);
1237 else if (sType
== "gtk-cancel")
1238 xWindow
= VclPtr
<CancelButton
>::Create(pParent
, nBits
);
1239 else if (sType
== "gtk-close")
1240 xWindow
= VclPtr
<CloseButton
>::Create(pParent
, nBits
);
1241 else if (sType
== "gtk-help")
1242 xWindow
= VclPtr
<HelpButton
>::Create(pParent
, nBits
);
1246 xWindow
= VclPtr
<PushButton
>::Create(pParent
, nBits
);
1247 xWindow
->SetText(getStockText(sType
));
1252 xWindow
= VclPtr
<PushButton
>::Create(pParent
, nBits
);
1256 VclPtr
<MenuButton
> extractStockAndBuildMenuButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
)
1258 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1260 nBits
|= extractRelief(rMap
);
1262 VclPtr
<MenuButton
> xWindow
= VclPtr
<MenuButton
>::Create(pParent
, nBits
);
1264 if (extractStock(rMap
))
1266 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1272 VclPtr
<Button
> extractStockAndBuildMenuToggleButton(vcl::Window
*pParent
, VclBuilder::stringmap
&rMap
)
1274 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1276 nBits
|= extractRelief(rMap
);
1278 VclPtr
<Button
> xWindow
= VclPtr
<MenuToggleButton
>::Create(pParent
, nBits
);
1280 if (extractStock(rMap
))
1282 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1288 OUString
extractUnit(const OUString
& sPattern
)
1290 OUString
sUnit(sPattern
);
1291 for (sal_Int32 i
= 0; i
< sPattern
.getLength(); ++i
)
1293 if (sPattern
[i
] != '.' && sPattern
[i
] != ',' && sPattern
[i
] != '0')
1295 sUnit
= sPattern
.copy(i
);
1302 int extractDecimalDigits(const OUString
& sPattern
)
1305 bool bAfterPoint
= false;
1306 for (sal_Int32 i
= 0; i
< sPattern
.getLength(); ++i
)
1308 if (sPattern
[i
] == '.' || sPattern
[i
] == ',')
1310 else if (sPattern
[i
] == '0')
1321 FieldUnit
detectMetricUnit(const OUString
& sUnit
)
1323 FieldUnit eUnit
= FieldUnit::NONE
;
1326 eUnit
= FieldUnit::MM
;
1327 else if (sUnit
== "cm")
1328 eUnit
= FieldUnit::CM
;
1329 else if (sUnit
== "m")
1330 eUnit
= FieldUnit::M
;
1331 else if (sUnit
== "km")
1332 eUnit
= FieldUnit::KM
;
1333 else if ((sUnit
== "twips") || (sUnit
== "twip"))
1334 eUnit
= FieldUnit::TWIP
;
1335 else if (sUnit
== "pt")
1336 eUnit
= FieldUnit::POINT
;
1337 else if (sUnit
== "pc")
1338 eUnit
= FieldUnit::PICA
;
1339 else if (sUnit
== "\"" || (sUnit
== "in") || (sUnit
== "inch"))
1340 eUnit
= FieldUnit::INCH
;
1341 else if ((sUnit
== "'") || (sUnit
== "ft") || (sUnit
== "foot") || (sUnit
== "feet"))
1342 eUnit
= FieldUnit::FOOT
;
1343 else if (sUnit
== "mile" || (sUnit
== "miles"))
1344 eUnit
= FieldUnit::MILE
;
1345 else if (sUnit
== "ch")
1346 eUnit
= FieldUnit::CHAR
;
1347 else if (sUnit
== "line")
1348 eUnit
= FieldUnit::LINE
;
1349 else if (sUnit
== "%")
1350 eUnit
= FieldUnit::PERCENT
;
1351 else if ((sUnit
== "pixels") || (sUnit
== "pixel") || (sUnit
== "px"))
1352 eUnit
= FieldUnit::PIXEL
;
1353 else if ((sUnit
== "degrees") || (sUnit
== "degree"))
1354 eUnit
= FieldUnit::DEGREE
;
1355 else if ((sUnit
== "sec") || (sUnit
== "seconds") || (sUnit
== "second"))
1356 eUnit
= FieldUnit::SECOND
;
1357 else if ((sUnit
== "ms") || (sUnit
== "milliseconds") || (sUnit
== "millisecond"))
1358 eUnit
= FieldUnit::MILLISECOND
;
1359 else if (sUnit
!= "0")
1360 eUnit
= FieldUnit::CUSTOM
;
1365 WinBits
extractDeferredBits(VclBuilder::stringmap
&rMap
)
1367 WinBits nBits
= WB_3DLOOK
|WB_HIDE
;
1368 if (extractResizable(rMap
))
1369 nBits
|= WB_SIZEABLE
;
1370 if (extractCloseable(rMap
))
1371 nBits
|= WB_CLOSEABLE
;
1372 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
1373 if (!sBorder
.isEmpty())
1375 if (!extractDecorated(rMap
))
1376 nBits
|= WB_OWNERDRAWDECORATION
;
1377 OUString
sType(extractTypeHint(rMap
));
1378 if (sType
== "utility")
1379 nBits
|= WB_SYSTEMWINDOW
| WB_DIALOGCONTROL
| WB_MOVEABLE
;
1380 else if (sType
== "popup-menu")
1381 nBits
|= WB_SYSTEMWINDOW
| WB_DIALOGCONTROL
| WB_POPUP
;
1382 else if (sType
== "dock")
1383 nBits
|= WB_DOCKABLE
| WB_MOVEABLE
;
1385 nBits
|= WB_MOVEABLE
;
1390 void VclBuilder::extractGroup(const OString
&id
, stringmap
&rMap
)
1392 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("group"));
1393 if (aFind
!= rMap
.end())
1395 OUString sID
= aFind
->second
;
1396 sal_Int32 nDelim
= sID
.indexOf(':');
1398 sID
= sID
.copy(0, nDelim
);
1399 m_pParserState
->m_aGroupMaps
.emplace_back(id
, sID
.toUtf8());
1404 void VclBuilder::connectNumericFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1406 if (!rAdjustment
.isEmpty())
1407 m_pParserState
->m_aNumericFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1410 void VclBuilder::connectFormattedFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1412 if (!rAdjustment
.isEmpty())
1413 m_pParserState
->m_aFormattedFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1416 void VclBuilder::connectTimeFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1418 if (!rAdjustment
.isEmpty())
1419 m_pParserState
->m_aTimeFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1422 void VclBuilder::connectDateFormatterAdjustment(const OString
&id
, const OUString
&rAdjustment
)
1424 if (!rAdjustment
.isEmpty())
1425 m_pParserState
->m_aDateFormatterAdjustmentMaps
.emplace_back(id
, rAdjustment
);
1428 bool VclBuilder::extractAdjustmentToMap(const OString
& id
, VclBuilder::stringmap
& rMap
, std::vector
<WidgetAdjustmentMap
>& rAdjustmentMap
)
1430 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("adjustment"));
1431 if (aFind
!= rMap
.end())
1433 rAdjustmentMap
.emplace_back(id
, aFind
->second
);
1442 sal_Int32
extractActive(VclBuilder::stringmap
&rMap
)
1444 sal_Int32 nActiveId
= 0;
1445 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("active"));
1446 if (aFind
!= rMap
.end())
1448 nActiveId
= aFind
->second
.toInt32();
1454 bool extractSelectable(VclBuilder::stringmap
&rMap
)
1456 bool bSelectable
= false;
1457 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("selectable"));
1458 if (aFind
!= rMap
.end())
1460 bSelectable
= toBool(aFind
->second
);
1466 OUString
extractAdjustment(VclBuilder::stringmap
&rMap
)
1468 OUString sAdjustment
;
1469 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("adjustment"));
1470 if (aFind
!= rMap
.end())
1472 sAdjustment
= aFind
->second
;
1479 bool extractDrawIndicator(VclBuilder::stringmap
&rMap
)
1481 bool bDrawIndicator
= false;
1482 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("draw-indicator"));
1483 if (aFind
!= rMap
.end())
1485 bDrawIndicator
= toBool(aFind
->second
);
1488 return bDrawIndicator
;
1492 void VclBuilder::extractModel(const OString
&id
, stringmap
&rMap
)
1494 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("model"));
1495 if (aFind
!= rMap
.end())
1497 m_pParserState
->m_aModelMaps
.emplace_back(id
, aFind
->second
,
1498 extractActive(rMap
));
1503 void VclBuilder::extractBuffer(const OString
&id
, stringmap
&rMap
)
1505 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("buffer"));
1506 if (aFind
!= rMap
.end())
1508 m_pParserState
->m_aTextBufferMaps
.emplace_back(id
, aFind
->second
);
1513 void VclBuilder::extractStock(const OString
&id
, stringmap
&rMap
)
1515 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("stock"));
1516 if (aFind
!= rMap
.end())
1519 aInfo
.m_sStock
= aFind
->second
;
1521 aFind
= rMap
.find(OString("icon-size"));
1522 if (aFind
!= rMap
.end())
1524 aInfo
.m_nSize
= aFind
->second
.toInt32();
1527 m_pParserState
->m_aStockMap
[id
] = aInfo
;
1531 void VclBuilder::extractButtonImage(const OString
&id
, stringmap
&rMap
, bool bRadio
)
1533 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("image"));
1534 if (aFind
!= rMap
.end())
1536 m_pParserState
->m_aButtonImageWidgetMaps
.emplace_back(id
, aFind
->second
, bRadio
);
1541 void VclBuilder::extractMnemonicWidget(const OString
&rLabelID
, stringmap
&rMap
)
1543 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("mnemonic-widget"));
1544 if (aFind
!= rMap
.end())
1546 OUString sID
= aFind
->second
;
1547 sal_Int32 nDelim
= sID
.indexOf(':');
1549 sID
= sID
.copy(0, nDelim
);
1550 m_pParserState
->m_aMnemonicWidgetMaps
.emplace_back(rLabelID
, sID
);
1555 vcl::Window
* VclBuilder::prepareWidgetOwnScrolling(vcl::Window
*pParent
, WinBits
&rWinStyle
)
1557 //For Widgets that manage their own scrolling, if one appears as a child of
1558 //a scrolling window shoehorn that scrolling settings to this widget and
1559 //return the real parent to use
1560 if (pParent
&& pParent
->GetType() == WindowType::SCROLLWINDOW
)
1562 WinBits nScrollBits
= pParent
->GetStyle();
1563 nScrollBits
&= (WB_AUTOHSCROLL
|WB_HSCROLL
|WB_AUTOVSCROLL
|WB_VSCROLL
);
1564 rWinStyle
|= nScrollBits
| WB_BORDER
;
1565 pParent
= pParent
->GetParent();
1571 void VclBuilder::cleanupWidgetOwnScrolling(vcl::Window
*pScrollParent
, vcl::Window
*pWindow
, stringmap
&rMap
)
1573 //remove the redundant scrolling parent
1574 sal_Int32 nWidthReq
= pScrollParent
->get_width_request();
1575 rMap
[OString("width-request")] = OUString::number(nWidthReq
);
1576 sal_Int32 nHeightReq
= pScrollParent
->get_height_request();
1577 rMap
[OString("height-request")] = OUString::number(nHeightReq
);
1579 m_pParserState
->m_aRedundantParentWidgets
[pScrollParent
] = pWindow
;
1582 #ifndef DISABLE_DYNLOADING
1584 extern "C" { static void thisModule() {} }
1586 // Don't unload the module on destruction
1587 class NoAutoUnloadModule
: public osl::Module
1590 ~NoAutoUnloadModule() { release(); }
1593 typedef std::map
<OUString
, std::shared_ptr
<NoAutoUnloadModule
>> ModuleMap
;
1594 static ModuleMap g_aModuleMap
;
1596 #if ENABLE_MERGELIBS
1597 static std::shared_ptr
<NoAutoUnloadModule
> g_pMergedLib
= std::make_shared
<NoAutoUnloadModule
>();
1600 #ifndef SAL_DLLPREFIX
1601 # define SAL_DLLPREFIX ""
1606 void VclBuilder::preload()
1608 #ifndef DISABLE_DYNLOADING
1610 #if ENABLE_MERGELIBS
1611 g_pMergedLib
->loadRelative(&thisModule
, SVLIBRARY("merged"));
1613 // find -name '*ui*' | xargs grep 'class=".*lo-' |
1614 // sed 's/.*class="//' | sed 's/-.*$//' | sort | uniq
1615 static const char *aWidgetLibs
[] = {
1616 "sfxlo", "svtlo", "svxcorelo", "foruilo",
1617 "vcllo", "svxlo", "cuilo", "swlo",
1618 "swuilo", "sclo", "sdlo", "chartcontrollerlo",
1619 "smlo", "scuilo", "basctllo", "sduilo",
1620 "scnlo", "xsltdlglo", "pcrlo" // "dbulo"
1622 for (const auto & lib
: aWidgetLibs
)
1624 std::unique_ptr
<NoAutoUnloadModule
> pModule(new NoAutoUnloadModule
);
1625 OUString sModule
= SAL_DLLPREFIX
+ OUString::createFromAscii(lib
) + SAL_DLLEXTENSION
;
1626 if (pModule
->loadRelative(&thisModule
, sModule
))
1627 g_aModuleMap
.insert(std::make_pair(sModule
, std::move(pModule
)));
1629 #endif // ENABLE_MERGELIBS
1630 #endif // DISABLE_DYNLOADING
1633 #if defined DISABLE_DYNLOADING && !HAVE_FEATURE_DESKTOP
1634 extern "C" VclBuilder::customMakeWidget
lo_get_custom_widget_func(const char* name
);
1639 // Takes a string like "sfxlo-SidebarToolBox"
1640 VclBuilder::customMakeWidget
GetCustomMakeWidget(const OString
& name
)
1642 VclBuilder::customMakeWidget pFunction
= nullptr;
1643 if (sal_Int32 nDelim
= name
.indexOf('-'); nDelim
!= -1)
1645 const OUString
sFunction("make"
1646 + OStringToOUString(name
.copy(nDelim
+ 1), RTL_TEXTENCODING_UTF8
));
1648 #ifndef DISABLE_DYNLOADING
1649 const OUString sModule
= SAL_DLLPREFIX
1650 + OStringToOUString(name
.copy(0, nDelim
), RTL_TEXTENCODING_UTF8
)
1652 ModuleMap::iterator aI
= g_aModuleMap
.find(sModule
);
1653 if (aI
== g_aModuleMap
.end())
1655 std::shared_ptr
<NoAutoUnloadModule
> pModule
;
1656 #if ENABLE_MERGELIBS
1657 if (!g_pMergedLib
->is())
1658 g_pMergedLib
->loadRelative(&thisModule
, SVLIBRARY("merged"));
1659 if ((pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1660 g_pMergedLib
->getFunctionSymbol(sFunction
))))
1661 pModule
= g_pMergedLib
;
1665 pModule
.reset(new NoAutoUnloadModule
);
1666 bool ok
= pModule
->loadRelative(&thisModule
, sModule
);
1667 assert(ok
&& "bad module name in .ui");
1669 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1670 pModule
->getFunctionSymbol(sFunction
));
1672 g_aModuleMap
.insert(std::make_pair(sModule
, pModule
));
1675 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1676 aI
->second
->getFunctionSymbol(sFunction
));
1677 #elif !HAVE_FEATURE_DESKTOP
1678 pFunction
= lo_get_custom_widget_func(sFunction
.toUtf8().getStr());
1679 SAL_WARN_IF(!pFunction
, "vcl.layout", "Could not find " << sFunction
);
1682 pFunction
= reinterpret_cast<VclBuilder::customMakeWidget
>(
1683 osl_getFunctionSymbol((oslModule
)RTLD_DEFAULT
, sFunction
.pData
));
1690 VclPtr
<vcl::Window
> VclBuilder::makeObject(vcl::Window
*pParent
, const OString
&name
, const OString
&id
,
1693 bool bIsPlaceHolder
= name
.isEmpty();
1694 bool bVertical
= false;
1696 if (pParent
&& (pParent
->GetType() == WindowType::TABCONTROL
||
1697 pParent
->GetType() == WindowType::VERTICALTABCONTROL
))
1699 bool bTopLevel(name
== "GtkDialog" || name
== "GtkMessageDialog" ||
1700 name
== "GtkWindow" || name
== "GtkPopover" || name
== "GtkAssistant");
1703 if (pParent
->GetType() == WindowType::TABCONTROL
)
1705 //We have to add a page
1706 //make default pageid == position
1707 TabControl
*pTabControl
= static_cast<TabControl
*>(pParent
);
1708 sal_uInt16 nNewPageCount
= pTabControl
->GetPageCount()+1;
1709 sal_uInt16 nNewPageId
= nNewPageCount
;
1710 pTabControl
->InsertPage(nNewPageId
, OUString());
1711 pTabControl
->SetCurPageId(nNewPageId
);
1712 SAL_WARN_IF(bIsPlaceHolder
, "vcl.layout", "we should have no placeholders for tabpages");
1713 if (!bIsPlaceHolder
)
1715 VclPtrInstance
<TabPage
> pPage(pTabControl
);
1718 //Make up a name for it
1719 OString sTabPageId
= get_by_window(pParent
) +
1721 OString::number(nNewPageCount
);
1722 m_aChildren
.emplace_back(sTabPageId
, pPage
, false);
1723 pPage
->SetHelpId(m_sHelpRoot
+ sTabPageId
);
1727 pTabControl
->SetTabPage(nNewPageId
, pPage
);
1732 VerticalTabControl
*pTabControl
= static_cast<VerticalTabControl
*>(pParent
);
1733 SAL_WARN_IF(bIsPlaceHolder
, "vcl.layout", "we should have no placeholders for tabpages");
1734 if (!bIsPlaceHolder
)
1735 pParent
= pTabControl
->GetPageParent();
1740 if (bIsPlaceHolder
|| name
== "GtkTreeSelection")
1743 extractButtonImage(id
, rMap
, name
== "GtkRadioButton");
1745 VclPtr
<vcl::Window
> xWindow
;
1746 if (name
== "GtkDialog" || name
== "GtkAboutDialog" || name
== "GtkAssistant")
1748 // WB_ALLOWMENUBAR because we don't know in advance if we will encounter
1749 // a menubar, and menubars need a BorderWindow in the toplevel, and
1750 // such border windows need to be in created during the dialog ctor
1751 WinBits nBits
= WB_MOVEABLE
|WB_3DLOOK
|WB_ALLOWMENUBAR
;
1752 if (extractResizable(rMap
))
1753 nBits
|= WB_SIZEABLE
;
1754 if (extractCloseable(rMap
))
1755 nBits
|= WB_CLOSEABLE
;
1756 Dialog::InitFlag eInit
= !pParent
? Dialog::InitFlag::NoParent
: Dialog::InitFlag::Default
;
1757 if (name
== "GtkAssistant")
1758 xWindow
= VclPtr
<vcl::RoadmapWizard
>::Create(pParent
, nBits
, eInit
);
1759 else if (name
== "GtkAboutDialog")
1760 xWindow
= VclPtr
<vcl::AboutDialog
>::Create(pParent
, nBits
, eInit
);
1762 xWindow
= VclPtr
<Dialog
>::Create(pParent
, nBits
, eInit
);
1763 #if HAVE_FEATURE_DESKTOP
1764 if (!m_bLegacy
&& !extractModal(rMap
))
1765 xWindow
->SetType(WindowType::MODELESSDIALOG
);
1768 else if (name
== "GtkMessageDialog")
1770 WinBits nBits
= WB_MOVEABLE
|WB_3DLOOK
|WB_CLOSEABLE
;
1771 if (extractResizable(rMap
))
1772 nBits
|= WB_SIZEABLE
;
1773 VclPtr
<MessageDialog
> xDialog(VclPtr
<MessageDialog
>::Create(pParent
, nBits
));
1774 m_pParserState
->m_aMessageDialogs
.push_back(xDialog
);
1777 xWindow
->set_border_width(3);
1779 xWindow
->set_border_width(12);
1782 else if (name
== "GtkBox" || name
== "GtkStatusbar")
1784 bVertical
= extractOrientation(rMap
);
1786 xWindow
= VclPtr
<VclVBox
>::Create(pParent
);
1788 xWindow
= VclPtr
<VclHBox
>::Create(pParent
);
1790 else if (name
== "GtkPaned")
1792 bVertical
= extractOrientation(rMap
);
1794 xWindow
= VclPtr
<VclVPaned
>::Create(pParent
);
1796 xWindow
= VclPtr
<VclHPaned
>::Create(pParent
);
1798 else if (name
== "GtkHBox")
1799 xWindow
= VclPtr
<VclHBox
>::Create(pParent
);
1800 else if (name
== "GtkVBox")
1801 xWindow
= VclPtr
<VclVBox
>::Create(pParent
);
1802 else if (name
== "GtkButtonBox")
1804 bVertical
= extractOrientation(rMap
);
1806 xWindow
= VclPtr
<VclVButtonBox
>::Create(pParent
);
1808 xWindow
= VclPtr
<VclHButtonBox
>::Create(pParent
);
1810 else if (name
== "GtkHButtonBox")
1811 xWindow
= VclPtr
<VclHButtonBox
>::Create(pParent
);
1812 else if (name
== "GtkVButtonBox")
1813 xWindow
= VclPtr
<VclVButtonBox
>::Create(pParent
);
1814 else if (name
== "GtkGrid")
1815 xWindow
= VclPtr
<VclGrid
>::Create(pParent
);
1816 else if (name
== "GtkFrame")
1817 xWindow
= VclPtr
<VclFrame
>::Create(pParent
);
1818 else if (name
== "GtkExpander")
1820 VclPtrInstance
<VclExpander
> pExpander(pParent
);
1821 m_pParserState
->m_aExpanderWidgets
.push_back(pExpander
);
1822 xWindow
= pExpander
;
1824 else if (name
== "GtkAlignment")
1825 xWindow
= VclPtr
<VclAlignment
>::Create(pParent
);
1826 else if (name
== "GtkButton" || (!m_bLegacy
&& name
== "GtkToggleButton"))
1828 VclPtr
<Button
> xButton
;
1829 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
1830 if (sMenu
.isEmpty())
1831 xButton
= extractStockAndBuildPushButton(pParent
, rMap
, name
== "GtkToggleButton", m_bLegacy
);
1834 assert(m_bLegacy
&& "use GtkMenuButton");
1835 xButton
= extractStockAndBuildMenuButton(pParent
, rMap
);
1836 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1838 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1839 setupFromActionName(xButton
, rMap
, m_xFrame
);
1842 else if (name
== "GtkMenuButton")
1844 VclPtr
<MenuButton
> xButton
= extractStockAndBuildMenuButton(pParent
, rMap
);
1845 OUString sMenu
= extractPopupMenu(rMap
);
1846 if (!sMenu
.isEmpty())
1847 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1848 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1849 xButton
->SetAccessibleRole(css::accessibility::AccessibleRole::BUTTON_MENU
);
1851 if (!extractDrawIndicator(rMap
))
1852 xButton
->SetDropDown(PushButtonDropdownStyle::NONE
);
1854 setupFromActionName(xButton
, rMap
, m_xFrame
);
1857 else if (name
== "GtkToggleButton" && m_bLegacy
)
1859 VclPtr
<Button
> xButton
;
1860 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
1861 assert(sMenu
.getLength() && "not implemented yet");
1862 xButton
= extractStockAndBuildMenuToggleButton(pParent
, rMap
);
1863 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
1864 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1865 setupFromActionName(xButton
, rMap
, m_xFrame
);
1868 else if (name
== "GtkRadioButton")
1870 extractGroup(id
, rMap
);
1871 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1872 OUString sWrap
= BuilderUtils::extractCustomProperty(rMap
);
1873 if (!sWrap
.isEmpty())
1874 nBits
|= WB_WORDBREAK
;
1875 VclPtr
<RadioButton
> xButton
= VclPtr
<RadioButton
>::Create(pParent
, nBits
);
1876 xButton
->SetImageAlign(ImageAlign::Left
); //default to left
1879 if (::extractStock(rMap
))
1881 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1884 else if (name
== "GtkCheckButton")
1886 WinBits nBits
= WB_CLIPCHILDREN
|WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
1887 OUString sWrap
= BuilderUtils::extractCustomProperty(rMap
);
1888 if (!sWrap
.isEmpty())
1889 nBits
|= WB_WORDBREAK
;
1890 //maybe always import as TriStateBox and enable/disable tristate
1891 bool bIsTriState
= extractInconsistent(rMap
);
1892 VclPtr
<CheckBox
> xCheckBox
;
1893 if (bIsTriState
&& m_bLegacy
)
1894 xCheckBox
= VclPtr
<TriStateBox
>::Create(pParent
, nBits
);
1896 xCheckBox
= VclPtr
<CheckBox
>::Create(pParent
, nBits
);
1899 xCheckBox
->EnableTriState(true);
1900 xCheckBox
->SetState(TRISTATE_INDET
);
1902 xCheckBox
->SetImageAlign(ImageAlign::Left
); //default to left
1904 xWindow
= xCheckBox
;
1906 if (::extractStock(rMap
))
1908 xWindow
->SetText(getStockText(extractLabel(rMap
)));
1911 else if (name
== "GtkSpinButton")
1913 OUString sAdjustment
= extractAdjustment(rMap
);
1914 OUString sPattern
= BuilderUtils::extractCustomProperty(rMap
);
1915 OUString sUnit
= extractUnit(sPattern
);
1917 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_BORDER
|WB_3DLOOK
;
1918 if (!id
.endsWith("-nospin"))
1919 nBits
|= WB_SPIN
| WB_REPEAT
;
1921 if (sPattern
.isEmpty())
1923 SAL_INFO("vcl.layout", "making numeric field for " << name
<< " " << sUnit
);
1926 connectNumericFormatterAdjustment(id
, sAdjustment
);
1927 xWindow
= VclPtr
<NumericField
>::Create(pParent
, nBits
);
1931 connectFormattedFormatterAdjustment(id
, sAdjustment
);
1932 VclPtrInstance
<FormattedField
> xField(pParent
, nBits
);
1933 xField
->SetMinValue(0);
1939 if (sPattern
== "hh:mm")
1941 connectTimeFormatterAdjustment(id
, sAdjustment
);
1942 SAL_INFO("vcl.layout", "making time field for " << name
<< " " << sUnit
);
1943 xWindow
= VclPtr
<TimeField
>::Create(pParent
, nBits
);
1945 else if (sPattern
== "yy:mm:dd")
1947 connectDateFormatterAdjustment(id
, sAdjustment
);
1948 SAL_INFO("vcl.layout", "making date field for " << name
<< " " << sUnit
);
1949 xWindow
= VclPtr
<DateField
>::Create(pParent
, nBits
);
1953 connectNumericFormatterAdjustment(id
, sAdjustment
);
1954 FieldUnit eUnit
= detectMetricUnit(sUnit
);
1955 SAL_INFO("vcl.layout", "making metric field for " << name
<< " " << sUnit
);
1956 VclPtrInstance
<MetricField
> xField(pParent
, nBits
);
1957 xField
->SetUnit(eUnit
);
1958 if (eUnit
== FieldUnit::CUSTOM
)
1959 xField
->SetCustomUnitText(sUnit
);
1964 else if (name
== "GtkLinkButton")
1965 xWindow
= VclPtr
<FixedHyperlink
>::Create(pParent
, WB_CENTER
|WB_VCENTER
|WB_3DLOOK
|WB_NOLABEL
);
1966 else if (name
== "GtkComboBox" || name
== "GtkComboBoxText")
1968 OUString sPattern
= BuilderUtils::extractCustomProperty(rMap
);
1969 extractModel(id
, rMap
);
1971 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
1973 bool bDropdown
= BuilderUtils::extractDropdown(rMap
);
1976 nBits
|= WB_DROPDOWN
;
1978 if (!sPattern
.isEmpty())
1980 OUString sAdjustment
= extractAdjustment(rMap
);
1981 connectNumericFormatterAdjustment(id
, sAdjustment
);
1982 OUString sUnit
= extractUnit(sPattern
);
1983 FieldUnit eUnit
= detectMetricUnit(sUnit
);
1984 SAL_WARN("vcl.layout", "making metric box for type: " << name
1985 << " unit: " << sUnit
1987 << " use a VclComboBoxNumeric instead");
1988 VclPtrInstance
<MetricBox
> xBox(pParent
, nBits
);
1989 xBox
->EnableAutoSize(true);
1990 xBox
->SetUnit(eUnit
);
1991 xBox
->SetDecimalDigits(extractDecimalDigits(sPattern
));
1992 if (eUnit
== FieldUnit::CUSTOM
)
1993 xBox
->SetCustomUnitText(sUnit
);
1996 else if (extractEntry(rMap
))
1998 VclPtrInstance
<ComboBox
> xComboBox(pParent
, nBits
);
1999 xComboBox
->EnableAutoSize(true);
2000 xWindow
= xComboBox
;
2004 VclPtrInstance
<ListBox
> xListBox(pParent
, nBits
|WB_SIMPLEMODE
);
2005 xListBox
->EnableAutoSize(true);
2009 else if (name
== "VclComboBoxNumeric")
2011 OUString sPattern
= BuilderUtils::extractCustomProperty(rMap
);
2012 OUString sAdjustment
= extractAdjustment(rMap
);
2013 extractModel(id
, rMap
);
2015 WinBits nBits
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
2017 bool bDropdown
= BuilderUtils::extractDropdown(rMap
);
2020 nBits
|= WB_DROPDOWN
;
2022 if (!sPattern
.isEmpty())
2024 connectNumericFormatterAdjustment(id
, sAdjustment
);
2025 OUString sUnit
= extractUnit(sPattern
);
2026 FieldUnit eUnit
= detectMetricUnit(sUnit
);
2027 SAL_INFO("vcl.layout", "making metric box for " << name
<< " " << sUnit
);
2028 VclPtrInstance
<MetricBox
> xBox(pParent
, nBits
);
2029 xBox
->EnableAutoSize(true);
2030 xBox
->SetUnit(eUnit
);
2031 xBox
->SetDecimalDigits(extractDecimalDigits(sPattern
));
2032 if (eUnit
== FieldUnit::CUSTOM
)
2033 xBox
->SetCustomUnitText(sUnit
);
2038 SAL_INFO("vcl.layout", "making numeric box for " << name
);
2039 connectNumericFormatterAdjustment(id
, sAdjustment
);
2040 VclPtrInstance
<NumericBox
> xBox(pParent
, nBits
);
2042 xBox
->EnableAutoSize(true);
2046 else if (name
== "GtkIconView")
2048 assert(rMap
.find(OString("model")) != rMap
.end() && "GtkIconView must have a model");
2050 //window we want to apply the packing props for this GtkIconView to
2051 VclPtr
<vcl::Window
> xWindowForPackingProps
;
2052 extractModel(id
, rMap
);
2053 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
2054 //IconView manages its own scrolling,
2055 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
2056 if (pRealParent
!= pParent
)
2057 nWinStyle
|= WB_BORDER
;
2059 VclPtr
<IconView
> xBox
= VclPtr
<IconView
>::Create(pRealParent
, nWinStyle
);
2060 xWindowForPackingProps
= xBox
;
2063 xBox
->SetNoAutoCurEntry(true);
2064 xBox
->SetQuickSearch(true);
2066 if (pRealParent
!= pParent
)
2067 cleanupWidgetOwnScrolling(pParent
, xWindowForPackingProps
, rMap
);
2069 else if (name
== "GtkTreeView")
2073 assert(rMap
.find(OString("model")) != rMap
.end() && "GtkTreeView must have a model");
2076 //window we want to apply the packing props for this GtkTreeView to
2077 VclPtr
<vcl::Window
> xWindowForPackingProps
;
2079 //a) make SvHeaderTabListBox/SvTabListBox the default target for GtkTreeView
2080 //b) remove the non-drop down mode of ListBox and convert
2081 // everything over to SvHeaderTabListBox/SvTabListBox
2082 //c) remove the users of makeSvTabListBox and makeSvTreeListBox
2083 extractModel(id
, rMap
);
2084 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
|WB_VCENTER
|WB_3DLOOK
;
2087 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
2088 if (!sBorder
.isEmpty())
2089 nWinStyle
|= WB_BORDER
;
2093 nWinStyle
|= WB_HASBUTTONS
| WB_HASBUTTONSATROOT
;
2095 //ListBox/SvHeaderTabListBox manages its own scrolling,
2096 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
2097 if (pRealParent
!= pParent
)
2098 nWinStyle
|= WB_BORDER
;
2101 xWindow
= VclPtr
<ListBox
>::Create(pRealParent
, nWinStyle
| WB_SIMPLEMODE
);
2102 xWindowForPackingProps
= xWindow
;
2106 VclPtr
<SvTabListBox
> xBox
;
2107 bool bHeadersVisible
= extractHeadersVisible(rMap
);
2108 if (bHeadersVisible
)
2110 VclPtr
<VclVBox
> xContainer
= VclPtr
<VclVBox
>::Create(pRealParent
);
2111 OString
containerid(id
+ "-container");
2112 xContainer
->SetHelpId(m_sHelpRoot
+ containerid
);
2113 m_aChildren
.emplace_back(containerid
, xContainer
, true);
2115 VclPtrInstance
<HeaderBar
> xHeader(xContainer
, WB_BUTTONSTYLE
| WB_BORDER
| WB_TABSTOP
| WB_3DLOOK
);
2116 xHeader
->set_width_request(0); // let the headerbar width not affect the size request
2117 OString
headerid(id
+ "-header");
2118 xHeader
->SetHelpId(m_sHelpRoot
+ headerid
);
2119 m_aChildren
.emplace_back(headerid
, xHeader
, true);
2121 VclPtr
<LclHeaderTabListBox
> xHeaderBox
= VclPtr
<LclHeaderTabListBox
>::Create(xContainer
, nWinStyle
);
2122 xHeaderBox
->InitHeaderBar(xHeader
);
2123 xContainer
->set_expand(true);
2127 xWindowForPackingProps
= xContainer
;
2131 xBox
= VclPtr
<LclTabListBox
>::Create(pRealParent
, nWinStyle
);
2132 xWindowForPackingProps
= xBox
;
2135 xBox
->SetNoAutoCurEntry(true);
2136 xBox
->SetQuickSearch(true);
2137 xBox
->SetSpaceBetweenEntries(3);
2138 xBox
->SetEntryHeight(16);
2139 xBox
->SetHighlightRange(); // select over the whole width
2141 if (pRealParent
!= pParent
)
2142 cleanupWidgetOwnScrolling(pParent
, xWindowForPackingProps
, rMap
);
2144 else if (name
== "GtkTreeViewColumn")
2148 SvHeaderTabListBox
* pTreeView
= dynamic_cast<SvHeaderTabListBox
*>(pParent
);
2149 if (HeaderBar
* pHeaderBar
= pTreeView
? pTreeView
->GetHeaderBar() : nullptr)
2151 HeaderBarItemBits nBits
= HeaderBarItemBits::LEFTIMAGE
;
2152 if (extractClickable(rMap
))
2153 nBits
|= HeaderBarItemBits::CLICKABLE
;
2154 if (extractSortIndicator(rMap
))
2155 nBits
|= HeaderBarItemBits::DOWNARROW
;
2156 float fAlign
= extractAlignment(rMap
);
2158 nBits
|= HeaderBarItemBits::LEFT
;
2159 else if (fAlign
== 1.0)
2160 nBits
|= HeaderBarItemBits::RIGHT
;
2161 else if (fAlign
== 0.5)
2162 nBits
|= HeaderBarItemBits::CENTER
;
2163 auto nItemId
= pHeaderBar
->GetItemCount() + 1;
2164 OUString
sTitle(extractTitle(rMap
));
2165 pHeaderBar
->InsertItem(nItemId
, sTitle
, 100, nBits
);
2169 else if (name
== "GtkLabel")
2171 WinBits nWinStyle
= WB_CENTER
|WB_VCENTER
|WB_3DLOOK
;
2172 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
2173 if (!sBorder
.isEmpty())
2174 nWinStyle
|= WB_BORDER
;
2175 extractMnemonicWidget(id
, rMap
);
2176 if (extractSelectable(rMap
))
2177 xWindow
= VclPtr
<SelectableFixedText
>::Create(pParent
, nWinStyle
);
2179 xWindow
= VclPtr
<FixedText
>::Create(pParent
, nWinStyle
);
2181 else if (name
== "GtkImage")
2183 extractStock(id
, rMap
);
2184 xWindow
= VclPtr
<FixedImage
>::Create(pParent
, WB_CENTER
|WB_VCENTER
|WB_3DLOOK
|WB_SCALE
);
2185 //such parentless GtkImages are temps used to set icons on buttons
2186 //default them to hidden to stop e.g. insert->index entry flicking temp
2187 //full screen windows
2190 rMap
["visible"] = "false";
2193 else if (name
== "GtkSeparator")
2195 bVertical
= extractOrientation(rMap
);
2196 xWindow
= VclPtr
<FixedLine
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2198 else if (name
== "GtkScrollbar")
2200 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aScrollAdjustmentMaps
);
2201 bVertical
= extractOrientation(rMap
);
2202 xWindow
= VclPtr
<ScrollBar
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2204 else if (name
== "GtkProgressBar")
2206 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aScrollAdjustmentMaps
);
2207 bVertical
= extractOrientation(rMap
);
2208 xWindow
= VclPtr
<ProgressBar
>::Create(pParent
, bVertical
? WB_VERT
: WB_HORZ
);
2210 else if (name
== "GtkScrolledWindow")
2212 xWindow
= VclPtr
<VclScrolledWindow
>::Create(pParent
);
2214 else if (name
== "GtkViewport")
2216 xWindow
= VclPtr
<VclViewport
>::Create(pParent
);
2218 else if (name
== "GtkEventBox")
2220 xWindow
= VclPtr
<VclEventBox
>::Create(pParent
);
2222 else if (name
== "GtkEntry")
2224 xWindow
= VclPtr
<Edit
>::Create(pParent
, WB_LEFT
|WB_VCENTER
|WB_BORDER
|WB_3DLOOK
);
2225 BuilderUtils::ensureDefaultWidthChars(rMap
);
2227 else if (name
== "GtkNotebook")
2229 if (!extractVerticalTabPos(rMap
))
2230 xWindow
= VclPtr
<TabControl
>::Create(pParent
, WB_STDTABCONTROL
|WB_3DLOOK
);
2232 xWindow
= VclPtr
<VerticalTabControl
>::Create(pParent
);
2234 else if (name
== "GtkDrawingArea")
2236 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
2237 xWindow
= VclPtr
<VclDrawingArea
>::Create(pParent
, sBorder
.isEmpty() ? WB_TABSTOP
: WB_BORDER
| WB_TABSTOP
);
2239 else if (name
== "GtkTextView")
2241 extractBuffer(id
, rMap
);
2243 WinBits nWinStyle
= WB_CLIPCHILDREN
|WB_LEFT
;
2246 OUString sBorder
= BuilderUtils::extractCustomProperty(rMap
);
2247 if (!sBorder
.isEmpty())
2248 nWinStyle
|= WB_BORDER
;
2250 //VclMultiLineEdit manages its own scrolling,
2251 vcl::Window
*pRealParent
= prepareWidgetOwnScrolling(pParent
, nWinStyle
);
2252 if (pRealParent
!= pParent
)
2253 nWinStyle
|= WB_BORDER
;
2254 xWindow
= VclPtr
<VclMultiLineEdit
>::Create(pRealParent
, nWinStyle
);
2255 if (pRealParent
!= pParent
)
2256 cleanupWidgetOwnScrolling(pParent
, xWindow
, rMap
);
2258 else if (name
== "GtkSpinner")
2260 xWindow
= VclPtr
<Throbber
>::Create(pParent
, WB_3DLOOK
);
2262 else if (name
== "GtkScale")
2264 extractAdjustmentToMap(id
, rMap
, m_pParserState
->m_aSliderAdjustmentMaps
);
2265 bool bDrawValue
= extractDrawValue(rMap
);
2268 OUString sValuePos
= extractValuePos(rMap
);
2271 bVertical
= extractOrientation(rMap
);
2273 WinBits nWinStyle
= bVertical
? WB_VERT
: WB_HORZ
;
2275 xWindow
= VclPtr
<Slider
>::Create(pParent
, nWinStyle
);
2277 else if (name
== "GtkToolbar")
2279 xWindow
= VclPtr
<ToolBox
>::Create(pParent
, WB_3DLOOK
| WB_TABSTOP
);
2281 else if(name
== "NotebookBarAddonsToolMergePoint")
2283 customMakeWidget pFunction
= GetCustomMakeWidget("sfxlo-NotebookbarToolBox");
2284 if(pFunction
!= nullptr)
2285 NotebookBarAddonsMerger::MergeNotebookBarAddons(pParent
, pFunction
, m_xFrame
, *m_pNotebookBarAddonsItem
, rMap
);
2288 else if (name
== "GtkToolButton" || name
== "GtkMenuToolButton" ||
2289 name
== "GtkToggleToolButton" || name
== "GtkRadioToolButton")
2291 ToolBox
*pToolBox
= dynamic_cast<ToolBox
*>(pParent
);
2294 OUString
aCommand(extractActionName(rMap
));
2296 sal_uInt16 nItemId
= 0;
2297 ToolBoxItemBits nBits
= ToolBoxItemBits::NONE
;
2298 if (name
== "GtkMenuToolButton")
2299 nBits
|= ToolBoxItemBits::DROPDOWN
;
2300 else if (name
== "GtkToggleToolButton")
2301 nBits
|= ToolBoxItemBits::AUTOCHECK
| ToolBoxItemBits::CHECKABLE
;
2302 else if (name
== "GtkRadioToolButton")
2303 nBits
|= ToolBoxItemBits::AUTOCHECK
| ToolBoxItemBits::RADIOCHECK
;
2305 if (!aCommand
.isEmpty() && m_xFrame
.is())
2307 pToolBox
->InsertItem(aCommand
, m_xFrame
, nBits
, extractSizeRequest(rMap
));
2308 nItemId
= pToolBox
->GetItemId(aCommand
);
2312 nItemId
= pToolBox
->GetItemCount() + 1;
2313 //TODO: ImplToolItems::size_type -> sal_uInt16!
2314 pToolBox
->InsertItem(nItemId
, extractLabel(rMap
), nBits
);
2315 if (aCommand
.isEmpty() && !m_bLegacy
)
2316 aCommand
= OUString::fromUtf8(id
);
2317 pToolBox
->SetItemCommand(nItemId
, aCommand
);
2320 pToolBox
->SetHelpId(nItemId
, m_sHelpRoot
+ id
);
2321 OUString
sTooltip(extractTooltipText(rMap
));
2322 if (!sTooltip
.isEmpty())
2323 pToolBox
->SetQuickHelpText(nItemId
, sTooltip
);
2325 OUString
sIconName(extractIconName(rMap
));
2326 if (!sIconName
.isEmpty())
2327 pToolBox
->SetItemImage(nItemId
, FixedImage::loadThemeImage(sIconName
));
2329 if (!extractVisible(rMap
))
2330 pToolBox
->HideItem(nItemId
);
2332 m_pParserState
->m_nLastToolbarId
= nItemId
;
2334 return nullptr; // no widget to be created
2337 else if (name
== "GtkSeparatorToolItem")
2339 ToolBox
*pToolBox
= dynamic_cast<ToolBox
*>(pParent
);
2342 pToolBox
->InsertSeparator();
2343 return nullptr; // no widget to be created
2346 else if (name
== "GtkWindow")
2348 WinBits nBits
= extractDeferredBits(rMap
);
2349 if (nBits
& WB_DOCKABLE
)
2350 xWindow
= VclPtr
<DockingWindow
>::Create(pParent
, nBits
|WB_MOVEABLE
);
2352 xWindow
= VclPtr
<FloatingWindow
>::Create(pParent
, nBits
|WB_MOVEABLE
);
2354 else if (name
== "GtkPopover")
2356 WinBits nBits
= extractDeferredBits(rMap
);
2357 xWindow
= VclPtr
<DockingWindow
>::Create(pParent
, nBits
|WB_DOCKABLE
|WB_MOVEABLE
);
2359 else if (name
== "GtkCalendar")
2361 WinBits nBits
= extractDeferredBits(rMap
);
2362 xWindow
= VclPtr
<Calendar
>::Create(pParent
, nBits
);
2366 if (customMakeWidget pFunction
= GetCustomMakeWidget(name
))
2368 pFunction(xWindow
, pParent
, rMap
);
2369 if (xWindow
->GetType() == WindowType::PUSHBUTTON
)
2370 setupFromActionName(static_cast<Button
*>(xWindow
.get()), rMap
, m_xFrame
);
2371 else if (xWindow
->GetType() == WindowType::MENUBUTTON
)
2373 OUString sMenu
= BuilderUtils::extractCustomProperty(rMap
);
2374 if (!sMenu
.isEmpty())
2375 m_pParserState
->m_aButtonMenuMaps
.emplace_back(id
, sMenu
);
2376 setupFromActionName(static_cast<Button
*>(xWindow
.get()), rMap
, m_xFrame
);
2380 SAL_INFO_IF(!xWindow
, "vcl.layout", "probably need to implement " << name
<< " or add a make" << name
<< " function");
2383 xWindow
->SetHelpId(m_sHelpRoot
+ id
);
2384 SAL_INFO("vcl.layout", "for " << name
<<
2385 ", created " << xWindow
.get() << " child of " <<
2386 pParent
<< "(" << xWindow
->ImplGetWindowImpl()->mpParent
.get() << "/" <<
2387 xWindow
->ImplGetWindowImpl()->mpRealParent
.get() << "/" <<
2388 xWindow
->ImplGetWindowImpl()->mpBorderWindow
.get() << ") with helpid " <<
2389 xWindow
->GetHelpId());
2390 m_aChildren
.emplace_back(id
, xWindow
, bVertical
);
2397 //return true for window types which exist in vcl but are not themselves
2398 //represented in the .ui format, i.e. only their children exist.
2399 bool isConsideredGtkPseudo(vcl::Window
const *pWindow
)
2401 return pWindow
->GetType() == WindowType::TABPAGE
;
2405 //Any properties from .ui load we couldn't set because of potential virtual methods
2406 //during ctor are applied here
2407 void VclBuilder::setDeferredProperties()
2409 if (!m_bToplevelHasDeferredProperties
)
2411 stringmap aDeferredProperties
;
2412 aDeferredProperties
.swap(m_aDeferredProperties
);
2413 m_bToplevelHasDeferredProperties
= false;
2414 BuilderUtils::set_properties(m_pParent
, aDeferredProperties
);
2417 namespace BuilderUtils
2419 void set_properties(vcl::Window
*pWindow
, const VclBuilder::stringmap
&rProps
)
2421 for (auto const& prop
: rProps
)
2423 const OString
&rKey
= prop
.first
;
2424 const OUString
&rValue
= prop
.second
;
2425 pWindow
->set_property(rKey
, rValue
);
2429 OUString
convertMnemonicMarkup(const OUString
&rIn
)
2431 OUStringBuffer
aRet(rIn
);
2432 for (sal_Int32 nI
= 0; nI
< aRet
.getLength(); ++nI
)
2434 if (aRet
[nI
] == '_' && nI
+1 < aRet
.getLength())
2436 if (aRet
[nI
+1] != '_')
2437 aRet
[nI
] = MNEMONIC_CHAR
;
2443 return aRet
.makeStringAndClear();
2446 OUString
extractCustomProperty(VclBuilder::stringmap
&rMap
)
2448 OUString sCustomProperty
;
2449 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("customproperty"));
2450 if (aFind
!= rMap
.end())
2452 sCustomProperty
= aFind
->second
;
2455 return sCustomProperty
;
2458 FieldUnit
detectUnit(OUString
const& rString
)
2460 OUString
const unit(extractUnit(rString
));
2461 return detectMetricUnit(unit
);
2464 void ensureDefaultWidthChars(VclBuilder::stringmap
&rMap
)
2466 OString
sWidthChars("width-chars");
2467 VclBuilder::stringmap::iterator aFind
= rMap
.find(sWidthChars
);
2468 if (aFind
== rMap
.end())
2469 rMap
[sWidthChars
] = "25";
2472 bool extractDropdown(VclBuilder::stringmap
&rMap
)
2474 bool bDropdown
= true;
2475 VclBuilder::stringmap::iterator aFind
= rMap
.find(OString("dropdown"));
2476 if (aFind
!= rMap
.end())
2478 bDropdown
= toBool(aFind
->second
);
2484 void reorderWithinParent(vcl::Window
&rWindow
, sal_uInt16 nNewPosition
)
2486 WindowImpl
*pWindowImpl
= rWindow
.ImplGetWindowImpl();
2487 if (pWindowImpl
->mpParent
!= pWindowImpl
->mpRealParent
)
2489 assert(pWindowImpl
->mpBorderWindow
== pWindowImpl
->mpParent
);
2490 assert(pWindowImpl
->mpBorderWindow
->ImplGetWindowImpl()->mpParent
== pWindowImpl
->mpRealParent
);
2491 reorderWithinParent(*pWindowImpl
->mpBorderWindow
, nNewPosition
);
2494 rWindow
.reorderWithinParent(nNewPosition
);
2497 void reorderWithinParent(std::vector
<vcl::Window
*>& rChilds
, bool bIsButtonBox
)
2499 for (size_t i
= 0; i
< rChilds
.size(); ++i
)
2501 reorderWithinParent(*rChilds
[i
], i
);
2506 //The first member of the group for legacy code needs WB_GROUP set and the
2508 WinBits nBits
= rChilds
[i
]->GetStyle();
2512 rChilds
[i
]->SetStyle(nBits
);
2516 sal_Int16
getRoleFromName(const OString
& roleName
)
2518 using namespace com::sun::star::accessibility
;
2520 static const std::unordered_map
<OString
, sal_Int16
> aAtkRoleToAccessibleRole
= {
2521 /* This is in atkobject.h's AtkRole order */
2522 { "invalid", AccessibleRole::UNKNOWN
},
2523 { "accelerator label", AccessibleRole::UNKNOWN
},
2524 { "alert", AccessibleRole::ALERT
},
2525 { "animation", AccessibleRole::UNKNOWN
},
2526 { "arrow", AccessibleRole::UNKNOWN
},
2527 { "calendar", AccessibleRole::UNKNOWN
},
2528 { "canvas", AccessibleRole::CANVAS
},
2529 { "check box", AccessibleRole::CHECK_BOX
},
2530 { "check menu item", AccessibleRole::CHECK_MENU_ITEM
},
2531 { "color chooser", AccessibleRole::COLOR_CHOOSER
},
2532 { "column header", AccessibleRole::COLUMN_HEADER
},
2533 { "combo box", AccessibleRole::COMBO_BOX
},
2534 { "date editor", AccessibleRole::DATE_EDITOR
},
2535 { "desktop icon", AccessibleRole::DESKTOP_ICON
},
2536 { "desktop frame", AccessibleRole::DESKTOP_PANE
}, // ?
2537 { "dial", AccessibleRole::UNKNOWN
},
2538 { "dialog", AccessibleRole::DIALOG
},
2539 { "directory pane", AccessibleRole::DIRECTORY_PANE
},
2540 { "drawing area", AccessibleRole::UNKNOWN
},
2541 { "file chooser", AccessibleRole::FILE_CHOOSER
},
2542 { "filler", AccessibleRole::FILLER
},
2543 { "font chooser", AccessibleRole::FONT_CHOOSER
},
2544 { "frame", AccessibleRole::FRAME
},
2545 { "glass pane", AccessibleRole::GLASS_PANE
},
2546 { "html container", AccessibleRole::UNKNOWN
},
2547 { "icon", AccessibleRole::ICON
},
2548 { "image", AccessibleRole::GRAPHIC
},
2549 { "internal frame", AccessibleRole::INTERNAL_FRAME
},
2550 { "label", AccessibleRole::LABEL
},
2551 { "layered pane", AccessibleRole::LAYERED_PANE
},
2552 { "list", AccessibleRole::LIST
},
2553 { "list item", AccessibleRole::LIST_ITEM
},
2554 { "menu", AccessibleRole::MENU
},
2555 { "menu bar", AccessibleRole::MENU_BAR
},
2556 { "menu item", AccessibleRole::MENU_ITEM
},
2557 { "option pane", AccessibleRole::OPTION_PANE
},
2558 { "page tab", AccessibleRole::PAGE_TAB
},
2559 { "page tab list", AccessibleRole::PAGE_TAB_LIST
},
2560 { "panel", AccessibleRole::PANEL
}, // or SHAPE or TEXT_FRAME ?
2561 { "password text", AccessibleRole::PASSWORD_TEXT
},
2562 { "popup menu", AccessibleRole::POPUP_MENU
},
2563 { "progress bar", AccessibleRole::PROGRESS_BAR
},
2564 { "push button", AccessibleRole::PUSH_BUTTON
}, // or BUTTON_DROPDOWN or BUTTON_MENU
2565 { "radio button", AccessibleRole::RADIO_BUTTON
},
2566 { "radio menu item", AccessibleRole::RADIO_MENU_ITEM
},
2567 { "root pane", AccessibleRole::ROOT_PANE
},
2568 { "row header", AccessibleRole::ROW_HEADER
},
2569 { "scroll bar", AccessibleRole::SCROLL_BAR
},
2570 { "scroll pane", AccessibleRole::SCROLL_PANE
},
2571 { "separator", AccessibleRole::SEPARATOR
},
2572 { "slider", AccessibleRole::SLIDER
},
2573 { "split pane", AccessibleRole::SPLIT_PANE
},
2574 { "spin button", AccessibleRole::SPIN_BOX
}, // ?
2575 { "statusbar", AccessibleRole::STATUS_BAR
},
2576 { "table", AccessibleRole::TABLE
},
2577 { "table cell", AccessibleRole::TABLE_CELL
},
2578 { "table column header", AccessibleRole::COLUMN_HEADER
}, // approximate
2579 { "table row header", AccessibleRole::ROW_HEADER
}, // approximate
2580 { "tear off menu item", AccessibleRole::UNKNOWN
},
2581 { "terminal", AccessibleRole::UNKNOWN
},
2582 { "text", AccessibleRole::TEXT
},
2583 { "toggle button", AccessibleRole::TOGGLE_BUTTON
},
2584 { "tool bar", AccessibleRole::TOOL_BAR
},
2585 { "tool tip", AccessibleRole::TOOL_TIP
},
2586 { "tree", AccessibleRole::TREE
},
2587 { "tree table", AccessibleRole::TREE_TABLE
},
2588 { "unknown", AccessibleRole::UNKNOWN
},
2589 { "viewport", AccessibleRole::VIEW_PORT
},
2590 { "window", AccessibleRole::WINDOW
},
2591 { "header", AccessibleRole::HEADER
},
2592 { "footer", AccessibleRole::FOOTER
},
2593 { "paragraph", AccessibleRole::PARAGRAPH
},
2594 { "ruler", AccessibleRole::RULER
},
2595 { "application", AccessibleRole::UNKNOWN
},
2596 { "autocomplete", AccessibleRole::UNKNOWN
},
2597 { "edit bar", AccessibleRole::EDIT_BAR
},
2598 { "embedded", AccessibleRole::EMBEDDED_OBJECT
},
2599 { "entry", AccessibleRole::UNKNOWN
},
2600 { "chart", AccessibleRole::CHART
},
2601 { "caption", AccessibleRole::CAPTION
},
2602 { "document frame", AccessibleRole::DOCUMENT
},
2603 { "heading", AccessibleRole::HEADING
},
2604 { "page", AccessibleRole::PAGE
},
2605 { "section", AccessibleRole::SECTION
},
2606 { "redundant object", AccessibleRole::UNKNOWN
},
2607 { "form", AccessibleRole::FORM
},
2608 { "link", AccessibleRole::HYPER_LINK
},
2609 { "input method window", AccessibleRole::UNKNOWN
},
2610 { "table row", AccessibleRole::UNKNOWN
},
2611 { "tree item", AccessibleRole::TREE_ITEM
},
2612 { "document spreadsheet", AccessibleRole::DOCUMENT_SPREADSHEET
},
2613 { "document presentation", AccessibleRole::DOCUMENT_PRESENTATION
},
2614 { "document text", AccessibleRole::DOCUMENT_TEXT
},
2615 { "document web", AccessibleRole::DOCUMENT
}, // approximate
2616 { "document email", AccessibleRole::DOCUMENT
}, // approximate
2617 { "comment", AccessibleRole::COMMENT
}, // or NOTE or END_NOTE or FOOTNOTE or SCROLL_PANE
2618 { "list box", AccessibleRole::UNKNOWN
},
2619 { "grouping", AccessibleRole::GROUP_BOX
},
2620 { "image map", AccessibleRole::IMAGE_MAP
},
2621 { "notification", AccessibleRole::UNKNOWN
},
2622 { "info bar", AccessibleRole::UNKNOWN
},
2623 { "level bar", AccessibleRole::UNKNOWN
},
2624 { "title bar", AccessibleRole::UNKNOWN
},
2625 { "block quote", AccessibleRole::UNKNOWN
},
2626 { "audio", AccessibleRole::UNKNOWN
},
2627 { "video", AccessibleRole::UNKNOWN
},
2628 { "definition", AccessibleRole::UNKNOWN
},
2629 { "article", AccessibleRole::UNKNOWN
},
2630 { "landmark", AccessibleRole::UNKNOWN
},
2631 { "log", AccessibleRole::UNKNOWN
},
2632 { "marquee", AccessibleRole::UNKNOWN
},
2633 { "math", AccessibleRole::UNKNOWN
},
2634 { "rating", AccessibleRole::UNKNOWN
},
2635 { "timer", AccessibleRole::UNKNOWN
},
2636 { "description list", AccessibleRole::UNKNOWN
},
2637 { "description term", AccessibleRole::UNKNOWN
},
2638 { "description value", AccessibleRole::UNKNOWN
},
2639 { "static", AccessibleRole::STATIC
},
2640 { "math fraction", AccessibleRole::UNKNOWN
},
2641 { "math root", AccessibleRole::UNKNOWN
},
2642 { "subscript", AccessibleRole::UNKNOWN
},
2643 { "superscript", AccessibleRole::UNKNOWN
},
2644 { "footnote", AccessibleRole::FOOTNOTE
},
2647 auto it
= aAtkRoleToAccessibleRole
.find(roleName
);
2648 if (it
== aAtkRoleToAccessibleRole
.end())
2649 return AccessibleRole::UNKNOWN
;
2654 VclPtr
<vcl::Window
> VclBuilder::insertObject(vcl::Window
*pParent
, const OString
&rClass
,
2655 const OString
&rID
, stringmap
&rProps
, stringmap
&rPango
, stringmap
&rAtk
)
2657 VclPtr
<vcl::Window
> pCurrentChild
;
2659 if (m_pParent
&& !isConsideredGtkPseudo(m_pParent
) && !m_sID
.isEmpty() && rID
== m_sID
)
2661 pCurrentChild
= m_pParent
;
2663 //toplevels default to resizable and apparently you can't change them
2664 //afterwards, so we need to wait until now before we can truly
2665 //initialize the dialog.
2666 if (pParent
&& pParent
->IsSystemWindow())
2668 SystemWindow
*pSysWin
= static_cast<SystemWindow
*>(pCurrentChild
.get());
2669 pSysWin
->doDeferredInit(extractDeferredBits(rProps
));
2670 m_bToplevelHasDeferredInit
= false;
2672 else if (pParent
&& pParent
->IsDockingWindow())
2674 DockingWindow
*pDockWin
= static_cast<DockingWindow
*>(pCurrentChild
.get());
2675 pDockWin
->doDeferredInit(extractDeferredBits(rProps
));
2676 m_bToplevelHasDeferredInit
= false;
2679 if (pCurrentChild
->GetHelpId().isEmpty())
2681 pCurrentChild
->SetHelpId(m_sHelpRoot
+ m_sID
);
2682 SAL_INFO("vcl.layout", "for toplevel dialog " << this << " " <<
2683 rID
<< ", set helpid " << pCurrentChild
->GetHelpId());
2685 m_bToplevelParentFound
= true;
2689 //if we're being inserting under a toplevel dialog whose init is
2690 //deferred due to waiting to encounter it in this .ui, and it hasn't
2691 //been seen yet, then make unattached widgets parent-less toplevels
2692 if (pParent
== m_pParent
.get() && m_bToplevelHasDeferredInit
)
2694 pCurrentChild
= makeObject(pParent
, rClass
, rID
, rProps
);
2699 pCurrentChild
->set_id(OStringToOUString(rID
, RTL_TEXTENCODING_UTF8
));
2700 if (pCurrentChild
== m_pParent
.get() && m_bToplevelHasDeferredProperties
)
2701 m_aDeferredProperties
= rProps
;
2703 BuilderUtils::set_properties(pCurrentChild
, rProps
);
2705 for (auto const& elem
: rPango
)
2707 const OString
&rKey
= elem
.first
;
2708 const OUString
&rValue
= elem
.second
;
2709 pCurrentChild
->set_font_attribute(rKey
, rValue
);
2712 m_pParserState
->m_aAtkInfo
[pCurrentChild
] = rAtk
;
2720 pCurrentChild
= m_aChildren
.empty() ? pParent
: m_aChildren
.back().m_pWindow
.get();
2721 return pCurrentChild
;
2724 void VclBuilder::handleTabChild(vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
2726 std::vector
<OString
> sIDs
;
2729 stringmap aProperties
;
2730 std::vector
<vcl::EnumContext::Context
> context
;
2734 xmlreader::Span name
;
2737 xmlreader::XmlReader::Result res
= reader
.nextItem(
2738 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
2740 if (res
== xmlreader::XmlReader::Result::Begin
)
2743 if (name
== "object")
2745 while (reader
.nextAttribute(&nsId
, &name
))
2749 name
= reader
.getAttributeValue(false);
2750 OString
sID(name
.begin
, name
.length
);
2751 sal_Int32 nDelim
= sID
.indexOf(':');
2754 OString sPattern
= sID
.copy(nDelim
+1);
2755 aProperties
[OString("customproperty")] = OUString::fromUtf8(sPattern
);
2756 sID
= sID
.copy(0, nDelim
);
2758 sIDs
.push_back(sID
);
2762 else if (name
== "style")
2765 context
= handleStyle(reader
, nPriority
);
2768 else if (name
== "property")
2769 collectProperty(reader
, aProperties
);
2772 if (res
== xmlreader::XmlReader::Result::End
)
2778 if (res
== xmlreader::XmlReader::Result::Done
)
2785 TabControl
*pTabControl
= pParent
->GetType() == WindowType::TABCONTROL
?
2786 static_cast<TabControl
*>(pParent
) : nullptr;
2787 VerticalTabControl
*pVerticalTabControl
= pParent
->GetType() == WindowType::VERTICALTABCONTROL
?
2788 static_cast<VerticalTabControl
*>(pParent
) : nullptr;
2789 assert(pTabControl
|| pVerticalTabControl
);
2790 VclBuilder::stringmap::iterator aFind
= aProperties
.find(OString("label"));
2791 if (aFind
!= aProperties
.end())
2795 sal_uInt16 nPageId
= pTabControl
->GetCurPageId();
2796 pTabControl
->SetPageText(nPageId
, aFind
->second
);
2797 pTabControl
->SetPageName(nPageId
, sIDs
.back());
2798 if (!context
.empty())
2800 TabPage
* pPage
= pTabControl
->GetTabPage(nPageId
);
2801 pPage
->SetContext(context
);
2806 OUString
sLabel(aFind
->second
);
2807 OUString
sIconName(extractIconName(aProperties
));
2808 OUString
sTooltip(extractTooltipText(aProperties
));
2809 pVerticalTabControl
->InsertPage(sIDs
.front(), sLabel
, FixedImage::loadThemeImage(sIconName
), sTooltip
,
2810 pVerticalTabControl
->GetPageParent()->GetWindow(GetWindowType::LastChild
));
2816 pTabControl
->RemovePage(pTabControl
->GetCurPageId());
2820 //so that tabbing between controls goes in a visually sensible sequence
2821 //we sort these into a best-tab-order sequence
2822 bool VclBuilder::sortIntoBestTabTraversalOrder::operator()(const vcl::Window
*pA
, const vcl::Window
*pB
) const
2824 //sort child order within parent list by grid position
2825 sal_Int32 nTopA
= pA
->get_grid_top_attach();
2826 sal_Int32 nTopB
= pB
->get_grid_top_attach();
2831 sal_Int32 nLeftA
= pA
->get_grid_left_attach();
2832 sal_Int32 nLeftB
= pB
->get_grid_left_attach();
2833 if (nLeftA
< nLeftB
)
2835 if (nLeftA
> nLeftB
)
2837 //sort into two groups of pack start and pack end
2838 VclPackType ePackA
= pA
->get_pack_type();
2839 VclPackType ePackB
= pB
->get_pack_type();
2840 if (ePackA
< ePackB
)
2842 if (ePackA
> ePackB
)
2844 bool bVerticalContainer
= m_pBuilder
->get_window_packing_data(pA
->GetParent()).m_bVerticalOrient
;
2845 bool bPackA
= pA
->get_secondary();
2846 bool bPackB
= pB
->get_secondary();
2847 if (!bVerticalContainer
)
2849 //for horizontal boxes group secondaries before primaries
2850 if (bPackA
> bPackB
)
2852 if (bPackA
< bPackB
)
2857 //for vertical boxes group secondaries after primaries
2858 if (bPackA
< bPackB
)
2860 if (bPackA
> bPackB
)
2863 //honour relative box positions with pack group, (numerical order is reversed
2864 //for VclPackType::End, they are packed from the end back, but here we need
2865 //them in visual layout order so that tabbing works as expected)
2866 sal_Int32 nPackA
= m_pBuilder
->get_window_packing_data(pA
).m_nPosition
;
2867 sal_Int32 nPackB
= m_pBuilder
->get_window_packing_data(pB
).m_nPosition
;
2868 if (nPackA
< nPackB
)
2869 return ePackA
== VclPackType::Start
;
2870 if (nPackA
> nPackB
)
2871 return ePackA
!= VclPackType::Start
;
2872 //sort labels of Frames before body
2873 if (pA
->GetParent() == pB
->GetParent())
2875 const VclFrame
*pFrameParent
= dynamic_cast<const VclFrame
*>(pA
->GetParent());
2878 const vcl::Window
*pLabel
= pFrameParent
->get_label_widget();
2879 int nFramePosA
= (pA
== pLabel
) ? 0 : 1;
2880 int nFramePosB
= (pB
== pLabel
) ? 0 : 1;
2881 return nFramePosA
< nFramePosB
;
2887 void VclBuilder::handleChild(vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
2889 vcl::Window
*pCurrentChild
= nullptr;
2891 xmlreader::Span name
;
2893 OString sType
, sInternalChild
;
2895 while (reader
.nextAttribute(&nsId
, &name
))
2899 name
= reader
.getAttributeValue(false);
2900 sType
= OString(name
.begin
, name
.length
);
2902 else if (name
== "internal-child")
2904 name
= reader
.getAttributeValue(false);
2905 sInternalChild
= OString(name
.begin
, name
.length
);
2911 handleTabChild(pParent
, reader
);
2918 xmlreader::XmlReader::Result res
= reader
.nextItem(
2919 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
2921 if (res
== xmlreader::XmlReader::Result::Begin
)
2923 if (name
== "object" || name
== "placeholder")
2925 pCurrentChild
= handleObject(pParent
, reader
).get();
2927 bool bObjectInserted
= pCurrentChild
&& pParent
!= pCurrentChild
;
2929 if (bObjectInserted
)
2931 //Internal-children default in glade to not having their visible bits set
2932 //even though they are visible (generally anyway)
2933 if (!sInternalChild
.isEmpty())
2934 pCurrentChild
->Show();
2936 //Select the first page if it's a notebook
2937 if (pCurrentChild
->GetType() == WindowType::TABCONTROL
)
2939 TabControl
*pTabControl
= static_cast<TabControl
*>(pCurrentChild
);
2940 pTabControl
->SetCurPageId(pTabControl
->GetPageId(0));
2942 //To-Do add reorder capability to the TabControl
2946 // We want to sort labels before contents of frames
2947 // for keyboard traversal, especially if there
2948 // are multiple widgets using the same mnemonic
2949 if (sType
== "label")
2951 if (VclFrame
*pFrameParent
= dynamic_cast<VclFrame
*>(pParent
))
2952 pFrameParent
->designate_label(pCurrentChild
);
2954 if (sInternalChild
.startsWith("vbox") || sInternalChild
.startsWith("messagedialog-vbox"))
2956 if (Dialog
*pBoxParent
= dynamic_cast<Dialog
*>(pParent
))
2957 pBoxParent
->set_content_area(static_cast<VclBox
*>(pCurrentChild
)); // FIXME-VCLPTR
2959 else if (sInternalChild
.startsWith("action_area") || sInternalChild
.startsWith("messagedialog-action_area"))
2961 vcl::Window
*pContentArea
= pCurrentChild
->GetParent();
2962 if (Dialog
*pBoxParent
= dynamic_cast<Dialog
*>(pContentArea
? pContentArea
->GetParent() : nullptr))
2964 pBoxParent
->set_action_area(static_cast<VclButtonBox
*>(pCurrentChild
)); // FIXME-VCLPTR
2968 bool bIsButtonBox
= dynamic_cast<VclButtonBox
*>(pCurrentChild
) != nullptr;
2970 //To-Do make reorder a virtual in Window, move this foo
2971 //there and see above
2972 std::vector
<vcl::Window
*> aChilds
;
2973 for (vcl::Window
* pChild
= pCurrentChild
->GetWindow(GetWindowType::FirstChild
); pChild
;
2974 pChild
= pChild
->GetWindow(GetWindowType::Next
))
2978 if (PushButton
* pPushButton
= dynamic_cast<PushButton
*>(pChild
))
2979 pPushButton
->setAction(true);
2982 aChilds
.push_back(pChild
);
2985 //sort child order within parent so that tabbing
2986 //between controls goes in a visually sensible sequence
2987 std::stable_sort(aChilds
.begin(), aChilds
.end(), sortIntoBestTabTraversalOrder(this));
2988 BuilderUtils::reorderWithinParent(aChilds
, bIsButtonBox
);
2992 else if (name
== "packing")
2994 handlePacking(pCurrentChild
, pParent
, reader
);
2996 else if (name
== "interface")
2998 while (reader
.nextAttribute(&nsId
, &name
))
3000 if (name
== "domain")
3002 name
= reader
.getAttributeValue(false);
3003 sType
= OString(name
.begin
, name
.length
);
3004 m_pParserState
->m_aResLocale
= Translate::Create(sType
.getStr());
3013 if (res
== xmlreader::XmlReader::Result::End
)
3019 if (res
== xmlreader::XmlReader::Result::Done
)
3024 void VclBuilder::collectPangoAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
3026 xmlreader::Span span
;
3032 while (reader
.nextAttribute(&nsId
, &span
))
3036 span
= reader
.getAttributeValue(false);
3037 sProperty
= OString(span
.begin
, span
.length
);
3039 else if (span
== "value")
3041 span
= reader
.getAttributeValue(false);
3042 sValue
= OString(span
.begin
, span
.length
);
3046 if (!sProperty
.isEmpty())
3047 rMap
[sProperty
] = OUString::fromUtf8(sValue
);
3050 void VclBuilder::collectAtkRelationAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
3052 xmlreader::Span span
;
3058 while (reader
.nextAttribute(&nsId
, &span
))
3062 span
= reader
.getAttributeValue(false);
3063 sProperty
= OString(span
.begin
, span
.length
);
3065 else if (span
== "target")
3067 span
= reader
.getAttributeValue(false);
3068 sValue
= OString(span
.begin
, span
.length
);
3069 sal_Int32 nDelim
= sValue
.indexOf(':');
3071 sValue
= sValue
.copy(0, nDelim
);
3075 if (!sProperty
.isEmpty())
3076 rMap
[sProperty
] = OUString::fromUtf8(sValue
);
3079 void VclBuilder::collectAtkRoleAttribute(xmlreader::XmlReader
&reader
, stringmap
&rMap
)
3081 xmlreader::Span span
;
3086 while (reader
.nextAttribute(&nsId
, &span
))
3090 span
= reader
.getAttributeValue(false);
3091 sProperty
= OString(span
.begin
, span
.length
);
3095 if (!sProperty
.isEmpty())
3096 rMap
["role"] = OUString::fromUtf8(sProperty
);
3099 void VclBuilder::handleRow(xmlreader::XmlReader
&reader
, const OString
&rID
)
3103 ListStore::row aRow
;
3107 xmlreader::Span name
;
3110 xmlreader::XmlReader::Result res
= reader
.nextItem(
3111 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3113 if (res
== xmlreader::XmlReader::Result::Done
)
3116 if (res
== xmlreader::XmlReader::Result::Begin
)
3121 bool bTranslated
= false;
3125 while (reader
.nextAttribute(&nsId
, &name
))
3129 name
= reader
.getAttributeValue(false);
3130 nId
= OString(name
.begin
, name
.length
).toInt32();
3132 else if (nId
== 0 && name
== "translatable" && reader
.getAttributeValue(false) == "yes")
3136 else if (name
== "context")
3138 name
= reader
.getAttributeValue(false);
3139 sContext
= OString(name
.begin
, name
.length
);
3144 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3146 OString
sValue(name
.begin
, name
.length
);
3147 OUString sFinalValue
;
3150 if (!sContext
.isEmpty())
3151 sValue
= sContext
+ "\004" + sValue
;
3152 sFinalValue
= Translate::get(sValue
.getStr(), m_pParserState
->m_aResLocale
);
3155 sFinalValue
= OUString::fromUtf8(sValue
);
3158 if (aRow
.size() < nId
+1)
3160 aRow
[nId
] = sFinalValue
;
3164 if (res
== xmlreader::XmlReader::Result::End
)
3173 m_pParserState
->m_aModels
[rID
].m_aEntries
.push_back(aRow
);
3176 void VclBuilder::handleListStore(xmlreader::XmlReader
&reader
, const OString
&rID
, const OString
&rClass
)
3182 xmlreader::Span name
;
3185 xmlreader::XmlReader::Result res
= reader
.nextItem(
3186 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3188 if (res
== xmlreader::XmlReader::Result::Done
)
3191 if (res
== xmlreader::XmlReader::Result::Begin
)
3195 bool bNotTreeStore
= rClass
!= "GtkTreeStore";
3197 handleRow(reader
, rID
);
3198 assert(bNotTreeStore
&& "gtk, as the time of writing, doesn't support data in GtkTreeStore serialization");
3204 if (res
== xmlreader::XmlReader::Result::End
)
3214 void VclBuilder::handleAtkObject(xmlreader::XmlReader
&reader
, vcl::Window
*pWindow
)
3220 stringmap aProperties
;
3224 xmlreader::Span name
;
3227 xmlreader::XmlReader::Result res
= reader
.nextItem(
3228 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3230 if (res
== xmlreader::XmlReader::Result::Done
)
3233 if (res
== xmlreader::XmlReader::Result::Begin
)
3236 if (name
== "property")
3237 collectProperty(reader
, aProperties
);
3240 if (res
== xmlreader::XmlReader::Result::End
)
3249 for (auto const& prop
: aProperties
)
3251 const OString
&rKey
= prop
.first
;
3252 const OUString
&rValue
= prop
.second
;
3254 if (pWindow
&& rKey
.match("AtkObject::"))
3255 pWindow
->set_property(rKey
.copy(RTL_CONSTASCII_LENGTH("AtkObject::")), rValue
);
3257 SAL_WARN("vcl.layout", "unhandled atk prop: " << rKey
);
3261 std::vector
<ComboBoxTextItem
> VclBuilder::handleItems(xmlreader::XmlReader
&reader
) const
3265 std::vector
<ComboBoxTextItem
> aItems
;
3269 xmlreader::Span name
;
3272 xmlreader::XmlReader::Result res
= reader
.nextItem(
3273 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3275 if (res
== xmlreader::XmlReader::Result::Done
)
3278 if (res
== xmlreader::XmlReader::Result::Begin
)
3283 bool bTranslated
= false;
3284 OString sContext
, sId
;
3286 while (reader
.nextAttribute(&nsId
, &name
))
3288 if (name
== "translatable" && reader
.getAttributeValue(false) == "yes")
3292 else if (name
== "context")
3294 name
= reader
.getAttributeValue(false);
3295 sContext
= OString(name
.begin
, name
.length
);
3297 else if (name
== "id")
3299 name
= reader
.getAttributeValue(false);
3300 sId
= OString(name
.begin
, name
.length
);
3305 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3307 OString
sValue(name
.begin
, name
.length
);
3308 OUString sFinalValue
;
3311 if (!sContext
.isEmpty())
3312 sValue
= sContext
+ "\004" + sValue
;
3313 sFinalValue
= Translate::get(sValue
.getStr(), m_pParserState
->m_aResLocale
);
3316 sFinalValue
= OUString::fromUtf8(sValue
);
3318 if (m_pStringReplace
)
3319 sFinalValue
= (*m_pStringReplace
)(sFinalValue
);
3321 aItems
.emplace_back(sFinalValue
, sId
);
3325 if (res
== xmlreader::XmlReader::Result::End
)
3337 VclPtr
<Menu
> VclBuilder::handleMenu(xmlreader::XmlReader
&reader
, const OString
&rID
, bool bMenuBar
)
3339 VclPtr
<Menu
> pCurrentMenu
;
3341 pCurrentMenu
= VclPtr
<MenuBar
>::Create();
3343 pCurrentMenu
= VclPtr
<PopupMenu
>::Create();
3347 stringmap aProperties
;
3351 xmlreader::Span name
;
3354 xmlreader::XmlReader::Result res
= reader
.nextItem(
3355 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3357 if (res
== xmlreader::XmlReader::Result::Done
)
3360 if (res
== xmlreader::XmlReader::Result::Begin
)
3362 if (name
== "child")
3364 handleMenuChild(pCurrentMenu
, reader
);
3369 if (name
== "property")
3370 collectProperty(reader
, aProperties
);
3374 if (res
== xmlreader::XmlReader::Result::End
)
3383 m_aMenus
.emplace_back(rID
, pCurrentMenu
);
3385 return pCurrentMenu
;
3388 void VclBuilder::handleMenuChild(Menu
*pParent
, xmlreader::XmlReader
&reader
)
3390 xmlreader::Span name
;
3396 xmlreader::XmlReader::Result res
= reader
.nextItem(
3397 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3399 if (res
== xmlreader::XmlReader::Result::Begin
)
3401 if (name
== "object" || name
== "placeholder")
3403 handleMenuObject(pParent
, reader
);
3409 if (res
== xmlreader::XmlReader::Result::End
)
3415 if (res
== xmlreader::XmlReader::Result::Done
)
3420 void VclBuilder::handleMenuObject(Menu
*pParent
, xmlreader::XmlReader
&reader
)
3424 OUString sCustomProperty
;
3425 PopupMenu
*pSubMenu
= nullptr;
3427 xmlreader::Span name
;
3430 while (reader
.nextAttribute(&nsId
, &name
))
3432 if (name
== "class")
3434 name
= reader
.getAttributeValue(false);
3435 sClass
= OString(name
.begin
, name
.length
);
3437 else if (name
== "id")
3439 name
= reader
.getAttributeValue(false);
3440 sID
= OString(name
.begin
, name
.length
);
3441 sal_Int32 nDelim
= sID
.indexOf(':');
3444 sCustomProperty
= OUString::fromUtf8(sID
.copy(nDelim
+1));
3445 sID
= sID
.copy(0, nDelim
);
3452 stringmap aProperties
;
3453 accelmap aAccelerators
;
3455 if (!sCustomProperty
.isEmpty())
3456 aProperties
[OString("customproperty")] = sCustomProperty
;
3460 xmlreader::XmlReader::Result res
= reader
.nextItem(
3461 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3463 if (res
== xmlreader::XmlReader::Result::Done
)
3466 if (res
== xmlreader::XmlReader::Result::Begin
)
3468 if (name
== "child")
3470 size_t nChildMenuIdx
= m_aMenus
.size();
3471 handleChild(nullptr, reader
);
3472 assert(m_aMenus
.size() > nChildMenuIdx
&& "menu not inserted");
3473 pSubMenu
= dynamic_cast<PopupMenu
*>(m_aMenus
[nChildMenuIdx
].m_pMenu
.get());
3478 if (name
== "property")
3479 collectProperty(reader
, aProperties
);
3480 else if (name
== "accelerator")
3481 collectAccelerator(reader
, aAccelerators
);
3485 if (res
== xmlreader::XmlReader::Result::End
)
3494 insertMenuObject(pParent
, pSubMenu
, sClass
, sID
, aProperties
, aAccelerators
);
3497 void VclBuilder::handleSizeGroup(xmlreader::XmlReader
&reader
)
3499 m_pParserState
->m_aSizeGroups
.emplace_back();
3500 SizeGroup
&rSizeGroup
= m_pParserState
->m_aSizeGroups
.back();
3506 xmlreader::Span name
;
3509 xmlreader::XmlReader::Result res
= reader
.nextItem(
3510 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3512 if (res
== xmlreader::XmlReader::Result::Done
)
3515 if (res
== xmlreader::XmlReader::Result::Begin
)
3518 if (name
== "widget")
3520 while (reader
.nextAttribute(&nsId
, &name
))
3524 name
= reader
.getAttributeValue(false);
3525 OString
sWidget(name
.begin
, name
.length
);
3526 sal_Int32 nDelim
= sWidget
.indexOf(':');
3528 sWidget
= sWidget
.copy(0, nDelim
);
3529 rSizeGroup
.m_aWidgets
.push_back(sWidget
);
3535 if (name
== "property")
3536 collectProperty(reader
, rSizeGroup
.m_aProperties
);
3540 if (res
== xmlreader::XmlReader::Result::End
)
3552 vcl::KeyCode
makeKeyCode(const std::pair
<OString
,OString
> &rKey
)
3554 bool bShift
= rKey
.second
.indexOf("GDK_SHIFT_MASK") != -1;
3555 bool bMod1
= rKey
.second
.indexOf("GDK_CONTROL_MASK") != -1;
3556 bool bMod2
= rKey
.second
.indexOf("GDK_MOD1_MASK") != -1;
3557 bool bMod3
= rKey
.second
.indexOf("GDK_MOD2_MASK") != -1;
3559 if (rKey
.first
== "Insert")
3560 return vcl::KeyCode(KEY_INSERT
, bShift
, bMod1
, bMod2
, bMod3
);
3561 else if (rKey
.first
== "Delete")
3562 return vcl::KeyCode(KEY_DELETE
, bShift
, bMod1
, bMod2
, bMod3
);
3564 assert (rKey
.first
.getLength() == 1);
3565 sal_Char cChar
= rKey
.first
.toChar();
3567 if (cChar
>= 'a' && cChar
<= 'z')
3568 return vcl::KeyCode(KEY_A
+ (cChar
- 'a'), bShift
, bMod1
, bMod2
, bMod3
);
3569 else if (cChar
>= 'A' && cChar
<= 'Z')
3570 return vcl::KeyCode(KEY_A
+ (cChar
- 'A'), bShift
, bMod1
, bMod2
, bMod3
);
3571 else if (cChar
>= '0' && cChar
<= '9')
3572 return vcl::KeyCode(KEY_0
+ (cChar
- 'A'), bShift
, bMod1
, bMod2
, bMod3
);
3574 return vcl::KeyCode(cChar
, bShift
, bMod1
, bMod2
, bMod3
);
3578 void VclBuilder::insertMenuObject(Menu
*pParent
, PopupMenu
*pSubMenu
, const OString
&rClass
, const OString
&rID
,
3579 stringmap
&rProps
, accelmap
&rAccels
)
3581 sal_uInt16 nOldCount
= pParent
->GetItemCount();
3582 sal_uInt16 nNewId
= ++m_pParserState
->m_nLastMenuItemId
;
3584 if(rClass
== "NotebookBarAddonsMenuMergePoint")
3586 NotebookBarAddonsMerger::MergeNotebookBarMenuAddons(pParent
, nNewId
, rID
, *m_pNotebookBarAddonsItem
);
3587 m_pParserState
->m_nLastMenuItemId
= pParent
->GetItemCount();
3589 else if (rClass
== "GtkMenuItem")
3591 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3592 OUString
aCommand(extractActionName(rProps
));
3593 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::NONE
, rID
);
3594 pParent
->SetItemCommand(nNewId
, aCommand
);
3596 pParent
->SetPopupMenu(nNewId
, pSubMenu
);
3598 else if (rClass
== "GtkCheckMenuItem")
3600 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3601 OUString
aCommand(extractActionName(rProps
));
3602 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::CHECKABLE
, rID
);
3603 pParent
->SetItemCommand(nNewId
, aCommand
);
3605 else if (rClass
== "GtkRadioMenuItem")
3607 OUString
sLabel(BuilderUtils::convertMnemonicMarkup(extractLabel(rProps
)));
3608 OUString
aCommand(extractActionName(rProps
));
3609 pParent
->InsertItem(nNewId
, sLabel
, MenuItemBits::AUTOCHECK
| MenuItemBits::RADIOCHECK
, rID
);
3610 pParent
->SetItemCommand(nNewId
, aCommand
);
3612 else if (rClass
== "GtkSeparatorMenuItem")
3614 pParent
->InsertSeparator(rID
);
3617 SAL_WARN_IF(nOldCount
== pParent
->GetItemCount(), "vcl.layout", "probably need to implement " << rClass
);
3619 if (nOldCount
!= pParent
->GetItemCount())
3621 pParent
->SetHelpId(nNewId
, m_sHelpRoot
+ rID
);
3623 for (auto const& prop
: rProps
)
3625 const OString
&rKey
= prop
.first
;
3626 const OUString
&rValue
= prop
.second
;
3628 if (rKey
== "tooltip-markup")
3629 pParent
->SetTipHelpText(nNewId
, rValue
);
3630 else if (rKey
== "tooltip-text")
3631 pParent
->SetTipHelpText(nNewId
, rValue
);
3632 else if (rKey
== "visible")
3633 pParent
->ShowItem(nNewId
, toBool(rValue
));
3635 SAL_INFO("vcl.layout", "unhandled property: " << rKey
);
3638 for (auto const& accel
: rAccels
)
3640 const OString
&rSignal
= accel
.first
;
3641 const auto &rValue
= accel
.second
;
3643 if (rSignal
== "activate")
3644 pParent
->SetAccelKey(nNewId
, makeKeyCode(rValue
));
3646 SAL_INFO("vcl.layout", "unhandled accelerator for: " << rSignal
);
3653 /// Insert items to a ComboBox or a ListBox.
3654 /// They have no common ancestor that would have 'InsertEntry()', so use a template.
3655 template<typename T
> static bool insertItems(vcl::Window
*pWindow
, VclBuilder::stringmap
&rMap
,
3656 std::vector
<std::unique_ptr
<OUString
>>& rUserData
,
3657 const std::vector
<ComboBoxTextItem
> &rItems
)
3659 T
*pContainer
= dynamic_cast<T
*>(pWindow
);
3663 sal_uInt16 nActiveId
= extractActive(rMap
);
3664 for (auto const& item
: rItems
)
3666 sal_Int32 nPos
= pContainer
->InsertEntry(item
.m_sItem
);
3667 if (!item
.m_sId
.isEmpty())
3669 rUserData
.emplace_back(std::make_unique
<OUString
>(OUString::fromUtf8(item
.m_sId
)));
3670 pContainer
->SetEntryData(nPos
, rUserData
.back().get());
3673 if (nActiveId
< rItems
.size())
3674 pContainer
->SelectEntryPos(nActiveId
);
3679 VclPtr
<vcl::Window
> VclBuilder::handleObject(vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
3683 OUString sCustomProperty
;
3685 xmlreader::Span name
;
3688 while (reader
.nextAttribute(&nsId
, &name
))
3690 if (name
== "class")
3692 name
= reader
.getAttributeValue(false);
3693 sClass
= OString(name
.begin
, name
.length
);
3695 else if (name
== "id")
3697 name
= reader
.getAttributeValue(false);
3698 sID
= OString(name
.begin
, name
.length
);
3701 sal_Int32 nDelim
= sID
.indexOf(':');
3704 sCustomProperty
= OUString::fromUtf8(sID
.copy(nDelim
+1));
3705 sID
= sID
.copy(0, nDelim
);
3711 if (sClass
== "GtkListStore" || sClass
== "GtkTreeStore")
3713 handleListStore(reader
, sID
, sClass
);
3716 else if (sClass
== "GtkMenu")
3718 handleMenu(reader
, sID
, false);
3721 else if (sClass
== "GtkMenuBar")
3723 VclPtr
<Menu
> xMenu
= handleMenu(reader
, sID
, true);
3724 if (SystemWindow
* pTopLevel
= pParent
? pParent
->GetSystemWindow() : nullptr)
3725 pTopLevel
->SetMenuBar(dynamic_cast<MenuBar
*>(xMenu
.get()));
3728 else if (sClass
== "GtkSizeGroup")
3730 handleSizeGroup(reader
);
3733 else if (sClass
== "AtkObject")
3735 handleAtkObject(reader
, pParent
);
3741 stringmap aProperties
, aPangoAttributes
;
3742 stringmap aAtkAttributes
;
3743 std::vector
<ComboBoxTextItem
> aItems
;
3745 if (!sCustomProperty
.isEmpty())
3746 aProperties
[OString("customproperty")] = sCustomProperty
;
3748 VclPtr
<vcl::Window
> pCurrentChild
;
3751 xmlreader::XmlReader::Result res
= reader
.nextItem(
3752 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3754 if (res
== xmlreader::XmlReader::Result::Done
)
3757 if (res
== xmlreader::XmlReader::Result::Begin
)
3759 if (name
== "child")
3763 pCurrentChild
= insertObject(pParent
, sClass
, sID
,
3764 aProperties
, aPangoAttributes
, aAtkAttributes
);
3766 handleChild(pCurrentChild
, reader
);
3768 else if (name
== "items")
3769 aItems
= handleItems(reader
);
3770 else if (name
== "style")
3773 std::vector
<vcl::EnumContext::Context
> aContext
= handleStyle(reader
, nPriority
);
3776 vcl::IPrioritable
* pPrioritable
= dynamic_cast<vcl::IPrioritable
*>(pCurrentChild
.get());
3777 SAL_WARN_IF(!pPrioritable
, "vcl", "priority set for not supported item");
3779 pPrioritable
->SetPriority(nPriority
);
3781 if (!aContext
.empty())
3783 vcl::IContext
* pContextControl
= dynamic_cast<vcl::IContext
*>(pCurrentChild
.get());
3784 SAL_WARN_IF(!pContextControl
, "vcl", "context set for not supported item");
3785 if (pContextControl
)
3786 pContextControl
->SetContext(aContext
);
3792 if (name
== "property")
3793 collectProperty(reader
, aProperties
);
3794 else if (name
== "attribute")
3795 collectPangoAttribute(reader
, aPangoAttributes
);
3796 else if (name
== "relation")
3797 collectAtkRelationAttribute(reader
, aAtkAttributes
);
3798 else if (name
== "role")
3799 collectAtkRoleAttribute(reader
, aAtkAttributes
);
3800 else if (name
== "action-widget")
3801 handleActionWidget(reader
);
3805 if (res
== xmlreader::XmlReader::Result::End
)
3814 if (sClass
== "GtkAdjustment")
3816 m_pParserState
->m_aAdjustments
[sID
] = aProperties
;
3819 else if (sClass
== "GtkTextBuffer")
3821 m_pParserState
->m_aTextBuffers
[sID
] = aProperties
;
3827 pCurrentChild
= insertObject(pParent
, sClass
, sID
, aProperties
,
3828 aPangoAttributes
, aAtkAttributes
);
3831 if (!aItems
.empty())
3833 // try to fill-in the items
3834 if (!insertItems
<ComboBox
>(pCurrentChild
, aProperties
, m_aUserData
, aItems
))
3835 insertItems
<ListBox
>(pCurrentChild
, aProperties
, m_aUserData
, aItems
);
3838 return pCurrentChild
;
3841 void VclBuilder::handlePacking(vcl::Window
*pCurrent
, vcl::Window
*pParent
, xmlreader::XmlReader
&reader
)
3843 xmlreader::Span name
;
3850 xmlreader::XmlReader::Result res
= reader
.nextItem(
3851 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3853 if (res
== xmlreader::XmlReader::Result::Done
)
3856 if (res
== xmlreader::XmlReader::Result::Begin
)
3859 if (name
== "property")
3860 applyPackingProperty(pCurrent
, pParent
, reader
);
3863 if (res
== xmlreader::XmlReader::Result::End
)
3873 void VclBuilder::applyPackingProperty(vcl::Window
*pCurrent
,
3874 vcl::Window
*pParent
,
3875 xmlreader::XmlReader
&reader
)
3880 //ToolBoxItems are not true widgets just elements
3881 //of the ToolBox itself
3882 ToolBox
*pToolBoxParent
= nullptr;
3883 if (pCurrent
== pParent
)
3884 pToolBoxParent
= dynamic_cast<ToolBox
*>(pParent
);
3886 xmlreader::Span name
;
3889 if (pCurrent
->GetType() == WindowType::SCROLLWINDOW
)
3891 auto aFind
= m_pParserState
->m_aRedundantParentWidgets
.find(VclPtr
<vcl::Window
>(pCurrent
));
3892 if (aFind
!= m_pParserState
->m_aRedundantParentWidgets
.end())
3894 pCurrent
= aFind
->second
;
3899 while (reader
.nextAttribute(&nsId
, &name
))
3903 name
= reader
.getAttributeValue(false);
3904 OString
sKey(name
.begin
, name
.length
);
3905 sKey
= sKey
.replace('_', '-');
3907 xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
3908 OString
sValue(name
.begin
, name
.length
);
3910 if (sKey
== "expand" || sKey
== "resize")
3912 bool bTrue
= (!sValue
.isEmpty() && (sValue
[0] == 't' || sValue
[0] == 'T' || sValue
[0] == '1'));
3914 pToolBoxParent
->SetItemExpand(m_pParserState
->m_nLastToolbarId
, bTrue
);
3916 pCurrent
->set_expand(bTrue
);
3925 bool bTrue
= (!sValue
.isEmpty() && (sValue
[0] == 't' || sValue
[0] == 'T' || sValue
[0] == '1'));
3926 pCurrent
->set_fill(bTrue
);
3928 else if (sKey
== "pack-type")
3930 VclPackType ePackType
= (!sValue
.isEmpty() && (sValue
[0] == 'e' || sValue
[0] == 'E')) ? VclPackType::End
: VclPackType::Start
;
3931 pCurrent
->set_pack_type(ePackType
);
3933 else if (sKey
== "left-attach")
3935 pCurrent
->set_grid_left_attach(sValue
.toInt32());
3937 else if (sKey
== "top-attach")
3939 pCurrent
->set_grid_top_attach(sValue
.toInt32());
3941 else if (sKey
== "width")
3943 pCurrent
->set_grid_width(sValue
.toInt32());
3945 else if (sKey
== "height")
3947 pCurrent
->set_grid_height(sValue
.toInt32());
3949 else if (sKey
== "padding")
3951 pCurrent
->set_padding(sValue
.toInt32());
3953 else if (sKey
== "position")
3955 set_window_packing_position(pCurrent
, sValue
.toInt32());
3957 else if (sKey
== "secondary")
3959 pCurrent
->set_secondary(toBool(sValue
));
3961 else if (sKey
== "non-homogeneous")
3963 pCurrent
->set_non_homogeneous(toBool(sValue
));
3965 else if (sKey
== "homogeneous")
3967 pCurrent
->set_non_homogeneous(!toBool(sValue
));
3971 SAL_WARN("vcl.layout", "unknown packing: " << sKey
);
3977 std::vector
<vcl::EnumContext::Context
> VclBuilder::handleStyle(xmlreader::XmlReader
&reader
, int &nPriority
)
3979 std::vector
<vcl::EnumContext::Context
> aContext
;
3981 xmlreader::Span name
;
3988 xmlreader::XmlReader::Result res
= reader
.nextItem(
3989 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
3991 if (res
== xmlreader::XmlReader::Result::Done
)
3994 if (res
== xmlreader::XmlReader::Result::Begin
)
3997 if (name
== "class")
3999 OString classStyle
= getStyleClass(reader
);
4001 if (classStyle
.startsWith("context-"))
4003 OString sContext
= classStyle
.copy(classStyle
.indexOf('-') + 1);
4004 OUString
sContext2(sContext
.getStr(), sContext
.getLength(), RTL_TEXTENCODING_UTF8
);
4005 aContext
.push_back(vcl::EnumContext::GetContextEnum(sContext2
));
4007 else if (classStyle
.startsWith("priority-"))
4009 OString aPriority
= classStyle
.copy(classStyle
.indexOf('-') + 1);
4010 OUString
aPriority2(aPriority
.getStr(), aPriority
.getLength(), RTL_TEXTENCODING_UTF8
);
4011 nPriority
= aPriority2
.toInt32();
4015 SAL_WARN("vcl.layout", "unknown class: " << classStyle
);
4020 if (res
== xmlreader::XmlReader::Result::End
)
4032 OString
VclBuilder::getStyleClass(xmlreader::XmlReader
&reader
)
4034 xmlreader::Span name
;
4038 while (reader
.nextAttribute(&nsId
, &name
))
4042 name
= reader
.getAttributeValue(false);
4043 aRet
= OString (name
.begin
, name
.length
);
4050 void VclBuilder::collectProperty(xmlreader::XmlReader
&reader
, stringmap
&rMap
) const
4052 xmlreader::Span name
;
4055 OString sProperty
, sContext
;
4057 bool bTranslated
= false;
4059 while (reader
.nextAttribute(&nsId
, &name
))
4063 name
= reader
.getAttributeValue(false);
4064 sProperty
= OString(name
.begin
, name
.length
);
4066 else if (name
== "context")
4068 name
= reader
.getAttributeValue(false);
4069 sContext
= OString(name
.begin
, name
.length
);
4071 else if (name
== "translatable" && reader
.getAttributeValue(false) == "yes")
4077 reader
.nextItem(xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
4078 OString
sValue(name
.begin
, name
.length
);
4079 OUString sFinalValue
;
4082 if (!sContext
.isEmpty())
4083 sValue
= sContext
+ "\004" + sValue
;
4084 sFinalValue
= Translate::get(sValue
.getStr(), m_pParserState
->m_aResLocale
);
4087 sFinalValue
= OUString::fromUtf8(sValue
);
4089 if (!sProperty
.isEmpty())
4091 sProperty
= sProperty
.replace('_', '-');
4092 if (m_pStringReplace
)
4093 sFinalValue
= (*m_pStringReplace
)(sFinalValue
);
4094 rMap
[sProperty
] = sFinalValue
;
4098 void VclBuilder::handleActionWidget(xmlreader::XmlReader
&reader
)
4100 xmlreader::Span name
;
4105 while (reader
.nextAttribute(&nsId
, &name
))
4107 if (name
== "response")
4109 name
= reader
.getAttributeValue(false);
4110 sResponse
= OString(name
.begin
, name
.length
);
4114 reader
.nextItem(xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
4115 OString
sID(name
.begin
, name
.length
);
4116 sal_Int32 nDelim
= sID
.indexOf(':');
4118 sID
= sID
.copy(0, nDelim
);
4119 set_response(sID
, sResponse
.toInt32());
4122 void VclBuilder::collectAccelerator(xmlreader::XmlReader
&reader
, accelmap
&rMap
)
4124 xmlreader::Span name
;
4131 while (reader
.nextAttribute(&nsId
, &name
))
4135 name
= reader
.getAttributeValue(false);
4136 sValue
= OString(name
.begin
, name
.length
);
4138 else if (name
== "signal")
4140 name
= reader
.getAttributeValue(false);
4141 sProperty
= OString(name
.begin
, name
.length
);
4143 else if (name
== "modifiers")
4145 name
= reader
.getAttributeValue(false);
4146 sModifiers
= OString(name
.begin
, name
.length
);
4150 if (!sProperty
.isEmpty() && !sValue
.isEmpty())
4152 rMap
[sProperty
] = std::make_pair(sValue
, sModifiers
);
4156 vcl::Window
*VclBuilder::get_widget_root()
4158 return m_aChildren
.empty() ? nullptr : m_aChildren
[0].m_pWindow
.get();
4161 vcl::Window
*VclBuilder::get_by_name(const OString
& sID
)
4163 for (auto const& child
: m_aChildren
)
4165 if (child
.m_sID
== sID
)
4166 return child
.m_pWindow
;
4172 PopupMenu
*VclBuilder::get_menu(const OString
& sID
)
4174 for (auto const& menu
: m_aMenus
)
4176 if (menu
.m_sID
== sID
)
4177 return dynamic_cast<PopupMenu
*>(menu
.m_pMenu
.get());
4183 void VclBuilder::set_response(const OString
& sID
, short nResponse
)
4191 nResponse
= RET_CANCEL
;
4194 nResponse
= RET_CLOSE
;
4197 nResponse
= RET_YES
;
4203 nResponse
= RET_HELP
;
4206 assert(nResponse
>= 100 && "keep non-canned responses in range 100+ to avoid collision with vcl RET_*");
4210 for (const auto & child
: m_aChildren
)
4212 if (child
.m_sID
== sID
)
4214 PushButton
* pPushButton
= dynamic_cast<PushButton
*>(child
.m_pWindow
.get());
4215 assert(pPushButton
);
4216 Dialog
* pDialog
= pPushButton
->GetParentDialog();
4218 pDialog
->add_button(pPushButton
, nResponse
, false);
4226 void VclBuilder::delete_by_name(const OString
& sID
)
4228 auto aI
= std::find_if(m_aChildren
.begin(), m_aChildren
.end(),
4229 [&sID
](WinAndId
& rItem
) { return rItem
.m_sID
== sID
; });
4230 if (aI
!= m_aChildren
.end())
4232 aI
->m_pWindow
.disposeAndClear();
4233 m_aChildren
.erase(aI
);
4237 void VclBuilder::delete_by_window(vcl::Window
*pWindow
)
4239 drop_ownership(pWindow
);
4240 pWindow
->disposeOnce();
4243 void VclBuilder::drop_ownership(const vcl::Window
*pWindow
)
4245 auto aI
= std::find_if(m_aChildren
.begin(), m_aChildren
.end(),
4246 [&pWindow
](WinAndId
& rItem
) { return rItem
.m_pWindow
== pWindow
; });
4247 if (aI
!= m_aChildren
.end())
4248 m_aChildren
.erase(aI
);
4251 OString
VclBuilder::get_by_window(const vcl::Window
*pWindow
) const
4253 for (auto const& child
: m_aChildren
)
4255 if (child
.m_pWindow
== pWindow
)
4262 VclBuilder::PackingData
VclBuilder::get_window_packing_data(const vcl::Window
*pWindow
) const
4264 //We've stored the return of new Control, some of these get
4265 //border windows placed around them which are what you get
4266 //from GetChild, so scoot up a level if necessary to get the
4267 //window whose position value we have
4268 const vcl::Window
*pPropHolder
= pWindow
->ImplGetWindow();
4270 for (auto const& child
: m_aChildren
)
4272 if (child
.m_pWindow
== pPropHolder
)
4273 return child
.m_aPackingData
;
4276 return PackingData();
4279 void VclBuilder::set_window_packing_position(const vcl::Window
*pWindow
, sal_Int32 nPosition
)
4281 for (auto & child
: m_aChildren
)
4283 if (child
.m_pWindow
== pWindow
)
4284 child
.m_aPackingData
.m_nPosition
= nPosition
;
4288 const VclBuilder::ListStore
*VclBuilder::get_model_by_name(const OString
& sID
) const
4290 std::map
<OString
, ListStore
>::const_iterator aI
= m_pParserState
->m_aModels
.find(sID
);
4291 if (aI
!= m_pParserState
->m_aModels
.end())
4292 return &(aI
->second
);
4296 const VclBuilder::TextBuffer
*VclBuilder::get_buffer_by_name(const OString
& sID
) const
4298 std::map
<OString
, TextBuffer
>::const_iterator aI
= m_pParserState
->m_aTextBuffers
.find(sID
);
4299 if (aI
!= m_pParserState
->m_aTextBuffers
.end())
4300 return &(aI
->second
);
4304 const VclBuilder::Adjustment
*VclBuilder::get_adjustment_by_name(const OString
& sID
) const
4306 std::map
<OString
, Adjustment
>::const_iterator aI
= m_pParserState
->m_aAdjustments
.find(sID
);
4307 if (aI
!= m_pParserState
->m_aAdjustments
.end())
4308 return &(aI
->second
);
4312 void VclBuilder::mungeModel(ComboBox
&rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4314 for (auto const& entry
: rStore
.m_aEntries
)
4316 const ListStore::row
&rRow
= entry
;
4317 sal_uInt16 nEntry
= rTarget
.InsertEntry(rRow
[0]);
4318 if (rRow
.size() > 1)
4322 sal_IntPtr nValue
= rRow
[1].toInt32();
4323 rTarget
.SetEntryData(nEntry
, reinterpret_cast<void*>(nValue
));
4327 if (!rRow
[1].isEmpty())
4329 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4330 rTarget
.SetEntryData(nEntry
, m_aUserData
.back().get());
4335 if (nActiveId
< rStore
.m_aEntries
.size())
4336 rTarget
.SelectEntryPos(nActiveId
);
4339 void VclBuilder::mungeModel(ListBox
&rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4341 for (auto const& entry
: rStore
.m_aEntries
)
4343 const ListStore::row
&rRow
= entry
;
4344 sal_uInt16 nEntry
= rTarget
.InsertEntry(rRow
[0]);
4345 if (rRow
.size() > 1)
4349 sal_IntPtr nValue
= rRow
[1].toInt32();
4350 rTarget
.SetEntryData(nEntry
, reinterpret_cast<void*>(nValue
));
4354 if (!rRow
[1].isEmpty())
4356 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4357 rTarget
.SetEntryData(nEntry
, m_aUserData
.back().get());
4362 if (nActiveId
< rStore
.m_aEntries
.size())
4363 rTarget
.SelectEntryPos(nActiveId
);
4366 void VclBuilder::mungeModel(SvTabListBox
& rTarget
, const ListStore
&rStore
, sal_uInt16 nActiveId
)
4368 for (auto const& entry
: rStore
.m_aEntries
)
4370 const ListStore::row
&rRow
= entry
;
4371 auto pEntry
= rTarget
.InsertEntry(rRow
[0]);
4372 if (rRow
.size() > 1)
4376 sal_IntPtr nValue
= rRow
[1].toInt32();
4377 pEntry
->SetUserData(reinterpret_cast<void*>(nValue
));
4381 if (!rRow
[1].isEmpty())
4383 m_aUserData
.emplace_back(std::make_unique
<OUString
>(rRow
[1]));
4384 pEntry
->SetUserData(m_aUserData
.back().get());
4389 if (nActiveId
< rStore
.m_aEntries
.size())
4391 SvTreeListEntry
* pEntry
= rTarget
.GetEntry(nullptr, nActiveId
);
4392 rTarget
.Select(pEntry
);
4396 void VclBuilder::mungeAdjustment(NumericFormatter
&rTarget
, const Adjustment
&rAdjustment
)
4398 int nMul
= rtl_math_pow10Exp(1, rTarget
.GetDecimalDigits());
4400 for (auto const& elem
: rAdjustment
)
4402 const OString
&rKey
= elem
.first
;
4403 const OUString
&rValue
= elem
.second
;
4405 if (rKey
== "upper")
4407 sal_Int64 nUpper
= rValue
.toDouble() * nMul
;
4408 rTarget
.SetMax(nUpper
);
4409 rTarget
.SetLast(nUpper
);
4411 else if (rKey
== "lower")
4413 sal_Int64 nLower
= rValue
.toDouble() * nMul
;
4414 rTarget
.SetMin(nLower
);
4415 rTarget
.SetFirst(nLower
);
4417 else if (rKey
== "value")
4419 sal_Int64 nValue
= rValue
.toDouble() * nMul
;
4420 rTarget
.SetValue(nValue
);
4422 else if (rKey
== "step-increment")
4424 sal_Int64 nSpinSize
= rValue
.toDouble() * nMul
;
4425 rTarget
.SetSpinSize(nSpinSize
);
4429 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4434 void VclBuilder::mungeAdjustment(FormattedField
&rTarget
, const Adjustment
&rAdjustment
)
4436 for (auto const& elem
: rAdjustment
)
4438 const OString
&rKey
= elem
.first
;
4439 const OUString
&rValue
= elem
.second
;
4441 if (rKey
== "upper")
4443 rTarget
.SetMaxValue(rValue
.toDouble());
4445 else if (rKey
== "lower")
4447 rTarget
.SetMinValue(rValue
.toDouble());
4449 else if (rKey
== "value")
4451 rTarget
.SetValue(rValue
.toDouble());
4453 else if (rKey
== "step-increment")
4455 rTarget
.SetSpinSize(rValue
.toDouble());
4459 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4464 void VclBuilder::mungeAdjustment(TimeField
&rTarget
, const Adjustment
&rAdjustment
)
4466 for (auto const& elem
: rAdjustment
)
4468 const OString
&rKey
= elem
.first
;
4469 const OUString
&rValue
= elem
.second
;
4471 if (rKey
== "upper")
4473 tools::Time
aUpper(rValue
.toInt32());
4474 rTarget
.SetMax(aUpper
);
4475 rTarget
.SetLast(aUpper
);
4477 else if (rKey
== "lower")
4479 tools::Time
aLower(rValue
.toInt32());
4480 rTarget
.SetMin(aLower
);
4481 rTarget
.SetFirst(aLower
);
4483 else if (rKey
== "value")
4485 tools::Time
aValue(rValue
.toInt32());
4486 rTarget
.SetTime(aValue
);
4490 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4495 void VclBuilder::mungeAdjustment(DateField
&rTarget
, const Adjustment
&rAdjustment
)
4497 for (auto const& elem
: rAdjustment
)
4499 const OString
&rKey
= elem
.first
;
4500 const OUString
&rValue
= elem
.second
;
4502 if (rKey
== "upper")
4504 Date
aUpper(rValue
.toInt32());
4505 rTarget
.SetMax(aUpper
);
4506 rTarget
.SetLast(aUpper
);
4508 else if (rKey
== "lower")
4510 Date
aLower(rValue
.toInt32());
4511 rTarget
.SetMin(aLower
);
4512 rTarget
.SetFirst(aLower
);
4514 else if (rKey
== "value")
4516 Date
aValue(rValue
.toInt32());
4517 rTarget
.SetDate(aValue
);
4521 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4526 void VclBuilder::mungeAdjustment(ScrollBar
&rTarget
, const Adjustment
&rAdjustment
)
4528 for (auto const& elem
: rAdjustment
)
4530 const OString
&rKey
= elem
.first
;
4531 const OUString
&rValue
= elem
.second
;
4533 if (rKey
== "upper")
4534 rTarget
.SetRangeMax(rValue
.toInt32());
4535 else if (rKey
== "lower")
4536 rTarget
.SetRangeMin(rValue
.toInt32());
4537 else if (rKey
== "value")
4538 rTarget
.SetThumbPos(rValue
.toInt32());
4539 else if (rKey
== "step-increment")
4540 rTarget
.SetLineSize(rValue
.toInt32());
4541 else if (rKey
== "page-increment")
4542 rTarget
.SetPageSize(rValue
.toInt32());
4545 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4550 void VclBuilder::mungeAdjustment(Slider
& rTarget
, const Adjustment
& rAdjustment
)
4552 for (auto const& elem
: rAdjustment
)
4554 const OString
&rKey
= elem
.first
;
4555 const OUString
&rValue
= elem
.second
;
4557 if (rKey
== "upper")
4558 rTarget
.SetRangeMax(rValue
.toInt32());
4559 else if (rKey
== "lower")
4560 rTarget
.SetRangeMin(rValue
.toInt32());
4561 else if (rKey
== "value")
4562 rTarget
.SetThumbPos(rValue
.toInt32());
4563 else if (rKey
== "step-increment")
4564 rTarget
.SetLineSize(rValue
.toInt32());
4565 else if (rKey
== "page-increment")
4566 rTarget
.SetPageSize(rValue
.toInt32());
4569 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4574 void VclBuilder::mungeTextBuffer(VclMultiLineEdit
&rTarget
, const TextBuffer
&rTextBuffer
)
4576 for (auto const& elem
: rTextBuffer
)
4578 const OString
&rKey
= elem
.first
;
4579 const OUString
&rValue
= elem
.second
;
4582 rTarget
.SetText(rValue
);
4585 SAL_INFO("vcl.layout", "unhandled property :" << rKey
);
4590 VclBuilder::ParserState::ParserState()
4591 : m_nLastToolbarId(0)
4592 , m_nLastMenuItemId(0)
4595 VclBuilder::MenuAndId::MenuAndId(const OString
&rId
, Menu
*pMenu
)
4600 VclBuilder::MenuAndId::~MenuAndId() {}
4602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */