summaryrefslogtreecommitdiff
path: root/include/vcl/weldutils.hxx
blob: 5cb8e5c972aaeb98a4770279d6052d5be2a8d223 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDED_VCL_WELDUTILS_HXX
#define INCLUDED_VCL_WELDUTILS_HXX

#include <com/sun/star/awt/XWindow.hpp>
#include <com/sun/star/frame/XDispatch.hpp>
#include <com/sun/star/frame/XFrame.hpp>
#include <com/sun/star/frame/XStatusListener.hpp>
#include <com/sun/star/uno/Reference.hxx>
#include <comphelper/interfacecontainer2.hxx>
#include <cppuhelper/compbase.hxx>
#include <tools/time.hxx>
#include <vcl/dllapi.h>
#include <vcl/formatter.hxx>
#include <vcl/timer.hxx>
#include <vcl/transfer.hxx>
#include <vcl/weld.hxx>

class CalendarWrapper;

namespace vcl
{
class Window;
}

namespace weld
{
typedef cppu::WeakComponentImplHelper<css::awt::XWindow> TransportAsXWindow_Base;

class VCL_DLLPUBLIC TransportAsXWindow : public TransportAsXWindow_Base
{
private:
    osl::Mutex m_aHelperMtx;
    weld::Widget* m_pWeldWidget;
    weld::Builder* m_pWeldWidgetBuilder;

    comphelper::OInterfaceContainerHelper2 m_aWindowListeners;
    comphelper::OInterfaceContainerHelper2 m_aKeyListeners;
    comphelper::OInterfaceContainerHelper2 m_aFocusListeners;
    comphelper::OInterfaceContainerHelper2 m_aMouseListeners;
    comphelper::OInterfaceContainerHelper2 m_aMotionListeners;
    comphelper::OInterfaceContainerHelper2 m_aPaintListeners;

public:
    TransportAsXWindow(weld::Widget* pWeldWidget, weld::Builder* pWeldWidgetBuilder = nullptr)
        : TransportAsXWindow_Base(m_aHelperMtx)
        , m_pWeldWidget(pWeldWidget)
        , m_pWeldWidgetBuilder(pWeldWidgetBuilder)
        , m_aWindowListeners(m_aHelperMtx)
        , m_aKeyListeners(m_aHelperMtx)
        , m_aFocusListeners(m_aHelperMtx)
        , m_aMouseListeners(m_aHelperMtx)
        , m_aMotionListeners(m_aHelperMtx)
        , m_aPaintListeners(m_aHelperMtx)
    {
    }

    weld::Widget* getWidget() const { return m_pWeldWidget; }

    weld::Builder* getBuilder() const { return m_pWeldWidgetBuilder; }

    virtual void clear()
    {
        m_pWeldWidget = nullptr;
        m_pWeldWidgetBuilder = nullptr;
    }

    // css::awt::XWindow
    void SAL_CALL setPosSize(sal_Int32, sal_Int32, sal_Int32, sal_Int32, sal_Int16) override
    {
        throw css::uno::RuntimeException("not implemented");
    }

    css::awt::Rectangle SAL_CALL getPosSize() override
    {
        throw css::uno::RuntimeException("not implemented");
    }

    void SAL_CALL setVisible(sal_Bool bVisible) override { m_pWeldWidget->set_visible(bVisible); }

    void SAL_CALL setEnable(sal_Bool bSensitive) override
    {
        m_pWeldWidget->set_sensitive(bSensitive);
    }

    void SAL_CALL setFocus() override { m_pWeldWidget->grab_focus(); }

    void SAL_CALL
    addWindowListener(const css::uno::Reference<css::awt::XWindowListener>& rListener) override
    {
        m_aWindowListeners.addInterface(rListener);
    }

    void SAL_CALL
    removeWindowListener(const css::uno::Reference<css::awt::XWindowListener>& rListener) override
    {
        m_aWindowListeners.removeInterface(rListener);
    }

    void SAL_CALL
    addFocusListener(const css::uno::Reference<css::awt::XFocusListener>& rListener) override
    {
        m_aFocusListeners.addInterface(rListener);
    }

    void SAL_CALL
    removeFocusListener(const css::uno::Reference<css::awt::XFocusListener>& rListener) override
    {
        m_aFocusListeners.removeInterface(rListener);
    }

    void SAL_CALL
    addKeyListener(const css::uno::Reference<css::awt::XKeyListener>& rListener) override
    {
        m_aKeyListeners.addInterface(rListener);
    }

