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 <com/sun/star/util/URLTransformer.hpp>
11 #include <com/sun/star/frame/Desktop.hpp>
12 #include <comphelper/processfactory.hxx>
13 #include <svl/zforlist.hxx>
14 #include <svl/zformat.hxx>
15 #include <vcl/builderpage.hxx>
16 #include <vcl/commandinfoprovider.hxx>
17 #include <vcl/settings.hxx>
18 #include <vcl/svapp.hxx>
19 #include <vcl/weldutils.hxx>
21 BuilderPage::BuilderPage(weld::Widget
* pParent
, weld::DialogController
* pController
,
22 const OUString
& rUIXMLDescription
, const OString
& rID
, bool bIsMobile
)
23 : m_pDialogController(pController
)
24 , m_xBuilder(Application::CreateBuilder(pParent
, rUIXMLDescription
, bIsMobile
))
25 , m_xContainer(m_xBuilder
->weld_container(rID
))
29 void BuilderPage::Activate() {}
31 void BuilderPage::Deactivate() {}
33 BuilderPage::~BuilderPage() COVERITY_NOEXCEPT_FALSE
{}
37 bool DialogController::runAsync(const std::shared_ptr
<DialogController
>& rController
,
38 const std::function
<void(sal_Int32
)>& func
)
40 return rController
->getDialog()->runAsync(rController
, func
);
43 DialogController::~DialogController() COVERITY_NOEXCEPT_FALSE
{}
45 Dialog
* GenericDialogController::getDialog() { return m_xDialog
.get(); }
47 GenericDialogController::GenericDialogController(weld::Widget
* pParent
, const OUString
& rUIFile
,
48 const OString
& rDialogId
, bool bMobile
)
49 : m_xBuilder(Application::CreateBuilder(pParent
, rUIFile
, bMobile
))
50 , m_xDialog(m_xBuilder
->weld_dialog(rDialogId
))
54 GenericDialogController::~GenericDialogController() COVERITY_NOEXCEPT_FALSE
{}
56 Dialog
* MessageDialogController::getDialog() { return m_xDialog
.get(); }
58 MessageDialogController::MessageDialogController(weld::Widget
* pParent
, const OUString
& rUIFile
,
59 const OString
& rDialogId
,
60 const OString
& rRelocateId
)
61 : m_xBuilder(Application::CreateBuilder(pParent
, rUIFile
))
62 , m_xDialog(m_xBuilder
->weld_message_dialog(rDialogId
))
63 , m_xContentArea(m_xDialog
->weld_message_area())
65 if (!rRelocateId
.isEmpty())
67 m_xRelocate
= m_xBuilder
->weld_container(rRelocateId
);
68 m_xOrigParent
= m_xRelocate
->weld_parent();
69 //fdo#75121, a bit tricky because the widgets we want to align with
70 //don't actually exist in the ui description, they're implied
71 m_xOrigParent
->move(m_xRelocate
.get(), m_xContentArea
.get());
75 MessageDialogController::~MessageDialogController()
79 m_xContentArea
->move(m_xRelocate
.get(), m_xOrigParent
.get());
83 AssistantController::AssistantController(weld::Widget
* pParent
, const OUString
& rUIFile
,
84 const OString
& rDialogId
)
85 : m_xBuilder(Application::CreateBuilder(pParent
, rUIFile
))
86 , m_xAssistant(m_xBuilder
->weld_assistant(rDialogId
))
90 Dialog
* AssistantController::getDialog() { return m_xAssistant
.get(); }
92 AssistantController::~AssistantController() {}
94 void TriStateEnabled::ButtonToggled(weld::ToggleButton
& rToggle
)
101 rToggle
.set_state(TRISTATE_FALSE
);
104 rToggle
.set_state(TRISTATE_INDET
);
107 rToggle
.set_state(TRISTATE_TRUE
);
111 eState
= rToggle
.get_state();
114 void RemoveParentKeepChildren(weld::TreeView
& rTreeView
, weld::TreeIter
& rParent
)
116 if (rTreeView
.iter_has_child(rParent
))
118 std::unique_ptr
<weld::TreeIter
> xNewParent(rTreeView
.make_iterator(&rParent
));
119 if (!rTreeView
.iter_parent(*xNewParent
))
124 std::unique_ptr
<weld::TreeIter
> xChild(rTreeView
.make_iterator(&rParent
));
125 if (!rTreeView
.iter_children(*xChild
))
127 rTreeView
.move_subtree(*xChild
, xNewParent
.get(), -1);
130 rTreeView
.remove(rParent
);
133 EntryFormatter::EntryFormatter(weld::FormattedSpinButton
& rSpinButton
)
134 : m_rEntry(rSpinButton
)
135 , m_pSpinButton(&rSpinButton
)
136 , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
141 EntryFormatter::EntryFormatter(weld::Entry
& rEntry
)
143 , m_pSpinButton(nullptr)
144 , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
149 EntryFormatter::~EntryFormatter()
151 m_rEntry
.connect_changed(Link
<weld::Entry
&, void>());
152 m_rEntry
.connect_focus_out(Link
<weld::Widget
&, void>());
154 m_pSpinButton
->SetFormatter(nullptr);
157 void EntryFormatter::Init()
159 m_rEntry
.connect_changed(LINK(this, EntryFormatter
, ModifyHdl
));
160 m_rEntry
.connect_focus_out(LINK(this, EntryFormatter
, FocusOutHdl
));
162 m_pSpinButton
->SetFormatter(this);
165 Selection
EntryFormatter::GetEntrySelection() const
167 int nStartPos
, nEndPos
;
168 m_rEntry
.get_selection_bounds(nStartPos
, nEndPos
);
169 return Selection(nStartPos
, nEndPos
);
172 OUString
EntryFormatter::GetEntryText() const { return m_rEntry
.get_text(); }
174 void EntryFormatter::SetEntryText(const OUString
& rText
, const Selection
& rSel
)
176 m_rEntry
.set_text(rText
);
177 auto nMin
= rSel
.Min();
178 auto nMax
= rSel
.Max();
179 m_rEntry
.select_region(nMin
< 0 ? 0 : nMin
, nMax
== SELECTION_MAX
? -1 : nMax
);
182 void EntryFormatter::SetEntryTextColor(const Color
* pColor
)
184 m_rEntry
.set_font_color(pColor
? *pColor
: COL_AUTO
);
187 void EntryFormatter::UpdateCurrentValue(double dCurrentValue
)
189 Formatter::UpdateCurrentValue(dCurrentValue
);
191 m_pSpinButton
->sync_value_from_formatter();
194 void EntryFormatter::ClearMinValue()
196 Formatter::ClearMinValue();
198 m_pSpinButton
->sync_range_from_formatter();
201 void EntryFormatter::SetMinValue(double dMin
)
203 Formatter::SetMinValue(dMin
);
205 m_pSpinButton
->sync_range_from_formatter();
208 void EntryFormatter::ClearMaxValue()
210 Formatter::ClearMaxValue();
212 m_pSpinButton
->sync_range_from_formatter();
215 void EntryFormatter::SetMaxValue(double dMin
)
217 Formatter::SetMaxValue(dMin
);
219 m_pSpinButton
->sync_range_from_formatter();
222 void EntryFormatter::SetSpinSize(double dStep
)
224 Formatter::SetSpinSize(dStep
);
226 m_pSpinButton
->sync_increments_from_formatter();
229 SelectionOptions
EntryFormatter::GetEntrySelectionOptions() const { return m_eOptions
; }
231 void EntryFormatter::FieldModified() { m_aModifyHdl
.Call(m_rEntry
); }
233 IMPL_LINK_NOARG(EntryFormatter
, ModifyHdl
, weld::Entry
&, void)
235 // This leads to FieldModified getting called at the end of Modify() and
236 // FieldModified then calls any modification callback
240 IMPL_LINK_NOARG(EntryFormatter
, FocusOutHdl
, weld::Widget
&, void)
243 m_aFocusOutHdl
.Call(m_rEntry
);
246 DoubleNumericFormatter::DoubleNumericFormatter(weld::Entry
& rEntry
)
247 : EntryFormatter(rEntry
)
249 ResetConformanceTester();
252 DoubleNumericFormatter::DoubleNumericFormatter(weld::FormattedSpinButton
& rSpinButton
)
253 : EntryFormatter(rSpinButton
)
255 ResetConformanceTester();
258 DoubleNumericFormatter::~DoubleNumericFormatter() = default;
260 void DoubleNumericFormatter::FormatChanged(FORMAT_CHANGE_TYPE nWhat
)
262 ResetConformanceTester();
263 EntryFormatter::FormatChanged(nWhat
);
266 bool DoubleNumericFormatter::CheckText(const OUString
& sText
) const
268 // We'd like to implement this using the NumberFormatter::IsNumberFormat, but unfortunately, this doesn't
269 // recognize fragments of numbers (like, for instance "1e", which happens during entering e.g. "1e10")
270 // Thus, the roundabout way via a regular expression
271 return m_pNumberValidator
->isValidNumericFragment(sText
);
274 void DoubleNumericFormatter::ResetConformanceTester()
276 // the thousands and the decimal separator are language dependent
277 const SvNumberformat
* pFormatEntry
= GetOrCreateFormatter()->GetEntry(m_nFormatKey
);
279 sal_Unicode cSeparatorThousand
= ',';
280 sal_Unicode cSeparatorDecimal
= '.';
283 LocaleDataWrapper
aLocaleInfo(LanguageTag(pFormatEntry
->GetLanguage()));
285 OUString sSeparator
= aLocaleInfo
.getNumThousandSep();
286 if (!sSeparator
.isEmpty())
287 cSeparatorThousand
= sSeparator
[0];
289 sSeparator
= aLocaleInfo
.getNumDecimalSep();
290 if (!sSeparator
.isEmpty())
291 cSeparatorDecimal
= sSeparator
[0];
294 m_pNumberValidator
.reset(
295 new validation::NumberValidator(cSeparatorThousand
, cSeparatorDecimal
));
298 LongCurrencyFormatter::LongCurrencyFormatter(weld::Entry
& rEntry
)
299 : EntryFormatter(rEntry
)
300 , m_bThousandSep(true)
305 LongCurrencyFormatter::LongCurrencyFormatter(weld::FormattedSpinButton
& rSpinButton
)
306 : EntryFormatter(rSpinButton
)
307 , m_bThousandSep(true)
312 void LongCurrencyFormatter::Init()
314 SetOutputHdl(LINK(this, LongCurrencyFormatter
, FormatOutputHdl
));
315 SetInputHdl(LINK(this, LongCurrencyFormatter
, ParseInputHdl
));
318 void LongCurrencyFormatter::SetUseThousandSep(bool b
)
324 void LongCurrencyFormatter::SetCurrencySymbol(const OUString
& rStr
)
326 m_aCurrencySymbol
= rStr
;
330 LongCurrencyFormatter::~LongCurrencyFormatter() = default;
332 TimeFormatter::TimeFormatter(weld::Entry
& rEntry
)
333 : EntryFormatter(rEntry
)
334 , m_eFormat(TimeFieldFormat::F_NONE
)
335 , m_eTimeFormat(TimeFormat::Hour24
)
341 TimeFormatter::TimeFormatter(weld::FormattedSpinButton
& rSpinButton
)
342 : EntryFormatter(rSpinButton
)
343 , m_eFormat(TimeFieldFormat::F_NONE
)
344 , m_eTimeFormat(TimeFormat::Hour24
)
350 void TimeFormatter::Init()
352 DisableRemainderFactor(); //so with hh::mm::ss, incrementing mm will not reset ss
354 SetOutputHdl(LINK(this, TimeFormatter
, FormatOutputHdl
));
355 SetInputHdl(LINK(this, TimeFormatter
, ParseInputHdl
));
357 SetMin(tools::Time(0, 0));
358 SetMax(tools::Time(23, 59, 59, 999999999));
360 // so the spin size can depend on which zone the cursor is in
361 get_widget().connect_cursor_position(LINK(this, TimeFormatter
, CursorChangedHdl
));
362 // and set the initial spin size
363 CursorChangedHdl(get_widget());
366 void TimeFormatter::SetExtFormat(ExtTimeFieldFormat eFormat
)
370 case ExtTimeFieldFormat::Short24H
:
372 m_eTimeFormat
= TimeFormat::Hour24
;
374 m_eFormat
= TimeFieldFormat::F_NONE
;
377 case ExtTimeFieldFormat::Long24H
:
379 m_eTimeFormat
= TimeFormat::Hour24
;
381 m_eFormat
= TimeFieldFormat::F_SEC
;
384 case ExtTimeFieldFormat::Short12H
:
386 m_eTimeFormat
= TimeFormat::Hour12
;
388 m_eFormat
= TimeFieldFormat::F_NONE
;
391 case ExtTimeFieldFormat::Long12H
:
393 m_eTimeFormat
= TimeFormat::Hour12
;
395 m_eFormat
= TimeFieldFormat::F_SEC
;
398 case ExtTimeFieldFormat::ShortDuration
:
401 m_eFormat
= TimeFieldFormat::F_NONE
;
404 case ExtTimeFieldFormat::LongDuration
:
407 m_eFormat
= TimeFieldFormat::F_SEC
;
415 void TimeFormatter::SetDuration(bool bDuration
)
417 m_bDuration
= bDuration
;
421 void TimeFormatter::SetTimeFormat(TimeFieldFormat eTimeFormat
)
423 m_eFormat
= eTimeFormat
;
427 TimeFormatter::~TimeFormatter() = default;
429 DateFormatter::DateFormatter(weld::Entry
& rEntry
)
430 : EntryFormatter(rEntry
)
431 , m_eFormat(ExtDateFieldFormat::SystemShort
)
436 void DateFormatter::Init()
438 SetOutputHdl(LINK(this, DateFormatter
, FormatOutputHdl
));
439 SetInputHdl(LINK(this, DateFormatter
, ParseInputHdl
));
441 SetMin(Date(1, 1, 1900));
442 SetMax(Date(31, 12, 2200));
445 void DateFormatter::SetExtDateFormat(ExtDateFieldFormat eFormat
)
451 DateFormatter::~DateFormatter() = default;
453 PatternFormatter::PatternFormatter(weld::Entry
& rEntry
)
455 , m_bStrictFormat(false)
458 , m_bInPattKeyInput(false)
460 m_rEntry
.connect_changed(LINK(this, PatternFormatter
, ModifyHdl
));
461 m_rEntry
.connect_focus_in(LINK(this, PatternFormatter
, FocusInHdl
));
462 m_rEntry
.connect_focus_out(LINK(this, PatternFormatter
, FocusOutHdl
));
463 m_rEntry
.connect_key_press(LINK(this, PatternFormatter
, KeyInputHdl
));
466 IMPL_LINK_NOARG(PatternFormatter
, ModifyHdl
, weld::Entry
&, void) { Modify(); }
468 IMPL_LINK_NOARG(PatternFormatter
, FocusOutHdl
, weld::Widget
&, void)
471 m_aFocusOutHdl
.Call(m_rEntry
);
474 IMPL_LINK_NOARG(PatternFormatter
, FocusInHdl
, weld::Widget
&, void)
477 m_aFocusInHdl
.Call(m_rEntry
);
480 PatternFormatter::~PatternFormatter()
482 m_rEntry
.connect_changed(Link
<weld::Entry
&, void>());
483 m_rEntry
.connect_focus_out(Link
<weld::Widget
&, void>());
486 int GetMinimumEditHeight()
488 // load this little .ui just to measure the height of an Entry
489 std::unique_ptr
<weld::Builder
> xBuilder(
490 Application::CreateBuilder(nullptr, "cui/ui/namedialog.ui"));
491 std::unique_ptr
<weld::Entry
> xEntry(xBuilder
->weld_entry("name_entry"));
492 return xEntry
->get_preferred_size().Height();
495 WidgetStatusListener::WidgetStatusListener(weld::Widget
* widget
, const OUString
& aCommand
)
498 css::uno::Reference
<css::uno::XComponentContext
> xContext
499 = ::comphelper::getProcessComponentContext();
500 css::uno::Reference
<css::frame::XDesktop2
> xDesktop
= css::frame::Desktop::create(xContext
);
502 css::uno::Reference
<css::frame::XFrame
> xFrame(xDesktop
->getActiveFrame());
508 maCommandURL
.Complete
= aCommand
;
509 css::uno::Reference
<css::util::XURLTransformer
> xParser
510 = css::util::URLTransformer::create(xContext
);
511 xParser
->parseStrict(maCommandURL
);
514 void WidgetStatusListener::startListening()
517 mxDispatch
->removeStatusListener(this, maCommandURL
);
519 css::uno::Reference
<css::frame::XDispatchProvider
> xDispatchProvider(mxFrame
,
520 css::uno::UNO_QUERY
);
521 if (!xDispatchProvider
.is())
524 mxDispatch
= xDispatchProvider
->queryDispatch(maCommandURL
, "", 0);
526 mxDispatch
->addStatusListener(this, maCommandURL
);
529 void WidgetStatusListener::statusChanged(const css::frame::FeatureStateEvent
& rEvent
)
531 mWidget
->set_sensitive(rEvent
.IsEnabled
);
534 void WidgetStatusListener::disposing(const css::lang::EventObject
& /*Source*/)
539 void WidgetStatusListener::dispose()
543 mxDispatch
->removeStatusListener(this, maCommandURL
);
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */