Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/vcl/source/app/weldutils.cxx
Line
Count
Source (jump to first uncovered line)
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
#include <com/sun/star/util/URLTransformer.hpp>
11
#include <com/sun/star/frame/Desktop.hpp>
12
#include <comphelper/processfactory.hxx>
13
#include <svl/numformat.hxx>
14
#include <svl/zforlist.hxx>
15
#include <svl/zformat.hxx>
16
#include <vcl/builderpage.hxx>
17
#include <vcl/commandevent.hxx>
18
#include <vcl/commandinfoprovider.hxx>
19
#include <vcl/event.hxx>
20
#include <vcl/toolkit/floatwin.hxx>
21
#include <vcl/settings.hxx>
22
#include <vcl/svapp.hxx>
23
#include <vcl/weldutils.hxx>
24
25
BuilderPage::BuilderPage(weld::Widget* pParent, weld::DialogController* pController,
26
                         const OUString& rUIXMLDescription, const OUString& rID, bool bIsMobile)
27
0
    : m_pDialogController(pController)
28
0
    , m_xBuilder(Application::CreateBuilder(pParent, rUIXMLDescription, bIsMobile))
29
0
    , m_xContainer(m_xBuilder->weld_container(rID))
30
0
{
31
0
}
32
33
0
void BuilderPage::Activate() {}
34
35
0
void BuilderPage::Deactivate() {}
36
37
0
BuilderPage::~BuilderPage() COVERITY_NOEXCEPT_FALSE {}
38
39
namespace weld
40
{
41
bool DialogController::runAsync(const std::shared_ptr<DialogController>& rController,
42
                                const std::function<void(sal_Int32)>& func)
43
0
{
44
0
    return rController->getDialog()->runAsync(rController, func);
45
0
}
46
47
0
DialogController::~DialogController() COVERITY_NOEXCEPT_FALSE {}
48
49
0
Dialog* GenericDialogController::getDialog() { return m_xDialog.get(); }
50
51
GenericDialogController::GenericDialogController(weld::Widget* pParent, const OUString& rUIFile,
52
                                                 const OUString& rDialogId, bool bMobile)
53
0
    : m_xBuilder(Application::CreateBuilder(pParent, rUIFile, bMobile))
54
0
    , m_xDialog(m_xBuilder->weld_dialog(rDialogId))
55
0
{
56
0
}
57
58
0
GenericDialogController::~GenericDialogController() COVERITY_NOEXCEPT_FALSE {}
59
60
0
Dialog* MessageDialogController::getDialog() { return m_xDialog.get(); }
61
62
MessageDialogController::MessageDialogController(weld::Widget* pParent, const OUString& rUIFile,
63
                                                 const OUString& rDialogId,
64
                                                 const OUString& rRelocateId)
65
0
    : m_xBuilder(Application::CreateBuilder(pParent, rUIFile))
66
0
    , m_xDialog(m_xBuilder->weld_message_dialog(rDialogId))
67
0
    , m_xContentArea(m_xDialog->weld_message_area())
68
0
{
69
0
    if (!rRelocateId.isEmpty())
70
0
    {
71
0
        m_xRelocate = m_xBuilder->weld_container(rRelocateId);
72
0
        m_xOrigParent = m_xRelocate->weld_parent();
73
        //fdo#75121, a bit tricky because the widgets we want to align with
74
        //don't actually exist in the ui description, they're implied
75
0
        m_xOrigParent->move(m_xRelocate.get(), m_xContentArea.get());
76
0
    }
77
0
}
78
79
MessageDialogController::~MessageDialogController()
80
0
{
81
0
    if (m_xRelocate)
82
0
    {
83
0
        m_xContentArea->move(m_xRelocate.get(), m_xOrigParent.get());
84
0
    }
85
0
}
86
87
AssistantController::AssistantController(weld::Widget* pParent, const OUString& rUIFile,
88
                                         const OUString& rDialogId)
89
0
    : m_xBuilder(Application::CreateBuilder(pParent, rUIFile))
90
0
    , m_xAssistant(m_xBuilder->weld_assistant(rDialogId))
91
0
{
92
0
}
93
94
0
Dialog* AssistantController::getDialog() { return m_xAssistant.get(); }
95
96
0
AssistantController::~AssistantController() {}
97
98
void TriStateEnabled::ButtonToggled(weld::Toggleable& rToggle)
99
0
{
100
0
    if (bTriStateEnabled)
101
0
    {
102
0
        switch (eState)
103
0
        {
104
0
            case TRISTATE_INDET:
105
0
                rToggle.set_state(TRISTATE_FALSE);
106
0
                break;
107
0
            case TRISTATE_TRUE:
108
0
                rToggle.set_state(TRISTATE_INDET);
109
0
                break;
110
0
            case TRISTATE_FALSE:
111
0
                rToggle.set_state(TRISTATE_TRUE);
112
0
                break;
113
0
        }
114
0
    }
115
0
    eState = rToggle.get_state();
116
0
}
117
118
void RemoveParentKeepChildren(weld::TreeView& rTreeView, const weld::TreeIter& rParent)
119
0
{
120
0
    if (rTreeView.iter_has_child(rParent))
121
0
    {
122
0
        std::unique_ptr<weld::TreeIter> xNewParent(rTreeView.make_iterator(&rParent));
123
0
        if (!rTreeView.iter_parent(*xNewParent))
124
0
            xNewParent.reset();
125
126
0
        while (true)
127
0
        {
128
0
            std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(&rParent));
129
0
            if (!rTreeView.iter_children(*xChild))
130
0
                break;
131
0
            rTreeView.move_subtree(*xChild, xNewParent.get(), -1);
132
0
        }
133
0
    }
134
0
    rTreeView.remove(rParent);
135
0
}
136
137
EntryFormatter::EntryFormatter(weld::FormattedSpinButton& rSpinButton)
138
0
    : m_rEntry(rSpinButton)
139
0
    , m_pSpinButton(&rSpinButton)
140
0
    , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
141
0
{
142
0
    Init();
143
0
}
144
145
EntryFormatter::EntryFormatter(weld::Entry& rEntry)
146
0
    : m_rEntry(rEntry)
147
0
    , m_pSpinButton(nullptr)
148
0
    , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
149
0
{
150
0
    Init();
151
0
}
152
153
EntryFormatter::~EntryFormatter()
154
0
{
155
0
    m_rEntry.connect_changed(Link<weld::Entry&, void>());
156
0
    m_rEntry.connect_focus_out(Link<weld::Widget&, void>());
157
0
    if (m_pSpinButton)
158
0
        m_pSpinButton->SetFormatter(nullptr);
159
0
}
160
161
void EntryFormatter::Init()
162
0
{
163
0
    m_rEntry.connect_changed(LINK(this, EntryFormatter, ModifyHdl));
164
0
    m_rEntry.connect_focus_out(LINK(this, EntryFormatter, FocusOutHdl));
165
0
    if (m_pSpinButton)
166
0
        m_pSpinButton->SetFormatter(this);
167
0
}
168
169
Selection EntryFormatter::GetEntrySelection() const
170
0
{
171
0
    int nStartPos, nEndPos;
172
0
    m_rEntry.get_selection_bounds(nStartPos, nEndPos);
173
0
    return Selection(nStartPos, nEndPos);
174
0
}
175
176
0
OUString EntryFormatter::GetEntryText() const { return m_rEntry.get_text(); }
177
178
void EntryFormatter::SetEntryText(const OUString& rText, const Selection& rSel)
179
0
{
180
0
    m_rEntry.set_text(rText);
181
0
    auto nMin = rSel.Min();
182
0
    auto nMax = rSel.Max();
183
0
    m_rEntry.select_region(nMin < 0 ? 0 : nMin, nMax == SELECTION_MAX ? -1 : nMax);
184
0
}
185
186
void EntryFormatter::SetEntryTextColor(const Color* pColor)
187
0
{
188
0
    m_rEntry.set_font_color(pColor ? *pColor : COL_AUTO);
189
0
}
190
191
void EntryFormatter::UpdateCurrentValue(double dCurrentValue)
192
0
{
193
0
    Formatter::UpdateCurrentValue(dCurrentValue);
194
0
    if (m_pSpinButton)
195
0
        m_pSpinButton->sync_value_from_formatter();
196
0
}
197
198
void EntryFormatter::ClearMinValue()
199
0
{
200
0
    Formatter::ClearMinValue();
201
0
    if (m_pSpinButton)
202
0
        m_pSpinButton->sync_range_from_formatter();
203
0
}
204
205
void EntryFormatter::SetMinValue(double dMin)
206
0
{
207
0
    Formatter::SetMinValue(dMin);
208
0
    if (m_pSpinButton)
209
0
        m_pSpinButton->sync_range_from_formatter();
210
0
}
211
212
void EntryFormatter::ClearMaxValue()
213
0
{
214
0
    Formatter::ClearMaxValue();
215
0
    if (m_pSpinButton)
216
0
        m_pSpinButton->sync_range_from_formatter();
217
0
}
218
219
void EntryFormatter::SetMaxValue(double dMin)
220
0
{
221
0
    Formatter::SetMaxValue(dMin);
222
0
    if (m_pSpinButton)
223
0
        m_pSpinButton->sync_range_from_formatter();
224
0
}
225
226
void EntryFormatter::SetSpinSize(double dStep)
227
0
{
228
0
    Formatter::SetSpinSize(dStep);
229
0
    if (m_pSpinButton)
230
0
        m_pSpinButton->sync_increments_from_formatter();
231
0
}
232
233
0
SelectionOptions EntryFormatter::GetEntrySelectionOptions() const { return m_eOptions; }
234
235
0
void EntryFormatter::FieldModified() { m_aModifyHdl.Call(m_rEntry); }
236
237
IMPL_LINK_NOARG(EntryFormatter, ModifyHdl, weld::Entry&, void)
238
0
{
239
    // This leads to FieldModified getting called at the end of Modify() and
240
    // FieldModified then calls any modification callback
241
0
    Modify();
242
0
}
243
244
IMPL_LINK_NOARG(EntryFormatter, FocusOutHdl, weld::Widget&, void)
245
0
{
246
0
    EntryLostFocus();
247
0
    if (m_pSpinButton)
248
0
        m_pSpinButton->signal_value_changed();
249
0
    m_aFocusOutHdl.Call(m_rEntry);
250
0
}
251
252
DoubleNumericFormatter::DoubleNumericFormatter(weld::Entry& rEntry)
253
0
    : EntryFormatter(rEntry)
254
0
{
255
0
    ResetConformanceTester();
256
0
}
257
258
DoubleNumericFormatter::DoubleNumericFormatter(weld::FormattedSpinButton& rSpinButton)
259
0
    : EntryFormatter(rSpinButton)
260
0
{
261
0
    ResetConformanceTester();
262
0
}
263
264
0
DoubleNumericFormatter::~DoubleNumericFormatter() = default;
265
266
void DoubleNumericFormatter::FormatChanged(FORMAT_CHANGE_TYPE nWhat)
267
0
{
268
0
    ResetConformanceTester();
269
0
    EntryFormatter::FormatChanged(nWhat);
270
0
}
271
272
bool DoubleNumericFormatter::CheckText(const OUString& sText) const
273
0
{
274
    // We'd like to implement this using the NumberFormatter::IsNumberFormat, but unfortunately, this doesn't
275
    // recognize fragments of numbers (like, for instance "1e", which happens during entering e.g. "1e10")
276
    // Thus, the roundabout way via a regular expression
277
0
    return m_pNumberValidator->isValidNumericFragment(sText);
278
0
}
279
280
void DoubleNumericFormatter::ResetConformanceTester()
281
0
{
282
    // the thousands and the decimal separator are language dependent
283
0
    const SvNumberformat* pFormatEntry = GetOrCreateFormatter().GetEntry(m_nFormatKey);
284
285
0
    sal_Unicode cSeparatorThousand = ',';
286
0
    sal_Unicode cSeparatorDecimal = '.';
287
0
    if (pFormatEntry)
288
0
    {
289
0
        LocaleDataWrapper aLocaleInfo(LanguageTag(pFormatEntry->GetLanguage()));
290
291
0
        OUString sSeparator = aLocaleInfo.getNumThousandSep();
292
0
        if (!sSeparator.isEmpty())
293
0
            cSeparatorThousand = sSeparator[0];
294
295
0
        sSeparator = aLocaleInfo.getNumDecimalSep();
296
0
        if (!sSeparator.isEmpty())
297
0
            cSeparatorDecimal = sSeparator[0];
298
0
    }
299
300
0
    m_pNumberValidator.reset(
301
0
        new validation::NumberValidator(cSeparatorThousand, cSeparatorDecimal));
302
0
}
303
304
LongCurrencyFormatter::LongCurrencyFormatter(weld::Entry& rEntry)
305
0
    : EntryFormatter(rEntry)
306
0
    , m_bThousandSep(true)
307
0
{
308
0
    Init();
309
0
}
310
311
LongCurrencyFormatter::LongCurrencyFormatter(weld::FormattedSpinButton& rSpinButton)
312
0
    : EntryFormatter(rSpinButton)
313
0
    , m_bThousandSep(true)
314
0
{
315
0
    Init();
316
0
}
317
318
void LongCurrencyFormatter::Init()
319
0
{
320
0
    SetFormatValueHdl(LINK(this, LongCurrencyFormatter, FormatOutputHdl));
321
0
    SetParseTextHdl(LINK(this, LongCurrencyFormatter, ParseInputHdl));
322
0
}
323
324
void LongCurrencyFormatter::SetUseThousandSep(bool b)
325
0
{
326
0
    m_bThousandSep = b;
327
0
    ReFormat();
328
0
}
329
330
void LongCurrencyFormatter::SetCurrencySymbol(const OUString& rStr)
331
0
{
332
0
    m_aCurrencySymbol = rStr;
333
0
    ReFormat();
334
0
}
335
336
0
LongCurrencyFormatter::~LongCurrencyFormatter() = default;
337
338
TimeFormatter::TimeFormatter(weld::Entry& rEntry)
339
0
    : EntryFormatter(rEntry)
340
0
    , m_eFormat(TimeFieldFormat::F_NONE)
341
0
    , m_eTimeFormat(TimeFormat::Hour24)
342
0
    , m_bDuration(false)
343
0
{
344
0
    Init();
345
0
}
346
347
TimeFormatter::TimeFormatter(weld::FormattedSpinButton& rSpinButton)
348
0
    : EntryFormatter(rSpinButton)
349
0
    , m_eFormat(TimeFieldFormat::F_NONE)
350
0
    , m_eTimeFormat(TimeFormat::Hour24)
351
0
    , m_bDuration(false)
352
0
{
353
0
    Init();
354
0
}
355
356
void TimeFormatter::Init()
357
0
{
358
0
    DisableRemainderFactor(); //so with hh::mm::ss, incrementing mm will not reset ss
359
360
0
    SetFormatValueHdl(LINK(this, TimeFormatter, FormatOutputHdl));
361
0
    SetParseTextHdl(LINK(this, TimeFormatter, ParseInputHdl));
362
363
0
    SetMin(tools::Time(0, 0));
364
0
    SetMax(tools::Time(23, 59, 59, 999999999));
365
366
    // so the spin size can depend on which zone the cursor is in
367
0
    get_widget().connect_cursor_position(LINK(this, TimeFormatter, CursorChangedHdl));
368
    // and set the initial spin size
369
0
    CursorChangedHdl(get_widget());
370
0
}
371
372
void TimeFormatter::SetExtFormat(ExtTimeFieldFormat eFormat)
373
0
{
374
0
    switch (eFormat)
375
0
    {
376
0
        case ExtTimeFieldFormat::Short24H:
377
0
        {
378
0
            m_eTimeFormat = TimeFormat::Hour24;
379
0
            m_bDuration = false;
380
0
            m_eFormat = TimeFieldFormat::F_NONE;
381
0
        }
382
0
        break;
383
0
        case ExtTimeFieldFormat::Long24H:
384
0
        {
385
0
            m_eTimeFormat = TimeFormat::Hour24;
386
0
            m_bDuration = false;
387
0
            m_eFormat = TimeFieldFormat::F_SEC;
388
0
        }
389
0
        break;
390
0
        case ExtTimeFieldFormat::Short12H:
391
0
        {
392
0
            m_eTimeFormat = TimeFormat::Hour12;
393
0
            m_bDuration = false;
394
0
            m_eFormat = TimeFieldFormat::F_NONE;
395
0
        }
396
0
        break;
397
0
        case ExtTimeFieldFormat::Long12H:
398
0
        {
399
0
            m_eTimeFormat = TimeFormat::Hour12;
400
0
            m_bDuration = false;
401
0
            m_eFormat = TimeFieldFormat::F_SEC;
402
0
        }
403
0
        break;
404
0
        case ExtTimeFieldFormat::ShortDuration:
405
0
        {
406
0
            m_bDuration = true;
407
0
            m_eFormat = TimeFieldFormat::F_NONE;
408
0
        }
409
0
        break;
410
0
        case ExtTimeFieldFormat::LongDuration:
411
0
        {
412
0
            m_bDuration = true;
413
0
            m_eFormat = TimeFieldFormat::F_SEC;
414
0
        }
415
0
        break;
416
0
    }
417
418
0
    ReFormat();
419
0
}
420
421
void TimeFormatter::SetDuration(bool bDuration)
422
0
{
423
0
    m_bDuration = bDuration;
424
0
    ReFormat();
425
0
}
426
427
void TimeFormatter::SetTimeFormat(TimeFieldFormat eTimeFormat)
428
0
{
429
0
    m_eFormat = eTimeFormat;
430
0
    ReFormat();
431
0
}
432
433
TimeFormatter::~TimeFormatter() = default;
434
435
DateFormatter::DateFormatter(weld::Entry& rEntry)
436
0
    : EntryFormatter(rEntry)
437
0
    , m_eFormat(ExtDateFieldFormat::SystemShort)
438
0
{
439
0
    Init();
440
0
}
441
442
void DateFormatter::Init()
443
0
{
444
0
    SetFormatValueHdl(LINK(this, DateFormatter, FormatOutputHdl));
445
0
    SetParseTextHdl(LINK(this, DateFormatter, ParseInputHdl));
446
447
0
    SetMin(Date(1, 1, 1900));
448
0
    SetMax(Date(31, 12, 2200));
449
0
}
450
451
void DateFormatter::SetExtDateFormat(ExtDateFieldFormat eFormat)
452
0
{
453
0
    m_eFormat = eFormat;
454
0
    ReFormat();
455
0
}
456
457
0
DateFormatter::~DateFormatter() = default;
458
459
PatternFormatter::PatternFormatter(weld::Entry& rEntry)
460
0
    : m_rEntry(rEntry)
461
0
    , m_bStrictFormat(false)
462
0
    , m_bSameMask(true)
463
0
    , m_bReformat(false)
464
0
    , m_bInPattKeyInput(false)
465
0
{
466
0
    m_rEntry.connect_changed(LINK(this, PatternFormatter, ModifyHdl));
467
0
    m_rEntry.connect_focus_in(LINK(this, PatternFormatter, FocusInHdl));
468
0
    m_rEntry.connect_focus_out(LINK(this, PatternFormatter, FocusOutHdl));
469
0
    m_rEntry.connect_key_press(LINK(this, PatternFormatter, KeyInputHdl));
470
0
}
471
472
0
IMPL_LINK_NOARG(PatternFormatter, ModifyHdl, weld::Entry&, void) { Modify(); }
473
474
IMPL_LINK_NOARG(PatternFormatter, FocusOutHdl, weld::Widget&, void)
475
0
{
476
0
    EntryLostFocus();
477
0
    m_aFocusOutHdl.Call(m_rEntry);
478
0
}
479
480
IMPL_LINK_NOARG(PatternFormatter, FocusInHdl, weld::Widget&, void)
481
0
{
482
0
    EntryGainFocus();
483
0
    m_aFocusInHdl.Call(m_rEntry);
484
0
}
485
486
PatternFormatter::~PatternFormatter()
487
0
{
488
0
    m_rEntry.connect_changed(Link<weld::Entry&, void>());
489
0
    m_rEntry.connect_focus_out(Link<weld::Widget&, void>());
490
0
}
491
492
WidgetStatusListener::WidgetStatusListener(weld::Widget* widget, const OUString& aCommand)
493
0
    : mWidget(widget)
494
0
{
495
0
    const css::uno::Reference<css::uno::XComponentContext>& xContext
496
0
        = ::comphelper::getProcessComponentContext();
497
0
    css::uno::Reference<css::frame::XDesktop2> xDesktop = css::frame::Desktop::create(xContext);
498
499
0
    css::uno::Reference<css::frame::XFrame> xFrame(xDesktop->getActiveFrame());
500
0
    if (!xFrame.is())
501
0
        xFrame = xDesktop;
502
503
0
    mxFrame = std::move(xFrame);
504
505
0
    maCommandURL.Complete = aCommand;
506
0
    css::uno::Reference<css::util::XURLTransformer> xParser
507
0
        = css::util::URLTransformer::create(xContext);
508
0
    xParser->parseStrict(maCommandURL);
509
0
}
510
511
void WidgetStatusListener::startListening()
512
0
{
513
0
    if (mxDispatch.is())
514
0
        mxDispatch->removeStatusListener(this, maCommandURL);
515
516
0
    css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(mxFrame,
517
0
                                                                         css::uno::UNO_QUERY);
518
0
    if (!xDispatchProvider.is())
519
0
        return;
520
521
0
    mxDispatch = xDispatchProvider->queryDispatch(maCommandURL, u""_ustr, 0);
522
0
    if (mxDispatch.is())
523
0
        mxDispatch->addStatusListener(this, maCommandURL);
524
0
}
525
526
void WidgetStatusListener::statusChanged(const css::frame::FeatureStateEvent& rEvent)
527
0
{
528
0
    mWidget->set_sensitive(rEvent.IsEnabled);
529
0
}
530
531
void WidgetStatusListener::disposing(const css::lang::EventObject& /*Source*/)
532
0
{
533
0
    mxDispatch.clear();
534
0
}
535
536
void WidgetStatusListener::dispose()
537
0
{
538
0
    if (mxDispatch.is())
539
0
    {
540
0
        mxDispatch->removeStatusListener(this, maCommandURL);
541
0
        mxDispatch.clear();
542
0
    }
543
0
    mxFrame.clear();
544
0
    mWidget = nullptr;
545
0
}
546
547
ButtonPressRepeater::ButtonPressRepeater(weld::Button& rButton, const Link<Button&, void>& rLink,
548
                                         const Link<const CommandEvent&, void>& rContextLink)
549
0
    : m_rButton(rButton)
550
0
    , m_aRepeat("vcl ButtonPressRepeater m_aRepeat")
551
0
    , m_aLink(rLink)
552
0
    , m_aContextLink(rContextLink)
553
0
    , m_bModKey(false)
554
0
{
555
    // instead of connect_clicked because we want a button held down to
556
    // repeat the next/prev
557
0
    m_rButton.connect_mouse_press(LINK(this, ButtonPressRepeater, MousePressHdl));
558
0
    m_rButton.connect_mouse_release(LINK(this, ButtonPressRepeater, MouseReleaseHdl));
559
560
0
    m_aRepeat.SetInvokeHandler(LINK(this, ButtonPressRepeater, RepeatTimerHdl));
561
0
}
562
563
IMPL_LINK(ButtonPressRepeater, MousePressHdl, const MouseEvent&, rMouseEvent, bool)
564
0
{
565
0
    if (rMouseEvent.IsRight())
566
0
    {
567
0
        m_aContextLink.Call(
568
0
            CommandEvent(rMouseEvent.GetPosPixel(), CommandEventId::ContextMenu, true));
569
0
        return false;
570
0
    }
571
0
    m_bModKey = rMouseEvent.IsMod1();
572
0
    if (!m_rButton.get_sensitive())
573
0
        return false;
574
0
    auto self = weak_from_this();
575
0
    RepeatTimerHdl(nullptr);
576
0
    if (!self.lock())
577
0
        return false;
578
0
    if (!m_rButton.get_sensitive())
579
0
        return false;
580
0
    m_aRepeat.SetTimeout(MouseSettings::GetButtonStartRepeat());
581
0
    m_aRepeat.Start();
582
0
    return true;
583
0
}
584
585
IMPL_LINK_NOARG(ButtonPressRepeater, MouseReleaseHdl, const MouseEvent&, bool)
586
0
{
587
0
    m_bModKey = false;
588
0
    m_aRepeat.Stop();
589
0
    return true;
590
0
}
591
592
IMPL_LINK_NOARG(ButtonPressRepeater, RepeatTimerHdl, Timer*, void)
593
0
{
594
0
    m_aRepeat.SetTimeout(Application::GetSettings().GetMouseSettings().GetButtonRepeat());
595
0
    m_aLink.Call(m_rButton);
596
0
}
597
598
weld::Window* GetPopupParent(vcl::Window& rOutWin, tools::Rectangle& rRect)
599
0
{
600
0
    rRect.SetPos(rOutWin.OutputToScreenPixel(rRect.TopLeft()));
601
0
    AbsoluteScreenPixelRectangle aRectAbs = FloatingWindow::ImplConvertToAbsPos(&rOutWin, rRect);
602
603
0
    vcl::Window* pWin = rOutWin.GetFrameWindow();
604
    // resolve from a possible BorderWindow to the ClientWindow (returns itself if not)
605
0
    pWin = pWin->ImplGetWindow();
606
607
0
    rRect = FloatingWindow::ImplConvertToRelPos(pWin, aRectAbs);
608
0
    rRect.SetPos(pWin->ScreenToOutputPixel(rRect.TopLeft()));
609
610
0
    return rOutWin.GetFrameWeld();
611
0
}
612
613
void SetPointFont(OutputDevice& rDevice, const vcl::Font& rFont, bool bUseDeviceDPI)
614
0
{
615
0
    auto pDefaultDevice = Application::GetDefaultDevice();
616
0
    if (pDefaultDevice)
617
0
        if (vcl::Window* pDefaultWindow = pDefaultDevice->GetOwnerWindow())
618
0
            pDefaultWindow->SetPointFont(rDevice, rFont, bUseDeviceDPI);
619
0
}
620
621
ReorderingDropTarget::ReorderingDropTarget(weld::TreeView& rTreeView)
622
0
    : DropTargetHelper(rTreeView.get_drop_target())
623
0
    , m_rTreeView(rTreeView)
624
0
{
625
0
}
626
627
sal_Int8 ReorderingDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
628
0
{
629
    // to enable the autoscroll when we're close to the edges
630
0
    m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
631
0
    return DND_ACTION_MOVE;
632
0
}
633
634
sal_Int8 ReorderingDropTarget::ExecuteDrop(const ExecuteDropEvent& rEvt)
635
0
{
636
0
    weld::TreeView* pSource = m_rTreeView.get_drag_source();
637
    // only dragging within the same widget allowed
638
0
    if (!pSource || pSource != &m_rTreeView)
639
0
        return DND_ACTION_NONE;
640
641
0
    std::unique_ptr<weld::TreeIter> xSource(m_rTreeView.make_iterator());
642
0
    if (!m_rTreeView.get_selected(xSource.get()))
643
0
        return DND_ACTION_NONE;
644
645
0
    std::unique_ptr<weld::TreeIter> xTarget(m_rTreeView.make_iterator());
646
0
    int nTargetPos = -1;
647
0
    if (m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
648
0
        nTargetPos = m_rTreeView.get_iter_index_in_parent(*xTarget);
649
0
    m_rTreeView.move_subtree(*xSource, nullptr, nTargetPos);
650
651
0
    return DND_ACTION_NONE;
652
0
}
653
}
654
655
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */