Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / extensions / source / propctrlr / standardcontrol.cxx
blob6ac10dc4fbe71ae7f28ed8b1b131ac1f36a02e70
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 <rtl/math.hxx>
32 #include <sfx2/objsh.hxx>
35 // ugly dependencies for the OColorControl
36 #include <svx/svxids.hrc>
37 #include <svx/drawitem.hxx>
38 #include <svx/xtable.hxx>
40 #include <vcl/floatwin.hxx>
41 #include <svtools/svmedit.hxx>
42 #include <svtools/colorcfg.hxx>
43 #include <unotools/syslocale.hxx>
44 #include <unotools/datetime.hxx>
45 #include <i18nlangtag/languagetag.hxx>
46 #include <vcl/button.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/settings.hxx>
50 #include <cstdlib>
51 #include <limits>
52 #include <memory>
55 namespace pcr
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star::awt;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::util;
64 using namespace ::com::sun::star::beans;
65 using namespace ::com::sun::star::inspection;
68 //= OTimeControl
71 OTimeControl::OTimeControl( vcl::Window* pParent, WinBits nWinStyle )
72 :OTimeControl_Base( PropertyControlType::TimeField, pParent, nWinStyle )
74 getTypedControlWindow()->SetStrictFormat( true );
75 getTypedControlWindow()->SetFormat( TimeFieldFormat::F_SEC );
76 getTypedControlWindow()->EnableEmptyFieldValue( true );
80 void SAL_CALL OTimeControl::setValue( const Any& _rValue )
82 util::Time aUNOTime;
83 if ( !( _rValue >>= aUNOTime ) )
85 getTypedControlWindow()->SetText( "" );
86 getTypedControlWindow()->SetEmptyTime();
88 else
90 getTypedControlWindow()->SetTime( ::tools::Time(aUNOTime) );
95 Any SAL_CALL OTimeControl::getValue()
97 Any aPropValue;
98 if ( !getTypedControlWindow()->GetText().isEmpty() )
100 aPropValue <<= getTypedControlWindow()->GetTime().GetUNOTime();
102 return aPropValue;
106 Type SAL_CALL OTimeControl::getValueType()
108 return ::cppu::UnoType<util::Time>::get();
112 //= ODateControl
115 ODateControl::ODateControl( vcl::Window* pParent, WinBits nWinStyle )
116 :ODateControl_Base( PropertyControlType::DateField, pParent, nWinStyle | WB_DROPDOWN )
118 CalendarField* pControlWindow = getTypedControlWindow();
119 pControlWindow->SetStrictFormat(true);
121 pControlWindow->SetMin( ::Date( 1,1,1600 ) );
122 pControlWindow->SetFirst( ::Date( 1,1,1600 ) );
123 pControlWindow->SetLast( ::Date( 1, 1, 9999 ) );
124 pControlWindow->SetMax( ::Date( 1, 1, 9999 ) );
126 pControlWindow->SetExtDateFormat( ExtDateFieldFormat::SystemShortYYYY );
127 pControlWindow->EnableEmptyFieldValue( true );
131 void SAL_CALL ODateControl::setValue( const Any& _rValue )
133 util::Date aUNODate;
134 if ( !( _rValue >>= aUNODate ) )
136 getTypedControlWindow()->SetText( "" );
137 getTypedControlWindow()->SetEmptyDate();
139 else
141 ::Date aDate( aUNODate.Day, aUNODate.Month, aUNODate.Year );
142 getTypedControlWindow()->SetDate( aDate );
147 Any SAL_CALL ODateControl::getValue()
149 Any aPropValue;
150 if ( !getTypedControlWindow()->GetText().isEmpty() )
152 ::Date aDate( getTypedControlWindow()->GetDate() );
153 aPropValue <<= aDate.GetUNODate();
155 return aPropValue;
159 Type SAL_CALL ODateControl::getValueType()
161 return ::cppu::UnoType<util::Date>::get();
165 //= OEditControl
168 OEditControl::OEditControl(vcl::Window* _pParent, bool _bPW, WinBits _nWinStyle)
169 :OEditControl_Base( _bPW ? PropertyControlType::CharacterField : PropertyControlType::TextField, _pParent, _nWinStyle )
171 m_bIsPassword = _bPW;
173 if ( m_bIsPassword )
174 getTypedControlWindow()->SetMaxTextLen( 1 );
178 void SAL_CALL OEditControl::setValue( const Any& _rValue )
180 OUString sText;
181 if ( m_bIsPassword )
183 sal_Int16 nValue = 0;
184 _rValue >>= nValue;
185 if ( nValue )
187 sText = OUString(static_cast<sal_Unicode>(nValue));
190 else
191 _rValue >>= sText;
193 getTypedControlWindow()->SetText( sText );
197 Any SAL_CALL OEditControl::getValue()
199 Any aPropValue;
201 OUString sText( getTypedControlWindow()->GetText() );
202 if ( m_bIsPassword )
204 if ( !sText.isEmpty() )
205 aPropValue <<= (sal_Int16)sText[0];
207 else
208 aPropValue <<= sText;
210 return aPropValue;
214 Type SAL_CALL OEditControl::getValueType()
216 return m_bIsPassword ? ::cppu::UnoType<sal_Int16>::get() : ::cppu::UnoType<OUString>::get();
220 void OEditControl::setModified()
222 OEditControl_Base::setModified();
224 // for password controls, we fire a commit for every single change
225 if ( m_bIsPassword )
226 notifyModifiedValue();
230 static long ImplCalcLongValue( double nValue, sal_uInt16 nDigits )
232 double n = nValue;
233 for ( sal_uInt16 d = 0; d < nDigits; ++d )
234 n *= 10;
236 if ( n > std::numeric_limits< long >::max() )
237 return std::numeric_limits< long >::max();
238 return (long)n;
242 static double ImplCalcDoubleValue( long nValue, sal_uInt16 nDigits )
244 double n = nValue;
245 for ( sal_uInt16 d = 0; d < nDigits; ++d )
246 n /= 10;
247 return n;
251 // class ODateTimeControl
254 ODateTimeControl::ODateTimeControl( vcl::Window* _pParent, WinBits _nWinStyle)
255 :ODateTimeControl_Base( PropertyControlType::DateTimeField, _pParent, _nWinStyle )
257 getTypedControlWindow()->EnableEmptyField( true );
259 // determine a default format
260 LanguageType eSysLanguage = SvtSysLocale().GetLanguageTag().getLanguageType( false);
262 getTypedControlWindow()->SetFormatter( getTypedControlWindow()->StandardFormatter() );
263 SvNumberFormatter* pFormatter = getTypedControlWindow()->GetFormatter();
264 sal_uLong nStandardDateTimeFormat = pFormatter->GetStandardFormat( css::util::NumberFormat::DATETIME, eSysLanguage );
266 getTypedControlWindow()->SetFormatKey( nStandardDateTimeFormat );
270 void SAL_CALL ODateTimeControl::setValue( const Any& _rValue )
272 if ( !_rValue.hasValue() )
274 getTypedControlWindow()->SetText( "" );
276 else
278 util::DateTime aUNODateTime;
279 OSL_VERIFY( _rValue >>= aUNODateTime );
281 ::DateTime aDateTime( ::DateTime::EMPTY );
282 ::utl::typeConvert( aUNODateTime, aDateTime );
284 double nValue = aDateTime - ::DateTime( *getTypedControlWindow()->GetFormatter()->GetNullDate() );
285 getTypedControlWindow()->SetValue( nValue );
290 Any SAL_CALL ODateTimeControl::getValue()
292 Any aPropValue;
293 if ( !getTypedControlWindow()->GetText().isEmpty() )
295 double nValue = getTypedControlWindow()->GetValue();
297 ::DateTime aDateTime( *getTypedControlWindow()->GetFormatter()->GetNullDate() );
299 // add the "days" part
300 double nDays = floor( nValue );
301 aDateTime += nDays;
303 // add the "time" part
304 double nTime = nValue - nDays;
305 nTime = ::rtl::math::round( nTime * 86400.0 ) / 86400.0;
306 // we're not interested in 100th seconds, and this here prevents rounding errors
307 aDateTime += nTime;
309 util::DateTime aUNODateTime;
310 ::utl::typeConvert( aDateTime, aUNODateTime );
312 aPropValue <<= aUNODateTime;
314 return aPropValue;
318 Type SAL_CALL ODateTimeControl::getValueType()
320 return ::cppu::UnoType<util::DateTime>::get();
324 //= HyperlinkInput
327 HyperlinkInput::HyperlinkInput( vcl::Window* _pParent, WinBits _nWinStyle )
328 :Edit( _pParent, _nWinStyle )
330 ::svtools::ColorConfig aColorConfig;
331 ::svtools::ColorConfigValue aLinkColor( aColorConfig.GetColorValue( ::svtools::LINKS ) );
333 AllSettings aAllSettings( GetSettings() );
334 StyleSettings aStyleSettings( aAllSettings.GetStyleSettings() );
336 vcl::Font aFieldFont( aStyleSettings.GetFieldFont() );
337 aFieldFont.SetUnderline( LINESTYLE_SINGLE );
338 aFieldFont.SetColor( aLinkColor.nColor );
339 aStyleSettings.SetFieldFont( aFieldFont );
341 aStyleSettings.SetFieldTextColor( aLinkColor.nColor );
343 aAllSettings.SetStyleSettings( aStyleSettings );
344 SetSettings( aAllSettings );
348 void HyperlinkInput::MouseMove( const ::MouseEvent& rMEvt )
350 Edit::MouseMove( rMEvt );
352 PointerStyle ePointerStyle( PointerStyle::Text );
354 if ( !rMEvt.IsLeaveWindow() )
356 if ( impl_textHitTest( rMEvt.GetPosPixel() ) )
357 ePointerStyle = PointerStyle::RefHand;
360 SetPointer( Pointer( ePointerStyle ) );
364 void HyperlinkInput::MouseButtonDown( const ::MouseEvent& rMEvt )
366 Edit::MouseButtonDown( rMEvt );
368 if ( impl_textHitTest( rMEvt.GetPosPixel() ) )
369 m_aMouseButtonDownPos = rMEvt.GetPosPixel();
370 else
371 m_aMouseButtonDownPos.X() = m_aMouseButtonDownPos.Y() = -1;
375 void HyperlinkInput::MouseButtonUp( const ::MouseEvent& rMEvt )
377 Edit::MouseButtonUp( rMEvt );
379 impl_checkEndClick( rMEvt );
383 bool HyperlinkInput::impl_textHitTest( const ::Point& _rWindowPos )
385 sal_Int32 nPos = GetCharPos( _rWindowPos );
386 return ( ( nPos != EDIT_NOLIMIT ) && ( nPos < GetText().getLength() ) );
390 void HyperlinkInput::impl_checkEndClick( const ::MouseEvent& rMEvt )
392 const MouseSettings& rMouseSettings( GetSettings().GetMouseSettings() );
393 if ( ( std::abs( rMEvt.GetPosPixel().X() - m_aMouseButtonDownPos.X() ) < rMouseSettings.GetStartDragWidth() )
394 && ( std::abs( rMEvt.GetPosPixel().Y() - m_aMouseButtonDownPos.Y() ) < rMouseSettings.GetStartDragHeight() )
396 Application::PostUserEvent( m_aClickHandler );
400 void HyperlinkInput::Tracking( const TrackingEvent& rTEvt )
402 Edit::Tracking( rTEvt );
404 if ( rTEvt.IsTrackingEnded() )
405 impl_checkEndClick( rTEvt.GetMouseEvent() );
409 //= OHyperlinkControl
412 OHyperlinkControl::OHyperlinkControl( vcl::Window* _pParent, WinBits _nWinStyle )
413 :OHyperlinkControl_Base( PropertyControlType::HyperlinkField, _pParent, _nWinStyle )
414 ,m_aActionListeners( m_aMutex )
416 getTypedControlWindow()->SetClickHdl( LINK( this, OHyperlinkControl, OnHyperlinkClicked ) );
420 Any SAL_CALL OHyperlinkControl::getValue()
422 OUString sText = getTypedControlWindow()->GetText();
423 return makeAny( sText );
427 void SAL_CALL OHyperlinkControl::setValue( const Any& _value )
429 OUString sText;
430 _value >>= sText;
431 getTypedControlWindow()->SetText( sText );
435 Type SAL_CALL OHyperlinkControl::getValueType()
437 return ::cppu::UnoType<OUString>::get();
441 void SAL_CALL OHyperlinkControl::addActionListener( const Reference< XActionListener >& listener )
443 if ( listener.is() )
444 m_aActionListeners.addInterface( listener );
448 void SAL_CALL OHyperlinkControl::removeActionListener( const Reference< XActionListener >& listener )
450 m_aActionListeners.removeInterface( listener );
454 void SAL_CALL OHyperlinkControl::disposing()
456 OHyperlinkControl_Base::disposing();
458 EventObject aEvent( *this );
459 m_aActionListeners.disposeAndClear( aEvent );
463 IMPL_LINK_NOARG( OHyperlinkControl, OnHyperlinkClicked, void*, void )
465 ActionEvent aEvent( *this, "clicked" );
466 m_aActionListeners.forEach< XActionListener >(
467 [&aEvent] (uno::Reference<awt::XActionListener> const& xListener)
468 { return xListener->actionPerformed(aEvent); });
472 //= ONumericControl
475 ONumericControl::ONumericControl( vcl::Window* _pParent, WinBits _nWinStyle )
476 :ONumericControl_Base( PropertyControlType::NumericField, _pParent, _nWinStyle )
477 ,m_eValueUnit( FUNIT_NONE )
478 ,m_nFieldToUNOValueFactor( 1 )
480 MetricField::SetDefaultUnit( FUNIT_NONE );
482 getTypedControlWindow()->EnableEmptyFieldValue( true );
483 getTypedControlWindow()->SetStrictFormat( true );
484 Optional< double > value( getMaxValue() );
485 value.Value = -value.Value;
486 setMinValue( value );
490 ::sal_Int16 SAL_CALL ONumericControl::getDecimalDigits()
492 return getTypedControlWindow()->GetDecimalDigits();
496 void SAL_CALL ONumericControl::setDecimalDigits( ::sal_Int16 _decimaldigits )
498 getTypedControlWindow()->SetDecimalDigits( _decimaldigits );
502 Optional< double > SAL_CALL ONumericControl::getMinValue()
504 Optional< double > aReturn( true, 0 );
506 sal_Int64 minValue = getTypedControlWindow()->GetMin();
507 if ( minValue == std::numeric_limits< sal_Int64 >::min() )
508 aReturn.IsPresent = false;
509 else
510 aReturn.Value = (double)minValue;
512 return aReturn;
516 void SAL_CALL ONumericControl::setMinValue( const Optional< double >& _minvalue )
518 if ( !_minvalue.IsPresent )
519 getTypedControlWindow()->SetMin( std::numeric_limits< sal_Int64 >::min() );
520 else
521 getTypedControlWindow()->SetMin( impl_apiValueToFieldValue_nothrow( _minvalue.Value ) , m_eValueUnit);
525 Optional< double > SAL_CALL ONumericControl::getMaxValue()
527 Optional< double > aReturn( true, 0 );
529 sal_Int64 maxValue = getTypedControlWindow()->GetMax();
530 if ( maxValue == std::numeric_limits< sal_Int64 >::max() )
531 aReturn.IsPresent = false;
532 else
533 aReturn.Value = (double)maxValue;
535 return aReturn;
539 void SAL_CALL ONumericControl::setMaxValue( const Optional< double >& _maxvalue )
541 if ( !_maxvalue.IsPresent )
542 getTypedControlWindow()->SetMax( std::numeric_limits< sal_Int64 >::max() );
543 else
544 getTypedControlWindow()->SetMax( impl_apiValueToFieldValue_nothrow( _maxvalue.Value ), m_eValueUnit );
548 ::sal_Int16 SAL_CALL ONumericControl::getDisplayUnit()
550 return VCLUnoHelper::ConvertToMeasurementUnit( getTypedControlWindow()->GetUnit(), 1 );
554 void SAL_CALL ONumericControl::setDisplayUnit( ::sal_Int16 _displayunit )
556 if ( ( _displayunit < MeasureUnit::MM_100TH ) || ( _displayunit > MeasureUnit::PERCENT ) )
557 throw IllegalArgumentException();
558 if ( ( _displayunit == MeasureUnit::MM_100TH )
559 || ( _displayunit == MeasureUnit::MM_10TH )
560 || ( _displayunit == MeasureUnit::INCH_1000TH )
561 || ( _displayunit == MeasureUnit::INCH_100TH )
562 || ( _displayunit == MeasureUnit::INCH_10TH )
563 || ( _displayunit == MeasureUnit::PERCENT )
565 throw IllegalArgumentException();
567 sal_Int16 nDummyFactor = 1;
568 FieldUnit eFieldUnit = VCLUnoHelper::ConvertToFieldUnit( _displayunit, nDummyFactor );
569 if ( nDummyFactor != 1 )
570 // everything which survived the checks above should result in a factor of 1, i.e.,
571 // it should have a direct counterpart as FieldUnit
572 throw RuntimeException();
573 getTypedControlWindow()->MetricFormatter::SetUnit( eFieldUnit );
577 ::sal_Int16 SAL_CALL ONumericControl::getValueUnit()
579 return VCLUnoHelper::ConvertToMeasurementUnit( m_eValueUnit, m_nFieldToUNOValueFactor );
583 void SAL_CALL ONumericControl::setValueUnit( ::sal_Int16 _valueunit )
585 if ( ( _valueunit < MeasureUnit::MM_100TH ) || ( _valueunit > MeasureUnit::PERCENT ) )
586 throw IllegalArgumentException();
587 m_eValueUnit = VCLUnoHelper::ConvertToFieldUnit( _valueunit, m_nFieldToUNOValueFactor );
591 void SAL_CALL ONumericControl::setValue( const Any& _rValue )
593 if ( !_rValue.hasValue() )
595 getTypedControlWindow()->SetText( "" );
596 getTypedControlWindow()->SetEmptyFieldValue();
598 else
600 double nValue( 0 );
601 OSL_VERIFY( _rValue >>= nValue );
602 long nControlValue = impl_apiValueToFieldValue_nothrow( nValue );
603 getTypedControlWindow()->SetValue( nControlValue, m_eValueUnit );
608 long ONumericControl::impl_apiValueToFieldValue_nothrow( double _nApiValue ) const
610 long nControlValue = ImplCalcLongValue( _nApiValue, getTypedControlWindow()->GetDecimalDigits() );
611 nControlValue /= m_nFieldToUNOValueFactor;
612 return nControlValue;
616 double ONumericControl::impl_fieldValueToApiValue_nothrow( sal_Int64 _nFieldValue ) const
618 double nApiValue = ImplCalcDoubleValue( (long)_nFieldValue, getTypedControlWindow()->GetDecimalDigits() );
619 nApiValue *= m_nFieldToUNOValueFactor;
620 return nApiValue;
624 Any SAL_CALL ONumericControl::getValue()
626 Any aPropValue;
627 if ( !getTypedControlWindow()->GetText().isEmpty() )
629 double nValue = impl_fieldValueToApiValue_nothrow( getTypedControlWindow()->GetValue( m_eValueUnit ) );
630 aPropValue <<= nValue;
632 return aPropValue;
636 Type SAL_CALL ONumericControl::getValueType()
638 return ::cppu::UnoType<double>::get();
642 //= OColorControl
644 #define LB_DEFAULT_COUNT 20
646 OColorControl::OColorControl(vcl::Window* pParent, WinBits nWinStyle)
647 : OColorControl_Base(PropertyControlType::ColorListBox, pParent, nWinStyle)
649 getTypedControlWindow()->SetSlotId(SID_FM_CTL_PROPERTIES);
652 void SAL_CALL OColorControl::setValue( const Any& _rValue )
654 css::util::Color nColor = COL_TRANSPARENT;
655 if (_rValue.hasValue())
656 _rValue >>= nColor;
657 getTypedControlWindow()->SelectEntry(::Color((ColorData)nColor));
660 Any SAL_CALL OColorControl::getValue()
662 Any aPropValue;
663 ::Color aRgbCol = getTypedControlWindow()->GetSelectEntryColor();
664 if (aRgbCol == COL_TRANSPARENT)
665 return aPropValue;
666 aPropValue <<= (css::util::Color)aRgbCol.GetColor();
667 return aPropValue;
670 Type SAL_CALL OColorControl::getValueType()
672 return ::cppu::UnoType<sal_Int32>::get();
675 void OColorControl::setModified()
677 OColorControl_Base::setModified();
679 // fire a commit
680 notifyModifiedValue();
683 //= OListboxControl
685 OListboxControl::OListboxControl( vcl::Window* pParent, WinBits nWinStyle)
686 :OListboxControl_Base( PropertyControlType::ListBox, pParent, nWinStyle )
688 getTypedControlWindow()->SetDropDownLineCount( LB_DEFAULT_COUNT );
689 if ( ( nWinStyle & WB_READONLY ) != 0 )
691 getTypedControlWindow()->SetReadOnly();
692 getTypedControlWindow()->Enable();
697 Any SAL_CALL OListboxControl::getValue()
699 OUString sControlValue( getTypedControlWindow()->GetSelectEntry() );
701 Any aPropValue;
702 if ( !sControlValue.isEmpty() )
703 aPropValue <<= sControlValue;
704 return aPropValue;
708 Type SAL_CALL OListboxControl::getValueType()
710 return ::cppu::UnoType<OUString>::get();
714 void SAL_CALL OListboxControl::setValue( const Any& _rValue )
716 if ( !_rValue.hasValue() )
717 getTypedControlWindow()->SetNoSelection();
718 else
720 OUString sSelection;
721 _rValue >>= sSelection;
723 if ( !sSelection.equals( getTypedControlWindow()->GetSelectEntry() ) )
724 getTypedControlWindow()->SelectEntry( sSelection );
726 if ( !getTypedControlWindow()->IsEntrySelected( sSelection ) )
728 getTypedControlWindow()->InsertEntry( sSelection, 0 );
729 getTypedControlWindow()->SelectEntry( sSelection );
735 void SAL_CALL OListboxControl::clearList()
737 getTypedControlWindow()->Clear();
741 void SAL_CALL OListboxControl::prependListEntry( const OUString& NewEntry )
743 getTypedControlWindow()->InsertEntry( NewEntry, 0 );
747 void SAL_CALL OListboxControl::appendListEntry( const OUString& NewEntry )
749 getTypedControlWindow()->InsertEntry( NewEntry );
752 Sequence< OUString > SAL_CALL OListboxControl::getListEntries( )
754 const sal_Int32 nCount = getTypedControlWindow()->GetEntryCount();
755 Sequence< OUString > aRet(nCount);
756 OUString* pIter = aRet.getArray();
757 for (sal_Int32 i = 0; i < nCount ; ++i,++pIter)
758 *pIter = getTypedControlWindow()->GetEntry(i);
760 return aRet;
764 void OListboxControl::setModified()
766 OListboxControl_Base::setModified();
768 if ( !getTypedControlWindow()->IsTravelSelect() )
769 // fire a commit
770 notifyModifiedValue();
774 //= OComboboxControl
777 OComboboxControl::OComboboxControl( vcl::Window* pParent, WinBits nWinStyle)
778 :OComboboxControl_Base( PropertyControlType::ComboBox, pParent, nWinStyle )
780 getTypedControlWindow()->SetDropDownLineCount( LB_DEFAULT_COUNT );
781 getTypedControlWindow()->SetSelectHdl( LINK( this, OComboboxControl, OnEntrySelected ) );
785 void SAL_CALL OComboboxControl::setValue( const Any& _rValue )
787 OUString sText;
788 _rValue >>= sText;
789 getTypedControlWindow()->SetText( sText );
793 Any SAL_CALL OComboboxControl::getValue()
795 return makeAny( OUString( getTypedControlWindow()->GetText() ) );
799 Type SAL_CALL OComboboxControl::getValueType()
801 return ::cppu::UnoType<OUString>::get();
805 void SAL_CALL OComboboxControl::clearList()
807 getTypedControlWindow()->Clear();
811 void SAL_CALL OComboboxControl::prependListEntry( const OUString& NewEntry )
813 getTypedControlWindow()->InsertEntry( NewEntry, 0 );
817 void SAL_CALL OComboboxControl::appendListEntry( const OUString& NewEntry )
819 getTypedControlWindow()->InsertEntry( NewEntry );
822 Sequence< OUString > SAL_CALL OComboboxControl::getListEntries( )
824 const sal_Int32 nCount = getTypedControlWindow()->GetEntryCount();
825 Sequence< OUString > aRet(nCount);
826 OUString* pIter = aRet.getArray();
827 for (sal_Int32 i = 0; i < nCount ; ++i,++pIter)
828 *pIter = getTypedControlWindow()->GetEntry(i);
830 return aRet;
834 IMPL_LINK_NOARG( OComboboxControl, OnEntrySelected, ComboBox&, void )
836 if ( !getTypedControlWindow()->IsTravelSelect() )
837 // fire a commit
838 notifyModifiedValue();
842 //= OMultilineFloatingEdit
844 class OMultilineFloatingEdit : public FloatingWindow
846 private:
847 VclPtr<MultiLineEdit> m_aImplEdit;
849 protected:
850 virtual void Resize() override;
852 public:
853 explicit OMultilineFloatingEdit(vcl::Window* _pParen);
854 virtual ~OMultilineFloatingEdit() override;
855 virtual void dispose() override;
856 MultiLineEdit& getEdit() { return *m_aImplEdit.get(); }
858 protected:
859 virtual bool PreNotify(NotifyEvent& _rNEvt) override;
863 OMultilineFloatingEdit::OMultilineFloatingEdit(vcl::Window* _pParent)
864 :FloatingWindow(_pParent, WB_BORDER)
865 ,m_aImplEdit(VclPtr<MultiLineEdit>::Create(this, WB_VSCROLL|WB_IGNORETAB|WB_NOBORDER))
867 m_aImplEdit->Show();
870 OMultilineFloatingEdit::~OMultilineFloatingEdit()
872 disposeOnce();
875 void OMultilineFloatingEdit::dispose()
877 m_aImplEdit.disposeAndClear();
878 FloatingWindow::dispose();
881 void OMultilineFloatingEdit::Resize()
883 m_aImplEdit->SetSizePixel(GetOutputSizePixel());
887 bool OMultilineFloatingEdit::PreNotify(NotifyEvent& _rNEvt)
889 bool bResult = true;
891 MouseNotifyEvent nSwitch = _rNEvt.GetType();
892 if (MouseNotifyEvent::KEYINPUT == nSwitch)
894 const vcl::KeyCode& aKeyCode = _rNEvt.GetKeyEvent()->GetKeyCode();
895 sal_uInt16 nKey = aKeyCode.GetCode();
897 if ( ( (KEY_RETURN == nKey)
898 && !aKeyCode.IsShift()
900 || ( (KEY_UP == nKey)
901 && aKeyCode.IsMod2()
905 EndPopupMode();
907 else
908 bResult=FloatingWindow::PreNotify(_rNEvt);
910 else
911 bResult=FloatingWindow::PreNotify(_rNEvt);
913 return bResult;
917 //= DropDownEditControl_Base
920 DropDownEditControl::DropDownEditControl( vcl::Window* _pParent, WinBits _nStyle )
921 :Edit( _pParent, _nStyle )
922 ,m_pFloatingEdit( nullptr )
923 ,m_pDropdownButton( nullptr )
924 ,m_nOperationMode( eStringList )
925 ,m_bDropdown(false)
926 ,m_pHelper(nullptr)
928 SetCompoundControl( true );
930 m_pImplEdit = VclPtr<MultiLineEdit>::Create( this, WB_TABSTOP | WB_IGNORETAB | WB_NOBORDER | (_nStyle & WB_READONLY) );
931 SetSubEdit( m_pImplEdit );
932 m_pImplEdit->Show();
934 if ( _nStyle & WB_DROPDOWN )
936 m_pDropdownButton = VclPtr<PushButton>::Create( this, WB_NOLIGHTBORDER | WB_RECTSTYLE | WB_NOTABSTOP);
937 m_pDropdownButton->SetSymbol(SymbolType::SPIN_DOWN);
938 m_pDropdownButton->SetClickHdl( LINK( this, DropDownEditControl, DropDownHdl ) );
939 m_pDropdownButton->Show();
942 m_pFloatingEdit = VclPtr<OMultilineFloatingEdit>::Create(this);
944 m_pFloatingEdit->SetPopupModeEndHdl( LINK( this, DropDownEditControl, ReturnHdl ) );
945 m_pFloatingEdit->getEdit().SetReadOnly( ( _nStyle & WB_READONLY ) != 0 );
949 void DropDownEditControl::setControlHelper( CommonBehaviourControlHelper& _rControlHelper )
951 m_pHelper = &_rControlHelper;
952 m_pFloatingEdit->getEdit().SetModifyHdl( LINK( &_rControlHelper, CommonBehaviourControlHelper, EditModifiedHdl ) );
953 m_pImplEdit->SetGetFocusHdl( LINK( &_rControlHelper, CommonBehaviourControlHelper, GetFocusHdl ) );
954 m_pImplEdit->SetModifyHdl( LINK( &_rControlHelper, CommonBehaviourControlHelper, EditModifiedHdl ) );
955 m_pImplEdit->SetLoseFocusHdl( LINK( &_rControlHelper, CommonBehaviourControlHelper, LoseFocusHdl ) );
959 DropDownEditControl::~DropDownEditControl()
961 disposeOnce();
964 void DropDownEditControl::dispose()
966 SetSubEdit(nullptr);
967 m_pImplEdit.disposeAndClear();
968 m_pFloatingEdit.disposeAndClear();
969 m_pDropdownButton.disposeAndClear();
970 Edit::dispose();
974 void DropDownEditControl::Resize()
976 ::Size aOutSz = GetOutputSizePixel();
978 if (m_pDropdownButton!=nullptr)
980 long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
981 nSBWidth = CalcZoom( nSBWidth );
982 m_pImplEdit->setPosSizePixel( 0, 1, aOutSz.Width() - nSBWidth, aOutSz.Height()-2 );
983 m_pDropdownButton->setPosSizePixel( aOutSz.Width() - nSBWidth, 0, nSBWidth, aOutSz.Height() );
985 else
986 m_pImplEdit->setPosSizePixel( 0, 1, aOutSz.Width(), aOutSz.Height()-2 );
990 bool DropDownEditControl::PreNotify( NotifyEvent& rNEvt )
992 bool bResult = true;
994 if (rNEvt.GetType() == MouseNotifyEvent::KEYINPUT)
996 const vcl::KeyCode& aKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
997 sal_uInt16 nKey = aKeyCode.GetCode();
999 if ( nKey == KEY_RETURN && !aKeyCode.IsShift() )
1001 if ( m_pHelper )
1003 m_pHelper->LoseFocusHdl( *m_pImplEdit.get() );
1004 m_pHelper->activateNextControl();
1007 else if ( nKey == KEY_DOWN && aKeyCode.IsMod2() )
1009 Invalidate();
1010 ShowDropDown( true );
1012 else if ( KEYGROUP_CURSOR == aKeyCode.GetGroup()
1013 || nKey == KEY_HELP
1014 || KEYGROUP_FKEYS == aKeyCode.GetGroup()
1015 || m_nOperationMode == eMultiLineText
1018 bResult = Edit::PreNotify( rNEvt );
1020 else if ( m_nOperationMode == eStringList )
1022 Selection aSel = m_pImplEdit->GetSelection();
1023 if ( aSel.Min() != aSel.Max() )
1025 aSel.Min() = FindPos( aSel.Min() );
1026 aSel.Max() = FindPos( aSel.Max() );
1028 else
1030 aSel.Min() = FindPos( aSel.Min() );
1031 aSel.Max() = aSel.Min();
1033 Invalidate();
1034 ShowDropDown( true );
1035 m_pFloatingEdit->getEdit().GrabFocus();
1036 m_pFloatingEdit->getEdit().SetSelection( aSel );
1037 vcl::Window* pFocusWin = Application::GetFocusWindow();
1038 pFocusWin->KeyInput( *rNEvt.GetKeyEvent() );
1041 else
1042 bResult = Edit::PreNotify(rNEvt);
1044 return bResult;
1048 namespace
1051 StlSyntaxSequence< OUString > lcl_convertMultiLineToList( const OUString& _rCompsedTextWithLineBreaks )
1053 sal_Int32 nLines = comphelper::string::getTokenCount(_rCompsedTextWithLineBreaks, '\n');
1054 StlSyntaxSequence< OUString > aStrings( nLines );
1055 StlSyntaxSequence< OUString >::iterator stringItem = aStrings.begin();
1056 for ( sal_Int32 token = 0; token < nLines; ++token, ++stringItem )
1057 *stringItem = _rCompsedTextWithLineBreaks.getToken( token, '\n' );
1058 return aStrings;
1061 OUString lcl_convertListToMultiLine( const StlSyntaxSequence< OUString >& _rStrings )
1063 OUString sMultiLineText;
1064 for ( StlSyntaxSequence< OUString >::const_iterator item = _rStrings.begin();
1065 item != _rStrings.end();
1068 sMultiLineText += *item;
1069 if ( ++item != _rStrings.end() )
1070 sMultiLineText += "\n";
1072 return sMultiLineText;
1076 OUString lcl_convertListToDisplayText( const StlSyntaxSequence< OUString >& _rStrings )
1078 OUStringBuffer aComposed;
1079 for ( StlSyntaxSequence< OUString >::const_iterator strings = _rStrings.begin();
1080 strings != _rStrings.end();
1081 ++strings
1084 if ( strings != _rStrings.begin() )
1085 aComposed.append( ';' );
1086 aComposed.append( '\"' );
1087 aComposed.append( *strings );
1088 aComposed.append( '\"' );
1090 return aComposed.makeStringAndClear();
1095 #define STD_HEIGHT 100
1096 void DropDownEditControl::ShowDropDown( bool bShow )
1098 if (bShow)
1100 ::Point aMePos= GetPosPixel();
1101 aMePos = GetParent()->OutputToScreenPixel( aMePos );
1102 ::Size aSize=GetSizePixel();
1103 ::tools::Rectangle aRect(aMePos,aSize);
1104 aSize.Height() = STD_HEIGHT;
1105 m_pFloatingEdit->SetOutputSizePixel(aSize);
1106 m_pFloatingEdit->StartPopupMode( aRect, FloatWinPopupFlags::Down );
1108 m_pFloatingEdit->Show();
1109 m_pFloatingEdit->getEdit().GrabFocus();
1110 m_pFloatingEdit->getEdit().SetSelection(Selection(m_pFloatingEdit->getEdit().GetText().getLength()));
1111 m_bDropdown = true;
1112 if ( m_nOperationMode == eMultiLineText )
1113 m_pFloatingEdit->getEdit().SetText( m_pImplEdit->GetText() );
1114 m_pImplEdit->SetText("");
1116 else
1118 m_pFloatingEdit->Hide();
1119 m_pFloatingEdit->Invalidate();
1120 m_pFloatingEdit->Update();
1122 // transfer the text from the floating edit to our own edit
1123 OUString sDisplayText( m_pFloatingEdit->getEdit().GetText() );
1124 if ( m_nOperationMode == eStringList )
1125 sDisplayText = lcl_convertListToDisplayText( lcl_convertMultiLineToList( sDisplayText ) );
1127 m_pImplEdit->SetText( sDisplayText );
1128 GetParent()->Invalidate( InvalidateFlags::Children );
1129 m_bDropdown = false;
1130 m_pImplEdit->GrabFocus();
1135 long DropDownEditControl::FindPos(long nSinglePos)
1137 long nPos = 0;
1138 OUString aOutput;
1139 OUString aStr = m_pFloatingEdit->getEdit().GetText();
1140 OUString aStr1 = GetText();
1142 if ((nSinglePos == 0) || (nSinglePos == aStr1.getLength()))
1144 return nSinglePos;
1147 if (!aStr.isEmpty())
1149 long nDiff=0;
1150 sal_Int32 nCount = comphelper::string::getTokenCount(aStr, '\n');
1152 OUString aInput = aStr.getToken(0,'\n' );
1154 if (!aInput.isEmpty())
1156 aOutput += "\"";
1157 nDiff++;
1158 aOutput += aInput;
1159 aOutput += "\"";
1162 if (nSinglePos <= aOutput.getLength())
1164 nPos=nSinglePos-nDiff;
1166 else
1168 for (sal_Int32 i=1; i<nCount; ++i)
1170 aInput=aStr.getToken((sal_uInt16)i, '\n');
1171 if (!aInput.isEmpty())
1173 aOutput += ";";
1174 aOutput += "\"";
1175 nDiff += 2;
1176 aOutput += aInput;
1177 aOutput += "\"";
1179 if (nSinglePos <= aOutput.getLength())
1181 nPos=nSinglePos-nDiff;
1182 break;
1188 return nPos;
1192 IMPL_LINK_NOARG( DropDownEditControl, ReturnHdl, FloatingWindow*, void)
1194 OUString aStr = m_pFloatingEdit->getEdit().GetText();
1195 OUString aStr2 = GetText();
1196 ShowDropDown(false);
1198 if (aStr!=aStr2 || ( m_nOperationMode == eStringList ) )
1200 if ( m_pHelper )
1201 m_pHelper->notifyModifiedValue();
1206 IMPL_LINK_NOARG( DropDownEditControl, DropDownHdl, Button*, void )
1208 ShowDropDown(!m_bDropdown);
1212 void DropDownEditControl::SetStringListValue( const StlSyntaxSequence< OUString >& _rStrings )
1214 SetText( lcl_convertListToDisplayText( _rStrings ) );
1215 m_pFloatingEdit->getEdit().SetText( lcl_convertListToMultiLine( _rStrings ) );
1219 StlSyntaxSequence< OUString > DropDownEditControl::GetStringListValue() const
1221 return lcl_convertMultiLineToList( m_pFloatingEdit->getEdit().GetText() );
1225 void DropDownEditControl::SetTextValue( const OUString& _rText )
1227 OSL_PRECOND( m_nOperationMode == eMultiLineText, "DropDownEditControl::SetTextValue: illegal call!" );
1229 m_pFloatingEdit->getEdit().SetText( _rText );
1230 SetText( _rText );
1234 OUString DropDownEditControl::GetTextValue() const
1236 OSL_PRECOND( m_nOperationMode == eMultiLineText, "DropDownEditControl::GetTextValue: illegal call!" );
1237 return GetText();
1241 //= OMultilineEditControl
1244 OMultilineEditControl::OMultilineEditControl( vcl::Window* pParent, MultiLineOperationMode _eMode, WinBits nWinStyle )
1245 :OMultilineEditControl_Base( _eMode == eMultiLineText ? PropertyControlType::MultiLineTextField : PropertyControlType::StringListField
1246 , pParent
1247 , ( nWinStyle | WB_DIALOGCONTROL ) & ( ~WB_READONLY | ~WB_DROPDOWN )
1248 , false )
1250 getTypedControlWindow()->setOperationMode( _eMode );
1251 getTypedControlWindow()->setControlHelper( *this );
1255 void SAL_CALL OMultilineEditControl::setValue( const Any& _rValue )
1257 impl_checkDisposed_throw();
1259 switch ( getTypedControlWindow()->getOperationMode() )
1261 case eMultiLineText:
1263 OUString sText;
1264 if ( !( _rValue >>= sText ) && _rValue.hasValue() )
1265 throw IllegalTypeException();
1266 getTypedControlWindow()->SetTextValue( sText );
1268 break;
1269 case eStringList:
1271 Sequence< OUString > aStringLines;
1272 if ( !( _rValue >>= aStringLines ) && _rValue.hasValue() )
1273 throw IllegalTypeException();
1274 getTypedControlWindow()->SetStringListValue( StlSyntaxSequence<OUString>(aStringLines) );
1276 break;
1281 Any SAL_CALL OMultilineEditControl::getValue()
1283 impl_checkDisposed_throw();
1285 Any aValue;
1286 switch ( getTypedControlWindow()->getOperationMode() )
1288 case eMultiLineText:
1289 aValue <<= getTypedControlWindow()->GetTextValue();
1290 break;
1291 case eStringList:
1292 aValue <<= getTypedControlWindow()->GetStringListValue();
1293 break;
1295 return aValue;
1299 Type SAL_CALL OMultilineEditControl::getValueType()
1301 if ( getTypedControlWindow()->getOperationMode() == eMultiLineText )
1302 return ::cppu::UnoType<OUString>::get();
1303 return cppu::UnoType<Sequence< OUString >>::get();
1307 } // namespace pcr
1310 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */