Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / extensions / source / propctrlr / standardcontrol.cxx
blob7d79231e1ecd20b6c2e54fd3e6b429deef41e46e
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 "standardcontrol.hxx"
21 #include "pcrcommon.hxx"
23 #include <com/sun/star/beans/IllegalTypeException.hpp>
24 #include <com/sun/star/util/DateTime.hpp>
25 #include <com/sun/star/util/Date.hpp>
26 #include <com/sun/star/util/Time.hpp>
27 #include <com/sun/star/util/Color.hpp>
28 #include <com/sun/star/util/MeasureUnit.hpp>
29 #include <com/sun/star/inspection/PropertyControlType.hpp>
30 #include <comphelper/string.hxx>
31 #include <o3tl/float_int_conversion.hxx>
32 #include <rtl/math.hxx>
33 #include <sfx2/objsh.hxx>
36 // ugly dependencies for the OColorControl
37 #include <svx/svxids.hrc>
38 #include <svx/drawitem.hxx>
39 #include <svx/xtable.hxx>
41 #include <vcl/floatwin.hxx>
42 #include <svtools/svmedit.hxx>
43 #include <svtools/colorcfg.hxx>
44 #include <svl/zforlist.hxx>
45 #include <unotools/syslocale.hxx>
46 #include <unotools/datetime.hxx>
47 #include <i18nlangtag/languagetag.hxx>
48 #include <vcl/button.hxx>
49 #include <vcl/event.hxx>
50 #include <vcl/svapp.hxx>
51 #include <vcl/settings.hxx>
52 #include <vcl/ptrstyle.hxx>
54 #include <cstdlib>
55 #include <limits>
56 #include <memory>
59 namespace pcr
63 using namespace ::com::sun::star;
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::awt;
66 using namespace ::com::sun::star::lang;
67 using namespace ::com::sun::star::util;
68 using namespace ::com::sun::star::beans;
69 using namespace ::com::sun::star::inspection;
72 //= OTimeControl
75 OTimeControl::OTimeControl( vcl::Window* pParent, WinBits nWinStyle )
76 :OTimeControl_Base( PropertyControlType::TimeField, pParent, nWinStyle )
78 getTypedControlWindow()->SetStrictFormat( true );
79 getTypedControlWindow()->SetFormat( TimeFieldFormat::F_SEC );
80 getTypedControlWindow()->EnableEmptyFieldValue( true );
84 void SAL_CALL OTimeControl::setValue( const Any& _rValue )
86 util::Time aUNOTime;
87 if ( !( _rValue >>= aUNOTime ) )
89 getTypedControlWindow()->SetText( "" );
90 getTypedControlWindow()->SetEmptyTime();
92 else
94 getTypedControlWindow()->SetTime( ::tools::Time(aUNOTime) );
99 Any SAL_CALL OTimeControl::getValue()
101 Any aPropValue;
102 if ( !getTypedControlWindow()->GetText().isEmpty() )
104 aPropValue <<= getTypedControlWindow()->GetTime().GetUNOTime();
106 return aPropValue;
110 Type SAL_CALL OTimeControl::getValueType()
112 return ::cppu::UnoType<util::Time>::get();
116 //= ODateControl
119 ODateControl::ODateControl( vcl::Window* pParent, WinBits nWinStyle )
120 :ODateControl_Base( PropertyControlType::DateField, pParent, nWinStyle | WB_DROPDOWN )
122 CalendarField* pControlWindow = getTypedControlWindow();
123 pControlWindow->SetStrictFormat(true);
125 pControlWindow->SetMin( ::Date( 1,1,1600 ) );
126 pControlWindow->SetFirst( ::Date( 1,1,1600 ) );
127 pControlWindow->SetLast( ::Date( 1, 1, 9999 ) );
128 pControlWindow->SetMax( ::Date( 1, 1, 9999 ) );
130 pControlWindow->SetExtDateFormat( ExtDateFieldFormat::SystemShortYYYY );
131 pControlWindow->EnableEmptyFieldValue( true );
135 void SAL_CALL ODateControl::setValue( const Any& _rValue )
137 util::Date aUNODate;
138 if ( !( _rValue >>= aUNODate ) )
140 getTypedControlWindow()->SetText( "" );
141 getTypedControlWindow()->SetEmptyDate();
143 else
145 ::Date aDate( aUNODate.Day, aUNODate.Month, aUNODate.Year );
146 getTypedControlWindow()->SetDate( aDate );
151 Any SAL_CALL ODateControl::getValue()
153 Any aPropValue;
154 if ( !getTypedControlWindow()->GetText().isEmpty() )
156 ::Date aDate( getTypedControlWindow()->GetDate() );
157 aPropValue <<= aDate.GetUNODate();
159 return aPropValue;
163 Type SAL_CALL ODateControl::getValueType()
165 return ::cppu::UnoType<util::Date>::get();
169 //= OEditControl
172 OEditControl::OEditControl(vcl::Window* _pParent, bool _bPW, WinBits _nWinStyle)
173 :OEditControl_Base( _bPW ? PropertyControlType::CharacterField : PropertyControlType::TextField, _pParent, _nWinStyle )
175 m_bIsPassword = _bPW;
177 if ( m_bIsPassword )
178 getTypedControlWindow()->SetMaxTextLen( 1 );
182 void SAL_CALL OEditControl::setValue( const Any& _rValue )
184 OUString sText;
185 if ( m_bIsPassword )
187 sal_Int16 nValue = 0;
188 _rValue >>= nValue;
189 if ( nValue )
191 sText = OUString(static_cast<sal_Unicode>(nValue));
194 else
195 _rValue >>= sText;
197 getTypedControlWindow()->SetText( sText );
201 Any SAL_CALL OEditControl::getValue()
203 Any aPropValue;
205 OUString sText( getTypedControlWindow()->GetText() );
206 if ( m_bIsPassword )
208 if ( !sText.isEmpty() )
209 aPropValue <<= static_cast<sal_Int16>(sText[0]);
211 else
212 aPropValue <<= sText;
214 return aPropValue;
218 Type SAL_CALL OEditControl::getValueType()
220 return m_bIsPassword ? ::cppu::UnoType<sal_Int16>::get() : ::cppu::UnoType<OUString>::get();
224 void OEditControl::setModified()
226 OEditControl_Base::setModified();
228 // for password controls, we fire a commit for every single change
229 if ( m_bIsPassword )
230 notifyModifiedValue();
234 static long ImplCalcLongValue( double nValue, sal_uInt16 nDigits )
236 double n = nValue;
237 for ( sal_uInt16 d = 0; d < nDigits; ++d )
238 n *= 10;
240 if ( !o3tl::convertsToAtMost(n, std::numeric_limits< long >::max()) )
241 return std::numeric_limits< long >::max();
242 return static_cast<long>(n);
246 static double ImplCalcDoubleValue( long nValue, sal_uInt16 nDigits )
248 double n = nValue;
249 for ( sal_uInt16 d = 0; d < nDigits; ++d )
250 n /= 10;
251 return n;
255 // class ODateTimeControl
258 ODateTimeControl::ODateTimeControl( vcl::Window* _pParent, WinBits _nWinStyle)
259 :ODateTimeControl_Base( PropertyControlType::DateTimeField, _pParent, _nWinStyle )
261 getTypedControlWindow()->EnableEmptyField( true );
263 // determine a default format
264 LanguageType eSysLanguage = SvtSysLocale().GetLanguageTag().getLanguageType( false);
266 getTypedControlWindow()->SetFormatter( getTypedControlWindow()->StandardFormatter() );
267 SvNumberFormatter* pFormatter = getTypedControlWindow()->GetFormatter();
268 sal_uLong nStandardDateTimeFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATETIME, eSysLanguage );
270 getTypedControlWindow()->SetFormatKey( nStandardDateTimeFormat );
274 void SAL_CALL ODateTimeControl::setValue( const Any& _rValue )
276 if ( !_rValue.hasValue() )
278 getTypedControlWindow()->SetText( "" );
280 else
282 util::DateTime aUNODateTime;
283 OSL_VERIFY( _rValue >>= aUNODateTime );
285 ::DateTime aDateTime( ::DateTime::EMPTY );
286 ::utl::typeConvert( aUNODateTime, aDateTime );
288 double nValue = aDateTime - ::DateTime( getTypedControlWindow()->GetFormatter()->GetNullDate() );
289 getTypedControlWindow()->SetValue( nValue );
294 Any SAL_CALL ODateTimeControl::getValue()
296 Any aPropValue;
297 if ( !getTypedControlWindow()->GetText().isEmpty() )
299 double nValue = getTypedControlWindow()->GetValue();
301 ::DateTime aDateTime( getTypedControlWindow()->GetFormatter()->GetNullDate() );
303 // add the "days" part
304 double nDays = floor( nValue );
305 aDateTime.AddDays( nDays );
307 // add the "time" part
308 double nTime = nValue - nDays;
309 nTime = ::rtl::math::round( nTime * 86400.0 ) / 86400.0;
310 // we're not interested in 100th seconds, and this here prevents rounding errors
311 aDateTime.AddTime( nTime );
313 util::DateTime aUNODateTime;
314 ::utl::typeConvert( aDateTime, aUNODateTime );
316 aPropValue <<= aUNODateTime;
318 return aPropValue;
322 Type SAL_CALL ODateTimeControl::getValueType()
324 return ::cppu::UnoType<util::DateTime>::get();
328 //= HyperlinkInput
331 HyperlinkInput::HyperlinkInput( vcl::Window* _pParent, WinBits _nWinStyle )
332 :Edit( _pParent, _nWinStyle )
334 ::svtools::ColorConfig aColorConfig;
335 ::svtools::ColorConfigValue aLinkColor( aColorConfig.GetColorValue( ::svtools::LINKS ) );
337 AllSettings aAllSettings( GetSettings() );
338 StyleSettings aStyleSettings( aAllSettings.GetStyleSettings() );
340 vcl::Font aFieldFont( aStyleSettings.GetFieldFont() );
341 aFieldFont.SetUnderline( LINESTYLE_SINGLE );
342 aFieldFont.SetColor( aLinkColor.nColor );
343 aStyleSettings.SetFieldFont( aFieldFont );
345 aStyleSettings.SetFieldTextColor( aLinkColor.nColor );
347 aAllSettings.SetStyleSettings( aStyleSettings );
348 SetSettings( aAllSettings );
352 void HyperlinkInput::MouseMove( const ::MouseEvent& rMEvt )
354 Edit::MouseMove( rMEvt );
356 PointerStyle ePointerStyle( PointerStyle::Text );
358 if ( !rMEvt.IsLeaveWindow() )
360 if ( impl_textHitTest( rMEvt.GetPosPixel() ) )
361 ePointerStyle = PointerStyle::RefHand;
364 SetPointer( ePointerStyle );
368 void HyperlinkInput::MouseButtonDown( const ::MouseEvent& rMEvt )
370 Edit::MouseButtonDown( rMEvt );
372 if ( impl_textHitTest( rMEvt.GetPosPixel() ) )
373 m_aMouseButtonDownPos = rMEvt.GetPosPixel();
374 else
376 m_aMouseButtonDownPos.setX(-1);
377 m_aMouseButtonDownPos.setY(-1);
382 void HyperlinkInput::MouseButtonUp( const ::MouseEvent& rMEvt )
384 Edit::MouseButtonUp( rMEvt );
386 impl_checkEndClick( rMEvt );
390 bool HyperlinkInput::impl_textHitTest( const ::Point& _rWindowPos )
392 sal_Int32 nPos = GetCharPos( _rWindowPos );
393 return ( ( nPos != EDIT_NOLIMIT ) && ( nPos < GetText().getLength() ) );
397 void HyperlinkInput::impl_checkEndClick( const ::MouseEvent& rMEvt )
399 const MouseSettings& rMouseSettings( GetSettings().GetMouseSettings() );
400 if ( ( std::abs( rMEvt.GetPosPixel().X() - m_aMouseButtonDownPos.X() ) < rMouseSettings.GetStartDragWidth() )
401 && ( std::abs( rMEvt.GetPosPixel().Y() - m_aMouseButtonDownPos.Y() ) < rMouseSettings.GetStartDragHeight() )
403 Application::PostUserEvent( m_aClickHandler );
407 void HyperlinkInput::Tracking( const TrackingEvent& rTEvt )
409 Edit::Tracking( rTEvt );
411 if ( rTEvt.IsTrackingEnded() )
412 impl_checkEndClick( rTEvt.GetMouseEvent() );
416 //= OHyperlinkControl
419 OHyperlinkControl::OHyperlinkControl( vcl::Window* _pParent, WinBits _nWinStyle )
420 :OHyperlinkControl_Base( PropertyControlType::HyperlinkField, _pParent, _nWinStyle )
421 ,m_aActionListeners( m_aMutex )
423 getTypedControlWindow()->SetClickHdl( LINK( this, OHyperlinkControl, OnHyperlinkClicked ) );
427 Any SAL_CALL OHyperlinkControl::getValue()
429 OUString sText = getTypedControlWindow()->GetText();
430 return makeAny( sText );
434 void SAL_CALL OHyperlinkControl::setValue( const Any& _value )
436 OUString sText;
437 _value >>= sText;
438 getTypedControlWindow()->SetText( sText );
442 Type SAL_CALL OHyperlinkControl::getValueType()
444 return ::cppu::UnoType<OUString>::get();
448 void SAL_CALL OHyperlinkControl::addActionListener( const Reference< XActionListener >& listener )
450 if ( listener.is() )
451 m_aActionListeners.addInterface( listener );
455 void SAL_CALL OHyperlinkControl::removeActionListener( const Reference< XActionListener >& listener )
457 m_aActionListeners.removeInterface( listener );
461 void SAL_CALL OHyperlinkControl::disposing()
463 OHyperlinkControl_Base::disposing();
465 EventObject aEvent( *this );
466 m_aActionListeners.disposeAndClear( aEvent );
470 IMPL_LINK_NOARG( OHyperlinkControl, OnHyperlinkClicked, void*, void )
472 ActionEvent aEvent( *this, "clicked" );
473 m_aActionListeners.forEach< XActionListener >(
474 [&aEvent] (uno::Reference<awt::XActionListener> const& xListener)
475 { return xListener->actionPerformed(aEvent); });
479 //= ONumericControl
482 ONumericControl::ONumericControl( vcl::Window* _pParent, WinBits _nWinStyle )
483 :ONumericControl_Base( PropertyControlType::NumericField, _pParent, _nWinStyle )
484 ,m_eValueUnit( FieldUnit::NONE )
485 ,m_nFieldToUNOValueFactor( 1 )
487 MetricField::SetDefaultUnit( FieldUnit::NONE );
489 getTypedControlWindow()->EnableEmptyFieldValue( true );
490 getTypedControlWindow()->SetStrictFormat( true );
491 Optional< double > value( getMaxValue() );
492 value.Value = -value.Value;
493 setMinValue( value );
497 ::sal_Int16 SAL_CALL ONumericControl::getDecimalDigits()
499 return getTypedControlWindow()->GetDecimalDigits();
503 void SAL_CALL ONumericControl::setDecimalDigits( ::sal_Int16 _decimaldigits )
505 getTypedControlWindow()->SetDecimalDigits( _decimaldigits );
509 Optional< double > SAL_CALL ONumericControl::getMinValue()
511 Optional< double > aReturn( true, 0 );
513 sal_Int64 minValue = getTypedControlWindow()->GetMin();
514 if ( minValue == std::numeric_limits< sal_Int64 >::min() )
515 aReturn.IsPresent = false;
516 else
517 aReturn.Value = static_cast<double>(minValue);
519 return aReturn;
523 void SAL_CALL ONumericControl::setMinValue( const Optional< double >& _minvalue )
525 if ( !_minvalue.IsPresent )
526 getTypedControlWindow()->SetMin( std::numeric_limits< sal_Int64 >::min() );
527 else
528 getTypedControlWindow()->SetMin( impl_apiValueToFieldValue_nothrow( _minvalue.Value ) , m_eValueUnit);
532 Optional< double > SAL_CALL ONumericControl::getMaxValue()
534 Optional< double > aReturn( true, 0 );
536 sal_Int64 maxValue = getTypedControlWindow()->GetMax();
537 if ( maxValue == std::numeric_limits< sal_Int64 >::max() )
538 aReturn.IsPresent = false;
539 else
540 aReturn.Value = static_cast<double>(maxValue);
542 return aReturn;
546 void SAL_CALL ONumericControl::setMaxValue( const Optional< double >& _maxvalue )
548 if ( !_maxvalue.IsPresent )
549 getTypedControlWindow()->SetMax( std::numeric_limits< sal_Int64 >::max() );
550 else
551 getTypedControlWindow()->SetMax( impl_apiValueToFieldValue_nothrow( _maxvalue.Value ), m_eValueUnit );
555 ::sal_Int16 SAL_CALL ONumericControl::getDisplayUnit()
557 return VCLUnoHelper::ConvertToMeasurementUnit( getTypedControlWindow()->GetUnit(), 1 );
561 void SAL_CALL ONumericControl::setDisplayUnit( ::sal_Int16 _displayunit )
563 if ( ( _displayunit < MeasureUnit::MM_100TH ) || ( _displayunit > MeasureUnit::PERCENT ) )
564 throw IllegalArgumentException();
565 if ( ( _displayunit == MeasureUnit::MM_100TH )
566 || ( _displayunit == MeasureUnit::MM_10TH )
567 || ( _displayunit == MeasureUnit::INCH_1000TH )
568 || ( _displayunit == MeasureUnit::INCH_100TH )
569 || ( _displayunit == MeasureUnit::INCH_10TH )
570 || ( _displayunit == MeasureUnit::PERCENT )
572 throw IllegalArgumentException();
574 sal_Int16 nDummyFactor = 1;
575 FieldUnit eFieldUnit = VCLUnoHelper::ConvertToFieldUnit( _displayunit, nDummyFactor );
576 if ( nDummyFactor != 1 )
577 // everything which survived the checks above should result in a factor of 1, i.e.,
578 // it should have a direct counterpart as FieldUnit
579 throw RuntimeException();
580 getTypedControlWindow()->MetricFormatter::SetUnit( eFieldUnit );
584 ::sal_Int16 SAL_CALL ONumericControl::getValueUnit()
586 return VCLUnoHelper::ConvertToMeasurementUnit( m_eValueUnit, m_nFieldToUNOValueFactor );
590 void SAL_CALL ONumericControl::setValueUnit( ::sal_Int16 _valueunit )
592 if ( ( _valueunit < MeasureUnit::MM_100TH ) || ( _valueunit > MeasureUnit::PERCENT ) )
593 throw IllegalArgumentException();
594 m_eValueUnit = VCLUnoHelper::ConvertToFieldUnit( _valueunit, m_nFieldToUNOValueFactor );
598 void SAL_CALL ONumericControl::setValue( const Any& _rValue )
600 if ( !_rValue.hasValue() )
602 getTypedControlWindow()->SetText( "" );
603 getTypedControlWindow()->SetEmptyFieldValue();
605 else
607 double nValue( 0 );
608 OSL_VERIFY( _rValue >>= nValue );
609 long nControlValue = impl_apiValueToFieldValue_nothrow( nValue );
610 getTypedControlWindow()->SetValue( nControlValue, m_eValueUnit );
615 long ONumericControl::impl_apiValueToFieldValue_nothrow( double _nApiValue ) const
617 long nControlValue = ImplCalcLongValue( _nApiValue, getTypedControlWindow()->GetDecimalDigits() );
618 nControlValue /= m_nFieldToUNOValueFactor;
619 return nControlValue;
623 double ONumericControl::impl_fieldValueToApiValue_nothrow( sal_Int64 _nFieldValue ) const
625 double nApiValue = ImplCalcDoubleValue( static_cast<long>(_nFieldValue), getTypedControlWindow()->GetDecimalDigits() );
626 nApiValue *= m_nFieldToUNOValueFactor;
627 return nApiValue;
631 Any SAL_CALL ONumericControl::getValue()
633 Any aPropValue;
634 if ( !getTypedControlWindow()->GetText().isEmpty() )
636 double nValue = impl_fieldValueToApiValue_nothrow( getTypedControlWindow()->GetValue( m_eValueUnit ) );
637 aPropValue <<= nValue;
639 return aPropValue;
643 Type SAL_CALL ONumericControl::getValueType()
645 return ::cppu::UnoType<double>::get();
649 //= OColorControl
651 #define LB_DEFAULT_COUNT 20
653 OColorControl::OColorControl(vcl::Window* pParent, WinBits nWinStyle)
654 : OColorControl_Base(PropertyControlType::ColorListBox, pParent, nWinStyle)
656 getTypedControlWindow()->SetSlotId(SID_FM_CTL_PROPERTIES);
659 void SAL_CALL OColorControl::setValue( const Any& _rValue )
661 css::util::Color nColor = sal_uInt32(COL_TRANSPARENT);
662 if (_rValue.hasValue())
663 _rValue >>= nColor;
664 getTypedControlWindow()->SelectEntry(nColor);
667 Any SAL_CALL OColorControl::getValue()
669 Any aPropValue;
670 ::Color aRgbCol = getTypedControlWindow()->GetSelectEntryColor();
671 if (aRgbCol == COL_TRANSPARENT)
672 return aPropValue;
673 aPropValue <<= aRgbCol;
674 return aPropValue;
677 Type SAL_CALL OColorControl::getValueType()
679 return ::cppu::UnoType<sal_Int32>::get();
682 void OColorControl::setModified()
684 OColorControl_Base::setModified();
686 // fire a commit
687 notifyModifiedValue();
690 //= OListboxControl
692 OListboxControl::OListboxControl( vcl::Window* pParent, WinBits nWinStyle)
693 :OListboxControl_Base( PropertyControlType::ListBox, pParent, nWinStyle )
695 getTypedControlWindow()->SetDropDownLineCount( LB_DEFAULT_COUNT );
696 if ( ( nWinStyle & WB_READONLY ) != 0 )
698 getTypedControlWindow()->SetReadOnly();
699 getTypedControlWindow()->Enable();
704 Any SAL_CALL OListboxControl::getValue()
706 OUString sControlValue( getTypedControlWindow()->GetSelectedEntry() );
708 Any aPropValue;
709 if ( !sControlValue.isEmpty() )
710 aPropValue <<= sControlValue;
711 return aPropValue;
715 Type SAL_CALL OListboxControl::getValueType()
717 return ::cppu::UnoType<OUString>::get();
721 void SAL_CALL OListboxControl::setValue( const Any& _rValue )
723 if ( !_rValue.hasValue() )
724 getTypedControlWindow()->SetNoSelection();
725 else
727 OUString sSelection;
728 _rValue >>= sSelection;
730 if ( sSelection != getTypedControlWindow()->GetSelectedEntry() )
731 getTypedControlWindow()->SelectEntry( sSelection );
733 if ( !getTypedControlWindow()->IsEntrySelected( sSelection ) )
735 getTypedControlWindow()->InsertEntry( sSelection, 0 );
736 getTypedControlWindow()->SelectEntry( sSelection );
742 void SAL_CALL OListboxControl::clearList()
744 getTypedControlWindow()->Clear();
748 void SAL_CALL OListboxControl::prependListEntry( const OUString& NewEntry )
750 getTypedControlWindow()->InsertEntry( NewEntry, 0 );
754 void SAL_CALL OListboxControl::appendListEntry( const OUString& NewEntry )
756 getTypedControlWindow()->InsertEntry( NewEntry );
759 Sequence< OUString > SAL_CALL OListboxControl::getListEntries( )
761 const sal_Int32 nCount = getTypedControlWindow()->GetEntryCount();
762 Sequence< OUString > aRet(nCount);
763 OUString* pIter = aRet.getArray();
764 for (sal_Int32 i = 0; i < nCount ; ++i,++pIter)
765 *pIter = getTypedControlWindow()->GetEntry(i);
767 return aRet;
771 void OListboxControl::setModified()
773 OListboxControl_Base::setModified();
775 if ( !getTypedControlWindow()->IsTravelSelect() )
776 // fire a commit
777 notifyModifiedValue();
781 //= OComboboxControl
784 OComboboxControl::OComboboxControl( vcl::Window* pParent, WinBits nWinStyle)
785 :OComboboxControl_Base( PropertyControlType::ComboBox, pParent, nWinStyle )
787 getTypedControlWindow()->SetDropDownLineCount( LB_DEFAULT_COUNT );
788 getTypedControlWindow()->SetSelectHdl( LINK( this, OComboboxControl, OnEntrySelected ) );
792 void SAL_CALL OComboboxControl::setValue( const Any& _rValue )
794 OUString sText;
795 _rValue >>= sText;
796 getTypedControlWindow()->SetText( sText );
800 Any SAL_CALL OComboboxControl::getValue()
802 return makeAny( getTypedControlWindow()->GetText() );
806 Type SAL_CALL OComboboxControl::getValueType()
808 return ::cppu::UnoType<OUString>::get();
812 void SAL_CALL OComboboxControl::clearList()
814 getTypedControlWindow()->Clear();
818 void SAL_CALL OComboboxControl::prependListEntry( const OUString& NewEntry )
820 getTypedControlWindow()->InsertEntry( NewEntry, 0 );
824 void SAL_CALL OComboboxControl::appendListEntry( const OUString& NewEntry )
826 getTypedControlWindow()->InsertEntry( NewEntry );
829 Sequence< OUString > SAL_CALL OComboboxControl::getListEntries( )
831 const sal_Int32 nCount = getTypedControlWindow()->GetEntryCount();
832 Sequence< OUString > aRet(nCount);
833 OUString* pIter = aRet.getArray();
834 for (sal_Int32 i = 0; i < nCount ; ++i,++pIter)
835 *pIter = getTypedControlWindow()->GetEntry(i);
837 return aRet;
841 IMPL_LINK_NOARG( OComboboxControl, OnEntrySelected, ComboBox&, void )
843 if ( !getTypedControlWindow()->IsTravelSelect() )
844 // fire a commit
845 notifyModifiedValue();
849 //= OMultilineFloatingEdit
851 class OMultilineFloatingEdit : public FloatingWindow
853 private:
854 VclPtr<MultiLineEdit> m_aImplEdit;
856 protected:
857 virtual void Resize() override;
859 public:
860 explicit OMultilineFloatingEdit(vcl::Window* _pParen);
861 virtual ~OMultilineFloatingEdit() override;
862 virtual void dispose() override;
863 MultiLineEdit& getEdit() { return *m_aImplEdit.get(); }
865 protected:
866 virtual bool PreNotify(NotifyEvent& _rNEvt) override;
870 OMultilineFloatingEdit::OMultilineFloatingEdit(vcl::Window* _pParent)
871 :FloatingWindow(_pParent, WB_BORDER)
872 ,m_aImplEdit(VclPtr<MultiLineEdit>::Create(this, WB_VSCROLL|WB_IGNORETAB|WB_NOBORDER))
874 m_aImplEdit->Show();
877 OMultilineFloatingEdit::~OMultilineFloatingEdit()
879 disposeOnce();
882 void OMultilineFloatingEdit::dispose()
884 m_aImplEdit.disposeAndClear();
885 FloatingWindow::dispose();
888 void OMultilineFloatingEdit::Resize()
890 m_aImplEdit->SetSizePixel(GetOutputSizePixel());
894 bool OMultilineFloatingEdit::PreNotify(NotifyEvent& _rNEvt)
896 bool bResult = true;
898 MouseNotifyEvent nSwitch = _rNEvt.GetType();
899 if (MouseNotifyEvent::KEYINPUT == nSwitch)
901 const vcl::KeyCode& aKeyCode = _rNEvt.GetKeyEvent()->GetKeyCode();
902 sal_uInt16 nKey = aKeyCode.GetCode();
904 if ( ( (KEY_RETURN == nKey)
905 && !aKeyCode.IsShift()
907 || ( (KEY_UP == nKey)
908 && aKeyCode.IsMod2()
912 EndPopupMode();
914 else
915 bResult=FloatingWindow::PreNotify(_rNEvt);
917 else
918 bResult=FloatingWindow::PreNotify(_rNEvt);
920 return bResult;
924 //= DropDownEditControl_Base
927 DropDownEditControl::DropDownEditControl( vcl::Window* _pParent, WinBits _nStyle )
928 :Edit( _pParent, _nStyle )
929 ,m_pFloatingEdit( nullptr )
930 ,m_pDropdownButton( nullptr )
931 ,m_nOperationMode( eStringList )
932 ,m_bDropdown(false)
933 ,m_pHelper(nullptr)
935 SetCompoundControl( true );
937 m_pImplEdit = VclPtr<MultiLineEdit>::Create( this, WB_TABSTOP | WB_IGNORETAB | WB_NOBORDER | (_nStyle & WB_READONLY) );
938 SetSubEdit( m_pImplEdit );
939 m_pImplEdit->Show();
941 if ( _nStyle & WB_DROPDOWN )
943 m_pDropdownButton = VclPtr<PushButton>::Create( this, WB_NOLIGHTBORDER | WB_RECTSTYLE | WB_NOTABSTOP);
944 m_pDropdownButton->SetSymbol(SymbolType::SPIN_DOWN);
945 m_pDropdownButton->SetClickHdl( LINK( this, DropDownEditControl, DropDownHdl ) );
946 m_pDropdownButton->Show();
949 m_pFloatingEdit = VclPtr<OMultilineFloatingEdit>::Create(this);
951 m_pFloatingEdit->SetPopupModeEndHdl( LINK( this, DropDownEditControl, ReturnHdl ) );
952 m_pFloatingEdit->getEdit().SetReadOnly( ( _nStyle & WB_READONLY ) != 0 );
956 void DropDownEditControl::setControlHelper( CommonBehaviourControlHelper& _rControlHelper )
958 m_pHelper = &_rControlHelper;
959 m_pFloatingEdit->getEdit().SetModifyHdl( LINK( &_rControlHelper, CommonBehaviourControlHelper, EditModifiedHdl ) );
960 m_pImplEdit->SetGetFocusHdl( LINK( &_rControlHelper, CommonBehaviourControlHelper, GetFocusHdl ) );
961 m_pImplEdit->SetModifyHdl( LINK( &_rControlHelper, CommonBehaviourControlHelper, EditModifiedHdl ) );
962 m_pImplEdit->SetLoseFocusHdl( LINK( &_rControlHelper, CommonBehaviourControlHelper, LoseFocusHdl ) );
966 DropDownEditControl::~DropDownEditControl()
968 disposeOnce();
971 void DropDownEditControl::dispose()
973 SetSubEdit(nullptr);
974 m_pImplEdit.disposeAndClear();
975 m_pFloatingEdit.disposeAndClear();
976 m_pDropdownButton.disposeAndClear();
977 Edit::dispose();
981 void DropDownEditControl::Resize()
983 ::Size aOutSz = GetOutputSizePixel();
985 if (m_pDropdownButton!=nullptr)
987 long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
988 nSBWidth = CalcZoom( nSBWidth );
989 m_pImplEdit->setPosSizePixel( 0, 1, aOutSz.Width() - nSBWidth, aOutSz.Height()-2 );
990 m_pDropdownButton->setPosSizePixel( aOutSz.Width() - nSBWidth, 0, nSBWidth, aOutSz.Height() );
992 else
993 m_pImplEdit->setPosSizePixel( 0, 1, aOutSz.Width(), aOutSz.Height()-2 );
997 bool DropDownEditControl::PreNotify( NotifyEvent& rNEvt )
999 bool bResult = true;
1001 if (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
1003 const vcl::KeyCode& aKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
1004 sal_uInt16 nKey = aKeyCode.GetCode();
1006 if ( nKey == KEY_RETURN && !aKeyCode.IsShift() )
1008 if ( m_pHelper )
1010 m_pHelper->LoseFocusHdl( *m_pImplEdit.get() );
1011 m_pHelper->activateNextControl();
1014 else if ( nKey == KEY_DOWN && aKeyCode.IsMod2() )
1016 Invalidate();
1017 ShowDropDown( true );
1019 else if ( KEYGROUP_CURSOR == aKeyCode.GetGroup()
1020 || nKey == KEY_HELP
1021 || KEYGROUP_FKEYS == aKeyCode.GetGroup()
1022 || m_nOperationMode == eMultiLineText
1025 bResult = Edit::PreNotify( rNEvt );
1027 else if ( m_nOperationMode == eStringList )
1029 Selection aSel = m_pImplEdit->GetSelection();
1030 if ( aSel.Min() != aSel.Max() )
1032 aSel.Min() = FindPos( aSel.Min() );
1033 aSel.Max() = FindPos( aSel.Max() );
1035 else
1037 aSel.Min() = FindPos( aSel.Min() );
1038 aSel.Max() = aSel.Min();
1040 Invalidate();
1041 ShowDropDown( true );
1042 m_pFloatingEdit->getEdit().GrabFocus();
1043 m_pFloatingEdit->getEdit().SetSelection( aSel );
1044 vcl::Window* pFocusWin = Application::GetFocusWindow();
1045 pFocusWin->KeyInput( *rNEvt.GetKeyEvent() );
1048 else
1049 bResult = Edit::PreNotify(rNEvt);
1051 return bResult;
1055 namespace
1058 StlSyntaxSequence< OUString > lcl_convertMultiLineToList( const OUString& _rCompsedTextWithLineBreaks )
1060 sal_Int32 nLines = comphelper::string::getTokenCount(_rCompsedTextWithLineBreaks, '\n');
1061 StlSyntaxSequence< OUString > aStrings( nLines );
1062 if (nLines)
1064 StlSyntaxSequence< OUString >::iterator stringItem = aStrings.begin();
1065 sal_Int32 nIdx {0};
1068 *stringItem = _rCompsedTextWithLineBreaks.getToken( 0, '\n', nIdx );
1069 ++stringItem;
1071 while (nIdx>0);
1073 return aStrings;
1076 OUString lcl_convertListToMultiLine( const StlSyntaxSequence< OUString >& _rStrings )
1078 OUStringBuffer sMultiLineText;
1079 for ( StlSyntaxSequence< OUString >::const_iterator item = _rStrings.begin();
1080 item != _rStrings.end();
1083 sMultiLineText.append(*item);
1084 if ( ++item != _rStrings.end() )
1085 sMultiLineText.append("\n");
1087 return sMultiLineText.makeStringAndClear();
1091 OUString lcl_convertListToDisplayText( const StlSyntaxSequence< OUString >& _rStrings )
1093 OUStringBuffer aComposed;
1094 for ( StlSyntaxSequence< OUString >::const_iterator strings = _rStrings.begin();
1095 strings != _rStrings.end();
1096 ++strings
1099 if ( strings != _rStrings.begin() )
1100 aComposed.append( ';' );
1101 aComposed.append( '\"' );
1102 aComposed.append( *strings );
1103 aComposed.append( '\"' );
1105 return aComposed.makeStringAndClear();
1110 #define STD_HEIGHT 100
1111 void DropDownEditControl::ShowDropDown( bool bShow )
1113 if (bShow)
1115 ::Point aMePos= GetPosPixel();
1116 aMePos = GetParent()->OutputToScreenPixel( aMePos );
1117 ::Size aSize=GetSizePixel();
1118 ::tools::Rectangle aRect(aMePos,aSize);
1119 aSize.setHeight( STD_HEIGHT );
1120 m_pFloatingEdit->SetOutputSizePixel(aSize);
1121 m_pFloatingEdit->StartPopupMode( aRect, FloatWinPopupFlags::Down );
1123 m_pFloatingEdit->Show();
1124 m_pFloatingEdit->getEdit().GrabFocus();
1125 m_pFloatingEdit->getEdit().SetSelection(Selection(m_pFloatingEdit->getEdit().GetText().getLength()));
1126 m_bDropdown = true;
1127 if ( m_nOperationMode == eMultiLineText )
1128 m_pFloatingEdit->getEdit().SetText( m_pImplEdit->GetText() );
1129 m_pImplEdit->SetText("");
1131 else
1133 m_pFloatingEdit->Hide();
1134 m_pFloatingEdit->Invalidate();
1135 m_pFloatingEdit->Update();
1137 // transfer the text from the floating edit to our own edit
1138 OUString sDisplayText( m_pFloatingEdit->getEdit().GetText() );
1139 if ( m_nOperationMode == eStringList )
1140 sDisplayText = lcl_convertListToDisplayText( lcl_convertMultiLineToList( sDisplayText ) );
1142 m_pImplEdit->SetText( sDisplayText );
1143 GetParent()->Invalidate( InvalidateFlags::Children );
1144 m_bDropdown = false;
1145 m_pImplEdit->GrabFocus();
1150 long DropDownEditControl::FindPos(long nSinglePos)
1152 long nPos = 0;
1153 OUString aOutput;
1154 OUString aStr = m_pFloatingEdit->getEdit().GetText();
1155 OUString aStr1 = GetText();
1157 if ((nSinglePos == 0) || (nSinglePos == aStr1.getLength()))
1159 return nSinglePos;
1162 if (!aStr.isEmpty())
1164 long nDiff=0;
1166 sal_Int32 nIdx {0};
1167 OUString aInput = aStr.getToken(0, '\n', nIdx );
1169 if (!aInput.isEmpty())
1171 aOutput += "\"" + aInput + "\"";
1172 nDiff++;
1175 if (nSinglePos <= aOutput.getLength())
1177 nPos=nSinglePos-nDiff;
1179 else
1181 while (nIdx>0)
1183 aInput=aStr.getToken(0, '\n', nIdx);
1184 if (!aInput.isEmpty())
1186 aOutput += ";\"" + aInput + "\"";
1187 nDiff += 2;
1189 if (nSinglePos <= aOutput.getLength())
1191 nPos=nSinglePos-nDiff;
1192 break;
1198 return nPos;
1202 IMPL_LINK_NOARG( DropDownEditControl, ReturnHdl, FloatingWindow*, void)
1204 OUString aStr = m_pFloatingEdit->getEdit().GetText();
1205 OUString aStr2 = GetText();
1206 ShowDropDown(false);
1208 if (aStr!=aStr2 || ( m_nOperationMode == eStringList ) )
1210 if ( m_pHelper )
1211 m_pHelper->notifyModifiedValue();
1216 IMPL_LINK_NOARG( DropDownEditControl, DropDownHdl, Button*, void )
1218 ShowDropDown(!m_bDropdown);
1222 void DropDownEditControl::SetStringListValue( const StlSyntaxSequence< OUString >& _rStrings )
1224 SetText( lcl_convertListToDisplayText( _rStrings ) );
1225 m_pFloatingEdit->getEdit().SetText( lcl_convertListToMultiLine( _rStrings ) );
1229 StlSyntaxSequence< OUString > DropDownEditControl::GetStringListValue() const
1231 return lcl_convertMultiLineToList( m_pFloatingEdit->getEdit().GetText() );
1235 void DropDownEditControl::SetTextValue( const OUString& _rText )
1237 OSL_PRECOND( m_nOperationMode == eMultiLineText, "DropDownEditControl::SetTextValue: illegal call!" );
1239 m_pFloatingEdit->getEdit().SetText( _rText );
1240 SetText( _rText );
1244 OUString DropDownEditControl::GetTextValue() const
1246 OSL_PRECOND( m_nOperationMode == eMultiLineText, "DropDownEditControl::GetTextValue: illegal call!" );
1247 return GetText();
1251 //= OMultilineEditControl
1254 OMultilineEditControl::OMultilineEditControl( vcl::Window* pParent, MultiLineOperationMode _eMode, WinBits nWinStyle )
1255 :OMultilineEditControl_Base( _eMode == eMultiLineText ? PropertyControlType::MultiLineTextField : PropertyControlType::StringListField
1256 , pParent
1257 , ( nWinStyle | WB_DIALOGCONTROL ) & ( ~WB_READONLY | ~WB_DROPDOWN )
1258 , false )
1260 getTypedControlWindow()->setOperationMode( _eMode );
1261 getTypedControlWindow()->setControlHelper( *this );
1265 void SAL_CALL OMultilineEditControl::setValue( const Any& _rValue )
1267 impl_checkDisposed_throw();
1269 switch ( getTypedControlWindow()->getOperationMode() )
1271 case eMultiLineText:
1273 OUString sText;
1274 if ( !( _rValue >>= sText ) && _rValue.hasValue() )
1275 throw IllegalTypeException();
1276 getTypedControlWindow()->SetTextValue( sText );
1278 break;
1279 case eStringList:
1281 Sequence< OUString > aStringLines;
1282 if ( !( _rValue >>= aStringLines ) && _rValue.hasValue() )
1283 throw IllegalTypeException();
1284 getTypedControlWindow()->SetStringListValue( StlSyntaxSequence<OUString>(aStringLines) );
1286 break;
1291 Any SAL_CALL OMultilineEditControl::getValue()
1293 impl_checkDisposed_throw();
1295 Any aValue;
1296 switch ( getTypedControlWindow()->getOperationMode() )
1298 case eMultiLineText:
1299 aValue <<= getTypedControlWindow()->GetTextValue();
1300 break;
1301 case eStringList:
1302 aValue <<= getTypedControlWindow()->GetStringListValue();
1303 break;
1305 return aValue;
1309 Type SAL_CALL OMultilineEditControl::getValueType()
1311 if ( getTypedControlWindow()->getOperationMode() == eMultiLineText )
1312 return ::cppu::UnoType<OUString>::get();
1313 return cppu::UnoType<Sequence< OUString >>::get();
1317 } // namespace pcr
1320 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */