nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / app / weldutils.cxx
blob23764507633068c30795ba006ed4a9292c72edcb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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 {}
35 namespace weld
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()
77 if (m_xRelocate)
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)
96 if (bTriStateEnabled)
98 switch (eState)
100 case TRISTATE_INDET:
101 rToggle.set_state(TRISTATE_FALSE);
102 break;
103 case TRISTATE_TRUE:
104 rToggle.set_state(TRISTATE_INDET);
105 break;
106 case TRISTATE_FALSE:
107 rToggle.set_state(TRISTATE_TRUE);
108 break;
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))
120 xNewParent.reset();
122 while (true)
124 std::unique_ptr<weld::TreeIter> xChild(rTreeView.make_iterator(&rParent));
125 if (!rTreeView.iter_children(*xChild))
126 break;
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())
138 Init();
141 EntryFormatter::EntryFormatter(weld::Entry& rEntry)
142 : m_rEntry(rEntry)
143 , m_pSpinButton(nullptr)
144 , m_eOptions(Application::GetSettings().GetStyleSettings().GetSelectionOptions())
146 Init();
149 EntryFormatter::~EntryFormatter()
151 m_rEntry.connect_changed(Link<weld::Entry&, void>());
152 m_rEntry.connect_focus_out(Link<weld::Widget&, void>());
153 if (m_pSpinButton)
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));
161 if (m_pSpinButton)
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);
190 if (m_pSpinButton)
191 m_pSpinButton->sync_value_from_formatter();
194 void EntryFormatter::ClearMinValue()
196 Formatter::ClearMinValue();
197 if (m_pSpinButton)
198 m_pSpinButton->sync_range_from_formatter();
201 void EntryFormatter::SetMinValue(double dMin)
203 Formatter::SetMinValue(dMin);
204 if (m_pSpinButton)
205 m_pSpinButton->sync_range_from_formatter();
208 void EntryFormatter::ClearMaxValue()
210 Formatter::ClearMaxValue();
211 if (m_pSpinButton)
212 m_pSpinButton->sync_range_from_formatter();
215 void EntryFormatter::SetMaxValue(double dMin)
217 Formatter::SetMaxValue(dMin);
218 if (m_pSpinButton)
219 m_pSpinButton->sync_range_from_formatter();
222 void EntryFormatter::SetSpinSize(double dStep)
224 Formatter::SetSpinSize(dStep);
225 if (m_pSpinButton)
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
237 Modify();
240 IMPL_LINK_NOARG(EntryFormatter, FocusOutHdl, weld::Widget&, void)
242 EntryLostFocus();
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 = '.';
281 if (pFormatEntry)
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)
302 Init();
305 LongCurrencyFormatter::LongCurrencyFormatter(weld::FormattedSpinButton& rSpinButton)
306 : EntryFormatter(rSpinButton)
307 , m_bThousandSep(true)
309 Init();
312 void LongCurrencyFormatter::Init()
314 SetOutputHdl(LINK(this, LongCurrencyFormatter, FormatOutputHdl));
315 SetInputHdl(LINK(this, LongCurrencyFormatter, ParseInputHdl));
318 void LongCurrencyFormatter::SetUseThousandSep(bool b)
320 m_bThousandSep = b;
321 ReFormat();
324 void LongCurrencyFormatter::SetCurrencySymbol(const OUString& rStr)
326 m_aCurrencySymbol = rStr;
327 ReFormat();
330 LongCurrencyFormatter::~LongCurrencyFormatter() = default;
332 TimeFormatter::TimeFormatter(weld::Entry& rEntry)
333 : EntryFormatter(rEntry)
334 , m_eFormat(TimeFieldFormat::F_NONE)
335 , m_eTimeFormat(TimeFormat::Hour24)
336 , m_bDuration(false)
338 Init();
341 TimeFormatter::TimeFormatter(weld::FormattedSpinButton& rSpinButton)
342 : EntryFormatter(rSpinButton)
343 , m_eFormat(TimeFieldFormat::F_NONE)
344 , m_eTimeFormat(TimeFormat::Hour24)
345 , m_bDuration(false)
347 Init();
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)
368 switch (eFormat)
370 case ExtTimeFieldFormat::Short24H:
372 m_eTimeFormat = TimeFormat::Hour24;
373 m_bDuration = false;
374 m_eFormat = TimeFieldFormat::F_NONE;
376 break;
377 case ExtTimeFieldFormat::Long24H:
379 m_eTimeFormat = TimeFormat::Hour24;
380 m_bDuration = false;
381 m_eFormat = TimeFieldFormat::F_SEC;
383 break;
384 case ExtTimeFieldFormat::Short12H:
386 m_eTimeFormat = TimeFormat::Hour12;
387 m_bDuration = false;
388 m_eFormat = TimeFieldFormat::F_NONE;
390 break;
391 case ExtTimeFieldFormat::Long12H:
393 m_eTimeFormat = TimeFormat::Hour12;
394 m_bDuration = false;
395 m_eFormat = TimeFieldFormat::F_SEC;
397 break;
398 case ExtTimeFieldFormat::ShortDuration:
400 m_bDuration = true;
401 m_eFormat = TimeFieldFormat::F_NONE;
403 break;
404 case ExtTimeFieldFormat::LongDuration:
406 m_bDuration = true;
407 m_eFormat = TimeFieldFormat::F_SEC;
409 break;
412 ReFormat();
415 void TimeFormatter::SetDuration(bool bDuration)
417 m_bDuration = bDuration;
418 ReFormat();
421 void TimeFormatter::SetTimeFormat(TimeFieldFormat eTimeFormat)
423 m_eFormat = eTimeFormat;
424 ReFormat();
427 TimeFormatter::~TimeFormatter() = default;
429 DateFormatter::DateFormatter(weld::Entry& rEntry)
430 : EntryFormatter(rEntry)
431 , m_eFormat(ExtDateFieldFormat::SystemShort)
433 Init();
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)
447 m_eFormat = eFormat;
448 ReFormat();
451 DateFormatter::~DateFormatter() = default;
453 PatternFormatter::PatternFormatter(weld::Entry& rEntry)
454 : m_rEntry(rEntry)
455 , m_bStrictFormat(false)
456 , m_bSameMask(true)
457 , m_bReformat(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)
470 EntryLostFocus();
471 m_aFocusOutHdl.Call(m_rEntry);
474 IMPL_LINK_NOARG(PatternFormatter, FocusInHdl, weld::Widget&, void)
476 EntryGainFocus();
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)
496 : mWidget(widget)
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());
503 if (!xFrame.is())
504 xFrame = xDesktop;
506 mxFrame = xFrame;
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()
516 if (mxDispatch.is())
517 mxDispatch->removeStatusListener(this, maCommandURL);
519 css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(mxFrame,
520 css::uno::UNO_QUERY);
521 if (!xDispatchProvider.is())
522 return;
524 mxDispatch = xDispatchProvider->queryDispatch(maCommandURL, "", 0);
525 if (mxDispatch.is())
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*/)
536 mxDispatch.clear();
539 void WidgetStatusListener::dispose()
541 if (mxDispatch.is())
543 mxDispatch->removeStatusListener(this, maCommandURL);
544 mxDispatch.clear();
546 mxFrame.clear();
547 mWidget = nullptr;
551 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */