diff options
46 files changed, 2356 insertions, 942 deletions
diff --git a/comphelper/source/misc/anycompare.cxx b/comphelper/source/misc/anycompare.cxx index a86174daf08e..d01363e6656a 100755..100644 --- a/comphelper/source/misc/anycompare.cxx +++ b/comphelper/source/misc/anycompare.cxx @@ -29,6 +29,9 @@ #include "comphelper/anycompare.hxx" /** === begin UNO includes === **/ +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/DateTime.hpp> /** === end UNO includes === **/ //...................................................................................................................... @@ -63,9 +66,128 @@ namespace comphelper using ::com::sun::star::uno::TypeClass_TYPE; using ::com::sun::star::uno::TypeClass_ENUM; using ::com::sun::star::uno::TypeClass_INTERFACE; + using ::com::sun::star::uno::TypeClass_STRUCT; using ::com::sun::star::i18n::XCollator; + using ::com::sun::star::util::Date; + using ::com::sun::star::util::Time; + using ::com::sun::star::util::DateTime; /** === end UNO using === **/ + //================================================================================================================== + //= DatePredicateLess + //================================================================================================================== + class DatePredicateLess : public IKeyPredicateLess + { + public: + virtual bool isLess( ::com::sun::star::uno::Any const & _lhs, ::com::sun::star::uno::Any const & _rhs ) const + { + Date lhs, rhs; + if ( !( _lhs >>= lhs ) + || !( _rhs >>= rhs ) + ) + throw ::com::sun::star::lang::IllegalArgumentException(); + + if ( lhs.Year < rhs.Year ) + return true; + if ( lhs.Year > rhs.Year ) + return false; + + if ( lhs.Month < rhs.Month ) + return true; + if ( lhs.Month > rhs.Month ) + return false; + + if ( lhs.Day < rhs.Day ) + return true; + return false; + } + }; + + //================================================================================================================== + //= TimePredicateLess + //================================================================================================================== + class TimePredicateLess : public IKeyPredicateLess + { + public: + virtual bool isLess( ::com::sun::star::uno::Any const & _lhs, ::com::sun::star::uno::Any const & _rhs ) const + { + Time lhs, rhs; + if ( !( _lhs >>= lhs ) + || !( _rhs >>= rhs ) + ) + throw ::com::sun::star::lang::IllegalArgumentException(); + + if ( lhs.Hours < rhs.Hours ) + return true; + if ( lhs.Hours > rhs.Hours ) + return false; + + if ( lhs.Minutes < rhs.Minutes ) + return true; + if ( lhs.Minutes > rhs.Minutes ) + return false; + + if ( lhs.Seconds < rhs.Seconds ) + return true; + if ( lhs.Seconds > rhs.Seconds ) + return false; + + if ( lhs.HundredthSeconds < rhs.HundredthSeconds ) + return true; + return false; + } + }; + + //================================================================================================================== + //= DateTimePredicateLess + //================================================================================================================== + class DateTimePredicateLess : public IKeyPredicateLess + { + public: + virtual bool isLess( ::com::sun::star::uno::Any const & _lhs, ::com::sun::star::uno::Any const & _rhs ) const + { + DateTime lhs, rhs; + if ( !( _lhs >>= lhs ) + || !( _rhs >>= rhs ) + ) + throw ::com::sun::star::lang::IllegalArgumentException(); + + if ( lhs.Year < rhs.Year ) + return true; + if ( lhs.Year > rhs.Year ) + return false; + + if ( lhs.Month < rhs.Month ) + return true; + if ( lhs.Month > rhs.Month ) + return false; + + if ( lhs.Day < rhs.Day ) + return true; + if ( lhs.Day > rhs.Day ) + return false; + + if ( lhs.Hours < rhs.Hours ) + return true; + if ( lhs.Hours > rhs.Hours ) + return false; + + if ( lhs.Minutes < rhs.Minutes ) + return true; + if ( lhs.Minutes > rhs.Minutes ) + return false; + + if ( lhs.Seconds < rhs.Seconds ) + return true; + if ( lhs.Seconds > rhs.Seconds ) + return false; + + if ( lhs.HundredthSeconds < rhs.HundredthSeconds ) + return true; + return false; + } + }; + //------------------------------------------------------------------------------------------------------------------ ::std::auto_ptr< IKeyPredicateLess > getStandardLessPredicate( Type const & i_type, Reference< XCollator > const & i_collator ) { @@ -120,6 +242,14 @@ namespace comphelper case TypeClass_INTERFACE: pComparator.reset( new InterfacePredicateLess() ); break; + case TypeClass_STRUCT: + if ( i_type.equals( ::cppu::UnoType< Date >::get() ) ) + pComparator.reset( new DatePredicateLess() ); + else if ( i_type.equals( ::cppu::UnoType< Time >::get() ) ) + pComparator.reset( new TimePredicateLess() ); + else if ( i_type.equals( ::cppu::UnoType< DateTime >::get() ) ) + pComparator.reset( new DateTimePredicateLess() ); + break; default: break; } diff --git a/svtools/inc/svtools/accessibletable.hxx b/svtools/inc/svtools/accessibletable.hxx index d7bd98481404..186c83d75be8 100644 --- a/svtools/inc/svtools/accessibletable.hxx +++ b/svtools/inc/svtools/accessibletable.hxx @@ -111,7 +111,9 @@ public: virtual sal_Bool HasRowHeader() const= 0; virtual sal_Bool ConvertPointToCellAddress( sal_Int32& _rnRow, sal_Int32& _rnColPos, const Point& _rPoint )= 0; virtual Rectangle calcHeaderRect( sal_Bool _bIsColumnBar, sal_Bool _bOnScreen = sal_True ) = 0; + virtual Rectangle calcHeaderCellRect( sal_Bool _bColHeader, sal_Int32 _nPos ) = 0; virtual Rectangle calcTableRect( sal_Bool _bOnScreen = sal_True ) = 0; + virtual Rectangle calcCellRect( sal_Int32 _nRowPos, sal_Int32 _nColPos ) = 0; virtual Rectangle GetFieldCharacterBounds(sal_Int32 _nRow,sal_Int32 _nColumnPos,sal_Int32 nIndex)= 0; virtual sal_Int32 GetFieldIndexAtPoint(sal_Int32 _nRow,sal_Int32 _nColumnPos,const Point& _rPoint)= 0; virtual void FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumnPos ) const= 0; @@ -165,6 +167,33 @@ public: virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getTable() = 0; + /** commits the event at all listeners of the cell + @param nEventId + the event id + @param rNewValue + the new value + @param rOldValue + the old value + */ + virtual void commitCellEvent( + sal_Int16 nEventId, + const ::com::sun::star::uno::Any& rNewValue, + const ::com::sun::star::uno::Any& rOldValue + ) = 0; + /** commits the event at all listeners of the table + @param nEventId + the event id + @param rNewValue + the new value + @param rOldValue + the old value + */ + virtual void commitTableEvent( + sal_Int16 nEventId, + const ::com::sun::star::uno::Any& rNewValue, + const ::com::sun::star::uno::Any& rOldValue + ) = 0; + ///** Commits an event to all listeners. */ virtual void commitEvent( sal_Int16 nEventId, diff --git a/svtools/inc/svtools/table/gridtablerenderer.hxx b/svtools/inc/svtools/table/gridtablerenderer.hxx index c472fa408574..d7196419e2e5 100644 --- a/svtools/inc/svtools/table/gridtablerenderer.hxx +++ b/svtools/inc/svtools/table/gridtablerenderer.hxx @@ -90,15 +90,15 @@ namespace svt { namespace table virtual void PaintColumnHeader( ColPos _nCol, bool _bActive, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle ); - virtual void PrepareRow( RowPos _nRow, bool _bActive, bool _bSelected, + virtual void PrepareRow( RowPos _nRow, bool i_hasControlFocus, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rRowArea, const StyleSettings& _rStyle ); virtual void PaintRowHeader( - bool _bActive, bool _bSelected, + bool i_hasControlFocus, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle ); virtual void PaintCell( ColPos const i_col, - bool _bActive, bool _bSelected, + bool i_hasControlFocus, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle ); virtual void ShowCellCursor( Window& _rView, const Rectangle& _rCursorRect); @@ -108,7 +108,12 @@ namespace svt { namespace table ColPos const i_colPos, RowPos const i_rowPos, bool const i_active, bool const i_selected, OutputDevice& i_targetDevice, Rectangle const & i_targetArea - ); + ) const; + virtual bool GetFormattedCellString( + ::com::sun::star::uno::Any const & i_cellValue, + ColPos const i_colPos, RowPos const i_rowPos, + ::rtl::OUString & o_cellString + ) const; private: struct CellRenderContext; diff --git a/svtools/inc/svtools/table/tablecontrol.hxx b/svtools/inc/svtools/table/tablecontrol.hxx index 8afc2209227c..6237e4fb9b6a 100644 --- a/svtools/inc/svtools/table/tablecontrol.hxx +++ b/svtools/inc/svtools/table/tablecontrol.hxx @@ -169,9 +169,14 @@ namespace svt { namespace table SVT_DLLPRIVATE virtual ::rtl::OUString GetAccessibleObjectName(AccessibleTableControlObjType eObjType, sal_Int32 _nRow, sal_Int32 _nCol) const; SVT_DLLPRIVATE virtual sal_Bool GoToCell( sal_Int32 _nColumnPos, sal_Int32 _nRow ); SVT_DLLPRIVATE virtual ::rtl::OUString GetAccessibleObjectDescription(AccessibleTableControlObjType eObjType, sal_Int32 _nPosition = -1) const; - virtual void FillAccessibleStateSet( - ::utl::AccessibleStateSetHelper& rStateSet, - AccessibleTableControlObjType eObjType ) const; + SVT_DLLPRIVATE virtual void FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& rStateSet, AccessibleTableControlObjType eObjType ) const; + + // temporary methods + // Those do not really belong into the public API - they're intended for firing A11Y-related events. However, + // firing those events should be an implementation internal to the TableControl resp. TableControl_Impl, + // instead of something triggered externally. + void commitCellEventIfAccessibleAlive( sal_Int16 const i_eventID, const ::com::sun::star::uno::Any& i_newValue, const ::com::sun::star::uno::Any& i_oldValue ); + void commitTableEventIfAccessibleAlive( sal_Int16 const i_eventID, const ::com::sun::star::uno::Any& i_newValue, const ::com::sun::star::uno::Any& i_oldValue ); // ............................................................................................................. // IAccessibleTable @@ -187,7 +192,9 @@ namespace svt { namespace table virtual sal_Bool HasRowHeader() const; virtual sal_Bool ConvertPointToCellAddress( sal_Int32& _rnRow, sal_Int32& _rnColPos, const Point& _rPoint ); virtual Rectangle calcHeaderRect( sal_Bool _bIsColumnBar, sal_Bool _bOnScreen = sal_True ); + virtual Rectangle calcHeaderCellRect( sal_Bool _bIsColumnBar, sal_Int32 nPos); virtual Rectangle calcTableRect( sal_Bool _bOnScreen = sal_True ); + virtual Rectangle calcCellRect( sal_Int32 _nRowPos, sal_Int32 _nColPos ); virtual Rectangle GetFieldCharacterBounds(sal_Int32 _nRow,sal_Int32 _nColumnPos,sal_Int32 nIndex); virtual sal_Int32 GetFieldIndexAtPoint(sal_Int32 _nRow,sal_Int32 _nColumnPos,const Point& _rPoint); virtual void FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumnPos ) const; @@ -208,9 +215,6 @@ namespace svt { namespace table // ............................................................................................................. private: - DECL_DLLPRIVATE_LINK( ImplMouseButtonDownHdl, MouseEvent* ); - DECL_DLLPRIVATE_LINK( ImplMouseButtonUpHdl, MouseEvent* ); - DECL_DLLPRIVATE_LINK( ImplSelectHdl, void* ); private: diff --git a/svtools/inc/svtools/table/tablemodel.hxx b/svtools/inc/svtools/table/tablemodel.hxx index 94f03b684e64..9cfc30c1a338 100755..100644 --- a/svtools/inc/svtools/table/tablemodel.hxx +++ b/svtools/inc/svtools/table/tablemodel.hxx @@ -472,6 +472,30 @@ namespace svt { namespace table */ virtual ::boost::optional< ::Color > getHeaderTextColor() const = 0; + /** returns the color to be used for the background of selected cells, when the control has the focus + + If this value is not set, a default color from the style settings will be used. + */ + virtual ::boost::optional< ::Color > getActiveSelectionBackColor() const = 0; + + /** returns the color to be used for the background of selected cells, when the control does not have the focus + + If this value is not set, a default color from the style settings will be used. + */ + virtual ::boost::optional< ::Color > getInactiveSelectionBackColor() const = 0; + + /** returns the color to be used for the text of selected cells, when the control has the focus + + If this value is not set, a default color from the style settings will be used. + */ + virtual ::boost::optional< ::Color > getActiveSelectionTextColor() const = 0; + + /** returns the color to be used for the text of selected cells, when the control does not have the focus + + If this value is not set, a default color from the style settings will be used. + */ + virtual ::boost::optional< ::Color > getInactiveSelectionTextColor() const = 0; + /** returns the color to be used for rendering cell texts. If this value is not set, a default color from the style settings will be used. diff --git a/svtools/inc/svtools/table/tablerenderer.hxx b/svtools/inc/svtools/table/tablerenderer.hxx index 3d50c9d70ee7..73d41028bf1f 100644 --- a/svtools/inc/svtools/table/tablerenderer.hxx +++ b/svtools/inc/svtools/table/tablerenderer.hxx @@ -133,9 +133,8 @@ namespace svt { namespace table However, the renderer is also allowed to render any cell-independent content of this row. - @param _bActive - <TRUE/> if and only if the row to be painted contains the - currently active cell. + @param i_hasControlFocus + <TRUE/> if and only if the table control currently has the focus @param _bSelected <TRUE/> if and only if the row to be prepared is selected currently. @@ -147,7 +146,7 @@ namespace svt { namespace table @param _rStyle the style to be used for drawing */ - virtual void PrepareRow( RowPos _nRow, bool _bActive, bool _bSelected, + virtual void PrepareRow( RowPos _nRow, bool i_hasControlFocus, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rRowArea, const StyleSettings& _rStyle ) = 0; @@ -156,9 +155,8 @@ namespace svt { namespace table The row to be painted is denoted by the most recent call to ->PrepareRow. - @param _bActive - <TRUE/> if and only if the row to be painted contains the - currently active cell. + @param i_hasControlFocus + <TRUE/> if and only if the table control currently has the focus <br/> Note that this flag is equal to the respective flag in the previous ->PrepareRow call, it's passed here for convinience @@ -177,9 +175,9 @@ namespace svt { namespace table @param _rStyle the style to be used for drawing */ - virtual void PaintRowHeader( bool _bActive, bool _bSelected, - OutputDevice& _rDevice, const Rectangle& _rArea, - const StyleSettings& _rStyle ) = 0; + virtual void PaintRowHeader( bool i_hasControlFocus, bool _bSelected, + OutputDevice& _rDevice, Rectangle const & _rArea, + StyleSettings const & _rStyle ) = 0; /** paints a certain cell @@ -194,8 +192,8 @@ namespace svt { namespace table Note that this flag is equal to the respective flag in the previous ->PrepareRow call, it's passed here for convinience only. - @param _bActive - <TRUE/> if the cell is currently active. + @param i_hasControlFocus + <TRUE/> if and only if the table control currently has the focus <br/> Note that this flag is equal to the respective flag in the previous ->PrepareRow call, it's passed here for convinience @@ -208,7 +206,7 @@ namespace svt { namespace table the style to be used for drawing */ virtual void PaintCell( ColPos const i_col, - bool _bActive, bool _bSelected, + bool i_hasControlFocus, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle ) = 0; @@ -259,7 +257,26 @@ namespace svt { namespace table ColPos const i_colPos, RowPos const i_rowPos, bool const i_active, bool const i_selected, OutputDevice& i_targetDevice, Rectangle const & i_targetArea - ) = 0; + ) const = 0; + + /** attempts to format the content of the given cell as string + + @param i_cellValue + the value for which an attempt for a string conversion should be made + @param i_colPos + the column position of the cell in question + @param i_rowPos + the row position of the cell in question + @param o_cellString + the cell content, formatted as string + @return + <TRUE/> if and only if the content could be formatted as string + */ + virtual bool GetFormattedCellString( + ::com::sun::star::uno::Any const & i_cellValue, + ColPos const i_colPos, RowPos const i_rowPos, + ::rtl::OUString & o_cellString + ) const = 0; /// deletes the renderer instance virtual ~ITableRenderer() { } diff --git a/svtools/source/table/cellvalueconversion.cxx b/svtools/source/table/cellvalueconversion.cxx index 286ca505bb30..18e28c2cdc82 100755..100644 --- a/svtools/source/table/cellvalueconversion.cxx +++ b/svtools/source/table/cellvalueconversion.cxx @@ -29,8 +29,27 @@ #include "cellvalueconversion.hxx" /** === begin UNO includes === **/ +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/XNumberFormatTypes.hpp> +#include <com/sun/star/util/NumberFormat.hpp> /** === end UNO includes === **/ +#include <comphelper/componentcontext.hxx> +#include <rtl/math.hxx> +#include <rtl/strbuf.hxx> +#include <tools/date.hxx> +#include <tools/time.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/syslocale.hxx> + +#include <boost/shared_ptr.hpp> +#include <hash_map> + //...................................................................................................................... namespace svt { @@ -38,36 +57,432 @@ namespace svt /** === begin UNO using === **/ using ::com::sun::star::uno::Any; + using ::com::sun::star::util::XNumberFormatter; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::util::XNumberFormatsSupplier; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::util::DateTime; + using ::com::sun::star::uno::TypeClass; + using ::com::sun::star::util::XNumberFormatTypes; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Type; + using ::com::sun::star::uno::TypeClass_BYTE; + using ::com::sun::star::uno::TypeClass_SHORT; + using ::com::sun::star::uno::TypeClass_UNSIGNED_SHORT; + using ::com::sun::star::uno::TypeClass_LONG; + using ::com::sun::star::uno::TypeClass_UNSIGNED_LONG; + using ::com::sun::star::uno::TypeClass_HYPER; /** === end UNO using === **/ + namespace NumberFormat = ::com::sun::star::util::NumberFormat; + + typedef ::com::sun::star::util::Time UnoTime; + typedef ::com::sun::star::util::Date UnoDate; //================================================================================================================== - //= CellValueConversion + //= helper //================================================================================================================== - //------------------------------------------------------------------------------------------------------------------ - ::rtl::OUString CellValueConversion::convertToString( const Any& i_value ) + namespace { - ::rtl::OUString sConvertString; - if ( !i_value.hasValue() ) - return sConvertString; + //-------------------------------------------------------------------------------------------------------------- + double lcl_convertDateToDays( long const i_day, long const i_month, long const i_year ) + { + long const nNullDateDays = ::Date::DateToDays( 1, 1, 1900 ); + long const nValueDateDays = ::Date::DateToDays( i_day, i_month, i_year ); + + return nValueDateDays - nNullDateDays; + } + + //-------------------------------------------------------------------------------------------------------------- + double lcl_convertTimeToDays( long const i_hours, long const i_minutes, long const i_seconds, long const i_100thSeconds ) + { + return Time( i_hours, i_minutes, i_seconds, i_100thSeconds ).GetTimeInDays(); + } + } + + //================================================================================================================== + //= IValueNormalization + //================================================================================================================== + class SAL_NO_VTABLE IValueNormalization + { + public: + virtual ~IValueNormalization() { } + + /** converts the given <code>Any</code> into a <code>double</code> value to be fed into a number formatter + */ + virtual double convertToDouble( Any const & i_value ) const = 0; + + /** returns the format key to be used for formatting values + */ + virtual ::sal_Int32 getFormatKey() const = 0; + }; + + typedef ::boost::shared_ptr< IValueNormalization > PValueNormalization; + typedef ::std::hash_map< ::rtl::OUString, PValueNormalization, ::rtl::OUStringHash > NormalizerCache; + + //================================================================================================================== + //= CellValueConversion_Data + //================================================================================================================== + struct CellValueConversion_Data + { + ::comphelper::ComponentContext const aContext; + Reference< XNumberFormatter > xNumberFormatter; + bool bAttemptedFormatterCreation; + NormalizerCache aNormalizers; + + CellValueConversion_Data( ::comphelper::ComponentContext const & i_context ) + :aContext( i_context ) + ,xNumberFormatter() + ,bAttemptedFormatterCreation( false ) + ,aNormalizers() + { + } + }; + + //================================================================================================================== + //= StandardFormatNormalizer + //================================================================================================================== + class StandardFormatNormalizer : public IValueNormalization + { + protected: + StandardFormatNormalizer( Reference< XNumberFormatter > const & i_formatter, ::sal_Int32 const i_numberFormatType ) + :m_nFormatKey( 0 ) + { + try + { + ENSURE_OR_THROW( i_formatter.is(), "StandardFormatNormalizer: no formatter!" ); + Reference< XNumberFormatsSupplier > const xSupplier( i_formatter->getNumberFormatsSupplier(), UNO_SET_THROW ); + Reference< XNumberFormatTypes > const xTypes( xSupplier->getNumberFormats(), UNO_QUERY_THROW ); + m_nFormatKey = xTypes->getStandardFormat( i_numberFormatType, SvtSysLocale().GetLocale() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + virtual ::sal_Int32 getFormatKey() const + { + return m_nFormatKey; + } + + private: + ::sal_Int32 m_nFormatKey; + }; + + //================================================================================================================== + //= DoubleNormalization + //================================================================================================================== + class DoubleNormalization : public StandardFormatNormalizer + { + public: + DoubleNormalization( Reference< XNumberFormatter > const & i_formatter ) + :StandardFormatNormalizer( i_formatter, NumberFormat::NUMBER ) + { + } + + virtual double convertToDouble( Any const & i_value ) const + { + double returnValue(0); + ::rtl::math::setNan( &returnValue ); + OSL_VERIFY( i_value >>= returnValue ); + return returnValue; + } + + virtual ~DoubleNormalization() { } + }; + + //================================================================================================================== + //= IntegerNormalization + //================================================================================================================== + class IntegerNormalization : public StandardFormatNormalizer + { + public: + IntegerNormalization( Reference< XNumberFormatter > const & i_formatter ) + :StandardFormatNormalizer( i_formatter, NumberFormat::NUMBER ) + { + } + + virtual ~IntegerNormalization() {} + + virtual double convertToDouble( Any const & i_value ) const + { + sal_Int64 value( 0 ); + OSL_VERIFY( i_value >>= value ); + return value; + } + }; + + //================================================================================================================== + //= BooleanNormalization + //================================================================================================================== + class BooleanNormalization : public StandardFormatNormalizer + { + public: + BooleanNormalization( Reference< XNumberFormatter > const & i_formatter ) + :StandardFormatNormalizer( i_formatter, NumberFormat::LOGICAL ) + { + } + + virtual ~BooleanNormalization() {} + + virtual double convertToDouble( Any const & i_value ) const + { + bool value( false ); + OSL_VERIFY( i_value >>= value ); + return value ? 1 : 0; + } + }; + + //================================================================================================================== + //= DateTimeNormalization + //================================================================================================================== + class DateTimeNormalization : public StandardFormatNormalizer + { + public: + DateTimeNormalization( Reference< XNumberFormatter > const & i_formatter ) + :StandardFormatNormalizer( i_formatter, NumberFormat::DATETIME ) + { + } + + virtual ~DateTimeNormalization() {} + + virtual double convertToDouble( Any const & i_value ) const + { + double returnValue(0); + ::rtl::math::setNan( &returnValue ); + // extract actual UNO value + DateTime aDateTimeValue; + ENSURE_OR_RETURN( i_value >>= aDateTimeValue, "allowed for DateTime values only", returnValue ); - // TODO: use css.script.XTypeConverter? + // date part + returnValue = lcl_convertDateToDays( aDateTimeValue.Day, aDateTimeValue.Month, aDateTimeValue.Year ); - sal_Int32 nInt = 0; - sal_Bool bBool = false; - double fDouble = 0; + // time part + returnValue += lcl_convertTimeToDays( + aDateTimeValue.Hours, aDateTimeValue.Minutes, aDateTimeValue.Seconds, aDateTimeValue.HundredthSeconds ); + // done + return returnValue; + } + }; + + //================================================================================================================== + //= DateNormalization + //================================================================================================================== + class DateNormalization : public StandardFormatNormalizer + { + public: + DateNormalization( Reference< XNumberFormatter > const & i_formatter ) + :StandardFormatNormalizer( i_formatter, NumberFormat::DATE ) + { + } + + virtual ~DateNormalization() {} + + virtual double convertToDouble( Any const & i_value ) const + { + double returnValue(0); + ::rtl::math::setNan( &returnValue ); + + // extract + UnoDate aDateValue; + ENSURE_OR_RETURN( i_value >>= aDateValue, "allowed for Date values only", returnValue ); + + // convert + returnValue = lcl_convertDateToDays( aDateValue.Day, aDateValue.Month, aDateValue.Year ); + + // done + return returnValue; + } + }; + + //================================================================================================================== + //= TimeNormalization + //================================================================================================================== + class TimeNormalization : public StandardFormatNormalizer + { + public: + TimeNormalization( Reference< XNumberFormatter > const & i_formatter ) + :StandardFormatNormalizer( i_formatter, NumberFormat::TIME ) + { + } + + virtual ~TimeNormalization() {} + + virtual double convertToDouble( Any const & i_value ) const + { + double returnValue(0); + ::rtl::math::setNan( &returnValue ); + + // extract + UnoTime aTimeValue; + ENSURE_OR_RETURN( i_value >>= aTimeValue, "allowed for Time values only", returnValue ); + + // convert + returnValue += lcl_convertTimeToDays( + aTimeValue.Hours, aTimeValue.Minutes, aTimeValue.Seconds, aTimeValue.HundredthSeconds ); + + // done + return returnValue; + } + }; + + //================================================================================================================== + //= operations + //================================================================================================================== + namespace + { + //-------------------------------------------------------------------------------------------------------------- + bool lcl_ensureNumberFormatter( CellValueConversion_Data & io_data ) + { + if ( io_data.bAttemptedFormatterCreation ) + return io_data.xNumberFormatter.is(); + io_data.bAttemptedFormatterCreation = true; + + try + { + // a number formatter + Reference< XNumberFormatter > const xFormatter( + io_data.aContext.createComponent( "com.sun.star.util.NumberFormatter" ), UNO_QUERY_THROW ); + + // a supplier of number formats + Sequence< Any > aInitArgs(1); + aInitArgs[0] <<= SvtSysLocale().GetLocale(); + + Reference< XNumberFormatsSupplier > const xSupplier( + io_data.aContext.createComponentWithArguments( "com.sun.star.util.NumberFormatsSupplier", aInitArgs ), + UNO_QUERY_THROW + ); + + // ensure a NullDate we will assume later on + UnoDate const aNullDate( 1, 1, 1900 ); + Reference< XPropertySet > const xFormatSettings( xSupplier->getNumberFormatSettings(), UNO_SET_THROW ); + xFormatSettings->setPropertyValue( ::rtl::OUString::createFromAscii( "NullDate" ), makeAny( aNullDate ) ); + + // knit + xFormatter->attachNumberFormatsSupplier( xSupplier ); + + // done + io_data.xNumberFormatter = xFormatter; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return io_data.xNumberFormatter.is(); + } + + //-------------------------------------------------------------------------------------------------------------- + bool lcl_getValueNormalizer( CellValueConversion_Data & io_data, Type const & i_valueType, + PValueNormalization & o_formatter ) + { + NormalizerCache::const_iterator pos = io_data.aNormalizers.find( i_valueType.getTypeName() ); + if ( pos == io_data.aNormalizers.end() ) + { + // never encountered this type before + o_formatter.reset(); + + ::rtl::OUString const sTypeName( i_valueType.getTypeName() ); + TypeClass const eTypeClass = i_valueType.getTypeClass(); + + if ( sTypeName.equals( ::cppu::UnoType< DateTime >::get().getTypeName() ) ) + { + o_formatter.reset( new DateTimeNormalization( io_data.xNumberFormatter ) ); + } + else if ( sTypeName.equals( ::cppu::UnoType< UnoDate >::get().getTypeName() ) ) + { + o_formatter.reset( new DateNormalization( io_data.xNumberFormatter ) ); + } + else if ( sTypeName.equals( ::cppu::UnoType< UnoTime >::get().getTypeName() ) ) + { + o_formatter.reset( new TimeNormalization( io_data.xNumberFormatter ) ); + } + else if ( sTypeName.equals( ::cppu::UnoType< ::sal_Bool >::get().getTypeName() ) ) + { + o_formatter.reset( new BooleanNormalization( io_data.xNumberFormatter ) ); + } + else if ( sTypeName.equals( ::cppu::UnoType< double >::get().getTypeName() ) + || sTypeName.equals( ::cppu::UnoType< float >::get().getTypeName() ) + ) + { + o_formatter.reset( new DoubleNormalization( io_data.xNumberFormatter ) ); + } + else if ( ( eTypeClass == TypeClass_BYTE ) + || ( eTypeClass == TypeClass_SHORT ) + || ( eTypeClass == TypeClass_UNSIGNED_SHORT ) + || ( eTypeClass == TypeClass_LONG ) + || ( eTypeClass == TypeClass_UNSIGNED_LONG ) + || ( eTypeClass == TypeClass_HYPER ) + ) + { + o_formatter.reset( new IntegerNormalization( io_data.xNumberFormatter ) ); + } + else + { +#if OSL_DEBUG_LEVEL > 0 + ::rtl::OStringBuffer message( "lcl_getValueNormalizer: unsupported type '" ); + message.append( ::rtl::OUStringToOString( sTypeName, RTL_TEXTENCODING_ASCII_US ) ); + message.append( "'!" ); + OSL_ENSURE( false, message.makeStringAndClear() ); +#endif + } + io_data.aNormalizers[ sTypeName ] = o_formatter; + } + else + o_formatter = pos->second; + + return !!o_formatter; + } + } + + //================================================================================================================== + //= CellValueConversion + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + CellValueConversion::CellValueConversion( ::comphelper::ComponentContext const & i_context ) + :m_pData( new CellValueConversion_Data( i_context ) ) + { + } + + //------------------------------------------------------------------------------------------------------------------ + CellValueConversion::~CellValueConversion() + { + } + + //------------------------------------------------------------------------------------------------------------------ + ::rtl::OUString CellValueConversion::convertToString( const Any& i_value ) + { ::rtl::OUString sStringValue; - if ( i_value >>= sConvertString ) - sStringValue = sConvertString; - else if ( i_value >>= nInt ) - sStringValue = sConvertString.valueOf( nInt ); - else if ( i_value >>= bBool ) - sStringValue = sConvertString.valueOf( bBool ); - else if ( i_value >>= fDouble ) - sStringValue = sConvertString.valueOf( fDouble ); - else - OSL_ENSURE( !i_value.hasValue(), "CellValueConversion::convertToString: cannot handle the given cell content type!" ); + if ( !i_value.hasValue() ) + return sStringValue; + + if ( ! ( i_value >>= sStringValue ) ) + { + if ( lcl_ensureNumberFormatter( *m_pData ) ) + { + PValueNormalization pNormalizer; + if ( lcl_getValueNormalizer( *m_pData, i_value.getValueType(), pNormalizer ) ) + { + try + { + double const formatterCompliantValue = pNormalizer->convertToDouble( i_value ); + sal_Int32 const formatKey = pNormalizer->getFormatKey(); + sStringValue = m_pData->xNumberFormatter->convertNumberToString( + formatKey, formatterCompliantValue ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + } return sStringValue; } diff --git a/svtools/source/table/cellvalueconversion.hxx b/svtools/source/table/cellvalueconversion.hxx index 4d6b8c8d6aac..c4d8baa98489 100755..100644 --- a/svtools/source/table/cellvalueconversion.hxx +++ b/svtools/source/table/cellvalueconversion.hxx @@ -31,6 +31,13 @@ #include <com/sun/star/uno/Any.hxx> /** === end UNO includes === **/ +#include <boost/scoped_ptr.hpp> + +namespace comphelper +{ + class ComponentContext; +} + //...................................................................................................................... namespace svt { @@ -39,10 +46,17 @@ namespace svt //================================================================================================================== //= CellValueConversion //================================================================================================================== + struct CellValueConversion_Data; class CellValueConversion { public: - static ::rtl::OUString convertToString( const ::com::sun::star::uno::Any& i_cellValue ); + CellValueConversion( ::comphelper::ComponentContext const & i_context ); + ~CellValueConversion(); + + ::rtl::OUString convertToString( const ::com::sun::star::uno::Any& i_cellValue ); + + private: + ::boost::scoped_ptr< CellValueConversion_Data > m_pData; }; //...................................................................................................................... diff --git a/svtools/source/table/gridtablerenderer.cxx b/svtools/source/table/gridtablerenderer.cxx index 1e230d372c24..341c398b5bcd 100644 --- a/svtools/source/table/gridtablerenderer.cxx +++ b/svtools/source/table/gridtablerenderer.cxx @@ -35,6 +35,8 @@ #include <com/sun/star/graphic/XGraphic.hpp> /** === end UNO includes === **/ +#include <comphelper/componentcontext.hxx> +#include <comphelper/processfactory.hxx> #include <tools/debug.hxx> #include <tools/diagnose_ex.h> #include <vcl/window.hxx> @@ -123,11 +125,14 @@ namespace svt { namespace table RowPos nCurrentRow; bool bUseGridLines; CachedSortIndicator aSortIndicator; + CellValueConversion aStringConverter; GridTableRenderer_Impl( ITableModel& _rModel ) :rModel( _rModel ) ,nCurrentRow( ROW_INVALID ) ,bUseGridLines( true ) + ,aSortIndicator( ) + ,aStringConverter( ::comphelper::ComponentContext( ::comphelper::getProcessServiceFactory() ) ) { } }; @@ -168,7 +173,9 @@ namespace svt { namespace table } sal_uLong nHorzFlag = TEXT_DRAW_LEFT; - HorizontalAlignment const eHorzAlign = i_impl.rModel.getColumnModel( i_columnPos )->getHorizontalAlign(); + HorizontalAlignment const eHorzAlign = i_impl.rModel.getColumnCount() > 0 + ? i_impl.rModel.getColumnModel( i_columnPos )->getHorizontalAlign() + : HorizontalAlignment_CENTER; switch ( eHorzAlign ) { case HorizontalAlignment_CENTER: nHorzFlag = TEXT_DRAW_CENTER; break; @@ -324,7 +331,7 @@ namespace svt { namespace table } //------------------------------------------------------------------------------------------------------------------ - void GridTableRenderer::PrepareRow( RowPos _nRow, bool _bActive, bool _bSelected, + void GridTableRenderer::PrepareRow( RowPos _nRow, bool i_hasControlFocus, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rRowArea, const StyleSettings& _rStyle ) { // remember the row for subsequent calls to the other ->ITableRenderer methods @@ -334,13 +341,17 @@ namespace svt { namespace table ::Color backgroundColor = _rStyle.GetFieldColor(); - ::boost::optional< ::Color > aLineColor( m_pImpl->rModel.getLineColor() ); + ::boost::optional< ::Color > const aLineColor( m_pImpl->rModel.getLineColor() ); ::Color lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor; + ::Color const activeSelectionBackColor = + lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionBackColor(), _rStyle, &StyleSettings::GetHighlightColor ); if ( _bSelected ) { // selected rows use the background color from the style - backgroundColor = _rStyle.GetHighlightColor(); + backgroundColor = i_hasControlFocus + ? activeSelectionBackColor + : lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionBackColor(), _rStyle, &StyleSettings::GetDeactiveColor ); if ( !aLineColor ) lineColor = backgroundColor; } @@ -357,7 +368,7 @@ namespace svt { namespace table } else { - Color hilightColor = _rStyle.GetHighlightColor(); + Color hilightColor = activeSelectionBackColor; hilightColor.SetRed( 9 * ( fieldColor.GetRed() - hilightColor.GetRed() ) / 10 + hilightColor.GetRed() ); hilightColor.SetGreen( 9 * ( fieldColor.GetGreen() - hilightColor.GetGreen() ) / 10 + hilightColor.GetGreen() ); hilightColor.SetBlue( 9 * ( fieldColor.GetBlue() - hilightColor.GetBlue() ) / 10 + hilightColor.GetBlue() ); @@ -384,13 +395,10 @@ namespace svt { namespace table _rDevice.DrawRect( _rRowArea ); _rDevice.Pop(); - - (void)_bActive; - // row containing the active cell not rendered any special at the moment } //------------------------------------------------------------------------------------------------------------------ - void GridTableRenderer::PaintRowHeader( bool _bActive, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rArea, + void GridTableRenderer::PaintRowHeader( bool i_hasControlFocus, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle ) { _rDevice.Push( PUSH_LINECOLOR | PUSH_TEXTCOLOR ); @@ -401,7 +409,7 @@ namespace svt { namespace table _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() ); Any const rowHeading( m_pImpl->rModel.getRowHeading( m_pImpl->nCurrentRow ) ); - ::rtl::OUString const rowTitle( CellValueConversion::convertToString( rowHeading ) ); + ::rtl::OUString const rowTitle( m_pImpl->aStringConverter.convertToString( rowHeading ) ); if ( rowTitle.getLength() ) { ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getHeaderTextColor(), _rStyle, &StyleSettings::GetFieldTextColor ); @@ -413,8 +421,7 @@ namespace svt { namespace table _rDevice.DrawText( aTextRect, rowTitle, nDrawTextFlags ); } - // TODO: active? selected? - (void)_bActive; + (void)i_hasControlFocus; (void)_bSelected; _rDevice.Pop(); } @@ -427,26 +434,28 @@ namespace svt { namespace table StyleSettings const & rStyle; ColPos const nColumn; bool const bSelected; + bool const bHasControlFocus; CellRenderContext( OutputDevice& i_device, Rectangle const & i_contentArea, - StyleSettings const & i_style, ColPos const i_column, bool const i_selected ) + StyleSettings const & i_style, ColPos const i_column, bool const i_selected, bool const i_hasControlFocus ) :rDevice( i_device ) ,aContentArea( i_contentArea ) ,rStyle( i_style ) ,nColumn( i_column ) ,bSelected( i_selected ) + ,bHasControlFocus( i_hasControlFocus ) { } }; //------------------------------------------------------------------------------------------------------------------ - void GridTableRenderer::PaintCell( ColPos const i_column, bool _bSelected, bool _bActive, + void GridTableRenderer::PaintCell( ColPos const i_column, bool _bSelected, bool i_hasControlFocus, OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle ) { _rDevice.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR ); Rectangle const aContentArea( lcl_getContentArea( *m_pImpl, _rArea ) ); - CellRenderContext const aRenderContext( _rDevice, aContentArea, _rStyle, i_column, _bSelected ); + CellRenderContext const aRenderContext( _rDevice, aContentArea, _rStyle, i_column, _bSelected, i_hasControlFocus ); impl_paintCellContent( aRenderContext ); if ( m_pImpl->bUseGridLines ) @@ -457,7 +466,9 @@ namespace svt { namespace table if ( _bSelected && !aLineColor ) { // if no line color is specified by the model, use the usual selection color for lines in selected cells - lineColor = _rStyle.GetHighlightColor(); + lineColor = i_hasControlFocus + ? lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionBackColor(), _rStyle, &StyleSettings::GetHighlightColor ) + : lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionBackColor(), _rStyle, &StyleSettings::GetDeactiveColor ); } _rDevice.SetLineColor( lineColor ); @@ -466,9 +477,6 @@ namespace svt { namespace table } _rDevice.Pop(); - - (void)_bActive; - // no special painting for the active cell at the moment } //------------------------------------------------------------------------------------------------------------------ @@ -537,7 +545,7 @@ namespace svt { namespace table return; } - const ::rtl::OUString sText( CellValueConversion::convertToString( aCellContent ) ); + const ::rtl::OUString sText( m_pImpl->aStringConverter.convertToString( aCellContent ) ); impl_paintCellText( i_context, sText ); } @@ -545,7 +553,12 @@ namespace svt { namespace table void GridTableRenderer::impl_paintCellText( CellRenderContext const & i_context, ::rtl::OUString const & i_text ) { if ( i_context.bSelected ) - i_context.rDevice.SetTextColor( i_context.rStyle.GetHighlightTextColor() ); + { + ::Color const textColor = i_context.bHasControlFocus + ? lcl_getEffectiveColor( m_pImpl->rModel.getActiveSelectionTextColor(), i_context.rStyle, &StyleSettings::GetHighlightTextColor ) + : lcl_getEffectiveColor( m_pImpl->rModel.getInactiveSelectionTextColor(), i_context.rStyle, &StyleSettings::GetDeactiveTextColor ); + i_context.rDevice.SetTextColor( textColor ); + } else { ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getTextColor(), i_context.rStyle, &StyleSettings::GetFieldTextColor ); @@ -572,7 +585,7 @@ namespace svt { namespace table //------------------------------------------------------------------------------------------------------------------ bool GridTableRenderer::FitsIntoCell( Any const & i_cellContent, ColPos const i_colPos, RowPos const i_rowPos, - bool const i_active, bool const i_selected, OutputDevice& i_targetDevice, Rectangle const & i_targetArea ) + bool const i_active, bool const i_selected, OutputDevice& i_targetDevice, Rectangle const & i_targetArea ) const { if ( !i_cellContent.hasValue() ) return true; @@ -592,7 +605,7 @@ namespace svt { namespace table return true; } - ::rtl::OUString const sText( CellValueConversion::convertToString( i_cellContent ) ); + ::rtl::OUString const sText( m_pImpl->aStringConverter.convertToString( i_cellContent ) ); if ( sText.getLength() == 0 ) return true; @@ -613,6 +626,16 @@ namespace svt { namespace table return true; } + //------------------------------------------------------------------------------------------------------------------ + bool GridTableRenderer::GetFormattedCellString( Any const & i_cellValue, ColPos const i_colPos, RowPos const i_rowPos, ::rtl::OUString & o_cellString ) const + { + o_cellString = m_pImpl->aStringConverter.convertToString( i_cellValue ); + + OSL_UNUSED( i_colPos ); + OSL_UNUSED( i_rowPos ); + return true; + } + //...................................................................................................................... } } // namespace svt::table //...................................................................................................................... diff --git a/svtools/source/table/mousefunction.cxx b/svtools/source/table/mousefunction.cxx index 20d505e911e9..162abc7936c8 100755..100644 --- a/svtools/source/table/mousefunction.cxx +++ b/svtools/source/table/mousefunction.cxx @@ -207,27 +207,14 @@ namespace svt { namespace table TableCell const tableCell( i_tableControl.hitTest( i_event.GetPosPixel() ) ); if ( tableCell.nRow >= 0 ) { - bool bSetCursor = false; if ( i_tableControl.getSelEngine()->GetSelectionMode() == NO_SELECTION ) { - bSetCursor = true; + i_tableControl.activateCell( tableCell.nColumn, tableCell.nRow ); + handled = true; } else { - if ( !i_tableControl.isRowSelected( tableCell.nRow ) ) - { - handled = i_tableControl.getSelEngine()->SelMouseButtonDown( i_event ); - } - else - { - bSetCursor = true; - } - } - - if ( bSetCursor ) - { - i_tableControl.activateCell( tableCell.nColumn, tableCell.nRow ); - handled = true; + handled = i_tableControl.getSelEngine()->SelMouseButtonDown( i_event ); } } diff --git a/svtools/source/table/tablecontrol.cxx b/svtools/source/table/tablecontrol.cxx index 01a9b667a8f7..d0e726fa5c53 100644 --- a/svtools/source/table/tablecontrol.cxx +++ b/svtools/source/table/tablecontrol.cxx @@ -35,6 +35,7 @@ #include <com/sun/star/accessibility/AccessibleStateType.hpp> #include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> #include <tools/diagnose_ex.h> @@ -49,6 +50,8 @@ namespace svt { namespace table { //...................................................................................................................... + namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId; + //================================================================================================================== //= TableControl //================================================================================================================== @@ -58,14 +61,14 @@ namespace svt { namespace table ,m_pImpl( new TableControl_Impl( *this ) ) { TableDataWindow& rDataWindow = m_pImpl->getDataWindow(); - rDataWindow.SetMouseButtonDownHdl( LINK( this, TableControl, ImplMouseButtonDownHdl ) ); - rDataWindow.SetMouseButtonUpHdl( LINK( this, TableControl, ImplMouseButtonUpHdl ) ); rDataWindow.SetSelectHdl( LINK( this, TableControl, ImplSelectHdl ) ); // by default, use the background as determined by the style settings const Color aWindowColor( GetSettings().GetStyleSettings().GetFieldColor() ); SetBackground( Wallpaper( aWindowColor ) ); SetFillColor( aWindowColor ); + + SetCompoundControl( true ); } // ----------------------------------------------------------------------------------------------------------------- @@ -97,6 +100,27 @@ namespace svt { namespace table { if ( !m_pImpl->getInputHandler()->KeyInput( *m_pImpl, rKEvt ) ) Control::KeyInput( rKEvt ); + else + { + if ( m_pImpl->isAccessibleAlive() ) + { + m_pImpl->commitCellEvent( AccessibleEventId::STATE_CHANGED, + makeAny( AccessibleStateType::FOCUSED ), + Any() + ); + // Huh? What the heck? Why do we unconditionally notify a STATE_CHANGE/FOCUSED after each and every + // (handled) key stroke? + + m_pImpl->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, + Any(), + Any() + ); + // ditto: Why do we notify this unconditionally? We should find the right place to notify the + // ACTIVE_DESCENDANT_CHANGED event. + // Also, we should check if STATE_CHANGED/FOCUSED is really necessary: finally, the children are + // transient, aren't they? + } + } } @@ -108,6 +132,10 @@ namespace svt { namespace table // forward certain settings to the data window switch ( i_nStateChange ) { + case STATE_CHANGE_CONTROL_FOCUS: + m_pImpl->invalidateSelectedRows(); + break; + case STATE_CHANGE_CONTROLBACKGROUND: if ( IsControlBackground() ) getDataWindow().SetControlBackground( GetControlBackground() ); @@ -209,7 +237,7 @@ namespace svt { namespace table void TableControl::SelectRow( RowPos const i_rowIndex, bool const i_select ) { ENSURE_OR_RETURN_VOID( ( i_rowIndex >= 0 ) && ( i_rowIndex < m_pImpl->getModel()->getRowCount() ), - "TableControl::SelectRow: no control (anymore)!" ); + "TableControl::SelectRow: invalid row index!" ); if ( i_select ) { @@ -291,10 +319,10 @@ namespace svt { namespace table switch( eObjType ) { case TCTYPE_GRIDCONTROL: - aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GridControl" ) ); + aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Grid control" ) ); break; case TCTYPE_TABLE: - aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Table" ) ); + aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Grid conrol" ) ); break; case TCTYPE_ROWHEADERBAR: aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RowHeaderBar" ) ); @@ -303,7 +331,19 @@ namespace svt { namespace table aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ColumnHeaderBar" ) ); break; case TCTYPE_TABLECELL: - aRetText = GetAccessibleCellText(_nRow, _nCol); + //the name of the cell constists of column name and row name if defined + //if the name is equal to cell content, it'll be read twice + if(GetModel()->hasColumnHeaders()) + { + aRetText = GetColumnName(_nCol); + aRetText += rtl::OUString::createFromAscii(" , "); + } + if(GetModel()->hasRowHeaders()) + { + aRetText += GetRowName(_nRow); + aRetText += rtl::OUString::createFromAscii(" , "); + } + //aRetText = GetAccessibleCellText(_nRow, _nCol); break; case TCTYPE_ROWHEADERCELL: aRetText = GetRowName(_nRow); @@ -324,7 +364,7 @@ namespace svt { namespace table switch( eObjType ) { case TCTYPE_GRIDCONTROL: - aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GridControl description" ) ); + aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Grid control description" ) ); break; case TCTYPE_TABLE: aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TABLE description" ) ); @@ -336,7 +376,17 @@ namespace svt { namespace table aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "COLUMNHEADERBAR description" ) ); break; case TCTYPE_TABLECELL: - aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TABLECELL description" ) ); + // the description of the cell consists of column name and row name if defined + // if the name is equal to cell content, it'll be read twice + if ( GetModel()->hasColumnHeaders() ) + { + aRetText = GetColumnName( GetCurrentColumn() ); + aRetText += rtl::OUString::createFromAscii( " , " ); + } + if ( GetModel()->hasRowHeaders() ) + { + aRetText += GetRowName( GetCurrentRow() ); + } break; case TCTYPE_ROWHEADERCELL: aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ROWHEADERCELL description" ) ); @@ -401,38 +451,60 @@ namespace svt { namespace table case TCTYPE_TABLE: rStateSet.AddState( AccessibleStateType::FOCUSABLE ); - rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE); - if ( HasFocus() ) + + if ( m_pImpl->getSelEngine()->GetSelectionMode() == MULTIPLE_SELECTION ) + rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE); + + if ( HasChildPathFocus() ) rStateSet.AddState( AccessibleStateType::FOCUSED ); + if ( IsActive() ) rStateSet.AddState( AccessibleStateType::ACTIVE ); - if ( IsEnabled() ) + + if ( m_pImpl->getDataWindow().IsEnabled() ) + { rStateSet.AddState( AccessibleStateType::ENABLED ); + rStateSet.AddState( AccessibleStateType::SENSITIVE ); + } + if ( IsReallyVisible() ) rStateSet.AddState( AccessibleStateType::VISIBLE ); - rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS ); + if ( eObjType == TCTYPE_TABLE ) + rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS ); break; + case TCTYPE_ROWHEADERBAR: rStateSet.AddState( AccessibleStateType::VISIBLE ); rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS ); break; + case TCTYPE_COLUMNHEADERBAR: rStateSet.AddState( AccessibleStateType::VISIBLE ); rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS ); break; + case TCTYPE_TABLECELL: { + rStateSet.AddState( AccessibleStateType::FOCUSABLE ); + if ( HasChildPathFocus() ) + rStateSet.AddState( AccessibleStateType::FOCUSED ); + rStateSet.AddState( AccessibleStateType::ACTIVE ); rStateSet.AddState( AccessibleStateType::TRANSIENT ); rStateSet.AddState( AccessibleStateType::SELECTABLE); - if( GetSelectedRowCount()>0) - rStateSet.AddState( AccessibleStateType::SELECTED); + rStateSet.AddState( AccessibleStateType::VISIBLE ); + rStateSet.AddState( AccessibleStateType::SHOWING ); + if ( IsRowSelected( GetCurrentRow() ) ) + // Hmm? Wouldn't we expect the affected row to be a parameter to this function? + rStateSet.AddState( AccessibleStateType::SELECTED ); } break; + case TCTYPE_ROWHEADERCELL: rStateSet.AddState( AccessibleStateType::VISIBLE ); rStateSet.AddState( AccessibleStateType::TRANSIENT ); break; + case TCTYPE_COLUMNHEADERCELL: rStateSet.AddState( AccessibleStateType::VISIBLE ); break; @@ -440,6 +512,20 @@ namespace svt { namespace table } //------------------------------------------------------------------------------------------------------------------ + void TableControl::commitCellEventIfAccessibleAlive( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue ) + { + if ( m_pImpl->isAccessibleAlive() ) + m_pImpl->commitCellEvent( i_eventID, i_newValue, i_oldValue ); + } + + //------------------------------------------------------------------------------------------------------------------ + void TableControl::commitTableEventIfAccessibleAlive( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue ) + { + if ( m_pImpl->isAccessibleAlive() ) + m_pImpl->commitTableEvent( i_eventID, i_newValue, i_oldValue ); + } + + //------------------------------------------------------------------------------------------------------------------ Rectangle TableControl::GetWindowExtentsRelative( Window *pRelativeWindow ) const { return Control::GetWindowExtentsRelative( pRelativeWindow ); @@ -484,13 +570,12 @@ namespace svt { namespace table //------------------------------------------------------------------------------------------------------------------ sal_Int32 TableControl::GetAccessibleControlCount() const { - sal_Int32 count = 0; - if(GetRowCount()>0) - count+=1; - if(GetModel()->hasRowHeaders()) - count+=1; - if(GetModel()->hasColumnHeaders()) - count+=1; + // TC_TABLE is always defined, no matter whether empty or not + sal_Int32 count = 1; + if ( GetModel()->hasRowHeaders() ) + ++count; + if ( GetModel()->hasColumnHeaders() ) + ++count; return count; } @@ -532,10 +617,20 @@ namespace svt { namespace table //------------------------------------------------------------------------------------------------------------------ void TableControl::FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumnPos ) const { - if ( GetCurrentRow() == _nRow && GetCurrentColumn() == _nColumnPos ) + if ( IsRowSelected( _nRow ) ) + _rStateSet.AddState( AccessibleStateType::SELECTED ); + if ( HasChildPathFocus() ) _rStateSet.AddState( AccessibleStateType::FOCUSED ); else // only transient when column is not focused _rStateSet.AddState( AccessibleStateType::TRANSIENT ); + + _rStateSet.AddState( AccessibleStateType::VISIBLE ); + _rStateSet.AddState( AccessibleStateType::SHOWING ); + _rStateSet.AddState( AccessibleStateType::ENABLED ); + _rStateSet.AddState( AccessibleStateType::SENSITIVE ); + _rStateSet.AddState( AccessibleStateType::ACTIVE ); + + (void)_nColumnPos; } //------------------------------------------------------------------------------------------------------------------ @@ -562,30 +657,27 @@ namespace svt { namespace table } //------------------------------------------------------------------------------------------------------------------ - Rectangle TableControl::calcTableRect(sal_Bool _bOnScreen) + Rectangle TableControl::calcHeaderCellRect( sal_Bool _bIsColumnBar, sal_Int32 nPos ) { - (void)_bOnScreen; - return m_pImpl->calcTableRect(); + return m_pImpl->calcHeaderCellRect( _bIsColumnBar, nPos ); } //------------------------------------------------------------------------------------------------------------------ - IMPL_LINK( TableControl, ImplSelectHdl, void*, EMPTYARG ) + Rectangle TableControl::calcTableRect(sal_Bool _bOnScreen) { - Select(); - return 1; + (void)_bOnScreen; + return m_pImpl->calcTableRect(); } //------------------------------------------------------------------------------------------------------------------ - IMPL_LINK( TableControl, ImplMouseButtonDownHdl, MouseEvent*, pData ) + Rectangle TableControl::calcCellRect( sal_Int32 _nRowPos, sal_Int32 _nColPos ) { - CallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, pData ); - return 1; + return m_pImpl->calcCellRect( _nRowPos, _nColPos ); } - //------------------------------------------------------------------------------------------------------------------ - IMPL_LINK( TableControl, ImplMouseButtonUpHdl, MouseEvent*, pData ) + IMPL_LINK( TableControl, ImplSelectHdl, void*, EMPTYARG ) { - CallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, pData ); + Select(); return 1; } @@ -593,6 +685,15 @@ namespace svt { namespace table void TableControl::Select() { ImplCallEventListenersAndHandler( VCLEVENT_TABLEROW_SELECT, m_pImpl->getSelectHandler(), this ); + + if ( m_pImpl->isAccessibleAlive() ) + { + m_pImpl->commitAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() ); + + m_pImpl->commitTableEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), Any() ); + // TODO: why do we notify this when the *selection* changed? Shouldn't we find a better place for this, + // actually, when the active descendant, i.e. the current cell, *really* changed? + } } //------------------------------------------------------------------------------------------------------------------ diff --git a/svtools/source/table/tablecontrol_impl.cxx b/svtools/source/table/tablecontrol_impl.cxx index 8e481d27d993..4ecce7359a15 100755..100644 --- a/svtools/source/table/tablecontrol_impl.cxx +++ b/svtools/source/table/tablecontrol_impl.cxx @@ -34,7 +34,6 @@ #include "tabledatawindow.hxx" #include "tablecontrol_impl.hxx" #include "tablegeometry.hxx" -#include "cellvalueconversion.hxx" /** === begin UNO includes === **/ #include <com/sun/star/accessibility/XAccessible.hpp> @@ -51,6 +50,7 @@ #include <tools/diagnose_ex.h> #include <functional> +#include <numeric> #define MIN_COLUMN_WIDTH_PIXEL 4 @@ -186,6 +186,22 @@ namespace svt { namespace table { return ::boost::optional< ::Color >(); } + virtual ::boost::optional< ::Color > getActiveSelectionBackColor() const + { + return ::boost::optional< ::Color >(); + } + virtual ::boost::optional< ::Color > getInactiveSelectionBackColor() const + { + return ::boost::optional< ::Color >(); + } + virtual ::boost::optional< ::Color > getActiveSelectionTextColor() const + { + return ::boost::optional< ::Color >(); + } + virtual ::boost::optional< ::Color > getInactiveSelectionTextColor() const + { + return ::boost::optional< ::Color >(); + } virtual ::boost::optional< ::Color > getTextColor() const { return ::boost::optional< ::Color >(); @@ -487,7 +503,7 @@ namespace svt { namespace table // recalc some model-dependent cached info impl_ni_updateCachedModelValues(); - impl_ni_updateScrollbars(); + impl_ni_relayout(); // completely invalidate m_rAntiImpl.Invalidate(); @@ -535,8 +551,8 @@ namespace svt { namespace table if ( i_first <= m_nCurRow ) goTo( m_nCurColumn, m_nCurRow + insertedRows ); - // adjust scrollbars - impl_ni_updateScrollbars(); + // relayout, since the scrollbar need might have changed + impl_ni_relayout(); // notify A1YY events if ( impl_isAccessibleAlive() ) @@ -545,20 +561,6 @@ namespace svt { namespace table makeAny( AccessibleTableModelChange( AccessibleTableModelChangeType::INSERT, i_first, i_last, 0, m_pModel->getColumnCount() ) ), Any() ); - impl_commitAccessibleEvent( AccessibleEventId::CHILD, - makeAny( m_pAccessibleTable->getTableHeader( TCTYPE_ROWHEADERBAR ) ), - Any() - ); - -// for ( sal_Int32 i = 0 ; i <= m_pModel->getColumnCount(); ++i ) -// { -// impl_commitAccessibleEvent( -// CHILD, -// makeAny( m_pAccessibleTable->getTable() ), -// Any()); -// } - // Huh? What's that? We're notifying |columnCount| CHILD events here, claiming the *table* itself - // has been inserted. Doesn't make much sense, does it? } // schedule repaint @@ -610,13 +612,13 @@ namespace svt { namespace table m_nCurRow = ROW_INVALID; } - // adjust scrollbars - impl_ni_updateScrollbars(); + // relayout, since the scrollbar need might have changed + impl_ni_relayout(); // notify A11Y events if ( impl_isAccessibleAlive() ) { - impl_commitAccessibleEvent( + commitTableEvent( AccessibleEventId::TABLE_MODEL_CHANGED, makeAny( AccessibleTableModelChange( AccessibleTableModelChangeType::DELETE, @@ -641,8 +643,7 @@ namespace svt { namespace table void TableControl_Impl::columnInserted( ColPos const i_colIndex ) { m_nColumnCount = m_pModel->getColumnCount(); - impl_ni_updateColumnWidths(); - impl_ni_updateScrollbars(); + impl_ni_relayout(); m_rAntiImpl.Invalidate(); @@ -653,8 +654,17 @@ namespace svt { namespace table void TableControl_Impl::columnRemoved( ColPos const i_colIndex ) { m_nColumnCount = m_pModel->getColumnCount(); - impl_ni_updateColumnWidths(); - impl_ni_updateScrollbars(); + + // adjust the current column, if it is larger than the column count now + if ( m_nCurColumn >= m_nColumnCount ) + { + if ( m_nColumnCount > 0 ) + goTo( m_nCurColumn - 1, m_nCurRow ); + else + m_nCurColumn = COL_INVALID; + } + + impl_ni_relayout(); m_rAntiImpl.Invalidate(); @@ -665,8 +675,7 @@ namespace svt { namespace table void TableControl_Impl::allColumnsRemoved() { m_nColumnCount = m_pModel->getColumnCount(); - impl_ni_updateColumnWidths(); - impl_ni_updateScrollbars(); + impl_ni_relayout(); m_rAntiImpl.Invalidate(); } @@ -683,11 +692,8 @@ namespace svt { namespace table //------------------------------------------------------------------------------------------------------------------ void TableControl_Impl::tableMetricsChanged() { - long const oldRowHeaderWidthPixel = m_nRowHeaderWidthPixel; impl_ni_updateCachedTableMetrics(); - if ( oldRowHeaderWidthPixel != m_nRowHeaderWidthPixel ) - impl_ni_updateColumnWidths(); - impl_ni_updateScrollbars(); + impl_ni_relayout(); m_rAntiImpl.Invalidate(); } @@ -717,9 +723,8 @@ namespace svt { namespace table { if ( !m_bUpdatingColWidths ) { - impl_ni_updateColumnWidths( i_column ); + impl_ni_relayout( i_column ); invalidate( TableAreaAll ); - impl_ni_updateScrollbars(); } nGroup &= ~COL_ATTRS_WIDTH; @@ -795,67 +800,157 @@ namespace svt { namespace table //------------------------------------------------------------------------------------------------------------------ void TableControl_Impl::impl_ni_updateCachedModelValues() { - m_pInputHandler.reset(); - m_nColumnCount = m_nRowCount = 0; - - impl_ni_updateCachedTableMetrics(); - impl_ni_updateColumnWidths(); - m_pInputHandler = m_pModel->getInputHandler(); if ( !m_pInputHandler ) m_pInputHandler.reset( new DefaultInputHandler ); m_nColumnCount = m_pModel->getColumnCount(); + if ( m_nLeftColumn >= m_nColumnCount ) + m_nLeftColumn = ( m_nColumnCount > 0 ) ? m_nColumnCount - 1 : 0; + m_nRowCount = m_pModel->getRowCount(); + if ( m_nTopRow >= m_nRowCount ) + m_nTopRow = ( m_nRowCount > 0 ) ? m_nRowCount - 1 : 0; + + impl_ni_updateCachedTableMetrics(); } //------------------------------------------------------------------------------------------------------------------ - void TableControl_Impl::impl_ni_updateColumnWidths( ColPos const i_assumeInflexibleColumnsUpToIncluding ) + namespace { - ENSURE_OR_RETURN_VOID( !m_bUpdatingColWidths, "TableControl_Impl::impl_ni_updateColumnWidths: recursive call detected!" ); + //.............................................................................................................. + /// determines whether a scrollbar is needed for the given values + bool lcl_determineScrollbarNeed( long const i_position, ScrollbarVisibility const i_visibility, + long const i_availableSpace, long const i_neededSpace ) + { + if ( i_visibility == ScrollbarShowNever ) + return false; + if ( i_visibility == ScrollbarShowAlways ) + return true; + if ( i_position > 0 ) + return true; + if ( i_availableSpace >= i_neededSpace ) + return false; + return true; + } - m_aColumnWidths.resize( 0 ); - if ( !m_pModel ) - return; + //.............................................................................................................. + void lcl_setButtonRepeat( Window& _rWindow, sal_uLong _nDelay ) + { + AllSettings aSettings = _rWindow.GetSettings(); + MouseSettings aMouseSettings = aSettings.GetMouseSettings(); - const TableSize colCount = m_pModel->getColumnCount(); - if ( colCount == 0 ) - return; + aMouseSettings.SetButtonRepeat( _nDelay ); + aSettings.SetMouseSettings( aMouseSettings ); - m_bUpdatingColWidths = true; - const ::comphelper::FlagGuard aWidthUpdateFlag( m_bUpdatingColWidths ); + _rWindow.SetSettings( aSettings, sal_True ); + } - m_aColumnWidths.reserve( colCount ); + //.............................................................................................................. + bool lcl_updateScrollbar( Window& _rParent, ScrollBar*& _rpBar, + bool const i_needBar, long _nVisibleUnits, + long _nPosition, long _nLineSize, long _nRange, + bool _bHorizontal, const Link& _rScrollHandler ) + { + // do we currently have the scrollbar? + bool bHaveBar = _rpBar != NULL; + + // do we need to correct the scrollbar visibility? + if ( bHaveBar && !i_needBar ) + { + if ( _rpBar->IsTracking() ) + _rpBar->EndTracking(); + DELETEZ( _rpBar ); + } + else if ( !bHaveBar && i_needBar ) + { + _rpBar = new ScrollBar( + &_rParent, + WB_DRAG | ( _bHorizontal ? WB_HSCROLL : WB_VSCROLL ) + ); + _rpBar->SetScrollHdl( _rScrollHandler ); + // get some speed into the scrolling .... + lcl_setButtonRepeat( *_rpBar, 0 ); + } + + if ( _rpBar ) + { + _rpBar->SetRange( Range( 0, _nRange ) ); + _rpBar->SetVisibleSize( _nVisibleUnits ); + _rpBar->SetPageSize( _nVisibleUnits ); + _rpBar->SetLineSize( _nLineSize ); + _rpBar->SetThumbPos( _nPosition ); + _rpBar->Show(); + } + + return ( bHaveBar != i_needBar ); + } + //.............................................................................................................. + /** returns the number of rows fitting into the given range, + for the given row height. Partially fitting rows are counted, too, if the + respective parameter says so. + */ + TableSize lcl_getRowsFittingInto( long _nOverallHeight, long _nRowHeightPixel, bool _bAcceptPartialRow = false ) + { + return _bAcceptPartialRow + ? ( _nOverallHeight + ( _nRowHeightPixel - 1 ) ) / _nRowHeightPixel + : _nOverallHeight / _nRowHeightPixel; + } + + //.............................................................................................................. + /** returns the number of columns fitting into the given area, + with the first visible column as given. Partially fitting columns are counted, too, + if the respective parameter says so. + */ + TableSize lcl_getColumnsVisibleWithin( const Rectangle& _rArea, ColPos _nFirstVisibleColumn, + const TableControl_Impl& _rControl, bool _bAcceptPartialRow ) + { + TableSize visibleColumns = 0; + TableColumnGeometry aColumn( _rControl, _rArea, _nFirstVisibleColumn ); + while ( aColumn.isValid() ) + { + if ( !_bAcceptPartialRow ) + if ( aColumn.getRect().Right() > _rArea.Right() ) + // this column is only partially visible, and this is not allowed + break; + + aColumn.moveRight(); + ++visibleColumns; + } + return visibleColumns; + } + + } + + //------------------------------------------------------------------------------------------------------------------ + long TableControl_Impl::impl_ni_calculateColumnWidths( ColPos const i_assumeInflexibleColumnsUpToIncluding, + bool const i_assumeVerticalScrollbar, ::std::vector< long >& o_newColWidthsPixel ) const + { // the available horizontal space long gridWidthPixel = m_rAntiImpl.GetOutputSizePixel().Width(); + ENSURE_OR_RETURN( !!m_pModel, "TableControl_Impl::impl_ni_calculateColumnWidths: not allowed without a model!", gridWidthPixel ); if ( m_pModel->hasRowHeaders() && ( gridWidthPixel != 0 ) ) { gridWidthPixel -= m_nRowHeaderWidthPixel; } - if ( m_pModel->getVerticalScrollbarVisibility() != ScrollbarShowNever ) + + if ( i_assumeVerticalScrollbar && ( m_pModel->getVerticalScrollbarVisibility() != ScrollbarShowNever ) ) { long nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize(); gridWidthPixel -= nScrollbarMetrics; } - // TODO: shouldn't we take the visibility of the vertical scroll bar into account here, too? - long const gridWidthAppFont = m_rAntiImpl.PixelToLogic( Size( gridWidthPixel, 0 ), MAP_APPFONT ).Width(); - - // determine the accumulated current width of all columns - for ( ColPos col = 0; col < colCount; ++col ) - { - const PColumnModel pColumn = m_pModel->getColumnModel( col ); - ENSURE_OR_THROW( !!pColumn, "invalid column returned by the model!" ); - - } + // no need to do anything without columns + TableSize const colCount = m_pModel->getColumnCount(); + if ( colCount == 0 ) + return gridWidthPixel; // collect some meta data for our columns: - // - their current (appt-font) metrics + // - their current (pixel) metrics long accumulatedCurrentWidth = 0; ::std::vector< long > currentColWidths; currentColWidths.reserve( colCount ); - // - their effective minimal and maximal width (app-font!) typedef ::std::vector< ::std::pair< long, long > > ColumnLimits; ColumnLimits effectiveColumnLimits; effectiveColumnLimits.reserve( colCount ); @@ -865,13 +960,14 @@ namespace svt { namespace table ::std::vector< ::sal_Int32 > columnFlexibilities; columnFlexibilities.reserve( colCount ); long flexibilityDenominator = 0; + size_t flexibleColumnCount = 0; for ( ColPos col = 0; col < colCount; ++col ) { PColumnModel const pColumn = m_pModel->getColumnModel( col ); ENSURE_OR_THROW( !!pColumn, "invalid column returned by the model!" ); // current width - TableMetrics const currentWidth = pColumn->getWidth(); + long const currentWidth = appFontWidthToPixel( pColumn->getWidth() ); currentColWidths.push_back( currentWidth ); // accumulated width @@ -879,7 +975,7 @@ namespace svt { namespace table // flexibility ::sal_Int32 flexibility = pColumn->getFlexibility(); - OSL_ENSURE( flexibility >= 0, "TableControl_Impl::impl_ni_updateColumnWidths: a column's flexibility should be non-negative." ); + OSL_ENSURE( flexibility >= 0, "TableControl_Impl::impl_ni_calculateColumnWidths: a column's flexibility should be non-negative." ); if ( ( flexibility < 0 ) // normalization || ( !pColumn->isResizable() ) // column not resizeable => no auto-resize || ( col <= i_assumeInflexibleColumnsUpToIncluding ) // column shall be treated as inflexible => respec this @@ -891,18 +987,18 @@ namespace svt { namespace table // if the column is not flexible, it will not be asked for min/max, but we assume the current width as limit then if ( flexibility > 0 ) { - long const minWidth = pColumn->getMinWidth(); + long const minWidth = appFontWidthToPixel( pColumn->getMinWidth() ); if ( minWidth > 0 ) effectiveMin = minWidth; else effectiveMin = MIN_COLUMN_WIDTH_PIXEL; - long const maxWidth = pColumn->getMaxWidth(); - OSL_ENSURE( minWidth <= maxWidth, "TableControl_Impl::impl_ni_updateColumnWidths: pretty undecided 'bout its width limits, this column!" ); + long const maxWidth = appFontWidthToPixel( pColumn->getMaxWidth() ); + OSL_ENSURE( minWidth <= maxWidth, "TableControl_Impl::impl_ni_calculateColumnWidths: pretty undecided 'bout its width limits, this column!" ); if ( ( maxWidth > 0 ) && ( maxWidth >= minWidth ) ) effectiveMax = maxWidth; else - effectiveMax = gridWidthAppFont; // TODO: any better guess here? + effectiveMax = gridWidthPixel; // TODO: any better guess here? if ( effectiveMin == effectiveMax ) // if the min and the max are identical, this implies no flexibility at all @@ -911,27 +1007,29 @@ namespace svt { namespace table columnFlexibilities.push_back( flexibility ); flexibilityDenominator += flexibility; + if ( flexibility > 0 ) + ++flexibleColumnCount; effectiveColumnLimits.push_back( ::std::pair< long, long >( effectiveMin, effectiveMax ) ); accumulatedMinWidth += effectiveMin; accumulatedMaxWidth += effectiveMax; } - ::std::vector< long > newWidths( currentColWidths ); + o_newColWidthsPixel = currentColWidths; if ( flexibilityDenominator == 0 ) { // no column is flexible => don't adjust anything } - else if ( gridWidthAppFont > accumulatedCurrentWidth ) + else if ( gridWidthPixel > accumulatedCurrentWidth ) { // we have space to give away ... - long distributeAppFontUnits = gridWidthAppFont - accumulatedCurrentWidth; - if ( gridWidthAppFont > accumulatedMaxWidth ) + long distributePixel = gridWidthPixel - accumulatedCurrentWidth; + if ( gridWidthPixel > accumulatedMaxWidth ) { // ... but the column's maximal widths are still less than we have // => set them all to max for ( size_t i = 0; i < size_t( colCount ); ++i ) { - newWidths[i] = effectiveColumnLimits[i].second; + o_newColWidthsPixel[i] = effectiveColumnLimits[i].second; } } else @@ -941,13 +1039,13 @@ namespace svt { namespace table { startOver = false; // distribute the remaining space amongst all columns with a positive flexibility - for ( size_t i=0; i<newWidths.size() && !startOver; ++i ) + for ( size_t i=0; i<o_newColWidthsPixel.size() && !startOver; ++i ) { long const columnFlexibility = columnFlexibilities[i]; if ( columnFlexibility == 0 ) continue; - long newColWidth = currentColWidths[i] + columnFlexibility * distributeAppFontUnits / flexibilityDenominator; + long newColWidth = currentColWidths[i] + columnFlexibility * distributePixel / flexibilityDenominator; if ( newColWidth > effectiveColumnLimits[i].second ) { // that was too much, we hit the col's maximum @@ -956,9 +1054,10 @@ namespace svt { namespace table // adjust the flexibility denominator ... flexibilityDenominator -= columnFlexibility; columnFlexibilities[i] = 0; + --flexibleColumnCount; // ... and the remaining width ... long const difference = newColWidth - currentColWidths[i]; - distributeAppFontUnits -= difference; + distributePixel -= difference; // ... this way, we ensure that the width not taken up by this column is consumed by the other // flexible ones (if there are some) @@ -967,22 +1066,47 @@ namespace svt { namespace table startOver = true; } - newWidths[i] = newColWidth; + o_newColWidthsPixel[i] = newColWidth; } } while ( startOver ); + + // are there pixels left (might be caused by rounding errors)? + distributePixel = gridWidthPixel - ::std::accumulate( o_newColWidthsPixel.begin(), o_newColWidthsPixel.end(), 0 ); + while ( ( distributePixel > 0 ) && ( flexibleColumnCount > 0 ) ) + { + // yes => ignore relative flexibilities, and subsequently distribute single pixels to all flexible + // columns which did not yet reach their maximum. + for ( size_t i=0; ( i < o_newColWidthsPixel.size() ) && ( distributePixel > 0 ); ++i ) + { + if ( columnFlexibilities[i] == 0 ) + continue; + + OSL_ENSURE( o_newColWidthsPixel[i] <= effectiveColumnLimits[i].second, + "TableControl_Impl::impl_ni_calculateColumnWidths: inconsitency!" ); + if ( o_newColWidthsPixel[i] >= effectiveColumnLimits[i].first ) + { + columnFlexibilities[i] = 0; + --flexibleColumnCount; + continue; + } + + ++o_newColWidthsPixel[i]; + --distributePixel; + } + } } } - else if ( gridWidthAppFont < accumulatedCurrentWidth ) + else if ( gridWidthPixel < accumulatedCurrentWidth ) { // we need to take away some space from the columns which allow it ... - long takeAwayAppFontUnits = accumulatedCurrentWidth - gridWidthAppFont; - if ( gridWidthAppFont < accumulatedMinWidth ) + long takeAwayPixel = accumulatedCurrentWidth - gridWidthPixel; + if ( gridWidthPixel < accumulatedMinWidth ) { // ... but the column's minimal widths are still more than we have // => set them all to min for ( size_t i = 0; i < size_t( colCount ); ++i ) { - newWidths[i] = effectiveColumnLimits[i].first; + o_newColWidthsPixel[i] = effectiveColumnLimits[i].first; } } else @@ -992,13 +1116,13 @@ namespace svt { namespace table { startOver = false; // take away the space we need from the columns with a positive flexibility - for ( size_t i=0; i<newWidths.size() && !startOver; ++i ) + for ( size_t i=0; i<o_newColWidthsPixel.size() && !startOver; ++i ) { long const columnFlexibility = columnFlexibilities[i]; if ( columnFlexibility == 0 ) continue; - long newColWidth = currentColWidths[i] - columnFlexibility * takeAwayAppFontUnits / flexibilityDenominator; + long newColWidth = currentColWidths[i] - columnFlexibility * takeAwayPixel / flexibilityDenominator; if ( newColWidth < effectiveColumnLimits[i].first ) { // that was too much, we hit the col's minimum @@ -1007,172 +1131,79 @@ namespace svt { namespace table // adjust the flexibility denominator ... flexibilityDenominator -= columnFlexibility; columnFlexibilities[i] = 0; + --flexibleColumnCount; // ... and the remaining width ... long const difference = currentColWidths[i] - newColWidth; - takeAwayAppFontUnits -= difference; + takeAwayPixel -= difference; // and start over with the first column, since there might be earlier columns which need // to be recalculated now startOver = true; } - newWidths[i] = newColWidth; + o_newColWidthsPixel[i] = newColWidth; } } while ( startOver ); - } - } - // now that we have calculated the app-font widths, get the actual pixels - long accumulatedWidthPixel = m_nRowHeaderWidthPixel; - for ( ColPos col = 0; col < colCount; ++col ) - { - long const colWidth = m_rAntiImpl.LogicToPixel( Size( newWidths[col], 0 ), MAP_APPFONT ).Width(); - const long columnStart = accumulatedWidthPixel; - const long columnEnd = columnStart + colWidth; - m_aColumnWidths.push_back( MutableColumnMetrics( columnStart, columnEnd ) ); - accumulatedWidthPixel = columnEnd; - - // and don't forget to forward this to the column models - PColumnModel const pColumn = m_pModel->getColumnModel( col ); - ENSURE_OR_THROW( !!pColumn, "invalid column returned by the model!" ); - pColumn->setWidth( newWidths[col] ); - } + // are there pixels left (might be caused by rounding errors)? + takeAwayPixel = ::std::accumulate( o_newColWidthsPixel.begin(), o_newColWidthsPixel.end(), 0 ) - gridWidthPixel; + while ( ( takeAwayPixel > 0 ) && ( flexibleColumnCount > 0 ) ) + { + // yes => ignore relative flexibilities, and subsequently take away pixels from all flexible + // columns which did not yet reach their minimum. + for ( size_t i=0; ( i < o_newColWidthsPixel.size() ) && ( takeAwayPixel > 0 ); ++i ) + { + if ( columnFlexibilities[i] == 0 ) + continue; - // if the column resizing happened to leave some space at the right, but there are columns - // scrolled out to the left, scroll them in - while ( ( m_nLeftColumn > 0 ) - && ( accumulatedWidthPixel - m_aColumnWidths[ m_nLeftColumn - 1 ].getStart() <= gridWidthPixel ) - ) - { - --m_nLeftColumn; - } + OSL_ENSURE( o_newColWidthsPixel[i] >= effectiveColumnLimits[i].first, + "TableControl_Impl::impl_ni_calculateColumnWidths: inconsitency!" ); + if ( o_newColWidthsPixel[i] <= effectiveColumnLimits[i].first ) + { + columnFlexibilities[i] = 0; + --flexibleColumnCount; + continue; + } - // now adjust the column metrics, since they currently ignore the horizontal scroll position - if ( m_nLeftColumn > 0 ) - { - const long offsetPixel = m_aColumnWidths[ 0 ].getStart() - m_aColumnWidths[ m_nLeftColumn ].getStart(); - for ( ColumnPositions::iterator colPos = m_aColumnWidths.begin(); - colPos != m_aColumnWidths.end(); - ++colPos - ) - { - colPos->move( offsetPixel ); + --o_newColWidthsPixel[i]; + --takeAwayPixel; + } + } } } + + return gridWidthPixel; } //------------------------------------------------------------------------------------------------------------------ - namespace + void TableControl_Impl::impl_ni_relayout( ColPos const i_assumeInflexibleColumnsUpToIncluding ) { - //.............................................................................................................. - /// determines whether a scrollbar is needed for the given values - bool lcl_determineScrollbarNeed( long const i_position, ScrollbarVisibility const i_visibility, - long const i_availableSpace, long const i_neededSpace ) - { - if ( i_visibility == ScrollbarShowNever ) - return false; - if ( i_visibility == ScrollbarShowAlways ) - return true; - if ( i_position > 0 ) - return true; - if ( i_availableSpace >= i_neededSpace ) - return false; - return true; - } - - //.............................................................................................................. - void lcl_setButtonRepeat( Window& _rWindow, sal_uLong _nDelay ) - { - AllSettings aSettings = _rWindow.GetSettings(); - MouseSettings aMouseSettings = aSettings.GetMouseSettings(); - - aMouseSettings.SetButtonRepeat( _nDelay ); - aSettings.SetMouseSettings( aMouseSettings ); - - _rWindow.SetSettings( aSettings, sal_True ); - } - - //.............................................................................................................. - void lcl_updateScrollbar( Window& _rParent, ScrollBar*& _rpBar, - bool const i_needBar, long _nVisibleUnits, - long _nPosition, long _nLineSize, long _nRange, - bool _bHorizontal, const Link& _rScrollHandler ) - { - // do we currently have the scrollbar? - bool bHaveBar = _rpBar != NULL; - - // do we need to correct the scrollbar visibility? - if ( bHaveBar && !i_needBar ) - { - if ( _rpBar->IsTracking() ) - _rpBar->EndTracking(); - DELETEZ( _rpBar ); - } - else if ( !bHaveBar && i_needBar ) - { - _rpBar = new ScrollBar( - &_rParent, - WB_DRAG | ( _bHorizontal ? WB_HSCROLL : WB_VSCROLL ) - ); - _rpBar->SetScrollHdl( _rScrollHandler ); - // get some speed into the scrolling .... - lcl_setButtonRepeat( *_rpBar, 0 ); - } - - if ( _rpBar ) - { - _rpBar->SetRange( Range( 0, _nRange ) ); - _rpBar->SetVisibleSize( _nVisibleUnits ); - _rpBar->SetPageSize( _nVisibleUnits ); - _rpBar->SetLineSize( _nLineSize ); - _rpBar->SetThumbPos( _nPosition ); - _rpBar->Show(); - } - } - - //.............................................................................................................. - /** returns the number of rows fitting into the given range, - for the given row height. Partially fitting rows are counted, too, if the - respective parameter says so. - */ - TableSize lcl_getRowsFittingInto( long _nOverallHeight, long _nRowHeightPixel, bool _bAcceptPartialRow = false ) - { - return _bAcceptPartialRow - ? ( _nOverallHeight + ( _nRowHeightPixel - 1 ) ) / _nRowHeightPixel - : _nOverallHeight / _nRowHeightPixel; - } - - //.............................................................................................................. - /** returns the number of columns fitting into the given area, - with the first visible column as given. Partially fitting columns are counted, too, - if the respective parameter says so. - */ - TableSize lcl_getColumnsVisibleWithin( const Rectangle& _rArea, ColPos _nFirstVisibleColumn, - const TableControl_Impl& _rControl, bool _bAcceptPartialRow ) - { - TableSize visibleColumns = 0; - TableColumnGeometry aColumn( _rControl, _rArea, _nFirstVisibleColumn ); - while ( aColumn.isValid() ) - { - if ( !_bAcceptPartialRow ) - if ( aColumn.getRect().Right() > _rArea.Right() ) - // this column is only partially visible, and this is not allowed - break; + ENSURE_OR_RETURN_VOID( !m_bUpdatingColWidths, "TableControl_Impl::impl_ni_relayout: recursive call detected!" ); - aColumn.moveRight(); - ++visibleColumns; - } - return visibleColumns; - } - - } + m_aColumnWidths.resize( 0 ); + if ( !m_pModel ) + return; - //------------------------------------------------------------------------------------------------------------------ - void TableControl_Impl::impl_ni_updateScrollbars() - { + ::comphelper::FlagRestorationGuard const aWidthUpdateFlag( m_bUpdatingColWidths, true ); SuppressCursor aHideCursor( *this ); + // layouting steps: + // + // 1. adjust column widths, leaving space for a vertical scrollbar + // 2. determine need for a vertical scrollbar + // - V-YES: all fine, result from 1. is still valid + // - V-NO: result from 1. is still under consideration + // + // 3. determine need for a horizontal scrollbar + // - H-NO: all fine, result from 2. is still valid + // - H-YES: reconsider need for a vertical scrollbar, if result of 2. was V-NO + // - V-YES: all fine, result from 1. is still valid + // - V-NO: redistribute the remaining space (if any) amongst all columns which allow it + + ::std::vector< long > newWidthsPixel; + long gridWidthPixel = impl_ni_calculateColumnWidths( i_assumeInflexibleColumnsUpToIncluding, true, newWidthsPixel ); + // the width/height of a scrollbar, needed several times below long const nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize(); @@ -1181,18 +1212,13 @@ namespace svt { namespace table Rectangle aDataCellPlayground( Point( 0, 0 ), m_rAntiImpl.GetOutputSizePixel() ); aDataCellPlayground.Left() = m_nRowHeaderWidthPixel; aDataCellPlayground.Top() = m_nColHeaderHeightPixel; - m_nRowCount = m_pModel->getRowCount(); - m_nColumnCount = m_pModel->getColumnCount(); - if ( m_aColumnWidths.empty() ) - impl_ni_updateColumnWidths(); - OSL_ENSURE( m_aColumnWidths.size() == size_t( m_nColumnCount ), "TableControl_Impl::impl_ni_updateScrollbars: inconsistency!" ); - const long nAllColumnsWidth = m_aColumnWidths.empty() - ? 0 - : m_aColumnWidths[ m_nColumnCount - 1 ].getEnd() - m_aColumnWidths[ 0 ].getStart(); + OSL_ENSURE( ( m_nRowCount == m_pModel->getRowCount() ) && ( m_nColumnCount == m_pModel->getColumnCount() ), + "TableControl_Impl::impl_ni_relayout: how is this expected to work with invalid data?" ); + long const nAllColumnsWidth = ::std::accumulate( newWidthsPixel.begin(), newWidthsPixel.end(), 0 ); - const ScrollbarVisibility eVertScrollbar = m_pModel->getVerticalScrollbarVisibility(); - const ScrollbarVisibility eHorzScrollbar = m_pModel->getHorizontalScrollbarVisibility(); + ScrollbarVisibility const eVertScrollbar = m_pModel->getVerticalScrollbarVisibility(); + ScrollbarVisibility const eHorzScrollbar = m_pModel->getHorizontalScrollbarVisibility(); // do we need a vertical scrollbar? bool bNeedVerticalScrollbar = lcl_determineScrollbarNeed( @@ -1203,8 +1229,10 @@ namespace svt { namespace table aDataCellPlayground.Right() -= nScrollbarMetrics; bFirstRoundVScrollNeed = true; } + // do we need a horizontal scrollbar? - const bool bNeedHorizontalScrollbar = lcl_determineScrollbarNeed( m_nLeftColumn, eHorzScrollbar, aDataCellPlayground.GetWidth(), nAllColumnsWidth ); + bool const bNeedHorizontalScrollbar = lcl_determineScrollbarNeed( + m_nLeftColumn, eHorzScrollbar, aDataCellPlayground.GetWidth(), nAllColumnsWidth ); if ( bNeedHorizontalScrollbar ) { aDataCellPlayground.Bottom() -= nScrollbarMetrics; @@ -1223,12 +1251,77 @@ namespace svt { namespace table } } } + + // the initial call to impl_ni_calculateColumnWidths assumed that we need a vertical scrollbar. If, by now, + // we know that this is not the case, re-calculate the column widths. + if ( !bNeedVerticalScrollbar ) + gridWidthPixel = impl_ni_calculateColumnWidths( i_assumeInflexibleColumnsUpToIncluding, false, newWidthsPixel ); + + // update the column objects with the new widths we finally calculated + TableSize const colCount = m_pModel->getColumnCount(); + m_aColumnWidths.reserve( colCount ); + long accumulatedWidthPixel = m_nRowHeaderWidthPixel; + bool anyColumnWidthChanged = false; + for ( ColPos col = 0; col < colCount; ++col ) + { + const long columnStart = accumulatedWidthPixel; + const long columnEnd = columnStart + newWidthsPixel[col]; + m_aColumnWidths.push_back( MutableColumnMetrics( columnStart, columnEnd ) ); + accumulatedWidthPixel = columnEnd; + + // and don't forget to forward this to the column models + PColumnModel const pColumn = m_pModel->getColumnModel( col ); + ENSURE_OR_THROW( !!pColumn, "invalid column returned by the model!" ); + + long const oldColumnWidthAppFont = pColumn->getWidth(); + long const newColumnWidthAppFont = pixelWidthToAppFont( newWidthsPixel[col] ); + pColumn->setWidth( newColumnWidthAppFont ); + + anyColumnWidthChanged |= ( oldColumnWidthAppFont != newColumnWidthAppFont ); + } + + // if the column widths changed, ensure everything is repainted + if ( anyColumnWidthChanged ) + invalidate( TableAreaAll ); + + // if the column resizing happened to leave some space at the right, but there are columns + // scrolled out to the left, scroll them in + while ( ( m_nLeftColumn > 0 ) + && ( accumulatedWidthPixel - m_aColumnWidths[ m_nLeftColumn - 1 ].getStart() <= gridWidthPixel ) + ) + { + --m_nLeftColumn; + } + + // now adjust the column metrics, since they currently ignore the horizontal scroll position + if ( m_nLeftColumn > 0 ) + { + const long offsetPixel = m_aColumnWidths[ 0 ].getStart() - m_aColumnWidths[ m_nLeftColumn ].getStart(); + for ( ColumnPositions::iterator colPos = m_aColumnWidths.begin(); + colPos != m_aColumnWidths.end(); + ++colPos + ) + { + colPos->move( offsetPixel ); + } + } + + // show or hide the scrollbars as needed, and position the data window + impl_ni_positionChildWindows( aDataCellPlayground, bNeedVerticalScrollbar, bNeedHorizontalScrollbar ); + } + + //------------------------------------------------------------------------------------------------------------------ + void TableControl_Impl::impl_ni_positionChildWindows( Rectangle const & i_dataCellPlayground, + bool const i_verticalScrollbar, bool const i_horizontalScrollbar ) + { + long const nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize(); + // create or destroy the vertical scrollbar, as needed lcl_updateScrollbar( m_rAntiImpl, m_pVScroll, - bNeedVerticalScrollbar, - lcl_getRowsFittingInto( aDataCellPlayground.GetHeight(), m_nRowHeightPixel ), + i_verticalScrollbar, + lcl_getRowsFittingInto( i_dataCellPlayground.GetHeight(), m_nRowHeightPixel ), // visible units m_nTopRow, // current position 1, // line size @@ -1236,12 +1329,13 @@ namespace svt { namespace table false, // vertical LINK( this, TableControl_Impl, OnScroll ) // scroll handler ); + // position it if ( m_pVScroll ) { Rectangle aScrollbarArea( - Point( aDataCellPlayground.Right() + 1, 0 ), - Size( nScrollbarMetrics, aDataCellPlayground.Bottom() + 1 ) + Point( i_dataCellPlayground.Right() + 1, 0 ), + Size( nScrollbarMetrics, i_dataCellPlayground.Bottom() + 1 ) ); m_pVScroll->SetPosSizePixel( aScrollbarArea.TopLeft(), aScrollbarArea.GetSize() ); @@ -1251,8 +1345,8 @@ namespace svt { namespace table lcl_updateScrollbar( m_rAntiImpl, m_pHScroll, - bNeedHorizontalScrollbar, - lcl_getColumnsVisibleWithin( aDataCellPlayground, m_nLeftColumn, *this, false ), + i_horizontalScrollbar, + lcl_getColumnsVisibleWithin( i_dataCellPlayground, m_nLeftColumn, *this, false ), // visible units m_nLeftColumn, // current position 1, // line size @@ -1260,22 +1354,23 @@ namespace svt { namespace table true, // horizontal LINK( this, TableControl_Impl, OnScroll ) // scroll handler ); + // position it if ( m_pHScroll ) { - TableSize const nVisibleUnits = lcl_getColumnsVisibleWithin( aDataCellPlayground, m_nLeftColumn, *this, false ); + TableSize const nVisibleUnits = lcl_getColumnsVisibleWithin( i_dataCellPlayground, m_nLeftColumn, *this, false ); TableMetrics const nRange = m_nColumnCount; if( m_nLeftColumn + nVisibleUnits == nRange - 1 ) { - if ( m_aColumnWidths[ nRange - 1 ].getStart() - m_aColumnWidths[ m_nLeftColumn ].getEnd() + m_aColumnWidths[ nRange-1 ].getWidth() > aDataCellPlayground.GetWidth() ) + if ( m_aColumnWidths[ nRange - 1 ].getStart() - m_aColumnWidths[ m_nLeftColumn ].getEnd() + m_aColumnWidths[ nRange-1 ].getWidth() > i_dataCellPlayground.GetWidth() ) { m_pHScroll->SetVisibleSize( nVisibleUnits -1 ); m_pHScroll->SetPageSize( nVisibleUnits - 1 ); } } Rectangle aScrollbarArea( - Point( 0, aDataCellPlayground.Bottom() + 1 ), - Size( aDataCellPlayground.Right() + 1, nScrollbarMetrics ) + Point( 0, i_dataCellPlayground.Bottom() + 1 ), + Size( i_dataCellPlayground.Right() + 1, nScrollbarMetrics ) ); m_pHScroll->SetPosSizePixel( aScrollbarArea.TopLeft(), aScrollbarArea.GetSize() ); @@ -1292,19 +1387,19 @@ namespace svt { namespace table { m_pScrollCorner = new ScrollBarBox( &m_rAntiImpl ); m_pScrollCorner->SetSizePixel( Size( nScrollbarMetrics, nScrollbarMetrics ) ); - m_pScrollCorner->SetPosPixel( Point( aDataCellPlayground.Right() + 1, aDataCellPlayground.Bottom() + 1 ) ); + m_pScrollCorner->SetPosPixel( Point( i_dataCellPlayground.Right() + 1, i_dataCellPlayground.Bottom() + 1 ) ); m_pScrollCorner->Show(); } else if(bHaveScrollCorner && bNeedScrollCorner) { - m_pScrollCorner->SetPosPixel( Point( aDataCellPlayground.Right() + 1, aDataCellPlayground.Bottom() + 1 ) ); + m_pScrollCorner->SetPosPixel( Point( i_dataCellPlayground.Right() + 1, i_dataCellPlayground.Bottom() + 1 ) ); m_pScrollCorner->Show(); } // resize the data window m_pDataWindow->SetSizePixel( Size( - aDataCellPlayground.GetWidth() + m_nRowHeaderWidthPixel, - aDataCellPlayground.GetHeight() + m_nColHeaderHeightPixel + i_dataCellPlayground.GetWidth() + m_nRowHeaderWidthPixel, + i_dataCellPlayground.GetHeight() + m_nColHeaderHeightPixel ) ); } @@ -1313,8 +1408,7 @@ namespace svt { namespace table { DBG_CHECK_ME(); - impl_ni_updateColumnWidths(); - impl_ni_updateScrollbars(); + impl_ni_relayout(); checkCursorPosition(); } @@ -1408,14 +1502,14 @@ namespace svt { namespace table if ( _rUpdateRect.GetIntersection( aRowIterator.getRect() ).IsEmpty() ) continue; - bool const isActiveRow = ( aRowIterator.getRow() == getCurrentRow() ); + bool const isControlFocused = m_rAntiImpl.HasControlFocus(); bool const isSelectedRow = isRowSelected( aRowIterator.getRow() ); Rectangle const aRect = aRowIterator.getRect().GetIntersection( aAllDataCellsArea ); // give the redenderer a chance to prepare the row pRenderer->PrepareRow( - aRowIterator.getRow(), isActiveRow, isSelectedRow, + aRowIterator.getRow(), isControlFocused, isSelectedRow, *m_pDataWindow, aRect, rStyle ); @@ -1423,7 +1517,7 @@ namespace svt { namespace table if ( m_pModel->hasRowHeaders() ) { const Rectangle aCurrentRowHeader( aRowHeaderArea.GetIntersection( aRowIterator.getRect() ) ); - pRenderer->PaintRowHeader( isActiveRow, isSelectedRow, *m_pDataWindow, aCurrentRowHeader, + pRenderer->PaintRowHeader( isControlFocused, isSelectedRow, *m_pDataWindow, aCurrentRowHeader, rStyle ); } @@ -1437,7 +1531,7 @@ namespace svt { namespace table ) { bool isSelectedColumn = false; - pRenderer->PaintCell( aCell.getColumn(), isSelectedRow || isSelectedColumn, isActiveRow, + pRenderer->PaintCell( aCell.getColumn(), isSelectedRow || isSelectedColumn, isControlFocused, *m_pDataWindow, aCell.getRect(), rStyle ); } } @@ -1469,30 +1563,25 @@ namespace svt { namespace table bool bSuccess = false; bool selectionChanged = false; - Rectangle rCells; switch ( _eAction ) { case cursorDown: - if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION) + if ( m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION ) { //if other rows already selected, deselect them - if(m_aSelectedRows.size()>0) + if ( m_aSelectedRows.size()>0 ) { - for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin(); - it!=m_aSelectedRows.end();++it) - { - invalidateSelectedRegion(*it, *it, rCells); - } + invalidateSelectedRows(); m_aSelectedRows.clear(); } - if(m_nCurRow < m_nRowCount-1) + if ( m_nCurRow < m_nRowCount-1 ) { ++m_nCurRow; m_aSelectedRows.push_back(m_nCurRow); } else m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); ensureVisible(m_nCurColumn,m_nCurRow,false); selectionChanged = true; bSuccess = true; @@ -1509,23 +1598,19 @@ namespace svt { namespace table { if(m_aSelectedRows.size()>0) { - for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin(); - it!=m_aSelectedRows.end();++it) - { - invalidateSelectedRegion(*it, *it, rCells); - } + invalidateSelectedRows(); m_aSelectedRows.clear(); } if(m_nCurRow>0) { --m_nCurRow; m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); } else { m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); } ensureVisible(m_nCurColumn,m_nCurRow,false); selectionChanged = true; @@ -1607,7 +1692,7 @@ namespace svt { namespace table //else select the row->put it in the vector else m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); selectionChanged = true; bSuccess = true; } @@ -1630,14 +1715,10 @@ namespace svt { namespace table //and select the current row if(m_nAnchor==-1) { - for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin(); - it!=m_aSelectedRows.end();++it) - { - invalidateSelectedRegion(*it, *it, rCells); - } + invalidateSelectedRows(); m_aSelectedRows.clear(); m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); } else { @@ -1655,12 +1736,12 @@ namespace svt { namespace table if(nextRow>-1 && m_aSelectedRows[nextRow] == m_nCurRow) { m_aSelectedRows.erase(m_aSelectedRows.begin()+prevRow); - invalidateSelectedRegion(m_nCurRow+1, m_nCurRow+1, rCells); + invalidateRow( m_nCurRow + 1 ); } else { m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); } } else @@ -1670,7 +1751,7 @@ namespace svt { namespace table m_aSelectedRows.push_back(m_nCurRow); m_nCurRow--; m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow+1, m_nCurRow, rCells); + invalidateSelectedRegion( m_nCurRow+1, m_nCurRow ); } } } @@ -1685,12 +1766,12 @@ namespace svt { namespace table m_aSelectedRows.push_back(m_nCurRow); m_nCurRow--; m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow+1, m_nCurRow, rCells); + invalidateSelectedRegion( m_nCurRow+1, m_nCurRow ); } else { m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); } } m_pSelEngine->SetAnchor(sal_True); @@ -1717,14 +1798,10 @@ namespace svt { namespace table //and select the current row if(m_nAnchor==-1) { - for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin(); - it!=m_aSelectedRows.end();++it) - { - invalidateSelectedRegion(*it, *it, rCells); - } + invalidateSelectedRows(); m_aSelectedRows.clear(); m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); } else { @@ -1742,12 +1819,12 @@ namespace svt { namespace table if(nextRow>-1 && m_aSelectedRows[nextRow] == m_nCurRow) { m_aSelectedRows.erase(m_aSelectedRows.begin()+prevRow); - invalidateSelectedRegion(m_nCurRow-1, m_nCurRow-1, rCells); + invalidateRow( m_nCurRow - 1 ); } else { m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); } } else @@ -1757,7 +1834,7 @@ namespace svt { namespace table m_aSelectedRows.push_back(m_nCurRow); m_nCurRow++; m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow-1, m_nCurRow, rCells); + invalidateSelectedRegion( m_nCurRow-1, m_nCurRow ); } } } @@ -1770,12 +1847,12 @@ namespace svt { namespace table m_aSelectedRows.push_back(m_nCurRow); m_nCurRow++; m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow-1, m_nCurRow, rCells); + invalidateSelectedRegion( m_nCurRow-1, m_nCurRow ); } else { m_aSelectedRows.push_back(m_nCurRow); - invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells); + invalidateRow( m_nCurRow ); } } m_pSelEngine->SetAnchor(sal_True); @@ -1797,7 +1874,7 @@ namespace svt { namespace table { //select the region between the current and the upper row RowPos iter = m_nCurRow; - invalidateSelectedRegion(m_nCurRow, 0, rCells); + invalidateSelectedRegion( m_nCurRow, 0 ); //put the rows in vector while(iter>=0) { @@ -1823,7 +1900,7 @@ namespace svt { namespace table return bSuccess = false; //select the region between the current and the last row RowPos iter = m_nCurRow; - invalidateSelectedRegion(m_nCurRow, m_nRowCount-1, rCells); + invalidateSelectedRegion( m_nCurRow, m_nRowCount-1 ); //put the rows in the vector while(iter<=m_nRowCount) { @@ -2001,6 +2078,12 @@ namespace svt { namespace table } //------------------------------------------------------------------------------------------------------------------ + long TableControl_Impl::appFontWidthToPixel( long const i_appFontUnits ) const + { + return m_pDataWindow->LogicToPixel( Size( i_appFontUnits, 0 ), MAP_APPFONT ).Width(); + } + + //------------------------------------------------------------------------------------------------------------------ void TableControl_Impl::hideTracking() { m_pDataWindow->HideTracking(); @@ -2020,48 +2103,59 @@ namespace svt { namespace table } //------------------------------------------------------------------------------------------------------------------ - void TableControl_Impl::invalidateSelectedRegion(RowPos _nPrevRow, RowPos _nCurRow, Rectangle& _rCellRect) + void TableControl_Impl::invalidateSelectedRegion( RowPos _nPrevRow, RowPos _nCurRow ) { DBG_CHECK_ME(); - //get the visible area of the table control and set the Left and right border of the region to be repainted + // get the visible area of the table control and set the Left and right border of the region to be repainted Rectangle const aAllCells( impl_getAllVisibleCellsArea() ); - _rCellRect.Left() = aAllCells.Left(); - _rCellRect.Right() = aAllCells.Right(); - //if only one row is selected - if(_nPrevRow == _nCurRow) + + Rectangle aInvalidateRect; + aInvalidateRect.Left() = aAllCells.Left(); + aInvalidateRect.Right() = aAllCells.Right(); + // if only one row is selected + if ( _nPrevRow == _nCurRow ) { Rectangle aCellRect; impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect ); - _rCellRect.Top() = aCellRect.Top(); - _rCellRect.Bottom() = aCellRect.Bottom(); + aInvalidateRect.Top() = aCellRect.Top(); + aInvalidateRect.Bottom() = aCellRect.Bottom(); } //if the region is above the current row else if(_nPrevRow < _nCurRow ) { Rectangle aCellRect; impl_getCellRect( m_nCurColumn, _nPrevRow, aCellRect ); - _rCellRect.Top() = aCellRect.Top(); + aInvalidateRect.Top() = aCellRect.Top(); impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect ); - _rCellRect.Bottom() = aCellRect.Bottom(); + aInvalidateRect.Bottom() = aCellRect.Bottom(); } //if the region is beneath the current row else { Rectangle aCellRect; impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect ); - _rCellRect.Top() = aCellRect.Top(); + aInvalidateRect.Top() = aCellRect.Top(); impl_getCellRect( m_nCurColumn, _nPrevRow, aCellRect ); - _rCellRect.Bottom() = aCellRect.Bottom(); + aInvalidateRect.Bottom() = aCellRect.Bottom(); } - m_pDataWindow->Invalidate(_rCellRect); + m_pDataWindow->Invalidate( aInvalidateRect ); } + //------------------------------------------------------------------------------------------------------------------ - void TableControl_Impl::invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow ) + void TableControl_Impl::invalidateSelectedRows() { - if ( m_nCursorHidden == 2 ) - // WTF? what kind of hack is this? - --m_nCursorHidden; + for ( ::std::vector< RowPos >::iterator selRow = m_aSelectedRows.begin(); + selRow != m_aSelectedRows.end(); + ++selRow + ) + { + invalidateRow( *selRow ); + } + } + //------------------------------------------------------------------------------------------------------------------ + void TableControl_Impl::invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow ) + { RowPos const firstRow = i_firstRow < m_nTopRow ? m_nTopRow : i_firstRow; RowPos const lastVisibleRow = m_nTopRow + impl_getVisibleRows( true ) - 1; RowPos const lastRow = ( ( i_lastRow == ROW_INVALID ) || ( i_lastRow > lastVisibleRow ) ) ? lastVisibleRow : i_lastRow; @@ -2203,9 +2297,13 @@ namespace svt { namespace table //-------------------------------------------------------------------- ::rtl::OUString TableControl_Impl::getCellContentAsString( RowPos const i_row, ColPos const i_col ) { - ::com::sun::star::uno::Any content; - m_pModel->getCellContent( i_col, i_row, content ); - return CellValueConversion::convertToString( content ); + Any aCellValue; + m_pModel->getCellContent( i_col, i_row, aCellValue ); + + ::rtl::OUString sCellStringContent; + m_pModel->getRenderer()->GetFormattedCellString( aCellValue, i_col, i_row, sCellStringContent ); + + return sCellStringContent; } //-------------------------------------------------------------------- @@ -2245,12 +2343,19 @@ namespace svt { namespace table m_pDataWindow->Invalidate( INVALIDATE_UPDATE ); // update the position at the vertical scrollbar - m_pVScroll->SetThumbPos( m_nTopRow ); - } - - // The scroll bar availaility might change when we scrolled. This is because we do not hide - // the scrollbar when it is, in theory, unnecessary, but currently at a position > 0. In this case, it will - // be auto-hidden when it's scrolled back to pos 0. + if ( m_pVScroll != NULL ) + m_pVScroll->SetThumbPos( m_nTopRow ); + } + + // The scroll bar availaility might change when we scrolled. + // For instance, imagine a view with 10 rows, if which 5 fit into the window, numbered 1 to 10. + // Now let + // - the user scroll to row number 6, so the last 5 rows are visible + // - somebody remove the last 4 rows + // - the user scroll to row number 5 being the top row, so the last two rows are visible + // - somebody remove row number 6 + // - the user scroll to row number 1 + // => in this case, the need for the scrollbar vanishes immediately. if ( m_nTopRow == 0 ) m_rAntiImpl.PostUserEvent( LINK( this, TableControl_Impl, OnUpdateScrollbars ) ); @@ -2315,7 +2420,8 @@ namespace svt { namespace table m_pDataWindow->Invalidate( INVALIDATE_UPDATE ); // update the position at the horizontal scrollbar - m_pHScroll->SetThumbPos( m_nLeftColumn ); + if ( m_pHScroll != NULL ) + m_pHScroll->SetThumbPos( m_nLeftColumn ); } // The scroll bar availaility might change when we scrolled. This is because we do not hide @@ -2388,18 +2494,16 @@ namespace svt { namespace table if ( i_ordinate < m_nRowHeaderWidthPixel ) return COL_ROW_HEADERS; - long const ordinate = i_ordinate - m_nRowHeaderWidthPixel; - ColumnPositions::const_iterator lowerBound = ::std::lower_bound( m_aColumnWidths.begin(), m_aColumnWidths.end(), - ordinate + 1, + i_ordinate + 1, ColumnInfoPositionLess() ); if ( lowerBound == m_aColumnWidths.end() ) { // point is *behind* the start of the last column ... - if ( ordinate < m_aColumnWidths.rbegin()->getEnd() ) + if ( i_ordinate < m_aColumnWidths.rbegin()->getEnd() ) // ... but still before its end return m_nColumnCount - 1; return COL_INVALID; @@ -2506,6 +2610,28 @@ namespace svt { namespace table } //-------------------------------------------------------------------- + void TableControl_Impl::commitAccessibleEvent( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue ) + { + impl_commitAccessibleEvent( i_eventID, i_newValue, i_oldValue ); + } + + //-------------------------------------------------------------------- + void TableControl_Impl::commitCellEvent( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue ) + { + DBG_CHECK_ME(); + if ( impl_isAccessibleAlive() ) + m_pAccessibleTable->commitCellEvent( i_eventID, i_newValue, i_oldValue ); + } + + //-------------------------------------------------------------------- + void TableControl_Impl::commitTableEvent( sal_Int16 const i_eventID, const Any& i_newValue, const Any& i_oldValue ) + { + DBG_CHECK_ME(); + if ( impl_isAccessibleAlive() ) + m_pAccessibleTable->commitTableEvent( i_eventID, i_newValue, i_oldValue ); + } + + //-------------------------------------------------------------------- Rectangle TableControl_Impl::calcHeaderRect(bool bColHeader) { Rectangle const aRectTableWithHeaders( impl_getAllVisibleCellsArea() ); @@ -2517,16 +2643,38 @@ namespace svt { namespace table } //-------------------------------------------------------------------- + Rectangle TableControl_Impl::calcHeaderCellRect( bool bColHeader, sal_Int32 nPos ) + { + Rectangle const aHeaderRect = calcHeaderRect( bColHeader ); + TableCellGeometry const aGeometry( + *this, aHeaderRect, + bColHeader ? nPos : COL_ROW_HEADERS, + bColHeader ? ROW_COL_HEADERS : nPos + ); + return aGeometry.getRect(); + } + + //-------------------------------------------------------------------- Rectangle TableControl_Impl::calcTableRect() { return impl_getAllVisibleDataCellArea(); } //-------------------------------------------------------------------- + Rectangle TableControl_Impl::calcCellRect( sal_Int32 nRow, sal_Int32 nCol ) + { + Rectangle aCellRect; + impl_getCellRect( nRow, nCol, aCellRect ); + return aCellRect; + } + + //-------------------------------------------------------------------- IMPL_LINK( TableControl_Impl, OnUpdateScrollbars, void*, /**/ ) { DBG_CHECK_ME(); - impl_ni_updateScrollbars(); + // TODO: can't we simply use lcl_updateScrollbar here, so the scrollbars ranges are updated, instead of + // doing a complete re-layout? + impl_ni_relayout(); return 1L; } @@ -2666,8 +2814,7 @@ namespace svt { namespace table } m_pTableControl->setAnchor( m_pTableControl->getAnchor() - 1 ); } - Rectangle aCellRect; - m_pTableControl->invalidateSelectedRegion( m_pTableControl->getCurRow(), newRow, aCellRect ); + m_pTableControl->invalidateSelectedRegion( m_pTableControl->getCurRow(), newRow ); bHandled = sal_True; } //no region selected @@ -2690,8 +2837,7 @@ namespace svt { namespace table if ( m_pTableControl->getSelectedRowCount() > 1 && m_pTableControl->getSelEngine()->GetSelectionMode() != SINGLE_SELECTION ) m_pTableControl->getSelEngine()->AddAlways(sal_True); - Rectangle aCellRect; - m_pTableControl->invalidateSelectedRegion( newRow, newRow, aCellRect ); + m_pTableControl->invalidateRow( newRow ); bHandled = sal_True; } m_pTableControl->goTo( newCol, newRow ); @@ -2716,8 +2862,7 @@ namespace svt { namespace table void TableFunctionSet::DeselectAtPoint( const Point& rPoint ) { (void)rPoint; - Rectangle aCellRange; - m_pTableControl->invalidateSelectedRegion( m_nCurrentRow, m_nCurrentRow, aCellRange ); + m_pTableControl->invalidateRow( m_nCurrentRow ); m_pTableControl->markRowAsDeselected( m_nCurrentRow ); } @@ -2726,11 +2871,10 @@ namespace svt { namespace table { if ( m_pTableControl->hasRowSelection() ) { - Rectangle aCellRange; for ( size_t i=0; i<m_pTableControl->getSelectedRowCount(); ++i ) { RowPos const rowIndex = m_pTableControl->getSelectedRowIndex(i); - m_pTableControl->invalidateSelectedRegion( rowIndex, rowIndex, aCellRange ); + m_pTableControl->invalidateRow( rowIndex ); } m_pTableControl->markAllRowsAsDeselected(); diff --git a/svtools/source/table/tablecontrol_impl.hxx b/svtools/source/table/tablecontrol_impl.hxx index bc1ac55fbe51..4f3d18aa84fd 100755..100644 --- a/svtools/source/table/tablecontrol_impl.hxx +++ b/svtools/source/table/tablecontrol_impl.hxx @@ -226,10 +226,10 @@ namespace svt { namespace table /** returns the position of the current row in the selection vector */ int getRowSelectedNumber(const ::std::vector<RowPos>& selectedRows, RowPos current); - /** _rCellRect contains the region, which should be invalidate after some action e.g. selecting row*/ - void invalidateSelectedRegion(RowPos _nPrevRow, RowPos _nCurRow, Rectangle& _rCellRect ); + /** ??? */ + void invalidateSelectedRegion( RowPos _nPrevRow, RowPos _nCurRow ); - /** invalidates the part of the data window which is covered by the given row + /** invalidates the part of the data window which is covered by the given rows @param i_firstRow the index of the first row to include in the invalidation @param i_lastRow @@ -238,6 +238,14 @@ namespace svt { namespace table */ void invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow ); + /** invalidates the part of the data window which is covered by the given row + */ + void invalidateRow( RowPos const i_row ) { invalidateRowRange( i_row, i_row ); } + + /** invalidates all selected rows + */ + void invalidateSelectedRows(); + void checkCursorPosition(); bool hasRowSelection() const { return !m_aSelectedRows.empty(); } @@ -272,6 +280,10 @@ namespace svt { namespace table void setSelectHandler( Link const & i_selectHandler ) { m_aSelectHdl = i_selectHandler; } Link const& getSelectHandler() const { return m_aSelectHdl; } + void commitAccessibleEvent( sal_Int16 const i_eventID, const com::sun::star::uno::Any& i_newValue, const com::sun::star::uno::Any& i_oldValue ); + void commitCellEvent( sal_Int16 const i_eventID, const com::sun::star::uno::Any& i_newValue, const com::sun::star::uno::Any& i_oldValue ); + void commitTableEvent( sal_Int16 const i_eventID, const com::sun::star::uno::Any& i_newValue, const com::sun::star::uno::Any& i_oldValue ); + // ITableControl virtual void hideCursor(); virtual void showCursor(); @@ -296,19 +308,25 @@ namespace svt { namespace table virtual bool isRowSelected( RowPos i_row ) const; + long appFontWidthToPixel( long const i_appFontUnits ) const; + TableDataWindow& getDataWindow() { return *m_pDataWindow; } const TableDataWindow& getDataWindow() const { return *m_pDataWindow; } ScrollBar* getHorzScrollbar(); ScrollBar* getVertScrollbar(); - Rectangle calcHeaderRect(bool bColHeader); + Rectangle calcHeaderRect( bool bColHeader ); + Rectangle calcHeaderCellRect( bool bColHeader, sal_Int32 nPos ); Rectangle calcTableRect(); + Rectangle calcCellRect( sal_Int32 nRow, sal_Int32 nCol ); // A11Y ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > getAccessible( Window& i_parentWindow ); void disposeAccessible(); + inline bool isAccessibleAlive() const { return impl_isAccessibleAlive(); } + // ITableModelListener virtual void rowsInserted( RowPos first, RowPos last ); virtual void rowsRemoved( RowPos first, RowPos last ); @@ -371,26 +389,45 @@ namespace svt { namespace table */ void impl_ni_updateCachedTableMetrics(); - /** updates ->m_aColumnWidthsPixel with the current pixel widths of all model columns + /** does a relayout of the table control - The method is not bound to the classes public invariants, as it's used in - situations where the they must not necessarily be fullfilled. + Column widths, and consequently the availability of the vertical and horizontal scrollbar, are updated + with a call to this method. @param i_assumeInflexibleColumnsUpToIncluding the index of a column up to which all columns should be considered as inflexible, or <code>COL_INVALID</code>. */ - void impl_ni_updateColumnWidths( ColPos const i_assumeInflexibleColumnsUpToIncluding = COL_INVALID ); + void impl_ni_relayout( ColPos const i_assumeInflexibleColumnsUpToIncluding = COL_INVALID ); - /** updates the scrollbars of the control + /** calculates the new width of our columns, taking into account their min and max widths, and their relative + flexibility. - The method is not bound to the classes public invariants, as it's used in - situations where the they must not necessarily be fullfilled. + @param i_assumeInflexibleColumnsUpToIncluding + the index of a column up to which all columns should be considered as inflexible, or + <code>COL_INVALID</code>. + + @param i_assumeVerticalScrollbar + controls whether or not we should assume the presence of a vertical scrollbar. If <true/>, and + if the model has a VerticalScrollbarVisibility != ScrollbarShowNever, the method will leave + space for a vertical scrollbar. + + @return + the overall width of the grid, which is available for columns + */ + long impl_ni_calculateColumnWidths( + ColPos const i_assumeInflexibleColumnsUpToIncluding, + bool const i_assumeVerticalScrollbar, + ::std::vector< long >& o_newColWidthsPixel + ) const; - This includes both the existence of the scrollbars, and their - state. + /** positions all child windows, e.g. the both scrollbars, the corner window, and the data window */ - void impl_ni_updateScrollbars(); + void impl_ni_positionChildWindows( + Rectangle const & i_dataCellPlayground, + bool const i_verticalScrollbar, + bool const i_horizontalScrollbar + ); /** scrolls the view by the given number of rows diff --git a/svtools/source/table/tabledatawindow.cxx b/svtools/source/table/tabledatawindow.cxx index 11605e36c8b2..ccdd826686f6 100644 --- a/svtools/source/table/tabledatawindow.cxx +++ b/svtools/source/table/tabledatawindow.cxx @@ -32,7 +32,6 @@ #include "tabledatawindow.hxx" #include "tablecontrol_impl.hxx" #include "tablegeometry.hxx" -#include "cellvalueconversion.hxx" #include <vcl/help.hxx> @@ -140,7 +139,7 @@ namespace svt { namespace table aCellToolTip.clear(); } - sHelpText = CellValueConversion::convertToString( aCellToolTip ); + pTableModel->getRenderer()->GetFormattedCellString( aCellToolTip, hitCol, hitRow, sHelpText ); if ( sHelpText.indexOf( '\n' ) >= 0 ) nHelpStyle = QUICKHELP_TIP_STYLE_BALLOON; @@ -149,18 +148,26 @@ namespace svt { namespace table if ( sHelpText.getLength() ) { + // hide the standard (singleton) help window, so we do not have two help windows open at the same time + Help::HideBalloonAndQuickHelp(); + Rectangle const aControlScreenRect( OutputToScreenPixel( Point( 0, 0 ) ), GetOutputSizePixel() ); if ( m_nTipWindowHandle ) + { Help::UpdateTip( m_nTipWindowHandle, this, aControlScreenRect, sHelpText ); + } else m_nTipWindowHandle = Help::ShowTip( this, aControlScreenRect, sHelpText, nHelpStyle ); } else + { impl_hideTipWindow(); + Window::RequestHelp( rHEvt ); + } } //------------------------------------------------------------------------------------------------------------------ @@ -204,7 +211,6 @@ namespace svt { namespace table { m_aSelectHdl.Call( NULL ); } - m_aMouseButtonDownHdl.Call((MouseEvent*) &rMEvt); } //------------------------------------------------------------------------------------------------------------------ @@ -213,7 +219,6 @@ namespace svt { namespace table if ( !m_rTableControl.getInputHandler()->MouseButtonUp( m_rTableControl, rMEvt ) ) Window::MouseButtonUp( rMEvt ); - m_aMouseButtonUpHdl.Call((MouseEvent*) &rMEvt); m_rTableControl.getAntiImpl().GrabFocus(); } diff --git a/svtools/source/table/tabledatawindow.hxx b/svtools/source/table/tabledatawindow.hxx index 6f78ac49c44d..645c37641870 100644 --- a/svtools/source/table/tabledatawindow.hxx +++ b/svtools/source/table/tabledatawindow.hxx @@ -52,8 +52,6 @@ namespace svt { namespace table friend class TableFunctionSet; private: TableControl_Impl& m_rTableControl; - Link m_aMouseButtonDownHdl; - Link m_aMouseButtonUpHdl; Link m_aSelectHdl; sal_uLong m_nTipWindowHandle; @@ -61,10 +59,6 @@ namespace svt { namespace table TableDataWindow( TableControl_Impl& _rTableControl ); ~TableDataWindow(); - inline void SetMouseButtonDownHdl( const Link& rLink ) { m_aMouseButtonDownHdl = rLink; } - inline const Link& GetMouseButtonDownHdl() const { return m_aMouseButtonDownHdl; } - inline void SetMouseButtonUpHdl( const Link& rLink ) { m_aMouseButtonUpHdl = rLink; } - inline const Link& GetMouseButtonUpHdl() const { return m_aMouseButtonUpHdl; } inline void SetSelectHdl( const Link& rLink ) { m_aSelectHdl = rLink; } inline const Link& GetSelectHdl() const { return m_aSelectHdl; } diff --git a/svtools/source/toolpanel/drawerlayouter.cxx b/svtools/source/toolpanel/drawerlayouter.cxx index 4de76107fd20..ecb808395c35 100644 --- a/svtools/source/toolpanel/drawerlayouter.cxx +++ b/svtools/source/toolpanel/drawerlayouter.cxx @@ -87,7 +87,7 @@ namespace svt const size_t nUpperBound = !!aActivePanel ? *aActivePanel : nPanelCount - 1; for ( size_t i=0; i<=nUpperBound; ++i ) { - sal_uInt32 nDrawerHeight = m_aDrawers[i]->GetPreferredHeightPixel(); + long const nDrawerHeight = m_aDrawers[i]->GetPreferredHeightPixel(); m_aDrawers[i]->SetPosSizePixel( aUpperDrawerPos, Size( nWidth, nDrawerHeight ) ); aUpperDrawerPos.Move( 0, nDrawerHeight ); @@ -97,7 +97,7 @@ namespace svt Point aLowerDrawerPos( i_rDeckPlayground.BottomLeft() ); for ( size_t j = nPanelCount - 1; j > nUpperBound; --j ) { - sal_uInt32 nDrawerHeight = m_aDrawers[j]->GetPreferredHeightPixel(); + long const nDrawerHeight = m_aDrawers[j]->GetPreferredHeightPixel(); m_aDrawers[j]->SetPosSizePixel( Point( aLowerDrawerPos.X(), aLowerDrawerPos.Y() - nDrawerHeight + 1 ), Size( nWidth, nDrawerHeight ) diff --git a/svtools/source/uno/svtxgridcontrol.cxx b/svtools/source/uno/svtxgridcontrol.cxx index 0e826ef6bff3..64b8f9241ae0 100644 --- a/svtools/source/uno/svtxgridcontrol.cxx +++ b/svtools/source/uno/svtxgridcontrol.cxx @@ -43,24 +43,52 @@ #include <com/sun/star/awt/XControl.hpp> #include <com/sun/star/awt/grid/GridInvalidDataException.hpp> #include <com/sun/star/awt/grid/GridInvalidModelException.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> #include <com/sun/star/util/Color.hpp> #include <com/sun/star/awt/FontDescriptor.hpp> +/** === begin UNO using === **/ +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::makeAny; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::awt::grid::XGridSelectionListener; +using ::com::sun::star::style::VerticalAlignment; +using ::com::sun::star::style::VerticalAlignment_TOP; +using ::com::sun::star::view::SelectionType; +using ::com::sun::star::view::SelectionType_NONE; +using ::com::sun::star::view::SelectionType_RANGE; +using ::com::sun::star::view::SelectionType_SINGLE; +using ::com::sun::star::view::SelectionType_MULTI; +using ::com::sun::star::awt::grid::XGridDataModel; +using ::com::sun::star::awt::grid::GridInvalidDataException; +using ::com::sun::star::lang::EventObject; +using ::com::sun::star::lang::IndexOutOfBoundsException; +using ::com::sun::star::awt::grid::XGridColumnModel; +using ::com::sun::star::awt::grid::GridSelectionEvent; +using ::com::sun::star::awt::grid::XGridColumn; +using ::com::sun::star::container::ContainerEvent; +using ::com::sun::star::awt::grid::GridDataEvent; +using ::com::sun::star::awt::grid::GridInvalidModelException; +using ::com::sun::star::util::VetoException; +/** === end UNO using === **/ + +namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId; +namespace AccessibleStateType = ::com::sun::star::accessibility::AccessibleStateType; + using namespace ::svt::table; -using namespace ::com::sun::star::uno; -using namespace ::com::sun::star::awt::grid; -using namespace ::com::sun::star::view; -using namespace ::com::sun::star::style; -using namespace ::com::sun::star::container; -using namespace ::com::sun::star::accessibility; +typedef ::com::sun::star::util::Color UnoColor; +// --------------------------------------------------------------------------------------------------------------------- SVTXGridControl::SVTXGridControl() :m_pTableModel( new UnoControlTableModel() ) - ,m_bHasColumnHeaders( false ) - ,m_bHasRowHeaders( false ) ,m_bTableModelInitCompleted( false ) - ,m_nSelectedRowCount( 0 ) ,m_aSelectionListeners( *this ) { } @@ -78,7 +106,21 @@ void SVTXGridControl::SetWindow( Window* pWindow ) } // --------------------------------------------------------------------------------------------------------------------- -sal_Int32 SAL_CALL SVTXGridControl::getRowAtPoint(::sal_Int32 x, ::sal_Int32 y) throw (::com::sun::star::uno::RuntimeException) +void SVTXGridControl::impl_checkColumnIndex_throw( ::svt::table::TableControl const & i_table, sal_Int32 const i_columnIndex ) const +{ + if ( ( i_columnIndex < 0 ) || ( i_columnIndex >= i_table.GetColumnCount() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *const_cast< SVTXGridControl* >( this ) ); +} + +// --------------------------------------------------------------------------------------------------------------------- +void SVTXGridControl::impl_checkRowIndex_throw( ::svt::table::TableControl const & i_table, sal_Int32 const i_rowIndex ) const +{ + if ( ( i_rowIndex < 0 ) || ( i_rowIndex >= i_table.GetRowCount() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *const_cast< SVTXGridControl* >( this ) ); +} + +// --------------------------------------------------------------------------------------------------------------------- +sal_Int32 SAL_CALL SVTXGridControl::getRowAtPoint(::sal_Int32 x, ::sal_Int32 y) throw (RuntimeException) { ::vos::OGuard aGuard( GetMutex() ); @@ -90,7 +132,7 @@ sal_Int32 SAL_CALL SVTXGridControl::getRowAtPoint(::sal_Int32 x, ::sal_Int32 y) } // --------------------------------------------------------------------------------------------------------------------- -sal_Int32 SAL_CALL SVTXGridControl::getColumnAtPoint(::sal_Int32 x, ::sal_Int32 y) throw (::com::sun::star::uno::RuntimeException) +sal_Int32 SAL_CALL SVTXGridControl::getColumnAtPoint(::sal_Int32 x, ::sal_Int32 y) throw (RuntimeException) { ::vos::OGuard aGuard( GetMutex() ); @@ -125,14 +167,28 @@ sal_Int32 SAL_CALL SVTXGridControl::getCurrentRow( ) throw (RuntimeException) return ( nRow >= 0 ) ? nRow : -1; } +//---------------------------------------------------------------------------------------------------------------------- +void SAL_CALL SVTXGridControl::goToCell( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) throw (RuntimeException, IndexOutOfBoundsException, VetoException) +{ + ::vos::OGuard aGuard( GetMutex() ); + + TableControl* pTable = dynamic_cast< TableControl* >( GetWindow() ); + ENSURE_OR_RETURN_VOID( pTable != NULL, "SVTXGridControl::getCurrentRow: no control (anymore)!" ); + + impl_checkColumnIndex_throw( *pTable, i_columnIndex ); + impl_checkRowIndex_throw( *pTable, i_rowIndex ); + + pTable->GoTo( i_columnIndex, i_rowIndex ); +} + // --------------------------------------------------------------------------------------------------------------------- -void SAL_CALL SVTXGridControl::addSelectionListener(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::grid::XGridSelectionListener > & listener) throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL SVTXGridControl::addSelectionListener(const Reference< XGridSelectionListener > & listener) throw (RuntimeException) { m_aSelectionListeners.addInterface(listener); } // --------------------------------------------------------------------------------------------------------------------- -void SAL_CALL SVTXGridControl::removeSelectionListener(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::grid::XGridSelectionListener > & listener) throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL SVTXGridControl::removeSelectionListener(const Reference< XGridSelectionListener > & listener) throw (RuntimeException) { m_aSelectionListeners.removeInterface(listener); } @@ -284,6 +340,27 @@ void SVTXGridControl::setProperty( const ::rtl::OUString& PropertyName, const An pTable->Invalidate(); break; + case BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR: + m_pTableModel->setActiveSelectionBackColor( aValue ); + pTable->Invalidate(); + break; + + case BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR: + m_pTableModel->setInactiveSelectionBackColor( aValue ); + pTable->Invalidate(); + break; + + case BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR: + m_pTableModel->setActiveSelectionTextColor( aValue ); + pTable->Invalidate(); + break; + + case BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR: + m_pTableModel->setInactiveSelectionTextColor( aValue ); + pTable->Invalidate(); + break; + + case BASEPROPERTY_TEXTCOLOR: m_pTableModel->setTextColor( aValue ); pTable->Invalidate(); @@ -455,7 +532,7 @@ Any SVTXGridControl::getProperty( const ::rtl::OUString& PropertyName ) throw(Ru aPropertyValue.clear(); else { - Sequence< ::com::sun::star::util::Color > aAPIColors( aColors->size() ); + Sequence< UnoColor > aAPIColors( aColors->size() ); for ( size_t i=0; i<aColors->size(); ++i ) { aAPIColors[i] = aColors->at(i).GetColor(); @@ -477,6 +554,22 @@ Any SVTXGridControl::getProperty( const ::rtl::OUString& PropertyName ) throw(Ru lcl_convertColor( m_pTableModel->getHeaderTextColor(), aPropertyValue ); break; + case BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR: + lcl_convertColor( m_pTableModel->getActiveSelectionBackColor(), aPropertyValue ); + break; + + case BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR: + lcl_convertColor( m_pTableModel->getInactiveSelectionBackColor(), aPropertyValue ); + break; + + case BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR: + lcl_convertColor( m_pTableModel->getActiveSelectionTextColor(), aPropertyValue ); + break; + + case BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR: + lcl_convertColor( m_pTableModel->getInactiveSelectionTextColor(), aPropertyValue ); + break; + case BASEPROPERTY_TEXTCOLOR: lcl_convertColor( m_pTableModel->getTextColor(), aPropertyValue ); break; @@ -505,6 +598,10 @@ void SVTXGridControl::ImplGetPropertyIds( std::list< sal_uInt16 > &rIds ) BASEPROPERTY_GRID_HEADER_TEXT_COLOR, BASEPROPERTY_GRID_LINE_COLOR, BASEPROPERTY_GRID_ROW_BACKGROUND_COLORS, + BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR, + BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR, + BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR, + BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR, 0 ); VCLXWindow::ImplGetPropertyIds( rIds, true ); @@ -585,24 +682,26 @@ void SAL_CALL SVTXGridControl::elementReplaced( const ContainerEvent& i_event ) //---------------------------------------------------------------------------------------------------------------------- -void SAL_CALL SVTXGridControl::disposing( const ::com::sun::star::lang::EventObject& Source ) throw(::com::sun::star::uno::RuntimeException) +void SAL_CALL SVTXGridControl::disposing( const EventObject& Source ) throw(RuntimeException) { VCLXWindow::disposing( Source ); } //---------------------------------------------------------------------------------------------------------------------- -void SAL_CALL SVTXGridControl::selectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL SVTXGridControl::selectRow( ::sal_Int32 i_rowIndex ) throw (RuntimeException, IndexOutOfBoundsException ) { ::vos::OGuard aGuard( GetMutex() ); TableControl* pTable = dynamic_cast< TableControl* >( GetWindow() ); ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::selectRow: no control (anymore)!" ); + impl_checkRowIndex_throw( *pTable, i_rowIndex ); + pTable->SelectRow( i_rowIndex, true ); } //---------------------------------------------------------------------------------------------------------------------- -void SAL_CALL SVTXGridControl::selectAllRows() throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL SVTXGridControl::selectAllRows() throw (RuntimeException) { ::vos::OGuard aGuard( GetMutex() ); @@ -613,18 +712,20 @@ void SAL_CALL SVTXGridControl::selectAllRows() throw (::com::sun::star::uno::Run } //---------------------------------------------------------------------------------------------------------------------- -void SAL_CALL SVTXGridControl::deselectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL SVTXGridControl::deselectRow( ::sal_Int32 i_rowIndex ) throw (RuntimeException, IndexOutOfBoundsException ) { ::vos::OGuard aGuard( GetMutex() ); TableControl* pTable = dynamic_cast< TableControl* >( GetWindow() ); ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::deselectRow: no control (anymore)!" ); + impl_checkRowIndex_throw( *pTable, i_rowIndex ); + pTable->SelectRow( i_rowIndex, false ); } //---------------------------------------------------------------------------------------------------------------------- -void SAL_CALL SVTXGridControl::deselectAllRows() throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL SVTXGridControl::deselectAllRows() throw (RuntimeException) { ::vos::OGuard aGuard( GetMutex() ); @@ -635,12 +736,12 @@ void SAL_CALL SVTXGridControl::deselectAllRows() throw (::com::sun::star::uno::R } //---------------------------------------------------------------------------------------------------------------------- -::com::sun::star::uno::Sequence< ::sal_Int32 > SAL_CALL SVTXGridControl::getSelection() throw (::com::sun::star::uno::RuntimeException) +Sequence< ::sal_Int32 > SAL_CALL SVTXGridControl::getSelectedRows() throw (RuntimeException) { ::vos::OGuard aGuard( GetMutex() ); TableControl* pTable = dynamic_cast< TableControl* >( GetWindow() ); - ENSURE_OR_RETURN( pTable, "SVTXGridControl::getSelection: no control (anymore)!", Sequence< sal_Int32 >() ); + ENSURE_OR_RETURN( pTable, "SVTXGridControl::getSelectedRows: no control (anymore)!", Sequence< sal_Int32 >() ); sal_Int32 selectionCount = pTable->GetSelectedRowCount(); Sequence< sal_Int32 > selectedRows( selectionCount ); @@ -650,31 +751,31 @@ void SAL_CALL SVTXGridControl::deselectAllRows() throw (::com::sun::star::uno::R } //---------------------------------------------------------------------------------------------------------------------- -::sal_Bool SAL_CALL SVTXGridControl::isSelectionEmpty() throw (::com::sun::star::uno::RuntimeException) +::sal_Bool SAL_CALL SVTXGridControl::hasSelectedRows() throw (RuntimeException) { ::vos::OGuard aGuard( GetMutex() ); TableControl* pTable = dynamic_cast< TableControl* >( GetWindow() ); - ENSURE_OR_RETURN( pTable, "SVTXGridControl::getSelection: no control (anymore)!", sal_True ); + ENSURE_OR_RETURN( pTable, "SVTXGridControl::hasSelectedRows: no control (anymore)!", sal_True ); return pTable->GetSelectedRowCount() > 0; } //---------------------------------------------------------------------------------------------------------------------- -::sal_Bool SAL_CALL SVTXGridControl::isSelectedIndex( ::sal_Int32 index ) throw (::com::sun::star::uno::RuntimeException) +::sal_Bool SAL_CALL SVTXGridControl::isRowSelected( ::sal_Int32 index ) throw (RuntimeException) { ::vos::OGuard aGuard( GetMutex() ); TableControl* pTable = dynamic_cast< TableControl* >( GetWindow() ); - ENSURE_OR_RETURN( pTable, "SVTXGridControl::isSelectedIndex: no control (anymore)!", sal_False ); + ENSURE_OR_RETURN( pTable, "SVTXGridControl::isRowSelected: no control (anymore)!", sal_False ); return pTable->IsRowSelected( index ); } //---------------------------------------------------------------------------------------------------------------------- -void SVTXGridControl::dispose() throw(::com::sun::star::uno::RuntimeException) +void SVTXGridControl::dispose() throw(RuntimeException) { - ::com::sun::star::lang::EventObject aObj; + EventObject aObj; aObj.Source = (::cppu::OWeakObject*)this; m_aSelectionListeners.disposeAndClear( aObj ); VCLXWindow::dispose(); @@ -685,22 +786,76 @@ void SVTXGridControl::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent { ::vos::OGuard aGuard( GetMutex() ); - ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow > xKeepAlive( this ); + Reference< XWindow > xKeepAlive( this ); + + TableControl* pTable = dynamic_cast< TableControl* >( GetWindow() ); + ENSURE_OR_RETURN_VOID( pTable, "SVTXGridControl::ProcessWindowEvent: no control (anymore)!" ); + + bool handled = false; switch ( rVclWindowEvent.GetId() ) { case VCLEVENT_TABLEROW_SELECT: { - TableControl* pTable = dynamic_cast< TableControl* >( GetWindow() ); - ENSURE_OR_BREAK( pTable, "SVTXGridControl::ProcessWindowEvent: no control (anymore)!" ); if ( m_aSelectionListeners.getLength() ) ImplCallItemListeners(); + handled = true; } break; - default: - VCLXWindow::ProcessWindowEvent( rVclWindowEvent ); - break; + case VCLEVENT_CONTROL_GETFOCUS: + { + // TODO: this doesn't belong here. It belongs into the TableControl/_Impl, so A11Y also + // works when the control is used outside the UNO context + if ( pTable->GetRowCount()>0 ) + { + pTable->commitCellEventIfAccessibleAlive( + AccessibleEventId::STATE_CHANGED, + makeAny( AccessibleStateType::FOCUSED ), + Any() + ); + pTable->commitTableEventIfAccessibleAlive( + AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, + Any(), + Any() + ); + } + else + { + pTable->commitTableEventIfAccessibleAlive( + AccessibleEventId::STATE_CHANGED, + makeAny( AccessibleStateType::FOCUSED ), + Any() + ); + } + } + break; + + case VCLEVENT_CONTROL_LOSEFOCUS: + { + // TODO: this doesn't belong here. It belongs into the TableControl/_Impl, so A11Y also + // works when the control is used outside the UNO context + if ( pTable->GetRowCount()>0 ) + { + pTable->commitCellEventIfAccessibleAlive( + AccessibleEventId::STATE_CHANGED, + Any(), + makeAny( AccessibleStateType::FOCUSED ) + ); + } + else + { + pTable->commitTableEventIfAccessibleAlive( + AccessibleEventId::STATE_CHANGED, + Any(), + makeAny( AccessibleStateType::FOCUSED ) + ); + } + } + break; } + + if ( !handled ) + VCLXWindow::ProcessWindowEvent( rVclWindowEvent ); } //---------------------------------------------------------------------------------------------------------------------- @@ -711,42 +866,13 @@ void SVTXGridControl::ImplCallItemListeners() if ( m_aSelectionListeners.getLength() ) { - sal_Int32 const actSelRowCount = pTable->GetSelectedRowCount(); - ::com::sun::star::awt::grid::GridSelectionEvent aEvent; + GridSelectionEvent aEvent; aEvent.Source = (::cppu::OWeakObject*)this; - aEvent.Column = 0; - sal_Int32 diff = actSelRowCount - m_nSelectedRowCount; - //row added to selection - if(diff >= 1) - { - aEvent.Action = com::sun::star::awt::grid::SelectionEventType(0); - aEvent.Row = pTable->GetSelectedRowIndex( actSelRowCount - 1 ); - aEvent.Range = diff; - } - //selected row changed - else if(diff == 0 && actSelRowCount != 0) - { - aEvent.Row = pTable->GetSelectedRowIndex( actSelRowCount - 1 ); - aEvent.Action = com::sun::star::awt::grid::SelectionEventType(2); - aEvent.Range = 0; - } - else - { - //selection changed: multiple row deselected, only 1 row is selected - if(actSelRowCount == 1) - { - aEvent.Row = pTable->GetSelectedRowIndex( actSelRowCount - 1 ); - aEvent.Action = com::sun::star::awt::grid::SelectionEventType(2); - } - //row is deselected - else - { - aEvent.Row = pTable->GetCurrentRow(); - aEvent.Action = com::sun::star::awt::grid::SelectionEventType(1); - } - aEvent.Range = 0; - } - m_nSelectedRowCount=actSelRowCount; + + sal_Int32 const nSelectedRowCount( pTable->GetSelectedRowCount() ); + aEvent.SelectedRowIndexes.realloc( nSelectedRowCount ); + for ( sal_Int32 i=0; i<nSelectedRowCount; ++i ) + aEvent.SelectedRowIndexes[i] = pTable->GetSelectedRowIndex( i ); m_aSelectionListeners.selectionChanged( aEvent ); } } @@ -777,4 +903,3 @@ void SVTXGridControl::impl_updateColumnsFromModel_nothrow() DBG_UNHANDLED_EXCEPTION(); } } - diff --git a/svtools/source/uno/svtxgridcontrol.hxx b/svtools/source/uno/svtxgridcontrol.hxx index 525327b3c760..ebde9b76c078 100755 --- a/svtools/source/uno/svtxgridcontrol.hxx +++ b/svtools/source/uno/svtxgridcontrol.hxx @@ -31,6 +31,7 @@ #include <unocontroltablemodel.hxx> #include <svtools/table/tablecontrol.hxx> #include <com/sun/star/awt/grid/XGridControl.hpp> +#include <com/sun/star/awt/grid/XGridRowSelection.hpp> #include <com/sun/star/awt/grid/XGridDataListener.hpp> #include <com/sun/star/awt/grid/GridDataEvent.hpp> #include <com/sun/star/awt/grid/GridColumnEvent.hpp> @@ -45,22 +46,22 @@ #include <toolkit/helper/listenermultiplexer.hxx> -using namespace ::svt::table; +namespace svt { namespace table { + class TableControl; +} } -typedef ::cppu::ImplInheritanceHelper3 < VCLXWindow +typedef ::cppu::ImplInheritanceHelper4 < VCLXWindow , ::com::sun::star::awt::grid::XGridControl + , ::com::sun::star::awt::grid::XGridRowSelection , ::com::sun::star::awt::grid::XGridDataListener , ::com::sun::star::container::XContainerListener > SVTXGridControl_Base; class SVTXGridControl : public SVTXGridControl_Base { private: - ::boost::shared_ptr< UnoControlTableModel > m_pTableModel; - bool m_bHasColumnHeaders; - bool m_bHasRowHeaders; - bool m_bTableModelInitCompleted; - sal_Int32 m_nSelectedRowCount; - SelectionListenerMultiplexer m_aSelectionListeners; + ::boost::shared_ptr< ::svt::table::UnoControlTableModel > m_pTableModel; + bool m_bTableModelInitCompleted; + SelectionListenerMultiplexer m_aSelectionListeners; protected: virtual void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ); @@ -84,22 +85,23 @@ public: // XEventListener virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw(::com::sun::star::uno::RuntimeException); - // XGridSelection - virtual void SAL_CALL selectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL selectAllRows() throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL deselectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL deselectAllRows() throw (::com::sun::star::uno::RuntimeException); - virtual ::com::sun::star::uno::Sequence< ::sal_Int32 > SAL_CALL getSelection() throw (::com::sun::star::uno::RuntimeException); - virtual ::sal_Bool SAL_CALL isSelectionEmpty() throw (::com::sun::star::uno::RuntimeException); - virtual ::sal_Bool SAL_CALL isSelectedIndex(::sal_Int32 index) throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL addSelectionListener(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::grid::XGridSelectionListener > & listener) throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL removeSelectionListener(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::grid::XGridSelectionListener > & listener) throw (::com::sun::star::uno::RuntimeException); - // XGridControl virtual ::sal_Int32 SAL_CALL getRowAtPoint(::sal_Int32 x, ::sal_Int32 y) throw (::com::sun::star::uno::RuntimeException); virtual ::sal_Int32 SAL_CALL getColumnAtPoint(::sal_Int32 x, ::sal_Int32 y) throw (::com::sun::star::uno::RuntimeException); virtual ::sal_Int32 SAL_CALL getCurrentColumn( ) throw (::com::sun::star::uno::RuntimeException); virtual ::sal_Int32 SAL_CALL getCurrentRow( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL goToCell( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::util::VetoException); + + // XGridRowSelection + virtual void SAL_CALL selectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException ); + virtual void SAL_CALL selectAllRows() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL deselectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException ); + virtual void SAL_CALL deselectAllRows() throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::sal_Int32 > SAL_CALL getSelectedRows() throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL hasSelectedRows() throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL isRowSelected(::sal_Int32 index) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addSelectionListener(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::grid::XGridSelectionListener > & listener) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeSelectionListener(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::grid::XGridSelectionListener > & listener) throw (::com::sun::star::uno::RuntimeException); void SAL_CALL setProperty( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Any& Value ) throw(::com::sun::star::uno::RuntimeException); ::com::sun::star::uno::Any SAL_CALL getProperty( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::uno::RuntimeException); @@ -115,5 +117,8 @@ protected: private: void impl_updateColumnsFromModel_nothrow(); void impl_checkTableModelInit(); + + void impl_checkColumnIndex_throw( ::svt::table::TableControl const & i_table, sal_Int32 const i_columnIndex ) const; + void impl_checkRowIndex_throw( ::svt::table::TableControl const & i_table, sal_Int32 const i_rowIndex ) const; }; #endif // _SVT_GRIDCONTROL_HXX_ diff --git a/svtools/source/uno/unocontroltablemodel.cxx b/svtools/source/uno/unocontroltablemodel.cxx index 933363115810..b4c1bed746fa 100644 --- a/svtools/source/uno/unocontroltablemodel.cxx +++ b/svtools/source/uno/unocontroltablemodel.cxx @@ -98,6 +98,10 @@ namespace svt { namespace table ::boost::optional< ::Color > m_aGridLineColor; ::boost::optional< ::Color > m_aHeaderBackgroundColor; ::boost::optional< ::Color > m_aHeaderTextColor; + ::boost::optional< ::Color > m_aActiveSelectionBackColor; + ::boost::optional< ::Color > m_aInactiveSelectionBackColor; + ::boost::optional< ::Color > m_aActiveSelectionTextColor; + ::boost::optional< ::Color > m_aInactiveSelectionTextColor; ::boost::optional< ::Color > m_aTextColor; ::boost::optional< ::Color > m_aTextLineColor; ::boost::optional< ::std::vector< ::Color > > m_aRowColors; @@ -107,23 +111,27 @@ namespace svt { namespace table WeakReference< XGridColumnModel > m_aColumnModel; UnoControlTableModel_Impl() - :aColumns ( ) - ,bHasColumnHeaders ( true ) - ,bHasRowHeaders ( false ) - ,eVScrollMode ( ScrollbarShowNever ) - ,eHScrollMode ( ScrollbarShowNever ) - ,pRenderer ( ) - ,pInputHandler ( ) - ,nRowHeight ( 10 ) - ,nColumnHeaderHeight ( 10 ) - ,nRowHeaderWidth ( 10 ) - ,m_aGridLineColor ( ) - ,m_aHeaderBackgroundColor ( ) - ,m_aHeaderTextColor ( ) - ,m_aTextColor ( ) - ,m_aTextLineColor ( ) - ,m_aRowColors ( ) - ,m_eVerticalAlign ( VerticalAlignment_TOP ) + :aColumns ( ) + ,bHasColumnHeaders ( true ) + ,bHasRowHeaders ( false ) + ,eVScrollMode ( ScrollbarShowNever ) + ,eHScrollMode ( ScrollbarShowNever ) + ,pRenderer ( ) + ,pInputHandler ( ) + ,nRowHeight ( 10 ) + ,nColumnHeaderHeight ( 10 ) + ,nRowHeaderWidth ( 10 ) + ,m_aGridLineColor ( ) + ,m_aHeaderBackgroundColor ( ) + ,m_aHeaderTextColor ( ) + ,m_aActiveSelectionBackColor ( ) + ,m_aInactiveSelectionBackColor ( ) + ,m_aActiveSelectionTextColor ( ) + ,m_aInactiveSelectionTextColor ( ) + ,m_aTextColor ( ) + ,m_aTextLineColor ( ) + ,m_aRowColors ( ) + ,m_eVerticalAlign ( VerticalAlignment_TOP ) { } }; @@ -654,6 +662,34 @@ namespace svt { namespace table } //------------------------------------------------------------------------------------------------------------------ + ::boost::optional< ::Color > UnoControlTableModel::getActiveSelectionBackColor() const + { + DBG_CHECK_ME(); + return m_pImpl->m_aActiveSelectionBackColor; + } + + //------------------------------------------------------------------------------------------------------------------ + ::boost::optional< ::Color > UnoControlTableModel::getInactiveSelectionBackColor() const + { + DBG_CHECK_ME(); + return m_pImpl->m_aInactiveSelectionBackColor; + } + + //------------------------------------------------------------------------------------------------------------------ + ::boost::optional< ::Color > UnoControlTableModel::getActiveSelectionTextColor() const + { + DBG_CHECK_ME(); + return m_pImpl->m_aActiveSelectionTextColor; + } + + //------------------------------------------------------------------------------------------------------------------ + ::boost::optional< ::Color > UnoControlTableModel::getInactiveSelectionTextColor() const + { + DBG_CHECK_ME(); + return m_pImpl->m_aInactiveSelectionTextColor; + } + + //------------------------------------------------------------------------------------------------------------------ void UnoControlTableModel::setHeaderTextColor( Any const & i_color ) { DBG_CHECK_ME(); @@ -661,6 +697,34 @@ namespace svt { namespace table } //------------------------------------------------------------------------------------------------------------------ + void UnoControlTableModel::setActiveSelectionBackColor( Any const & i_color ) + { + DBG_CHECK_ME(); + lcl_setColor( i_color, m_pImpl->m_aActiveSelectionBackColor ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UnoControlTableModel::setInactiveSelectionBackColor( Any const & i_color ) + { + DBG_CHECK_ME(); + lcl_setColor( i_color, m_pImpl->m_aInactiveSelectionBackColor ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UnoControlTableModel::setActiveSelectionTextColor( Any const & i_color ) + { + DBG_CHECK_ME(); + lcl_setColor( i_color, m_pImpl->m_aActiveSelectionTextColor ); + } + + //------------------------------------------------------------------------------------------------------------------ + void UnoControlTableModel::setInactiveSelectionTextColor( Any const & i_color ) + { + DBG_CHECK_ME(); + lcl_setColor( i_color, m_pImpl->m_aInactiveSelectionTextColor ); + } + + //------------------------------------------------------------------------------------------------------------------ ::boost::optional< ::Color > UnoControlTableModel::getTextColor() const { DBG_CHECK_ME(); diff --git a/svtools/source/uno/unocontroltablemodel.hxx b/svtools/source/uno/unocontroltablemodel.hxx index 537c3d9a5249..3c5f52748eee 100644 --- a/svtools/source/uno/unocontroltablemodel.hxx +++ b/svtools/source/uno/unocontroltablemodel.hxx @@ -89,6 +89,10 @@ namespace svt { namespace table virtual ::boost::optional< ::Color > getLineColor() const; virtual ::boost::optional< ::Color > getHeaderBackgroundColor() const; virtual ::boost::optional< ::Color > getHeaderTextColor() const; + virtual ::boost::optional< ::Color > getActiveSelectionBackColor() const; + virtual ::boost::optional< ::Color > getInactiveSelectionBackColor() const; + virtual ::boost::optional< ::Color > getActiveSelectionTextColor() const; + virtual ::boost::optional< ::Color > getInactiveSelectionTextColor() const; virtual ::boost::optional< ::Color > getTextColor() const; virtual ::boost::optional< ::Color > getTextLineColor() const; virtual ::boost::optional< ::std::vector< ::Color > > @@ -130,6 +134,10 @@ namespace svt { namespace table void setLineColor( ::com::sun::star::uno::Any const & i_color ); void setHeaderBackgroundColor( ::com::sun::star::uno::Any const & i_color ); void setHeaderTextColor( ::com::sun::star::uno::Any const & i_color ); + void setActiveSelectionBackColor( ::com::sun::star::uno::Any const & i_color ); + void setInactiveSelectionBackColor( ::com::sun::star::uno::Any const & i_color ); + void setActiveSelectionTextColor( ::com::sun::star::uno::Any const & i_color ); + void setInactiveSelectionTextColor( ::com::sun::star::uno::Any const & i_color ); void setTextColor( ::com::sun::star::uno::Any const & i_color ); void setTextLineColor( ::com::sun::star::uno::Any const & i_color ); void setRowBackgroundColors( ::com::sun::star::uno::Any const & i_APIValue ); diff --git a/toolkit/inc/toolkit/awt/vclxtabpagecontainer.hxx b/toolkit/inc/toolkit/awt/vclxtabpagecontainer.hxx index d4fe2a727b43..f9c7b01da551 100644 --- a/toolkit/inc/toolkit/awt/vclxtabpagecontainer.hxx +++ b/toolkit/inc/toolkit/awt/vclxtabpagecontainer.hxx @@ -63,12 +63,12 @@ public: // ::com::sun::star::awt::grid::XTabPageContainer virtual ::sal_Int16 SAL_CALL getActiveTabPageID() throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL setActiveTabPageID( ::sal_Int16 _activetabpageid ) throw (::com::sun::star::uno::RuntimeException); - virtual ::sal_Int32 SAL_CALL getTabPageCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Int16 SAL_CALL getTabPageCount( ) throw (::com::sun::star::uno::RuntimeException); virtual ::sal_Bool SAL_CALL isTabPageActive( ::sal_Int16 tabPageIndex ) throw (::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPage > SAL_CALL getTabPage( ::sal_Int16 tabPageIndex ) throw (::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPage > SAL_CALL getTabPageByID( ::sal_Int16 tabPageID ) throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL addTabPageListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL removeTabPageListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addTabPageContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeTabPageContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (::com::sun::star::uno::RuntimeException); static void ImplGetPropertyIds( std::list< sal_uInt16 > &aIds ); virtual void GetPropertyIds( std::list< sal_uInt16 > &aIds ) { return ImplGetPropertyIds( aIds ); } diff --git a/toolkit/inc/toolkit/awt/vclxtabpagemodel.hxx b/toolkit/inc/toolkit/awt/vclxtabpagemodel.hxx index 670ed25c0f2d..5d8237f2cacc 100644 --- a/toolkit/inc/toolkit/awt/vclxtabpagemodel.hxx +++ b/toolkit/inc/toolkit/awt/vclxtabpagemodel.hxx @@ -74,8 +74,8 @@ public: virtual void SAL_CALL setTitle( const ::rtl::OUString& _title ) throw (::com::sun::star::uno::RuntimeException); virtual ::rtl::OUString SAL_CALL getImageURL() throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL setImageURL( const ::rtl::OUString& _imageurl ) throw (::com::sun::star::uno::RuntimeException); - virtual ::rtl::OUString SAL_CALL getTooltip() throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL setTooltip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getToolTip() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setToolTip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException); protected: ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper(); }; diff --git a/toolkit/inc/toolkit/controls/controlmodelcontainerbase.hxx b/toolkit/inc/toolkit/controls/controlmodelcontainerbase.hxx index 3090eba68749..c607a48f66cd 100644 --- a/toolkit/inc/toolkit/controls/controlmodelcontainerbase.hxx +++ b/toolkit/inc/toolkit/controls/controlmodelcontainerbase.hxx @@ -173,8 +173,8 @@ public: virtual void SAL_CALL setTitle( const ::rtl::OUString& _title ) throw (::com::sun::star::uno::RuntimeException); virtual ::rtl::OUString SAL_CALL getImageURL() throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL setImageURL( const ::rtl::OUString& _imageurl ) throw (::com::sun::star::uno::RuntimeException); - virtual ::rtl::OUString SAL_CALL getTooltip() throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL setTooltip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getToolTip() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setToolTip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException); protected: void startControlListening( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControlModel >& _rxChildModel ); diff --git a/toolkit/inc/toolkit/controls/tabpagecontainer.hxx b/toolkit/inc/toolkit/controls/tabpagecontainer.hxx index c7a2e3b8ef90..c660edf2e3e9 100644 --- a/toolkit/inc/toolkit/controls/tabpagecontainer.hxx +++ b/toolkit/inc/toolkit/controls/tabpagecontainer.hxx @@ -76,28 +76,29 @@ public: // ::com::sun::star::lang::XServiceInfo DECLIMPL_SERVICEINFO_DERIVED( UnoControlTabPageContainerModel, UnoControlModel, szServiceName_UnoControlTabPageContainerModel ) + + // XTabPageContainerModel + virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageModel > SAL_CALL createTabPage( ::sal_Int16 TabPageID ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageModel > SAL_CALL loadTabPage( ::sal_Int16 TabPageID, const ::rtl::OUString& ResourceURL ) throw (::com::sun::star::uno::RuntimeException); + // XIndexContainer virtual void SAL_CALL insertByIndex( sal_Int32 Index, const ::com::sun::star::uno::Any& Element ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); virtual void SAL_CALL removeByIndex( sal_Int32 Index ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); - // XIndexReplace + // XIndexReplace virtual void SAL_CALL replaceByIndex( sal_Int32 Index, const ::com::sun::star::uno::Any& Element ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); - // XIndexAccess + // XIndexAccess virtual sal_Int32 SAL_CALL getCount() throw (::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); - // XElementAccess + // XElementAccess virtual ::com::sun::star::uno::Type SAL_CALL getElementType() throw (::com::sun::star::uno::RuntimeException); - //{ - //return ::getCppuType((com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >*)0); - //} - virtual sal_Bool SAL_CALL hasElements() throw (::com::sun::star::uno::RuntimeException); // ::com::sun::star::container::XContainer @@ -125,12 +126,12 @@ public: // ::com::sun::star::awt::tab::XTabPageContainer virtual ::sal_Int16 SAL_CALL getActiveTabPageID() throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL setActiveTabPageID( ::sal_Int16 _activetabpageid ) throw (::com::sun::star::uno::RuntimeException); - virtual ::sal_Int32 SAL_CALL getTabPageCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Int16 SAL_CALL getTabPageCount( ) throw (::com::sun::star::uno::RuntimeException); virtual ::sal_Bool SAL_CALL isTabPageActive( ::sal_Int16 tabPageIndex ) throw (::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPage > SAL_CALL getTabPage( ::sal_Int16 tabPageIndex ) throw (::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPage > SAL_CALL getTabPageByID( ::sal_Int16 tabPageID ) throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL addTabPageListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL removeTabPageListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addTabPageContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeTabPageContainerListener( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL addControl( const ::rtl::OUString& Name, const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XControl >& Control ) throw (::com::sun::star::uno::RuntimeException); // ::com::sun::star::lang::XServiceInfo diff --git a/toolkit/inc/toolkit/controls/tabpagemodel.hxx b/toolkit/inc/toolkit/controls/tabpagemodel.hxx index 08938669fa58..68924b831af4 100644 --- a/toolkit/inc/toolkit/controls/tabpagemodel.hxx +++ b/toolkit/inc/toolkit/controls/tabpagemodel.hxx @@ -33,7 +33,6 @@ #include <com/sun/star/awt/tab/XTabPage.hpp> #include <com/sun/star/resource/XStringResourceResolver.hpp> #include <com/sun/star/lang/XInitialization.hpp> -#include <com/sun/star/uno/XComponentContext.hpp> #include "toolkit/helper/servicenames.hxx" #include "toolkit/helper/macros.hxx" #include <toolkit/controls/unocontrolcontainer.hxx> @@ -41,55 +40,6 @@ #include <list> #include <cppuhelper/implbase2.hxx> -// ---------------------------------------------------- -// class TabPageModel -// ---------------------------------------------------- -//typedef ::cppu::ImplHelper2< ::com::sun::star::awt::tab::XTabPageModel, -// ::com::sun::star::lang::XInitialization -// > TabPageAccess_BASE; -// -//class TabPageModel : public TabPageAccess_BASE -//{ -// -//private: -// bool m_bEnabled; -// ::rtl::OUString m_sTitle; -// ::rtl::OUString m_sImageURL; -// ::rtl::OUString m_sTooltip; -// sal_Int16 m_nTabPageId; -// -//public: -// TabPageModel(); -// explicit TabPageModel( ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > const & xCompContext); -// ~TabPageModel(); -// -// // XInitialization -// virtual void SAL_CALL initialize (const com::sun::star::uno::Sequence<com::sun::star::uno::Any>& rArguments) -// throw (com::sun::star::uno::Exception, com::sun::star::uno::RuntimeException); -// -// ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException); -// void SAL_CALL acquire() throw() { OWeakAggObject::acquire(); } -// void SAL_CALL release() throw() { OWeakAggObject::release(); } -// -// // ::com::sun::star::lang::XTypeProvider -// //::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes() throw(::com::sun::star::uno::RuntimeException); -// //::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() throw(::com::sun::star::uno::RuntimeException); -// -// // ::com::sun::star::awt::tab::XTabPageModel -// virtual ::sal_Int16 SAL_CALL getTabPageID() throw (::com::sun::star::uno::RuntimeException); -// virtual ::sal_Bool SAL_CALL getEnabled() throw (::com::sun::star::uno::RuntimeException); -// virtual void SAL_CALL setEnabled( ::sal_Bool _enabled ) throw (::com::sun::star::uno::RuntimeException); -// virtual ::rtl::OUString SAL_CALL getTitle() throw (::com::sun::star::uno::RuntimeException); -// virtual void SAL_CALL setTitle( const ::rtl::OUString& _title ) throw (::com::sun::star::uno::RuntimeException); -// virtual ::rtl::OUString SAL_CALL getImageURL() throw (::com::sun::star::uno::RuntimeException); -// virtual void SAL_CALL setImageURL( const ::rtl::OUString& _imageurl ) throw (::com::sun::star::uno::RuntimeException); -// virtual ::rtl::OUString SAL_CALL getTooltip() throw (::com::sun::star::uno::RuntimeException); -// virtual void SAL_CALL setTooltip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException); -//}; -// ---------------------------------------------------- -// class UnoControlTabPageModel -// ---------------------------------------------------- - class UnoControlTabPageModel : public ControlModelContainerBase //public TabPageModel { diff --git a/toolkit/inc/toolkit/helper/property.hxx b/toolkit/inc/toolkit/helper/property.hxx index c2d6380dcb65..03cd972940a7 100644 --- a/toolkit/inc/toolkit/helper/property.hxx +++ b/toolkit/inc/toolkit/helper/property.hxx @@ -206,6 +206,10 @@ namespace rtl { #define BASEPROPERTY_ROW_HEADER_WIDTH 155 #define BASEPROPERTY_COLUMN_HEADER_HEIGHT 156 #define BASEPROPERTY_USE_GRID_LINES 157 +#define BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR 158 +#define BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR 159 +#define BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR 160 +#define BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR 161 // Keine gebundenen Properties, werden immer aus der Property BASEPROPERTY_FONTDESCRIPTOR entnommen. diff --git a/toolkit/qa/complex/toolkit/GridControl.java b/toolkit/qa/complex/toolkit/GridControl.java index a06a52342417..22d6e10c7b60 100755..100644 --- a/toolkit/qa/complex/toolkit/GridControl.java +++ b/toolkit/qa/complex/toolkit/GridControl.java @@ -33,6 +33,7 @@ import com.sun.star.awt.XToolkit; import com.sun.star.awt.grid.DefaultGridDataModel; import com.sun.star.awt.grid.XGridColumn; import com.sun.star.awt.grid.XGridColumnModel; +import com.sun.star.awt.grid.XGridControl; import com.sun.star.awt.grid.XGridDataModel; import com.sun.star.awt.grid.XMutableGridDataModel; import com.sun.star.awt.grid.XSortableMutableGridDataModel; @@ -59,6 +60,8 @@ import java.util.List; import java.util.Random; import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import static org.junit.Assert.*; import org.openoffice.test.OfficeConnection; @@ -205,6 +208,8 @@ public class GridControl TMutableGridDataModel test = new TMutableGridDataModel( m_dataModel ); test.testAddRow(); test.testAddRows(); + test.testInsertRow(); + test.testInsertRows(); test.testRemoveRow(); test.testRemoveAllRows(); test.testUpdateCellData(); @@ -326,6 +331,33 @@ public class GridControl // ----------------------------------------------------------------------------------------------------------------- @Test + public void testDataModel() throws Exception + { + impl_recreateGridModel(); + + // ensure that getCellData and getRowData have the same opinion on the data they deliver + final Object[][] data = new Object[][] { + new Object[] { 15, 17, 0 }, + new Object[] { 9, 8, 14 }, + new Object[] { 17, 2, 16 }, + new Object[] { 0, 7, 14 }, + new Object[] { 10, 16, 16 }, + }; + m_dataModel.addRows( new Object[ data.length ], data ); + + for ( int row = 0; row < data.length; ++row ) + { + assertArrayEquals( "getRowData delivers wrong data in row " + row, data[row], m_dataModel.getRowData( row ) ); + for ( int col = 0; col < data[row].length; ++col ) + { + assertEquals( "getCellData delivers wrong data at position (" + col + ", " + row + ")", + data[row][col], m_dataModel.getCellData( col, row ) ); + } + } + } + + // ----------------------------------------------------------------------------------------------------------------- + @Test public void testSortableDataModel() throws Exception { impl_recreateGridModel(); @@ -403,63 +435,88 @@ public class GridControl // ----------------------------------------------------------------------------------------------------------------- @Test - public void testModelViewInteraction() throws Exception + public void testView() throws Exception { - final List< Object > disposables = new ArrayList< Object >(); - try - { - // create a siple dialog model/control/peer trinity - final XControlModel dialogModel = createInstance( XControlModel.class, "com.sun.star.awt.UnoControlDialogModel" ); - disposables.add( dialogModel ); - final XPropertySet dialogProps = UnoRuntime.queryInterface( XPropertySet.class, dialogModel ); - dialogProps.setPropertyValue( "Width", 200 ); - dialogProps.setPropertyValue( "Height", 100 ); - dialogProps.setPropertyValue( "Title", "Grid Control Unit Test" ); - final XControl dialogControl = createInstance( XControl.class, "com.sun.star.awt.UnoControlDialog" ); - disposables.add( dialogControl ); - dialogControl.setModel( dialogModel ); - dialogControl.createPeer( createInstance( XToolkit.class, "com.sun.star.awt.Toolkit" ), null ); - - // insert a grid control model - final XMultiServiceFactory controlModelFactory = UnoRuntime.queryInterface( XMultiServiceFactory.class, - dialogModel ); - XPropertySet gridModelProps = UnoRuntime.queryInterface( XPropertySet.class, - controlModelFactory.createInstance( "com.sun.star.awt.grid.UnoControlGridModel" ) ); - disposables.add( gridModelProps ); - gridModelProps.setPropertyValue( "PositionX", 6 ); - gridModelProps.setPropertyValue( "PositionY", 6 ); - gridModelProps.setPropertyValue( "Width", 188 ); - gridModelProps.setPropertyValue( "Height", 88 ); - final XNameContainer modelContainer = UnoRuntime.queryInterface( XNameContainer.class, dialogModel ); - modelContainer.insertByName( "grid", gridModelProps ); - - // check the respective control has been created - final XControlContainer controlContainer = UnoRuntime.queryInterface( XControlContainer.class, dialogControl ); - final XControl gridControl = controlContainer.getControl( "grid" ); - assertNotNull( "no grid control created in the dialog", gridControl ); - - // in the current implementation (not sure this is a good idea at all), the control (more precise: the peer) - // ensures that if there are no columns in the column model, but in the data model, then the column model - // will implicitly have the needed columns added. - // To ensure that clients which rely on this do not break in the future, check this here. - final XMutableGridDataModel dataModel = UnoRuntime.queryInterface( XMutableGridDataModel.class, - gridModelProps.getPropertyValue( "GridDataModel" ) ); - assertNotNull( dataModel ); - assertEquals( 0, dataModel.getColumnCount() ); - - final XGridColumnModel columnModel = UnoRuntime.queryInterface( XGridColumnModel.class, - gridModelProps.getPropertyValue( "ColumnModel" ) ); - assertNotNull( columnModel ); - assertEquals( 0, columnModel.getColumnCount() ); - - dataModel.addRow( null, new Object[] { 1, 2, 3 } ); - assertEquals( 3, dataModel.getColumnCount() ); - assertEquals( 3, columnModel.getColumnCount() ); - } - finally - { - impl_dispose( disposables.toArray()); - } + final XControl control = impl_createDialogWithGridControl(); + final XPropertySet gridModelProps = + UnoRuntime.queryInterface( XPropertySet.class, control.getModel() ); + + // in the current implementation (not sure this is a good idea at all), the control (more precise: the peer) + // ensures that if there are no columns in the column model, but in the data model, then the column model + // will implicitly have the needed columns added. + // To ensure that clients which rely on this do not break in the future, check this here. + final XMutableGridDataModel dataModel = UnoRuntime.queryInterface( XMutableGridDataModel.class, + gridModelProps.getPropertyValue( "GridDataModel" ) ); + assertNotNull( dataModel ); + assertEquals( 0, dataModel.getColumnCount() ); + + final XGridColumnModel columnModel = UnoRuntime.queryInterface( XGridColumnModel.class, + gridModelProps.getPropertyValue( "ColumnModel" ) ); + assertNotNull( columnModel ); + assertEquals( 0, columnModel.getColumnCount() ); + + final int columnCount = 3; + final int rowCount = 2; + dataModel.addRow( null, new Object[] { 1, 2, 3 } ); + dataModel.addRow( null, new Object[] { 6, 5, 4 } ); + + assertEquals( columnCount, dataModel.getColumnCount() ); + assertEquals( columnCount, columnModel.getColumnCount() ); + + // some cursor traveling + final XGridControl gridControl = UnoRuntime.queryInterface( XGridControl.class, control ); + gridControl.goToCell( 0, 0 ); + assertEquals( "wrong 'current column' (1)", 0, gridControl.getCurrentColumn() ); + assertEquals( "wrong 'current row' (1)", 0, gridControl.getCurrentRow() ); + gridControl.goToCell( columnCount - 1, rowCount - 1 ); + assertEquals( "wrong 'current column' (2)", dataModel.getColumnCount() - 1, gridControl.getCurrentColumn() ); + assertEquals( "wrong 'current row' (2)", dataModel.getRowCount() - 1, gridControl.getCurrentRow() ); + + // removing the last column, while the active cell is in this very last column, is expected to adjust + // the active cell + columnModel.removeColumn( columnCount - 1 ); + assertEquals( "removed the last and active column, active column was not adjusted!", + columnCount - 2, gridControl.getCurrentColumn() ); + // same holds for rows + dataModel.removeRow( rowCount - 1 ); + assertEquals( "removed the last and active row, active row was not adjusted!", + rowCount - 2, gridControl.getCurrentRow() ); + } + + // ----------------------------------------------------------------------------------------------------------------- + private XControl impl_createDialogWithGridControl() throws Exception + { + // create a simple dialog model/control/peer trinity + final XControlModel dialogModel = createInstance( XControlModel.class, "com.sun.star.awt.UnoControlDialogModel" ); + m_disposables.add( dialogModel ); + final XPropertySet dialogProps = UnoRuntime.queryInterface( XPropertySet.class, dialogModel ); + dialogProps.setPropertyValue( "Width", 200 ); + dialogProps.setPropertyValue( "Height", 100 ); + dialogProps.setPropertyValue( "Title", "Grid Control Unit Test" ); + final XControl dialogControl = createInstance( XControl.class, "com.sun.star.awt.UnoControlDialog" ); + m_disposables.add( dialogControl ); + dialogControl.setModel( dialogModel ); + dialogControl.createPeer( createInstance( XToolkit.class, "com.sun.star.awt.Toolkit" ), null ); + + // insert a grid control model + final XMultiServiceFactory controlModelFactory = UnoRuntime.queryInterface( XMultiServiceFactory.class, + dialogModel ); + final XPropertySet gridModelProps = UnoRuntime.queryInterface( XPropertySet.class, + controlModelFactory.createInstance( "com.sun.star.awt.grid.UnoControlGridModel" ) ); + m_disposables.add( gridModelProps ); + gridModelProps.setPropertyValue( "PositionX", 6 ); + gridModelProps.setPropertyValue( "PositionY", 6 ); + gridModelProps.setPropertyValue( "Width", 188 ); + gridModelProps.setPropertyValue( "Height", 88 ); + final XNameContainer modelContainer = UnoRuntime.queryInterface( XNameContainer.class, dialogModel ); + modelContainer.insertByName( "grid", gridModelProps ); + + // check the respective control has been created + final XControlContainer controlContainer = UnoRuntime.queryInterface( XControlContainer.class, dialogControl ); + final XControl gridControl = controlContainer.getControl( "grid" ); + assertNotNull( "no grid control created in the dialog", gridControl ); + + return gridControl; } // ----------------------------------------------------------------------------------------------------------------- @@ -554,6 +611,20 @@ public class GridControl } // ----------------------------------------------------------------------------------------------------------------- + @Before + public void initTestCase() + { + m_disposables.clear(); + } + + // ----------------------------------------------------------------------------------------------------------------- + @After + public void cleanupTestCase() + { + impl_dispose( m_disposables.toArray() ); + } + + // ----------------------------------------------------------------------------------------------------------------- @BeforeClass public static void setUpConnection() throws java.lang.Exception { @@ -684,4 +755,5 @@ public class GridControl private XPropertySet m_gridControlModel; private XGridColumnModel m_columnModel; private XSortableMutableGridDataModel m_dataModel; + private final List< Object > m_disposables = new ArrayList< Object >(); } diff --git a/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java b/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java index c550dd9a047d..7f3c8fb55541 100755..100644 --- a/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java +++ b/toolkit/qa/complex/toolkit/awtgrid/TMutableGridDataModel.java @@ -53,14 +53,14 @@ public class TMutableGridDataModel */ public void testAddRow() throws IndexOutOfBoundsException { - m_dataModel.addRow( 1, m_rowValues[0] ); + m_dataModel.addRow( m_rowHeadings[0], m_rowValues[0] ); GridDataEvent event = m_listener.assertSingleRowInsertionEvent(); m_listener.reset(); assertEquals( "row insertion: wrong FirstRow (1)", 0, event.FirstRow ); assertEquals( "row insertion: wrong LastRow (1)", 0, event.LastRow ); impl_assertRowData( 0 ); - m_dataModel.addRow( 2, m_rowValues[1] ); + m_dataModel.addRow( m_rowHeadings[1], m_rowValues[1] ); event = m_listener.assertSingleRowInsertionEvent(); m_listener.reset(); assertEquals( "row insertion: wrong FirstRow (2)", 1, event.FirstRow ); @@ -75,7 +75,9 @@ public class TMutableGridDataModel { assertEquals( "precondition not met: call this directly after testAddRow, please!", 2, m_dataModel.getRowCount() ); - m_dataModel.addRows( new Object[] { "3", 4.0, "5" }, new Object[][] { m_rowValues[2], m_rowValues[3], m_rowValues[4] } ); + m_dataModel.addRows( + new Object[] { m_rowHeadings[2], m_rowHeadings[3], m_rowHeadings[4] }, + new Object[][] { m_rowValues[2], m_rowValues[3], m_rowValues[4] } ); GridDataEvent event = m_listener.assertSingleRowInsertionEvent(); assertEquals( "row insertion: wrong FirstRow (1)", 2, event.FirstRow ); assertEquals( "row insertion: wrong LastRow (1)", 4, event.LastRow ); @@ -97,6 +99,145 @@ public class TMutableGridDataModel } /** + * tests the XMutableGridDataModel.insertRow method + */ + public void testInsertRow() throws IndexOutOfBoundsException + { + int expectedRowCount = m_rowValues.length; + assertEquals( "precondition not met: call this directly after testAddRows, please!", expectedRowCount, m_dataModel.getRowCount() ); + + // inserting some row somewhere between the other rows + final Object heading = "inbetweenRow"; + final Object[] inbetweenRow = new Object[] { "foo", "bar", 3, 4, 5 }; + final int insertionPos = 2; + m_dataModel.insertRow( insertionPos, heading, inbetweenRow ); + ++expectedRowCount; + assertEquals( "inserting a row is expected to increment the row count", + expectedRowCount, m_dataModel.getRowCount() ); + + final GridDataEvent event = m_listener.assertSingleRowInsertionEvent(); + assertEquals( "inserting a row results in wrong FirstRow being notified", insertionPos, event.FirstRow ); + assertEquals( "inserting a row results in wrong LastRow being notified", insertionPos, event.LastRow ); + m_listener.reset(); + + for ( int row=0; row<expectedRowCount; ++row ) + { + final Object[] actualRowData = m_dataModel.getRowData( row ); + final Object[] expectedRowData = + ( row < insertionPos ) + ? m_rowValues[ row ] + : ( row == insertionPos ) + ? inbetweenRow + : m_rowValues[ row - 1 ]; + assertArrayEquals( "row number " + row + " has wrong content content after inserting a row", + expectedRowData, actualRowData ); + + final Object actualHeading = m_dataModel.getRowHeading(row); + final Object expectedHeading = + ( row < insertionPos ) + ? m_rowHeadings[ row ] + : ( row == insertionPos ) + ? heading + : m_rowHeadings[ row - 1 ]; + assertEquals( "row " + row + " has a wrong heading after invoking insertRow", + expectedHeading, actualHeading ); + } + + // exceptions + assertException( "inserting a row at a position > rowCount is expected to throw", + m_dataModel, "insertRow", + new Class[] { Integer.class, Object.class, Object[].class }, + new Object[] { expectedRowCount + 1, "", new Object[] { "1", 2, 3 } }, + IndexOutOfBoundsException.class ); + assertException( "inserting a row at a position < 0 is expected to throw", + m_dataModel, "insertRow", + new Class[] { Integer.class, Object.class, Object[].class }, + new Object[] { -1, "", new Object[] { "1", 2, 3 } }, + IndexOutOfBoundsException.class ); + + // remove the row, to create the situation expected by the next test + m_dataModel.removeRow( insertionPos ); + m_listener.reset(); + } + + /** + * tests the XMutableGridDataModel.insertRows method + */ + public void testInsertRows() throws IndexOutOfBoundsException, IllegalArgumentException + { + int expectedRowCount = m_rowValues.length; + assertEquals( "precondition not met: call this directly after testInsertRow, please!", expectedRowCount, m_dataModel.getRowCount() ); + + // inserting some rows somewhere between the other rows + final int insertionPos = 3; + final Object[] rowHeadings = new Object[] { "A", "B", "C" }; + final Object[][] rowData = new Object[][] { + new Object[] { "A", "B", "C", "D", "E" }, + new Object[] { "J", "I", "H", "G", "F" }, + new Object[] { "K", "L", "M", "N", "O" } + }; + final int insertedRowCount = rowData.length; + assertEquals( "invalid test data", rowHeadings.length, insertedRowCount ); + + m_dataModel.insertRows( insertionPos, rowHeadings, rowData ); + expectedRowCount += insertedRowCount; + + final GridDataEvent event = m_listener.assertSingleRowInsertionEvent(); + assertEquals( "inserting multiple rows results in wrong FirstRow being notified", + insertionPos, event.FirstRow ); + assertEquals( "inserting multiple rows results in wrong LastRow being notified", + insertionPos + insertedRowCount - 1, event.LastRow ); + m_listener.reset(); + + for ( int row=0; row<expectedRowCount; ++row ) + { + final Object[] actualRowData = m_dataModel.getRowData( row ); + final Object[] expectedRowData = + ( row < insertionPos ) + ? m_rowValues[ row ] + : ( row >= insertionPos ) && ( row < insertionPos + insertedRowCount ) + ? rowData[ row - insertionPos ] + : m_rowValues[ row - insertedRowCount ]; + assertArrayEquals( "row number " + row + " has wrong content content after inserting multiple rows", + expectedRowData, actualRowData ); + + final Object actualHeading = m_dataModel.getRowHeading(row); + final Object expectedHeading = + ( row < insertionPos ) + ? m_rowHeadings[ row ] + : ( row >= insertionPos ) && ( row < insertionPos + insertedRowCount ) + ? rowHeadings[ row - insertionPos ] + : m_rowHeadings[ row - insertedRowCount ]; + assertEquals( "row " + row + " has a wrong heading after invoking insertRows", + expectedHeading, actualHeading ); + } + + // exceptions + assertException( "inserting multiple rows at a position > rowCount is expected to throw an IndexOutOfBoundsException", + m_dataModel, "insertRows", + new Class[] { Integer.class, Object[].class, Object[][].class }, + new Object[] { expectedRowCount + 1, new Object[0], new Object[][] { } }, + IndexOutOfBoundsException.class ); + assertException( "inserting multiple rows at a position < 0 is expected to throw an IndexOutOfBoundsException", + m_dataModel, "insertRows", + new Class[] { Integer.class, Object[].class, Object[][].class }, + new Object[] { -1, new Object[0], new Object[][] { } }, + IndexOutOfBoundsException.class ); + assertException( "inserting multiple rows with inconsistent array lengths is expected to throw an IllegalArgumentException", + m_dataModel, "insertRows", + new Class[] { Integer.class, Object[].class, Object[][].class }, + new Object[] { 0, new Object[0], new Object[][] { new Object[0] } }, + IllegalArgumentException.class ); + + // remove the row, to create the situation expected by the next test + for ( int i=0; i<insertedRowCount; ++i ) + { + m_dataModel.removeRow( insertionPos ); + m_listener.reset(); + } + } + + /** * tests the XMutableGridDataModel.removeRow method */ public void testRemoveRow() throws IndexOutOfBoundsException @@ -150,7 +291,7 @@ public class TMutableGridDataModel { assertEquals( "precondition not met: call this directly after testRemoveAllRows, please!", 0, m_dataModel.getRowCount() ); - m_dataModel.addRows( new Object[] { 1, 2, 3, 4, 5 }, m_rowValues ); + m_dataModel.addRows( m_rowHeadings, m_rowValues ); m_listener.assertSingleRowInsertionEvent(); m_listener.reset(); @@ -311,4 +452,8 @@ public class TMutableGridDataModel new Object[] { 4, 5, 6, 7, "8" }, new Object[] { 5, "6", 7, 8, 9 }, }; + + private final static Object[] m_rowHeadings = new Object[] { + "1", 2, 3.0, "4", (float)5.0 + }; } diff --git a/toolkit/source/awt/vclxtabpagecontainer.cxx b/toolkit/source/awt/vclxtabpagecontainer.cxx index d4f7a5048701..64337153dac1 100644 --- a/toolkit/source/awt/vclxtabpagecontainer.cxx +++ b/toolkit/source/awt/vclxtabpagecontainer.cxx @@ -126,7 +126,7 @@ void SAL_CALL VCLXTabPageContainer::setActiveTabPageID( ::sal_Int16 _activetabpa if ( pTabCtrl ) pTabCtrl->SelectTabPage(_activetabpageid); } -::sal_Int32 SAL_CALL VCLXTabPageContainer::getTabPageCount( ) throw (RuntimeException) +::sal_Int16 SAL_CALL VCLXTabPageContainer::getTabPageCount( ) throw (RuntimeException) { TabControl* pTabCtrl = (TabControl*)GetWindow(); return pTabCtrl != NULL ? pTabCtrl->GetPageCount() : 0; @@ -157,11 +157,11 @@ Reference< ::com::sun::star::awt::tab::XTabPage > SAL_CALL VCLXTabPageContainer: } return xTabPage; } -void SAL_CALL VCLXTabPageContainer::addTabPageListener( const Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (RuntimeException) +void SAL_CALL VCLXTabPageContainer::addTabPageContainerListener( const Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (RuntimeException) { m_aTabPageListeners.addInterface( listener ); } -void SAL_CALL VCLXTabPageContainer::removeTabPageListener( const Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (RuntimeException) +void SAL_CALL VCLXTabPageContainer::removeTabPageContainerListener( const Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (RuntimeException) { m_aTabPageListeners.removeInterface( listener ); } @@ -209,7 +209,7 @@ void SAL_CALL VCLXTabPageContainer::elementInserted( const ::com::sun::star::con pPage->Hide(); pTabCtrl->SetTabPage(nPageID,pPage); - pTabCtrl->SetHelpText(nPageID,xP->getTooltip()); + pTabCtrl->SetHelpText(nPageID,xP->getToolTip()); pTabCtrl->SetPageImage(nPageID,TkResMgr::getImageFromURL(xP->getImageURL())); pTabCtrl->SelectTabPage(nPageID); m_aTabPages.push_back(xTabPage); diff --git a/toolkit/source/awt/vclxtabpagemodel.cxx b/toolkit/source/awt/vclxtabpagemodel.cxx index c7145992bd7f..936a2301dcb4 100644 --- a/toolkit/source/awt/vclxtabpagemodel.cxx +++ b/toolkit/source/awt/vclxtabpagemodel.cxx @@ -124,12 +124,12 @@ void SAL_CALL VCLXTabPageModel::setImageURL( const ::rtl::OUString& /*_imageurl* { //m_sImageURL = _imageurl; } -::rtl::OUString SAL_CALL VCLXTabPageModel::getTooltip() throw (::com::sun::star::uno::RuntimeException) +::rtl::OUString SAL_CALL VCLXTabPageModel::getToolTip() throw (::com::sun::star::uno::RuntimeException) { //return m_sTooltip; return ::rtl::OUString::createFromAscii(""); } -void SAL_CALL VCLXTabPageModel::setTooltip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL VCLXTabPageModel::setToolTip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException) { (void)_tooltip; } diff --git a/toolkit/source/controls/controlmodelcontainerbase.cxx b/toolkit/source/controls/controlmodelcontainerbase.cxx index 25f30cb88d34..aa7452113652 100644 --- a/toolkit/source/controls/controlmodelcontainerbase.cxx +++ b/toolkit/source/controls/controlmodelcontainerbase.cxx @@ -39,14 +39,14 @@ #include <toolkit/controls/unocontrols.hxx> #include "toolkit/controls/formattedcontrol.hxx" #include "toolkit/controls/roadmapcontrol.hxx" -#ifndef TOOLKIT_INC_TOOLKIT_CONTROLS_TKSCROLLBAR_HXX #include "toolkit/controls/tkscrollbar.hxx" -#endif +#include "toolkit/controls/tabpagemodel.hxx" #include <toolkit/controls/stdtabcontroller.hxx> #include <com/sun/star/awt/PosSize.hpp> #include <com/sun/star/awt/WindowAttribute.hpp> #include <com/sun/star/resource/XStringResourceResolver.hpp> #include <com/sun/star/graphic/XGraphicProvider.hpp> +#include <com/sun/star/lang/XInitialization.hpp> #include <tools/list.hxx> #include <cppuhelper/typeprovider.hxx> #include <tools/debug.hxx> @@ -389,6 +389,8 @@ Reference< XInterface > ControlModelContainerBase::createInstance( const ::rtl:: pNewModel = new OGeometryControlModel< UnoGridModel >( xFactory ); else if ( aServiceSpecifier.compareToAscii( szServiceName_UnoControlTabPageContainerModel ) == 0 ) pNewModel = new OGeometryControlModel< UnoControlTabPageContainerModel >( xFactory ); + else if ( aServiceSpecifier.compareToAscii( szServiceName_UnoControlTabPageModel ) == 0 ) + pNewModel = new OGeometryControlModel< UnoControlTabPageModel >( xFactory ); if ( !pNewModel ) { @@ -417,9 +419,13 @@ Reference< XInterface > ControlModelContainerBase::createInstance( const ::rtl:: return xNewModel; } -Reference< XInterface > ControlModelContainerBase::createInstanceWithArguments( const ::rtl::OUString& ServiceSpecifier, const Sequence< Any >& /* Arguments */ ) throw(Exception, RuntimeException) +Reference< XInterface > ControlModelContainerBase::createInstanceWithArguments( const ::rtl::OUString& ServiceSpecifier, const Sequence< Any >& i_arguments ) throw(Exception, RuntimeException) { - return createInstance( ServiceSpecifier ); + const Reference< XInterface > xInstance( createInstance( ServiceSpecifier ) ); + const Reference< XInitialization > xInstanceInit( xInstance, UNO_QUERY ); + ENSURE_OR_RETURN( xInstanceInit.is(), "ControlModelContainerBase::createInstanceWithArguments: can't pass the arguments!", xInstance ); + xInstanceInit->initialize( i_arguments ); + return xInstance; } Sequence< ::rtl::OUString > ControlModelContainerBase::getAvailableServiceNames() throw(RuntimeException) @@ -779,11 +785,11 @@ void SAL_CALL ControlModelContainerBase::setImageURL( const ::rtl::OUString& _im { m_sImageURL = _imageurl; } -::rtl::OUString SAL_CALL ControlModelContainerBase::getTooltip() throw (::com::sun::star::uno::RuntimeException) +::rtl::OUString SAL_CALL ControlModelContainerBase::getToolTip() throw (::com::sun::star::uno::RuntimeException) { return m_sTooltip; } -void SAL_CALL ControlModelContainerBase::setTooltip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL ControlModelContainerBase::setToolTip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException) { m_sTooltip = _tooltip; } @@ -1344,7 +1350,7 @@ void ControlContainerBase::ImplInsertControl( Reference< XControlModel >& rxMode Reference < XControl > xCtrl; maContext.createComponent( aDefCtrl, xCtrl ); - DBG_ASSERT( xCtrl.is(), "UnoDialogControl::ImplInsertControl: could not create the control!" ); + DBG_ASSERT( xCtrl.is(), "ControlContainerBase::ImplInsertControl: could not create the control!" ); if ( xCtrl.is() ) { xCtrl->setModel( rxModel ); @@ -1562,7 +1568,7 @@ void ControlContainerBase::elementInserted( const ContainerEvent& Event ) throw( Event.Accessor >>= aName; Event.Element >>= xModel; - ENSURE_OR_RETURN_VOID( xModel.is(), "UnoDialogControl::elementInserted: illegal element!" ); + ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementInserted: illegal element!" ); try { ImplInsertControl( xModel, aName ); @@ -1580,7 +1586,7 @@ void ControlContainerBase::elementRemoved( const ContainerEvent& Event ) throw(R Reference< XControlModel > xModel; Event.Element >>= xModel; - ENSURE_OR_RETURN_VOID( xModel.is(), "UnoDialogControl::elementRemoved: illegal element!" ); + ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementRemoved: illegal element!" ); try { ImplRemoveControl( xModel ); @@ -1600,7 +1606,7 @@ void ControlContainerBase::elementReplaced( const ContainerEvent& Event ) throw( Event.ReplacedElement >>= xModel; try { - OSL_ENSURE( xModel.is(), "UnoDialogControl::elementReplaced: invalid ReplacedElement!" ); + OSL_ENSURE( xModel.is(), "ControlContainerBase::elementReplaced: invalid ReplacedElement!" ); if ( xModel.is() ) ImplRemoveControl( xModel ); } @@ -1613,7 +1619,7 @@ void ControlContainerBase::elementReplaced( const ContainerEvent& Event ) throw( ::rtl::OUString aName; Event.Accessor >>= aName; Event.Element >>= xModel; - ENSURE_OR_RETURN_VOID( xModel.is(), "UnoDialogControl::elementReplaced: invalid new element!" ); + ENSURE_OR_RETURN_VOID( xModel.is(), "ControlContainerBase::elementReplaced: invalid new element!" ); try { ImplInsertControl( xModel, aName ); diff --git a/toolkit/source/controls/grid/defaultgriddatamodel.cxx b/toolkit/source/controls/grid/defaultgriddatamodel.cxx index 4ef99d749ba1..acb71a33be4c 100644 --- a/toolkit/source/controls/grid/defaultgriddatamodel.cxx +++ b/toolkit/source/controls/grid/defaultgriddatamodel.cxx @@ -37,6 +37,7 @@ #include <rtl/ref.hxx> #include <algorithm> +#include <functional> //...................................................................................................................... namespace toolkit @@ -100,7 +101,7 @@ namespace toolkit ::sal_Int32 SAL_CALL DefaultGridDataModel::getRowCount() throw (::com::sun::star::uno::RuntimeException) { ::comphelper::ComponentGuard aGuard( *this, rBHelper ); - return m_aData.size(); + return impl_getRowCount_nolck(); } //------------------------------------------------------------------------------------------------------------------ @@ -175,52 +176,82 @@ namespace toolkit } //------------------------------------------------------------------------------------------------------------------ - void SAL_CALL DefaultGridDataModel::addRow( const Any& i_heading, const Sequence< Any >& i_data ) throw (RuntimeException) + Sequence< Any > SAL_CALL DefaultGridDataModel::getRowData( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException) { ::comphelper::ComponentGuard aGuard( *this, rBHelper ); - sal_Int32 const columnCount = i_data.getLength(); - - // store header name - m_aRowHeaders.push_back( i_heading ); - - // store row m_aData - impl_addRow( i_data ); - - // update column count - if ( columnCount > m_nColumnCount ) - m_nColumnCount = columnCount; + Sequence< Any > resultData( m_nColumnCount ); + RowData& rRowData = impl_getRowDataAccess_throw( i_rowIndex, m_nColumnCount ); - sal_Int32 const rowIndex = sal_Int32( m_aData.size() - 1 ); - broadcast( - GridDataEvent( *this, -1, -1, rowIndex, rowIndex ), - &XGridDataListener::rowsInserted, - aGuard - ); + ::std::transform( rRowData.begin(), rRowData.end(), resultData.getArray(), ::std::select1st< CellData >() ); + return resultData; } //------------------------------------------------------------------------------------------------------------------ - void DefaultGridDataModel::impl_addRow( Sequence< Any > const & i_rowData, sal_Int32 const i_assumedColCount ) + void DefaultGridDataModel::impl_insertRow( sal_Int32 const i_position, Any const & i_heading, Sequence< Any > const & i_rowData, sal_Int32 const i_assumedColCount ) { OSL_PRECOND( ( i_assumedColCount <= 0 ) || ( i_assumedColCount >= i_rowData.getLength() ), - "DefaultGridDataModel::impl_addRow: invalid column count!" ); + "DefaultGridDataModel::impl_insertRow: invalid column count!" ); + + // insert heading + m_aRowHeaders.insert( m_aRowHeaders.begin() + i_position, i_heading ); + // create new data row RowData newRow( i_assumedColCount > 0 ? i_assumedColCount : i_rowData.getLength() ); RowData::iterator cellData = newRow.begin(); for ( const Any* pData = stl_begin( i_rowData ); pData != stl_end( i_rowData ); ++pData, ++cellData ) cellData->first = *pData; - m_aData.push_back( newRow ); + // insert data row + m_aData.insert( m_aData.begin() + i_position, newRow ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL DefaultGridDataModel::addRow( const Any& i_heading, const Sequence< Any >& i_data ) throw (RuntimeException) + { + insertRow( getRowCount(), i_heading, i_data ); } //------------------------------------------------------------------------------------------------------------------ void SAL_CALL DefaultGridDataModel::addRows( const Sequence< Any >& i_headings, const Sequence< Sequence< Any > >& i_data ) throw (IllegalArgumentException, RuntimeException) { + insertRows( getRowCount(), i_headings, i_data ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL DefaultGridDataModel::insertRow( ::sal_Int32 i_index, const Any& i_heading, const Sequence< Any >& i_data ) throw (RuntimeException, IndexOutOfBoundsException) + { + ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + + if ( ( i_index < 0 ) || ( i_index > impl_getRowCount_nolck() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); + + // actually insert the row + impl_insertRow( i_index, i_heading, i_data ); + + // update column count + sal_Int32 const columnCount = i_data.getLength(); + if ( columnCount > m_nColumnCount ) + m_nColumnCount = columnCount; + + broadcast( + GridDataEvent( *this, -1, -1, i_index, i_index ), + &XGridDataListener::rowsInserted, + aGuard + ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL DefaultGridDataModel::insertRows( ::sal_Int32 i_index, const Sequence< Any>& i_headings, const Sequence< Sequence< Any > >& i_data ) throw (IllegalArgumentException, IndexOutOfBoundsException, RuntimeException) + { if ( i_headings.getLength() != i_data.getLength() ) throw IllegalArgumentException( ::rtl::OUString(), *this, -1 ); ::comphelper::ComponentGuard aGuard( *this, rBHelper ); + if ( ( i_index < 0 ) || ( i_index > impl_getRowCount_nolck() ) ) + throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); + sal_Int32 const rowCount = i_headings.getLength(); if ( rowCount == 0 ) return; @@ -236,17 +267,14 @@ namespace toolkit for ( sal_Int32 row=0; row<rowCount; ++row ) { - m_aRowHeaders.push_back( i_headings[row] ); - impl_addRow( i_data[row], maxColCount ); + impl_insertRow( i_index + row, i_headings[row], i_data[row], maxColCount ); } if ( maxColCount > m_nColumnCount ) m_nColumnCount = maxColCount; - sal_Int32 const firstRow = sal_Int32( m_aData.size() - rowCount ); - sal_Int32 const lastRow = sal_Int32( m_aData.size() - 1 ); broadcast( - GridDataEvent( *this, -1, -1, firstRow, lastRow ), + GridDataEvent( *this, -1, -1, i_index, i_index + rowCount - 1 ), &XGridDataListener::rowsInserted, aGuard ); diff --git a/toolkit/source/controls/grid/defaultgriddatamodel.hxx b/toolkit/source/controls/grid/defaultgriddatamodel.hxx index bf4b6cc3355e..e679160dc9db 100644 --- a/toolkit/source/controls/grid/defaultgriddatamodel.hxx +++ b/toolkit/source/controls/grid/defaultgriddatamodel.hxx @@ -65,6 +65,8 @@ public: // XMutableGridDataModel virtual void SAL_CALL addRow( const Any& i_heading, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Data ) throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL addRows( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any>& Headings, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > >& Data ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL insertRow( ::sal_Int32 i_index, const ::com::sun::star::uno::Any& i_heading, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Data ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException); + virtual void SAL_CALL insertRows( ::sal_Int32 i_index, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any>& Headings, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > >& Data ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); virtual void SAL_CALL removeRow( ::sal_Int32 RowIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); virtual void SAL_CALL removeAllRows( ) throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL updateCellData( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const ::com::sun::star::uno::Any& Value ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); @@ -81,6 +83,7 @@ public: virtual ::com::sun::star::uno::Any SAL_CALL getCellData( ::sal_Int32 Column, ::sal_Int32 Row ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Any SAL_CALL getCellToolTip( ::sal_Int32 Column, ::sal_Int32 Row ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Any SAL_CALL getRowHeading( ::sal_Int32 RowIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > SAL_CALL getRowData( ::sal_Int32 RowIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); // OComponentHelper virtual void SAL_CALL disposing(); @@ -104,7 +107,9 @@ private: ::comphelper::ComponentGuard & i_instanceLock ); - void impl_addRow( Sequence< Any > const & i_rowData, sal_Int32 const i_assumedColCount = -1 ); + void impl_insertRow( sal_Int32 const i_position, Any const & i_heading, Sequence< Any > const & i_rowData, sal_Int32 const i_assumedColCount = -1 ); + + ::sal_Int32 impl_getRowCount_nolck() const { return sal_Int32( m_aData.size() ); } CellData const & impl_getCellData_throw( sal_Int32 const i_columnIndex, sal_Int32 const i_rowIndex ) const; CellData& impl_getCellDataAccess_throw( sal_Int32 const i_columnIndex, sal_Int32 const i_rowIndex ); diff --git a/toolkit/source/controls/grid/gridcontrol.cxx b/toolkit/source/controls/grid/gridcontrol.cxx index acda52753a60..82619d01c7f5 100644 --- a/toolkit/source/controls/grid/gridcontrol.cxx +++ b/toolkit/source/controls/grid/gridcontrol.cxx @@ -54,6 +54,7 @@ using namespace ::com::sun::star::lang; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::container; using namespace ::com::sun::star::view; +using namespace ::com::sun::star::util; namespace toolkit { @@ -111,6 +112,10 @@ UnoGridModel::UnoGridModel( const ::com::sun::star::uno::Reference< ::com::sun:: ImplRegisterProperty( BASEPROPERTY_GRID_HEADER_BACKGROUND ); ImplRegisterProperty( BASEPROPERTY_GRID_HEADER_TEXT_COLOR ); ImplRegisterProperty( BASEPROPERTY_GRID_ROW_BACKGROUND_COLORS ); + ImplRegisterProperty( BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR ); + ImplRegisterProperty( BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR ); + ImplRegisterProperty( BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR ); + ImplRegisterProperty( BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR ); ImplRegisterProperty( BASEPROPERTY_VERTICALALIGN ); } @@ -240,6 +245,10 @@ Any UnoGridModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const case BASEPROPERTY_GRID_HEADER_TEXT_COLOR: case BASEPROPERTY_GRID_LINE_COLOR: case BASEPROPERTY_GRID_ROW_BACKGROUND_COLORS: + case BASEPROPERTY_ACTIVE_SEL_BACKGROUND_COLOR: + case BASEPROPERTY_INACTIVE_SEL_BACKGROUND_COLOR: + case BASEPROPERTY_ACTIVE_SEL_TEXT_COLOR: + case BASEPROPERTY_INACTIVE_SEL_TEXT_COLOR: return Any(); default: return UnoControlModel::ImplGetDefaultValue( nPropId ); @@ -304,8 +313,8 @@ void SAL_CALL UnoGridControl::createPeer( const uno::Reference< awt::XToolkit > { UnoControlBase::createPeer( rxToolkit, rParentPeer ); - const Reference< XGridControl > xGrid( getPeer(), UNO_QUERY_THROW ); - xGrid->addSelectionListener(&m_aSelectionListeners); + const Reference< XGridRowSelection > xGrid( getPeer(), UNO_QUERY_THROW ); + xGrid->addSelectionListener( &m_aSelectionListeners ); } //---------------------------------------------------------------------------------------------------------------------- @@ -387,45 +396,52 @@ sal_Bool SAL_CALL UnoGridControl::setModel( const Reference< XControlModel >& i_ } //---------------------------------------------------------------------------------------------------------------------- -void SAL_CALL UnoGridControl::selectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL UnoGridControl::goToCell( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) throw (RuntimeException, IndexOutOfBoundsException, VetoException) { - Reference< XGridControl >( getPeer(), UNO_QUERY_THROW )->selectRow( i_rowIndex ); + Reference< XGridControl > const xGrid ( getPeer(), UNO_QUERY_THROW ); + xGrid->goToCell( i_columnIndex, i_rowIndex ); +} + +//---------------------------------------------------------------------------------------------------------------------- +void SAL_CALL UnoGridControl::selectRow( ::sal_Int32 i_rowIndex ) throw (RuntimeException, IndexOutOfBoundsException ) +{ + Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->selectRow( i_rowIndex ); } //---------------------------------------------------------------------------------------------------------------------- void SAL_CALL UnoGridControl::selectAllRows() throw (::com::sun::star::uno::RuntimeException) { - Reference< XGridControl >( getPeer(), UNO_QUERY_THROW )->selectAllRows(); + Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->selectAllRows(); } //---------------------------------------------------------------------------------------------------------------------- -void SAL_CALL UnoGridControl::deselectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException) +void SAL_CALL UnoGridControl::deselectRow( ::sal_Int32 i_rowIndex ) throw (RuntimeException, IndexOutOfBoundsException ) { - Reference< XGridControl >( getPeer(), UNO_QUERY_THROW )->deselectRow( i_rowIndex ); + Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->deselectRow( i_rowIndex ); } //---------------------------------------------------------------------------------------------------------------------- void SAL_CALL UnoGridControl::deselectAllRows() throw (::com::sun::star::uno::RuntimeException) { - Reference< XGridControl >( getPeer(), UNO_QUERY_THROW )->deselectAllRows(); + Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->deselectAllRows(); } //---------------------------------------------------------------------------------------------------------------------- -::com::sun::star::uno::Sequence< ::sal_Int32 > SAL_CALL UnoGridControl::getSelection() throw (::com::sun::star::uno::RuntimeException) +::com::sun::star::uno::Sequence< ::sal_Int32 > SAL_CALL UnoGridControl::getSelectedRows() throw (::com::sun::star::uno::RuntimeException) { - return Reference< XGridControl >( getPeer(), UNO_QUERY_THROW )->getSelection(); + return Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->getSelectedRows(); } //---------------------------------------------------------------------------------------------------------------------- -::sal_Bool SAL_CALL UnoGridControl::isSelectionEmpty() throw (::com::sun::star::uno::RuntimeException) +::sal_Bool SAL_CALL UnoGridControl::hasSelectedRows() throw (::com::sun::star::uno::RuntimeException) { - return Reference< XGridControl >( getPeer(), UNO_QUERY_THROW )->isSelectionEmpty(); + return Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->hasSelectedRows(); } //---------------------------------------------------------------------------------------------------------------------- -::sal_Bool SAL_CALL UnoGridControl::isSelectedIndex(::sal_Int32 index) throw (::com::sun::star::uno::RuntimeException) +::sal_Bool SAL_CALL UnoGridControl::isRowSelected(::sal_Int32 index) throw (::com::sun::star::uno::RuntimeException) { - return Reference< XGridControl >( getPeer(), UNO_QUERY_THROW )->isSelectedIndex( index ); + return Reference< XGridRowSelection >( getPeer(), UNO_QUERY_THROW )->isRowSelected( index ); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/toolkit/source/controls/grid/gridcontrol.hxx b/toolkit/source/controls/grid/gridcontrol.hxx index 61d9f8fc0232..de1ac8d657c3 100644 --- a/toolkit/source/controls/grid/gridcontrol.hxx +++ b/toolkit/source/controls/grid/gridcontrol.hxx @@ -29,12 +29,13 @@ #define TOOLKIT_GRID_CONTROL_HXX #include <com/sun/star/awt/grid/XGridControl.hpp> +#include <com/sun/star/awt/grid/XGridRowSelection.hpp> #include <com/sun/star/view/SelectionType.hpp> #include <toolkit/controls/unocontrolbase.hxx> #include <toolkit/controls/unocontrolmodel.hxx> #include <toolkit/helper/servicenames.hxx> -#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase2.hxx> #include <comphelper/sequence.hxx> #include <toolkit/helper/listenermultiplexer.hxx> @@ -80,8 +81,9 @@ public: // =================================================================== // = UnoGridControl // =================================================================== -typedef ::cppu::ImplInheritanceHelper1 < UnoControlBase +typedef ::cppu::ImplInheritanceHelper2 < UnoControlBase , ::com::sun::star::awt::grid::XGridControl + , ::com::sun::star::awt::grid::XGridRowSelection > UnoGridControl_Base; class UnoGridControl : public UnoGridControl_Base { @@ -101,15 +103,16 @@ public: virtual ::sal_Int32 SAL_CALL getRowAtPoint(::sal_Int32 x, ::sal_Int32 y) throw (::com::sun::star::uno::RuntimeException); virtual ::sal_Int32 SAL_CALL getCurrentColumn( ) throw (::com::sun::star::uno::RuntimeException); virtual ::sal_Int32 SAL_CALL getCurrentRow( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL goToCell( ::sal_Int32 i_columnIndex, ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::util::VetoException); - // ::com::sun::star::awt::grid::XGridSelection - virtual void SAL_CALL selectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException); + // ::com::sun::star::awt::grid::XGridRowSelection + virtual void SAL_CALL selectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException ); virtual void SAL_CALL selectAllRows() throw (::com::sun::star::uno::RuntimeException); - virtual void SAL_CALL deselectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL deselectRow( ::sal_Int32 i_rowIndex ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException ); virtual void SAL_CALL deselectAllRows() throw (::com::sun::star::uno::RuntimeException); - virtual ::com::sun::star::uno::Sequence< ::sal_Int32 > SAL_CALL getSelection() throw (::com::sun::star::uno::RuntimeException); - virtual ::sal_Bool SAL_CALL isSelectionEmpty() throw (::com::sun::star::uno::RuntimeException); - virtual ::sal_Bool SAL_CALL isSelectedIndex(::sal_Int32 index) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::sal_Int32 > SAL_CALL getSelectedRows() throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL hasSelectedRows() throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL isRowSelected(::sal_Int32 index) throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL addSelectionListener(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::grid::XGridSelectionListener > & listener) throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL removeSelectionListener(const ::com::sun::star::uno::Reference< ::com::sun::star::awt::grid::XGridSelectionListener > & listener) throw (::com::sun::star::uno::RuntimeException); diff --git a/toolkit/source/controls/grid/sortablegriddatamodel.cxx b/toolkit/source/controls/grid/sortablegriddatamodel.cxx index 77a2ffa1637b..abfa123df0de 100755..100644 --- a/toolkit/source/controls/grid/sortablegriddatamodel.cxx +++ b/toolkit/source/controls/grid/sortablegriddatamodel.cxx @@ -295,45 +295,15 @@ namespace toolkit MethodGuard aGuard( *this, rBHelper ); DBG_CHECK_ME(); - // if the data is not sorted, broadcast the event unchanged - if ( !impl_isSorted_nothrow() ) - { - GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); - impl_broadcast( &XGridDataListener::rowsInserted, aEvent, aGuard ); - return; - } - - bool needReIndex = false; - if ( i_event.FirstRow > i_event.LastRow ) - { - OSL_ENSURE( false, "SortableGridDataModel::rowsInserted: invalid event - invalid row indexes!" ); - needReIndex = true; - } - else if ( size_t( i_event.FirstRow ) > m_privateToPublicRowIndex.size() ) - { - OSL_ENSURE( false, "SortableGridDataModel::rowsInserted: invalid event - too large row index!" ); - needReIndex = true; - } - - if ( needReIndex ) - { - impl_rebuildIndexesAndNotify( aGuard ); - return; - } - - // we do not insert the new rows into the sort order - if somebody adds rows while we're sorted, s/he has - // to resort. Instead, we simply append the rows, no matter where they were inserted in the delegator data - // model. - sal_Int32 const nPublicFirstRow = sal_Int32( m_privateToPublicRowIndex.size() ); - sal_Int32 nPublicLastRow = nPublicFirstRow; - for ( sal_Int32 newRow = i_event.FirstRow; newRow <= i_event.LastRow; ++newRow, ++nPublicLastRow ) + if ( impl_isSorted_nothrow() ) { - m_privateToPublicRowIndex.push_back( nPublicLastRow ); - m_publicToPrivateRowIndex.push_back( nPublicLastRow ); + // no infrastructure is in place currently to sort the new row to its proper location, + // so we remove the sorting here. + impl_removeColumnSort( aGuard ); + aGuard.reset(); } - // broadcast the event - GridDataEvent const aEvent( *this, -1, -1, nPublicFirstRow, nPublicLastRow ); + GridDataEvent const aEvent( impl_createPublicEvent( i_event ) ); impl_broadcast( &XGridDataListener::rowsInserted, aEvent, aGuard ); } @@ -362,14 +332,18 @@ namespace toolkit lcl_clear( m_publicToPrivateRowIndex ); lcl_clear( m_privateToPublicRowIndex ); + // rebuild the index + if ( !impl_reIndex_nothrow( m_currentSortColumn, m_sortAscending ) ) + { + impl_removeColumnSort( i_instanceLock ); + return; + } + // broadcast an artificial event, saying that all rows have been removed GridDataEvent const aRemovalEvent( *this, -1, -1, -1, -1 ); impl_broadcast( &XGridDataListener::rowsRemoved, aRemovalEvent, i_instanceLock ); i_instanceLock.reset(); - // rebuild the index - impl_reIndex_nothrow( m_currentSortColumn, m_sortAscending ); - // broadcast an artificial event, saying that n rows have been added GridDataEvent const aAdditionEvent( *this, -1, -1, 0, m_delegator->getRowCount() - 1 ); impl_broadcast( &XGridDataListener::rowsInserted, aAdditionEvent, i_instanceLock ); @@ -505,7 +479,7 @@ namespace toolkit } //------------------------------------------------------------------------------------------------------------------ - void SortableGridDataModel::impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, sal_Bool const i_sortAscending ) + bool SortableGridDataModel::impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, sal_Bool const i_sortAscending ) { ::sal_Int32 const rowCount( getRowCount() ); ::std::vector< ::sal_Int32 > aPublicToPrivate( rowCount ); @@ -527,7 +501,7 @@ namespace toolkit // get predicate object ::std::auto_ptr< ::comphelper::IKeyPredicateLess > const pPredicate( ::comphelper::getStandardLessPredicate( dataType, m_collator ) ); - ENSURE_OR_RETURN_VOID( pPredicate.get(), "SortableGridDataModel::impl_reIndex_nothrow: no sortable data found!" ); + ENSURE_OR_RETURN_FALSE( pPredicate.get(), "SortableGridDataModel::impl_reIndex_nothrow: no sortable data found!" ); // then sort CellDataLessComparison const aComparator( aColumnData, *pPredicate, i_sortAscending ); @@ -536,7 +510,7 @@ namespace toolkit catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); - return; + return false; } // also build the "private to public" mapping @@ -546,6 +520,8 @@ namespace toolkit m_publicToPrivateRowIndex.swap( aPublicToPrivate ); m_privateToPublicRowIndex.swap( aPrivateToPublic ); + + return true; } //------------------------------------------------------------------------------------------------------------------ @@ -557,7 +533,8 @@ namespace toolkit if ( ( i_columnIndex < 0 ) || ( i_columnIndex >= getColumnCount() ) ) throw IndexOutOfBoundsException( ::rtl::OUString(), *this ); - impl_reIndex_nothrow( i_columnIndex, i_sortAscending ); + if ( !impl_reIndex_nothrow( i_columnIndex, i_sortAscending ) ) + return; m_currentSortColumn = i_columnIndex; m_sortAscending = i_sortAscending; @@ -570,25 +547,35 @@ namespace toolkit } //------------------------------------------------------------------------------------------------------------------ - void SAL_CALL SortableGridDataModel::removeColumnSort( ) throw (RuntimeException) + void SortableGridDataModel::impl_removeColumnSort_noBroadcast() { - MethodGuard aGuard( *this, rBHelper ); - DBG_CHECK_ME(); - lcl_clear( m_publicToPrivateRowIndex ); lcl_clear( m_privateToPublicRowIndex ); m_currentSortColumn = -1; m_sortAscending = sal_True; + } + //------------------------------------------------------------------------------------------------------------------ + void SortableGridDataModel::impl_removeColumnSort( MethodGuard& i_instanceLock ) + { + impl_removeColumnSort_noBroadcast(); impl_broadcast( &XGridDataListener::dataChanged, GridDataEvent( *this, -1, -1, -1, -1 ), - aGuard + i_instanceLock ); } //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::removeColumnSort( ) throw (RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + impl_removeColumnSort( aGuard ); + } + + //------------------------------------------------------------------------------------------------------------------ Pair< ::sal_Int32, ::sal_Bool > SAL_CALL SortableGridDataModel::getCurrentSortOrder( ) throw (RuntimeException) { MethodGuard aGuard( *this, rBHelper ); @@ -620,6 +607,34 @@ namespace toolkit } //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::insertRow( ::sal_Int32 i_index, const Any& i_heading, const Sequence< Any >& i_data ) throw (RuntimeException, IndexOutOfBoundsException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = i_index == getRowCount() ? i_index : impl_getPrivateRowIndex_throw( i_index ); + // note that |RowCount| is a valid index in this method, but not for impl_getPrivateRowIndex_throw + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->insertRow( rowIndex, i_heading, i_data ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL SortableGridDataModel::insertRows( ::sal_Int32 i_index, const Sequence< Any>& i_headings, const Sequence< Sequence< Any > >& i_data ) throw (IllegalArgumentException, IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = i_index == getRowCount() ? i_index : impl_getPrivateRowIndex_throw( i_index ); + // note that |RowCount| is a valid index in this method, but not for impl_getPrivateRowIndex_throw + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + delegator->insertRows( rowIndex, i_headings, i_data ); + } + + //------------------------------------------------------------------------------------------------------------------ void SAL_CALL SortableGridDataModel::removeRow( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException) { MethodGuard aGuard( *this, rBHelper ); @@ -782,6 +797,19 @@ namespace toolkit } //------------------------------------------------------------------------------------------------------------------ + Sequence< Any > SAL_CALL SortableGridDataModel::getRowData( ::sal_Int32 i_rowIndex ) throw (IndexOutOfBoundsException, RuntimeException) + { + MethodGuard aGuard( *this, rBHelper ); + DBG_CHECK_ME(); + + ::sal_Int32 const rowIndex = impl_getPrivateRowIndex_throw( i_rowIndex ); + + Reference< XMutableGridDataModel > const delegator( m_delegator ); + aGuard.clear(); + return delegator->getRowData( rowIndex ); + } + + //------------------------------------------------------------------------------------------------------------------ void SAL_CALL SortableGridDataModel::disposing() { m_currentSortColumn = -1; diff --git a/toolkit/source/controls/grid/sortablegriddatamodel.hxx b/toolkit/source/controls/grid/sortablegriddatamodel.hxx index 50f08d3a7113..8f90801ee50c 100755..100644 --- a/toolkit/source/controls/grid/sortablegriddatamodel.hxx +++ b/toolkit/source/controls/grid/sortablegriddatamodel.hxx @@ -85,6 +85,8 @@ namespace toolkit // XMutableGridDataModel virtual void SAL_CALL addRow( const ::com::sun::star::uno::Any& Heading, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Data ) throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL addRows( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Headings, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > >& Data ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL insertRow( ::sal_Int32 i_index, const ::com::sun::star::uno::Any& i_heading, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Data ) throw (::com::sun::star::uno::RuntimeException, ::com::sun::star::lang::IndexOutOfBoundsException); + virtual void SAL_CALL insertRows( ::sal_Int32 i_index, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any>& Headings, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > >& Data ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); virtual void SAL_CALL removeRow( ::sal_Int32 RowIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); virtual void SAL_CALL removeAllRows( ) throw (::com::sun::star::uno::RuntimeException); virtual void SAL_CALL updateCellData( ::sal_Int32 ColumnIndex, ::sal_Int32 RowIndex, const ::com::sun::star::uno::Any& Value ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); @@ -98,9 +100,10 @@ namespace toolkit // XGridDataModel virtual ::sal_Int32 SAL_CALL getRowCount() throw (::com::sun::star::uno::RuntimeException); virtual ::sal_Int32 SAL_CALL getColumnCount() throw (::com::sun::star::uno::RuntimeException); - virtual ::com::sun::star::uno::Any SAL_CALL getCellData( ::sal_Int32 Column, ::sal_Int32 Row ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); - virtual ::com::sun::star::uno::Any SAL_CALL getCellToolTip( ::sal_Int32 Column, ::sal_Int32 Row ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getCellData( ::sal_Int32 Column, ::sal_Int32 RowIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getCellToolTip( ::sal_Int32 Column, ::sal_Int32 RowIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); virtual ::com::sun::star::uno::Any SAL_CALL getRowHeading( ::sal_Int32 RowIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > SAL_CALL getRowData( ::sal_Int32 RowIndex ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); // OComponentHelper virtual void SAL_CALL disposing(); @@ -155,7 +158,7 @@ namespace toolkit Neither <member>m_currentSortColumn</member> nor <member>m_sortAscending</member> are touched by this method. Also, the given column index is not checked, this is the responsibility of the caller. */ - void impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, sal_Bool const i_sortAscending ); + bool impl_reIndex_nothrow( ::sal_Int32 const i_columnIndex, sal_Bool const i_sortAscending ); /** translates the given event, obtained from our delegator, to a version which can be broadcasted to our own clients. @@ -180,6 +183,14 @@ namespace toolkit */ void impl_rebuildIndexesAndNotify( MethodGuard& i_instanceLock ); + /** removes the current sorting, and notifies a change of all data + */ + void impl_removeColumnSort( MethodGuard& i_instanceLock ); + + /** removes the current sorting, without any broadcast + */ + void impl_removeColumnSort_noBroadcast(); + private: ::comphelper::ComponentContext m_context; bool m_isInitialized; diff --git a/toolkit/source/controls/tabpagecontainer.cxx b/toolkit/source/controls/tabpagecontainer.cxx index 808feca02e8a..84ecef367e56 100644 --- a/toolkit/source/controls/tabpagecontainer.cxx +++ b/toolkit/source/controls/tabpagecontainer.cxx @@ -28,19 +28,21 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_toolkit.hxx" +#include <toolkit/controls/geometrycontrolmodel.hxx> #include <toolkit/controls/tabpagecontainer.hxx> - -#include <com/sun/star/lang/XMultiServiceFactory.hpp> -#include <toolkit/helper/unopropertyarrayhelper.hxx> +#include <toolkit/controls/tabpagemodel.hxx> #include <toolkit/helper/property.hxx> -#include <toolkit/controls/geometrycontrolmodel.hxx> +#include <toolkit/helper/unopropertyarrayhelper.hxx> + +#include <com/sun/star/awt/XControlModel.hpp> #include <com/sun/star/awt/XVclWindowPeer.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + #include <comphelper/processfactory.hxx> #include <osl/diagnose.h> +#include <tools/diagnose_ex.h> #include <vcl/svapp.hxx> #include <vos/mutex.hxx> -#include <com/sun/star/awt/XControlModel.hpp> -#include <tools/diagnose_ex.h> using ::rtl::OUString; using namespace ::com::sun::star; @@ -49,6 +51,7 @@ using namespace ::com::sun::star::lang; using namespace ::com::sun::star::beans; using namespace ::com::sun::star::container; using namespace ::com::sun::star::view; +using ::com::sun::star::awt::tab::XTabPageModel; #define WRONG_TYPE_EXCEPTION "Type must be ::com::sun::star::awt::tab::XTabPageModel!" // ---------------------------------------------------- @@ -89,13 +92,13 @@ uno::Any UnoControlTabPageContainerModel::ImplGetDefaultValue( sal_uInt16 nPropI ::cppu::IPropertyArrayHelper& UnoControlTabPageContainerModel::getInfoHelper() { - static UnoPropertyArrayHelper* pHelper = NULL; - if ( !pHelper ) - { + static UnoPropertyArrayHelper* pHelper = NULL; + if ( !pHelper ) + { com::sun::star::uno::Sequence<sal_Int32> aIDs = ImplGetPropertyIds(); - pHelper = new UnoPropertyArrayHelper( aIDs ); + pHelper = new UnoPropertyArrayHelper( aIDs ); } - return *pHelper; + return *pHelper; } Reference< ::com::sun::star::beans::XPropertySetInfo > UnoControlTabPageContainerModel::getPropertySetInfo( ) throw(RuntimeException) { @@ -103,17 +106,67 @@ Reference< ::com::sun::star::beans::XPropertySetInfo > UnoControlTabPageContaine return xInfo; } +namespace +{ + Reference< XTabPageModel > lcl_createTabPageModel( ::comphelper::ComponentContext const & i_context, + Sequence< Any > const & i_initArguments, Reference< XPropertySet > const & i_parentModel ) + { + try + { + Reference< XPropertySet > const xParentDelegator( i_parentModel, UNO_QUERY_THROW ); + Reference< XPropertySetInfo > const xPSI( xParentDelegator->getPropertySetInfo() ); + bool const isGeometryControlModel = xPSI.is() && xPSI->hasPropertyByName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PositionX" ) ) ); + + Reference< XInterface > xInstance; + if ( isGeometryControlModel ) + xInstance = *( new OGeometryControlModel< UnoControlTabPageModel >( i_context.getLegacyServiceFactory() ) ); + else + xInstance = *( new UnoControlTabPageModel( i_context.getLegacyServiceFactory() ) ); + + Reference< XTabPageModel > const xTabPageModel( xInstance, UNO_QUERY_THROW ); + Reference< XInitialization > const xInit( xTabPageModel, UNO_QUERY_THROW ); + xInit->initialize( i_initArguments ); + + return xTabPageModel; + } + catch( const RuntimeException& ) + { + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return NULL; + } +} + +Reference< XTabPageModel > SAL_CALL UnoControlTabPageContainerModel::createTabPage( ::sal_Int16 i_tabPageID ) throw (RuntimeException) +{ + Sequence< Any > aInitArgs(1); + aInitArgs[0] <<= i_tabPageID; + return lcl_createTabPageModel( maContext, aInitArgs, this ); +} + +Reference< XTabPageModel > SAL_CALL UnoControlTabPageContainerModel::loadTabPage( ::sal_Int16 i_tabPageID, const ::rtl::OUString& i_resourceURL ) throw (RuntimeException) +{ + Sequence< Any > aInitArgs(2); + aInitArgs[0] <<= i_tabPageID; + aInitArgs[1] <<= i_resourceURL; + return lcl_createTabPageModel( maContext, aInitArgs, this ); +} + void SAL_CALL UnoControlTabPageContainerModel::insertByIndex( ::sal_Int32 nIndex, const com::sun::star::uno::Any& aElement) throw (IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, uno::RuntimeException) { vos::OGuard aSolarGuard( Application::GetSolarMutex() ); - uno::Reference < ::awt::tab::XTabPageModel > xTabPageModel; + uno::Reference < XTabPageModel > xTabPageModel; if(aElement >>= xTabPageModel) { if ( sal_Int32( m_aTabPageVector.size()) ==nIndex ) m_aTabPageVector.push_back( xTabPageModel ); else if ( sal_Int32( m_aTabPageVector.size()) > nIndex ) { - std::vector< uno::Reference< ::awt::tab::XTabPageModel > >::iterator aIter = m_aTabPageVector.begin(); + std::vector< uno::Reference< XTabPageModel > >::iterator aIter = m_aTabPageVector.begin(); aIter += nIndex; m_aTabPageVector.insert( aIter, xTabPageModel ); } @@ -167,12 +220,12 @@ uno::Type SAL_CALL UnoControlTabPageContainerModel::getElementType( ) throw (un // XContainer void UnoControlTabPageContainerModel::addContainerListener( const Reference< XContainerListener >& l ) throw(RuntimeException) { - maContainerListeners.addInterface( l ); + maContainerListeners.addInterface( l ); } void UnoControlTabPageContainerModel::removeContainerListener( const Reference< XContainerListener >& l ) throw(RuntimeException) { - maContainerListeners.removeInterface( l ); + maContainerListeners.removeInterface( l ); } // ---------------------------------------------------- @@ -203,7 +256,7 @@ void UnoControlTabPageContainer::createPeer( const uno::Reference< awt::XToolkit Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); if ( m_aTabPageListeners.getLength() ) - xTPContainer->addTabPageListener(&m_aTabPageListeners); + xTPContainer->addTabPageContainerListener(&m_aTabPageListeners); } // ------------------------------------------------------------------- @@ -221,7 +274,7 @@ void SAL_CALL UnoControlTabPageContainer::setActiveTabPageID( ::sal_Int16 _activ Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); xTPContainer->setActiveTabPageID(_activetabpageid); } -::sal_Int32 SAL_CALL UnoControlTabPageContainer::getTabPageCount( ) throw (RuntimeException) +::sal_Int16 SAL_CALL UnoControlTabPageContainer::getTabPageCount( ) throw (RuntimeException) { vos::OGuard aSolarGuard( Application::GetSolarMutex() ); Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); @@ -245,21 +298,21 @@ Reference< ::com::sun::star::awt::tab::XTabPage > SAL_CALL UnoControlTabPageCont Reference< XTabPageContainer > xTPContainer( getPeer(), UNO_QUERY_THROW ); return xTPContainer->getTabPageByID(tabPageID); } -void SAL_CALL UnoControlTabPageContainer::addTabPageListener( const Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (RuntimeException) +void SAL_CALL UnoControlTabPageContainer::addTabPageContainerListener( const Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (RuntimeException) { m_aTabPageListeners.addInterface( listener ); if( getPeer().is() && m_aTabPageListeners.getLength() == 1 ) { uno::Reference < awt::tab::XTabPageContainer > xTabPageContainer( getPeer(), uno::UNO_QUERY ); - xTabPageContainer->addTabPageListener( &m_aTabPageListeners ); + xTabPageContainer->addTabPageContainerListener( &m_aTabPageListeners ); } } -void SAL_CALL UnoControlTabPageContainer::removeTabPageListener( const Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (RuntimeException) +void SAL_CALL UnoControlTabPageContainer::removeTabPageContainerListener( const Reference< ::com::sun::star::awt::tab::XTabPageContainerListener >& listener ) throw (RuntimeException) { if( getPeer().is() && m_aTabPageListeners.getLength() == 1 ) { uno::Reference < awt::tab::XTabPageContainer > xTabPageContainer( getPeer(), uno::UNO_QUERY ); - xTabPageContainer->addTabPageListener( &m_aTabPageListeners ); + xTabPageContainer->addTabPageContainerListener( &m_aTabPageListeners ); } m_aTabPageListeners.removeInterface( listener ); } diff --git a/toolkit/source/controls/tabpagemodel.cxx b/toolkit/source/controls/tabpagemodel.cxx index f498fefd761b..834b7f92e013 100644 --- a/toolkit/source/controls/tabpagemodel.cxx +++ b/toolkit/source/controls/tabpagemodel.cxx @@ -75,72 +75,6 @@ using namespace ::com::sun::star::util; ::rtl::OUString getPhysicalLocation( const ::com::sun::star::uno::Any& rbase, const ::com::sun::star::uno::Any& rUrl ); // ---------------------------------------------------- -// class TabPageModel -// ---------------------------------------------------- - -//TabPageModel::TabPageModel() -//{ -//} -//TabPageModel::TabPageModel( uno::Reference< uno::XComponentContext > const & xCompContext) -//{ -// (void) xCompContext; -//} -// -//TabPageModel::~TabPageModel() -//{ -//} -// -//////----- XInitialization ------------------------------------------------------------------- -//void SAL_CALL TabPageModel::initialize (const Sequence<Any>& rArguments) -//{ -// sal_Int16 nPageId; -// if ( rArguments.getLength() == 1 ) -// { -// if ( !( rArguments[ 0 ] >>= nPageId )) -// throw lang::IllegalArgumentException(); -// m_nTabPageId = nPageId; -// } -// else -// m_nTabPageId = -1; -//} -//::sal_Int16 SAL_CALL TabPageModel::getTabPageID() throw (::com::sun::star::uno::RuntimeException) -//{ -// return m_nTabPageId; -//} -//::sal_Bool SAL_CALL TabPageModel::getEnabled() throw (::com::sun::star::uno::RuntimeException) -//{ -// return m_bEnabled; -//} -//void SAL_CALL TabPageModel::setEnabled( ::sal_Bool _enabled ) throw (::com::sun::star::uno::RuntimeException) -//{ -// m_bEnabled = _enabled; -//} -//::rtl::OUString SAL_CALL TabPageModel::getTitle() throw (::com::sun::star::uno::RuntimeException) -//{ -// return m_sTitle; -//} -//void SAL_CALL TabPageModel::setTitle( const ::rtl::OUString& _title ) throw (::com::sun::star::uno::RuntimeException) -//{ -// m_sTitle = _title; -//} -//::rtl::OUString SAL_CALL TabPageModel::getImageURL() throw (::com::sun::star::uno::RuntimeException) -//{ -// return m_sImageURL; -//} -//void SAL_CALL TabPageModel::setImageURL( const ::rtl::OUString& _imageurl ) throw (::com::sun::star::uno::RuntimeException) -//{ -// m_sImageURL = _imageurl; -//} -//::rtl::OUString SAL_CALL TabPageModel::getTooltip() throw (::com::sun::star::uno::RuntimeException) -//{ -// return m_sTooltip; -//} -//void SAL_CALL TabPageModel::setTooltip( const ::rtl::OUString& _tooltip ) throw (::com::sun::star::uno::RuntimeException) -//{ -// m_sTooltip = _tooltip; -//} - -// ---------------------------------------------------- // class UnoControlTabPageModel // ---------------------------------------------------- UnoControlTabPageModel::UnoControlTabPageModel( Reference< XMultiServiceFactory > const & i_factory ) diff --git a/toolkit/source/helper/property.cxx b/toolkit/source/helper/property.cxx index a418b4a00b7b..80ddf6d04fce 100644 --- a/toolkit/source/helper/property.cxx +++ b/toolkit/source/helper/property.cxx @@ -292,6 +292,10 @@ ImplPropertyInfo* ImplGetPropertyInfos( sal_uInt16& rElementCount ) DECL_PROP_3 ( "GridLineColor", GRID_LINE_COLOR, sal_Int32, BOUND, MAYBEDEFAULT, MAYBEVOID ), DECL_PROP_3 ( "RowBackgroundColors", GRID_ROW_BACKGROUND_COLORS, Sequence< sal_Int32 >, BOUND, MAYBEDEFAULT, MAYBEVOID ), DECL_PROP_2 ( "UseGridLines", USE_GRID_LINES, sal_Bool, BOUND, MAYBEDEFAULT ), + DECL_PROP_3 ( "ActiveSelectionBackgroundColor", ACTIVE_SEL_BACKGROUND_COLOR, sal_Int32, BOUND, MAYBEDEFAULT, MAYBEVOID ), + DECL_PROP_3 ( "InactiveSelectionBackgroundColor", INACTIVE_SEL_BACKGROUND_COLOR, sal_Int32, BOUND, MAYBEDEFAULT, MAYBEVOID ), + DECL_PROP_3 ( "ActiveSelectionTextColor", ACTIVE_SEL_TEXT_COLOR, sal_Int32, BOUND, MAYBEDEFAULT, MAYBEVOID ), + DECL_PROP_3 ( "InactiveSelectionTextColor", INACTIVE_SEL_TEXT_COLOR, sal_Int32, BOUND, MAYBEDEFAULT, MAYBEVOID ), }; pPropertyInfos = aImplPropertyInfos; nElements = sizeof( aImplPropertyInfos ) / sizeof( ImplPropertyInfo ); diff --git a/toolkit/source/helper/registerservices.cxx b/toolkit/source/helper/registerservices.cxx index 8a6b1d8de4b9..fa3afbe87af8 100644 --- a/toolkit/source/helper/registerservices.cxx +++ b/toolkit/source/helper/registerservices.cxx @@ -128,9 +128,10 @@ namespace toolkit ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL ImplName##_CreateInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& i_factory ) \ { return ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface >( ( ::cppu::OWeakObject* ) new ImplName( i_factory ) ); } -::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL UnoControlDialogModel_CreateInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& i_factory ) -{ - return ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface >( ( ::cppu::OWeakObject* ) new OGeometryControlModel<UnoControlDialogModel>( i_factory ) ); +#define IMPL_CREATE_INSTANCE_WITH_GEOMETRY( ImplName ) \ + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL ImplName##_CreateInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& i_factory ) \ +{ \ + return ::com::sun::star::uno::Reference < ::com::sun::star::uno::XInterface >( ( ::cppu::OWeakObject* ) new OGeometryControlModel< ImplName >( i_factory ) ); \ } #define GET_FACTORY_WITH_IMPL_PREFIX( ClassName, ImplNamePrefix, ServiceName1, ServiceName2 ) \ @@ -212,6 +213,8 @@ IMPL_CREATEINSTANCE2( AnimatedImagesControl ) IMPL_CREATEINSTANCE2( AnimatedImagesControlModel ) IMPL_CREATEINSTANCE2( SpinningProgressControlModel ) +IMPL_CREATE_INSTANCE_WITH_GEOMETRY( UnoControlDialogModel ) + extern ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL TreeControl_CreateInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& ); extern ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL TreeControlModel_CreateInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& ); extern ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL MutableTreeDataModel_CreateInstance( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& ); @@ -234,6 +237,7 @@ TOOLKIT_DLLPUBLIC void SAL_CALL component_getImplementationEnvironment( const sa *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; } + TOOLKIT_DLLPUBLIC void* SAL_CALL component_getFactory( const sal_Char* sImplementationName, void* _pServiceManager, void* _pRegistryKey ) { void* pRet = NULL; @@ -313,13 +317,13 @@ TOOLKIT_DLLPUBLIC void* SAL_CALL component_getFactory( const sal_Char* sImplemen GET_FACTORY( DefaultGridColumnModel, szServiceName_DefaultGridColumnModel, NULL ); GET_FACTORY_WITH_IMPL_PREFIX( GridColumn, "org.openoffice.comp.toolkit", szServiceName_GridColumn, NULL ); GET_FACTORY_WITH_IMPL_PREFIX( SortableGridDataModel, "org.openoffice.comp.toolkit", szServiceName_SortableGridDataModel, NULL ); - GET_FACTORY_WITH_IMPL_PREFIX( AnimatedImagesControl, "org.openoffice.comp.toolkit", szServiceName_AnimatedImagesControl, NULL ) - GET_FACTORY_WITH_IMPL_PREFIX( AnimatedImagesControlModel, "org.openoffice.comp.toolkit", szServiceName_AnimatedImagesControlModel, NULL ) - GET_FACTORY_WITH_IMPL_PREFIX( SpinningProgressControlModel, "org.openoffice.comp.toolkit", szServiceName_SpinningProgressControlModel, NULL ) GET_FACTORY( UnoControlTabPageModel, szServiceName_UnoControlTabPageModel, NULL ) GET_FACTORY( UnoControlTabPage, szServiceName_UnoControlTabPage, NULL ) GET_FACTORY( UnoControlTabPageContainerModel, szServiceName_UnoControlTabPageContainerModel, NULL ) GET_FACTORY( UnoControlTabPageContainer, szServiceName_UnoControlTabPageContainer, NULL ) + GET_FACTORY_WITH_IMPL_PREFIX( AnimatedImagesControl, "org.openoffice.comp.toolkit", szServiceName_AnimatedImagesControl, NULL ) + GET_FACTORY_WITH_IMPL_PREFIX( AnimatedImagesControlModel, "org.openoffice.comp.toolkit", szServiceName_AnimatedImagesControlModel, NULL ) + GET_FACTORY_WITH_IMPL_PREFIX( SpinningProgressControlModel, "org.openoffice.comp.toolkit", szServiceName_SpinningProgressControlModel, NULL ) if ( rtl_str_compare( sImplementationName, "com.sun.star.awt.comp.AsyncCallback" ) == 0 ) return comp_AsyncCallback_component_getFactory( sImplementationName, _pServiceManager, _pRegistryKey ); diff --git a/vcl/inc/vcl/ctrl.hxx b/vcl/inc/vcl/ctrl.hxx index 3bf529ada48b..88a4e1f08362 100644 --- a/vcl/inc/vcl/ctrl.hxx +++ b/vcl/inc/vcl/ctrl.hxx @@ -47,7 +47,7 @@ protected: ::vcl::ImplControlData* mpControlData; private: - sal_Bool mbHasFocus; + bool mbHasControlFocus; Link maGetFocusHdl; Link maLoseFocusHdl; @@ -179,6 +179,10 @@ public: void SetLoseFocusHdl( const Link& rLink ) { maLoseFocusHdl = rLink; } const Link& GetLoseFocusHdl() const { return maLoseFocusHdl; } + /** determines whether the control currently has the focus + */ + bool HasControlFocus() const { return mbHasControlFocus; } + void SetLayoutDataParent( const Control* pParent ) const; virtual Size GetOptimalSize(WindowSizeType eType) const; diff --git a/vcl/inc/vcl/help.hxx b/vcl/inc/vcl/help.hxx index b80b9a86627a..b1e7f05d53a1 100644 --- a/vcl/inc/vcl/help.hxx +++ b/vcl/inc/vcl/help.hxx @@ -77,30 +77,30 @@ public: void SetHelpFile( const String& rFileName ) { maHelpFile = rFileName; } const String& GetHelpFile() const { return maHelpFile; } - virtual sal_Bool Start( const XubString& rHelpId, const Window* pWindow ); - virtual sal_Bool SearchKeyword( const XubString& rKeyWord ); + virtual sal_Bool Start( const XubString& rHelpId, const Window* pWindow ); + virtual sal_Bool SearchKeyword( const XubString& rKeyWord ); virtual void OpenHelpAgent( const rtl::OString& rHelpId ); virtual XubString GetHelpText( const String& aHelpURL, const Window* pWindow ); static void EnableContextHelp(); static void DisableContextHelp(); - static sal_Bool IsContextHelpEnabled(); - static sal_Bool StartContextHelp(); + static sal_Bool IsContextHelpEnabled(); + static sal_Bool StartContextHelp(); static void EnableExtHelp(); static void DisableExtHelp(); - static sal_Bool IsExtHelpEnabled(); - static sal_Bool StartExtHelp(); - static sal_Bool EndExtHelp(); - static sal_Bool IsExtHelpActive(); + static sal_Bool IsExtHelpEnabled(); + static sal_Bool StartExtHelp(); + static sal_Bool EndExtHelp(); + static sal_Bool IsExtHelpActive(); static void EnableBalloonHelp(); static void DisableBalloonHelp(); - static sal_Bool IsBalloonHelpEnabled(); - static sal_Bool ShowBalloon( Window* pParent, + static sal_Bool IsBalloonHelpEnabled(); + static sal_Bool ShowBalloon( Window* pParent, const Point& rScreenPos, const XubString& rHelpText ); - static sal_Bool ShowBalloon( Window* pParent, + static sal_Bool ShowBalloon( Window* pParent, const Point& rScreenPos, const Rectangle&, const XubString& rHelpText ); @@ -119,6 +119,8 @@ public: sal_uInt16 nStyle = 0 ) { return Help::ShowQuickHelp( pParent, rScreenRect, rHelpText, XubString(), nStyle ); } + static void HideBalloonAndQuickHelp(); + static sal_uLong ShowTip( Window* pParent, const Rectangle& rScreenRect, const XubString& rText, sal_uInt16 nStyle = 0 ); diff --git a/vcl/inc/vcl/window.hxx b/vcl/inc/vcl/window.hxx index f367be85051d..219bd4328b1b 100755..100644 --- a/vcl/inc/vcl/window.hxx +++ b/vcl/inc/vcl/window.hxx @@ -270,6 +270,7 @@ typedef sal_uInt16 StateChangedType; #define STATE_CHANGE_FORMAT ((StateChangedType)17) #define STATE_CHANGE_EXTENDEDSTYLE ((StateChangedType)18) #define STATE_CHANGE_MIRRORING ((StateChangedType)19) +#define STATE_CHANGE_CONTROL_FOCUS ((StateChangedType)20) #define STATE_CHANGE_USER ((StateChangedType)10000) // GetFocusFlags diff --git a/vcl/source/app/help.cxx b/vcl/source/app/help.cxx index ce582916ea62..231b1df8e36c 100644 --- a/vcl/source/app/help.cxx +++ b/vcl/source/app/help.cxx @@ -277,6 +277,15 @@ sal_Bool Help::ShowQuickHelp( Window* pParent, // ----------------------------------------------------------------------- +void Help::HideBalloonAndQuickHelp() +{ + HelpTextWindow const * pHelpWin = ImplGetSVData()->maHelpData.mpHelpWin; + bool const bIsVisible = ( pHelpWin != NULL ) && pHelpWin->IsVisible(); + ImplDestroyHelpWindow( bIsVisible ); +} + +// ----------------------------------------------------------------------- + sal_uIntPtr Help::ShowTip( Window* pParent, const Rectangle& rScreenRect, const XubString& rText, sal_uInt16 nStyle ) { @@ -303,6 +312,7 @@ void Help::UpdateTip( sal_uIntPtr nId, Window* pParent, const Rectangle& rScreen pParent->OutputToScreenPixel( pParent->GetPointerPosPixel() ), &rScreenRect ); pHelpWin->SetHelpText( rText ); + pHelpWin->Invalidate(); } // ----------------------------------------------------------------------- diff --git a/vcl/source/control/ctrl.cxx b/vcl/source/control/ctrl.cxx index 26ef9b076d8c..dd887276ca5b 100644 --- a/vcl/source/control/ctrl.cxx +++ b/vcl/source/control/ctrl.cxx @@ -50,7 +50,7 @@ using namespace vcl; void Control::ImplInitControlData() { - mbHasFocus = sal_False; + mbHasControlFocus = sal_False; mpControlData = new ImplControlData; } @@ -304,9 +304,10 @@ long Control::Notify( NotifyEvent& rNEvt ) { if ( rNEvt.GetType() == EVENT_GETFOCUS ) { - if ( !mbHasFocus ) + if ( !mbHasControlFocus ) { - mbHasFocus = sal_True; + mbHasControlFocus = sal_True; + StateChanged( STATE_CHANGE_CONTROL_FOCUS ); if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_GETFOCUS, maGetFocusHdl, this ) ) // been destroyed within the handler return sal_True; @@ -319,7 +320,8 @@ long Control::Notify( NotifyEvent& rNEvt ) Window* pFocusWin = Application::GetFocusWindow(); if ( !pFocusWin || !ImplIsWindowOrChild( pFocusWin ) ) { - mbHasFocus = sal_False; + mbHasControlFocus = sal_False; + StateChanged( STATE_CHANGE_CONTROL_FOCUS ); if ( ImplCallEventListenersAndHandler( VCLEVENT_CONTROL_LOSEFOCUS, maLoseFocusHdl, this ) ) // been destroyed within the handler return sal_True; |