LibreOffice Module framework (master) 1
spinfieldtoolbarcontroller.cxx
Go to the documentation of this file.
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 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <stdio.h>
23
25
26#include <com/sun/star/beans/PropertyValue.hpp>
27
31#include <vcl/event.hxx>
32#include <vcl/formatter.hxx>
33#include <vcl/svapp.hxx>
34#include <vcl/toolbox.hxx>
36
37using namespace ::com::sun::star;
38using namespace ::com::sun::star::uno;
39using namespace ::com::sun::star::beans;
40using namespace ::com::sun::star::lang;
41using namespace ::com::sun::star::frame;
42using namespace ::com::sun::star::util;
43
44namespace framework
45{
46
47// Wrapper class to notify controller about events from combobox.
48// Unfortunaltly the events are notified through virtual methods instead
49// of Listeners.
50
52{
53public:
54 SpinfieldControl(vcl::Window* pParent, SpinfieldToolbarController* pSpinfieldToolbarController);
55 virtual ~SpinfieldControl() override;
56 virtual void dispose() override;
57
59 {
60 return m_xWidget->GetFormatter();
61 }
62
63 OUString get_entry_text() const { return m_xWidget->get_text(); }
64
65 DECL_LINK(ValueChangedHdl, weld::FormattedSpinButton&, void);
66 DECL_LINK(FormatOutputHdl, LinkParamNone*, bool);
67 DECL_LINK(ParseInputHdl, sal_Int64*, TriState);
68 DECL_LINK(ModifyHdl, weld::Entry&, void);
69 DECL_LINK(ActivateHdl, weld::Entry&, bool);
70 DECL_LINK(FocusInHdl, weld::Widget&, void);
71 DECL_LINK(FocusOutHdl, weld::Widget&, void);
72 DECL_LINK(KeyInputHdl, const ::KeyEvent&, bool);
73
74private:
75 std::unique_ptr<weld::FormattedSpinButton> m_xWidget;
77};
78
80 : InterimItemWindow(pParent, "svt/ui/spinfieldcontrol.ui", "SpinFieldControl")
81 , m_xWidget(m_xBuilder->weld_formatted_spin_button("spinbutton"))
82 , m_pSpinfieldToolbarController(pSpinfieldToolbarController)
83{
85
86 m_xWidget->connect_focus_in(LINK(this, SpinfieldControl, FocusInHdl));
87 m_xWidget->connect_focus_out(LINK(this, SpinfieldControl, FocusOutHdl));
88 Formatter& rFormatter = m_xWidget->GetFormatter();
89 rFormatter.SetOutputHdl(LINK(this, SpinfieldControl, FormatOutputHdl));
90 rFormatter.SetInputHdl(LINK(this, SpinfieldControl, ParseInputHdl));
91 m_xWidget->connect_value_changed(LINK(this, SpinfieldControl, ValueChangedHdl));
92 m_xWidget->connect_changed(LINK(this, SpinfieldControl, ModifyHdl));
93 m_xWidget->connect_activate(LINK(this, SpinfieldControl, ActivateHdl));
94 m_xWidget->connect_key_press(LINK(this, SpinfieldControl, KeyInputHdl));
95
96 // so a later narrow size request can stick
97 m_xWidget->set_width_chars(3);
98 m_xWidget->set_size_request(42, -1);
99
101}
102
103IMPL_LINK(SpinfieldControl, KeyInputHdl, const ::KeyEvent&, rKEvt, bool)
104{
105 return ChildKeyInput(rKEvt);
106}
107
108IMPL_LINK(SpinfieldControl, ParseInputHdl, sal_Int64*, result, TriState)
109{
110 *result = m_xWidget->get_text().toDouble() * weld::SpinButton::Power10(m_xWidget->GetFormatter().GetDecimalDigits());
111 return TRISTATE_TRUE;
112}
113
115{
116 disposeOnce();
117}
118
120{
122 m_xWidget.reset();
124}
125
127{
128 if (m_pSpinfieldToolbarController)
129 m_pSpinfieldToolbarController->execute(0);
130}
131
133{
134 if (m_pSpinfieldToolbarController)
135 m_pSpinfieldToolbarController->Modify();
136}
137
139{
140 if (m_pSpinfieldToolbarController)
141 m_pSpinfieldToolbarController->GetFocus();
142}
143
145{
146 if (m_pSpinfieldToolbarController)
147 m_pSpinfieldToolbarController->LoseFocus();
148}
149
151{
152 bool bConsumed = false;
153 if (m_pSpinfieldToolbarController)
154 {
155 m_pSpinfieldToolbarController->Activate();
156 bConsumed = true;
157 }
158 return bConsumed;
159}
160
162{
163 OUString aText = m_pSpinfieldToolbarController->FormatOutputString(m_xWidget->GetFormatter().GetValue());
164 m_xWidget->set_text(aText);
165 return true;
166}
167
169 const Reference< XComponentContext >& rxContext,
170 const Reference< XFrame >& rFrame,
171 ToolBox* pToolbar,
172 ToolBoxItemId nID,
173 sal_Int32 nWidth,
174 const OUString& aCommand ) :
175 ComplexToolbarController( rxContext, rFrame, pToolbar, nID, aCommand )
176 , m_bFloat( false )
177 , m_nMax( 0.0 )
178 , m_nMin( 0.0 )
179 , m_nValue( 0.0 )
180 , m_nStep( 0.0 )
181 , m_pSpinfieldControl( nullptr )
182{
184 if ( nWidth == 0 )
185 nWidth = 100;
186
187 // SpinFieldControl ctor has set a suitable height already
188 auto nHeight = m_pSpinfieldControl->GetSizePixel().Height();
189
190 m_pSpinfieldControl->SetSizePixel( ::Size( nWidth, nHeight ));
191 m_xToolbar->SetItemWindow( m_nID, m_pSpinfieldControl );
192}
193
195{
196}
197
199{
200 SolarMutexGuard aSolarMutexGuard;
201
202 m_xToolbar->SetItemWindow( m_nID, nullptr );
203 m_pSpinfieldControl.disposeAndClear();
204
206}
207
208Sequence<PropertyValue> SpinfieldToolbarController::getExecuteArgs(sal_Int16 KeyModifier) const
209{
210 OUString aSpinfieldText = m_pSpinfieldControl->get_entry_text();
211
212 // Add key modifier to argument list
213 auto aArgs0 = comphelper::makePropertyValue("KeyModifier", KeyModifier);
214 auto aArgs1 = comphelper::makePropertyValue("Value", m_bFloat ? Any(aSpinfieldText.toDouble())
215 : Any(aSpinfieldText.toInt32()));
216 return { aArgs0, aArgs1 };
217}
218
220{
221 notifyTextChanged(m_pSpinfieldControl->get_entry_text());
222}
223
225{
227}
228
230{
232}
233
235{
236 // Call execute only with non-empty text
237 if (!m_pSpinfieldControl->get_entry_text().isEmpty())
238 execute(0);
239}
240
241void SpinfieldToolbarController::executeControlCommand( const css::frame::ControlCommand& rControlCommand )
242{
243 OUString aValue;
244 OUString aMax;
245 OUString aMin;
246 OUString aStep;
247 bool bFloatValue( false );
248
249 if ( rControlCommand.Command == "SetStep" )
250 {
251 for ( auto const & arg : rControlCommand.Arguments )
252 {
253 if ( arg.Name == "Step" )
254 {
255 sal_Int32 nValue;
256 double fValue;
257 bool bFloat( false );
258 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
259 aStep = bFloat ? OUString::number( fValue ) :
260 OUString( OUString::number( nValue ));
261 break;
262 }
263 }
264 }
265 else if ( rControlCommand.Command == "SetValue" )
266 {
267 for ( auto const & arg : rControlCommand.Arguments )
268 {
269 if ( arg.Name == "Value" )
270 {
271 sal_Int32 nValue;
272 double fValue;
273 bool bFloat( false );
274
275 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
276 {
277 aValue = bFloat ? OUString::number( fValue ) :
278 OUString( OUString::number( nValue ));
279 bFloatValue = bFloat;
280 }
281 break;
282 }
283 }
284 }
285 else if ( rControlCommand.Command == "SetValues" )
286 {
287 for ( auto const & arg : rControlCommand.Arguments )
288 {
289 sal_Int32 nValue;
290 double fValue;
291 bool bFloat( false );
292
293 OUString aName = arg.Name;
294 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
295 {
296 if ( aName == "Value" )
297 {
298 aValue = bFloat ? OUString::number( fValue ) :
299 OUString( OUString::number( nValue ));
300 bFloatValue = bFloat;
301 }
302 else if ( aName == "Step" )
303 aStep = bFloat ? OUString::number( fValue ) :
304 OUString( OUString::number( nValue ));
305 else if ( aName == "LowerLimit" )
306 aMin = bFloat ? OUString::number( fValue ) :
307 OUString( OUString::number( nValue ));
308 else if ( aName == "UpperLimit" )
309 aMax = bFloat ? OUString::number( fValue ) :
310 OUString( OUString::number( nValue ));
311 }
312 else if ( aName == "OutputFormat" )
313 arg.Value >>= m_aOutFormat;
314 }
315 }
316 else if ( rControlCommand.Command == "SetLowerLimit" )
317 {
318 for ( auto const & arg : rControlCommand.Arguments )
319 {
320 if ( arg.Name == "LowerLimit" )
321 {
322 sal_Int32 nValue;
323 double fValue;
324 bool bFloat( false );
325 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
326 aMin = bFloat ? OUString::number( fValue ) :
327 OUString( OUString::number( nValue ));
328 break;
329 }
330 }
331 }
332 else if ( rControlCommand.Command == "SetUpperLimit" )
333 {
334 for ( auto const & arg : rControlCommand.Arguments )
335 {
336 if ( arg.Name == "UpperLimit" )
337 {
338 sal_Int32 nValue;
339 double fValue;
340 bool bFloat( false );
341 if ( impl_getValue( arg.Value, nValue, fValue, bFloat ))
342 aMax = bFloat ? OUString::number( fValue ) :
343 OUString( OUString::number( nValue ));
344 break;
345 }
346 }
347 }
348 else if ( rControlCommand.Command == "SetOutputFormat" )
349 {
350 for ( auto const & arg : rControlCommand.Arguments )
351 {
352 if ( arg.Name == "OutputFormat" )
353 {
354 arg.Value >>= m_aOutFormat;
355 break;
356 }
357 }
358 }
359
360 Formatter& rFormatter = m_pSpinfieldControl->GetFormatter();
361
362 // Check values and set members
363 if (bFloatValue)
364 rFormatter.SetDecimalDigits(2);
365 if ( !aValue.isEmpty() )
366 {
367 m_bFloat = bFloatValue;
368 m_nValue = aValue.toDouble();
369 rFormatter.SetValue(m_nValue);
370 }
371 if ( !aMax.isEmpty() )
372 {
373 m_nMax = aMax.toDouble();
374 rFormatter.SetMaxValue(m_nMax);
375 }
376 if ( !aMin.isEmpty() )
377 {
378 m_nMin = aMin.toDouble();
379 rFormatter.SetMinValue(m_nMin);
380 }
381 if ( !aStep.isEmpty() )
382 {
383 m_nStep = aStep.toDouble();
384 rFormatter.SetSpinSize(m_nStep);
385 }
386}
387
389 const Any& rAny, sal_Int32& nValue, double& fValue, bool& bFloat )
390{
391 using ::com::sun::star::uno::TypeClass;
392
393 bool bValueValid( false );
394
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 )))
403 {
404 bValueValid = rAny >>= fValue;
405 bFloat = true;
406 }
407
408 return bValueValid;
409}
410
412{
413 if ( m_aOutFormat.isEmpty() )
414 {
415 if ( m_bFloat )
416 return OUString::number( fValue );
417 else
418 return OUString::number( sal_Int32( fValue ));
419 }
420 else
421 {
422#ifdef _WIN32
423 sal_Unicode aBuffer[128];
424
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 ));
430
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];
436
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 ));
442
443 sal_Int32 nSize = strlen( aBuffer );
444 std::string_view aTmp( aBuffer, nSize );
445 return OStringToOUString( aTmp, osl_getThreadTextEncoding() );
446#endif
447 }
448}
449
450} // namespace
451
452/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::unique_ptr< weld::Image > m_xWidget
void SetValue(double dVal)
void SetDecimalDigits(sal_uInt16 _nPrecision)
void SetOutputHdl(const Link< LinkParamNone *, bool > &rLink)
void SetInputHdl(const Link< sal_Int64 *, TriState > &rLink)
virtual void SetMaxValue(double dMax)
virtual void SetMinValue(double dMin)
virtual void SetSpinSize(double dStep)
virtual void dispose() override
void InitControlBase(weld::Widget *pWidget)
static VclPtr< reference_type > Create(Arg &&... arg)
virtual void SAL_CALL dispose() override
virtual void SAL_CALL execute(sal_Int16 KeyModifier) override
DECL_LINK(ModifyHdl, weld::Entry &, void)
DECL_LINK(ParseInputHdl, sal_Int64 *, TriState)
DECL_LINK(FocusInHdl, weld::Widget &, void)
DECL_LINK(ActivateHdl, weld::Entry &, bool)
SpinfieldToolbarController * m_pSpinfieldToolbarController
DECL_LINK(FormatOutputHdl, LinkParamNone *, bool)
DECL_LINK(ValueChangedHdl, weld::FormattedSpinButton &, void)
SpinfieldControl(vcl::Window *pParent, SpinfieldToolbarController *pSpinfieldToolbarController)
DECL_LINK(FocusOutHdl, weld::Widget &, void)
DECL_LINK(KeyInputHdl, const ::KeyEvent &, bool)
std::unique_ptr< weld::FormattedSpinButton > m_xWidget
SpinfieldToolbarController(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Reference< css::frame::XFrame > &rFrame, ToolBox *pToolBar, ToolBoxItemId nID, sal_Int32 nWidth, const OUString &aCommand)
virtual css::uno::Sequence< css::beans::PropertyValue > getExecuteArgs(sal_Int16 KeyModifier) const override
virtual void executeControlCommand(const css::frame::ControlCommand &rControlCommand) override
bool impl_getValue(const css::uno::Any &rAny, sal_Int32 &nValue, double &fValue, bool &bFloat)
virtual void SetSizePixel(const Size &rNewSize)
Size get_preferred_size() const
static unsigned int Power10(unsigned int n)
sal_Int16 nValue
TriState
TRISTATE_TRUE
OUString aName
#define SAL_N_ELEMENTS(arr)
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
IMPL_LINK(WindowCommandDispatch, impl_notifyCommand, VclWindowEvent &, rEvent, void)
IMPL_LINK_NOARG(CloseDispatcher, impl_asyncCallback, LinkParamNone *, void)
asynchronous callback @descr We start all actions inside this object asynchronous (see comments there...
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
long Long
OUString aCommand
sal_uInt16 sal_Unicode
Any result
std::unique_ptr< char[]> aBuffer