diff options
author | Kurt Zenker <kz@openoffice.org> | 2011-04-13 17:46:26 +0200 |
---|---|---|
committer | Kurt Zenker <kz@openoffice.org> | 2011-04-13 17:46:26 +0200 |
commit | adb0b56e22c794b7f63ee19f4503cb38032e82d7 (patch) | |
tree | 6c0d371fad6b1ecbf287716401724f2e2ea09841 /svtools | |
parent | 9e84958536c737f8fdcff4d28664d0c13b9cdc8c (diff) | |
parent | 89ee82b47aa1bce8cf23c16049e990588172a820 (diff) |
CWS-TOOLING: integrate CWS gridfixes_OOO340
Diffstat (limited to 'svtools')
19 files changed, 1589 insertions, 588 deletions
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 ); |