    void SAL_CALL
    removeKeyListener(const css::uno::Reference<css::awt::XKeyListener>& rListener) override
    {
        m_aKeyListeners.removeInterface(rListener);
    }

    void SAL_CALL
    addMouseListener(const css::uno::Reference<css::awt::XMouseListener>& rListener) override
    {
        m_aMouseListeners.addInterface(rListener);
    }

    void SAL_CALL
    removeMouseListener(const css::uno::Reference<css::awt::XMouseListener>& rListener) override
    {
        m_aMouseListeners.removeInterface(rListener);
    }

    void SAL_CALL addMouseMotionListener(
        const css::uno::Reference<css::awt::XMouseMotionListener>& rListener) override
    {
        m_aMotionListeners.addInterface(rListener);
    }

    void SAL_CALL removeMouseMotionListener(
        const css::uno::Reference<css::awt::XMouseMotionListener>& rListener) override
    {
        m_aMotionListeners.removeInterface(rListener);
    }

    void SAL_CALL
    addPaintListener(const css::uno::Reference<css::awt::XPaintListener>& rListener) override
    {
        m_aPaintListeners.addInterface(rListener);
    }

    void SAL_CALL
    removePaintListener(const css::uno::Reference<css::awt::XPaintListener>& rListener) override
    {
        m_aPaintListeners.removeInterface(rListener);
    }
};

// don't export to avoid duplicate WeakImplHelper definitions with MSVC
class SAL_DLLPUBLIC_TEMPLATE WidgetStatusListener_Base
    : public cppu::WeakImplHelper<css::frame::XStatusListener>
{
};

class VCL_DLLPUBLIC WidgetStatusListener final : public WidgetStatusListener_Base
{
public:
    WidgetStatusListener(weld::Widget* widget, const OUString& rCommand);

private:
    weld::Widget* mWidget; /** The widget on which actions are performed */

    /** Dispatcher. Need to keep a reference to it as long as this StatusListener exists. */
    css::uno::Reference<css::frame::XDispatch> mxDispatch;
    css::util::URL maCommandURL;
    css::uno::Reference<css::frame::XFrame> mxFrame;

public:
    void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& rEvent) override;

    void SAL_CALL disposing(const css::lang::EventObject& /*Source*/) override;

    const css::uno::Reference<css::frame::XFrame>& getFrame() const { return mxFrame; }

    void startListening();

    void dispose();
};

class VCL_DLLPUBLIC EntryFormatter : public Formatter
{
public:
    EntryFormatter(weld::Entry& rEntry);
    EntryFormatter(weld::FormattedSpinButton& rSpinButton);

    weld::Entry& get_widget() { return m_rEntry; }

    // public Formatter overrides, drives interactions with the Entry
    virtual Selection GetEntrySelection() const override;
    virtual OUString GetEntryText() const override;
    virtual void SetEntryText(const OUString& rText, const Selection& rSel) override;
    virtual void SetEntryTextColor(const Color* pColor) override;
    virtual SelectionOptions GetEntrySelectionOptions() const override;
    virtual void FieldModified() override;

    // public Formatter overrides, drives optional SpinButton settings
    virtual void ClearMinValue() override;
    virtual void SetMinValue(double dMin) override;
    virtual void ClearMaxValue() override;
    virtual void SetMaxValue(double dMin) override;

    virtual void SetSpinSize(double dStep) override;

    void SetEntrySelectionOptions(SelectionOptions eOptions) { m_eOptions = eOptions; }

    /* EntryFormatter will set listeners to "changed" and "focus-out" of the
       Entry so users that want to add their own listeners to those must set
       them through this formatter and not directly on that entry.

       If EntryFormatter is used with a weld::FormattedSpinButton this is
       handled transparently by the FormattedSpinButton for the user and the
       handlers can be set on the FormattedSpinButton
    */
    void connect_changed(const Link<weld::Entry&, void>& rLink) { m_aModifyHdl = rLink; }
    void connect_focus_out(const Link<weld::Widget&, void>& rLink) { m_aFocusOutHdl = rLink; }

    virtual ~EntryFormatter() override;

private:
    weld::Entry& m_rEntry;
    weld::FormattedSpinButton* m_pSpinButton;
    Link<weld::Entry&, void> m_aModifyHdl;
    Link<weld::Widget&, void> m_aFocusOutHdl;
    SelectionOptions m_eOptions;
    DECL_DLLPRIVATE_LINK(ModifyHdl, weld::Entry&, void);
    DECL_DLLPRIVATE_LINK(FocusOutHdl, weld::Widget&, void);
    void Init();

    // private Formatter overrides
    virtual void UpdateCurrentValue(double dCurrentValue) override;
};

class VCL_DLLPUBLIC DoubleNumericFormatter final : public EntryFormatter
{
public:
    DoubleNumericFormatter(weld::Entry& rEntry);
    DoubleNumericFormatter(weld::FormattedSpinButton& rSpinButton);

    virtual ~DoubleNumericFormatter() override;

private:
    virtual bool CheckText(const OUString& sText) const override;

    virtual void FormatChanged(FORMAT_CHANGE_TYPE nWhat) override;
    void ResetConformanceTester();

    std::unique_ptr<validation::NumberValidator> m_pNumberValidator;
};

class VCL_DLLPUBLIC LongCurrencyFormatter final : public EntryFormatter
{
public:
    LongCurrencyFormatter(weld::Entry& rEntry);
    LongCurrencyFormatter(weld::FormattedSpinButton& rSpinButton);

    void SetUseThousandSep(bool b);
    void SetCurrencySymbol(const OUString& rStr);

    virtual ~LongCurrencyFormatter() override;

private:
    DECL_DLLPRIVATE_LINK(FormatOutputHdl, LinkParamNone*, bool);
    DECL_DLLPRIVATE_LINK(ParseInputHdl, sal_Int64*, TriState);

    void Init();

    OUString m_aCurrencySymbol;
    bool m_bThousandSep;
};

class VCL_DLLPUBLIC TimeFormatter final : public EntryFormatter
{
public:
    TimeFormatter(weld::Entry& rEntry);
    TimeFormatter(weld::FormattedSpinButton& rSpinButton);

    void SetExtFormat(ExtTimeFieldFormat eFormat);
    void SetDuration(bool bDuration);
    void SetTimeFormat(TimeFieldFormat eTimeFormat);

    void SetMin(const tools::Time& rNewMin);
    void SetMax(const tools::Time& rNewMax);

    void SetTime(const tools::Time& rNewTime);
    tools::Time GetTime();

    virtual ~TimeFormatter() override;

private:
    DECL_DLLPRIVATE_LINK(FormatOutputHdl, LinkParamNone*, bool);
    DECL_DLLPRIVATE_LINK(ParseInputHdl, sal_Int64*, TriState);
    DECL_DLLPRIVATE_LINK(CursorChangedHdl, weld::Entry&, void);

    void Init();

    static tools::Time ConvertValue(int nValue);
    static int ConvertValue(const tools::Time& rTime);

    OUString FormatNumber(int nValue) const;

    TimeFieldFormat m_eFormat;
    TimeFormat m_eTimeFormat;
    bool m_bDuration;
};

class VCL_DLLPUBLIC DateFormatter final : public EntryFormatter
{
public:
    DateFormatter(weld::Entry& rEntry);

    void SetMin(const Date& rNewMin);
    void SetMax(const Date& rNewMax);

    void SetDate(const Date& rNewDate);
    Date GetDate();

    void SetExtDateFormat(ExtDateFieldFormat eFormat);
    void SetShowDateCentury(bool bShowCentury);

    virtual ~DateFormatter() override;

private:
    DECL_DLLPRIVATE_LINK(FormatOutputHdl, LinkParamNone*, bool);
    DECL_DLLPRIVATE_LINK(ParseInputHdl, sal_Int64*, TriState);
    DECL_DLLPRIVATE_LINK(CursorChangedHdl, weld::Entry&, void);

    void Init();
    CalendarWrapper& GetCalendarWrapper() const;

    OUString FormatNumber(int nValue) const;

    ExtDateFieldFormat m_eFormat;
    mutable std::unique_ptr<CalendarWrapper> m_xCalendarWrapper;
};

class VCL_DLLPUBLIC PatternFormatter final
{
public:
    PatternFormatter(weld::Entry& rEntry);
    ~PatternFormatter();

    weld::Entry& get_widget() { return m_rEntry; }

    void SetMask(const OString& rEditMask, const OUString& rLiteralMask);
    void SetStrictFormat(bool bStrict);
    void ReformatAll();

    /* PatternFormatter will set listeners to "changed", "focus-out", "focus-in"
       and  "key-press" of the Entry so users that want to add their own listeners
       to those must set them through this formatter and not directly on that entry.
    */
    void connect_changed(const Link<weld::Entry&, void>& rLink) { m_aModifyHdl = rLink; }
    void connect_focus_out(const Link<weld::Widget&, void>& rLink) { m_aFocusOutHdl = rLink; }
    void connect_focus_in(const Link<weld::Widget&, void>& rLink) { m_aFocusInHdl = rLink; }
    void connect_key_press(const Link<const KeyEvent&, bool>& rLink) { m_aKeyPressHdl = rLink; }

    void Modify();

private:
    weld::Entry& m_rEntry;
    Link<weld::Entry&, void> m_aModifyHdl;
    Link<weld::Widget&, void> m_aFocusInHdl;
    Link<weld::Widget&, void> m_aFocusOutHdl;
    Link<const KeyEvent&, bool> m_aKeyPressHdl;
    bool m_bStrictFormat;
    bool m_bSameMask;
    bool m_bReformat;
    bool m_bInPattKeyInput;
    OString m_aEditMask;
    OUString m_aLiteralMask;

    void EntryGainFocus();
    void EntryLostFocus();
    DECL_DLLPRIVATE_LINK(ModifyHdl, weld::Entry&, void);
    DECL_DLLPRIVATE_LINK(FocusInHdl, weld::Widget&, void);
    DECL_DLLPRIVATE_LINK(FocusOutHdl, weld::Widget&, void);
    DECL_DLLPRIVATE_LINK(KeyInputHdl, const KeyEvent&, bool);
};

class VCL_DLLPUBLIC ButtonPressRepeater final
    : public std::enable_shared_from_this<ButtonPressRepeater>
{
private:
    weld::Button& m_rButton;
    AutoTimer m_aRepeat;
    const Link<Button&, void> m_aLink;
    const Link<const CommandEvent&, void> m_aContextLink;
    bool m_bModKey;

    DECL_DLLPRIVATE_LINK(MousePressHdl, const MouseEvent&, bool);
    DECL_DLLPRIVATE_LINK(MouseReleaseHdl, const MouseEvent&, bool);
    DECL_DLLPRIVATE_LINK(RepeatTimerHdl, Timer*, void);

public:
    ButtonPressRepeater(weld::Button& rButton, const Link<Button&, void>& rLink,
                        const Link<const CommandEvent&, void>& rContextLink
                        = Link<const CommandEvent&, void>());
    void Stop() { m_aRepeat.Stop(); }
    bool IsModKeyPressed() const { return m_bModKey; }
};

/*
  If a TreeView is used as a list, rather than a tree, and DnD should just
  reorder rows, then this can be used to implement that.

  Because the TreeView doesn't want or need subnodes, the drop target can be
  simply visually indicated as being between rows (the issue of a final drop
  location of a child of the drop target doesn't arise), and the meaning of
  what a drop before or after the last row should do is unambiguous.
*/
class VCL_DLLPUBLIC ReorderingDropTarget : public DropTargetHelper
{
protected:
    weld::TreeView& m_rTreeView;
    virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override;
    virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override;

public:
    ReorderingDropTarget(weld::TreeView& rTreeView);
};

// get the row the iterator is on
VCL_DLLPUBLIC size_t GetAbsPos(const weld::TreeView& rTreeView, const weld::TreeIter& rIter);

// an entry is visible if all parents are expanded
VCL_DLLPUBLIC bool IsEntryVisible(const weld::TreeView& rTreeView, const weld::TreeIter& rIter);

// A Parent's Children are turned into Children of the Parent which comes next in hierarchy
VCL_DLLPUBLIC void RemoveParentKeepChildren(weld::TreeView& rTreeView,
                                            const weld::TreeIter& rParent);

// return the min height of a weld::Entry
VCL_DLLPUBLIC int GetMinimumEditHeight();

// return the weld::Window of the SalFrame rOutWin is in, and convert rRect
// from relative to rOutWin to relative to that weld::Window suitable for use
// with popup_at_rect
VCL_DLLPUBLIC weld::Window* GetPopupParent(vcl::Window& rOutWin, tools::Rectangle& rRect);

// Use Application::GetDefaultDevice to set the PointFont rFont to the OutputDevice
VCL_DLLPUBLIC void SetPointFont(OutputDevice& rDevice, const vcl::Font& rFont);
}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */