1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  */
9 
10 #ifndef INCLUDED_VCL_BUILDER_HXX
11 #define INCLUDED_VCL_BUILDER_HXX
12 
13 #include <typeinfo>
14 #include <sal/log.hxx>
15 #include <unotools/resmgr.hxx>
16 #include <tools/fldunit.hxx>
17 #include <vcl/dllapi.h>
18 #include <vcl/window.hxx>
19 #include <vcl/vclptr.hxx>
20 #include <vcl/toolbox.hxx>
21 #include <tools/wintypes.hxx>
22 #include <vcl/EnumContext.hxx>
23 
24 #include <memory>
25 #include <map>
26 #include <string_view>
27 #include <vector>
28 #ifdef check
29 #  //some problem with MacOSX and a check define
30 #  undef check
31 #endif
32 
33 class Button;
34 class ComboBox;
35 class FormattedField;
36 class ListBox;
37 class Menu;
38 class MessageDialog;
39 class NumericFormatter;
40 class PopupMenu;
41 class SalInstanceBuilder;
42 class ScreenshotTest;
43 class ScrollBar;
44 class SvTabListBox;
45 class Slider;
46 class DateField;
47 class TimeField;
48 class VclExpander;
49 class VclMultiLineEdit;
50 struct NotebookBarAddonsItem;
51 namespace xmlreader { class XmlReader; }
52 namespace com::sun::star::frame { class XFrame; }
53 
54 struct ComboBoxTextItem
55 {
56     OUString m_sItem;
57     OString m_sId;
ComboBoxTextItemComboBoxTextItem58     ComboBoxTextItem(const OUString& rItem, const OString& rId)
59         : m_sItem(rItem)
60         , m_sId(rId)
61     {
62     }
63 };
64 
65 /// Creates a hierarchy of vcl::Windows (widgets) from a .ui file for dialogs, sidebar, etc.
66 class VCL_DLLPUBLIC VclBuilder
67 {
68 public:
69     typedef std::map<OString, OUString> stringmap;
70     typedef std::map<OString, std::pair<OString, OString>> accelmap;
71     /// These functions create a new widget with parent pParent and return it in rRet
72     typedef void (*customMakeWidget)(VclPtr<vcl::Window> &rRet, const VclPtr<vcl::Window> &pParent, stringmap &rVec);
73 
74 public:
75     VclBuilder(vcl::Window* pParent, const OUString& sUIRootDir, const OUString& sUIFile,
76                const OString& sID = OString(),
77                const css::uno::Reference<css::frame::XFrame>& rFrame
78                = css::uno::Reference<css::frame::XFrame>(),
79                bool bLegacy = true,
80                const NotebookBarAddonsItem* pNotebookBarAddonsItem = nullptr);
81     ~VclBuilder();
82     ///releases references and disposes all children.
83     void disposeBuilder();
84     //sID must exist and be of type T
85     template <typename T> T* get(VclPtr<T>& ret, const OString& sID);
86 
87     //sID may not exist, but must be of type T if it does
88     template <typename T = vcl::Window> T* get(const OString& sID);
89 
90     vcl::Window*    get_widget_root();
91 
92     //sID may not exist
93     PopupMenu*      get_menu(std::string_view sID);
94 
95     //release ownership of pWindow, i.e. don't delete it
96     void            drop_ownership(const vcl::Window *pWindow);
97 
98     //see m_aDeferredProperties, you need this for toplevel dialogs
99     //which build themselves from their ctor. The properties on
100     //the top level are stored in m_aDeferredProperties and need
101     //to be applied post ctor
102     void            setDeferredProperties();
103 
104     /// return UI-File name (without '.ui')
getUIFile() const105     const OString& getUIFile() const
106     {
107         return m_sHelpRoot;
108     }
109 
110     static SymbolType mapStockToSymbol(std::u16string_view icon_name);
111 
112 private:
113     VclBuilder(const VclBuilder&) = delete;
114     VclBuilder& operator=(const VclBuilder&) = delete;
115 
116     // owner for ListBox/ComboBox UserData
117     std::vector<std::unique_ptr<OUString>> m_aUserData;
118 
119     //If the toplevel window has any properties which need to be set on it,
120     //but the toplevel is the owner of the builder, then its ctor
121     //has not been completed during the building, so properties for it
122     //are collected here and need to be set afterwards, e.g. during
123     //Show or Execute
124     stringmap      m_aDeferredProperties;
125 
126     std::unique_ptr<NotebookBarAddonsItem> m_pNotebookBarAddonsItem;
127 
128     struct PackingData
129     {
130         bool m_bVerticalOrient;
131         sal_Int32 m_nPosition;
PackingDataVclBuilder::PackingData132         PackingData(bool bVerticalOrient = false)
133             : m_bVerticalOrient(bVerticalOrient)
134             , m_nPosition(-1)
135         {
136         }
137     };
138 
139     struct WinAndId
140     {
141         OString m_sID;
142         VclPtr<vcl::Window> m_pWindow;
143         PackingData m_aPackingData;
WinAndIdVclBuilder::WinAndId144         WinAndId(const OString &rId, vcl::Window *pWindow, bool bVertical)
145             : m_sID(rId)
146             , m_pWindow(pWindow)
147             , m_aPackingData(bVertical)
148         {
149         }
150     };
151     std::vector<WinAndId> m_aChildren;
152 
153     struct MenuAndId
154     {
155         OString m_sID;
156         VclPtr<Menu> m_pMenu;
157         MenuAndId(const OString &rId, Menu *pMenu);
158     };
159     std::vector<MenuAndId> m_aMenus;
160 
161     struct StringPair
162     {
163         OString m_sID;
164         OString m_sValue;
StringPairVclBuilder::StringPair165         StringPair(const OString &rId, const OString &rValue)
166             : m_sID(rId)
167             , m_sValue(rValue)
168         {
169         }
170     };
171 
172     struct UStringPair
173     {
174         OString m_sID;
175         OUString m_sValue;
UStringPairVclBuilder::UStringPair176         UStringPair(const OString &rId, const OUString &rValue)
177             : m_sID(rId)
178             , m_sValue(rValue)
179         {
180         }
181     };
182 
183     typedef StringPair RadioButtonGroupMap;
184 
185     struct ButtonImageWidgetMap
186     {
187         OString m_sID;
188         OUString m_sValue;
189         bool m_bRadio;
ButtonImageWidgetMapVclBuilder::ButtonImageWidgetMap190         ButtonImageWidgetMap(const OString &rId, const OUString &rValue, bool bRadio)
191             : m_sID(rId)
192             , m_sValue(rValue)
193             , m_bRadio(bRadio)
194         {
195         }
196     };
197 
198     typedef UStringPair TextBufferMap;
199     typedef UStringPair WidgetAdjustmentMap;
200     typedef UStringPair ButtonMenuMap;
201     typedef UStringPair MnemonicWidgetMap;
202 
203     struct ComboBoxModelMap
204     {
205         OString m_sID;
206         OUString m_sValue;
207         sal_Int32 m_nActiveId;
ComboBoxModelMapVclBuilder::ComboBoxModelMap208         ComboBoxModelMap(const OString &rId, const OUString &rValue, sal_Int32 nActiveId)
209             : m_sID(rId)
210             , m_sValue(rValue)
211             , m_nActiveId(nActiveId)
212         {
213         }
214     };
215 
216     struct ListStore
217     {
218         typedef std::vector<OUString> row;
219         std::vector<row> m_aEntries;
220     };
221 
222     const ListStore* get_model_by_name(const OString& sID) const;
223     void     mungeModel(ListBox &rTarget, const ListStore &rStore, sal_uInt16 nActiveId);
224     void     mungeModel(ComboBox &rTarget, const ListStore &rStore, sal_uInt16 nActiveId);
225     void     mungeModel(SvTabListBox &rTarget, const ListStore &rStore, sal_uInt16 nActiveId);
226 
227     typedef stringmap TextBuffer;
228     const TextBuffer* get_buffer_by_name(const OString& sID) const;
229 
230     static void     mungeTextBuffer(VclMultiLineEdit &rTarget, const TextBuffer &rTextBuffer);
231 
232     typedef stringmap Adjustment;
233     const Adjustment* get_adjustment_by_name(const OString& sID) const;
234 
235     static void     mungeAdjustment(NumericFormatter &rTarget, const Adjustment &rAdjustment);
236     static void     mungeAdjustment(FormattedField &rTarget, const Adjustment &rAdjustment);
237     static void     mungeAdjustment(ScrollBar &rTarget, const Adjustment &rAdjustment);
238     static void     mungeAdjustment(Slider &rTarget, const Adjustment &rAdjustment);
239 
240     typedef std::map<OString, int> ImageSizeMap;
241 
242     struct SizeGroup
243     {
244         std::vector<OString> m_aWidgets;
245         stringmap m_aProperties;
SizeGroupVclBuilder::SizeGroup246         SizeGroup() {}
247     };
248 
249 
250     struct ParserState
251     {
252         std::locale m_aResLocale;
253 
254         std::vector<RadioButtonGroupMap> m_aGroupMaps;
255 
256         std::vector<ComboBoxModelMap> m_aModelMaps;
257         std::map<OString, ListStore> m_aModels;
258 
259         std::vector<TextBufferMap> m_aTextBufferMaps;
260         std::map<OString, TextBuffer> m_aTextBuffers;
261 
262         std::vector<WidgetAdjustmentMap> m_aNumericFormatterAdjustmentMaps;
263         std::vector<WidgetAdjustmentMap> m_aFormattedFormatterAdjustmentMaps;
264         std::vector<WidgetAdjustmentMap> m_aScrollAdjustmentMaps;
265         std::vector<WidgetAdjustmentMap> m_aSliderAdjustmentMaps;
266 
267         std::map<OString, Adjustment> m_aAdjustments;
268 
269         std::vector<ButtonImageWidgetMap> m_aButtonImageWidgetMaps;
270         ImageSizeMap m_aImageSizeMap;
271 
272         std::vector<ButtonMenuMap> m_aButtonMenuMaps;
273 
274         std::map<VclPtr<vcl::Window>, VclPtr<vcl::Window>> m_aRedundantParentWidgets;
275 
276         std::vector<SizeGroup> m_aSizeGroups;
277 
278         std::map<VclPtr<vcl::Window>, stringmap> m_aAtkInfo;
279 
280         std::vector<MnemonicWidgetMap> m_aMnemonicWidgetMaps;
281 
282         std::vector< VclPtr<VclExpander> > m_aExpanderWidgets;
283 
284         std::vector< VclPtr<MessageDialog> > m_aMessageDialogs;
285 
286         ToolBoxItemId m_nLastToolbarId;
287 
288         sal_uInt16 m_nLastMenuItemId;
289 
290         ParserState();
291     };
292 
293     OString     m_sID;
294     OString     m_sHelpRoot;
295     ResHookProc m_pStringReplace;
296     VclPtr<vcl::Window> m_pParent;
297     bool        m_bToplevelHasDeferredInit;
298     bool        m_bToplevelHasDeferredProperties;
299     bool        m_bToplevelParentFound;
300     bool        m_bLegacy;
301     std::unique_ptr<ParserState> m_pParserState;
302 
303     vcl::Window *get_by_name(std::string_view sID);
304     void        delete_by_name(const OString& sID);
305 
306     class sortIntoBestTabTraversalOrder
307     {
308     public:
sortIntoBestTabTraversalOrder(VclBuilder * pBuilder)309                 sortIntoBestTabTraversalOrder(VclBuilder *pBuilder)
310                     : m_pBuilder(pBuilder) {}
311 
312         bool    operator()(const vcl::Window *pA, const vcl::Window *pB) const;
313 
314     private:
315         VclBuilder *m_pBuilder;
316     };
317 
318     /// XFrame to be able to extract labels and other properties of the UNO commands (like of .uno:Bold).
319     css::uno::Reference<css::frame::XFrame> m_xFrame;
320 
321 private:
322     VclPtr<vcl::Window> insertObject(vcl::Window *pParent,
323                     const OString &rClass, const OString &rID,
324                     stringmap &rProps, stringmap &rPangoAttributes,
325                     stringmap &rAtkProps);
326 
327     VclPtr<vcl::Window> makeObject(vcl::Window *pParent,
328                     const OString &rClass, const OString &rID,
329                     stringmap &rVec);
330 
331     void        connectNumericFormatterAdjustment(const OString &id, const OUString &rAdjustment);
332     void        connectFormattedFormatterAdjustment(const OString &id, const OUString &rAdjustment);
333 
334     static int  getImageSize(const stringmap &rMap);
335 
336     void        extractGroup(const OString &id, stringmap &rVec);
337     void        extractModel(const OString &id, stringmap &rVec);
338     void        extractBuffer(const OString &id, stringmap &rVec);
339     static bool extractAdjustmentToMap(const OString &id, stringmap &rVec, std::vector<WidgetAdjustmentMap>& rAdjustmentMap);
340     void        extractButtonImage(const OString &id, stringmap &rMap, bool bRadio);
341     void        extractMnemonicWidget(const OString &id, stringmap &rMap);
342 
343     // either pParent or pAtkProps must be set, pParent for a child of a widget, pAtkProps for
344     // collecting the atk info for a GtkMenuItem
345     void        handleChild(vcl::Window *pParent, stringmap *pAtkProps, xmlreader::XmlReader &reader);
346     VclPtr<vcl::Window> handleObject(vcl::Window *pParent, stringmap *pAtkProps, xmlreader::XmlReader &reader);
347     void        handlePacking(vcl::Window *pCurrent, vcl::Window *pParent, xmlreader::XmlReader &reader);
348     static std::vector<vcl::EnumContext::Context> handleStyle(xmlreader::XmlReader &reader, int &nPriority);
349     static OString getStyleClass(xmlreader::XmlReader &reader);
350     void        applyPackingProperty(vcl::Window *pCurrent, vcl::Window *pParent, xmlreader::XmlReader &reader);
351     void        collectProperty(xmlreader::XmlReader &reader, stringmap &rVec) const;
352     static void collectPangoAttribute(xmlreader::XmlReader &reader, stringmap &rMap);
353     static void collectAtkRelationAttribute(xmlreader::XmlReader &reader, stringmap &rMap);
354     static void collectAtkRoleAttribute(xmlreader::XmlReader &reader, stringmap &rMap);
355     static void collectAccelerator(xmlreader::XmlReader &reader, accelmap &rMap);
356 
357     void        insertMenuObject(
358                    Menu *pParent,
359                    PopupMenu *pSubMenu,
360                    const OString &rClass,
361                    const OString &rID,
362                    stringmap &rProps,
363                    stringmap &rAtkProps,
364                    accelmap &rAccels);
365 
366     void        handleMenuChild(Menu *pParent, xmlreader::XmlReader &reader);
367     void        handleMenuObject(Menu *pParent, xmlreader::XmlReader &reader);
368 
369     void        handleListStore(xmlreader::XmlReader &reader, const OString &rID, std::string_view rClass);
370     void        handleRow(xmlreader::XmlReader &reader, const OString &rID);
371     void        handleTabChild(vcl::Window *pParent, xmlreader::XmlReader &reader);
372     VclPtr<Menu> handleMenu(xmlreader::XmlReader &reader, const OString &rID, bool bMenuBar);
373     std::vector<ComboBoxTextItem> handleItems(xmlreader::XmlReader &reader) const;
374 
375     void        handleSizeGroup(xmlreader::XmlReader &reader);
376 
377     stringmap   handleAtkObject(xmlreader::XmlReader &reader);
378 
379     static void applyAtkProperties(vcl::Window *pWindow, const stringmap& rProperties);
380 
381     void        handleActionWidget(xmlreader::XmlReader &reader);
382 
383     PackingData get_window_packing_data(const vcl::Window *pWindow) const;
384     void        set_window_packing_position(const vcl::Window *pWindow, sal_Int32 nPosition);
385 
386     static vcl::Window* prepareWidgetOwnScrolling(vcl::Window *pParent, WinBits &rWinStyle);
387     void        cleanupWidgetOwnScrolling(vcl::Window *pScrollParent, vcl::Window *pWindow, stringmap &rMap);
388 
389     void        set_response(std::string_view sID, short nResponse);
390 
391     OString         get_by_window(const vcl::Window *pWindow) const;
392     void            delete_by_window(vcl::Window *pWindow);
393 };
394 
395 namespace BuilderUtils
396 {
397     //apply the properties of rProps to pWindow
398     VCL_DLLPUBLIC void set_properties(vcl::Window *pWindow, const VclBuilder::stringmap &rProps);
399 
400     //Convert _ gtk markup to ~ vcl markup
401     VCL_DLLPUBLIC OUString convertMnemonicMarkup(const OUString &rIn);
402 
403     VCL_DLLPUBLIC OUString extractCustomProperty(VclBuilder::stringmap &rMap);
404 
405     VCL_DLLPUBLIC bool extractDropdown(VclBuilder::stringmap &rMap);
406 
407     //add a default value of 25 width-chars to a map if width-chars not set
408     VCL_DLLPUBLIC void ensureDefaultWidthChars(VclBuilder::stringmap &rMap);
409 
410     //Helpers to retrofit all the existing code to the builder
411     VCL_DLLPUBLIC void reorderWithinParent(std::vector< vcl::Window*>& rChilds, bool bIsButtonBox);
412     VCL_DLLPUBLIC void reorderWithinParent(vcl::Window &rWindow, sal_uInt16 nNewPosition);
413 
414     //Convert an accessibility role name to accessibility role number
415     VCL_DLLPUBLIC sal_Int16 getRoleFromName(const OString& roleName);
416 }
417 
418 template <typename T>
get(VclPtr<T> & ret,const OString & sID)419 inline T* VclBuilder::get(VclPtr<T>& ret, const OString& sID)
420 {
421     vcl::Window *w = get_by_name(sID);
422     SAL_WARN_IF(!w, "vcl.layout", "widget \"" << sID << "\" not found in .ui");
423     SAL_WARN_IF(!dynamic_cast<T*>(w),
424        "vcl.layout", ".ui widget \"" << sID << "\" needs to correspond to vcl type " << typeid(T).name());
425     assert(w);
426     assert(dynamic_cast<T*>(w));
427     ret = static_cast<T*>(w);
428     return ret.get();
429 }
430 
431 //sID may not exist, but must be of type T if it does
432 template <typename T>
get(const OString & sID)433 inline T* VclBuilder::get(const OString& sID)
434 {
435     vcl::Window *w = get_by_name(sID);
436     SAL_WARN_IF(w && !dynamic_cast<T*>(w),
437         "vcl.layout", ".ui widget \"" << sID << "\" needs to correspond to vcl type " << typeid(T).name());
438     assert(!w || dynamic_cast<T*>(w));
439     return static_cast<T*>(w);
440 }
441 
442 /*
443  * @return true if rValue is "True", "true", "1", etc.
444  */
445 VCL_DLLPUBLIC bool toBool(std::u16string_view rValue);
446 
447 #endif
448 
449 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
450