tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / framework / source / uielement / spinfieldtoolbarcontroller.cxx
blobd2e4e6d332521fc6acc33fe65b493269a6b09ad2
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <stdio.h>
24 #include <uielement/spinfieldtoolbarcontroller.hxx>
26 #include <com/sun/star/beans/PropertyValue.hpp>
28 #include <comphelper/propertyvalue.hxx>
29 #include <svtools/toolboxcontroller.hxx>
30 #include <vcl/InterimItemWindow.hxx>
31 #include <vcl/event.hxx>
32 #include <vcl/formatter.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vcl/toolbox.hxx>
35 #include <o3tl/char16_t2wchar_t.hxx>
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::uno;
39 using namespace ::com::sun::star::beans;
40 using namespace ::com::sun::star::frame;
42 namespace framework
45 // Wrapper class to notify controller about events from combobox.
46 // Unfortunaltly the events are notified through virtual methods instead
47 // of Listeners.
49 class SpinfieldControl final : public InterimItemWindow
51 public:
52 SpinfieldControl(vcl::Window* pParent, SpinfieldToolbarController* pSpinfieldToolbarController);
53 virtual ~SpinfieldControl() override;
54 virtual void dispose() override;
56 Formatter& GetFormatter()
58 return m_xWidget->GetFormatter();
61 OUString get_entry_text() const { return m_xWidget->get_text(); }
63 DECL_LINK(ValueChangedHdl, weld::FormattedSpinButton&, void);
64 DECL_LINK(FormatOutputHdl, LinkParamNone*, bool);
65 DECL_LINK(ParseInputHdl, sal_Int64*, TriState);
66 DECL_LINK(ModifyHdl, weld::Entry&, void);
67 DECL_LINK(ActivateHdl, weld::Entry&, bool);
68 DECL_LINK(FocusInHdl, weld::Widget&, void);
69 DECL_LINK(FocusOutHdl, weld::Widget&, void);
70 DECL_LINK(KeyInputHdl, const ::KeyEvent&, bool);
72 private:
73 std::unique_ptr<weld::FormattedSpinButton> m_xWidget;
74 SpinfieldToolbarController* m_pSpinfieldToolbarController;
77 SpinfieldControl::SpinfieldControl(vcl::Window* pParent, SpinfieldToolbarController* pSpinfieldToolbarController)
78 : InterimItemWindow(pParent, u"svt/ui/spinfieldcontrol.ui"_ustr, u"SpinFieldControl"_ustr)
79 , m_xWidget(m_xBuilder->weld_formatted_spin_button(u"spinbutton"_ustr))
80 , m_pSpinfieldToolbarController(pSpinfieldToolbarController)
82 InitControlBase(m_xWidget.get());
84 m_xWidget->connect_focus_in(LINK(this, SpinfieldControl, FocusInHdl));
85 m_xWidget->connect_focus_out(LINK(this, SpinfieldControl, FocusOutHdl));
86 Formatter& rFormatter = m_xWidget->GetFormatter();
87 rFormatter.SetOutputHdl(LINK(this, SpinfieldControl, FormatOutputHdl));
88 rFormatter.SetInputHdl(LINK(this, SpinfieldControl, ParseInputHdl));
89 m_xWidget->connect_value_changed(LINK(this, SpinfieldControl, ValueChangedHdl));
90 m_xWidget->connect_changed(LINK(this, SpinfieldControl, ModifyHdl));
91 m_xWidget->connect_activate(LINK(this, SpinfieldControl, ActivateHdl));
92 m_xWidget->connect_key_press(LINK(this, SpinfieldControl, KeyInputHdl));
94 // so a later narrow size request can stick
95 m_xWidget->set_width_chars(3);
96 m_xWidget->set_size_request(42, -1);
98 SetSizePixel(get_preferred_size());
101 IMPL_LINK(SpinfieldControl, KeyInputHdl, const ::KeyEvent&, rKEvt, bool)
103 return ChildKeyInput(rKEvt);
106 IMPL_LINK(SpinfieldControl, ParseInputHdl, sal_Int64*, result, TriState)
108 *result = m_xWidget->get_text().toDouble() * weld::SpinButton::Power10(m_xWidget->GetFormatter().GetDecimalDigits());
109 return TRISTATE_TRUE;
112 SpinfieldControl::~SpinfieldControl()
114 disposeOnce();
117 void SpinfieldControl::dispose()
119 m_pSpinfieldToolbarController = nullptr;
120 m_xWidget.reset();
121 InterimItemWindow::dispose();
124 IMPL_LINK_NOARG(SpinfieldControl, ValueChangedHdl, weld::FormattedSpinButton&, void)
126 if (m_pSpinfieldToolbarController)
127 m_pSpinfieldToolbarController->execute(0);
130 IMPL_LINK_NOARG(SpinfieldControl, ModifyHdl, weld::Entry&, void)
132 if (m_pSpinfieldToolbarController)
133 m_pSpinfieldToolbarController->Modify();
136 IMPL_LINK_NOARG(SpinfieldControl, FocusInHdl, weld::Widget&, void)
138 if (m_pSpinfieldToolbarController)
139 m_pSpinfieldToolbarController->GetFocus();
142 IMPL_LINK_NOARG(SpinfieldControl, FocusOutHdl, weld::Widget&, void)
144 if (m_pSpinfieldToolbarController)
145 m_pSpinfieldToolbarController->LoseFocus();
148 IMPL_LINK_NOARG(SpinfieldControl, ActivateHdl, weld::Entry&, bool)
150 bool bConsumed = false;
151 if (m_pSpinfieldToolbarController)
153 m_pSpinfieldToolbarController->Activate();
154 bConsumed = true;
156 return bConsumed;
159 IMPL_LINK_NOARG(SpinfieldControl, FormatOutputHdl, LinkParamNone*, bool)
161 OUString aText = m_pSpinfieldToolbarController->FormatOutputString(m_xWidget->GetFormatter().GetValue());
162 m_xWidget->set_text(aText);
163 return true;
166 SpinfieldToolbarController::SpinfieldToolbarController(
167 const Reference< XComponentContext >& rxContext,
168 const Reference< XFrame >& rFrame,
169 ToolBox* pToolbar,
170 ToolBoxItemId nID,
171 sal_Int32 nWidth,
172 const OUString& aCommand ) :
173 ComplexToolbarController( rxContext, rFrame, pToolbar, nID, aCommand )
174 , m_bFloat( false )
175 , m_nMax( 0.0 )
176 , m_nMin( 0.0 )
177 , m_nValue( 0.0 )
178 , m_nStep( 0.0 )
179 , m_pSpinfieldControl( nullptr )
181 m_pSpinfieldControl = VclPtr<SpinfieldControl>::Create(m_xToolbar, this);
182 if ( nWidth == 0 )
183 nWidth = 100;
185 // SpinFieldControl ctor has set a suitable height already
186 auto nHeight = m_pSpinfieldControl->GetSizePixel().Height();
188 m_pSpinfieldControl->SetSizePixel( ::Size( nWidth, nHeight ));
189 m_xToolbar->SetItemWindow( m_nID, m_pSpinfieldControl );
192 SpinfieldToolbarController::~SpinfieldToolbarController()
196 void SAL_CALL SpinfieldToolbarController::dispose()
198 SolarMutexGuard aSolarMutexGuard;
200 m_xToolbar->SetItemWindow( m_nID, nullptr );
201 m_pSpinfieldControl.disposeAndClear();
203 ComplexToolbarController::dispose();
206 Sequence<PropertyValue> SpinfieldToolbarController::getExecuteArgs(sal_Int16 KeyModifier) const
208 OUString aSpinfieldText = m_pSpinfieldControl->get_entry_text();
210 // Add key modifier to argument list
211 return {
212 comphelper::makePropertyValue(u"KeyModifier"_ustr, KeyModifier),
213 comphelper::makePropertyValue(u"Value"_ustr, m_bFloat ? Any(aSpinfieldText.toDouble())
214 : Any(aSpinfieldText.toInt32()))
218 void SpinfieldToolbarController::Modify()
220 notifyTextChanged(m_pSpinfieldControl->get_entry_text());
223 void SpinfieldToolbarController::GetFocus()
225 notifyFocusGet();
228 void SpinfieldToolbarController::LoseFocus()
230 notifyFocusLost();
233 void SpinfieldToolbarController::Activate()
235 // Call execute only with non-empty text
236 if (!m_pSpinfieldControl->get_entry_text().isEmpty())
237 execute(0);
240 void SpinfieldToolbarController::executeControlCommand( const css::frame::ControlCommand& rControlCommand )
242 OUString aValue;
243 OUString aMax;
244 OUString aMin;
245 OUString aStep;
246 bool bFloatValue( false );
248 if ( rControlCommand.Command == "SetStep" )
250 for ( auto const & arg : rControlCommand.Arguments )
252 if ( arg.Name == "Step" )
254 sal_Int32 nValue;
255 double fValue;
256 bool bFloat( false );
257 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
258 aStep = bFloat ? OUString::number( fValue ) :
259 OUString( OUString::number( nValue ));
260 break;
264 else if ( rControlCommand.Command == "SetValue" )
266 for ( auto const & arg : rControlCommand.Arguments )
268 if ( arg.Name == "Value" )
270 sal_Int32 nValue;
271 double fValue;
272 bool bFloat( false );
274 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
276 aValue = bFloat ? OUString::number( fValue ) :
277 OUString( OUString::number( nValue ));
278 bFloatValue = bFloat;
280 break;
284 else if ( rControlCommand.Command == "SetValues" )
286 for ( auto const & arg : rControlCommand.Arguments )
288 sal_Int32 nValue;
289 double fValue;
290 bool bFloat( false );
292 OUString aName = arg.Name;
293 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
295 if ( aName == "Value" )
297 aValue = bFloat ? OUString::number( fValue ) :
298 OUString( OUString::number( nValue ));
299 bFloatValue = bFloat;
301 else if ( aName == "Step" )
302 aStep = bFloat ? OUString::number( fValue ) :
303 OUString( OUString::number( nValue ));
304 else if ( aName == "LowerLimit" )
305 aMin = bFloat ? OUString::number( fValue ) :
306 OUString( OUString::number( nValue ));
307 else if ( aName == "UpperLimit" )
308 aMax = bFloat ? OUString::number( fValue ) :
309 OUString( OUString::number( nValue ));
311 else if ( aName == "OutputFormat" )
312 arg.Value >>= m_aOutFormat;
315 else if ( rControlCommand.Command == "SetLowerLimit" )
317 for ( auto const & arg : rControlCommand.Arguments )
319 if ( arg.Name == "LowerLimit" )
321 sal_Int32 nValue;
322 double fValue;
323 bool bFloat( false );
324 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
325 aMin = bFloat ? OUString::number( fValue ) :
326 OUString( OUString::number( nValue ));
327 break;
331 else if ( rControlCommand.Command == "SetUpperLimit" )
333 for ( auto const & arg : rControlCommand.Arguments )
335 if ( arg.Name == "UpperLimit" )
337 sal_Int32 nValue;
338 double fValue;
339 bool bFloat( false );
340 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
341 aMax = bFloat ? OUString::number( fValue ) :
342 OUString( OUString::number( nValue ));
343 break;
347 else if ( rControlCommand.Command == "SetOutputFormat" )
349 for ( auto const & arg : rControlCommand.Arguments )
351 if ( arg.Name == "OutputFormat" )
353 arg.Value >>= m_aOutFormat;
354 break;
359 Formatter& rFormatter = m_pSpinfieldControl->GetFormatter();
361 // Check values and set members
362 if (bFloatValue)
363 rFormatter.SetDecimalDigits(2);
364 if ( !aValue.isEmpty() )
366 m_bFloat = bFloatValue;
367 m_nValue = aValue.toDouble();
368 rFormatter.SetValue(m_nValue);
370 if ( !aMax.isEmpty() )
372 m_nMax = aMax.toDouble();
373 rFormatter.SetMaxValue(m_nMax);
375 if ( !aMin.isEmpty() )
377 m_nMin = aMin.toDouble();
378 rFormatter.SetMinValue(m_nMin);
380 if ( !aStep.isEmpty() )
382 m_nStep = aStep.toDouble();
383 rFormatter.SetSpinSize(m_nStep);
387 // static
388 bool SpinfieldToolbarController::impl_getValue(
389 const Any& rAny, sal_Int32& nValue, double& fValue, bool& bFloat )
391 using ::com::sun::star::uno::TypeClass;
393 bool bValueValid( false );
395 bFloat = false;
396 TypeClass aTypeClass = rAny.getValueTypeClass();
397 if (( aTypeClass == TypeClass( typelib_TypeClass_LONG )) ||
398 ( aTypeClass == TypeClass( typelib_TypeClass_SHORT )) ||
399 ( aTypeClass == TypeClass( typelib_TypeClass_BYTE )))
400 bValueValid = rAny >>= nValue;
401 else if (( aTypeClass == TypeClass( typelib_TypeClass_FLOAT )) ||
402 ( aTypeClass == TypeClass( typelib_TypeClass_DOUBLE )))
404 bValueValid = rAny >>= fValue;
405 bFloat = true;
408 return bValueValid;
411 OUString SpinfieldToolbarController::FormatOutputString( double fValue )
413 if ( m_aOutFormat.isEmpty() )
415 if ( m_bFloat )
416 return OUString::number( fValue );
417 else
418 return OUString::number( sal_Int32( fValue ));
420 else
422 #ifdef _WIN32
423 sal_Unicode aBuffer[128];
425 aBuffer[0] = 0;
426 if ( m_bFloat )
427 _snwprintf( o3tl::toW(aBuffer), SAL_N_ELEMENTS(aBuffer), o3tl::toW(m_aOutFormat.getStr()), fValue );
428 else
429 _snwprintf( o3tl::toW(aBuffer), SAL_N_ELEMENTS(aBuffer), o3tl::toW(m_aOutFormat.getStr()), sal_Int32( fValue ));
431 return OUString(aBuffer);
432 #else
433 // Currently we have no support for a format string using sal_Unicode. wchar_t
434 // is 32 bit on Unix platform!
435 char aBuffer[128];
437 OString aFormat = OUStringToOString( m_aOutFormat, osl_getThreadTextEncoding() );
438 if ( m_bFloat )
439 snprintf( aBuffer, 128, aFormat.getStr(), fValue );
440 else
441 snprintf( aBuffer, 128, aFormat.getStr(), static_cast<tools::Long>( fValue ));
443 sal_Int32 nSize = strlen( aBuffer );
444 std::string_view aTmp( aBuffer, nSize );
445 return OStringToOUString( aTmp, osl_getThreadTextEncoding() );
446 #endif
450 } // namespace
452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */