summaryrefslogtreecommitdiff
path: root/svtools/source/table
diff options
context:
space:
mode:
Diffstat (limited to 'svtools/source/table')
-rw-r--r--svtools/source/table/defaultinputhandler.cxx210
-rw-r--r--svtools/source/table/gridtablerenderer.cxx234
-rw-r--r--svtools/source/table/makefile.mk59
-rw-r--r--svtools/source/table/tablecontrol.cxx179
-rw-r--r--svtools/source/table/tablecontrol_impl.cxx2003
-rw-r--r--svtools/source/table/tablecontrol_impl.hxx342
-rw-r--r--svtools/source/table/tabledatawindow.cxx81
-rw-r--r--svtools/source/table/tablegeometry.cxx130
-rw-r--r--svtools/source/table/tablegeometry.hxx161
9 files changed, 3399 insertions, 0 deletions
diff --git a/svtools/source/table/defaultinputhandler.cxx b/svtools/source/table/defaultinputhandler.cxx
new file mode 100644
index 000000000000..17ee0222857f
--- /dev/null
+++ b/svtools/source/table/defaultinputhandler.cxx
@@ -0,0 +1,210 @@
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2009 by Sun Microsystems, Inc.
+*
+* 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/abstracttablecontrol.hxx"
+
+#include <tools/debug.hxx>
+#include <vcl/event.hxx>
+#include <vcl/cursor.hxx>
+#include "svtools/table/tabledatawindow.hxx"
+
+//........................................................................
+namespace svt { namespace table
+{
+//.......................................................................
+
+ struct DefaultInputHandler_Impl
+ {
+ };
+
+ //====================================================================
+ //= DefaultInputHandler
+ //====================================================================
+ //--------------------------------------------------------------------
+ DefaultInputHandler::DefaultInputHandler()
+ :m_pImpl( new DefaultInputHandler_Impl )
+ {
+ }
+
+ //--------------------------------------------------------------------
+ DefaultInputHandler::~DefaultInputHandler()
+ {
+ DELETEZ( m_pImpl );
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultInputHandler::MouseMove( IAbstractTableControl& _rControl, const MouseEvent& _rMEvt )
+ {
+ (void)_rControl;
+ (void)_rMEvt;
+ return false;
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultInputHandler::MouseButtonDown( IAbstractTableControl& _rControl, const MouseEvent& _rMEvt )
+ {
+ bool bHandled = false;
+ Point aPoint = _rMEvt.GetPosPixel();
+ if(_rControl.isClickInVisibleArea(aPoint))
+ {
+ if(_rControl.getSelEngine()->GetSelectionMode() == NO_SELECTION)
+ {
+ LoseFocus(_rControl);
+ _rControl.setCursorAtCurrentCell(aPoint);
+ bHandled = true;
+ }
+ else
+ {
+ bHandled = _rControl.getSelEngine()->SelMouseButtonDown(_rMEvt);
+ }
+ }
+ return bHandled;
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultInputHandler::MouseButtonUp( IAbstractTableControl& _rControl, const MouseEvent& _rMEvt )
+ {
+ bool bHandled = false;
+ Point aPoint = _rMEvt.GetPosPixel();
+ if(_rControl.isClickInVisibleArea(aPoint))
+ {
+ if(_rControl.getSelEngine()->GetSelectionMode() == NO_SELECTION)
+ {
+ GetFocus(_rControl);
+ _rControl.setCursorAtCurrentCell(aPoint);
+ bHandled = true;
+ }
+ else
+ bHandled = _rControl.getSelEngine()->SelMouseButtonUp(_rMEvt);
+ }
+ return bHandled;
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultInputHandler::KeyInput( IAbstractTableControl& _rControl, const KeyEvent& rKEvt )
+ {
+ bool bHandled = false;
+
+ const KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ USHORT nKeyCode = rKeyCode.GetCode();
+
+ struct _ActionMapEntry
+ {
+ USHORT nKeyCode;
+ USHORT 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( IAbstractTableControl& _rControl )
+ {
+ _rControl.showCursor();
+ return false; // continue processing
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultInputHandler::LoseFocus( IAbstractTableControl& _rControl )
+ {
+ _rControl.hideCursor();
+ return false; // continue processing
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultInputHandler::RequestHelp( IAbstractTableControl& _rControl, const HelpEvent& _rHEvt )
+ {
+ (void)_rControl;
+ (void)_rHEvt;
+ // TODO
+ return false;
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultInputHandler::Command( IAbstractTableControl& _rControl, const CommandEvent& _rCEvt )
+ {
+ (void)_rControl;
+ (void)_rCEvt;
+ // TODO
+ return false;
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultInputHandler::PreNotify( IAbstractTableControl& _rControl, NotifyEvent& _rNEvt )
+ {
+ (void)_rControl;
+ (void)_rNEvt;
+ // TODO
+ return false;
+ }
+
+ //--------------------------------------------------------------------
+ bool DefaultInputHandler::Notify( IAbstractTableControl& _rControl, NotifyEvent& _rNEvt )
+ {
+ (void)_rControl;
+ (void)_rNEvt;
+ // TODO
+ return false;
+ }
+
+//........................................................................
+} } // namespace svt::table
+//........................................................................
diff --git a/svtools/source/table/gridtablerenderer.cxx b/svtools/source/table/gridtablerenderer.cxx
new file mode 100644
index 000000000000..2c4fda711009
--- /dev/null
+++ b/svtools/source/table/gridtablerenderer.cxx
@@ -0,0 +1,234 @@
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2009 by Sun Microsystems, Inc.
+*
+* 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/gridtablerenderer.hxx"
+
+#include <tools/debug.hxx>
+#include <vcl/window.hxx>
+
+//........................................................................
+namespace svt { namespace table
+{
+//........................................................................
+
+ struct GridTableRenderer_Impl
+ {
+ ITableModel& rModel;
+ RowPos nCurrentRow;
+
+ GridTableRenderer_Impl( ITableModel& _rModel )
+ :rModel( _rModel )
+ ,nCurrentRow( ROW_INVALID )
+ {
+ }
+ };
+
+ //====================================================================
+ //= GridTableRenderer
+ //====================================================================
+ //--------------------------------------------------------------------
+ GridTableRenderer::GridTableRenderer( ITableModel& _rModel )
+ :m_pImpl( new GridTableRenderer_Impl( _rModel ) )
+ {
+ }
+
+ //--------------------------------------------------------------------
+ GridTableRenderer::~GridTableRenderer()
+ {
+ DELETEZ( m_pImpl );
+ }
+
+ //--------------------------------------------------------------------
+ RowPos GridTableRenderer::getCurrentRow()
+ {
+ return m_pImpl->nCurrentRow;
+ }
+
+ //--------------------------------------------------------------------
+ void GridTableRenderer::PaintHeaderArea(
+ OutputDevice& _rDevice, const Rectangle& _rArea, bool _bIsColHeaderArea, bool _bIsRowHeaderArea,
+ const StyleSettings& _rStyle )
+ {
+ OSL_PRECOND( _bIsColHeaderArea || _bIsRowHeaderArea,
+ "GridTableRenderer::PaintHeaderArea: invalid area flags!" );
+
+ // fill the rows with alternating background colors
+ _rDevice.Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
+
+ _rDevice.SetLineColor();
+ _rDevice.SetFillColor( _rStyle.GetDialogColor() );
+ _rDevice.DrawRect( _rArea );
+
+ // delimiter lines at bottom/right
+ _rDevice.SetLineColor( _rStyle.GetDialogTextColor() );
+ _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 );
+
+ _rDevice.SetLineColor( _rStyle.GetDialogTextColor() );
+ _rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight() );
+
+ String sHeaderText;
+
+ PColumnModel pColumn = m_pImpl->rModel.getColumnModel( _nCol );
+ DBG_ASSERT( !!pColumn, "GridTableRenderer::PaintColumnHeader: invalid column model object!" );
+ if ( !!pColumn )
+ sHeaderText = pColumn->getName();
+ Color aRowBackground = _rStyle.GetFieldColor();
+ if ( _bSelected )
+ {
+ aRowBackground = COL_BLUE;
+ }
+ _rDevice.DrawText( _rArea, sHeaderText, TEXT_DRAW_LEFT | TEXT_DRAW_TOP );
+ _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
+ _rDevice.Pop();
+
+ (void)_bActive;
+ // no special painting for the active column at the moment
+
+ //(void)_bSelected;
+ // TODO: selection 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;
+
+ // fill the rows with alternating background colors
+ _rDevice.Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
+
+ _rDevice.SetLineColor();
+
+ Color aRowBackground = _rStyle.GetFieldColor();
+
+ _rDevice.SetFillColor( aRowBackground );
+
+ _rDevice.DrawRect( _rRowArea );
+
+ // TODO: active? selected?
+
+ _rDevice.Pop();
+ (void) _bSelected;
+ (void)_bActive;
+
+ // no special painting for the active row at the moment
+
+ //(void)_bSelected;
+ // TODO: selection not yet implemented
+ }
+
+ //--------------------------------------------------------------------
+ void GridTableRenderer::PaintRowHeader( bool _bActive, bool _bSelected, OutputDevice& _rDevice, const Rectangle& _rArea,
+ const StyleSettings& _rStyle, rtl::OUString& _rText )
+ {
+ _rDevice.Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
+
+ _rDevice.SetLineColor( _rStyle.GetDialogTextColor() );
+ _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
+ _rDevice.DrawText( _rArea, _rText, TEXT_DRAW_LEFT);
+ // TODO: active? selected?
+ (void)_bActive;
+ (void)_bSelected;
+
+ _rDevice.Pop();
+ }
+
+ //--------------------------------------------------------------------
+ void GridTableRenderer::PaintCell( ColPos _nColumn, bool _bSelected, bool _bActive,
+ OutputDevice& _rDevice, const Rectangle& _rArea, const StyleSettings& _rStyle, rtl::OUString& _rText )
+ {
+ _rDevice.Push( PUSH_LINECOLOR );
+
+ // draw the grid
+ _rDevice.SetLineColor( COL_LIGHTGRAY );
+ // TODO: the LIGHTGRAY should probably be a property/setting
+ _rDevice.DrawLine( _rArea.BottomRight(), _rArea.TopRight() );
+ _rDevice.DrawLine( _rArea.BottomLeft(), _rArea.BottomRight() );
+
+ {
+ // TODO: remove those temporary place holders
+ Rectangle aRect( _rArea );
+ ++aRect.Left(); --aRect.Right();
+ ++aRect.Top(); --aRect.Bottom();
+
+ String sText;
+ if(_bSelected)
+ {
+ Color aRed(COL_BLUE);
+ _rDevice.SetFillColor( aRed );
+ _rDevice.SetTextColor(COL_WHITE);
+ }
+ _rDevice.DrawRect( _rArea );
+ (void)_nColumn;
+ _rDevice.DrawText( aRect, _rText, TEXT_DRAW_LEFT | TEXT_DRAW_TOP);
+ }
+ if(_bSelected)
+ {
+ _rDevice.SetFillColor( _rStyle.GetFieldColor() );
+ _rDevice.SetTextColor(COL_BLACK);
+ }
+
+ _rDevice.Pop();
+
+ (void)_bActive;
+// // no special painting for the active cell at the moment
+ (void)_rStyle;
+// // TODO: do we need this?
+ }
+
+ //--------------------------------------------------------------------
+ void GridTableRenderer::ShowCellCursor( Window& _rView, const Rectangle& _rCursorRect)
+ {
+ _rView.ShowFocus( _rCursorRect );
+ }
+
+ //--------------------------------------------------------------------
+ void GridTableRenderer::HideCellCursor( Window& _rView, const Rectangle& _rCursorRect)
+ {
+ (void)_rCursorRect;
+ _rView.HideFocus();
+
+ }
+
+//........................................................................
+} } // namespace svt::table
+//........................................................................
+
diff --git a/svtools/source/table/makefile.mk b/svtools/source/table/makefile.mk
new file mode 100644
index 000000000000..8feb7fee10d8
--- /dev/null
+++ b/svtools/source/table/makefile.mk
@@ -0,0 +1,59 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.16 $
+#
+# 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.
+#
+#*************************************************************************
+
+PRJ=..$/..
+
+ENABLE_EXCEPTIONS=TRUE
+PRJNAME=svtools
+TARGET=table
+#LIBTARGET=NO
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+.INCLUDE : $(PRJ)$/util$/svt.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES=\
+ $(SLO)$/tablecontrol.obj \
+ $(SLO)$/tablecontrol_impl.obj \
+ $(SLO)$/gridtablerenderer.obj \
+ $(SLO)$/tablegeometry.obj \
+ $(SLO)$/defaultinputhandler.obj \
+ $(SLO)$/tabledatawindow.obj
+
+#LIB1TARGET= $(SLB)$/$(TARGET).lib
+#LIB1OBJFILES= $(SLOFILES)
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/svtools/source/table/tablecontrol.cxx b/svtools/source/table/tablecontrol.cxx
new file mode 100644
index 000000000000..c8895a19408d
--- /dev/null
+++ b/svtools/source/table/tablecontrol.cxx
@@ -0,0 +1,179 @@
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2009 by Sun Microsystems, Inc.
+*
+* 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 "svtools/table/tabledatawindow.hxx"
+//........................................................................
+namespace svt { namespace table
+{
+//........................................................................
+
+ //====================================================================
+ //= TableControl
+ //====================================================================
+ //--------------------------------------------------------------------
+ TableControl::TableControl( Window* _pParent, WinBits _nStyle )
+ :Control( _pParent, _nStyle )
+ ,m_pImpl( new TableControl_Impl( *this ) )
+ {
+ m_pImpl->getDataWindow()->SetMouseButtonDownHdl( LINK( this, TableControl, ImplMouseButtonDownHdl ) );
+ m_pImpl->getDataWindow()->SetMouseButtonUpHdl( LINK( this, TableControl, ImplMouseButtonUpHdl ) );
+ }
+
+ //--------------------------------------------------------------------
+ TableControl::~TableControl()
+ {
+ DELETEZ( m_pImpl );
+ }
+
+ //--------------------------------------------------------------------
+ void TableControl::GetFocus()
+ {
+ if ( !m_pImpl->getInputHandler()->GetFocus( *m_pImpl ) )
+ {
+ Control::GetFocus();
+ GrabFocus();
+ }
+ }
+
+ //--------------------------------------------------------------------
+ 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::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 )
+ {
+ // TODO
+ (void)_nRow;
+ }
+
+ //--------------------------------------------------------------------
+ RowPos TableControl::GetCurrentRow() const
+ {
+ return m_pImpl->getCurRow();
+ }
+
+ //--------------------------------------------------------------------
+ ColPos TableControl::GetCurrentColumn() const
+ {
+ return m_pImpl->getCurColumn();
+ }
+
+ //--------------------------------------------------------------------
+ bool TableControl::GoTo( ColPos _nColumn, RowPos _nRow )
+ {
+ return m_pImpl->goTo( _nColumn, _nRow );
+ }
+ //--------------------------------------------------------------------
+ void TableControl::InvalidateDataWindow(RowPos _nRowStart, bool _bRemoved)
+ {
+ Rectangle _rRect;
+ if(_bRemoved)
+ return m_pImpl->invalidateRows(_nRowStart, _rRect);
+ else
+ return m_pImpl->invalidateRow(_nRowStart, _rRect);
+ }
+ //--------------------------------------------------------------------
+ std::vector<RowPos> TableControl::getSelectedRows()
+ {
+ return m_pImpl->getSelectedRows();
+ }
+ //--------------------------------------------------------------------
+ void TableControl::removeSelectedRow(RowPos _nRowPos)
+ {
+ m_pImpl->removeSelectedRow(_nRowPos);
+ }
+ //--------------------------------------------------------------------
+
+ RowPos TableControl::GetCurrentRow(const Point& rPoint)
+ {
+ return m_pImpl->getCurrentRow( rPoint );
+ }
+
+ //--------------------------------------------------------------------
+
+ 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;
+ }
+
+ SelectionEngine* TableControl::getSelEngine()
+ {
+ return m_pImpl->getSelEngine();
+ }
+
+ TableDataWindow* TableControl::getDataWindow()
+ {
+ return m_pImpl->getDataWindow();
+ }
+//........................................................................
+} } // namespace svt::table
+//........................................................................
diff --git a/svtools/source/table/tablecontrol_impl.cxx b/svtools/source/table/tablecontrol_impl.cxx
new file mode 100644
index 000000000000..e1ff3aeb7f2a
--- /dev/null
+++ b/svtools/source/table/tablecontrol_impl.cxx
@@ -0,0 +1,2003 @@
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2009 by Sun Microsystems, Inc.
+*
+* 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 "tablecontrol_impl.hxx"
+#include "tablegeometry.hxx"
+#include "svtools/table/tabledatawindow.hxx"
+
+#include <vcl/scrbar.hxx>
+#include <vcl/seleng.hxx>
+
+#include <functional>
+#include <stdlib.h>
+
+//........................................................................
+namespace svt { namespace table
+{
+//........................................................................
+
+ //====================================================================
+ //= TempHideCursor
+ //====================================================================
+ class TempHideCursor
+ {
+ private:
+ IAbstractTableControl& m_rTable;
+
+ public:
+ TempHideCursor( IAbstractTableControl& _rTable )
+ :m_rTable( _rTable )
+ {
+ m_rTable.hideCursor();
+ }
+ ~TempHideCursor()
+ {
+ 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 void setRowHeaders(bool _bRowHeaders)
+ {
+ (void)_bRowHeaders;
+ }
+ virtual void setColumnHeaders(bool _bColumnHeaders)
+ {
+ (void)_bColumnHeaders;
+ }
+ void setColumnCount(TableSize _nColCount)
+ {
+ (void) _nColCount;
+ }
+ void setRowCount(TableSize _nRowCount)
+ {
+ (void)_nRowCount;
+ }
+ virtual bool isCellEditable( ColPos col, RowPos row ) const
+ {
+ (void)col;
+ (void)row;
+ return false;
+ }
+ virtual void addTableModelListener( const PTableModelListener& listener )
+ {
+ (void)listener;
+ // ignore
+ }
+ virtual void removeTableModelListener( const PTableModelListener& listener )
+ {
+ (void)listener;
+ // ignore
+ }
+ virtual PColumnModel getColumnModel( ColPos column )
+ {
+ DBG_ERROR( "EmptyTableModel::getColumnModel: invalid call!" );
+ (void)column;
+ return PColumnModel();
+ }
+ virtual PColumnModel getColumnModelByID( ColumnID id )
+ {
+ DBG_ERROR( "EmptyTableModel::getColumnModel: invalid call!" );
+ (void)id;
+ 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(int overAllHeight, int actHeight) const
+ {
+ (void)overAllHeight;
+ (void)actHeight;
+ return ScrollbarShowNever;
+ }
+ virtual ScrollbarVisibility getHorizontalScrollbarVisibility(int overAllWidth, int actWidth) const
+ {
+ (void)overAllWidth;
+ (void)actWidth;
+ return ScrollbarShowNever;
+ }
+ virtual void setCellContent(std::vector<std::vector<rtl::OUString> > pCellEntryType)
+ {
+ (void)pCellEntryType;
+ }
+ virtual std::vector<std::vector<rtl::OUString> > getCellContent()
+ {
+ std::vector<rtl::OUString> cCC;
+ cCC.push_back(rtl::OUString::createFromAscii(""));
+ std::vector<std::vector<rtl::OUString> > cC;
+ cC.push_back(cCC);
+ return cC;
+ }
+ virtual void setRowHeaderName(std::vector<rtl::OUString> pCellEntryType)
+ {
+ (void)pCellEntryType;
+ }
+ virtual std::vector<rtl::OUString> getRowHeaderName()
+ {
+ std::vector<rtl::OUString> cCC;
+ cCC.push_back(rtl::OUString::createFromAscii(""));
+ return cCC;
+ }
+ };
+
+
+ //====================================================================
+ //= 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_aColumnWidthsPixel.empty() && ( m_nCurColumn < 0 ) || ( m_nCurColumn >= (ColPos)m_aColumnWidthsPixel.size() ) )
+ return "current column is invalid!";
+
+ if ( m_aColumnWidthsPixel.size() != m_aAccColumnWidthsPixel.size() )
+ return "columnd width caches are inconsistent!";
+
+ 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_nColHeaderHeightPixel consistent with the model's value?
+ {
+ TableMetrics nHeaderHeight = m_pModel->hasColumnHeaders() ? m_pModel->getColumnHeaderHeight() : 0;
+ nHeaderHeight = m_rAntiImpl.LogicToPixel( Size( 0, nHeaderHeight ), MAP_100TH_MM ).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_100TH_MM ).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_100TH_MM ).Width();
+ if ( nHeaderWidth != m_nRowHeaderWidthPixel )
+ return "row header widths are inconsistent!";
+ }
+
+ // TODO: check m_aColumnWidthsPixel and m_aAccColumnWidthsPixel
+
+ 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_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_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_nRowSelected ( )
+ ,m_pTableFunctionSet ( new TableFunctionSet(this ) )
+ ,m_nAnchor (-1 )
+#if DBG_UTIL
+ ,m_nRequiredInvariants ( INV_SCROLL_POSITION )
+#endif
+ {
+ DBG_CTOR( TableControl_Impl, TableControl_Impl_checkInvariants );
+ m_pSelEngine = new SelectionEngine(m_pDataWindow, 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 );
+ DELETEZ( m_pDataWindow );
+ }
+
+ //--------------------------------------------------------------------
+ PTableModel TableControl_Impl::getModel() const
+ {
+ if ( dynamic_cast< const EmptyTableModel* >( m_pModel.get() ) != NULL )
+ // if it's an EmptyTableModel, pretend that there is no model
+ return PTableModel();
+
+ return m_pModel;
+ }
+
+ //--------------------------------------------------------------------
+ void TableControl_Impl::setModel( PTableModel _pModel )
+ {
+ DBG_CHECK_ME();
+
+ TempHideCursor aHideCursor( *this );
+
+ // TODO: revoke as table listener from the model
+
+ m_pModel = _pModel;
+ if ( !m_pModel )
+ m_pModel.reset( new EmptyTableModel );
+
+ // TODO: register as table listener
+ //m_pModel->addTableModelListener(PTableModelListener(m_pTableModelListener));
+ m_nCurRow = ROW_INVALID;
+ m_nCurColumn = COL_INVALID;
+
+ // recalc some model-dependent cached info
+ impl_ni_updateCachedModelValues();
+
+ // completely invalidate
+ m_rAntiImpl.Invalidate();
+
+ // reset cursor to (0,0)
+ if ( m_nRowCount ) m_nCurRow = 0;
+ if ( m_nColumnCount ) m_nCurColumn = 0;
+ }
+
+ //--------------------------------------------------------------------
+ void TableControl_Impl::impl_getAllVisibleCellsArea( Rectangle& _rCellArea ) const
+ {
+ DBG_CHECK_ME();
+
+ _rCellArea.Left() = 0;
+ _rCellArea.Top() = 0;
+
+ // determine the right-most border of the last column which is
+ // at least partially visible
+ _rCellArea.Right() = m_nRowHeaderWidthPixel;
+ if ( !m_aAccColumnWidthsPixel.empty() )
+ {
+ // the number of pixels which are scroll out of the left hand
+ // side of the window
+ long nScrolledOutLeft = m_nLeftColumn == 0 ? 0 : m_aAccColumnWidthsPixel[ m_nLeftColumn - 1 ];
+
+ ArrayOfLong::const_reverse_iterator loop = m_aAccColumnWidthsPixel.rbegin();
+ do
+ {
+ _rCellArea.Right() = *loop++ - nScrolledOutLeft + m_nRowHeaderWidthPixel;
+ }
+ while ( ( loop != m_aAccColumnWidthsPixel.rend() )
+ && ( *loop - nScrolledOutLeft >= _rCellArea.Right() )
+ );
+ }
+ // so far, _rCellArea.Right() denotes the first pixel *after* the cell area
+ --_rCellArea.Right();
+
+ // determine the last row which is at least partially visible
+ _rCellArea.Bottom() =
+ m_nColHeaderHeightPixel
+ + impl_getVisibleRows( true ) * m_nRowHeightPixel
+ - 1;
+ }
+
+ //--------------------------------------------------------------------
+ void TableControl_Impl::impl_getAllVisibleDataCellArea( Rectangle& _rCellArea ) const
+ {
+ DBG_CHECK_ME();
+
+ impl_getAllVisibleCellsArea( _rCellArea );
+ _rCellArea.Left() = m_nRowHeaderWidthPixel;
+ _rCellArea.Top() = m_nColHeaderHeightPixel;
+ }
+
+ //--------------------------------------------------------------------
+ void TableControl_Impl::impl_ni_updateCachedModelValues()
+ {
+ m_nRowHeightPixel = 15;
+ m_nColHeaderHeightPixel = 0;
+ m_nRowHeaderWidthPixel = 0;
+ m_pInputHandler.reset();
+ m_nColumnCount = m_nRowCount = 0;
+
+ m_nRowHeightPixel = m_rAntiImpl.LogicToPixel( Size( 0, m_pModel->getRowHeight() ), MAP_100TH_MM ).Height();
+ if ( m_pModel->hasColumnHeaders() )
+ m_nColHeaderHeightPixel = m_rAntiImpl.LogicToPixel( Size( 0, m_pModel->getColumnHeaderHeight() ), MAP_100TH_MM ).Height();
+ if ( m_pModel->hasRowHeaders() )
+ m_nRowHeaderWidthPixel = m_rAntiImpl.LogicToPixel( Size( m_pModel->getRowHeaderWidth(), 0 ), MAP_100TH_MM ).Width();
+
+ 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()
+ {
+ m_aColumnWidthsPixel.resize( 0 );
+ m_aAccColumnWidthsPixel.resize( 0 );
+ if ( !m_pModel )
+ return;
+
+ TableSize colCount = m_pModel->getColumnCount();
+ m_aColumnWidthsPixel.reserve( colCount );
+ m_aAccColumnWidthsPixel.reserve( colCount );
+ long accumulatedPixelWidth = 0;
+ for ( ColPos col = 0; col < colCount; ++col )
+ {
+ PColumnModel pColumn = m_pModel->getColumnModel( col );
+ DBG_ASSERT( !!pColumn, "TableControl_Impl::impl_ni_updateColumnWidths: invalid column returned by the model!" );
+ if ( !pColumn )
+ continue;
+
+ TableMetrics colWidth = pColumn->getWidth();
+ DBG_ASSERT( ( colWidth == COLWIDTH_FIT_TO_VIEW ) || ( colWidth > 0 ),
+ "TableControl_Impl::impl_ni_updateColumnWidths: invalid column width!" );
+
+ long pixelWidth = 0;
+ if ( colWidth == COLWIDTH_FIT_TO_VIEW )
+ {
+ // TODO
+ DBG_ERROR( "TableControl_Impl::impl_ni_updateColumnWidths: COLWIDTH_FIT_TO_VIEW not implemented, yet!" );
+ }
+ else
+ {
+ pixelWidth = m_rAntiImpl.LogicToPixel( Size( colWidth, 0 ), MAP_100TH_MM ).Width();
+ }
+
+ m_aColumnWidthsPixel.push_back( pixelWidth );
+
+ m_aAccColumnWidthsPixel.push_back( accumulatedPixelWidth += pixelWidth );
+ }
+ }
+
+ //--------------------------------------------------------------------
+ namespace
+ {
+ //................................................................
+ /// determines whether a scrollbar is needed for the given values
+ bool lcl_determineScrollbarNeed( ScrollbarVisibility _eVisibility,
+ long _nVisibleUnits, long _nRange )
+ {
+ if ( _eVisibility == ScrollbarShowNever )
+ return false;
+ if ( _eVisibility == ScrollbarShowAlways )
+ return true;
+ return _nVisibleUnits > _nRange;
+ }
+
+ //................................................................
+ void lcl_setButtonRepeat( Window& _rWindow, ULONG _nDelay )
+ {
+ AllSettings aSettings = _rWindow.GetSettings();
+ MouseSettings aMouseSettings = aSettings.GetMouseSettings();
+
+ aMouseSettings.SetButtonRepeat( _nDelay );
+ aSettings.SetMouseSettings( aMouseSettings );
+
+ _rWindow.SetSettings( aSettings, TRUE );
+ }
+
+ //................................................................
+ void lcl_updateScrollbar( Window& _rParent, ScrollBar*& _rpBar,
+ ScrollbarVisibility _eVisibility, long _nVisibleUnits,
+ long _nPosition, long _nLineSize, long _nRange,
+ bool _bHorizontal, const Link& _rScrollHandler )
+ {
+ // do we need the scrollbar?
+ bool bNeedBar = lcl_determineScrollbarNeed( _eVisibility, _nVisibleUnits, _nRange );
+
+ // do we currently have the scrollbar?
+ bool bHaveBar = _rpBar != NULL;
+
+ // do we need to correct the scrollbar visibility?
+ if ( bHaveBar && !bNeedBar )
+ {
+ DELETEZ( _rpBar );
+ }
+ else if ( !bHaveBar && bNeedBar )
+ {
+ _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()
+ {
+ TempHideCursor aHideCursor( *this );
+
+ // the width/height of a scrollbar, needed several times below
+ long nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize();
+ if ( m_rAntiImpl.IsZoom() )
+ nScrollbarMetrics = (long)( nScrollbarMetrics * (double)m_rAntiImpl.GetZoom() );
+
+ // 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;
+
+ // do we need a vertical scrollbar?
+ bool bFirstRoundVScrollNeed = false;
+ if ( lcl_determineScrollbarNeed(
+ m_pModel->getVerticalScrollbarVisibility(aDataCellPlayground.GetHeight(), m_nRowHeightPixel*m_nRowCount),
+ lcl_getRowsFittingInto( aDataCellPlayground.GetHeight(), m_nRowHeightPixel ),
+ m_nRowCount ) )
+ {
+ aDataCellPlayground.Right() -= nScrollbarMetrics;
+ bFirstRoundVScrollNeed = true;
+ }
+ // do we need a horizontal scrollbar?
+ if ( lcl_determineScrollbarNeed(
+ m_pModel->getHorizontalScrollbarVisibility(aDataCellPlayground.GetWidth(), m_aAccColumnWidthsPixel[m_nColumnCount-1]),
+ lcl_getColumnsVisibleWithin( aDataCellPlayground, m_nLeftColumn, *this, false ),
+ m_nColumnCount ) )
+ {
+ 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 && lcl_determineScrollbarNeed(
+ m_pModel->getVerticalScrollbarVisibility(aDataCellPlayground.GetHeight(),m_nRowHeightPixel*m_nRowCount),
+ lcl_getRowsFittingInto( aDataCellPlayground.GetHeight(), m_nRowHeightPixel ),
+ m_nRowCount ) )
+ {
+ aDataCellPlayground.Right() -= nScrollbarMetrics;
+ }
+ }
+ else
+ {
+ Size regionWithoutHeader = m_rAntiImpl.PixelToLogic(Size(aDataCellPlayground.Right() - aDataCellPlayground.Left(),0),MAP_100TH_MM);
+ TableMetrics nColWidth = regionWithoutHeader.Width()/m_nColumnCount;
+ for ( ColPos col = 0; col < m_nColumnCount; ++col )
+ m_pModel->getColumnModel(col)->setWidth(nColWidth);
+ m_rAntiImpl.SetModel(m_pModel);
+ }
+
+ // create or destroy the vertical scrollbar, as needed
+ lcl_updateScrollbar(
+ m_rAntiImpl,
+ m_pVScroll,
+ m_pModel->getVerticalScrollbarVisibility(aDataCellPlayground.GetHeight(),m_nRowHeightPixel*m_nRowCount),
+ 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,
+ m_pModel->getHorizontalScrollbarVisibility(aDataCellPlayground.GetWidth(), m_aAccColumnWidthsPixel[m_nColumnCount-1]),
+ 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 )
+ {
+ 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();
+ }
+
+ // 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_updateScrollbars();
+ //Rectangle aAllCells;
+ // impl_getAllVisibleCellsArea( aAllCells );
+ //m_pSelEngine->SetVisibleArea(aAllCells);
+ }
+
+ //--------------------------------------------------------------------
+ void TableControl_Impl::doPaintContent( const Rectangle& _rUpdateRect )
+ {
+ DBG_CHECK_ME();
+
+ if ( !getModel() )
+ return;
+
+ PTableRenderer pRenderer = getModel()->getRenderer();
+ DBG_ASSERT( !!pRenderer, "TableDataWindow::Paint: invalid renderer!" );
+ if ( !pRenderer )
+ return;
+
+ // our current style settings, to be passed to the renderer
+ const StyleSettings& rStyle = m_rAntiImpl.GetSettings().GetStyleSettings();
+
+ // the area occupied by all (at least partially) visible cells, including
+ // headers
+ Rectangle aAllCellsWithHeaders;
+ impl_getAllVisibleCellsArea( aAllCellsWithHeaders );
+
+ m_nRowCount = m_pModel->getRowCount();
+ // ............................
+ // draw the header column area
+ if ( getModel()->hasColumnHeaders() )
+ {
+ TableRowGeometry aHeaderRow( *this, Rectangle( Point( 0, 0 ),
+ aAllCellsWithHeaders.BottomRight() ), ROW_COL_HEADERS );
+ pRenderer->PaintHeaderArea(
+ *m_pDataWindow, aHeaderRow.getRect(), 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() == getCurColumn() );
+ 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 ( getModel()->hasRowHeaders() )
+ {
+ aRowHeaderArea = aAllCellsWithHeaders;
+ aRowHeaderArea.Right() = m_nRowHeaderWidthPixel - 1;
+ aRowHeaderArea.Bottom() = m_nRowHeightPixel * m_nRowCount + m_nColHeaderHeightPixel - 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 ( getModel()->hasColumnHeaders() )
+ {
+ TableCellGeometry aIntersection( *this, Rectangle( Point( 0, 0 ),
+ aAllCellsWithHeaders.BottomRight() ), COL_ROW_HEADERS, ROW_COL_HEADERS );
+ pRenderer->PaintHeaderArea(
+ *m_pDataWindow, aIntersection.getRect(), true, true, rStyle
+ );
+ }
+ }
+
+ // ............................
+ // draw the table content row by row
+
+ TableSize colCount = getModel()->getColumnCount();
+
+ // paint all rows
+ Rectangle aAllDataCellsArea;
+ impl_getAllVisibleDataCellArea( aAllDataCellsArea );
+
+ //get the vector, which contains row vectors, each containing the data for the cells in this row
+ std::vector<std::vector<rtl::OUString> > aCellContent = m_pModel->getCellContent();
+ //if the vector is empty, fill it with empty data, so the table can be painted
+ if(aCellContent.empty())
+ {
+ std::vector<rtl::OUString> emptyCells;
+ while(m_nRowCount!=0)
+ {
+ aCellContent.push_back(emptyCells);
+ --m_nRowCount;
+ }
+ }
+ std::vector<std::vector<rtl::OUString> >::iterator it = aCellContent.begin()+m_nTopRow;
+ //get the vector, which contains the row header titles
+ std::vector<rtl::OUString> aRowHeaderContent;
+ ::std::vector<rtl::OUString>::iterator itRowName = aRowHeaderContent.begin();
+
+ if(m_pModel->hasRowHeaders())
+ {
+ aRowHeaderContent = m_pModel->getRowHeaderName();
+ //if the vector is empty, fill it with empty strings, so the table can be painted
+ if(aRowHeaderContent.empty())
+ {
+ while(m_nRowCount!=0)
+ {
+ aRowHeaderContent.push_back(rtl::OUString::createFromAscii(""));
+ --m_nRowCount;
+ }
+ }
+ itRowName = aRowHeaderContent.begin()+m_nTopRow;
+ }
+ for ( TableRowGeometry aRowIterator( *this, aAllCellsWithHeaders, getTopRow() );
+ aRowIterator.isValid();
+ aRowIterator.moveDown() )
+ {
+ if ( _rUpdateRect.GetIntersection( aRowIterator.getRect() ).IsEmpty() )
+ {
+ if(m_pModel->hasRowHeaders())
+ ++itRowName;
+ ++it;
+ continue;
+ }
+ bool isActiveRow = ( aRowIterator.getRow() == getCurRow() );
+ bool isSelectedRow = false;
+ if(!m_nRowSelected.empty())
+ {
+ for(std::vector<RowPos>::iterator itSel=m_nRowSelected.begin();
+ itSel!=m_nRowSelected.end();++itSel)
+ {
+ if(*itSel == aRowIterator.getRow())
+ isSelectedRow = true;
+ }
+ }
+ std::vector<rtl::OUString> aCellData;
+ if(it != aCellContent.end())
+ {
+ aCellData = *it;
+ ++it;
+ }
+ ::std::vector<rtl::OUString>::iterator iter = aCellData.begin()+m_nLeftColumn;
+
+ // give the redenderer a chance to prepare the row
+ pRenderer->PrepareRow( aRowIterator.getRow(), isActiveRow, isSelectedRow,
+ *m_pDataWindow, aRowIterator.getRect().GetIntersection( aAllDataCellsArea ), rStyle );
+
+ // paint the row header
+ if ( m_pModel->hasRowHeaders() )
+ {
+ rtl::OUString rowHeaderName;
+ if(itRowName != aRowHeaderContent.end())
+ {
+ rowHeaderName = *itRowName;
+ ++itRowName;
+ }
+ Rectangle aCurrentRowHeader( aRowHeaderArea.GetIntersection( aRowIterator.getRect() ) );
+ pRenderer->PaintRowHeader( isActiveRow, isSelectedRow, *m_pDataWindow, aCurrentRowHeader,
+ rStyle, rowHeaderName );
+ }
+ if ( !colCount )
+ continue;
+
+ // paint all cells in this row
+ for ( TableCellGeometry aCell( aRowIterator, m_nLeftColumn );
+ aCell.isValid();
+ aCell.moveRight()
+ )
+ {
+ // if ( _rUpdateRect.GetIntersection( aCell.getRect() ).IsEmpty() )
+ // continue;
+
+ //bool isActiveCell = isActiveRow && ( aCell.getColumn() == getCurColumn() );
+ bool isSelectedColumn = false;
+ rtl::OUString cellData;
+ if(aCellData.empty())
+ cellData=rtl::OUString::createFromAscii("");
+ else if(iter != aCellData.end())
+ {
+ cellData = *iter;
+ ++iter;
+ }
+ pRenderer->PaintCell( aCell.getColumn(), isSelectedRow || isSelectedColumn, isActiveRow,
+ *m_pDataWindow, aCell.getRect(), rStyle, cellData );
+ }
+ }
+ }
+
+ //--------------------------------------------------------------------
+ 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;
+ Rectangle rCells;
+ switch ( _eAction )
+ {
+ case cursorDown:
+ if(m_pSelEngine->GetSelectionMode() == SINGLE_SELECTION)
+ {
+ //if other rows already selected, deselect them
+ if(m_nRowSelected.size()>0)
+ {
+ for(std::vector<RowPos>::iterator it=m_nRowSelected.begin();
+ it!=m_nRowSelected.end();++it)
+ {
+ invalidateSelectedRow(*it,rCells);
+ m_pDataWindow->Invalidate(rCells);
+ }
+ m_nRowSelected.clear();
+ }
+ if(m_nCurRow < m_nRowCount-1)
+ {
+ ++m_nCurRow;
+ m_nRowSelected.push_back(m_nCurRow);
+ }
+ else
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(m_nCurRow, rCells);
+ ensureVisible(m_nCurColumn,m_nCurRow,false);
+ 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_nRowSelected.size()>0)
+ {
+ for(std::vector<RowPos>::iterator it=m_nRowSelected.begin();
+ it!=m_nRowSelected.end();++it)
+ {
+ invalidateSelectedRow(*it,rCells);
+ m_pDataWindow->Invalidate(rCells);
+ }
+ m_nRowSelected.clear();
+ }
+ if(m_nCurRow>0)
+ {
+ --m_nCurRow;
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(m_nCurRow, rCells);
+ }
+ else
+ {
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(m_nCurRow, rCells);
+ }
+ ensureVisible(m_nCurColumn,m_nCurRow,false);
+ 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_nRowSelected, m_nCurRow);
+ //if current row is selected, it should be deselected, when ALT+SPACE are pressed
+ if(pos>-1)
+ m_nRowSelected.erase(m_nRowSelected.begin()+pos);
+ //else select the row->put it in the vector
+ else
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(m_nCurRow, rCells);
+ 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_nRowSelected.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_nRowSelected.begin();
+ it!=m_nRowSelected.end();++it)
+ {
+ invalidateSelectedRow(*it,rCells);
+ m_pDataWindow->Invalidate(rCells);
+ }
+ m_nRowSelected.clear();
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(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_nRowSelected, m_nCurRow);
+ int nextRow = getRowSelectedNumber(m_nRowSelected, 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(m_nRowSelected[nextRow] == m_nCurRow)
+ {
+ m_nRowSelected.erase(m_nRowSelected.begin()+prevRow);
+ invalidateSelectedRow(m_nCurRow+1, rCells);
+ }
+ else
+ {
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(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_nRowSelected.push_back(m_nCurRow);
+ m_nCurRow--;
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow+1, m_nCurRow, rCells);
+ }
+ else
+ {
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(m_nCurRow, rCells);
+ }
+ }
+ m_pSelEngine->SetAnchor(TRUE);
+ m_nAnchor = m_nCurRow;
+ ensureVisible(m_nCurColumn, m_nCurRow, false);
+ 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_nRowSelected.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_nRowSelected.begin();
+ it!=m_nRowSelected.end();++it)
+ {
+ invalidateSelectedRow(*it,rCells);
+ m_pDataWindow->Invalidate(rCells);
+ }
+ m_nRowSelected.clear();
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(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_nRowSelected, m_nCurRow);
+ int nextRow = getRowSelectedNumber(m_nRowSelected, m_nCurRow+1);
+ if(prevRow>-1)
+ {
+ //if m_nCurRow isn't the last one, can move down, otherwise not
+ if(m_nCurRow<m_nRowCount)
+ m_nCurRow++;
+ else
+ return bSuccess = true;
+ //if net row already selected, deselect it, otherwise select it
+ if(m_nRowSelected[nextRow] == m_nCurRow)
+ {
+ m_nRowSelected.erase(m_nRowSelected.begin()+prevRow);
+ invalidateSelectedRow(m_nCurRow-1, rCells);
+ }
+ else
+ {
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(m_nCurRow, rCells);
+ }
+ }
+ }
+ }
+ else
+ {
+ //there wasn't any selection, select curennt and row beneath, otherwise onlyrow beneath
+ if(m_nCurRow<m_nRowCount-1)
+ {
+ m_nRowSelected.push_back(m_nCurRow);
+ m_nCurRow++;
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRegion(m_nCurRow-1, m_nCurRow, rCells);
+ }
+ else
+ {
+ m_nRowSelected.push_back(m_nCurRow);
+ invalidateSelectedRow(m_nCurRow, rCells);
+ }
+ }
+ m_pSelEngine->SetAnchor(TRUE);
+ m_nAnchor = m_nCurRow;
+ ensureVisible(m_nCurColumn, m_nCurRow, false);
+ 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(m_nRowSelected, iter))
+ m_nRowSelected.push_back(iter);
+ --iter;
+ }
+ m_nCurRow = 0;
+ m_nAnchor = m_nCurRow;
+ m_pSelEngine->SetAnchor(TRUE);
+ ensureVisible(m_nCurColumn, 0, false);
+ 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(m_nRowSelected, iter))
+ m_nRowSelected.push_back(iter);
+ ++iter;
+ }
+ m_nCurRow = m_nRowCount-1;
+ m_nAnchor = m_nCurRow;
+ m_pSelEngine->SetAnchor(TRUE);
+ ensureVisible(m_nCurColumn, m_nRowCount, false);
+ bSuccess = true;
+ }
+ break;
+ default:
+ DBG_ERROR( "TableControl_Impl::dispatchAction: unsupported action!" );
+ }
+ 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 );
+
+ // const StyleSettings& rStyle = m_rAntiImpl.GetSettings().GetStyleSettings();
+ 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;
+ }
+
+ DBG_ASSERT( ( _nColumn >= 0 ) && ( _nColumn < m_pModel->getColumnCount() ),
+ "TableControl_Impl::impl_getCellRect: invalid column index!" );
+ DBG_ASSERT( ( _nRow >= 0 ) && ( _nRow < m_pModel->getRowCount() ),
+ "TableControl_Impl::impl_getCellRect: invalid row index!" );
+
+ Rectangle aAllCells;
+ impl_getAllVisibleCellsArea( aAllCells );
+
+ TableCellGeometry aCell( *this, aAllCells, _nColumn, _nRow );
+ _rCellRect = aCell.getRect();
+ }
+ //-------------------------------------------------------------------------------
+ RowPos TableControl_Impl::getCurrentRow(const Point& rPoint)
+ {
+ DBG_CHECK_ME();
+ Rectangle rCellRect;
+ RowPos newRowPos = -2;//-1 is HeaderRow
+ ColPos newColPos = 0;
+ //To Do: when only row position needed, the second loop isn't necessary, Please proove this!!!
+ for(int i=0;i<m_nRowCount;i++)
+ {
+ for(int j=-1;j<m_nColumnCount;j++)
+ {
+ impl_getCellRect(j,i,rCellRect);
+ if((rPoint.X() >= rCellRect.Left() && rPoint.X() <= rCellRect.Right()) && rPoint.Y() >= rCellRect.Top() && rPoint.Y() <= rCellRect.Bottom())
+ {
+ newRowPos = i;
+ newColPos = j;
+ if(newColPos == -1)
+ m_nCurColumn = 0;
+ else
+ m_nCurColumn = newColPos;
+ return newRowPos;
+ }
+ }
+ }
+ return newRowPos;
+ }
+ //-------------------------------------------------------------------------------
+ void TableControl_Impl::setCursorAtCurrentCell(const Point& rPoint)
+ {
+ DBG_CHECK_ME();
+ hideCursor();
+ Rectangle rCellRect;
+ RowPos newRowPos = -2;//-1 is HeaderRow
+ ColPos newColPos = 0;
+ //To Do: when only row position needed, the second loop isn't necessary, Please proove this!!!
+ for(int i=0;i<m_nRowCount;i++)
+ {
+ for(int j=-1;j<m_nColumnCount;j++)
+ {
+ impl_getCellRect(j,i,rCellRect);
+ if((rPoint.X() >= rCellRect.Left() && rPoint.X() <= rCellRect.Right()) && rPoint.Y() >= rCellRect.Top() && rPoint.Y() <= rCellRect.Bottom())
+ {
+ newRowPos = i;
+ m_nCurRow = newRowPos;
+ newColPos = j;
+ if(newColPos == -1)
+ m_nCurColumn = 0;
+ else
+ m_nCurColumn = newColPos;
+ }
+ }
+ }
+ showCursor();
+ }
+
+ //-------------------------------------------------------------------------------
+ void TableControl_Impl::invalidateSelectedRegion(RowPos _nPrevRow, RowPos _nCurRow, Rectangle& _rCellRect)
+ {
+ DBG_CHECK_ME();
+ Rectangle aAllCells;
+ //get the visible area of the table control and set the Left and right border of the region to be repainted
+ impl_getAllVisibleCellsArea( aAllCells );
+ _rCellRect.Left() = aAllCells.Left();
+ _rCellRect.Right() = aAllCells.Right();
+ Rectangle rCells;
+ //if only one row is selected
+ if(_nPrevRow == _nCurRow)
+ {
+ impl_getCellRect(m_nCurColumn,_nCurRow,rCells);
+ _rCellRect.Top()=rCells.Top();
+ _rCellRect.Bottom()=rCells.Bottom();
+ }
+ //if the region is above the current row
+ else if(_nPrevRow < _nCurRow )
+ {
+ impl_getCellRect(m_nCurColumn,_nPrevRow,rCells);
+ _rCellRect.Top()=rCells.Top();
+ impl_getCellRect(m_nCurColumn,_nCurRow,rCells);
+ _rCellRect.Bottom()=rCells.Bottom();
+ }
+ //if the region is beneath the current row
+ else
+ {
+ impl_getCellRect(m_nCurColumn,_nCurRow,rCells);
+ _rCellRect.Top()=rCells.Top();
+ impl_getCellRect(m_nCurColumn,_nPrevRow,rCells);
+ _rCellRect.Bottom()=rCells.Bottom();
+ }
+ m_pDataWindow->Invalidate(_rCellRect);
+ }
+
+ //-------------------------------------------------------------------------------
+ //To Do: not really needed, because in method above one row can be invalidate. Please Prove this!!!
+ void TableControl_Impl::invalidateSelectedRow(RowPos _nCurRow, Rectangle& _rCellRect)
+ {
+ DBG_CHECK_ME();
+ Rectangle aAllCells;
+ impl_getAllVisibleCellsArea( aAllCells );
+ _rCellRect.Left() = aAllCells.Left();
+ _rCellRect.Right() = aAllCells.Right();
+ Rectangle rCells;
+ impl_getCellRect(m_nCurColumn,_nCurRow,rCells);
+ _rCellRect.Top()=rCells.Top();
+ _rCellRect.Bottom()=rCells.Bottom();
+ m_pDataWindow->Invalidate(_rCellRect);
+ }
+ //-------------------------------------------------------------------------------
+ //this method is to be called, when a new row is added
+ void TableControl_Impl::invalidateRow(RowPos _nRowPos, Rectangle& _rCellRect)
+ {
+ //DBG_CHECK_ME();
+ TempHideCursor aHideCursor( *this );
+ impl_getAllVisibleCellsArea( _rCellRect );
+ TableRowGeometry _rRow( *this, _rCellRect, _nRowPos);
+ impl_ni_updateScrollbars();
+ m_pDataWindow->Invalidate(_rRow.getRect());
+ }
+
+ //-------------------------------------------------------------------------------
+ std::vector<RowPos> TableControl_Impl::getSelectedRows()
+ {
+ return m_nRowSelected;
+ }
+
+ void TableControl_Impl::removeSelectedRow(RowPos _nRowPos)
+ {
+ int i =0;
+ //if the row is selected, remove it from the selection vector
+ if(isRowSelected(m_nRowSelected, _nRowPos))
+ {
+ if(m_nRowSelected.size()>1)
+ m_nRowSelected.erase(m_nRowSelected.begin()+_nRowPos);
+ else
+ m_nRowSelected.clear();
+ }
+ //after removing a row, row positions must be updated, so selected rows could stay selected
+ if(m_nRowSelected.size()>1)
+ {
+ for(std::vector<RowPos>::iterator it=m_nRowSelected.begin();it!=m_nRowSelected.end();++it)
+ {
+ if(*it > _nRowPos)
+ m_nRowSelected[i]=*it-1;
+ ++i;
+ }
+ }
+ if(_nRowPos == 0)
+ m_nCurRow = 0;
+ else
+ m_nCurRow = _nRowPos-1;
+ }
+ //-------------------------------------------------------------------------------
+ void TableControl_Impl::invalidateRows(RowPos _nRowStart, Rectangle& _rCellRect)
+ {
+ //DBG_CHECK_ME();
+ (void)_nRowStart;
+ (void)_rCellRect;
+ /*TempHideCursor aHideCursor(*this);
+ Rectangle aAllCells;
+ impl_getAllVisibleCellsArea( aAllCells );
+ TableRowGeometry _rRow( *this, aAllCells, _nRowStart);
+ _rCellRect = _rRow.getRect();
+ Rectangle rCells1;
+ impl_getCellRect(m_nCurColumn,m_nRowCount,rCells1);
+ _rCellRect.Bottom() = rCells1.Bottom();*/
+ /*if(_nRowStart != _nRowEnd)
+ {
+ TableRowGeometry _rRow( *this, aAllCells, _nRowEnd);
+ _rCellRect.Bottom() = _rRow.getRect().Bottom();
+ }
+ */
+ //_rCellRect.Right() = aAllCells.Right();
+ //_rCellRect.Left() = aAllCells.Left();
+ //Rectangle rCells1;
+ //impl_getCellRect(m_nCurColumn,_nRowStart,rCells1);
+ //_rCellRect.Top()=rCells1.Top();
+ //Rectangle rCells2;
+ //impl_getCellRect(m_nCurColumn,_nRowEnd,rCells2);
+ //_rCellRect.Bottom()=rCells2.Bottom();
+ impl_ni_updateScrollbars();
+ //m_pDataWindow->Invalidate(_rCellRect);
+ m_pDataWindow->Invalidate();
+ }
+
+
+ //-------------------------------------------------------------------------------
+ bool TableControl_Impl::isClickInVisibleArea(const Point& rPoint)
+ {
+ DBG_CHECK_ME();
+ long nScrollbarMetrics = m_rAntiImpl.GetSettings().GetStyleSettings().GetScrollBarSize();
+ //clickable area is in the visible table control area without the scrollbars
+ Rectangle aDataCellPlayground( Point( 0, 0 ), m_rAntiImpl.GetOutputSizePixel() );
+ aDataCellPlayground.Top() = m_nColHeaderHeightPixel;
+ aDataCellPlayground.Right() -= nScrollbarMetrics;
+ aDataCellPlayground.Bottom() -= nScrollbarMetrics;
+ if((rPoint.X() >= aDataCellPlayground.Left() && rPoint.X() <= aDataCellPlayground.Right()) && rPoint.Y() >= aDataCellPlayground.Top() && rPoint.Y() <= aDataCellPlayground.Bottom())
+ {
+ return true;
+ }
+ else
+ return false;
+ }
+ //--------------------------------------------------------------------
+ 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 _bAcceptPartialRow ) 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,
+ _bAcceptPartialRow
+ );
+ }
+
+ //--------------------------------------------------------------------
+ bool TableControl_Impl::goTo( ColPos _nColumn, RowPos _nRow )
+ {
+ DBG_CHECK_ME();
+
+ // TODO: give veto listeners a chance
+
+ if ( ( _nColumn < -1 ) || ( _nColumn >= m_nColumnCount )
+ || ( _nRow < -1 ) || ( _nRow >= m_nRowCount )
+ )
+ return false;
+
+ TempHideCursor aHideCursor( *this );
+ m_nCurColumn = _nColumn;
+ m_nCurRow = _nRow;
+
+ // ensure that the new cell is visible
+ ensureVisible( m_nCurColumn, m_nCurRow, false );
+
+ // TODO: invalidate all and new column/row header, if present, to enforce
+ // re-painting them
+ //if(!m_nRowSelected.empty())
+ //{
+ // Rectangle rCells;
+ // for(std::vector<RowPos>::iterator it=m_nRowSelected.begin();
+ // it!=m_nRowSelected.end();++it)
+ // {
+ // invalidateSelectedRow(*it,rCells);
+ // }
+ // m_nRowSelected.clear();
+ //}
+ // TODO: notify listeners about new position
+ 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!" );
+
+ TempHideCursor aHideCursor( *this );
+
+ if ( _nColumn < m_nLeftColumn )
+ impl_ni_ScrollColumns( _nColumn - m_nLeftColumn );
+ else
+ {
+ TableSize nVisibleColumns = impl_getVisibleColumns( _bAcceptPartialVisibility );
+ if ( _nColumn > m_nLeftColumn + nVisibleColumns - 1 )
+ {
+ impl_ni_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_ni_ScrollRows( _nRow - m_nTopRow );
+ else
+ {
+ TableSize nVisibleRows = impl_getVisibleRows( _bAcceptPartialVisibility );
+ if ( _nRow > m_nTopRow + nVisibleRows - 1 )
+ impl_ni_ScrollRows( _nRow - ( m_nTopRow + nVisibleRows - 1 ) );
+ }
+ }
+
+ //--------------------------------------------------------------------
+ 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_rAntiImpl.IsUpdateMode() && ( m_nTopRow != nOldTopRow ) )
+ {
+ DBG_SUSPEND_INV( INV_SCROLL_POSITION );
+ TempHideCursor 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 );
+ }
+ else
+ m_pDataWindow->Invalidate( INVALIDATE_UPDATE );
+
+ // update the position at the vertical scrollbar
+ m_pVScroll->SetThumbPos( m_nTopRow );
+ }
+
+ return (TableSize)( m_nTopRow - nOldTopRow );
+ }
+
+ //--------------------------------------------------------------------
+ TableSize TableControl_Impl::impl_ni_ScrollColumns( TableSize _nColumnDelta )
+ {
+ // compute new left column
+ ColPos nNewLeftColumn =
+ ::std::max(
+ ::std::min( (ColPos)( m_nLeftColumn + _nColumnDelta ), (ColPos)( m_nColumnCount - 1 ) ),
+ (ColPos)0
+ );
+
+ ColPos nOldLeftColumn = m_nLeftColumn;
+ m_nLeftColumn = nNewLeftColumn;
+
+ // if updates are enabled currently, scroll the viewport
+ if ( m_rAntiImpl.IsUpdateMode() && ( m_nLeftColumn != nOldLeftColumn ) )
+ {
+ DBG_SUSPEND_INV( INV_SCROLL_POSITION );
+ TempHideCursor 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
+ Rectangle aDataArea( Point( m_nRowHeaderWidthPixel, 0 ), m_pDataWindow->GetOutputSizePixel() );
+
+ long nPixelDelta =
+ ( m_nLeftColumn > 0 ? m_aAccColumnWidthsPixel[ m_nLeftColumn - 1 ] : 0 )
+ - ( nOldLeftColumn > 0 ? m_aAccColumnWidthsPixel[ nOldLeftColumn - 1 ] : 0 );
+
+ if ( m_pDataWindow->GetBackground().IsScrollable()
+ && abs( nPixelDelta ) < aDataArea.GetWidth()
+ )
+ {
+ m_pDataWindow->Scroll( (long)-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 );
+ }
+
+ return (TableSize)( m_nLeftColumn - nOldLeftColumn );
+ }
+
+ SelectionEngine* TableControl_Impl::getSelEngine()
+ {
+ return m_pSelEngine;
+ }
+ TableDataWindow* TableControl_Impl::getDataWindow()
+ {
+ return m_pDataWindow;
+ }
+ BOOL TableControl_Impl::isRowSelected(::std::vector<RowPos> selectedRows, RowPos current)
+ {
+ for(::std::vector<RowPos>::iterator it=selectedRows.begin();
+ it!=selectedRows.end();++it)
+ {
+ if(*it == current)
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ int TableControl_Impl::getRowSelectedNumber(::std::vector<RowPos> selectedRows, RowPos current)
+ {
+ int pos = -1;
+ int i = 0;
+ for(std::vector<RowPos>::iterator it=selectedRows.begin();it!=selectedRows.end();++it)
+ {
+ if(*it == current)
+ return pos = i;
+ ++i;
+ }
+ return pos;
+ }
+
+ void TableControl_Impl::setCellContent(CellEntryType* pCellEntryType)
+ {
+ (void)pCellEntryType;
+ }
+
+ //--------------------------------------------------------------------
+ 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;
+ }
+
+ //---------------------------------------------------------------------------------------
+ TableFunctionSet::TableFunctionSet(TableControl_Impl* _pTableControl):
+ m_pTableControl( _pTableControl)
+ ,m_nCurrentRow (-2)
+ {
+ }
+
+ TableFunctionSet::~TableFunctionSet()
+ {
+ }
+
+ void TableFunctionSet::BeginDrag()
+ {
+ }
+
+ void TableFunctionSet::CreateAnchor()
+ {
+ m_pTableControl->m_nAnchor = m_pTableControl->m_nCurRow;
+ }
+
+ void TableFunctionSet::DestroyAnchor()
+ {
+ m_pTableControl->m_nAnchor = -1;
+ }
+
+ BOOL TableFunctionSet::SetCursorAtPoint(const Point& rPoint, BOOL bDontSelectAtCursor)
+ {
+ BOOL bHandled = FALSE;
+ Rectangle rCells;
+ //curRow is the row where the mouse click happened, m_nCurRow is the last selected row, before the mouse click
+ RowPos curRow = m_pTableControl->getCurrentRow(rPoint);
+ if(curRow == -2)
+ return FALSE;
+ if( bDontSelectAtCursor )
+ {
+ if(m_pTableControl->m_nRowSelected.size()>1)
+ m_pTableControl->m_pSelEngine->AddAlways(TRUE);
+ bHandled = TRUE;
+ }
+ else if(m_pTableControl->m_nAnchor == m_pTableControl->m_nCurRow)
+ {
+ //selecting region,
+ int diff = m_pTableControl->m_nCurRow - curRow;
+ //bool isAlreadySelected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, m_pTableControl->m_nAnchor);
+ /* if(!isAlreadySelected && m_nCurrentRow != m_pTableControl->m_nCurRow)
+ m_pTableControl->m_nRowSelected.push_back(m_nAnchor);*/
+ //selected region lies above the last selection
+ if( diff >= 0)
+ {
+ //put selected rows in vector
+ while(m_pTableControl->m_nAnchor>=curRow)
+ {
+ bool isAlreadySelected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, m_pTableControl->m_nAnchor);
+ //if row isn't selected, put it in vector, otherwise don't put it there, because it will be twice there
+ if(!isAlreadySelected)
+ m_pTableControl->m_nRowSelected.push_back(m_pTableControl->m_nAnchor);
+ m_pTableControl->m_nAnchor--;
+ diff--;
+ }
+ m_pTableControl->m_nAnchor++;
+ }
+ //selected region lies beneath the last selected row
+ else
+ {
+ while(m_pTableControl->m_nAnchor<=curRow)
+ {
+ bool isAlreadySelected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, m_pTableControl->m_nAnchor);
+ if(!isAlreadySelected)
+ m_pTableControl->m_nRowSelected.push_back(m_pTableControl->m_nAnchor);
+ m_pTableControl->m_nAnchor++;
+ diff++;
+ }
+ m_pTableControl->m_nAnchor--;
+ }
+ m_pTableControl->invalidateSelectedRegion(m_pTableControl->m_nCurRow, curRow, rCells);
+ bHandled = TRUE;
+ }
+ //no region selected
+ else
+ {
+ if(m_pTableControl->m_nRowSelected.empty())
+ {
+ m_pTableControl->m_nRowSelected.push_back(curRow);
+ }
+ else
+ {
+ if(m_pTableControl->m_pSelEngine->GetSelectionMode()==SINGLE_SELECTION)
+ {
+ DeselectAll();
+ m_pTableControl->m_nRowSelected.push_back(curRow);
+ }
+ else
+ {
+ bool isAlreadySelected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, curRow);
+ if(!isAlreadySelected)
+ m_pTableControl->m_nRowSelected.push_back(curRow);
+ }
+ }
+ if(m_pTableControl->m_nRowSelected.size()>1 && m_pTableControl->m_pSelEngine->GetSelectionMode()!=SINGLE_SELECTION)
+ m_pTableControl->m_pSelEngine->AddAlways(TRUE);
+ m_pTableControl->invalidateSelectedRow(curRow,rCells);
+ bHandled = TRUE;
+ }
+ m_pTableControl->m_nCurRow = curRow;
+ m_pTableControl->ensureVisible(m_pTableControl->m_nCurColumn,m_pTableControl->m_nCurRow,false);
+ return bHandled;
+ }
+
+ BOOL TableFunctionSet::IsSelectionAtPoint( const Point& rPoint )
+ {
+ m_pTableControl->m_pSelEngine->AddAlways(FALSE);
+ if(m_pTableControl->m_nRowSelected.empty())
+ return FALSE;
+ else
+ {
+ RowPos curRow = m_pTableControl->getCurrentRow(rPoint);
+ m_pTableControl->m_nAnchor = -1;
+ bool selected = m_pTableControl->isRowSelected(m_pTableControl->m_nRowSelected, curRow);
+ m_nCurrentRow = curRow;
+ return selected;
+ }
+ }
+
+ void TableFunctionSet::DeselectAtPoint( const Point& rPoint )
+ {
+ (void)rPoint;
+ long pos = 0;
+ long i = 0;
+ Rectangle rCells;
+ for(std::vector<RowPos>::iterator it=m_pTableControl->m_nRowSelected.begin();
+ it!=m_pTableControl->m_nRowSelected.end();++it)
+ {
+ if(*it == m_nCurrentRow)
+ {
+ pos = i;
+ m_pTableControl->invalidateSelectedRow(*it,rCells);
+ }
+ ++i;
+ }
+ m_pTableControl->m_nRowSelected.erase(m_pTableControl->m_nRowSelected.begin()+pos);
+ }
+ void TableFunctionSet::DeselectAll()
+ {
+ if(!m_pTableControl->m_nRowSelected.empty())
+ {
+ Rectangle rCells;
+ for(std::vector<RowPos>::iterator it=m_pTableControl->m_nRowSelected.begin();
+ it!=m_pTableControl->m_nRowSelected.end();++it)
+ {
+ m_pTableControl->invalidateSelectedRow(*it,rCells);
+ }
+ m_pTableControl->m_nRowSelected.clear();
+ }
+ }
+
+//........................................................................
+} } // namespace svt::table
+//........................................................................
diff --git a/svtools/source/table/tablecontrol_impl.hxx b/svtools/source/table/tablecontrol_impl.hxx
new file mode 100644
index 000000000000..410bc8b4c3a1
--- /dev/null
+++ b/svtools/source/table/tablecontrol_impl.hxx
@@ -0,0 +1,342 @@
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2009 by Sun Microsystems, Inc.
+*
+* 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
+
+#ifndef SVTOOLS_INC_TABLE_TABLEMODEL_HXX
+#include <svtools/table/tablemodel.hxx>
+#endif
+
+#ifndef SVTOOLS_INC_TABLE_ABSTRACTTABLECONTROL_HXX
+#include <svtools/table/abstracttablecontrol.hxx>
+#endif
+
+#include <svtools/table/tablemodel.hxx>
+#include <vector>
+#include <vcl/seleng.hxx>
+
+class ScrollBar;
+class ScrollBarBox;
+
+//........................................................................
+namespace svt { namespace table
+{
+//........................................................................
+
+ typedef ::std::vector< long > ArrayOfLong;
+
+ class TableControl;
+ class TableDataWindow;
+ class TableFunctionSet;
+
+ //====================================================================
+ //= TableControl_Impl
+ //====================================================================
+ class TableControl_Impl : public IAbstractTableControl
+ {
+ friend class TableGeometry;
+ friend class TableRowGeometry;
+ friend class TableColumnGeometry;
+ friend class SuspendInvariants;
+ friend class TableFunctionSet;
+ 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;
+ /// the widths of the single columns, measured in pixel
+ ArrayOfLong m_aColumnWidthsPixel;
+ /** the accumulated widths of the single columns, i.e. their exclusive right borders,
+ <strong<not</strong> counting the space for a possible row header column
+ */
+ ArrayOfLong m_aAccColumnWidthsPixel;
+ /// 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;
+
+ 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.
+ */
+ 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_nRowSelected;
+ //part of selection engine
+ TableFunctionSet* m_pTableFunctionSet;
+ //part of selection engine
+ RowPos m_nAnchor;
+
+
+
+#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:
+
+
+ PTableModel getModel() const;
+ void setModel( PTableModel _pModel );
+
+ inline const PTableInputHandler& getInputHandler() const { return m_pInputHandler; }
+
+ inline ColPos getCurColumn() const { return m_nCurColumn; }
+ inline RowPos getCurRow() const { return m_nCurRow; }
+ inline void setCurRow(RowPos curRow){ m_nCurRow = curRow; }
+ inline RowPos getTopRow() const { return m_nTopRow; }
+
+ inline long getColHeaderHightPixel() const { return m_nColHeaderHeightPixel; }
+
+ inline const TableControl& getAntiImpl() const { return m_rAntiImpl; }
+ inline TableControl& getAntiImpl() { return m_rAntiImpl; }
+ void setCellContent(CellEntryType* pCellEntryType);
+
+ 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 );
+ /** returns the row, which contains the input point*/
+ RowPos getCurrentRow (const Point& rPoint);
+
+ void setCursorAtCurrentCell(const Point& rPoint);
+ /** proves whether the vector with the selected rows contains the current row*/
+ BOOL isRowSelected(::std::vector<RowPos> selectedRows, RowPos current);
+ /** returns the position of the current row in the selecttion vector */
+ int getRowSelectedNumber(::std::vector<RowPos> selectedRows, RowPos current);
+ /** _rCellRect contains the region, which should be invalidate after some action e.g. selectiong row*/
+ void invalidateSelectedRegion(RowPos _nPrevRow, RowPos _nCurRow, Rectangle& _rCellRect );
+ /** _rCellRect contains the region, which should be invalidate after some action e.g. selectiong row*/
+ //vielleicht kann man mit den anderen verschmelzen, mit einer Überprüfung ob prev==curr?
+ void invalidateSelectedRow( RowPos _nCurRow, Rectangle& _rCellRect );
+ /** to be called when a new row is added to the control*/
+ void invalidateRow(RowPos _nRowPos, Rectangle& _rCellRect );
+ /** returns the vector, which contains the selected rows*/
+ std::vector<RowPos> getSelectedRows();
+ /** updates the vector, which contains the selected rows after removing the row nRowPos*/
+ void removeSelectedRow(RowPos _nRowPos);
+ void invalidateRows(RowPos _nRowStart, Rectangle& _rCellRect );
+ //virtual void DoubleClick();
+
+ // IAbstractTableControl
+ virtual void hideCursor();
+ virtual void showCursor();
+ virtual bool dispatchAction( TableControlAction _eAction );
+ virtual bool isClickInVisibleArea(const Point& rPoint);
+ virtual SelectionEngine* getSelEngine();
+
+ TableDataWindow* getDataWindow();
+
+ private:
+ /** 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 );
+
+ /** 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.
+ */
+ void impl_getAllVisibleCellsArea( Rectangle& _rCellArea ) 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.
+ */
+ void impl_getAllVisibleDataCellArea( Rectangle& _rCellArea ) const;
+
+ /** 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 _bAcceptPartialRow ) 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 ->m_aColumnWidthsPixel with the current pixel widths of all model columns
+
+ The method takes into account the current zoom factor and map mode of the table
+ control, plus any possible COLWIDTH_FIT_TO_VIEW widths in the 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.
+ */
+ void impl_ni_updateColumnWidths();
+
+ /** 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 );
+
+ /** 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 _nRowDelta );
+
+ DECL_LINK( OnScroll, ScrollBar* );
+ };
+ //see seleng.hxx, seleng.cxx, FunctionSet overwritables, part of selection engine
+ class TableFunctionSet : public FunctionSet
+ {
+ friend class TableDataWindow;
+ 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 BOOL SetCursorAtPoint(const Point& rPoint, BOOL bDontSelectAtCursor);
+ virtual BOOL IsSelectionAtPoint( const Point& rPoint );
+ virtual void DeselectAtPoint( const Point& rPoint );
+ virtual void DeselectAll();
+ };
+
+
+//........................................................................
+} } // namespace svt::table
+//........................................................................
+
+#endif // SVTOOLS_TABLECONTROL_IMPL_HXX
diff --git a/svtools/source/table/tabledatawindow.cxx b/svtools/source/table/tabledatawindow.cxx
new file mode 100644
index 000000000000..71a313bb2e00
--- /dev/null
+++ b/svtools/source/table/tabledatawindow.cxx
@@ -0,0 +1,81 @@
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2009 by Sun Microsystems, Inc.
+*
+* 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/tabledatawindow.hxx"
+#include "tablecontrol_impl.hxx"
+
+//........................................................................
+namespace svt { namespace table
+{
+ class TableControl_Impl;
+//........................................................................
+
+ //====================================================================
+ //= TableDataWindow
+ //====================================================================
+ //--------------------------------------------------------------------
+ TableDataWindow::TableDataWindow( TableControl_Impl& _rTableControl )
+ :Window( &_rTableControl.getAntiImpl() )
+ ,m_rTableControl ( _rTableControl )
+ {
+ Color backgroundColor = m_rTableControl.getAntiImpl().GetSettings().GetStyleSettings().GetFieldColor();
+ SetBackground( backgroundColor );
+ SetControlBackground( backgroundColor );
+ }
+
+ //--------------------------------------------------------------------
+ void TableDataWindow::Paint( const Rectangle& rUpdateRect )
+ {
+ m_rTableControl.doPaintContent( rUpdateRect );
+ }
+ void TableDataWindow::MouseMove( const MouseEvent& rMEvt )
+ {
+ if ( !m_rTableControl.getInputHandler()->MouseMove( m_rTableControl, rMEvt ) )
+ Window::MouseMove( rMEvt );
+ }
+ void TableDataWindow::MouseButtonDown( const MouseEvent& rMEvt )
+ {
+ if ( !m_rTableControl.getInputHandler()->MouseButtonDown( m_rTableControl, rMEvt ) )
+ Window::MouseButtonDown( rMEvt );
+ else
+ m_aMouseButtonDownHdl.Call( (MouseEvent*) &rMEvt);
+ m_rTableControl.getAntiImpl().LoseFocus();
+ }
+ void TableDataWindow::MouseButtonUp( const MouseEvent& rMEvt )
+ {
+ if ( !m_rTableControl.getInputHandler()->MouseButtonUp( m_rTableControl, rMEvt ) )
+ Window::MouseButtonUp( rMEvt );
+ else
+ m_aMouseButtonUpHdl.Call( (MouseEvent*) &rMEvt);
+ m_rTableControl.getAntiImpl().GetFocus();
+ }
+
+//........................................................................
+} } // namespace svt::table
+//........................................................................
diff --git a/svtools/source/table/tablegeometry.cxx b/svtools/source/table/tablegeometry.cxx
new file mode 100644
index 000000000000..569e14c61726
--- /dev/null
+++ b/svtools/source/table/tablegeometry.cxx
@@ -0,0 +1,130 @@
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2009 by Sun Microsystems, Inc.
+*
+* 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( const TableControl_Impl& _rControl, const Rectangle& _rBoundaries,
+ RowPos _nRow )
+ :TableGeometry( _rControl, _rBoundaries )
+ ,m_nRowPos( _nRow )
+ {
+ if ( m_nRowPos == ROW_COL_HEADERS )
+ {
+ DBG_ASSERT( m_rControl.m_pModel->hasColumnHeaders(),
+ "TableRowGeometry::TableRowGeometry: why asking for the geoemtry of the non-existent column header row?" );
+ m_aRect.Top() = 0;
+ m_aRect.Bottom() = m_rControl.m_nColHeaderHeightPixel - 1;
+ }
+ else
+ {
+ if ( ( m_nRowPos >= m_rControl.m_nTopRow ) && ( m_nRowPos < m_rControl.m_pModel->getRowCount() ) )
+ {
+ 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::moveDown()
+ {
+ if ( ++m_nRowPos < m_rControl.m_pModel->getRowCount() )
+ m_aRect.Move( 0, m_rControl.m_nRowHeightPixel );
+ else
+ m_aRect.SetEmpty();
+ return isValid();
+ }
+
+ //====================================================================
+ //= TableColumnGeometry
+ //====================================================================
+ //--------------------------------------------------------------------
+ TableColumnGeometry::TableColumnGeometry( const TableControl_Impl& _rControl, const Rectangle& _rBoundaries,
+ ColPos _nCol )
+ :TableGeometry( _rControl, _rBoundaries )
+ ,m_nColPos( _nCol )
+ {
+ if ( m_nColPos == COL_ROW_HEADERS )
+ {
+ DBG_ASSERT( m_rControl.m_pModel->hasRowHeaders(),
+ "TableColumnGeometry::TableColumnGeometry: why asking for the geoemtry of the non-existent row header column?" );
+ m_aRect.Left() = 0;
+ m_aRect.Right() = m_rControl.m_nRowHeaderWidthPixel - 1;
+ }
+ else
+ {
+ ColPos nLeftColumn = m_rControl.m_nLeftColumn;
+ if ( ( m_nColPos >= nLeftColumn ) && ( m_nColPos < (ColPos)m_rControl.m_aColumnWidthsPixel.size() ) )
+ {
+ 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_aColumnWidthsPixel[ col ];
+ m_aRect.Right() = m_aRect.Left() + m_rControl.m_aColumnWidthsPixel[ m_nColPos ] - 1;
+ }
+ else
+ m_aRect.SetEmpty();
+ }
+ }
+
+ //--------------------------------------------------------------------
+ bool TableColumnGeometry::moveRight()
+ {
+ DBG_ASSERT( m_nColPos != COL_ROW_HEADERS, "TableColumnGeometry::moveRight: cannot move the row header column!" );
+ // what would be COL_ROW_HEADERS + 1?
+
+ if ( ++m_nColPos < (ColPos)m_rControl.m_aColumnWidthsPixel.size() )
+ {
+ m_aRect.Left() = m_aRect.Right() + 1;
+ m_aRect.Right() += m_rControl.m_aColumnWidthsPixel[ m_nColPos ];
+ }
+ else
+ m_aRect.SetEmpty();
+
+ return isValid();
+ }
+
+//........................................................................
+} } // namespace svt::table
+//........................................................................
diff --git a/svtools/source/table/tablegeometry.hxx b/svtools/source/table/tablegeometry.hxx
new file mode 100644
index 000000000000..18b40c1e3781
--- /dev/null
+++ b/svtools/source/table/tablegeometry.hxx
@@ -0,0 +1,161 @@
+/*************************************************************************
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* Copyright 2009 by Sun Microsystems, Inc.
+*
+* 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
+
+#ifndef SVTOOLS_INC_TABLE_TABLETYPES_HXX
+#include <svtools/table/tabletypes.hxx>
+#endif
+
+#ifndef _SV_GEN_HXX
+#include <tools/gen.hxx>
+#endif
+
+//........................................................................
+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;
+
+ public:
+ TableRowGeometry(
+ const TableControl_Impl& _rControl,
+ const Rectangle& _rBoundaries,
+ RowPos _nRow
+ );
+
+ // status
+ RowPos getRow() const { return m_nRowPos; }
+ // operations
+ bool moveDown();
+ };
+
+ //====================================================================
+ //= TableColumnGeometry
+ //====================================================================
+ class TableColumnGeometry : public TableGeometry
+ {
+ protected:
+ ColPos m_nColPos;
+
+ public:
+ TableColumnGeometry(
+ const TableControl_Impl& _rControl,
+ const Rectangle& _rBoundaries,
+ ColPos _nCol
+ );
+
+ // status
+ ColPos getCol() const { return m_nColPos; }
+ // operations
+ bool moveRight();
+ };
+
+ //====================================================================
+ //= TableCellGeometry
+ //====================================================================
+ /** a helper representing geometry information of a cell
+ */
+ class TableCellGeometry
+ {
+ private:
+ TableRowGeometry m_aRow;
+ TableColumnGeometry m_aCol;
+
+ public:
+ TableCellGeometry(
+ const TableControl_Impl& _rControl,
+ const Rectangle& _rBoundaries,
+ ColPos _nCol,
+ RowPos _nRow
+ )
+ :m_aRow( _rControl, _rBoundaries, _nRow )
+ ,m_aCol( _rControl, _rBoundaries, _nCol )
+ {
+ }
+
+ 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