summaryrefslogtreecommitdiff
path: root/svtools/source/table
diff options
context:
space:
mode:
Diffstat (limited to 'svtools/source/table')
-rw-r--r--svtools/source/table/cellvalueconversion.cxx77
-rw-r--r--svtools/source/table/cellvalueconversion.hxx52
-rw-r--r--svtools/source/table/defaultinputhandler.cxx249
-rw-r--r--svtools/source/table/gridtablerenderer.cxx621
-rw-r--r--svtools/source/table/mousefunction.cxx320
-rw-r--r--svtools/source/table/mousefunction.hxx161
-rw-r--r--svtools/source/table/tablecontrol.cxx613
-rw-r--r--svtools/source/table/tablecontrol_impl.cxx2745
-rw-r--r--svtools/source/table/tablecontrol_impl.hxx488
-rw-r--r--svtools/source/table/tabledatawindow.cxx243
-rw-r--r--svtools/source/table/tabledatawindow.hxx92
-rw-r--r--svtools/source/table/tablegeometry.cxx168
-rw-r--r--svtools/source/table/tablegeometry.hxx175
13 files changed, 6004 insertions, 0 deletions
diff --git a/svtools/source/table/cellvalueconversion.cxx b/svtools/source/table/cellvalueconversion.cxx
new file mode 100644
index 000000000000..286ca505bb30
--- /dev/null
+++ b/svtools/source/table/cellvalueconversion.cxx
@@ -0,0 +1,77 @@
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_svtools.hxx"
+
+#include "cellvalueconversion.hxx"
+
+/** === begin UNO includes === **/
+/** === end UNO includes === **/
+
+//......................................................................................................................
+namespace svt
+{
+//......................................................................................................................
+
+ /** === begin UNO using === **/
+ using ::com::sun::star::uno::Any;
+ /** === end UNO using === **/
+
+ //==================================================================================================================
+ //= CellValueConversion
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ ::rtl::OUString CellValueConversion::convertToString( const Any& i_value )
+ {
+ ::rtl::OUString sConvertString;
+ if ( !i_value.hasValue() )
+ return sConvertString;
+
+
+ // TODO: use css.script.XTypeConverter?
+
+ sal_Int32 nInt = 0;
+ sal_Bool bBool = false;
+ double fDouble = 0;
+
+ ::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!" );
+
+ return sStringValue;
+ }
+
+//......................................................................................................................
+} // namespace svt
+//......................................................................................................................
diff --git a/svtools/source/table/cellvalueconversion.hxx b/svtools/source/table/cellvalueconversion.hxx
new file mode 100644
index 000000000000..4d6b8c8d6aac
--- /dev/null
+++ b/svtools/source/table/cellvalueconversion.hxx
@@ -0,0 +1,52 @@
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SVTOOLS_CELLVALUECONVERSION_HXX
+#define SVTOOLS_CELLVALUECONVERSION_HXX
+
+/** === begin UNO includes === **/
+#include <com/sun/star/uno/Any.hxx>
+/** === end UNO includes === **/
+
+//......................................................................................................................
+namespace svt
+{
+//......................................................................................................................
+
+ //==================================================================================================================
+ //= CellValueConversion
+ //==================================================================================================================
+ class CellValueConversion
+ {
+ public:
+ static ::rtl::OUString convertToString( const ::com::sun::star::uno::Any& i_cellValue );
+ };
+
+//......................................................................................................................
+} // namespace svt
+//......................................................................................................................
+
+#endif // SVTOOLS_CELLVALUECONVERSION_HXX
diff --git a/svtools/source/table/defaultinputhandler.cxx b/svtools/source/table/defaultinputhandler.cxx
new file mode 100644
index 000000000000..d0ecdb546837
--- /dev/null
+++ b/svtools/source/table/defaultinputhandler.cxx
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include "svtools/table/defaultinputhandler.hxx"
+#include "svtools/table/tablecontrolinterface.hxx"
+
+#include "tabledatawindow.hxx"
+#include "mousefunction.hxx"
+
+#include <tools/debug.hxx>
+#include <vcl/event.hxx>
+#include <vcl/cursor.hxx>
+
+//......................................................................................................................
+namespace svt { namespace table
+{
+//......................................................................................................................
+
+ typedef ::rtl::Reference< IMouseFunction > PMouseFunction;
+ typedef ::std::vector< PMouseFunction > MouseFunctions;
+ struct DefaultInputHandler_Impl
+ {
+ PMouseFunction pActiveFunction;
+ MouseFunctions aMouseFunctions;
+ };
+
+ //==================================================================================================================
+ //= DefaultInputHandler
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ DefaultInputHandler::DefaultInputHandler()
+ :m_pImpl( new DefaultInputHandler_Impl )
+ {
+ m_pImpl->aMouseFunctions.push_back( new ColumnResize );
+ m_pImpl->aMouseFunctions.push_back( new RowSelection );
+ m_pImpl->aMouseFunctions.push_back( new ColumnSortHandler );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ DefaultInputHandler::~DefaultInputHandler()
+ {
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ namespace
+ {
+ bool lcl_delegateMouseEvent( DefaultInputHandler_Impl& i_impl, ITableControl& i_control, const MouseEvent& i_event,
+ FunctionResult ( IMouseFunction::*i_handlerMethod )( ITableControl&, const MouseEvent& ) )
+ {
+ if ( i_impl.pActiveFunction.is() )
+ {
+ bool furtherHandler = false;
+ switch ( (i_impl.pActiveFunction.get()->*i_handlerMethod)( i_control, i_event ) )
+ {
+ case ActivateFunction:
+ OSL_ENSURE( false, "lcl_delegateMouseEvent: unexpected - function already *is* active!" );
+ break;
+ case ContinueFunction:
+ break;
+ case DeactivateFunction:
+ i_impl.pActiveFunction.clear();
+ break;
+ case SkipFunction:
+ furtherHandler = true;
+ break;
+ }
+ if ( !furtherHandler )
+ // handled the event
+ return true;
+ }
+
+ // ask all other handlers
+ bool handled = false;
+ for ( MouseFunctions::iterator handler = i_impl.aMouseFunctions.begin();
+ ( handler != i_impl.aMouseFunctions.end() ) && !handled;
+ ++handler
+ )
+ {
+ if ( *handler == i_impl.pActiveFunction )
+ // we already invoked this function
+ continue;
+
+ switch ( (handler->get()->*i_handlerMethod)( i_control, i_event ) )
+ {
+ case ActivateFunction:
+ i_impl.pActiveFunction = *handler;
+ handled = true;
+ break;
+ case ContinueFunction:
+ case DeactivateFunction:
+ OSL_ENSURE( false, "lcl_delegateMouseEvent: unexpected: inactivate handler cannot be continued or deactivated!" );
+ break;
+ case SkipFunction:
+ handled = false;
+ break;
+ }
+ }
+ return handled;
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::MouseMove( ITableControl& i_tableControl, const MouseEvent& i_event )
+ {
+ return lcl_delegateMouseEvent( *m_pImpl, i_tableControl, i_event, &IMouseFunction::handleMouseMove );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::MouseButtonDown( ITableControl& i_tableControl, const MouseEvent& i_event )
+ {
+ return lcl_delegateMouseEvent( *m_pImpl, i_tableControl, i_event, &IMouseFunction::handleMouseDown );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::MouseButtonUp( ITableControl& i_tableControl, const MouseEvent& i_event )
+ {
+ return lcl_delegateMouseEvent( *m_pImpl, i_tableControl, i_event, &IMouseFunction::handleMouseUp );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::KeyInput( ITableControl& _rControl, const KeyEvent& rKEvt )
+ {
+ bool bHandled = false;
+
+ const KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nKeyCode = rKeyCode.GetCode();
+
+ struct _ActionMapEntry
+ {
+ sal_uInt16 nKeyCode;
+ sal_uInt16 nKeyModifier;
+ TableControlAction eAction;
+ }
+ static aKnownActions[] = {
+ { KEY_DOWN, 0, cursorDown },
+ { KEY_UP, 0, cursorUp },
+ { KEY_LEFT, 0, cursorLeft },
+ { KEY_RIGHT, 0, cursorRight },
+ { KEY_HOME, 0, cursorToLineStart },
+ { KEY_END, 0, cursorToLineEnd },
+ { KEY_PAGEUP, 0, cursorPageUp },
+ { KEY_PAGEDOWN, 0, cursorPageDown },
+ { KEY_PAGEUP, KEY_MOD1, cursorToFirstLine },
+ { KEY_PAGEDOWN, KEY_MOD1, cursorToLastLine },
+ { KEY_HOME, KEY_MOD1, cursorTopLeft },
+ { KEY_END, KEY_MOD1, cursorBottomRight },
+ { KEY_SPACE, KEY_MOD1, cursorSelectRow },
+ { KEY_UP, KEY_SHIFT, cursorSelectRowUp },
+ { KEY_DOWN, KEY_SHIFT, cursorSelectRowDown },
+ { KEY_END, KEY_SHIFT, cursorSelectRowAreaBottom },
+ { KEY_HOME, KEY_SHIFT, cursorSelectRowAreaTop },
+
+ { 0, 0, invalidTableControlAction }
+ };
+
+ const _ActionMapEntry* pActions = aKnownActions;
+ for ( ; pActions->eAction != invalidTableControlAction; ++pActions )
+ {
+ if ( ( pActions->nKeyCode == nKeyCode ) && ( pActions->nKeyModifier == rKeyCode.GetAllModifier() ) )
+ {
+ bHandled = _rControl.dispatchAction( pActions->eAction );
+ break;
+ }
+ }
+
+ return bHandled;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::GetFocus( ITableControl& _rControl )
+ {
+ _rControl.showCursor();
+ return false; // continue processing
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::LoseFocus( ITableControl& _rControl )
+ {
+ _rControl.hideCursor();
+ return false; // continue processing
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::RequestHelp( ITableControl& _rControl, const HelpEvent& _rHEvt )
+ {
+ (void)_rControl;
+ (void)_rHEvt;
+ // TODO
+ return false;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::Command( ITableControl& _rControl, const CommandEvent& _rCEvt )
+ {
+ (void)_rControl;
+ (void)_rCEvt;
+ // TODO
+ return false;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::PreNotify( ITableControl& _rControl, NotifyEvent& _rNEvt )
+ {
+ (void)_rControl;
+ (void)_rNEvt;
+ // TODO
+ return false;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool DefaultInputHandler::Notify( ITableControl& _rControl, NotifyEvent& _rNEvt )
+ {
+ (void)_rControl;
+ (void)_rNEvt;
+ // TODO
+ return false;
+ }
+//......................................................................................................................
+} } // namespace svt::table
+//......................................................................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/table/gridtablerenderer.cxx b/svtools/source/table/gridtablerenderer.cxx
new file mode 100644
index 000000000000..e69ad5589087
--- /dev/null
+++ b/svtools/source/table/gridtablerenderer.cxx
@@ -0,0 +1,621 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include "cellvalueconversion.hxx"
+#include "svtools/table/gridtablerenderer.hxx"
+#include "svtools/colorcfg.hxx"
+
+/** === begin UNO includes === **/
+#include <com/sun/star/graphic/XGraphic.hpp>
+/** === end UNO includes === **/
+
+#include <tools/debug.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/window.hxx>
+#include <vcl/image.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/decoview.hxx>
+
+//......................................................................................................................
+namespace svt { namespace table
+{
+//......................................................................................................................
+
+ /** === begin UNO using === **/
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::XInterface;
+ using ::com::sun::star::uno::TypeClass_INTERFACE;
+ using ::com::sun::star::graphic::XGraphic;
+ using ::com::sun::star::style::HorizontalAlignment;
+ using ::com::sun::star::style::HorizontalAlignment_LEFT;
+ using ::com::sun::star::style::HorizontalAlignment_CENTER;
+ using ::com::sun::star::style::HorizontalAlignment_RIGHT;
+ using ::com::sun::star::style::VerticalAlignment;
+ using ::com::sun::star::style::VerticalAlignment_TOP;
+ using ::com::sun::star::style::VerticalAlignment_MIDDLE;
+ using ::com::sun::star::style::VerticalAlignment_BOTTOM;
+ /** === end UNO using === **/
+
+ //==================================================================================================================
+ //= CachedSortIndicator
+ //==================================================================================================================
+ class CachedSortIndicator
+ {
+ public:
+ CachedSortIndicator()
+ :m_lastHeaderHeight( 0 )
+ ,m_lastArrowColor( COL_TRANSPARENT )
+ {
+ }
+
+ BitmapEx const & getBitmapFor( OutputDevice const & i_device, long const i_headerHeight, StyleSettings const & i_style, bool const i_sortAscending );
+
+ private:
+ long m_lastHeaderHeight;
+ Color m_lastArrowColor;
+ BitmapEx m_sortAscending;
+ BitmapEx m_sortDescending;
+ };
+
+ //------------------------------------------------------------------------------------------------------------------
+ BitmapEx const & CachedSortIndicator::getBitmapFor( OutputDevice const & i_device, long const i_headerHeight,
+ StyleSettings const & i_style, bool const i_sortAscending )
+ {
+ BitmapEx & rBitmap( i_sortAscending ? m_sortAscending : m_sortDescending );
+ if ( !rBitmap || ( i_headerHeight != m_lastHeaderHeight ) || ( i_style.GetActiveColor() != m_lastArrowColor ) )
+ {
+ long const nSortIndicatorWidth = 2 * i_headerHeight / 3;
+ long const nSortIndicatorHeight = 2 * nSortIndicatorWidth / 3;
+
+ Point const aBitmapPos( 0, 0 );
+ Size const aBitmapSize( nSortIndicatorWidth, nSortIndicatorHeight );
+ VirtualDevice aDevice( i_device, 0, 0 );
+ aDevice.SetOutputSizePixel( aBitmapSize );
+
+ DecorationView aDecoView( &aDevice );
+ aDecoView.DrawSymbol(
+ Rectangle( aBitmapPos, aBitmapSize ),
+ i_sortAscending ? SYMBOL_SPIN_UP : SYMBOL_SPIN_DOWN,
+ i_style.GetActiveColor()
+ );
+
+ rBitmap = aDevice.GetBitmapEx( aBitmapPos, aBitmapSize );
+ m_lastHeaderHeight = i_headerHeight;
+ m_lastArrowColor = i_style.GetActiveColor();
+ }
+ return rBitmap;
+ }
+
+ //==================================================================================================================
+ //= GridTableRenderer_Impl
+ //==================================================================================================================
+ struct GridTableRenderer_Impl
+ {
+ ITableModel& rModel;
+ RowPos nCurrentRow;
+ bool bUseGridLines;
+ CachedSortIndicator aSortIndicator;
+
+ GridTableRenderer_Impl( ITableModel& _rModel )
+ :rModel( _rModel )
+ ,nCurrentRow( ROW_INVALID )
+ ,bUseGridLines( true )
+ {
+ }
+ };
+
+ //==================================================================================================================
+ //= helper
+ //==================================================================================================================
+ namespace
+ {
+ static Rectangle lcl_getContentArea( GridTableRenderer_Impl const & i_impl, Rectangle const & i_cellArea )
+ {
+ Rectangle aContentArea( i_cellArea );
+ if ( i_impl.bUseGridLines )
+ {
+ --aContentArea.Right();
+ --aContentArea.Bottom();
+ }
+ return aContentArea;
+ }
+ static Rectangle lcl_getTextRenderingArea( Rectangle const & i_contentArea )
+ {
+ Rectangle aTextArea( i_contentArea );
+ aTextArea.Left() += 2; aTextArea.Right() -= 2;
+ ++aTextArea.Top(); --aTextArea.Bottom();
+ return aTextArea;
+ }
+
+ static sal_uLong lcl_getAlignmentTextDrawFlags( GridTableRenderer_Impl const & i_impl, ColPos const i_columnPos )
+ {
+ sal_uLong nVertFlag = TEXT_DRAW_TOP;
+ VerticalAlignment const eVertAlign = i_impl.rModel.getVerticalAlign();
+ switch ( eVertAlign )
+ {
+ case VerticalAlignment_MIDDLE: nVertFlag = TEXT_DRAW_VCENTER; break;
+ case VerticalAlignment_BOTTOM: nVertFlag = TEXT_DRAW_BOTTOM; break;
+ default:
+ break;
+ }
+
+ sal_uLong nHorzFlag = TEXT_DRAW_LEFT;
+ HorizontalAlignment const eHorzAlign = i_impl.rModel.getColumnModel( i_columnPos )->getHorizontalAlign();
+ switch ( eHorzAlign )
+ {
+ case HorizontalAlignment_CENTER: nHorzFlag = TEXT_DRAW_CENTER; break;
+ case HorizontalAlignment_RIGHT: nHorzFlag = TEXT_DRAW_RIGHT; break;
+ default:
+ break;
+ }
+
+ return nVertFlag | nHorzFlag;
+ }
+
+ }
+
+ //==================================================================================================================
+ //= GridTableRenderer
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ GridTableRenderer::GridTableRenderer( ITableModel& _rModel )
+ :m_pImpl( new GridTableRenderer_Impl( _rModel ) )
+ {
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ GridTableRenderer::~GridTableRenderer()
+ {
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ RowPos GridTableRenderer::getCurrentRow() const
+ {
+ return m_pImpl->nCurrentRow;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool GridTableRenderer::useGridLines() const
+ {
+ return m_pImpl->bUseGridLines;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void GridTableRenderer::useGridLines( bool const i_use )
+ {
+ m_pImpl->bUseGridLines = i_use;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ namespace
+ {
+ Color lcl_getEffectiveColor(
+ ::boost::optional< ::Color > const & i_modelColor,
+ StyleSettings const & i_styleSettings,
+ ::Color const & ( StyleSettings::*i_getDefaultColor ) () const
+ )
+ {
+ if ( !!i_modelColor )
+ return *i_modelColor;
+ return ( i_styleSettings.*i_getDefaultColor )();
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void GridTableRenderer::PaintHeaderArea(
+ OutputDevice& _rDevice, const Rectangle& _rArea, bool _bIsColHeaderArea, bool _bIsRowHeaderArea,
+ const StyleSettings& _rStyle )
+ {
+ OSL_PRECOND( _bIsColHeaderArea || _bIsRowHeaderArea,
+ "GridTableRenderer::PaintHeaderArea: invalid area flags!" );
+
+ _rDevice.Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
+
+ Color const background = lcl_getEffectiveColor( m_pImpl->rModel.getHeaderBackgroundColor(), _rStyle, &StyleSettings::GetDialogColor );
+ _rDevice.SetFillColor( background );
+
+ _rDevice.SetLineColor();
+ _rDevice.DrawRect( _rArea );
+
+ // delimiter lines at bottom/right
+ ::boost::optional< ::Color > aLineColor( m_pImpl->rModel.getLineColor() );
+ ::Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
+ _rDevice.SetLineColor( lineColor );
+ _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
+ _rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight() );
+
+ _rDevice.Pop();
+ (void)_bIsColHeaderArea;
+ (void)_bIsRowHeaderArea;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void GridTableRenderer::PaintColumnHeader( ColPos _nCol, bool _bActive, bool _bSelected,
+ OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle )
+ {
+ _rDevice.Push( PUSH_LINECOLOR);
+
+ String sHeaderText;
+ PColumnModel const pColumn = m_pImpl->rModel.getColumnModel( _nCol );
+ DBG_ASSERT( !!pColumn, "GridTableRenderer::PaintColumnHeader: invalid column model object!" );
+ if ( !!pColumn )
+ sHeaderText = pColumn->getName();
+
+ ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getTextColor(), _rStyle, &StyleSettings::GetFieldTextColor );
+ _rDevice.SetTextColor( textColor );
+
+ Rectangle const aTextRect( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, _rArea ) ) );
+ sal_uLong const nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, _nCol ) | TEXT_DRAW_CLIP;
+ _rDevice.DrawText( aTextRect, sHeaderText, nDrawTextFlags );
+
+ ::boost::optional< ::Color > const aLineColor( m_pImpl->rModel.getLineColor() );
+ ::Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
+ _rDevice.SetLineColor( lineColor );
+ _rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight());
+ _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
+
+ // draw sort indicator if the model data is sorted by the given column
+ ITableDataSort const * pSortAdapter = m_pImpl->rModel.getSortAdapter();
+ ColumnSort aCurrentSortOrder;
+ if ( pSortAdapter != NULL )
+ aCurrentSortOrder = pSortAdapter->getCurrentSortOrder();
+ if ( aCurrentSortOrder.nColumnPos == _nCol )
+ {
+ long const nHeaderHeight( _rArea.GetHeight() );
+ BitmapEx const aIndicatorBitmap = m_pImpl->aSortIndicator.getBitmapFor( _rDevice, nHeaderHeight, _rStyle,
+ aCurrentSortOrder.eSortDirection == ColumnSortAscending );
+ Size const aBitmapSize( aIndicatorBitmap.GetSizePixel() );
+ long const nSortIndicatorPaddingX = 2;
+ long const nSortIndicatorPaddingY = ( nHeaderHeight - aBitmapSize.Height() ) / 2;
+
+ if ( ( nDrawTextFlags & TEXT_DRAW_RIGHT ) != 0 )
+ {
+ // text is right aligned => draw the sort indicator at the left hand side
+ _rDevice.DrawBitmapEx(
+ Point( _rArea.Left() + nSortIndicatorPaddingX, _rArea.Top() + nSortIndicatorPaddingY ),
+ aIndicatorBitmap
+ );
+ }
+ else
+ {
+ // text is left-aligned or centered => draw the sort indicator at the right hand side
+ _rDevice.DrawBitmapEx(
+ Point( _rArea.Right() - nSortIndicatorPaddingX - aBitmapSize.Width(), nSortIndicatorPaddingY ),
+ aIndicatorBitmap
+ );
+ }
+ }
+
+ _rDevice.Pop();
+
+ (void)_bActive;
+ // no special painting for the active column at the moment
+
+ (void)_bSelected;
+ // selection for column header not yet implemented
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void GridTableRenderer::PrepareRow( RowPos _nRow, bool _bActive, bool _bSelected,
+ OutputDevice& _rDevice, const Rectangle& _rRowArea, const StyleSettings& _rStyle )
+ {
+ // remember the row for subsequent calls to the other ->ITableRenderer methods
+ m_pImpl->nCurrentRow = _nRow;
+
+ _rDevice.Push( PUSH_FILLCOLOR | PUSH_LINECOLOR);
+
+ ::Color backgroundColor = _rStyle.GetFieldColor();
+
+ ::boost::optional< ::Color > aLineColor( m_pImpl->rModel.getLineColor() );
+ ::Color lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
+
+ if ( _bSelected )
+ {
+ // selected rows use the background color from the style
+ backgroundColor = _rStyle.GetHighlightColor();
+ if ( !aLineColor )
+ lineColor = backgroundColor;
+ }
+ else
+ {
+ ::boost::optional< ::std::vector< ::Color > > aRowColors = m_pImpl->rModel.getRowBackgroundColors();
+ if ( !aRowColors )
+ {
+ // use alternating default colors
+ Color const fieldColor = _rStyle.GetFieldColor();
+ if ( _rStyle.GetHighContrastMode() || ( ( m_pImpl->nCurrentRow % 2 ) == 0 ) )
+ {
+ backgroundColor = fieldColor;
+ }
+ else
+ {
+ Color hilightColor = _rStyle.GetHighlightColor();
+ 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() );
+ backgroundColor = hilightColor;
+ }
+ }
+ else
+ {
+ if ( aRowColors->empty() )
+ {
+ // all colors have the same background color
+ backgroundColor = _rStyle.GetFieldColor();
+ }
+ else
+ {
+ backgroundColor = aRowColors->at( m_pImpl->nCurrentRow % aRowColors->size() );
+ }
+ }
+ }
+
+ //m_pImpl->bUseGridLines ? _rDevice.SetLineColor( lineColor ) : _rDevice.SetLineColor();
+ _rDevice.SetLineColor();
+ _rDevice.SetFillColor( backgroundColor );
+ _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,
+ const StyleSettings& _rStyle )
+ {
+ _rDevice.Push( PUSH_LINECOLOR | PUSH_TEXTCOLOR );
+
+ ::boost::optional< ::Color > const aLineColor( m_pImpl->rModel.getLineColor() );
+ ::Color const lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
+ _rDevice.SetLineColor( lineColor );
+ _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
+
+ Any const rowHeading( m_pImpl->rModel.getRowHeading( m_pImpl->nCurrentRow ) );
+ ::rtl::OUString const rowTitle( CellValueConversion::convertToString( rowHeading ) );
+ if ( rowTitle.getLength() )
+ {
+ ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getHeaderTextColor(), _rStyle, &StyleSettings::GetFieldTextColor );
+ _rDevice.SetTextColor( textColor );
+
+ Rectangle const aTextRect( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, _rArea ) ) );
+ sal_uLong const nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, 0 ) | TEXT_DRAW_CLIP;
+ // TODO: is using the horizontal alignment of the 0'th column a good idea here? This is pretty ... arbitray ..
+ _rDevice.DrawText( aTextRect, rowTitle, nDrawTextFlags );
+ }
+
+ // TODO: active? selected?
+ (void)_bActive;
+ (void)_bSelected;
+ _rDevice.Pop();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ struct GridTableRenderer::CellRenderContext
+ {
+ OutputDevice& rDevice;
+ Rectangle const aContentArea;
+ StyleSettings const & rStyle;
+ ColPos const nColumn;
+ bool const bSelected;
+
+ CellRenderContext( OutputDevice& i_device, Rectangle const & i_contentArea,
+ StyleSettings const & i_style, ColPos const i_column, bool const i_selected )
+ :rDevice( i_device )
+ ,aContentArea( i_contentArea )
+ ,rStyle( i_style )
+ ,nColumn( i_column )
+ ,bSelected( i_selected )
+ {
+ }
+ };
+
+ //------------------------------------------------------------------------------------------------------------------
+ void GridTableRenderer::PaintCell( ColPos const i_column, bool _bSelected, bool _bActive,
+ 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 );
+ impl_paintCellContent( aRenderContext );
+
+ if ( m_pImpl->bUseGridLines )
+ {
+ ::boost::optional< ::Color > aLineColor( m_pImpl->rModel.getLineColor() );
+ ::Color lineColor = !aLineColor ? _rStyle.GetSeparatorColor() : *aLineColor;
+
+ 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();
+ }
+
+ _rDevice.SetLineColor( lineColor );
+ _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
+ _rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight() );
+ }
+
+ _rDevice.Pop();
+
+ (void)_bActive;
+ // no special painting for the active cell at the moment
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void GridTableRenderer::impl_paintCellImage( CellRenderContext const & i_context, Image const & i_image )
+ {
+ Point imagePos( Point( i_context.aContentArea.Left(), i_context.aContentArea.Top() ) );
+ Size imageSize = i_image.GetSizePixel();
+ if ( i_context.aContentArea.GetWidth() > imageSize.Width() )
+ {
+ const HorizontalAlignment eHorzAlign = m_pImpl->rModel.getColumnModel( i_context.nColumn )->getHorizontalAlign();
+ switch ( eHorzAlign )
+ {
+ case HorizontalAlignment_CENTER:
+ imagePos.X() += ( i_context.aContentArea.GetWidth() - imageSize.Width() ) / 2;
+ break;
+ case HorizontalAlignment_RIGHT:
+ imagePos.X() = i_context.aContentArea.Right() - imageSize.Width();
+ break;
+ default:
+ break;
+ }
+
+ }
+ else
+ imageSize.Width() = i_context.aContentArea.GetWidth();
+
+ if ( i_context.aContentArea.GetHeight() > imageSize.Height() )
+ {
+ const VerticalAlignment eVertAlign = m_pImpl->rModel.getVerticalAlign();
+ switch ( eVertAlign )
+ {
+ case VerticalAlignment_MIDDLE:
+ imagePos.Y() += ( i_context.aContentArea.GetHeight() - imageSize.Height() ) / 2;
+ break;
+ case VerticalAlignment_BOTTOM:
+ imagePos.Y() = i_context.aContentArea.Bottom() - imageSize.Height();
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ imageSize.Height() = i_context.aContentArea.GetHeight() - 1;
+
+ i_context.rDevice.DrawImage( imagePos, imageSize, i_image, 0 );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void GridTableRenderer::impl_paintCellContent( CellRenderContext const & i_context )
+ {
+ Any aCellContent;
+ m_pImpl->rModel.getCellContent( i_context.nColumn, m_pImpl->nCurrentRow, aCellContent );
+
+ if ( aCellContent.getValueTypeClass() == TypeClass_INTERFACE )
+ {
+ Reference< XInterface > const xContentInterface( aCellContent, UNO_QUERY );
+ if ( !xContentInterface.is() )
+ // allowed. kind of.
+ return;
+
+ Reference< XGraphic > const xGraphic( aCellContent, UNO_QUERY );
+ ENSURE_OR_RETURN_VOID( xGraphic.is(), "GridTableRenderer::impl_paintCellContent: only XGraphic interfaces (or NULL) are supported for painting." );
+
+ const Image aImage( xGraphic );
+ impl_paintCellImage( i_context, aImage );
+ return;
+ }
+
+ const ::rtl::OUString sText( CellValueConversion::convertToString( aCellContent ) );
+ impl_paintCellText( i_context, sText );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ 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() );
+ else
+ {
+ ::Color const textColor = lcl_getEffectiveColor( m_pImpl->rModel.getTextColor(), i_context.rStyle, &StyleSettings::GetFieldTextColor );
+ i_context.rDevice.SetTextColor( textColor );
+ }
+
+ Rectangle const textRect( lcl_getTextRenderingArea( i_context.aContentArea ) );
+ sal_uLong const nDrawTextFlags = lcl_getAlignmentTextDrawFlags( *m_pImpl, i_context.nColumn ) | TEXT_DRAW_CLIP;
+ i_context.rDevice.DrawText( textRect, i_text, nDrawTextFlags );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void GridTableRenderer::ShowCellCursor( Window& _rView, const Rectangle& _rCursorRect)
+ {
+ _rView.ShowFocus( _rCursorRect );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void GridTableRenderer::HideCellCursor( Window& _rView, const Rectangle& _rCursorRect)
+ {
+ (void)_rCursorRect;
+ _rView.HideFocus();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ 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 )
+ {
+ if ( !i_cellContent.hasValue() )
+ return true;
+
+ if ( i_cellContent.getValueTypeClass() == TypeClass_INTERFACE )
+ {
+ Reference< XInterface > const xContentInterface( i_cellContent, UNO_QUERY );
+ if ( !xContentInterface.is() )
+ return true;
+
+ Reference< XGraphic > const xGraphic( i_cellContent, UNO_QUERY );
+ if ( xGraphic.is() )
+ // for the moment, assume it fits. We can always scale it down during painting ...
+ return true;
+
+ OSL_ENSURE( false, "GridTableRenderer::FitsIntoCell: only XGraphic interfaces (or NULL) are supported for painting." );
+ return true;
+ }
+
+ ::rtl::OUString const sText( CellValueConversion::convertToString( i_cellContent ) );
+ if ( sText.getLength() == 0 )
+ return true;
+
+ Rectangle const aTargetArea( lcl_getTextRenderingArea( lcl_getContentArea( *m_pImpl, i_targetArea ) ) );
+
+ long const nTextHeight = i_targetDevice.GetTextHeight();
+ if ( nTextHeight > aTargetArea.GetHeight() )
+ return false;
+
+ long const nTextWidth = i_targetDevice.GetTextWidth( sText );
+ if ( nTextWidth > aTargetArea.GetWidth() )
+ return false;
+
+ OSL_UNUSED( i_active );
+ OSL_UNUSED( i_selected );
+ OSL_UNUSED( i_rowPos );
+ OSL_UNUSED( i_colPos );
+ return true;
+ }
+
+//......................................................................................................................
+} } // namespace svt::table
+//......................................................................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/table/mousefunction.cxx b/svtools/source/table/mousefunction.cxx
new file mode 100644
index 000000000000..20d505e911e9
--- /dev/null
+++ b/svtools/source/table/mousefunction.cxx
@@ -0,0 +1,320 @@
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_svtools.hxx"
+
+#include "mousefunction.hxx"
+#include "svtools/table/tablecontrolinterface.hxx"
+
+#include <tools/diagnose_ex.h>
+#include <vcl/window.hxx>
+
+//......................................................................................................................
+namespace svt { namespace table
+{
+//......................................................................................................................
+
+ //==================================================================================================================
+ //= MouseFunction
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ oslInterlockedCount MouseFunction::acquire()
+ {
+ return osl_incrementInterlockedCount( &m_refCount );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ oslInterlockedCount MouseFunction::release()
+ {
+ oslInterlockedCount newCount = osl_decrementInterlockedCount( &m_refCount );
+ if ( newCount == 0 )
+ {
+ delete this;
+ return 0;
+ }
+ return newCount;
+ }
+
+ //==================================================================================================================
+ //= ColumnResize
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ FunctionResult ColumnResize::handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event )
+ {
+ Point const aPoint = i_event.GetPosPixel();
+
+ if ( m_nResizingColumn == COL_INVALID )
+ {
+ // if we hit a column divider, change the mosue pointer accordingly
+ Pointer aNewPointer( POINTER_ARROW );
+ TableCell const tableCell = i_tableControl.hitTest( aPoint );
+ if ( ( tableCell.nRow == ROW_COL_HEADERS ) && ( tableCell.eArea == ColumnDivider ) )
+ {
+ aNewPointer = Pointer( POINTER_HSPLIT );
+ }
+ i_tableControl.setPointer( aNewPointer );
+
+ return SkipFunction; // TODO: is this correct?
+ }
+
+ ::Size const tableSize = i_tableControl.getTableSizePixel();
+
+ // set proper pointer
+ Pointer aNewPointer( POINTER_ARROW );
+ ColumnMetrics const & columnMetrics( i_tableControl.getColumnMetrics( m_nResizingColumn ) );
+ if ( ( aPoint.X() > tableSize.Width() )
+ || ( aPoint.X() < columnMetrics.nStartPixel )
+ )
+ {
+ aNewPointer = Pointer( POINTER_NOTALLOWED );
+ }
+ else
+ {
+ aNewPointer = Pointer( POINTER_HSPLIT );
+ }
+ i_tableControl.setPointer( aNewPointer );
+
+ // show tracking line
+ i_tableControl.hideTracking();
+ i_tableControl.showTracking(
+ Rectangle(
+ Point( aPoint.X(), 0 ),
+ Size( 1, tableSize.Height() )
+ ),
+ SHOWTRACK_SPLIT | SHOWTRACK_WINDOW
+ );
+
+ (void)i_event;
+ return ContinueFunction;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ FunctionResult ColumnResize::handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event )
+ {
+ if ( m_nResizingColumn != COL_INVALID )
+ {
+ OSL_ENSURE( false, "ColumnResize::handleMouseDown: suspicious: MouseButtonDown while still tracking?" );
+ return ContinueFunction;
+ }
+
+ TableCell const tableCell( i_tableControl.hitTest( i_event.GetPosPixel() ) );
+ if ( tableCell.nRow == ROW_COL_HEADERS )
+ {
+ if ( ( tableCell.nColumn != COL_INVALID )
+ && ( tableCell.eArea == ColumnDivider )
+ )
+ {
+ m_nResizingColumn = tableCell.nColumn;
+ i_tableControl.captureMouse();
+ return ActivateFunction;
+ }
+ }
+
+ return SkipFunction;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ FunctionResult ColumnResize::handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event )
+ {
+ if ( m_nResizingColumn == COL_INVALID )
+ return SkipFunction;
+
+ Point const aPoint = i_event.GetPosPixel();
+
+ i_tableControl.hideTracking();
+ PColumnModel const pColumn = i_tableControl.getModel()->getColumnModel( m_nResizingColumn );
+ long const maxWidthLogical = pColumn->getMaxWidth();
+ long const minWidthLogical = pColumn->getMinWidth();
+
+ // new position of mouse
+ long const requestedEnd = aPoint.X();
+
+ // old position of right border
+ long const oldEnd = i_tableControl.getColumnMetrics( m_nResizingColumn ).nEndPixel;
+
+ // position of left border if cursor in the to-be-resized column
+ long const columnStart = i_tableControl.getColumnMetrics( m_nResizingColumn ).nStartPixel;
+ long const requestedWidth = requestedEnd - columnStart;
+ // TODO: this is not correct, strictly: It assumes that the mouse was pressed exactly on the "end" pos,
+ // but for a while now, we have relaxed this, and allow clicking a few pixels aside, too
+
+ if ( requestedEnd >= columnStart )
+ {
+ long requestedWidthLogical = i_tableControl.pixelWidthToAppFont( requestedWidth );
+ // respect column width limits
+ if ( oldEnd > requestedEnd )
+ {
+ // column has become smaller, check against minimum width
+ if ( ( minWidthLogical != 0 ) && ( requestedWidthLogical < minWidthLogical ) )
+ requestedWidthLogical = minWidthLogical;
+ }
+ else if ( oldEnd < requestedEnd )
+ {
+ // column has become larger, check against max width
+ if ( ( maxWidthLogical != 0 ) && ( requestedWidthLogical >= maxWidthLogical ) )
+ requestedWidthLogical = maxWidthLogical;
+ }
+ pColumn->setWidth( requestedWidthLogical );
+ i_tableControl.invalidate( TableAreaAll );
+ }
+
+ i_tableControl.setPointer( Pointer() );
+ i_tableControl.releaseMouse();
+
+ m_nResizingColumn = COL_INVALID;
+ return DeactivateFunction;
+ }
+
+ //==================================================================================================================
+ //= RowSelection
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ FunctionResult RowSelection::handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event )
+ {
+ OSL_UNUSED( i_tableControl );
+ OSL_UNUSED( i_event );
+ return SkipFunction;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ FunctionResult RowSelection::handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event )
+ {
+ bool handled = false;
+
+ 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;
+ }
+ 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;
+ }
+ }
+
+ if ( handled )
+ m_bActive = true;
+ return handled ? ActivateFunction : SkipFunction;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ FunctionResult RowSelection::handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event )
+ {
+ TableCell const tableCell = i_tableControl.hitTest( i_event.GetPosPixel() );
+ if ( tableCell.nRow >= 0 )
+ {
+ if ( i_tableControl.getSelEngine()->GetSelectionMode() != NO_SELECTION )
+ {
+ i_tableControl.getSelEngine()->SelMouseButtonUp( i_event );
+ }
+ }
+ if ( m_bActive )
+ {
+ m_bActive = false;
+ return DeactivateFunction;
+ }
+ return SkipFunction;
+ }
+
+ //==================================================================================================================
+ //= ColumnSortHandler
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ FunctionResult ColumnSortHandler::handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event )
+ {
+ OSL_UNUSED( i_tableControl );
+ OSL_UNUSED( i_event );
+ return SkipFunction;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ FunctionResult ColumnSortHandler::handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event )
+ {
+ if ( m_nActiveColumn != COL_INVALID )
+ {
+ OSL_ENSURE( false, "ColumnSortHandler::handleMouseDown: called while already active - suspicious!" );
+ return ContinueFunction;
+ }
+
+ if ( i_tableControl.getModel()->getSortAdapter() == NULL )
+ // no sorting support at the model
+ return SkipFunction;
+
+ TableCell const tableCell( i_tableControl.hitTest( i_event.GetPosPixel() ) );
+ if ( ( tableCell.nRow != ROW_COL_HEADERS ) || ( tableCell.nColumn < 0 ) )
+ return SkipFunction;
+
+ // TODO: ensure the column header is rendered in some special way, indicating its current state
+
+ m_nActiveColumn = tableCell.nColumn;
+ return ActivateFunction;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ FunctionResult ColumnSortHandler::handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event )
+ {
+ if ( m_nActiveColumn == COL_INVALID )
+ return SkipFunction;
+
+ TableCell const tableCell( i_tableControl.hitTest( i_event.GetPosPixel() ) );
+ if ( ( tableCell.nRow == ROW_COL_HEADERS ) && ( tableCell.nColumn == m_nActiveColumn ) )
+ {
+ ITableDataSort* pSort = i_tableControl.getModel()->getSortAdapter();
+ ENSURE_OR_RETURN( pSort != NULL, "ColumnSortHandler::handleMouseUp: somebody is mocking with us!", DeactivateFunction );
+ // in handleMousButtonDown, the model claimed to have sort support ...
+
+ ColumnSortDirection eSortDirection = ColumnSortAscending;
+ ColumnSort const aCurrentSort = pSort->getCurrentSortOrder();
+ if ( aCurrentSort.nColumnPos == m_nActiveColumn )
+ // invert existing sort order
+ eSortDirection = ( aCurrentSort.eSortDirection == ColumnSortAscending ) ? ColumnSortDescending : ColumnSortAscending;
+
+ pSort->sortByColumn( m_nActiveColumn, eSortDirection );
+ }
+
+ m_nActiveColumn = COL_INVALID;
+ return DeactivateFunction;
+ }
+
+//......................................................................................................................
+} } // namespace svt::table
+//......................................................................................................................
diff --git a/svtools/source/table/mousefunction.hxx b/svtools/source/table/mousefunction.hxx
new file mode 100644
index 000000000000..2149026a0923
--- /dev/null
+++ b/svtools/source/table/mousefunction.hxx
@@ -0,0 +1,161 @@
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#ifndef SVTOOLS_MOUSEFUNCTION_HXX
+#define SVTOOLS_MOUSEFUNCTION_HXX
+
+#include "svtools/table/tabletypes.hxx"
+
+#include <rtl/ref.hxx>
+
+#include <boost/noncopyable.hpp>
+
+class MouseEvent;
+
+//......................................................................................................................
+namespace svt { namespace table
+{
+//......................................................................................................................
+
+ class ITableControl;
+
+ //==================================================================================================================
+ //= FunctionResult
+ //==================================================================================================================
+ enum FunctionResult
+ {
+ ActivateFunction,
+ ContinueFunction,
+ DeactivateFunction,
+
+ SkipFunction
+ };
+
+ //==================================================================================================================
+ //= IMouseFunction
+ //==================================================================================================================
+ class IMouseFunction : public ::rtl::IReference, public ::boost::noncopyable
+ {
+ public:
+ virtual FunctionResult handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event ) = 0;
+ virtual FunctionResult handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event ) = 0;
+ virtual FunctionResult handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event ) = 0;
+
+ protected:
+ virtual ~IMouseFunction() { }
+ };
+
+ //==================================================================================================================
+ //= MouseFunction
+ //==================================================================================================================
+ class MouseFunction : public IMouseFunction
+ {
+ public:
+ MouseFunction()
+ :m_refCount( 0 )
+ {
+ }
+ protected:
+ ~MouseFunction()
+ {
+ }
+
+ public:
+ virtual oslInterlockedCount SAL_CALL acquire();
+ virtual oslInterlockedCount SAL_CALL release();
+
+ private:
+ oslInterlockedCount m_refCount;
+ };
+
+ //==================================================================================================================
+ //= ColumnResize
+ //==================================================================================================================
+ class ColumnResize : public MouseFunction
+ {
+ public:
+ ColumnResize()
+ :m_nResizingColumn( COL_INVALID )
+ {
+ }
+
+ public:
+ // IMouseFunction
+ virtual FunctionResult handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event );
+ virtual FunctionResult handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event );
+ virtual FunctionResult handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event );
+
+ private:
+ ColPos m_nResizingColumn;
+ };
+
+ //==================================================================================================================
+ //= RowSelection
+ //==================================================================================================================
+ class RowSelection : public MouseFunction
+ {
+ public:
+ RowSelection()
+ :m_bActive( false )
+ {
+ }
+
+ public:
+ // IMouseFunction
+ virtual FunctionResult handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event );
+ virtual FunctionResult handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event );
+ virtual FunctionResult handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event );
+
+ private:
+ bool m_bActive;
+ };
+
+ //==================================================================================================================
+ //= ColumnSortHandler
+ //==================================================================================================================
+ class ColumnSortHandler : public MouseFunction
+ {
+ public:
+ ColumnSortHandler()
+ :m_nActiveColumn( COL_INVALID )
+ {
+ }
+
+ public:
+ // IMouseFunction
+ virtual FunctionResult handleMouseMove( ITableControl& i_tableControl, MouseEvent const & i_event );
+ virtual FunctionResult handleMouseDown( ITableControl& i_tableControl, MouseEvent const & i_event );
+ virtual FunctionResult handleMouseUp( ITableControl& i_tableControl, MouseEvent const & i_event );
+
+ private:
+ ColPos m_nActiveColumn;
+ };
+
+//......................................................................................................................
+} } // namespace svt::table
+//......................................................................................................................
+
+#endif // SVTOOLS_MOUSEFUNCTION_HXX
diff --git a/svtools/source/table/tablecontrol.cxx b/svtools/source/table/tablecontrol.cxx
new file mode 100644
index 000000000000..6ec1ec5e7121
--- /dev/null
+++ b/svtools/source/table/tablecontrol.cxx
@@ -0,0 +1,613 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include "svtools/table/tablecontrol.hxx"
+
+#include "tablegeometry.hxx"
+#include "tablecontrol_impl.hxx"
+#include "tabledatawindow.hxx"
+
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::uno;
+using ::com::sun::star::accessibility::XAccessible;
+using namespace ::com::sun::star::accessibility;
+using namespace ::com::sun::star::lang;
+using namespace utl;
+//......................................................................................................................
+namespace svt { namespace table
+{
+//......................................................................................................................
+
+ //==================================================================================================================
+ //= TableControl
+ //==================================================================================================================
+ // -----------------------------------------------------------------------------------------------------------------
+ TableControl::TableControl( Window* _pParent, WinBits _nStyle )
+ :Control( _pParent, _nStyle )
+ ,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 );
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ TableControl::~TableControl()
+ {
+ ImplCallEventListeners( VCLEVENT_OBJECT_DYING );
+
+ m_pImpl->setModel( PTableModel() );
+ m_pImpl->disposeAccessible();
+ m_pImpl.reset();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ void TableControl::GetFocus()
+ {
+ if ( !m_pImpl->getInputHandler()->GetFocus( *m_pImpl ) )
+ Control::GetFocus();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ void TableControl::LoseFocus()
+ {
+ if ( !m_pImpl->getInputHandler()->LoseFocus( *m_pImpl ) )
+ Control::LoseFocus();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ void TableControl::KeyInput( const KeyEvent& rKEvt )
+ {
+ if ( !m_pImpl->getInputHandler()->KeyInput( *m_pImpl, rKEvt ) )
+ Control::KeyInput( rKEvt );
+ }
+
+
+ // -----------------------------------------------------------------------------------------------------------------
+ void TableControl::StateChanged( StateChangedType i_nStateChange )
+ {
+ Control::StateChanged( i_nStateChange );
+
+ // forward certain settings to the data window
+ switch ( i_nStateChange )
+ {
+ case STATE_CHANGE_CONTROLBACKGROUND:
+ if ( IsControlBackground() )
+ getDataWindow().SetControlBackground( GetControlBackground() );
+ else
+ getDataWindow().SetControlBackground();
+ break;
+
+ case STATE_CHANGE_CONTROLFOREGROUND:
+ if ( IsControlForeground() )
+ getDataWindow().SetControlForeground( GetControlForeground() );
+ else
+ getDataWindow().SetControlForeground();
+ break;
+
+ case STATE_CHANGE_CONTROLFONT:
+ if ( IsControlFont() )
+ getDataWindow().SetControlFont( GetControlFont() );
+ else
+ getDataWindow().SetControlFont();
+ break;
+ }
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ void TableControl::Resize()
+ {
+ Control::Resize();
+ m_pImpl->onResize();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ void TableControl::SetModel( PTableModel _pModel )
+ {
+ m_pImpl->setModel( _pModel );
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ PTableModel TableControl::GetModel() const
+ {
+ return m_pImpl->getModel();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ RowPos TableControl::GetTopRow() const
+ {
+ return m_pImpl->getTopRow();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ void TableControl::SetTopRow( RowPos _nRow )
+ {
+ OSL_ENSURE( false, "TableControl::SetTopRow: not implemented!" );
+ OSL_UNUSED( _nRow );
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ sal_Int32 TableControl::GetCurrentRow() const
+ {
+ return m_pImpl->getCurrentRow();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ sal_Int32 TableControl::GetCurrentColumn() const
+ {
+ return m_pImpl->getCurrentColumn();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ bool TableControl::GoTo( ColPos _nColumn, RowPos _nRow )
+ {
+ return m_pImpl->goTo( _nColumn, _nRow );
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ sal_Bool TableControl::GoToCell(sal_Int32 _nColPos, sal_Int32 _nRowPos)
+ {
+ return m_pImpl->goTo( _nColPos, _nRowPos );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Int32 TableControl::GetSelectedRowCount() const
+ {
+ return sal_Int32( m_pImpl->getSelectedRowCount() );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Int32 TableControl::GetSelectedRowIndex( sal_Int32 const i_selectionIndex ) const
+ {
+ return sal_Int32( m_pImpl->getSelectedRowIndex( i_selectionIndex ) );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool TableControl::IsRowSelected( sal_Int32 const i_rowIndex ) const
+ {
+ return m_pImpl->isRowSelected( i_rowIndex );
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ 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)!" );
+
+ if ( i_select )
+ {
+ if ( !m_pImpl->markRowAsSelected( i_rowIndex ) )
+ // nothing to do
+ return;
+ }
+ else
+ {
+ m_pImpl->markRowAsDeselected( i_rowIndex );
+ }
+
+ m_pImpl->invalidateRowRange( i_rowIndex, i_rowIndex );
+ Select();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ void TableControl::SelectAllRows( bool const i_select )
+ {
+ if ( i_select )
+ {
+ if ( !m_pImpl->markAllRowsAsSelected() )
+ // nothing to do
+ return;
+ }
+ else
+ {
+ if ( !m_pImpl->markAllRowsAsDeselected() )
+ // nothing to do
+ return;
+ }
+
+
+ Invalidate();
+ // TODO: can't we do better than this, and invalidate only the rows which changed?
+ Select();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ ITableControl& TableControl::getTableControlInterface()
+ {
+ return *m_pImpl;
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ SelectionEngine* TableControl::getSelEngine()
+ {
+ return m_pImpl->getSelEngine();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ Window& TableControl::getDataWindow()
+ {
+ return m_pImpl->getDataWindow();
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ Reference< XAccessible > TableControl::CreateAccessible()
+ {
+ Window* pParent = GetAccessibleParentWindow();
+ ENSURE_OR_RETURN( pParent, "TableControl::CreateAccessible - parent not found", NULL );
+
+ return m_pImpl->getAccessible( *pParent );
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ Reference<XAccessible> TableControl::CreateAccessibleControl( sal_Int32 _nIndex )
+ {
+ (void)_nIndex;
+ DBG_ASSERT( sal_False, "TableControl::CreateAccessibleControl: to be overwritten!" );
+ return NULL;
+ }
+
+ // -----------------------------------------------------------------------------------------------------------------
+ ::rtl::OUString TableControl::GetAccessibleObjectName( AccessibleTableControlObjType eObjType, sal_Int32 _nRow, sal_Int32 _nCol) const
+ {
+ ::rtl::OUString aRetText;
+ //Window* pWin;
+ switch( eObjType )
+ {
+ case TCTYPE_GRIDCONTROL:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GridControl" ) );
+ break;
+ case TCTYPE_TABLE:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Table" ) );
+ break;
+ case TCTYPE_ROWHEADERBAR:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RowHeaderBar" ) );
+ break;
+ case TCTYPE_COLUMNHEADERBAR:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ColumnHeaderBar" ) );
+ break;
+ case TCTYPE_TABLECELL:
+ aRetText = GetAccessibleCellText(_nRow, _nCol);
+ break;
+ case TCTYPE_ROWHEADERCELL:
+ aRetText = GetRowName(_nRow);
+ break;
+ case TCTYPE_COLUMNHEADERCELL:
+ aRetText = GetColumnName(_nCol);
+ break;
+ default:
+ OSL_FAIL("GridControl::GetAccessibleName: invalid enum!");
+ }
+ return aRetText;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ::rtl::OUString TableControl::GetAccessibleObjectDescription( AccessibleTableControlObjType eObjType, sal_Int32 ) const
+ {
+ ::rtl::OUString aRetText;
+ switch( eObjType )
+ {
+ case TCTYPE_GRIDCONTROL:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GridControl description" ) );
+ break;
+ case TCTYPE_TABLE:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TABLE description" ) );
+ break;
+ case TCTYPE_ROWHEADERBAR:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ROWHEADERBAR description" ) );
+ break;
+ case TCTYPE_COLUMNHEADERBAR:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "COLUMNHEADERBAR description" ) );
+ break;
+ case TCTYPE_TABLECELL:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TABLECELL description" ) );
+ break;
+ case TCTYPE_ROWHEADERCELL:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ROWHEADERCELL description" ) );
+ break;
+ case TCTYPE_COLUMNHEADERCELL:
+ aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "COLUMNHEADERCELL description" ) );
+ break;
+ }
+ return aRetText;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ::rtl::OUString TableControl::GetRowDescription( sal_Int32 _nRow) const
+ {
+ (void)_nRow;
+ return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "row description" ) );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ::rtl::OUString TableControl::GetRowName( sal_Int32 _nIndex) const
+ {
+ ::rtl::OUString sRowName;
+ GetModel()->getRowHeading( _nIndex ) >>= sRowName;
+ return sRowName;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ::rtl::OUString TableControl::GetColumnDescription( sal_uInt16 _nColumn) const
+ {
+ (void)_nColumn;
+ return rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "col description" ) );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ::rtl::OUString TableControl::GetColumnName( sal_Int32 _nIndex) const
+ {
+ return GetModel()->getColumnModel(_nIndex)->getName();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ::com::sun::star::uno::Any TableControl::GetCellContent( sal_Int32 _nRowPos, sal_Int32 _nColPos ) const
+ {
+ Any aCellContent;
+ GetModel()->getCellContent( _nColPos, _nRowPos, aCellContent );
+ return aCellContent;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ::rtl::OUString TableControl::GetAccessibleCellText( sal_Int32 _nRowPos, sal_Int32 _nColPos) const
+ {
+ return m_pImpl->getCellContentAsString( _nRowPos, _nColPos );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl::FillAccessibleStateSet(
+ ::utl::AccessibleStateSetHelper& rStateSet,
+ AccessibleTableControlObjType eObjType ) const
+ {
+ switch( eObjType )
+ {
+ case TCTYPE_GRIDCONTROL:
+ case TCTYPE_TABLE:
+
+ rStateSet.AddState( AccessibleStateType::FOCUSABLE );
+ rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE);
+ if ( HasFocus() )
+ rStateSet.AddState( AccessibleStateType::FOCUSED );
+ if ( IsActive() )
+ rStateSet.AddState( AccessibleStateType::ACTIVE );
+ if ( IsEnabled() )
+ rStateSet.AddState( AccessibleStateType::ENABLED );
+ if ( IsReallyVisible() )
+ rStateSet.AddState( AccessibleStateType::VISIBLE );
+ 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::TRANSIENT );
+ rStateSet.AddState( AccessibleStateType::SELECTABLE);
+ if( GetSelectedRowCount()>0)
+ 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;
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Rectangle TableControl::GetWindowExtentsRelative( Window *pRelativeWindow ) const
+ {
+ return Control::GetWindowExtentsRelative( pRelativeWindow );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl::GrabFocus()
+ {
+ Control::GrabFocus();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Reference< XAccessible > TableControl::GetAccessible( sal_Bool bCreate )
+ {
+ return Control::GetAccessible( bCreate );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Window* TableControl::GetAccessibleParentWindow() const
+ {
+ return Control::GetAccessibleParentWindow();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Window* TableControl::GetWindowInstance()
+ {
+ return this;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Bool TableControl::HasRowHeader()
+ {
+ return GetModel()->hasRowHeaders();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Bool TableControl::HasColHeader()
+ {
+ return GetModel()->hasColumnHeaders();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Int32 TableControl::GetAccessibleControlCount() const
+ {
+ sal_Int32 count = 0;
+ if(GetRowCount()>0)
+ count+=1;
+ if(GetModel()->hasRowHeaders())
+ count+=1;
+ if(GetModel()->hasColumnHeaders())
+ count+=1;
+ return count;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Bool TableControl::ConvertPointToControlIndex( sal_Int32& _rnIndex, const Point& _rPoint )
+ {
+ sal_Int32 nRow = m_pImpl->getRowAtPoint( _rPoint );
+ sal_Int32 nCol = m_pImpl->getColAtPoint( _rPoint );
+ _rnIndex = nRow * GetColumnCount() + nCol;
+ return nRow >= 0 ? sal_True : sal_False;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ long TableControl::GetRowCount() const
+ {
+ return GetModel()->getRowCount();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ long TableControl::GetColumnCount() const
+ {
+ return GetModel()->getColumnCount();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Bool TableControl::HasRowHeader() const
+ {
+ return GetModel()->hasRowHeaders();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Bool TableControl::ConvertPointToCellAddress( sal_Int32& _rnRow, sal_Int32& _rnColPos, const Point& _rPoint )
+ {
+ _rnRow = m_pImpl->getRowAtPoint( _rPoint );
+ _rnColPos = m_pImpl->getColAtPoint( _rPoint );
+ return _rnRow >= 0 ? sal_True : sal_False;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl::FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumnPos ) const
+ {
+ if ( GetCurrentRow() == _nRow && GetCurrentColumn() == _nColumnPos )
+ _rStateSet.AddState( AccessibleStateType::FOCUSED );
+ else // only transient when column is not focused
+ _rStateSet.AddState( AccessibleStateType::TRANSIENT );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Rectangle TableControl::GetFieldCharacterBounds(sal_Int32 _nRow,sal_Int32 _nColumnPos,sal_Int32 nIndex)
+ {
+ (void)_nRow;
+ (void)_nColumnPos;
+ return GetCharacterBounds(nIndex);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Int32 TableControl::GetFieldIndexAtPoint(sal_Int32 _nRow,sal_Int32 _nColumnPos,const Point& _rPoint)
+ {
+ (void)_nRow;
+ (void)_nColumnPos;
+ return GetIndexForPoint(_rPoint);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Rectangle TableControl::calcHeaderRect(sal_Bool _bIsColumnBar,sal_Bool _bOnScreen)
+ {
+ (void)_bOnScreen;
+ return m_pImpl->calcHeaderRect( _bIsColumnBar ? false : true );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Rectangle TableControl::calcTableRect(sal_Bool _bOnScreen)
+ {
+ (void)_bOnScreen;
+ return m_pImpl->calcTableRect();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ IMPL_LINK( TableControl, ImplSelectHdl, void*, EMPTYARG )
+ {
+ Select();
+ return 1;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ IMPL_LINK( TableControl, ImplMouseButtonDownHdl, MouseEvent*, pData )
+ {
+ CallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, pData );
+ return 1;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ IMPL_LINK( TableControl, ImplMouseButtonUpHdl, MouseEvent*, pData )
+ {
+ CallEventListeners( VCLEVENT_WINDOW_MOUSEBUTTONUP, pData );
+ return 1;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl::Select()
+ {
+ ImplCallEventListenersAndHandler( VCLEVENT_TABLEROW_SELECT, m_pImpl->getSelectHandler(), this );
+ }
+//........................................................................
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl::SetSelectHdl( const Link& i_selectHandler )
+ {
+ m_pImpl->setSelectHandler( i_selectHandler );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ const Link& TableControl::GetSelectHdl() const
+ {
+ return m_pImpl->getSelectHandler();
+ }
+}} // namespace svt::table
+
+//......................................................................................................................
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/table/tablecontrol_impl.cxx b/svtools/source/table/tablecontrol_impl.cxx
new file mode 100644
index 000000000000..bbcdbfaddeb6
--- /dev/null
+++ b/svtools/source/table/tablecontrol_impl.cxx
@@ -0,0 +1,2745 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include "svtools/table/tablecontrol.hxx"
+#include "svtools/table/defaultinputhandler.hxx"
+#include "svtools/table/tablemodel.hxx"
+
+#include "tabledatawindow.hxx"
+#include "tablecontrol_impl.hxx"
+#include "tablegeometry.hxx"
+#include "cellvalueconversion.hxx"
+
+/** === begin UNO includes === **/
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
+/** === end UNO includes === **/
+
+#include <comphelper/flagguard.hxx>
+#include <vcl/scrbar.hxx>
+#include <vcl/seleng.hxx>
+#include <rtl/ref.hxx>
+#include <vcl/image.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <functional>
+
+#define MIN_COLUMN_WIDTH_PIXEL 4
+
+//......................................................................................................................
+namespace svt { namespace table
+{
+//......................................................................................................................
+
+ /** === begin UNO using === **/
+ using ::com::sun::star::accessibility::AccessibleTableModelChange;
+ using ::com::sun::star::uno::makeAny;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::accessibility::XAccessible;
+ using ::com::sun::star::uno::Reference;
+ /** === end UNO using === **/
+ namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId;
+ namespace AccessibleTableModelChangeType = ::com::sun::star::accessibility::AccessibleTableModelChangeType;
+
+ //==================================================================================================================
+ //= SuppressCursor
+ //==================================================================================================================
+ class SuppressCursor
+ {
+ private:
+ ITableControl& m_rTable;
+
+ public:
+ SuppressCursor( ITableControl& _rTable )
+ :m_rTable( _rTable )
+ {
+ m_rTable.hideCursor();
+ }
+ ~SuppressCursor()
+ {
+ m_rTable.showCursor();
+ }
+ };
+
+ //====================================================================
+ //= EmptyTableModel
+ //====================================================================
+ /** default implementation of an ->ITableModel, used as fallback when no
+ real model is present
+
+ Instances of this class are static in any way, and provide the least
+ necessary default functionality for a table model.
+ */
+ class EmptyTableModel : public ITableModel
+ {
+ public:
+ EmptyTableModel()
+ {
+ }
+
+ // ITableModel overridables
+ virtual TableSize getColumnCount() const
+ {
+ return 0;
+ }
+ virtual TableSize getRowCount() const
+ {
+ return 0;
+ }
+ virtual bool hasColumnHeaders() const
+ {
+ return false;
+ }
+ virtual bool hasRowHeaders() const
+ {
+ return false;
+ }
+ virtual bool isCellEditable( ColPos col, RowPos row ) const
+ {
+ (void)col;
+ (void)row;
+ return false;
+ }
+ virtual PColumnModel getColumnModel( ColPos column )
+ {
+ OSL_FAIL( "EmptyTableModel::getColumnModel: invalid call!" );
+ (void)column;
+ return PColumnModel();
+ }
+ virtual PTableRenderer getRenderer() const
+ {
+ return PTableRenderer();
+ }
+ virtual PTableInputHandler getInputHandler() const
+ {
+ return PTableInputHandler();
+ }
+ virtual TableMetrics getRowHeight() const
+ {
+ return 5 * 100;
+ }
+ virtual void setRowHeight(TableMetrics _nRowHeight)
+ {
+ (void)_nRowHeight;
+ }
+ virtual TableMetrics getColumnHeaderHeight() const
+ {
+ return 0;
+ }
+ virtual TableMetrics getRowHeaderWidth() const
+ {
+ return 0;
+ }
+ virtual ScrollbarVisibility getVerticalScrollbarVisibility() const
+ {
+ return ScrollbarShowNever;
+ }
+ virtual ScrollbarVisibility getHorizontalScrollbarVisibility() const
+ {
+ return ScrollbarShowNever;
+ }
+ virtual void addTableModelListener( const PTableModelListener& i_listener )
+ {
+ (void)i_listener;
+ }
+ virtual void removeTableModelListener( const PTableModelListener& i_listener )
+ {
+ (void)i_listener;
+ }
+ virtual ::boost::optional< ::Color > getLineColor() const
+ {
+ return ::boost::optional< ::Color >();
+ }
+ virtual ::boost::optional< ::Color > getHeaderBackgroundColor() const
+ {
+ return ::boost::optional< ::Color >();
+ }
+ virtual ::boost::optional< ::Color > getHeaderTextColor() const
+ {
+ return ::boost::optional< ::Color >();
+ }
+ virtual ::boost::optional< ::Color > getTextColor() const
+ {
+ return ::boost::optional< ::Color >();
+ }
+ virtual ::boost::optional< ::Color > getTextLineColor() const
+ {
+ return ::boost::optional< ::Color >();
+ }
+ virtual ::boost::optional< ::std::vector< ::Color > > getRowBackgroundColors() const
+ {
+ return ::boost::optional< ::std::vector< ::Color > >();
+ }
+ virtual ::com::sun::star::style::VerticalAlignment getVerticalAlign() const
+ {
+ return com::sun::star::style::VerticalAlignment(0);
+ }
+ virtual ITableDataSort* getSortAdapter()
+ {
+ return NULL;
+ }
+ virtual void getCellContent( ColPos const i_col, RowPos const i_row, ::com::sun::star::uno::Any& o_cellContent )
+ {
+ (void)i_row;
+ (void)i_col;
+ o_cellContent.clear();
+ }
+ virtual void getCellToolTip( ColPos const, RowPos const, ::com::sun::star::uno::Any& )
+ {
+ }
+ virtual Any getRowHeading( RowPos const i_rowPos ) const
+ {
+ (void)i_rowPos;
+ return Any();
+ }
+ };
+
+
+ //====================================================================
+ //= TableControl_Impl
+ //====================================================================
+ DBG_NAME( TableControl_Impl )
+
+#if DBG_UTIL
+ //====================================================================
+ //= SuspendInvariants
+ //====================================================================
+ class SuspendInvariants
+ {
+ private:
+ const TableControl_Impl& m_rTable;
+ sal_Int32 m_nSuspendFlags;
+
+ public:
+ SuspendInvariants( const TableControl_Impl& _rTable, sal_Int32 _nSuspendFlags )
+ :m_rTable( _rTable )
+ ,m_nSuspendFlags( _nSuspendFlags )
+ {
+ //DBG_ASSERT( ( m_rTable.m_nRequiredInvariants & m_nSuspendFlags ) == m_nSuspendFlags,
+ // "SuspendInvariants: cannot suspend what is already suspended!" );
+ const_cast< TableControl_Impl& >( m_rTable ).m_nRequiredInvariants &= ~m_nSuspendFlags;
+ }
+ ~SuspendInvariants()
+ {
+ const_cast< TableControl_Impl& >( m_rTable ).m_nRequiredInvariants |= m_nSuspendFlags;
+ }
+ };
+ #define DBG_SUSPEND_INV( flags ) \
+ SuspendInvariants aSuspendInv( *this, flags );
+#else
+ #define DBG_SUSPEND_INV( flags )
+#endif
+
+#if DBG_UTIL
+ //====================================================================
+ const char* TableControl_Impl_checkInvariants( const void* _pInstance )
+ {
+ return static_cast< const TableControl_Impl* >( _pInstance )->impl_checkInvariants();
+ }
+
+ namespace
+ {
+ template< typename SCALAR_TYPE >
+ bool lcl_checkLimitsExclusive( SCALAR_TYPE _nValue, SCALAR_TYPE _nMin, SCALAR_TYPE _nMax )
+ {
+ return ( _nValue > _nMin ) && ( _nValue < _nMax );
+ }
+
+ template< typename SCALAR_TYPE >
+ bool lcl_checkLimitsExclusive_OrDefault_OrFallback( SCALAR_TYPE _nValue, SCALAR_TYPE _nMin, SCALAR_TYPE _nMax,
+ PTableModel _pModel, SCALAR_TYPE _nDefaultOrFallback )
+ {
+ if ( !_pModel )
+ return _nValue == _nDefaultOrFallback;
+ if ( _nMax <= _nMin )
+ return _nDefaultOrFallback == _nValue;
+ return lcl_checkLimitsExclusive( _nValue, _nMin, _nMax );
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ const sal_Char* TableControl_Impl::impl_checkInvariants() const
+ {
+ if ( !m_pModel )
+ return "no model, not even an EmptyTableModel";
+
+ if ( !m_pDataWindow )
+ return "invalid data window!";
+
+ if ( m_pModel->getColumnCount() != m_nColumnCount )
+ return "column counts are inconsistent!";
+
+ if ( m_pModel->getRowCount() != m_nRowCount )
+ return "row counts are inconsistent!";
+
+ if ( ( ( m_nCurColumn != COL_INVALID ) && !m_aColumnWidths.empty() && ( m_nCurColumn < 0 ) ) || ( m_nCurColumn >= (ColPos)m_aColumnWidths.size() ) )
+ return "current column is invalid!";
+
+ if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nTopRow, (RowPos)-1, m_nRowCount, getModel(), (RowPos)0 ) )
+ return "invalid top row value!";
+
+ if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurRow, (RowPos)-1, m_nRowCount, getModel(), ROW_INVALID ) )
+ return "invalid current row value!";
+
+ if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nLeftColumn, (ColPos)-1, m_nColumnCount, getModel(), (ColPos)0 ) )
+ return "invalid current column value!";
+
+ if ( !lcl_checkLimitsExclusive_OrDefault_OrFallback( m_nCurColumn, (ColPos)-1, m_nColumnCount, getModel(), COL_INVALID ) )
+ return "invalid current column value!";
+
+ if ( m_pInputHandler != m_pModel->getInputHandler() )
+ return "input handler is not the model-provided one!";
+
+ // m_aSelectedRows should have reasonable content
+ {
+ if ( m_aSelectedRows.size() > size_t( m_pModel->getRowCount() ) )
+ return "there are more rows selected than actually exist";
+ for ( ::std::vector< RowPos >::const_iterator selRow = m_aSelectedRows.begin();
+ selRow != m_aSelectedRows.end();
+ ++selRow
+ )
+ {
+ if ( ( *selRow < 0 ) || ( *selRow >= m_pModel->getRowCount() ) )
+ return "a non-existent row is selected";
+ }
+ }
+
+ // m_nColHeaderHeightPixel consistent with the model's value?
+ {
+ TableMetrics nHeaderHeight = m_pModel->hasColumnHeaders() ? m_pModel->getColumnHeaderHeight() : 0;
+ nHeaderHeight = m_rAntiImpl.LogicToPixel( Size( 0, nHeaderHeight ), MAP_APPFONT ).Height();
+ if ( nHeaderHeight != m_nColHeaderHeightPixel )
+ return "column header heights are inconsistent!";
+ }
+
+ bool isDummyModel = dynamic_cast< const EmptyTableModel* >( m_pModel.get() ) != NULL;
+ if ( !isDummyModel )
+ {
+ TableMetrics nRowHeight = m_pModel->getRowHeight();
+ nRowHeight = m_rAntiImpl.LogicToPixel( Size( 0, nRowHeight ), MAP_APPFONT).Height();
+ if ( nRowHeight != m_nRowHeightPixel )
+ return "row heights are inconsistent!";
+ }
+
+ // m_nRowHeaderWidthPixel consistent with the model's value?
+ {
+ TableMetrics nHeaderWidth = m_pModel->hasRowHeaders() ? m_pModel->getRowHeaderWidth() : 0;
+ nHeaderWidth = m_rAntiImpl.LogicToPixel( Size( nHeaderWidth, 0 ), MAP_APPFONT ).Width();
+ if ( nHeaderWidth != m_nRowHeaderWidthPixel )
+ return "row header widths are inconsistent!";
+ }
+
+ // m_aColumnWidths consistency
+ if ( size_t( m_nColumnCount ) != m_aColumnWidths.size() )
+ return "wrong number of cached column widths";
+
+ for ( ColumnPositions::const_iterator col = m_aColumnWidths.begin();
+ col != m_aColumnWidths.end();
+ )
+ {
+ if ( col->getEnd() < col->getStart() )
+ return "column widths: 'end' is expected to not be smaller than start";
+
+ ColumnPositions::const_iterator nextCol = col + 1;
+ if ( nextCol != m_aColumnWidths.end() )
+ if ( col->getEnd() != nextCol->getStart() )
+ return "column widths: one column's end should be the next column's start";
+ col = nextCol;
+ }
+
+ if ( m_nLeftColumn < m_nColumnCount )
+ if ( m_aColumnWidths[ m_nLeftColumn ].getStart() != m_nRowHeaderWidthPixel )
+ return "the left-most column should start immediately after the row header";
+
+ if ( m_nCursorHidden < 0 )
+ return "invalid hidden count for the cursor!";
+
+ if ( ( m_nRequiredInvariants & INV_SCROLL_POSITION ) && m_pVScroll )
+ {
+ DBG_SUSPEND_INV( INV_SCROLL_POSITION );
+ // prevent infinite recursion
+
+ if ( m_nLeftColumn < 0 )
+ return "invalid left-most column index";
+ if ( m_pVScroll->GetThumbPos() != m_nTopRow )
+ return "vertical scroll bar |position| is incorrect!";
+ if ( m_pVScroll->GetRange().Max() != m_nRowCount )
+ return "vertical scroll bar |range| is incorrect!";
+ if ( m_pVScroll->GetVisibleSize() != impl_getVisibleRows( false ) )
+ return "vertical scroll bar |visible size| is incorrect!";
+ }
+
+ if ( ( m_nRequiredInvariants & INV_SCROLL_POSITION ) && m_pHScroll )
+ {
+ DBG_SUSPEND_INV( INV_SCROLL_POSITION );
+ // prevent infinite recursion
+
+ if ( m_pHScroll->GetThumbPos() != m_nLeftColumn )
+ return "horizontal scroll bar |position| is incorrect!";
+ if ( m_pHScroll->GetRange().Max() != m_nColumnCount )
+ return "horizontal scroll bar |range| is incorrect!";
+ if ( m_pHScroll->GetVisibleSize() != impl_getVisibleColumns( false ) )
+ return "horizontal scroll bar |visible size| is incorrect!";
+ }
+
+ return NULL;
+ }
+#endif
+
+#define DBG_CHECK_ME() \
+ DBG_CHKTHIS( TableControl_Impl, TableControl_Impl_checkInvariants )
+
+ //------------------------------------------------------------------------------------------------------------------
+ TableControl_Impl::TableControl_Impl( TableControl& _rAntiImpl )
+ :m_rAntiImpl ( _rAntiImpl )
+ ,m_pModel ( new EmptyTableModel )
+ ,m_pInputHandler ( )
+ ,m_nRowHeightPixel ( 15 )
+ ,m_nColHeaderHeightPixel( 0 )
+ ,m_nRowHeaderWidthPixel ( 0 )
+ ,m_nColumnCount ( 0 )
+ ,m_nRowCount ( 0 )
+ ,m_bColumnsFit ( true )
+ ,m_nCurColumn ( COL_INVALID )
+ ,m_nCurRow ( ROW_INVALID )
+ ,m_nLeftColumn ( 0 )
+ ,m_nTopRow ( 0 )
+ ,m_nCursorHidden ( 1 )
+ ,m_pDataWindow ( new TableDataWindow( *this ) )
+ ,m_pVScroll ( NULL )
+ ,m_pHScroll ( NULL )
+ ,m_pScrollCorner ( NULL )
+ ,m_pSelEngine ( )
+ ,m_aSelectedRows ( )
+ ,m_pTableFunctionSet ( new TableFunctionSet( this ) )
+ ,m_nAnchor ( -1 )
+ ,m_bUpdatingColWidths ( false )
+ ,m_pAccessibleTable ( NULL )
+#if DBG_UTIL
+ ,m_nRequiredInvariants ( INV_SCROLL_POSITION )
+#endif
+ {
+ DBG_CTOR( TableControl_Impl, TableControl_Impl_checkInvariants );
+ m_pSelEngine = new SelectionEngine( m_pDataWindow.get(), m_pTableFunctionSet );
+ m_pSelEngine->SetSelectionMode(SINGLE_SELECTION);
+ m_pDataWindow->SetPosPixel( Point( 0, 0 ) );
+ m_pDataWindow->Show();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ TableControl_Impl::~TableControl_Impl()
+ {
+ DBG_DTOR( TableControl_Impl, TableControl_Impl_checkInvariants );
+
+ DELETEZ( m_pVScroll );
+ DELETEZ( m_pHScroll );
+ DELETEZ( m_pScrollCorner );
+ DELETEZ( m_pTableFunctionSet );
+ DELETEZ( m_pSelEngine );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::setModel( PTableModel _pModel )
+ {
+ DBG_CHECK_ME();
+
+ SuppressCursor aHideCursor( *this );
+
+ if ( !!m_pModel )
+ m_pModel->removeTableModelListener( shared_from_this() );
+
+ m_pModel = _pModel;
+ if ( !m_pModel)
+ m_pModel.reset( new EmptyTableModel );
+
+ m_pModel->addTableModelListener( shared_from_this() );
+
+ m_nCurRow = ROW_INVALID;
+ m_nCurColumn = COL_INVALID;
+
+ // recalc some model-dependent cached info
+ impl_ni_updateCachedModelValues();
+ impl_ni_updateScrollbars();
+
+ // completely invalidate
+ m_rAntiImpl.Invalidate();
+
+ // reset cursor to (0,0)
+ if ( m_nRowCount ) m_nCurRow = 0;
+ if ( m_nColumnCount ) m_nCurColumn = 0;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ namespace
+ {
+ bool lcl_adjustSelectedRows( ::std::vector< RowPos >& io_selectionIndexes, RowPos const i_firstAffectedRowIndex, TableSize const i_offset )
+ {
+ bool didChanges = false;
+ for ( ::std::vector< RowPos >::iterator selPos = io_selectionIndexes.begin();
+ selPos != io_selectionIndexes.end();
+ ++selPos
+ )
+ {
+ if ( *selPos < i_firstAffectedRowIndex )
+ continue;
+ *selPos += i_offset;
+ didChanges = true;
+ }
+ return didChanges;
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::rowsInserted( RowPos i_first, RowPos i_last )
+ {
+ DBG_CHECK_ME();
+ OSL_PRECOND( i_last >= i_first, "TableControl_Impl::rowsInserted: invalid row indexes!" );
+
+ TableSize const insertedRows = i_last - i_first + 1;
+
+ // adjust selection, if necessary
+ bool const selectionChanged = lcl_adjustSelectedRows( m_aSelectedRows, i_first, insertedRows );
+
+ // adjust our cached row count
+ m_nRowCount = m_pModel->getRowCount();
+
+ // if the rows have been inserted before the current row, adjust this
+ if ( i_first <= m_nCurRow )
+ goTo( m_nCurColumn, m_nCurRow + insertedRows );
+
+ // adjust scrollbars
+ impl_ni_updateScrollbars();
+
+ // notify A1YY events
+ if ( impl_isAccessibleAlive() )
+ {
+ impl_commitAccessibleEvent( AccessibleEventId::TABLE_MODEL_CHANGED,
+ 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
+ invalidateRowRange( i_first, ROW_INVALID );
+
+ // call selection handlers, if necessary
+ if ( selectionChanged )
+ m_rAntiImpl.Select();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::rowsRemoved( RowPos i_first, RowPos i_last )
+ {
+ sal_Int32 firstRemovedRow = i_first;
+ sal_Int32 lastRemovedRow = i_last;
+
+ // adjust selection, if necessary
+ bool selectionChanged = false;
+ if ( i_first == -1 )
+ {
+ selectionChanged = markAllRowsAsDeselected();
+
+ firstRemovedRow = 0;
+ lastRemovedRow = m_nRowCount - 1;
+ }
+ else
+ {
+ ENSURE_OR_RETURN_VOID( i_last >= i_first, "TableControl_Impl::rowsRemoved: illegal indexes!" );
+
+ for ( sal_Int32 row = i_first; row <= i_last; ++row )
+ {
+ if ( markRowAsDeselected( row ) )
+ selectionChanged = true;
+ }
+
+ if ( lcl_adjustSelectedRows( m_aSelectedRows, i_last + 1, i_first - i_last - 1 ) )
+ selectionChanged = true;
+ }
+
+ // adjust cached row count
+ m_nRowCount = m_pModel->getRowCount();
+
+ // adjust the current row, if it is larger than the row count now
+ if ( m_nCurRow >= m_nRowCount )
+ {
+ if ( m_nRowCount > 0 )
+ goTo( m_nCurColumn, m_nRowCount - 1 );
+ else
+ m_nCurRow = ROW_INVALID;
+ }
+
+ // adjust scrollbars
+ impl_ni_updateScrollbars();
+
+ // notify A11Y events
+ if ( impl_isAccessibleAlive() )
+ {
+ impl_commitAccessibleEvent(
+ AccessibleEventId::TABLE_MODEL_CHANGED,
+ makeAny( AccessibleTableModelChange(
+ AccessibleTableModelChangeType::DELETE,
+ firstRemovedRow,
+ lastRemovedRow,
+ 0,
+ m_pModel->getColumnCount()
+ ) ),
+ Any()
+ );
+ }
+
+ // schedule a repaint
+ invalidateRowRange( firstRemovedRow, ROW_INVALID );
+
+ // call selection handlers, if necessary
+ if ( selectionChanged )
+ m_rAntiImpl.Select();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::columnInserted( ColPos const i_colIndex )
+ {
+ m_nColumnCount = m_pModel->getColumnCount();
+ impl_ni_updateColumnWidths();
+ impl_ni_updateScrollbars();
+
+ m_rAntiImpl.Invalidate();
+
+ OSL_UNUSED( i_colIndex );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::columnRemoved( ColPos const i_colIndex )
+ {
+ m_nColumnCount = m_pModel->getColumnCount();
+ impl_ni_updateColumnWidths();
+ impl_ni_updateScrollbars();
+
+ m_rAntiImpl.Invalidate();
+
+ OSL_UNUSED( i_colIndex );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::allColumnsRemoved()
+ {
+ m_nColumnCount = m_pModel->getColumnCount();
+ impl_ni_updateColumnWidths();
+ impl_ni_updateScrollbars();
+
+ m_rAntiImpl.Invalidate();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::cellsUpdated( ColPos const i_firstCol, ColPos i_lastCol, RowPos const i_firstRow, RowPos const i_lastRow )
+ {
+ invalidateRowRange( i_firstRow, i_lastRow );
+
+ OSL_UNUSED( i_firstCol );
+ OSL_UNUSED( i_lastCol );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::tableMetricsChanged()
+ {
+ long const oldRowHeaderWidthPixel = m_nRowHeaderWidthPixel;
+ impl_ni_updateCachedTableMetrics();
+ if ( oldRowHeaderWidthPixel != m_nRowHeaderWidthPixel )
+ impl_ni_updateColumnWidths();
+ impl_ni_updateScrollbars();
+ m_rAntiImpl.Invalidate();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::impl_invalidateColumn( ColPos const i_column )
+ {
+ DBG_CHECK_ME();
+
+ Rectangle const aAllCellsArea( impl_getAllVisibleCellsArea() );
+
+ const TableColumnGeometry aColumn( *this, aAllCellsArea, i_column );
+ if ( aColumn.isValid() )
+ m_rAntiImpl.Invalidate( aColumn.getRect() );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::columnChanged( ColPos const i_column, ColumnAttributeGroup const i_attributeGroup )
+ {
+ ColumnAttributeGroup nGroup( i_attributeGroup );
+ if ( nGroup & COL_ATTRS_APPEARANCE )
+ {
+ impl_invalidateColumn( i_column );
+ nGroup &= ~COL_ATTRS_APPEARANCE;
+ }
+
+ if ( nGroup & COL_ATTRS_WIDTH )
+ {
+ if ( !m_bUpdatingColWidths )
+ {
+ impl_ni_updateColumnWidths( i_column );
+ invalidate( TableAreaAll );
+ impl_ni_updateScrollbars();
+ }
+
+ nGroup &= ~COL_ATTRS_WIDTH;
+ }
+
+ OSL_ENSURE( ( nGroup == COL_ATTRS_NONE ) || ( i_attributeGroup == COL_ATTRS_ALL ),
+ "TableControl_Impl::columnChanged: don't know how to handle this change!" );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Rectangle TableControl_Impl::impl_getAllVisibleCellsArea() const
+ {
+ DBG_CHECK_ME();
+
+ Rectangle aArea( Point( 0, 0 ), Size( 0, 0 ) );
+
+ // determine the right-most border of the last column which is
+ // at least partially visible
+ aArea.Right() = m_nRowHeaderWidthPixel;
+ if ( !m_aColumnWidths.empty() )
+ {
+ // the number of pixels which are scrolled out of the left hand
+ // side of the window
+ const long nScrolledOutLeft = m_nLeftColumn == 0 ? 0 : m_aColumnWidths[ m_nLeftColumn - 1 ].getEnd();
+
+ ColumnPositions::const_reverse_iterator loop = m_aColumnWidths.rbegin();
+ do
+ {
+ aArea.Right() = loop->getEnd() - nScrolledOutLeft + m_nRowHeaderWidthPixel;
+ ++loop;
+ }
+ while ( ( loop != m_aColumnWidths.rend() )
+ && ( loop->getEnd() - nScrolledOutLeft >= aArea.Right() )
+ );
+ }
+ // so far, aArea.Right() denotes the first pixel *after* the cell area
+ --aArea.Right();
+
+ // determine the last row which is at least partially visible
+ aArea.Bottom() =
+ m_nColHeaderHeightPixel
+ + impl_getVisibleRows( true ) * m_nRowHeightPixel
+ - 1;
+
+ return aArea;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Rectangle TableControl_Impl::impl_getAllVisibleDataCellArea() const
+ {
+ DBG_CHECK_ME();
+
+ Rectangle aArea( impl_getAllVisibleCellsArea() );
+ aArea.Left() = m_nRowHeaderWidthPixel;
+ aArea.Top() = m_nColHeaderHeightPixel;
+ return aArea;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::impl_ni_updateCachedTableMetrics()
+ {
+ m_nRowHeightPixel = m_rAntiImpl.LogicToPixel( Size( 0, m_pModel->getRowHeight() ), MAP_APPFONT ).Height();
+
+ m_nColHeaderHeightPixel = 0;
+ if ( m_pModel->hasColumnHeaders() )
+ m_nColHeaderHeightPixel = m_rAntiImpl.LogicToPixel( Size( 0, m_pModel->getColumnHeaderHeight() ), MAP_APPFONT ).Height();
+
+ m_nRowHeaderWidthPixel = 0;
+ if ( m_pModel->hasRowHeaders() )
+ m_nRowHeaderWidthPixel = m_rAntiImpl.LogicToPixel( Size( m_pModel->getRowHeaderWidth(), 0 ), MAP_APPFONT).Width();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ 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();
+ m_nRowCount = m_pModel->getRowCount();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::impl_ni_updateColumnWidths( ColPos const i_assumeInflexibleColumnsUpToIncluding )
+ {
+ ENSURE_OR_RETURN_VOID( !m_bUpdatingColWidths, "TableControl_Impl::impl_ni_updateColumnWidths: recursive call detected!" );
+
+ m_aColumnWidths.resize( 0 );
+ if ( !m_pModel )
+ return;
+
+ const TableSize colCount = m_pModel->getColumnCount();
+ if ( colCount == 0 )
+ return;
+
+ m_bUpdatingColWidths = true;
+ const ::comphelper::FlagGuard aWidthUpdateFlag( m_bUpdatingColWidths );
+
+ m_aColumnWidths.reserve( colCount );
+
+ // the available horizontal space
+ long gridWidthPixel = m_rAntiImpl.GetOutputSizePixel().Width();
+ if ( m_pModel->hasRowHeaders() && ( gridWidthPixel != 0 ) )
+ {
+ gridWidthPixel -= m_nRowHeaderWidthPixel;
+ }
+ if ( 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!" );
+
+ }
+
+ // collect some meta data for our columns:
+ // - their current (appt-font) 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 );
+ long accumulatedMinWidth = 0;
+ long accumulatedMaxWidth = 0;
+ // - their relative flexibility
+ ::std::vector< ::sal_Int32 > columnFlexibilities;
+ columnFlexibilities.reserve( colCount );
+ long flexibilityDenominator = 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();
+ currentColWidths.push_back( currentWidth );
+
+ // accumulated width
+ accumulatedCurrentWidth += currentWidth;
+
+ // flexibility
+ ::sal_Int32 flexibility = pColumn->getFlexibility();
+ OSL_ENSURE( flexibility >= 0, "TableControl_Impl::impl_ni_updateColumnWidths: 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
+ )
+ flexibility = 0;
+
+ // min/max width
+ long effectiveMin = currentWidth, effectiveMax = currentWidth;
+ // 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();
+ 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!" );
+ if ( ( maxWidth > 0 ) && ( maxWidth >= minWidth ) )
+ effectiveMax = maxWidth;
+ else
+ effectiveMax = gridWidthAppFont; // TODO: any better guess here?
+
+ if ( effectiveMin == effectiveMax )
+ // if the min and the max are identical, this implies no flexibility at all
+ flexibility = 0;
+ }
+
+ columnFlexibilities.push_back( flexibility );
+ flexibilityDenominator += flexibility;
+
+ effectiveColumnLimits.push_back( ::std::pair< long, long >( effectiveMin, effectiveMax ) );
+ accumulatedMinWidth += effectiveMin;
+ accumulatedMaxWidth += effectiveMax;
+ }
+
+ ::std::vector< long > newWidths( currentColWidths );
+ if ( flexibilityDenominator == 0 )
+ {
+ // no column is flexible => don't adjust anything
+ }
+ else if ( gridWidthAppFont > accumulatedCurrentWidth )
+ { // we have space to give away ...
+ long distributeAppFontUnits = gridWidthAppFont - accumulatedCurrentWidth;
+ if ( gridWidthAppFont > 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;
+ }
+ }
+ else
+ {
+ bool startOver = false;
+ do
+ {
+ startOver = false;
+ // distribute the remaining space amongst all columns with a positive flexibility
+ for ( size_t i=0; i<newWidths.size() && !startOver; ++i )
+ {
+ long const columnFlexibility = columnFlexibilities[i];
+ if ( columnFlexibility == 0 )
+ continue;
+
+ long newColWidth = currentColWidths[i] + columnFlexibility * distributeAppFontUnits / flexibilityDenominator;
+
+ if ( newColWidth > effectiveColumnLimits[i].second )
+ { // that was too much, we hit the col's maximum
+ // set the new width to exactly this maximum
+ newColWidth = effectiveColumnLimits[i].second;
+ // adjust the flexibility denominator ...
+ flexibilityDenominator -= columnFlexibility;
+ columnFlexibilities[i] = 0;
+ // ... and the remaining width ...
+ long const difference = newColWidth - currentColWidths[i];
+ distributeAppFontUnits -= 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)
+
+ // and start over with the first column, since there might be earlier columns which need
+ // to be recalculated now
+ startOver = true;
+ }
+
+ newWidths[i] = newColWidth;
+ }
+ }
+ while ( startOver );
+ }
+ }
+ else if ( gridWidthAppFont < accumulatedCurrentWidth )
+ { // we need to take away some space from the columns which allow it ...
+ long takeAwayAppFontUnits = accumulatedCurrentWidth - gridWidthAppFont;
+ if ( gridWidthAppFont < 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;
+ }
+ }
+ else
+ {
+ bool startOver = false;
+ do
+ {
+ 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 )
+ {
+ long const columnFlexibility = columnFlexibilities[i];
+ if ( columnFlexibility == 0 )
+ continue;
+
+ long newColWidth = currentColWidths[i] - columnFlexibility * takeAwayAppFontUnits / flexibilityDenominator;
+
+ if ( newColWidth < effectiveColumnLimits[i].first )
+ { // that was too much, we hit the col's minimum
+ // set the new width to exactly this minimum
+ newColWidth = effectiveColumnLimits[i].first;
+ // adjust the flexibility denominator ...
+ flexibilityDenominator -= columnFlexibility;
+ columnFlexibilities[i] = 0;
+ // ... and the remaining width ...
+ long const difference = currentColWidths[i] - newColWidth;
+ takeAwayAppFontUnits -= 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;
+ }
+ }
+ 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] );
+ }
+
+ // 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 );
+ }
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ namespace
+ {
+ //..............................................................................................................
+ /// 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;
+
+ aColumn.moveRight();
+ ++visibleColumns;
+ }
+ return visibleColumns;
+ }
+
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::impl_ni_updateScrollbars()
+ {
+ SuppressCursor aHideCursor( *this );
+
+ // the width/height of a scrollbar, needed several times below
+ long const nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize();
+
+ // determine the playground for the data cells (excluding headers)
+ // TODO: what if the control is smaller than needed for the headers/scrollbars?
+ 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();
+
+ const ScrollbarVisibility eVertScrollbar = m_pModel->getVerticalScrollbarVisibility();
+ const ScrollbarVisibility eHorzScrollbar = m_pModel->getHorizontalScrollbarVisibility();
+
+ // do we need a vertical scrollbar?
+ bool bNeedVerticalScrollbar = lcl_determineScrollbarNeed(
+ m_nTopRow, eVertScrollbar, aDataCellPlayground.GetHeight(), m_nRowHeightPixel * m_nRowCount );
+ bool bFirstRoundVScrollNeed = false;
+ if ( bNeedVerticalScrollbar )
+ {
+ aDataCellPlayground.Right() -= nScrollbarMetrics;
+ bFirstRoundVScrollNeed = true;
+ }
+ // do we need a horizontal scrollbar?
+ const bool bNeedHorizontalScrollbar = lcl_determineScrollbarNeed( m_nLeftColumn, eHorzScrollbar, aDataCellPlayground.GetWidth(), nAllColumnsWidth );
+ if ( bNeedHorizontalScrollbar )
+ {
+ aDataCellPlayground.Bottom() -= nScrollbarMetrics;
+
+ // now that we just found that we need a horizontal scrollbar,
+ // the need for a vertical one may have changed, since the horizontal
+ // SB might just occupy enough space so that not all rows do fit
+ // anymore
+ if ( !bFirstRoundVScrollNeed )
+ {
+ bNeedVerticalScrollbar = lcl_determineScrollbarNeed(
+ m_nTopRow, eVertScrollbar, aDataCellPlayground.GetHeight(), m_nRowHeightPixel * m_nRowCount );
+ if ( bNeedVerticalScrollbar )
+ {
+ aDataCellPlayground.Right() -= nScrollbarMetrics;
+ }
+ }
+ }
+ // create or destroy the vertical scrollbar, as needed
+ lcl_updateScrollbar(
+ m_rAntiImpl,
+ m_pVScroll,
+ bNeedVerticalScrollbar,
+ lcl_getRowsFittingInto( aDataCellPlayground.GetHeight(), m_nRowHeightPixel ),
+ // visible units
+ m_nTopRow, // current position
+ 1, // line size
+ m_nRowCount, // range
+ 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 )
+ );
+ m_pVScroll->SetPosSizePixel(
+ aScrollbarArea.TopLeft(), aScrollbarArea.GetSize() );
+ }
+
+ // create or destroy the horizontal scrollbar, as needed
+ lcl_updateScrollbar(
+ m_rAntiImpl,
+ m_pHScroll,
+ bNeedHorizontalScrollbar,
+ lcl_getColumnsVisibleWithin( aDataCellPlayground, m_nLeftColumn, *this, false ),
+ // visible units
+ m_nLeftColumn, // current position
+ 1, // line size
+ m_nColumnCount, // range
+ true, // horizontal
+ LINK( this, TableControl_Impl, OnScroll ) // scroll handler
+ );
+ // position it
+ if ( m_pHScroll )
+ {
+ TableSize const nVisibleUnits = lcl_getColumnsVisibleWithin( aDataCellPlayground, 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() )
+ {
+ m_pHScroll->SetVisibleSize( nVisibleUnits -1 );
+ m_pHScroll->SetPageSize( nVisibleUnits - 1 );
+ }
+ }
+ Rectangle aScrollbarArea(
+ Point( 0, aDataCellPlayground.Bottom() + 1 ),
+ Size( aDataCellPlayground.Right() + 1, nScrollbarMetrics )
+ );
+ m_pHScroll->SetPosSizePixel(
+ aScrollbarArea.TopLeft(), aScrollbarArea.GetSize() );
+ }
+
+ // the corner window connecting the two scrollbars in the lower right corner
+ bool bHaveScrollCorner = NULL != m_pScrollCorner;
+ bool bNeedScrollCorner = ( NULL != m_pHScroll ) && ( NULL != m_pVScroll );
+ if ( bHaveScrollCorner && !bNeedScrollCorner )
+ {
+ DELETEZ( m_pScrollCorner );
+ }
+ else if ( !bHaveScrollCorner && bNeedScrollCorner )
+ {
+ m_pScrollCorner = new ScrollBarBox( &m_rAntiImpl );
+ m_pScrollCorner->SetSizePixel( Size( nScrollbarMetrics, nScrollbarMetrics ) );
+ m_pScrollCorner->SetPosPixel( Point( aDataCellPlayground.Right() + 1, aDataCellPlayground.Bottom() + 1 ) );
+ m_pScrollCorner->Show();
+ }
+ else if(bHaveScrollCorner && bNeedScrollCorner)
+ {
+ m_pScrollCorner->SetPosPixel( Point( aDataCellPlayground.Right() + 1, aDataCellPlayground.Bottom() + 1 ) );
+ m_pScrollCorner->Show();
+ }
+
+ // resize the data window
+ m_pDataWindow->SetSizePixel( Size(
+ aDataCellPlayground.GetWidth() + m_nRowHeaderWidthPixel,
+ aDataCellPlayground.GetHeight() + m_nColHeaderHeightPixel
+ ) );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::onResize()
+ {
+ DBG_CHECK_ME();
+
+ impl_ni_updateColumnWidths();
+ impl_ni_updateScrollbars();
+ checkCursorPosition();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::doPaintContent( const Rectangle& _rUpdateRect )
+ {
+ DBG_CHECK_ME();
+
+ if ( !getModel() )
+ return;
+ PTableRenderer pRenderer = getModel()->getRenderer();
+ DBG_ASSERT( !!pRenderer, "TableDataWindow::doPaintContent: invalid renderer!" );
+ if ( !pRenderer )
+ return;
+
+ // our current style settings, to be passed to the renderer
+ const StyleSettings& rStyle = m_rAntiImpl.GetSettings().GetStyleSettings();
+ m_nRowCount = m_pModel->getRowCount();
+ // the area occupied by all (at least partially) visible cells, including
+ // headers
+ Rectangle const aAllCellsWithHeaders( impl_getAllVisibleCellsArea() );
+
+ // ............................
+ // draw the header column area
+ if ( m_pModel->hasColumnHeaders() )
+ {
+ TableRowGeometry const aHeaderRow( *this, Rectangle( Point( 0, 0 ),
+ aAllCellsWithHeaders.BottomRight() ), ROW_COL_HEADERS );
+ Rectangle const aColRect(aHeaderRow.getRect());
+ pRenderer->PaintHeaderArea(
+ *m_pDataWindow, aColRect, true, false, rStyle
+ );
+ // Note that strictly, aHeaderRow.getRect() also contains the intersection between column
+ // and row header area. However, below we go to paint this intersection, again,
+ // so this hopefully doesn't hurt if we already paint it here.
+
+ for ( TableCellGeometry aCell( aHeaderRow, m_nLeftColumn );
+ aCell.isValid();
+ aCell.moveRight()
+ )
+ {
+ if ( _rUpdateRect.GetIntersection( aCell.getRect() ).IsEmpty() )
+ continue;
+
+ bool isActiveColumn = ( aCell.getColumn() == getCurrentColumn() );
+ bool isSelectedColumn = false;
+ pRenderer->PaintColumnHeader( aCell.getColumn(), isActiveColumn, isSelectedColumn,
+ *m_pDataWindow, aCell.getRect(), rStyle );
+ }
+ }
+ // the area occupied by the row header, if any
+ Rectangle aRowHeaderArea;
+ if ( m_pModel->hasRowHeaders() )
+ {
+ aRowHeaderArea = aAllCellsWithHeaders;
+ aRowHeaderArea.Right() = m_nRowHeaderWidthPixel - 1;
+
+ TableSize const nVisibleRows = impl_getVisibleRows( true );
+ TableSize nActualRows = nVisibleRows;
+ if ( m_nTopRow + nActualRows > m_nRowCount )
+ nActualRows = m_nRowCount - m_nTopRow;
+ aRowHeaderArea.Bottom() = m_nColHeaderHeightPixel + m_nRowHeightPixel * nActualRows - 1;
+
+ pRenderer->PaintHeaderArea( *m_pDataWindow, aRowHeaderArea, false, true, rStyle );
+ // Note that strictly, aRowHeaderArea also contains the intersection between column
+ // and row header area. However, below we go to paint this intersection, again,
+ // so this hopefully doesn't hurt if we already paint it here.
+
+ if ( m_pModel->hasColumnHeaders() )
+ {
+ TableCellGeometry const aIntersection( *this, Rectangle( Point( 0, 0 ),
+ aAllCellsWithHeaders.BottomRight() ), COL_ROW_HEADERS, ROW_COL_HEADERS );
+ Rectangle const aInters( aIntersection.getRect() );
+ pRenderer->PaintHeaderArea(
+ *m_pDataWindow, aInters, true, true, rStyle
+ );
+ }
+ }
+
+ // ............................
+ // draw the table content row by row
+
+ TableSize colCount = getModel()->getColumnCount();
+
+ // paint all rows
+ Rectangle const aAllDataCellsArea( impl_getAllVisibleDataCellArea() );
+ for ( TableRowGeometry aRowIterator( *this, aAllCellsWithHeaders, getTopRow() );
+ aRowIterator.isValid();
+ aRowIterator.moveDown() )
+ {
+ if ( _rUpdateRect.GetIntersection( aRowIterator.getRect() ).IsEmpty() )
+ continue;
+
+ bool const isActiveRow = ( aRowIterator.getRow() == getCurrentRow() );
+ 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,
+ *m_pDataWindow, aRect, rStyle
+ );
+
+ // paint the row header
+ if ( m_pModel->hasRowHeaders() )
+ {
+ const Rectangle aCurrentRowHeader( aRowHeaderArea.GetIntersection( aRowIterator.getRect() ) );
+ pRenderer->PaintRowHeader( isActiveRow, isSelectedRow, *m_pDataWindow, aCurrentRowHeader,
+ rStyle );
+ }
+
+ if ( !colCount )
+ continue;
+
+ // paint all cells in this row
+ for ( TableCellGeometry aCell( aRowIterator, m_nLeftColumn );
+ aCell.isValid();
+ aCell.moveRight()
+ )
+ {
+ bool isSelectedColumn = false;
+ pRenderer->PaintCell( aCell.getColumn(), isSelectedRow || isSelectedColumn, isActiveRow,
+ *m_pDataWindow, aCell.getRect(), rStyle );
+ }
+ }
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::hideCursor()
+ {
+ DBG_CHECK_ME();
+
+ if ( ++m_nCursorHidden == 1 )
+ impl_ni_doSwitchCursor( false );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::showCursor()
+ {
+ DBG_CHECK_ME();
+
+ DBG_ASSERT( m_nCursorHidden > 0, "TableControl_Impl::showCursor: cursor not hidden!" );
+ if ( --m_nCursorHidden == 0 )
+ impl_ni_doSwitchCursor( true );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool TableControl_Impl::dispatchAction( TableControlAction _eAction )
+ {
+ DBG_CHECK_ME();
+
+ bool bSuccess = false;
+ bool selectionChanged = false;
+
+ Rectangle rCells;
+ switch ( _eAction )
+ {
+ case cursorDown:
+ if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
+ {
+ //if other rows already selected, deselect them
+ if(m_aSelectedRows.size()>0)
+ {
+ for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin();
+ it!=m_aSelectedRows.end();++it)
+ {
+ invalidateSelectedRegion(*it, *it, rCells);
+ }
+ m_aSelectedRows.clear();
+ }
+ 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);
+ ensureVisible(m_nCurColumn,m_nCurRow,false);
+ selectionChanged = true;
+ bSuccess = true;
+ }
+ else
+ {
+ if ( m_nCurRow < m_nRowCount - 1 )
+ bSuccess = goTo( m_nCurColumn, m_nCurRow + 1 );
+ }
+ break;
+
+ case cursorUp:
+ if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
+ {
+ if(m_aSelectedRows.size()>0)
+ {
+ for(std::vector<RowPos>::iterator it=m_aSelectedRows.begin();
+ it!=m_aSelectedRows.end();++it)
+ {
+ invalidateSelectedRegion(*it, *it, rCells);
+ }
+ m_aSelectedRows.clear();
+ }
+ if(m_nCurRow>0)
+ {
+ --m_nCurRow;
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
+ }
+ else
+ {
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
+ }
+ ensureVisible(m_nCurColumn,m_nCurRow,false);
+ selectionChanged = true;
+ bSuccess = true;
+ }
+ else
+ {
+ if ( m_nCurRow > 0 )
+ bSuccess = goTo( m_nCurColumn, m_nCurRow - 1 );
+ }
+ break;
+ case cursorLeft:
+ if ( m_nCurColumn > 0 )
+ bSuccess = goTo( m_nCurColumn - 1, m_nCurRow );
+ else
+ if ( ( m_nCurColumn == 0) && ( m_nCurRow > 0 ) )
+ bSuccess = goTo( m_nColumnCount - 1, m_nCurRow - 1 );
+ break;
+
+ case cursorRight:
+ if ( m_nCurColumn < m_nColumnCount - 1 )
+ bSuccess = goTo( m_nCurColumn + 1, m_nCurRow );
+ else
+ if ( ( m_nCurColumn == m_nColumnCount - 1 ) && ( m_nCurRow < m_nRowCount - 1 ) )
+ bSuccess = goTo( 0, m_nCurRow + 1 );
+ break;
+
+ case cursorToLineStart:
+ bSuccess = goTo( 0, m_nCurRow );
+ break;
+
+ case cursorToLineEnd:
+ bSuccess = goTo( m_nColumnCount - 1, m_nCurRow );
+ break;
+
+ case cursorToFirstLine:
+ bSuccess = goTo( m_nCurColumn, 0 );
+ break;
+
+ case cursorToLastLine:
+ bSuccess = goTo( m_nCurColumn, m_nRowCount - 1 );
+ break;
+
+ case cursorPageUp:
+ {
+ RowPos nNewRow = ::std::max( (RowPos)0, m_nCurRow - impl_getVisibleRows( false ) );
+ bSuccess = goTo( m_nCurColumn, nNewRow );
+ }
+ break;
+
+ case cursorPageDown:
+ {
+ RowPos nNewRow = ::std::min( m_nRowCount - 1, m_nCurRow + impl_getVisibleRows( false ) );
+ bSuccess = goTo( m_nCurColumn, nNewRow );
+ }
+ break;
+
+ case cursorTopLeft:
+ bSuccess = goTo( 0, 0 );
+ break;
+
+ case cursorBottomRight:
+ bSuccess = goTo( m_nColumnCount - 1, m_nRowCount - 1 );
+ break;
+
+ case cursorSelectRow:
+ {
+ if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
+ return bSuccess = false;
+ //pos is the position of the current row in the vector of selected rows, if current row is selected
+ int pos = getRowSelectedNumber(m_aSelectedRows, m_nCurRow);
+ //if current row is selected, it should be deselected, when ALT+SPACE are pressed
+ if(pos>-1)
+ {
+ m_aSelectedRows.erase(m_aSelectedRows.begin()+pos);
+ if(m_aSelectedRows.empty() && m_nAnchor != -1)
+ m_nAnchor = -1;
+ }
+ //else select the row->put it in the vector
+ else
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
+ selectionChanged = true;
+ bSuccess = true;
+ }
+ break;
+ case cursorSelectRowUp:
+ {
+ if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
+ return bSuccess = false;
+ else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
+ {
+ //if there are other selected rows, deselect them
+ return false;
+ }
+ else
+ {
+ //there are other selected rows
+ if(m_aSelectedRows.size()>0)
+ {
+ //the anchor wasn't set -> a region is not selected, that's why clear all selection
+ //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);
+ }
+ m_aSelectedRows.clear();
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
+ }
+ else
+ {
+ //a region is already selected, prevRow is last selected row and the row above - nextRow - should be selected
+ int prevRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow);
+ int nextRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow-1);
+ if(prevRow>-1)
+ {
+ //if m_nCurRow isn't the upper one, can move up, otherwise not
+ if(m_nCurRow>0)
+ m_nCurRow--;
+ else
+ return bSuccess = true;
+ //if nextRow already selected, deselect it, otherwise select it
+ if(nextRow>-1 && m_aSelectedRows[nextRow] == m_nCurRow)
+ {
+ m_aSelectedRows.erase(m_aSelectedRows.begin()+prevRow);
+ invalidateSelectedRegion(m_nCurRow+1, m_nCurRow+1, rCells);
+ }
+ else
+ {
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
+ }
+ }
+ else
+ {
+ if(m_nCurRow>0)
+ {
+ m_aSelectedRows.push_back(m_nCurRow);
+ m_nCurRow--;
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow+1, m_nCurRow, rCells);
+ }
+ }
+ }
+ }
+ else
+ {
+ //if nothing is selected and the current row isn't the upper one
+ //select the current and one row above
+ //otherwise select only the upper row
+ if(m_nCurRow>0)
+ {
+ m_aSelectedRows.push_back(m_nCurRow);
+ m_nCurRow--;
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow+1, m_nCurRow, rCells);
+ }
+ else
+ {
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
+ }
+ }
+ m_pSelEngine->SetAnchor(sal_True);
+ m_nAnchor = m_nCurRow;
+ ensureVisible(m_nCurColumn, m_nCurRow, false);
+ selectionChanged = true;
+ bSuccess = true;
+ }
+ }
+ break;
+ case cursorSelectRowDown:
+ {
+ if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
+ bSuccess = false;
+ else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
+ {
+ bSuccess = false;
+ }
+ else
+ {
+ if(m_aSelectedRows.size()>0)
+ {
+ //the anchor wasn't set -> a region is not selected, that's why clear all selection
+ //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);
+ }
+ m_aSelectedRows.clear();
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
+ }
+ else
+ {
+ //a region is already selected, prevRow is last selected row and the row beneath - nextRow - should be selected
+ int prevRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow);
+ int nextRow = getRowSelectedNumber(m_aSelectedRows, m_nCurRow+1);
+ if(prevRow>-1)
+ {
+ //if m_nCurRow isn't the last one, can move down, otherwise not
+ if(m_nCurRow<m_nRowCount-1)
+ m_nCurRow++;
+ else
+ return bSuccess = true;
+ //if next row already selected, deselect it, otherwise select it
+ if(nextRow>-1 && m_aSelectedRows[nextRow] == m_nCurRow)
+ {
+ m_aSelectedRows.erase(m_aSelectedRows.begin()+prevRow);
+ invalidateSelectedRegion(m_nCurRow-1, m_nCurRow-1, rCells);
+ }
+ else
+ {
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
+ }
+ }
+ else
+ {
+ if(m_nCurRow<m_nRowCount-1)
+ {
+ m_aSelectedRows.push_back(m_nCurRow);
+ m_nCurRow++;
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow-1, m_nCurRow, rCells);
+ }
+ }
+ }
+ }
+ else
+ {
+ //there wasn't any selection, select current and row beneath, otherwise only row beneath
+ if(m_nCurRow<m_nRowCount-1)
+ {
+ m_aSelectedRows.push_back(m_nCurRow);
+ m_nCurRow++;
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow-1, m_nCurRow, rCells);
+ }
+ else
+ {
+ m_aSelectedRows.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow, m_nCurRow, rCells);
+ }
+ }
+ m_pSelEngine->SetAnchor(sal_True);
+ m_nAnchor = m_nCurRow;
+ ensureVisible(m_nCurColumn, m_nCurRow, false);
+ selectionChanged = true;
+ bSuccess = true;
+ }
+ }
+ break;
+
+ case cursorSelectRowAreaTop:
+ {
+ if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
+ bSuccess = false;
+ else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
+ bSuccess = false;
+ else
+ {
+ //select the region between the current and the upper row
+ RowPos iter = m_nCurRow;
+ invalidateSelectedRegion(m_nCurRow, 0, rCells);
+ //put the rows in vector
+ while(iter>=0)
+ {
+ if ( !isRowSelected( iter ) )
+ m_aSelectedRows.push_back(iter);
+ --iter;
+ }
+ m_nCurRow = 0;
+ m_nAnchor = m_nCurRow;
+ m_pSelEngine->SetAnchor(sal_True);
+ ensureVisible(m_nCurColumn, 0, false);
+ selectionChanged = true;
+ bSuccess = true;
+ }
+ }
+ break;
+
+ case cursorSelectRowAreaBottom:
+ {
+ if(m_pSelEngine->GetSelectionMode() == NO_SELECTION)
+ return bSuccess = false;
+ else if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
+ return bSuccess = false;
+ //select the region between the current and the last row
+ RowPos iter = m_nCurRow;
+ invalidateSelectedRegion(m_nCurRow, m_nRowCount-1, rCells);
+ //put the rows in the vector
+ while(iter<=m_nRowCount)
+ {
+ if ( !isRowSelected( iter ) )
+ m_aSelectedRows.push_back(iter);
+ ++iter;
+ }
+ m_nCurRow = m_nRowCount-1;
+ m_nAnchor = m_nCurRow;
+ m_pSelEngine->SetAnchor(sal_True);
+ ensureVisible(m_nCurColumn, m_nRowCount-1, false);
+ selectionChanged = true;
+ bSuccess = true;
+ }
+ break;
+ default:
+ OSL_FAIL( "TableControl_Impl::dispatchAction: unsupported action!" );
+ break;
+ }
+
+ if ( bSuccess && selectionChanged )
+ {
+ m_rAntiImpl.Select();
+ }
+
+ return bSuccess;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::impl_ni_doSwitchCursor( bool _bShow )
+ {
+ PTableRenderer pRenderer = !!m_pModel ? m_pModel->getRenderer() : PTableRenderer();
+ if ( !!pRenderer )
+ {
+ Rectangle aCellRect;
+ impl_getCellRect( m_nCurColumn, m_nCurRow, aCellRect );
+ if ( _bShow )
+ pRenderer->ShowCellCursor( *m_pDataWindow, aCellRect );
+ else
+ pRenderer->HideCellCursor( *m_pDataWindow, aCellRect );
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::impl_getCellRect( ColPos _nColumn, RowPos _nRow, Rectangle& _rCellRect ) const
+ {
+ DBG_CHECK_ME();
+
+ if ( !m_pModel
+ || ( COL_INVALID == _nColumn )
+ || ( ROW_INVALID == _nRow )
+ )
+ {
+ _rCellRect.SetEmpty();
+ return;
+ }
+
+ TableCellGeometry aCell( *this, impl_getAllVisibleCellsArea(), _nColumn, _nRow );
+ _rCellRect = aCell.getRect();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ RowPos TableControl_Impl::getRowAtPoint( const Point& rPoint ) const
+ {
+ DBG_CHECK_ME();
+ return impl_getRowForAbscissa( rPoint.Y() );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ColPos TableControl_Impl::getColAtPoint( const Point& rPoint ) const
+ {
+ DBG_CHECK_ME();
+ return impl_getColumnForOrdinate( rPoint.X() );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ TableCell TableControl_Impl::hitTest( Point const & i_point ) const
+ {
+ TableCell aCell( getColAtPoint( i_point ), getRowAtPoint( i_point ) );
+ if ( aCell.nColumn > COL_ROW_HEADERS )
+ {
+ PColumnModel const pColumn = m_pModel->getColumnModel( aCell.nColumn );
+ MutableColumnMetrics const & rColInfo( m_aColumnWidths[ aCell.nColumn ] );
+ if ( ( rColInfo.getEnd() - 3 <= i_point.X() )
+ && ( rColInfo.getEnd() >= i_point.X() )
+ && pColumn->isResizable()
+ )
+ {
+ aCell.eArea = ColumnDivider;
+ }
+ }
+ return aCell;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ColumnMetrics TableControl_Impl::getColumnMetrics( ColPos const i_column ) const
+ {
+ DBG_CHECK_ME();
+
+ ENSURE_OR_RETURN( ( i_column >= 0 ) && ( i_column < m_pModel->getColumnCount() ),
+ "TableControl_Impl::getColumnMetrics: illegal column index!", ColumnMetrics() );
+ return (ColumnMetrics const &)m_aColumnWidths[ i_column ];
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ PTableModel TableControl_Impl::getModel() const
+ {
+ return m_pModel;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ RowPos TableControl_Impl::getCurrentColumn() const
+ {
+ return m_nCurColumn;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ RowPos TableControl_Impl::getCurrentRow() const
+ {
+ return m_nCurRow;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ::Size TableControl_Impl::getTableSizePixel() const
+ {
+ return m_pDataWindow->GetOutputSizePixel();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::setPointer( Pointer const & i_pointer )
+ {
+ DBG_CHECK_ME();
+ m_pDataWindow->SetPointer( i_pointer );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::captureMouse()
+ {
+ m_pDataWindow->CaptureMouse();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::releaseMouse()
+ {
+ m_pDataWindow->ReleaseMouse();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::invalidate( TableArea const i_what )
+ {
+ switch ( i_what )
+ {
+ case TableAreaColumnHeaders:
+ m_pDataWindow->Invalidate( calcHeaderRect( true ) );
+ break;
+
+ case TableAreaRowHeaders:
+ m_pDataWindow->Invalidate( calcHeaderRect( false ) );
+ break;
+
+ case TableAreaDataArea:
+ m_pDataWindow->Invalidate( impl_getAllVisibleDataCellArea() );
+ break;
+
+ case TableAreaAll:
+ m_pDataWindow->Invalidate();
+ break;
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ long TableControl_Impl::pixelWidthToAppFont( long const i_pixels ) const
+ {
+ return m_pDataWindow->PixelToLogic( Size( i_pixels, 0 ), MAP_APPFONT ).Width();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::hideTracking()
+ {
+ m_pDataWindow->HideTracking();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::showTracking( Rectangle const & i_location, sal_uInt16 const i_flags )
+ {
+ m_pDataWindow->ShowTracking( i_location, i_flags );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool TableControl_Impl::activateCell( ColPos const i_col, RowPos const i_row )
+ {
+ DBG_CHECK_ME();
+ return goTo( i_col, i_row );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::invalidateSelectedRegion(RowPos _nPrevRow, RowPos _nCurRow, Rectangle& _rCellRect)
+ {
+ DBG_CHECK_ME();
+ //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 aCellRect;
+ impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
+ _rCellRect.Top() = aCellRect.Top();
+ _rCellRect.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();
+ impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
+ _rCellRect.Bottom() = aCellRect.Bottom();
+ }
+ //if the region is beneath the current row
+ else
+ {
+ Rectangle aCellRect;
+ impl_getCellRect( m_nCurColumn, _nCurRow, aCellRect );
+ _rCellRect.Top() = aCellRect.Top();
+ impl_getCellRect( m_nCurColumn, _nPrevRow, aCellRect );
+ _rCellRect.Bottom() = aCellRect.Bottom();
+ }
+ m_pDataWindow->Invalidate(_rCellRect);
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow )
+ {
+ if ( m_nCursorHidden == 2 )
+ // WTF? what kind of hack is this?
+ --m_nCursorHidden;
+
+ 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;
+
+ Rectangle aInvalidateRect;
+
+ Rectangle const aVisibleCellsArea( impl_getAllVisibleCellsArea() );
+ TableRowGeometry aRow( *this, aVisibleCellsArea, firstRow, true );
+ while ( aRow.isValid() && ( aRow.getRow() <= lastRow ) )
+ {
+ aInvalidateRect.Union( aRow.getRect() );
+ aRow.moveDown();
+ }
+
+ if ( i_lastRow == ROW_INVALID )
+ aInvalidateRect.Bottom() = m_pDataWindow->GetOutputSizePixel().Height();
+
+ m_pDataWindow->Invalidate( aInvalidateRect );
+ }
+
+ //------------------------------------------------------------------------------
+ void TableControl_Impl::checkCursorPosition()
+ {
+ DBG_CHECK_ME();
+
+ TableSize nVisibleRows = impl_getVisibleRows(true);
+ TableSize nVisibleCols = impl_getVisibleColumns(true);
+ if ( ( m_nTopRow + nVisibleRows > m_nRowCount )
+ && ( m_nRowCount >= nVisibleRows )
+ )
+ {
+ --m_nTopRow;
+ }
+ else
+ {
+ m_nTopRow = 0;
+ }
+
+ if ( ( m_nLeftColumn + nVisibleCols > m_nColumnCount )
+ && ( m_nColumnCount >= nVisibleCols )
+ )
+ {
+ --m_nLeftColumn;
+ }
+ else
+ {
+ m_nLeftColumn = 0;
+ }
+
+ m_pDataWindow->Invalidate();
+ }
+
+ //--------------------------------------------------------------------
+ TableSize TableControl_Impl::impl_getVisibleRows( bool _bAcceptPartialRow ) const
+ {
+ DBG_CHECK_ME();
+
+ DBG_ASSERT( m_pDataWindow, "TableControl_Impl::impl_getVisibleRows: no data window!" );
+
+ return lcl_getRowsFittingInto(
+ m_pDataWindow->GetOutputSizePixel().Height() - m_nColHeaderHeightPixel,
+ m_nRowHeightPixel,
+ _bAcceptPartialRow
+ );
+ }
+
+ //--------------------------------------------------------------------
+ TableSize TableControl_Impl::impl_getVisibleColumns( bool _bAcceptPartialCol ) const
+ {
+ DBG_CHECK_ME();
+
+ DBG_ASSERT( m_pDataWindow, "TableControl_Impl::impl_getVisibleColumns: no data window!" );
+
+ return lcl_getColumnsVisibleWithin(
+ Rectangle( Point( 0, 0 ), m_pDataWindow->GetOutputSizePixel() ),
+ m_nLeftColumn,
+ *this,
+ _bAcceptPartialCol
+ );
+ }
+
+ //--------------------------------------------------------------------
+ bool TableControl_Impl::goTo( ColPos _nColumn, RowPos _nRow )
+ {
+ DBG_CHECK_ME();
+
+ // TODO: give veto listeners a chance
+
+ if ( ( _nColumn < 0 ) || ( _nColumn >= m_nColumnCount )
+ || ( _nRow < 0 ) || ( _nRow >= m_nRowCount )
+ )
+ {
+ OSL_ENSURE( false, "TableControl_Impl::goTo: invalid row or column index!" );
+ return false;
+ }
+
+ SuppressCursor aHideCursor( *this );
+ m_nCurColumn = _nColumn;
+ m_nCurRow = _nRow;
+
+ // ensure that the new cell is visible
+ ensureVisible( m_nCurColumn, m_nCurRow, false );
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ void TableControl_Impl::ensureVisible( ColPos _nColumn, RowPos _nRow, bool _bAcceptPartialVisibility )
+ {
+ DBG_CHECK_ME();
+ DBG_ASSERT( ( _nColumn >= 0 ) && ( _nColumn < m_nColumnCount )
+ && ( _nRow >= 0 ) && ( _nRow < m_nRowCount ),
+ "TableControl_Impl::ensureVisible: invalid coordinates!" );
+
+ SuppressCursor aHideCursor( *this );
+
+ if ( _nColumn < m_nLeftColumn )
+ impl_scrollColumns( _nColumn - m_nLeftColumn );
+ else
+ {
+ TableSize nVisibleColumns = impl_getVisibleColumns( _bAcceptPartialVisibility );
+ if ( _nColumn > m_nLeftColumn + nVisibleColumns - 1 )
+ {
+ impl_scrollColumns( _nColumn - ( m_nLeftColumn + nVisibleColumns - 1 ) );
+ // TODO: since not all columns have the same width, this might in theory result
+ // in the column still not being visible.
+ }
+ }
+
+ if ( _nRow < m_nTopRow )
+ impl_scrollRows( _nRow - m_nTopRow );
+ else
+ {
+ TableSize nVisibleRows = impl_getVisibleRows( _bAcceptPartialVisibility );
+ if ( _nRow > m_nTopRow + nVisibleRows - 1 )
+ impl_scrollRows( _nRow - ( m_nTopRow + nVisibleRows - 1 ) );
+ }
+ }
+
+ //--------------------------------------------------------------------
+ ::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 );
+ }
+
+ //--------------------------------------------------------------------
+ TableSize TableControl_Impl::impl_ni_ScrollRows( TableSize _nRowDelta )
+ {
+ // compute new top row
+ RowPos nNewTopRow =
+ ::std::max(
+ ::std::min( (RowPos)( m_nTopRow + _nRowDelta ), (RowPos)( m_nRowCount - 1 ) ),
+ (RowPos)0
+ );
+
+ RowPos nOldTopRow = m_nTopRow;
+ m_nTopRow = nNewTopRow;
+
+ // if updates are enabled currently, scroll the viewport
+ if ( m_nTopRow != nOldTopRow )
+ {
+ DBG_SUSPEND_INV( INV_SCROLL_POSITION );
+ SuppressCursor aHideCursor( *this );
+ // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
+ // which hides the cursor and then calls the listener)
+ // Same for onEndScroll
+
+ // scroll the view port, if possible
+ long nPixelDelta = m_nRowHeightPixel * ( m_nTopRow - nOldTopRow );
+
+ Rectangle aDataArea( Point( 0, m_nColHeaderHeightPixel ), m_pDataWindow->GetOutputSizePixel() );
+
+ if ( m_pDataWindow->GetBackground().IsScrollable()
+ && abs( nPixelDelta ) < aDataArea.GetHeight()
+ )
+ {
+ m_pDataWindow->Scroll( 0, (long)-nPixelDelta, aDataArea, SCROLL_CLIP | SCROLL_UPDATE | SCROLL_CHILDREN);
+ }
+ else
+ 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_nTopRow == 0 )
+ m_rAntiImpl.PostUserEvent( LINK( this, TableControl_Impl, OnUpdateScrollbars ) );
+
+ return (TableSize)( m_nTopRow - nOldTopRow );
+ }
+
+ //--------------------------------------------------------------------
+ TableSize TableControl_Impl::impl_scrollRows( TableSize const i_rowDelta )
+ {
+ DBG_CHECK_ME();
+ return impl_ni_ScrollRows( i_rowDelta );
+ }
+
+ //--------------------------------------------------------------------
+ TableSize TableControl_Impl::impl_ni_ScrollColumns( TableSize _nColumnDelta )
+ {
+ // compute new left column
+ const ColPos nNewLeftColumn =
+ ::std::max(
+ ::std::min( (ColPos)( m_nLeftColumn + _nColumnDelta ), (ColPos)( m_nColumnCount - 1 ) ),
+ (ColPos)0
+ );
+
+ const ColPos nOldLeftColumn = m_nLeftColumn;
+ m_nLeftColumn = nNewLeftColumn;
+
+ // if updates are enabled currently, scroll the viewport
+ if ( m_nLeftColumn != nOldLeftColumn )
+ {
+ DBG_SUSPEND_INV( INV_SCROLL_POSITION );
+ SuppressCursor aHideCursor( *this );
+ // TODO: call a onStartScroll at our listener (or better an own onStartScroll,
+ // which hides the cursor and then calls the listener)
+ // Same for onEndScroll
+
+ // scroll the view port, if possible
+ const Rectangle aDataArea( Point( m_nRowHeaderWidthPixel, 0 ), m_pDataWindow->GetOutputSizePixel() );
+
+ long nPixelDelta =
+ m_aColumnWidths[ nOldLeftColumn ].getStart()
+ - m_aColumnWidths[ m_nLeftColumn ].getStart();
+
+ // update our column positions
+ // Do this *before* scrolling, as SCROLL_UPDATE will trigger a paint, which already needs the correct
+ // information in m_aColumnWidths
+ for ( ColumnPositions::iterator colPos = m_aColumnWidths.begin();
+ colPos != m_aColumnWidths.end();
+ ++colPos
+ )
+ {
+ colPos->move( nPixelDelta );
+ }
+
+ // scroll the window content (if supported and possible), or invalidate the complete window
+ if ( m_pDataWindow->GetBackground().IsScrollable()
+ && abs( nPixelDelta ) < aDataArea.GetWidth()
+ )
+ {
+ m_pDataWindow->Scroll( nPixelDelta, 0, aDataArea, SCROLL_CLIP | SCROLL_UPDATE );
+ }
+ else
+ m_pDataWindow->Invalidate( INVALIDATE_UPDATE );
+
+ // update the position at the horizontal scrollbar
+ m_pHScroll->SetThumbPos( m_nLeftColumn );
+ }
+
+ // 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_nLeftColumn == 0 )
+ m_rAntiImpl.PostUserEvent( LINK( this, TableControl_Impl, OnUpdateScrollbars ) );
+
+ return (TableSize)( m_nLeftColumn - nOldLeftColumn );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ TableSize TableControl_Impl::impl_scrollColumns( TableSize const i_columnDelta )
+ {
+ DBG_CHECK_ME();
+ return impl_ni_ScrollColumns( i_columnDelta );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ SelectionEngine* TableControl_Impl::getSelEngine()
+ {
+ return m_pSelEngine;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ScrollBar* TableControl_Impl::getHorzScrollbar()
+ {
+ return m_pHScroll;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ ScrollBar* TableControl_Impl::getVertScrollbar()
+ {
+ return m_pVScroll;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool TableControl_Impl::isRowSelected( RowPos i_row ) const
+ {
+ return ::std::find( m_aSelectedRows.begin(), m_aSelectedRows.end(), i_row ) != m_aSelectedRows.end();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ RowPos TableControl_Impl::getSelectedRowIndex( size_t const i_selectionIndex ) const
+ {
+ if ( i_selectionIndex < m_aSelectedRows.size() )
+ return m_aSelectedRows[ i_selectionIndex ];
+ return ROW_INVALID;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ int TableControl_Impl::getRowSelectedNumber(const ::std::vector<RowPos>& selectedRows, RowPos current)
+ {
+ std::vector<RowPos>::const_iterator it = ::std::find(selectedRows.begin(),selectedRows.end(),current);
+ if ( it != selectedRows.end() )
+ {
+ return it - selectedRows.begin();
+ }
+ return -1;
+ }
+
+ //--------------------------------------------------------------------
+ ColPos TableControl_Impl::impl_getColumnForOrdinate( long const i_ordinate ) const
+ {
+ DBG_CHECK_ME();
+
+ if ( ( m_aColumnWidths.empty() ) || ( i_ordinate < 0 ) )
+ return COL_INVALID;
+
+ 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,
+ ColumnInfoPositionLess()
+ );
+ if ( lowerBound == m_aColumnWidths.end() )
+ {
+ // point is *behind* the start of the last column ...
+ if ( ordinate < m_aColumnWidths.rbegin()->getEnd() )
+ // ... but still before its end
+ return m_nColumnCount - 1;
+ return COL_INVALID;
+ }
+ return lowerBound - m_aColumnWidths.begin();
+ }
+
+ //--------------------------------------------------------------------
+ RowPos TableControl_Impl::impl_getRowForAbscissa( long const i_abscissa ) const
+ {
+ DBG_CHECK_ME();
+
+ if ( i_abscissa < 0 )
+ return ROW_INVALID;
+
+ if ( i_abscissa < m_nColHeaderHeightPixel )
+ return ROW_COL_HEADERS;
+
+ long const abscissa = i_abscissa - m_nColHeaderHeightPixel;
+ long const row = m_nTopRow + abscissa / m_nRowHeightPixel;
+ return row < m_pModel->getRowCount() ? row : ROW_INVALID;
+ }
+
+ //--------------------------------------------------------------------
+ bool TableControl_Impl::markRowAsDeselected( RowPos const i_rowIndex )
+ {
+ DBG_CHECK_ME();
+
+ ::std::vector< RowPos >::iterator selPos = ::std::find( m_aSelectedRows.begin(), m_aSelectedRows.end(), i_rowIndex );
+ if ( selPos == m_aSelectedRows.end() )
+ return false;
+
+ m_aSelectedRows.erase( selPos );
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ bool TableControl_Impl::markRowAsSelected( RowPos const i_rowIndex )
+ {
+ DBG_CHECK_ME();
+
+ if ( isRowSelected( i_rowIndex ) )
+ return false;
+
+ SelectionMode const eSelMode = getSelEngine()->GetSelectionMode();
+ switch ( eSelMode )
+ {
+ case SINGLE_SELECTION:
+ if ( !m_aSelectedRows.empty() )
+ {
+ OSL_ENSURE( m_aSelectedRows.size() == 1, "TableControl::markRowAsSelected: SingleSelection with more than one selected element?" );
+ m_aSelectedRows[0] = i_rowIndex;
+ break;
+ }
+ // fall through
+
+ case MULTIPLE_SELECTION:
+ m_aSelectedRows.push_back( i_rowIndex );
+ break;
+
+ default:
+ OSL_ENSURE( false, "TableControl_Impl::markRowAsSelected: unsupported selection mode!" );
+ return false;
+ }
+
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ bool TableControl_Impl::markAllRowsAsDeselected()
+ {
+ if ( m_aSelectedRows.empty() )
+ return false;
+
+ m_aSelectedRows.clear();
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ bool TableControl_Impl::markAllRowsAsSelected()
+ {
+ DBG_CHECK_ME();
+
+ SelectionMode const eSelMode = getSelEngine()->GetSelectionMode();
+ ENSURE_OR_RETURN_FALSE( eSelMode == MULTIPLE_SELECTION, "TableControl_Impl::markAllRowsAsSelected: unsupported selection mode!" );
+
+ if ( m_aSelectedRows.size() == size_t( m_pModel->getRowCount() ) )
+ {
+ #if OSL_DEBUG_LEVEL > 0
+ for ( TableSize row = 0; row < m_pModel->getRowCount(); ++row )
+ {
+ OSL_ENSURE( isRowSelected( row ), "TableControl_Impl::markAllRowsAsSelected: inconsistency in the selected rows!" );
+ }
+ #endif
+ // already all rows marked as selected
+ return false;
+ }
+
+ m_aSelectedRows.clear();
+ for ( RowPos i=0; i < m_pModel->getRowCount(); ++i )
+ m_aSelectedRows.push_back(i);
+
+ return true;
+ }
+
+ //--------------------------------------------------------------------
+ Rectangle TableControl_Impl::calcHeaderRect(bool bColHeader)
+ {
+ Rectangle const aRectTableWithHeaders( impl_getAllVisibleCellsArea() );
+ Size const aSizeTableWithHeaders( aRectTableWithHeaders.GetSize() );
+ if ( bColHeader )
+ return Rectangle( aRectTableWithHeaders.TopLeft(), Size( aSizeTableWithHeaders.Width(), m_nColHeaderHeightPixel ) );
+ else
+ return Rectangle( aRectTableWithHeaders.TopLeft(), Size( m_nRowHeaderWidthPixel, aSizeTableWithHeaders.Height() ) );
+ }
+
+ //--------------------------------------------------------------------
+ Rectangle TableControl_Impl::calcTableRect()
+ {
+ return impl_getAllVisibleDataCellArea();
+ }
+
+ //--------------------------------------------------------------------
+ IMPL_LINK( TableControl_Impl, OnUpdateScrollbars, void*, /**/ )
+ {
+ DBG_CHECK_ME();
+ impl_ni_updateScrollbars();
+ return 1L;
+ }
+
+ //--------------------------------------------------------------------
+ IMPL_LINK( TableControl_Impl, OnScroll, ScrollBar*, _pScrollbar )
+ {
+ DBG_ASSERT( ( _pScrollbar == m_pVScroll ) || ( _pScrollbar == m_pHScroll ),
+ "TableControl_Impl::OnScroll: where did this come from?" );
+
+ if ( _pScrollbar == m_pVScroll )
+ impl_ni_ScrollRows( _pScrollbar->GetDelta() );
+ else
+ impl_ni_ScrollColumns( _pScrollbar->GetDelta() );
+
+ return 0L;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ Reference< XAccessible > TableControl_Impl::getAccessible( Window& i_parentWindow )
+ {
+ DBG_TESTSOLARMUTEX();
+ if ( m_pAccessibleTable == NULL )
+ {
+ Reference< XAccessible > const xAccParent = i_parentWindow.GetAccessible();
+ if ( xAccParent.is() )
+ {
+ m_pAccessibleTable = m_aFactoryAccess.getFactory().createAccessibleTableControl(
+ xAccParent, m_rAntiImpl
+ );
+ }
+ }
+
+ Reference< XAccessible > xAccessible;
+ if ( m_pAccessibleTable )
+ xAccessible = m_pAccessibleTable->getMyself();
+ return xAccessible;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::disposeAccessible()
+ {
+ if ( m_pAccessibleTable )
+ m_pAccessibleTable->dispose();
+ m_pAccessibleTable = NULL;
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool TableControl_Impl::impl_isAccessibleAlive() const
+ {
+ DBG_CHECK_ME();
+ return ( NULL != m_pAccessibleTable ) && m_pAccessibleTable->isAlive();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableControl_Impl::impl_commitAccessibleEvent( sal_Int16 const i_eventID, Any const & i_newValue, Any const & i_oldValue )
+ {
+ DBG_CHECK_ME();
+ if ( impl_isAccessibleAlive() )
+ m_pAccessibleTable->commitEvent( i_eventID, i_newValue, i_oldValue );
+ }
+
+ //==================================================================================================================
+ //= TableFunctionSet
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ TableFunctionSet::TableFunctionSet(TableControl_Impl* _pTableControl)
+ :m_pTableControl( _pTableControl)
+ ,m_nCurrentRow( ROW_INVALID )
+ {
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ TableFunctionSet::~TableFunctionSet()
+ {
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableFunctionSet::BeginDrag()
+ {
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableFunctionSet::CreateAnchor()
+ {
+ m_pTableControl->setAnchor( m_pTableControl->getCurRow() );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableFunctionSet::DestroyAnchor()
+ {
+ m_pTableControl->setAnchor( ROW_INVALID );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Bool TableFunctionSet::SetCursorAtPoint(const Point& rPoint, sal_Bool bDontSelectAtCursor)
+ {
+ sal_Bool bHandled = sal_False;
+ // newRow is the row which includes the point, getCurRow() is the last selected row, before the mouse click
+ RowPos newRow = m_pTableControl->getRowAtPoint( rPoint );
+ if ( newRow == ROW_COL_HEADERS )
+ newRow = m_pTableControl->getTopRow();
+
+ ColPos newCol = m_pTableControl->getColAtPoint( rPoint );
+ if ( newCol == COL_ROW_HEADERS )
+ newCol = m_pTableControl->getLeftColumn();
+
+ if ( ( newRow == ROW_INVALID ) || ( newCol == COL_INVALID ) )
+ return sal_False;
+
+ if ( bDontSelectAtCursor )
+ {
+ if ( m_pTableControl->getSelectedRowCount() > 1 )
+ m_pTableControl->getSelEngine()->AddAlways(sal_True);
+ bHandled = sal_True;
+ }
+ else if ( m_pTableControl->getAnchor() == m_pTableControl->getCurRow() )
+ {
+ //selecting region,
+ int diff = m_pTableControl->getCurRow() - newRow;
+ //selected region lies above the last selection
+ if( diff >= 0)
+ {
+ //put selected rows in vector
+ while ( m_pTableControl->getAnchor() >= newRow )
+ {
+ m_pTableControl->markRowAsSelected( m_pTableControl->getAnchor() );
+ m_pTableControl->setAnchor( m_pTableControl->getAnchor() - 1 );
+ diff--;
+ }
+ m_pTableControl->setAnchor( m_pTableControl->getAnchor() + 1 );
+ }
+ //selected region lies beneath the last selected row
+ else
+ {
+ while ( m_pTableControl->getAnchor() <= newRow )
+ {
+ m_pTableControl->markRowAsSelected( m_pTableControl->getAnchor() );
+ m_pTableControl->setAnchor( m_pTableControl->getAnchor() + 1 );
+ diff++;
+ }
+ m_pTableControl->setAnchor( m_pTableControl->getAnchor() - 1 );
+ }
+ Rectangle aCellRect;
+ m_pTableControl->invalidateSelectedRegion( m_pTableControl->getCurRow(), newRow, aCellRect );
+ bHandled = sal_True;
+ }
+ //no region selected
+ else
+ {
+ if ( !m_pTableControl->hasRowSelection() )
+ m_pTableControl->markRowAsSelected( newRow );
+ else
+ {
+ if ( m_pTableControl->getSelEngine()->GetSelectionMode() == SINGLE_SELECTION )
+ {
+ DeselectAll();
+ m_pTableControl->markRowAsSelected( newRow );
+ }
+ else
+ {
+ m_pTableControl->markRowAsSelected( newRow );
+ }
+ }
+ 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 );
+ bHandled = sal_True;
+ }
+ m_pTableControl->goTo( newCol, newRow );
+ return bHandled;
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ sal_Bool TableFunctionSet::IsSelectionAtPoint( const Point& rPoint )
+ {
+ m_pTableControl->getSelEngine()->AddAlways(sal_False);
+ if ( !m_pTableControl->hasRowSelection() )
+ return sal_False;
+ else
+ {
+ RowPos curRow = m_pTableControl->getRowAtPoint( rPoint );
+ m_pTableControl->setAnchor( ROW_INVALID );
+ bool selected = m_pTableControl->isRowSelected( curRow );
+ m_nCurrentRow = curRow;
+ return selected;
+ }
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableFunctionSet::DeselectAtPoint( const Point& rPoint )
+ {
+ (void)rPoint;
+ Rectangle aCellRange;
+ m_pTableControl->invalidateSelectedRegion( m_nCurrentRow, m_nCurrentRow, aCellRange );
+ m_pTableControl->markRowAsDeselected( m_nCurrentRow );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableFunctionSet::DeselectAll()
+ {
+ 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->markAllRowsAsDeselected();
+ }
+ }
+
+//......................................................................................................................
+} } // namespace svt::table
+//......................................................................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/table/tablecontrol_impl.hxx b/svtools/source/table/tablecontrol_impl.hxx
new file mode 100644
index 000000000000..2f9cffd3089b
--- /dev/null
+++ b/svtools/source/table/tablecontrol_impl.hxx
@@ -0,0 +1,488 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+#ifndef SVTOOLS_TABLECONTROL_IMPL_HXX
+#define SVTOOLS_TABLECONTROL_IMPL_HXX
+
+#include "svtools/table/tablemodel.hxx"
+#include "svtools/table/tablecontrolinterface.hxx"
+
+#include "svtaccessiblefactory.hxx"
+
+#include <vcl/seleng.hxx>
+
+#include <vector>
+
+#include <boost/scoped_ptr.hpp>
+
+class ScrollBar;
+class ScrollBarBox;
+
+//........................................................................
+namespace svt { namespace table
+{
+//........................................................................
+
+ struct MutableColumnMetrics : protected ColumnMetrics
+ {
+ MutableColumnMetrics()
+ :ColumnMetrics()
+ {
+ }
+
+ MutableColumnMetrics( long const i_startPixel, long const i_endPixel )
+ :ColumnMetrics( i_startPixel, i_endPixel )
+ {
+ }
+
+ long getStart() const { return nStartPixel; }
+ long getEnd() const { return nEndPixel; }
+
+ void setEnd( long const i_end ) { nEndPixel = i_end; }
+ void move( long const i_offset ) { nStartPixel += i_offset; nEndPixel += i_offset; }
+
+ long getWidth() const { return nEndPixel - nStartPixel; }
+
+ ColumnMetrics const & operator()() { return *this; }
+ };
+
+ struct ColumnInfoPositionLess
+ {
+ bool operator()( MutableColumnMetrics const& i_colInfo, long const i_position )
+ {
+ return i_colInfo.getEnd() < i_position;
+ }
+ bool operator()( long const i_position, MutableColumnMetrics const& i_colInfo )
+ {
+ return i_position < i_colInfo.getStart();
+ }
+ };
+
+ typedef ::std::vector< MutableColumnMetrics > ColumnPositions;
+
+ class TableControl;
+ class TableDataWindow;
+ class TableFunctionSet;
+
+ //====================================================================
+ //= TableControl_Impl
+ //====================================================================
+ class TableControl_Impl :public ITableControl
+ ,public ITableModelListener
+ {
+ friend class TableGeometry;
+ friend class TableRowGeometry;
+ friend class TableColumnGeometry;
+ friend class SuspendInvariants;
+
+ private:
+ /// the control whose impl-instance we implemnt
+ TableControl& m_rAntiImpl;
+ /// the model of the table control
+ PTableModel m_pModel;
+ /// the input handler to use, usually the input handler as provided by ->m_pModel
+ PTableInputHandler m_pInputHandler;
+ /// info about the widths of our columns
+ ColumnPositions m_aColumnWidths;
+
+ /// the height of a single row in the table, measured in pixels
+ long m_nRowHeightPixel;
+ /// the height of the column header row in the table, measured in pixels
+ long m_nColHeaderHeightPixel;
+ /// the width of the row header column in the table, measured in pixels
+ long m_nRowHeaderWidthPixel;
+
+ /// the number of columns in the table control. Cached model value.
+ TableSize m_nColumnCount;
+
+ /// the number of rows in the table control. Cached model value.
+ TableSize m_nRowCount;
+
+ /// denotes whether or not the columns fitted into the available width, last time we checked
+ long m_bColumnsFit;
+
+ ColPos m_nCurColumn;
+ RowPos m_nCurRow;
+ ColPos m_nLeftColumn;
+ RowPos m_nTopRow;
+
+ sal_Int32 m_nCursorHidden;
+
+ /** the window to contain all data content, including header bars
+
+ The window's upper left corner is at position (0,0), relative to the
+ table control, which is the direct parent of the data window.
+ */
+ ::boost::scoped_ptr< TableDataWindow >
+ m_pDataWindow;
+ /// the vertical scrollbar, if any
+ ScrollBar* m_pVScroll;
+ /// the horizontal scrollbar, if any
+ ScrollBar* m_pHScroll;
+ ScrollBarBox* m_pScrollCorner;
+ //selection engine - for determining selection range, e.g. single, multiple
+ SelectionEngine* m_pSelEngine;
+ //vector which contains the selected rows
+ std::vector<RowPos> m_aSelectedRows;
+ //part of selection engine
+ TableFunctionSet* m_pTableFunctionSet;
+ //part of selection engine
+ RowPos m_nAnchor;
+ bool m_bUpdatingColWidths;
+
+ Link m_aSelectHdl;
+
+ AccessibleFactoryAccess m_aFactoryAccess;
+ IAccessibleTableControl* m_pAccessibleTable;
+
+#if DBG_UTIL
+ #define INV_SCROLL_POSITION 1
+ /** represents a bitmask of invariants to check
+
+ Actually, impl_checkInvariants checks more invariants than denoted in this
+ bit mask, but only those present here can be disabled temporarily.
+ */
+ sal_Int32 m_nRequiredInvariants;
+#endif
+
+ public:
+ void setModel( PTableModel _pModel );
+
+ inline const PTableInputHandler& getInputHandler() const { return m_pInputHandler; }
+
+ inline RowPos getCurRow() const { return m_nCurRow; }
+ inline void setCurRow( RowPos i_curRow ){ m_nCurRow = i_curRow; }
+
+ RowPos getAnchor() const { return m_nAnchor; }
+ void setAnchor( RowPos const i_anchor ) { m_nAnchor = i_anchor; }
+
+ inline RowPos getTopRow() const { return m_nTopRow; }
+ inline ColPos getLeftColumn() const { return m_nLeftColumn; }
+
+ inline const TableControl& getAntiImpl() const { return m_rAntiImpl; }
+ inline TableControl& getAntiImpl() { return m_rAntiImpl; }
+
+ public:
+ TableControl_Impl( TableControl& _rAntiImpl );
+ ~TableControl_Impl();
+
+#if DBG_UTIL
+ const sal_Char* impl_checkInvariants() const;
+#endif
+ /** to be called when the anti-impl instance has been resized
+ */
+ void onResize();
+
+ /** paints the table control content which intersects with the given rectangle
+ */
+ void doPaintContent( const Rectangle& _rUpdateRect );
+
+ /** moves the cursor to the cell with the given coordinates
+
+ To ease the caller's code, the coordinates must not necessarily denote a
+ valid position. If they don't, <FALSE/> will be returned.
+ */
+ bool goTo( ColPos _nColumn, RowPos _nRow );
+
+ /** ensures that the given coordinate is visible
+ @param _nColumn
+ the column position which should be visible. Must be non-negative, and smaller
+ than the column count.
+ @param _nRow
+ the row position which should be visibleMust be non-negative, and smaller
+ than the row count.
+ @param _bAcceptPartialVisibility
+ <TRUE/> if it's okay that the given cooordinate is only partially visible
+ */
+ void ensureVisible( ColPos _nColumn, RowPos _nRow, bool _bAcceptPartialVisibility );
+
+ /** retrieves the content of the given cell, converted to a string
+ */
+ ::rtl::OUString getCellContentAsString( RowPos const i_row, ColPos const i_col );
+
+ /** 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 );
+
+ /** invalidates the part of the data window which is covered by the given row
+ @param i_firstRow
+ the index of the first row to include in the invalidation
+ @param i_lastRow
+ the index of the last row to include in the invalidation, or ROW_INVALID if the invalidation
+ should happen down to the bottom of the data window.
+ */
+ void invalidateRowRange( RowPos const i_firstRow, RowPos const i_lastRow );
+
+ void checkCursorPosition();
+
+ bool hasRowSelection() const { return !m_aSelectedRows.empty(); }
+ size_t getSelectedRowCount() const { return m_aSelectedRows.size(); }
+ RowPos getSelectedRowIndex( size_t const i_selectionIndex ) const;
+
+ /** removes the given row index from m_aSelectedRows
+
+ @return
+ <TRUE/> if and only if the row was previously marked as selected
+ */
+ bool markRowAsDeselected( RowPos const i_rowIndex );
+
+ /** marks the given row as selectged, by putting it into m_aSelectedRows
+ @return
+ <TRUE/> if and only if the row was previously <em>not</em> marked as selected
+ */
+ bool markRowAsSelected( RowPos const i_rowIndex );
+
+ /** marks all rows as deselected
+ @return
+ <TRUE/> if and only if the selection actually changed by this operation
+ */
+ bool markAllRowsAsDeselected();
+
+ /** marks all rows as selected
+ @return
+ <FALSE/> if and only if all rows were selected already.
+ */
+ bool markAllRowsAsSelected();
+
+ void setSelectHandler( Link const & i_selectHandler ) { m_aSelectHdl = i_selectHandler; }
+ Link const& getSelectHandler() const { return m_aSelectHdl; }
+
+ // ITableControl
+ virtual void hideCursor();
+ virtual void showCursor();
+ virtual bool dispatchAction( TableControlAction _eAction );
+ virtual SelectionEngine* getSelEngine();
+ virtual PTableModel getModel() const;
+ virtual ColPos getCurrentColumn() const;
+ virtual RowPos getCurrentRow() const;
+ virtual bool activateCell( ColPos const i_col, RowPos const i_row );
+ virtual ::Size getTableSizePixel() const;
+ virtual void setPointer( Pointer const & i_pointer );
+ virtual void captureMouse();
+ virtual void releaseMouse();
+ virtual void invalidate( TableArea const i_what );
+ virtual long pixelWidthToAppFont( long const i_pixels ) const;
+ virtual void hideTracking();
+ virtual void showTracking( Rectangle const & i_location, sal_uInt16 const i_flags );
+ virtual RowPos getRowAtPoint( const Point& rPoint ) const;
+ virtual ColPos getColAtPoint( const Point& rPoint ) const;
+ virtual TableCell hitTest( const Point& rPoint ) const;
+ virtual ColumnMetrics getColumnMetrics( ColPos const i_column ) const;
+ virtual bool isRowSelected( RowPos i_row ) const;
+
+
+ TableDataWindow& getDataWindow() { return *m_pDataWindow; }
+ const TableDataWindow& getDataWindow() const { return *m_pDataWindow; }
+ ScrollBar* getHorzScrollbar();
+ ScrollBar* getVertScrollbar();
+
+ Rectangle calcHeaderRect(bool bColHeader);
+ Rectangle calcTableRect();
+
+ // A11Y
+ ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >
+ getAccessible( Window& i_parentWindow );
+ void disposeAccessible();
+
+ // ITableModelListener
+ virtual void rowsInserted( RowPos first, RowPos last );
+ virtual void rowsRemoved( RowPos first, RowPos last );
+ virtual void columnInserted( ColPos const i_colIndex );
+ virtual void columnRemoved( ColPos const i_colIndex );
+ virtual void allColumnsRemoved();
+ virtual void cellsUpdated( ColPos const i_firstCol, ColPos i_lastCol, RowPos const i_firstRow, RowPos const i_lastRow );
+ virtual void columnChanged( ColPos const i_column, ColumnAttributeGroup const i_attributeGroup );
+ virtual void tableMetricsChanged();
+
+ private:
+ bool impl_isAccessibleAlive() const;
+ void impl_commitAccessibleEvent(
+ sal_Int16 const i_eventID,
+ ::com::sun::star::uno::Any const & i_newValue,
+ ::com::sun::star::uno::Any const & i_oldValue
+ );
+
+ /** toggles the cursor visibility
+
+ The method is not bound to the classes public invariants, as it's used in
+ situations where the they must not necessarily be fullfilled.
+ */
+ void impl_ni_doSwitchCursor( bool _bOn );
+
+ /** returns the number of visible rows.
+
+ @param _bAcceptPartialRow
+ specifies whether a possible only partially visible last row is
+ counted, too.
+ */
+ TableSize impl_getVisibleRows( bool _bAcceptPartialRow ) const;
+
+ /** returns the number of visible columns
+
+ The value may change with different horizontal scroll positions, as
+ different columns have different widths. For instance, if your control is
+ 100 pixels wide, and has three columns of width 50, 50, 100, respectively,
+ then this method will return either "2" or "1", depending on which column
+ is the first visible one.
+
+ @param _bAcceptPartialRow
+ specifies whether a possible only partially visible last row is
+ counted, too.
+ */
+ TableSize impl_getVisibleColumns( bool _bAcceptPartialCol ) const;
+
+ /** determines the rectangle occupied by the given cell
+ */
+ void impl_getCellRect( ColPos _nColumn, RowPos _nRow, Rectangle& _rCellRect ) const;
+
+ /** updates all cached model values
+
+ The method is not bound to the classes public invariants, as it's used in
+ situations where the they must not necessarily be fullfilled.
+ */
+ void impl_ni_updateCachedModelValues();
+
+ /** updates the cached table metrics (row height etc.)
+ */
+ void impl_ni_updateCachedTableMetrics();
+
+ /** updates ->m_aColumnWidthsPixel with the current pixel widths of all model columns
+
+ 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>.
+ */
+ void impl_ni_updateColumnWidths( ColPos const i_assumeInflexibleColumnsUpToIncluding = COL_INVALID );
+
+ /** updates the scrollbars of the 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.
+
+ This includes both the existence of the scrollbars, and their
+ state.
+ */
+ void impl_ni_updateScrollbars();
+
+ /** scrolls the view by the given number of rows
+
+ The method is not bound to the classes public invariants, as it's used in
+ situations where the they must not necessarily be fullfilled.
+
+ @return
+ the number of rows by which the viewport was scrolled. This may differ
+ from the given numbers to scroll in case the begin or the end of the
+ row range were reached.
+ */
+ TableSize impl_ni_ScrollRows( TableSize _nRowDelta );
+
+ /** equivalent to impl_ni_ScrollRows, but checks the instances invariants beforehand (in a non-product build only)
+ */
+ TableSize impl_scrollRows( TableSize const i_rowDelta );
+
+ /** scrolls the view by the given number of columns
+
+ The method is not bound to the classes public invariants, as it's used in
+ situations where the they must not necessarily be fullfilled.
+
+ @return
+ the number of columns by which the viewport was scrolled. This may differ
+ from the given numbers to scroll in case the begin or the end of the
+ column range were reached.
+ */
+ TableSize impl_ni_ScrollColumns( TableSize _nColumnDelta );
+
+ /** equivalent to impl_ni_ScrollColumns, but checks the instances invariants beforehand (in a non-product build only)
+ */
+ TableSize impl_scrollColumns( TableSize const i_columnDelta );
+
+ /** retrieves the area occupied by the totality of (at least partially) visible cells
+
+ The returned area includes row and column headers. Also, it takes into
+ account the the fact that there might be less columns than would normally
+ find room in the control.
+
+ As a result of respecting the partial visibility of rows and columns,
+ the returned area might be larger than the data window's output size.
+ */
+ Rectangle impl_getAllVisibleCellsArea() const;
+
+ /** retrieves the area occupied by all (at least partially) visible data cells.
+
+ Effectively, the returned area is the same as returned by ->impl_getAllVisibleCellsArea,
+ minus the row and column header areas.
+ */
+ Rectangle impl_getAllVisibleDataCellArea() const;
+
+ /** retrieves the column which covers the given ordinate
+ */
+ ColPos impl_getColumnForOrdinate( long const i_ordinate ) const;
+
+ /** retrieves the row which covers the given abscissa
+ */
+ RowPos impl_getRowForAbscissa( long const i_abscissa ) const;
+
+ /// invalidates the window area occupied by the given column
+ void impl_invalidateColumn( ColPos const i_column );
+
+ DECL_LINK( OnScroll, ScrollBar* );
+ DECL_LINK( OnUpdateScrollbars, void* );
+ };
+
+ //see seleng.hxx, seleng.cxx, FunctionSet overridables, part of selection engine
+ class TableFunctionSet : public FunctionSet
+ {
+ private:
+ TableControl_Impl* m_pTableControl;
+ RowPos m_nCurrentRow;
+
+ public:
+ TableFunctionSet(TableControl_Impl* _pTableControl);
+ virtual ~TableFunctionSet();
+
+ virtual void BeginDrag();
+ virtual void CreateAnchor();
+ virtual void DestroyAnchor();
+ virtual sal_Bool SetCursorAtPoint(const Point& rPoint, sal_Bool bDontSelectAtCursor);
+ virtual sal_Bool IsSelectionAtPoint( const Point& rPoint );
+ virtual void DeselectAtPoint( const Point& rPoint );
+ virtual void DeselectAll();
+ };
+
+
+//........................................................................
+} } // namespace svt::table
+//........................................................................
+
+#endif // SVTOOLS_TABLECONTROL_IMPL_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/table/tabledatawindow.cxx b/svtools/source/table/tabledatawindow.cxx
new file mode 100644
index 000000000000..7c546421555d
--- /dev/null
+++ b/svtools/source/table/tabledatawindow.cxx
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include "svtools/table/tablecontrol.hxx"
+
+#include "tabledatawindow.hxx"
+#include "tablecontrol_impl.hxx"
+#include "tablegeometry.hxx"
+#include "cellvalueconversion.hxx"
+
+#include <vcl/help.hxx>
+
+//......................................................................................................................
+namespace svt { namespace table
+{
+//......................................................................................................................
+
+ /** === begin UNO using === **/
+ using ::com::sun::star::uno::Any;
+ /** === end UNO using === **/
+
+ //==================================================================================================================
+ //= TableDataWindow
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ TableDataWindow::TableDataWindow( TableControl_Impl& _rTableControl )
+ :Window( &_rTableControl.getAntiImpl() )
+ ,m_rTableControl( _rTableControl )
+ ,m_nTipWindowHandle( 0 )
+ {
+ // by default, use the background as determined by the style settings
+ const Color aWindowColor( GetSettings().GetStyleSettings().GetFieldColor() );
+ SetBackground( Wallpaper( aWindowColor ) );
+ SetFillColor( aWindowColor );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ TableDataWindow::~TableDataWindow()
+ {
+ impl_hideTipWindow();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::Paint( const Rectangle& rUpdateRect )
+ {
+ m_rTableControl.doPaintContent( rUpdateRect );
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::SetBackground( const Wallpaper& rColor )
+ {
+ Window::SetBackground( rColor );
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::SetControlBackground( const Color& rColor )
+ {
+ Window::SetControlBackground( rColor );
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::SetBackground()
+ {
+ Window::SetBackground();
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::SetControlBackground()
+ {
+ Window::SetControlBackground();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::RequestHelp( const HelpEvent& rHEvt )
+ {
+ sal_uInt16 const nHelpMode = rHEvt.GetMode();
+ if ( ( IsMouseCaptured() )
+ || ( ( nHelpMode & HELPMODE_QUICK ) == 0 )
+ )
+ {
+ Window::RequestHelp( rHEvt );
+ return;
+ }
+
+ ::rtl::OUString sHelpText;
+ sal_uInt16 nHelpStyle = 0;
+
+ Point const aMousePos( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) );
+ RowPos const hitRow = m_rTableControl.getRowAtPoint( aMousePos );
+ ColPos const hitCol = m_rTableControl.getColAtPoint( aMousePos );
+
+ PTableModel const pTableModel( m_rTableControl.getModel() );
+ if ( ( hitCol >= 0 ) && ( hitCol < pTableModel->getColumnCount() ) )
+ {
+ if ( hitRow == ROW_COL_HEADERS )
+ {
+ sHelpText = pTableModel->getColumnModel( hitCol )->getHelpText();
+ }
+ else if ( ( hitRow >= 0 ) && ( hitRow < pTableModel->getRowCount() ) )
+ {
+ Any aCellToolTip;
+ pTableModel->getCellToolTip( hitCol, hitRow, aCellToolTip );
+ if ( !aCellToolTip.hasValue() )
+ {
+ // use the cell content
+ pTableModel->getCellContent( hitCol, hitRow, aCellToolTip );
+
+ // use the cell content as tool tip only if it doesn't fit into the cell.
+ bool const activeCell = ( hitRow == m_rTableControl.getCurrentRow() ) && ( hitCol == m_rTableControl.getCurrentColumn() );
+ bool const selectedCell = m_rTableControl.isRowSelected( hitRow );
+
+ Rectangle const aWindowRect( Point( 0, 0 ), GetOutputSizePixel() );
+ TableCellGeometry const aCell( m_rTableControl, aWindowRect, hitCol, hitRow );
+ Rectangle const aCellRect( aCell.getRect() );
+
+ PTableRenderer const pRenderer = pTableModel->getRenderer();
+ if ( pRenderer->FitsIntoCell( aCellToolTip, hitCol, hitRow, activeCell, selectedCell, *this, aCellRect ) )
+ aCellToolTip.clear();
+ }
+
+ sHelpText = CellValueConversion::convertToString( aCellToolTip );
+
+ if ( sHelpText.indexOf( '\n' ) >= 0 )
+ nHelpStyle = QUICKHELP_TIP_STYLE_BALLOON;
+ }
+ }
+
+ if ( sHelpText.getLength() )
+ {
+ 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();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::impl_hideTipWindow()
+ {
+ if ( m_nTipWindowHandle != 0 )
+ {
+ Help::HideTip( m_nTipWindowHandle );
+ m_nTipWindowHandle = 0;
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::MouseMove( const MouseEvent& rMEvt )
+ {
+ if ( rMEvt.IsLeaveWindow() )
+ impl_hideTipWindow();
+
+ if ( !m_rTableControl.getInputHandler()->MouseMove( m_rTableControl, rMEvt ) )
+ {
+ Window::MouseMove( rMEvt );
+ }
+ }
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::MouseButtonDown( const MouseEvent& rMEvt )
+ {
+ impl_hideTipWindow();
+
+ Point const aPoint = rMEvt.GetPosPixel();
+ RowPos const hitRow = m_rTableControl.getRowAtPoint( aPoint );
+ bool const wasRowSelected = m_rTableControl.isRowSelected( hitRow );
+
+ if ( !m_rTableControl.getInputHandler()->MouseButtonDown( m_rTableControl, rMEvt ) )
+ {
+ Window::MouseButtonDown( rMEvt );
+ return;
+ }
+
+ bool const isRowSelected = m_rTableControl.isRowSelected( hitRow );
+ if ( isRowSelected != wasRowSelected )
+ {
+ m_aSelectHdl.Call( NULL );
+ }
+ m_aMouseButtonDownHdl.Call((MouseEvent*) &rMEvt);
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableDataWindow::MouseButtonUp( const MouseEvent& rMEvt )
+ {
+ if ( !m_rTableControl.getInputHandler()->MouseButtonUp( m_rTableControl, rMEvt ) )
+ Window::MouseButtonUp( rMEvt );
+
+ m_aMouseButtonUpHdl.Call((MouseEvent*) &rMEvt);
+ m_rTableControl.getAntiImpl().GrabFocus();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ long TableDataWindow::Notify(NotifyEvent& rNEvt )
+ {
+ long nDone = 0;
+ if ( rNEvt.GetType() == EVENT_COMMAND )
+ {
+ const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
+ if ( rCEvt.GetCommand() == COMMAND_WHEEL )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
+ {
+ nDone = HandleScrollCommand( rCEvt, m_rTableControl.getHorzScrollbar(), m_rTableControl.getVertScrollbar() );
+ }
+ }
+ }
+ return nDone ? nDone : Window::Notify( rNEvt );
+ }
+//......................................................................................................................
+} } // namespace svt::table
+//......................................................................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/table/tabledatawindow.hxx b/svtools/source/table/tabledatawindow.hxx
new file mode 100644
index 000000000000..c26cd6ccd596
--- /dev/null
+++ b/svtools/source/table/tabledatawindow.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+#ifndef SVTOOLS_SOURCE_TABLE_TABLEDATAWINDOW_HXX
+#define SVTOOLS_SOURCE_TABLE_TABLEDATAWINDOW_HXX
+
+#include <vcl/window.hxx>
+#include <vcl/seleng.hxx>
+
+//........................................................................
+namespace svt { namespace table
+{
+//........................................................................
+
+ class TableControl_Impl;
+ class TableFunctionSet;
+
+
+ //====================================================================
+ //= TableDataWindow
+ //====================================================================
+ /** the window containing the content area (including headers) of
+ a table control
+ */
+ class TableDataWindow : public Window
+ {
+ friend class TableFunctionSet;
+ private:
+ TableControl_Impl& m_rTableControl;
+ Link m_aMouseButtonDownHdl;
+ Link m_aMouseButtonUpHdl;
+ Link m_aSelectHdl;
+ sal_uLong m_nTipWindowHandle;
+
+ public:
+ 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; }
+
+ // Window overridables
+ virtual void Paint( const Rectangle& rRect );
+ virtual void MouseMove( const MouseEvent& rMEvt);
+ virtual void MouseButtonDown( const MouseEvent& rMEvt);
+ virtual void MouseButtonUp( const MouseEvent& rMEvt);
+ virtual long Notify(NotifyEvent& rNEvt);
+ virtual void SetControlBackground(const Color& rColor);
+ virtual void SetControlBackground();
+ virtual void RequestHelp( const HelpEvent& rHEvt );
+
+ void SetBackground(const Wallpaper& rColor);
+ void SetBackground();
+
+ private:
+ void impl_hideTipWindow();
+ };
+//........................................................................
+} } // namespace svt::table
+//........................................................................
+
+#endif // SVTOOLS_SOURCE_TABLE_TABLEDATAWINDOW_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/table/tablegeometry.cxx b/svtools/source/table/tablegeometry.cxx
new file mode 100644
index 000000000000..e00e21c28911
--- /dev/null
+++ b/svtools/source/table/tablegeometry.cxx
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svtools.hxx"
+
+#include "tablegeometry.hxx"
+#include "tablecontrol_impl.hxx"
+
+#include <tools/debug.hxx>
+
+//......................................................................................................................
+namespace svt { namespace table
+{
+//......................................................................................................................
+
+ //==================================================================================================================
+ //= TableRowGeometry
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ TableRowGeometry::TableRowGeometry( TableControl_Impl const & _rControl, Rectangle const & _rBoundaries,
+ RowPos const _nRow, bool const i_allowVirtualRows )
+ :TableGeometry( _rControl, _rBoundaries )
+ ,m_nRowPos( _nRow )
+ ,m_bAllowVirtualRows( i_allowVirtualRows )
+ {
+ if ( m_nRowPos == ROW_COL_HEADERS )
+ {
+ m_aRect.Top() = 0;
+ m_aRect.Bottom() = m_rControl.m_nColHeaderHeightPixel - 1;
+ }
+ else
+ {
+ impl_initRect();
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableRowGeometry::impl_initRect()
+ {
+ if ( ( m_nRowPos >= m_rControl.m_nTopRow ) && impl_isValidRow( m_nRowPos ) )
+ {
+ m_aRect.Top() = m_rControl.m_nColHeaderHeightPixel + ( m_nRowPos - m_rControl.m_nTopRow ) * m_rControl.m_nRowHeightPixel;
+ m_aRect.Bottom() = m_aRect.Top() + m_rControl.m_nRowHeightPixel - 1;
+ }
+ else
+ m_aRect.SetEmpty();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool TableRowGeometry::impl_isValidRow( RowPos const i_row ) const
+ {
+ return m_bAllowVirtualRows || ( i_row < m_rControl.m_pModel->getRowCount() );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool TableRowGeometry::moveDown()
+ {
+ if ( m_nRowPos == ROW_COL_HEADERS )
+ {
+ m_nRowPos = m_rControl.m_nTopRow;
+ impl_initRect();
+ }
+ else
+ {
+ if ( impl_isValidRow( ++m_nRowPos ) )
+ m_aRect.Move( 0, m_rControl.m_nRowHeightPixel );
+ else
+ m_aRect.SetEmpty();
+ }
+ return isValid();
+ }
+
+ //==================================================================================================================
+ //= TableColumnGeometry
+ //==================================================================================================================
+ //------------------------------------------------------------------------------------------------------------------
+ TableColumnGeometry::TableColumnGeometry( TableControl_Impl const & _rControl, Rectangle const & _rBoundaries,
+ ColPos const _nCol, bool const i_allowVirtualColumns )
+ :TableGeometry( _rControl, _rBoundaries )
+ ,m_nColPos( _nCol )
+ ,m_bAllowVirtualColumns( i_allowVirtualColumns )
+ {
+ if ( m_nColPos == COL_ROW_HEADERS )
+ {
+ m_aRect.Left() = 0;
+ m_aRect.Right() = m_rControl.m_nRowHeaderWidthPixel - 1;
+ }
+ else
+ {
+ impl_initRect();
+ }
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ void TableColumnGeometry::impl_initRect()
+ {
+ ColPos nLeftColumn = m_rControl.m_nLeftColumn;
+ if ( ( m_nColPos >= nLeftColumn ) && impl_isValidColumn( m_nColPos ) )
+ {
+ m_aRect.Left() = m_rControl.m_nRowHeaderWidthPixel;
+ // TODO: take into account any possibly frozen columns
+
+ for ( ColPos col = nLeftColumn; col < m_nColPos; ++col )
+ m_aRect.Left() += m_rControl.m_aColumnWidths[ col ].getWidth();
+ m_aRect.Right() = m_aRect.Left() + m_rControl.m_aColumnWidths[ m_nColPos ].getWidth() - 1;
+ }
+ else
+ m_aRect.SetEmpty();
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool TableColumnGeometry::impl_isValidColumn( ColPos const i_column ) const
+ {
+ return m_bAllowVirtualColumns || ( i_column < ColPos( m_rControl.m_aColumnWidths.size() ) );
+ }
+
+ //------------------------------------------------------------------------------------------------------------------
+ bool TableColumnGeometry::moveRight()
+ {
+ if ( m_nColPos == COL_ROW_HEADERS )
+ {
+ m_nColPos = m_rControl.m_nLeftColumn;
+ impl_initRect();
+ }
+ else
+ {
+ if ( impl_isValidColumn( ++m_nColPos ) )
+ {
+ m_aRect.Left() = m_aRect.Right() + 1;
+ m_aRect.Right() += m_rControl.m_aColumnWidths[ m_nColPos ].getWidth();
+ }
+ else
+ m_aRect.SetEmpty();
+ }
+
+ return isValid();
+ }
+
+//......................................................................................................................
+} } // namespace svt::table
+//......................................................................................................................
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svtools/source/table/tablegeometry.hxx b/svtools/source/table/tablegeometry.hxx
new file mode 100644
index 000000000000..9520e4992411
--- /dev/null
+++ b/svtools/source/table/tablegeometry.hxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+************************************************************************/
+
+#ifndef SVTOOLS_TABLEGEOMETRY_HXX
+#define SVTOOLS_TABLEGEOMETRY_HXX
+
+#include "svtools/table/tabletypes.hxx"
+
+#include <tools/gen.hxx>
+
+//........................................................................
+namespace svt { namespace table
+{
+//........................................................................
+
+ class TableControl_Impl;
+
+ //====================================================================
+ //= TableGeometry
+ //====================================================================
+ class TableGeometry
+ {
+ protected:
+ const TableControl_Impl& m_rControl;
+ const Rectangle& m_rBoundaries;
+ Rectangle m_aRect;
+
+ protected:
+ TableGeometry(
+ const TableControl_Impl& _rControl,
+ const Rectangle& _rBoundaries
+ )
+ :m_rControl( _rControl )
+ ,m_rBoundaries( _rBoundaries )
+ ,m_aRect( _rBoundaries )
+ {
+ }
+
+ public:
+ // attribute access
+ const TableControl_Impl& getControl() const { return m_rControl; }
+
+ // status
+ const Rectangle& getRect() const { return m_aRect; }
+ bool isValid() const { return !m_aRect.GetIntersection( m_rBoundaries ).IsEmpty(); }
+ };
+
+ //====================================================================
+ //= TableRowGeometry
+ //====================================================================
+ class TableRowGeometry : public TableGeometry
+ {
+ protected:
+ RowPos m_nRowPos;
+ bool m_bAllowVirtualRows;
+
+ public:
+ TableRowGeometry(
+ TableControl_Impl const & _rControl,
+ Rectangle const & _rBoundaries,
+ RowPos const _nRow,
+ bool const i_allowVirtualRows = false
+ // allow rows >= getRowCount()?
+ );
+
+ // status
+ RowPos getRow() const { return m_nRowPos; }
+ // operations
+ bool moveDown();
+
+ private:
+ void impl_initRect();
+ bool impl_isValidRow( RowPos const i_row ) const;
+ };
+
+ //====================================================================
+ //= TableColumnGeometry
+ //====================================================================
+ class TableColumnGeometry : public TableGeometry
+ {
+ protected:
+ ColPos m_nColPos;
+ bool m_bAllowVirtualColumns;
+
+ public:
+ TableColumnGeometry(
+ TableControl_Impl const & _rControl,
+ Rectangle const & _rBoundaries,
+ ColPos const _nCol,
+ bool const i_allowVirtualColumns = false
+ );
+
+ // status
+ ColPos getCol() const { return m_nColPos; }
+ // operations
+ bool moveRight();
+
+ private:
+ void impl_initRect();
+ bool impl_isValidColumn( ColPos const i_column ) const;
+ };
+
+ //====================================================================
+ //= TableCellGeometry
+ //====================================================================
+ /** a helper representing geometry information of a cell
+ */
+ class TableCellGeometry
+ {
+ private:
+ TableRowGeometry m_aRow;
+ TableColumnGeometry m_aCol;
+
+ public:
+ TableCellGeometry(
+ TableControl_Impl const & _rControl,
+ Rectangle const & _rBoundaries,
+ ColPos const _nCol,
+ RowPos const _nRow,
+ bool const i_alllowVirtualCells = false
+ )
+ :m_aRow( _rControl, _rBoundaries, _nRow, i_alllowVirtualCells )
+ ,m_aCol( _rControl, _rBoundaries, _nCol, i_alllowVirtualCells )
+ {
+ }
+
+ TableCellGeometry(
+ const TableRowGeometry& _rRow,
+ ColPos _nCol
+ )
+ :m_aRow( _rRow )
+ ,m_aCol( _rRow.getControl(), _rRow.getRect(), _nCol )
+ {
+ }
+
+ inline Rectangle getRect() const { return m_aRow.getRect().GetIntersection( m_aCol.getRect() ); }
+ inline RowPos getRow() const { return m_aRow.getRow(); }
+ inline ColPos getColumn() const { return m_aCol.getCol(); }
+ inline bool isValid() const { return !getRect().IsEmpty(); }
+
+ inline bool moveDown() {return m_aRow.moveDown(); }
+ inline bool moveRight() {return m_aCol.moveRight(); }
+ };
+
+//........................................................................
+} } // namespace svt::table
+//........................................................................
+
+#endif // SVTOOLS_TABLEGEOMETRY_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */