summaryrefslogtreecommitdiffstats
path: root/kspread/kspread_canvas.cc
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kspread/kspread_canvas.cc
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kspread/kspread_canvas.cc')
-rw-r--r--kspread/kspread_canvas.cc6167
1 files changed, 6167 insertions, 0 deletions
diff --git a/kspread/kspread_canvas.cc b/kspread/kspread_canvas.cc
new file mode 100644
index 00000000..0f0971c5
--- /dev/null
+++ b/kspread/kspread_canvas.cc
@@ -0,0 +1,6167 @@
+/* This file is part of the KDE project
+
+ Copyright 2006 Robert Knight <[email protected]>
+ Copyright 2006 Inge Wallin <[email protected]>
+ Copyright 2006 Stefan Nikolaus <[email protected]>
+ Copyright 1999-2002,2004 Laurent Montel <[email protected]>
+ Copyright 2002-2005 Ariya Hidayat <[email protected]>
+ Copyright 1999-2004 David Faure <[email protected]>
+ Copyright 2004-2005 Meni Livne <[email protected]>
+ Copyright 2001-2003 Philipp Mueller <[email protected]>
+ Copyright 2002-2003 Norbert Andres <[email protected]>
+ Copyright 2003 Hamish Rodda <[email protected]>
+ Copyright 2003 Joseph Wenninger <[email protected]>
+ Copyright 2003 Lukas Tinkl <[email protected]>
+ Copyright 2000-2002 Werner Trobin <[email protected]>
+ Copyright 2002 Harri Porten <[email protected]>
+ Copyright 2002 John Dailey <[email protected]>
+ Copyright 2002 Daniel Naber <[email protected]>
+ Copyright 1999-2000 Torben Weis <[email protected]>
+ Copyright 1999-2000 Stephan Kulow <[email protected]>
+ Copyright 2000 Bernd Wuebben <[email protected]>
+ Copyright 2000 Wilco Greven <[email protected]>
+ Copyright 2000 Simon Hausmann <[email protected]
+ Copyright 1999 Michael Reiher <michael.reiher.gmx.de>
+ Copyright 1999 Boris Wedl <[email protected]>
+ Copyright 1999 Reginald Stadlbauer <[email protected]>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <assert.h>
+#include <float.h>
+#include <stdlib.h>
+
+#include <qapplication.h>
+#include <qbuffer.h>
+#include <qclipboard.h>
+#include <qdrawutil.h>
+#include <qlabel.h>
+#include <qpoint.h>
+#include <qscrollbar.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+#include <qwidgetlist.h>
+
+#include <kcursor.h>
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kmultipledrag.h>
+#include <krun.h>
+#include <kmimetype.h>
+#include <ksharedptr.h>
+#include <kwordwrap.h>
+
+#include <KoOasisStore.h>
+#include <KoSpeaker.h>
+#include <KoStore.h>
+#include <KoStoreDrag.h>
+#include <KoXmlWriter.h>
+#include <KoDocumentChild.h>
+#include <KoRect.h>
+
+#include "commands.h"
+#include "kspread_doc.h"
+#include "kspread_editors.h"
+#include "kspread_global.h"
+#include "kspread_locale.h"
+#include "kspread_map.h"
+#include "kspread_sheet.h"
+#include "kspread_undo.h"
+#include "kspread_util.h"
+#include "kspread_view.h"
+#include "selection.h"
+
+#include "kspread_canvas.h"
+
+// TODO Stefan: undefine/remove, if non-contiguous selections don't work
+// properly or if we are sure, that they do. ;-)
+#define NONCONTIGUOUSSELECTION
+
+#define MIN_SIZE 10
+
+using namespace KSpread;
+
+class Canvas::Private
+{
+ public:
+ ComboboxLocationEditWidget *posWidget;
+ KSpread::EditWidget *editWidget;
+ KSpread::CellEditor *cellEditor;
+
+ View *view;
+ QTimer* scrollTimer;
+
+ // Non visible range left from current screen
+ // Example: If the first visible column is 'E', then xOffset stores
+ // the width of the invisible columns 'A' to 'D'.
+ double xOffset;
+
+ // Non visible range on top of the current screen
+ // Example: If the first visible row is '5', then yOffset stores
+ // the height of the invisible rows '1' to '4'.
+ double yOffset;
+
+ // Used to draw the grey grid that is usually only visible on the
+ // screen, but not by printing on paper.
+ QPen defaultGridPen;
+
+ // see setLastEditorWithFocus, lastEditorWithFocus
+ Canvas::EditorType focusEditorType;
+
+ QLabel *validationInfo;
+
+ // true if the user is to choose a cell.
+ bool chooseCell;
+
+ // True when the mouse button is pressed
+ bool mousePressed;
+
+ // If the user is dragging around with the mouse then this tells us what he is doing.
+ // The user may want to mark cells or he started in the lower right corner
+ // of the marker which is something special. The values for the 2 above
+ // methods are called 'Mark' and 'ResizeCell' or 'AutoFill' depending
+ // on the mouse button used. By default this variable holds
+ // the value 'NoAction'.
+ Canvas::MouseActions mouseAction;
+
+ // If we use the lower right corner of the marker to start autofilling, then this
+ // rectangle conatins all cells that were already marker when the user started
+ // to mark the rectangle which he wants to become autofilled.
+ QRect autoFillSource;
+
+ // Start coordinates for drag and drop
+ QPoint dragStart;
+ bool dragging;
+
+ // Used to indicate whether the user started drawing a rubber band rectangle
+ bool rubberBandStarted;
+ QPoint rubberBandStart;
+ QPoint rubberBandEnd;
+
+ // If the mouse is over some anchor ( in the sense of HTML anchors )
+ QString anchor;
+
+ bool mouseSelectedObject;
+ bool drawContour;
+ ModifyType modType;
+ /**
+ * Saves the last mouse position during mouse move events.
+ */
+ QPoint m_savedMousePos;
+
+ //---- stuff needed for resizing ----
+ /// object which gets resized
+ EmbeddedObject *m_resizeObject;
+ /// ratio of the object ( width / height )
+ double m_ratio;
+ bool m_isResizing;
+ /// The last position of the mouse during moving
+ KoPoint m_origMousePos;
+
+ //---- stuff needed for moving ----
+ bool m_isMoving;
+ KoPoint m_moveStartPoint;
+
+ /// size of the object at when resizing is started
+ KoRect m_rectBeforeResize;
+ /// Start position for move with mouse
+ KoPoint m_moveStartPosMouse;
+
+ /// object which is selected and should be shown above all the other objects
+ EmbeddedObject * m_objectDisplayAbove;
+
+ // bool mouseOverHighlightRangeSizeGrip;
+
+ // The row and column of 1) the last cell under mouse pointer, 2) the last focused cell, and
+ // the last spoken cell.
+ int prevSpokenPointerRow;
+ int prevSpokenPointerCol;
+ int prevSpokenFocusRow;
+ int prevSpokenFocusCol;
+ int prevSpokenRow;
+ int prevSpokenCol;
+};
+
+
+
+/****************************************************************
+ *
+ * Canvas
+ *
+ ****************************************************************/
+
+Canvas::Canvas (View *_view)
+ : QWidget( _view, "", /*WNorthWestGravity*/ WStaticContents| WResizeNoErase | WRepaintNoErase )
+{
+ d = new Private;
+
+ d->cellEditor = 0;
+ d->chooseCell = false;
+ d->validationInfo = 0L;
+
+ QWidget::setFocusPolicy( QWidget::StrongFocus );
+
+ d->dragStart = QPoint( -1, -1 );
+ d->dragging = false;
+
+
+ d->defaultGridPen.setColor( lightGray );
+ d->defaultGridPen.setWidth( 1 );
+ d->defaultGridPen.setStyle( SolidLine );
+
+ d->xOffset = 0.0;
+ d->yOffset = 0.0;
+ d->view = _view;
+ // m_eAction = DefaultAction;
+ d->mouseAction = NoAction;
+ d->rubberBandStarted = false;
+ // m_bEditDirtyFlag = false;
+
+ //Now built afterwards(David)
+ //d->editWidget = d->view->editWidget();
+ d->posWidget = d->view->posWidget();
+
+ setBackgroundMode( PaletteBase );
+
+ setMouseTracking( true );
+ d->mousePressed = false;
+ d->mouseSelectedObject = false;
+ d->drawContour = false;
+ d->modType = MT_NONE;
+
+ d->m_resizeObject = 0L;
+ d->m_ratio = 0.0;
+ d->m_isMoving = false;
+ d->m_objectDisplayAbove = false;
+ d->m_isResizing = false;
+
+ d->prevSpokenPointerRow = -1;
+ d->prevSpokenPointerCol = -1;
+ d->prevSpokenFocusRow = -1;
+ d->prevSpokenFocusCol = -1;
+ d->prevSpokenRow = -1;
+ d->prevSpokenCol = -1;
+
+ d->scrollTimer = new QTimer( this );
+ connect (d->scrollTimer, SIGNAL( timeout() ), this, SLOT( doAutoScroll() ) );
+
+ if( d->view)
+ {
+ connect( d->view, SIGNAL( autoScroll( const QPoint & )), this, SLOT( slotAutoScroll( const QPoint &)));
+ }
+ if (kospeaker)
+ {
+ connect (kospeaker, SIGNAL(customSpeakWidget(QWidget*, const QPoint&, uint)),
+ this, SLOT(speakCell(QWidget*, const QPoint&, uint)));
+ }
+
+ setFocus();
+ installEventFilter( this );
+ (void)new ToolTip( this );
+ setAcceptDrops( true );
+ setInputMethodEnabled( true ); // ensure using the InputMethod
+
+ setWFlags(Qt::WNoAutoErase);
+}
+
+Canvas::~Canvas()
+{
+ delete d->scrollTimer;
+ delete d->validationInfo;
+ delete d;
+}
+
+KSpread::View* Canvas::view() const
+{
+ return d->view;
+}
+
+Doc* Canvas::doc() const
+{
+ return d->view->doc();
+}
+
+void Canvas::setEditWidget( KSpread::EditWidget * ew )
+{
+ d->editWidget = ew;
+}
+
+KSpread::EditWidget* Canvas::editWidget() const
+{
+ return d->editWidget;
+}
+
+CellEditor* Canvas::editor() const
+{
+ return d->cellEditor;
+}
+
+double Canvas::xOffset() const
+{
+ return d->xOffset;
+}
+
+double Canvas::yOffset() const
+{
+ return d->yOffset;
+}
+
+void Canvas::setXOffset( double _xOffset )
+{
+ d->xOffset = _xOffset;
+}
+
+void Canvas::setYOffset( double _yOffset )
+{
+ d->yOffset = _yOffset;
+}
+
+const QPen& Canvas::defaultGridPen() const
+{
+ return d->defaultGridPen;
+}
+
+void Canvas::setLastEditorWithFocus( Canvas::EditorType type )
+{
+ d->focusEditorType = type;
+}
+
+Canvas::EditorType Canvas::lastEditorWithFocus() const
+{
+ return d->focusEditorType;
+}
+
+
+bool Canvas::eventFilter( QObject *o, QEvent *e )
+{
+ /* this canvas event filter acts on events sent to the line edit as well
+ as events to this filter itself.
+ */
+ if ( !o || !e )
+ return true;
+ switch ( e->type() )
+ {
+ case QEvent::KeyPress:
+ {
+ QKeyEvent * keyev = static_cast<QKeyEvent *>(e);
+ if ((keyev->key()==Key_Tab) || (keyev->key()==Key_Backtab))
+ {
+ keyPressEvent ( keyev );
+ return true;
+ }
+ break;
+ }
+ case QEvent::IMStart:
+ case QEvent::IMCompose:
+ case QEvent::IMEnd:
+ {
+ QIMEvent * imev = static_cast<QIMEvent *>(e);
+ processIMEvent( imev );
+ break;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+bool Canvas::focusNextPrevChild( bool )
+{
+ return true; // Don't allow to go out of the canvas widget by pressing "Tab"
+}
+
+Selection* Canvas::selectionInfo() const
+{
+ return d->view->selectionInfo();
+}
+
+Selection* Canvas::choice() const
+{
+ return d->view->choice();
+}
+
+QRect Canvas::selection() const
+{
+ return d->view->selectionInfo()->selection();
+}
+
+QPoint Canvas::marker() const
+{
+ return d->view->selectionInfo()->marker();
+}
+
+int Canvas::markerColumn() const
+{
+ return d->view->selectionInfo()->marker().x();
+}
+
+int Canvas::markerRow() const
+{
+ return d->view->selectionInfo()->marker().y();
+}
+
+double Canvas::zoom() const
+{
+ return d->view->zoom();
+}
+
+void Canvas::setChooseMode(bool state)
+{
+ d->chooseCell = state;
+}
+
+bool Canvas::chooseMode() const
+{
+ return d->chooseCell;
+}
+
+void Canvas::startChoose()
+{
+ if ( d->chooseCell )
+ return;
+
+ choice()->clear();
+ choice()->setSheet(activeSheet());
+
+ // It is important to enable this AFTER we set the rect!
+ d->chooseCell = true;
+}
+
+void Canvas::startChoose( const QRect& rect )
+{
+ if (d->chooseCell)
+ return;
+
+ choice()->setSheet(activeSheet());
+ choice()->initialize(rect);
+
+ // It is important to enable this AFTER we set the rect!
+ d->chooseCell = true;
+}
+
+void Canvas::endChoose()
+{
+ // While entering a formula the choose mode is turned on and off.
+ // Clear the choice even if we are not in choose mode. Otherwise,
+ // cell references will stay highlighted.
+ if (!choice()->isEmpty())
+ {
+ choice()->clear();
+ update();
+ }
+
+ if ( !d->chooseCell )
+ return;
+
+ d->chooseCell = false;
+
+ Sheet *sheet = choice()->sheet();
+ if (sheet)
+ {
+ d->view->setActiveSheet(sheet);
+ }
+}
+
+HBorder* Canvas::hBorderWidget() const
+{
+ return d->view->hBorderWidget();
+}
+
+VBorder* Canvas::vBorderWidget() const
+{
+ return d->view->vBorderWidget();
+}
+
+QScrollBar* Canvas::horzScrollBar() const
+{
+ return d->view->horzScrollBar();
+}
+
+QScrollBar* Canvas::vertScrollBar() const
+{
+ return d->view->vertScrollBar();
+}
+
+Sheet* Canvas::findSheet( const QString& _name ) const
+{
+ return d->view->doc()->map()->findSheet( _name );
+}
+
+Sheet* Canvas::activeSheet() const
+{
+ return d->view->activeSheet();
+}
+
+void Canvas::validateSelection()
+{
+ Sheet* sheet = activeSheet();
+ if (!sheet)
+ {
+ return;
+ }
+
+ if ( selectionInfo()->isSingular() )
+ {
+ int col = selectionInfo()->marker().x();
+ int row = selectionInfo()->marker().y();
+ Cell * cell = sheet->cellAt( col,row );
+ if ( cell && cell->getValidity(0) && cell->getValidity()->displayValidationInformation)
+ {
+ QString title = cell->getValidity(0)->titleInfo;
+ QString message = cell->getValidity(0)->messageInfo;
+ if ( title.isEmpty() && message.isEmpty() )
+ return;
+
+ if ( !d->validationInfo )
+ d->validationInfo = new QLabel( this );
+ kdDebug()<<" display info validation\n";
+ double u = cell->dblWidth( col );
+ double v = cell->dblHeight( row );
+ double xpos = sheet->dblColumnPos( markerColumn() ) - xOffset();
+ double ypos = sheet->dblRowPos( markerRow() ) - yOffset();
+ // Special treatment for obscured cells.
+ if ( cell->isObscured() && cell->isPartOfMerged() )
+ {
+ cell = cell->obscuringCells().first();
+ int moveX = cell->column();
+ int moveY = cell->row();
+
+ // Use the obscuring cells dimensions
+ u = cell->dblWidth( moveX );
+ v = cell->dblHeight( moveY );
+ xpos = sheet->dblColumnPos( moveX );
+ ypos = sheet->dblRowPos( moveY );
+ }
+ //d->validationInfo->setGeometry( 3, y + 3, len + 2, hei + 2 );
+ d->validationInfo->setAlignment( Qt::AlignVCenter );
+ QPainter painter;
+ painter.begin( this );
+ int len = 0;
+ int hei = 0;
+ QString resultText;
+ if ( !title.isEmpty() )
+ {
+ len = painter.fontMetrics().width( title );
+ hei = painter.fontMetrics().height();
+ resultText = title + "\n";
+ }
+ if ( !message.isEmpty() )
+ {
+ int i = 0;
+ int pos = 0;
+ QString t;
+ do
+ {
+ i = message.find( "\n", pos );
+ if ( i == -1 )
+ t = message.mid( pos, message.length() - pos );
+ else
+ {
+ t = message.mid( pos, i - pos );
+ pos = i + 1;
+ }
+ hei += painter.fontMetrics().height();
+ len = QMAX( len, painter.fontMetrics().width( t ) );
+ }
+ while ( i != -1 );
+ resultText += message;
+ }
+ painter.end();
+ d->validationInfo->setText( resultText );
+
+ KoRect unzoomedMarker( xpos - xOffset()+u,
+ ypos - yOffset()+v,
+ len,
+ hei );
+ QRect marker( d->view->doc()->zoomRect( unzoomedMarker ) );
+
+ d->validationInfo->setGeometry( marker );
+ d->validationInfo->show();
+ }
+ else
+ {
+ delete d->validationInfo;
+ d->validationInfo = 0L;
+ }
+ }
+ else
+ {
+ delete d->validationInfo;
+ d->validationInfo = 0L;
+ }
+}
+
+
+void Canvas::scrollToCell(QPoint location) const
+{
+ Sheet* sheet = activeSheet();
+ if (sheet == NULL)
+ return;
+
+ if (d->view->isLoading())
+ return;
+
+ // kdDebug(36001) << "------------------------------------------------" << endl;
+ // kdDebug(36001) << "scrollToCell(): at location [" << location.x() << ","
+ // << location.y() << "]" << endl;
+
+ /* we don't need this cell ptr, but this call is necessary to update the
+ scroll bar correctly. I don't like having that as part of the cellAt function
+ but I suppose that's ok for now.
+ */
+ Cell* cell = sheet->cellAt(location.x(), location.y(), true);
+ Q_UNUSED(cell);
+
+ double unzoomedWidth = d->view->doc()->unzoomItX( width() );
+ double unzoomedHeight = d->view->doc()->unzoomItY( height() );
+
+ //kdDebug(36001) << "Unzoomed view size: [" << unzoomedWidth << ","
+ // << unzoomedHeight << "]" << endl;
+
+ // xpos is the position of the cell in the current window in unzoomed
+ // document coordinates.
+ double xpos;
+ if ( sheet->layoutDirection()==Sheet::LeftToRight )
+ xpos = sheet->dblColumnPos( location.x() ) - xOffset();
+ else
+ xpos = unzoomedWidth - sheet->dblColumnPos( location.x() ) + xOffset();
+ double ypos = sheet->dblRowPos( location.y() ) - yOffset();
+
+ //kdDebug(36001) << "Position: [" << xpos << "," << ypos << "]" << endl;
+
+ double minY = 40.0;
+ double maxY = unzoomedHeight - 40.0;
+ //kdDebug(36001) << "Canvas::scrollToCell : height=" << height() << endl;
+ //kdDebug(36001) << "Canvas::scrollToCell : width=" << width() << endl;
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft ) {
+ // Right to left sheet.
+
+ double minX = unzoomedWidth - 100.0; // less than that, we scroll
+ double maxX = 100.0; // more than that, we scroll
+
+ // kdDebug() << "rtl2: XPos: " << xpos << ", min: " << minX << ", maxX: " << maxX << ", Offset: " << xOffset() << endl;
+
+ // Do we need to scroll left?
+ if ( xpos > minX )
+ horzScrollBar()->setValue( horzScrollBar()->maxValue() -
+ d->view->doc()->zoomItX( xOffset() - xpos + minX ) );
+
+ // Do we need to scroll right?
+ else if ( xpos < maxX )
+ {
+ double horzScrollBarValue = xOffset() - xpos + maxX;
+ double horzScrollBarValueMax = sheet->sizeMaxX() - unzoomedWidth;
+
+ //We don't want to display any area > KS_colMax widths
+ if ( horzScrollBarValue > horzScrollBarValueMax )
+ horzScrollBarValue = horzScrollBarValueMax;
+
+ horzScrollBar()->setValue( horzScrollBar()->maxValue() -
+ d->view->doc()->zoomItX( horzScrollBarValue ) );
+ }
+ }
+ else {
+ // Left to right sheet.
+
+ double minX = 100.0; // less than that, we scroll
+ double maxX = unzoomedWidth - 100.0; // more than that, we scroll
+
+ // kdDebug() << "ltr: XPos: " << xpos << ", min: " << minX << ", maxX: " << maxX << endl;
+
+ // Do we need to scroll left?
+ if ( xpos < minX )
+ horzScrollBar()->setValue( d->view->doc()->zoomItX( xOffset() + xpos - minX ) );
+
+ // Do we need to scroll right?
+ else if ( xpos > maxX )
+ {
+ double horzScrollBarValue = xOffset() + xpos - maxX;
+ double horzScrollBarValueMax = sheet->sizeMaxX() - unzoomedWidth;
+
+ //We don't want to display any area > KS_colMax widths
+ if ( horzScrollBarValue > horzScrollBarValueMax )
+ horzScrollBarValue = horzScrollBarValueMax;
+
+ horzScrollBar()->setValue( d->view->doc()->zoomItX( horzScrollBarValue ) );
+ }
+ }
+// kdDebug() << "ltr: YPos: " << ypos << ", min: " << minY << ", maxY: " << maxY << endl;
+
+ // do we need to scroll up
+ if ( ypos < minY )
+ vertScrollBar()->setValue( d->view->doc()->zoomItY( yOffset() + ypos - minY ) );
+
+ // do we need to scroll down
+ else if ( ypos > maxY )
+ {
+ double vertScrollBarValue = yOffset() + ypos - maxY;
+ double vertScrollBarValueMax = sheet->sizeMaxY() - unzoomedHeight;
+
+ //We don't want to display any area > KS_rowMax heights
+ if ( vertScrollBarValue > vertScrollBarValueMax )
+ vertScrollBarValue = vertScrollBarValueMax;
+
+ vertScrollBar()->setValue( d->view->doc()->zoomItY( vertScrollBarValue ) );
+ }
+}
+
+void Canvas::slotScrollHorz( int _value )
+{
+ Sheet * sheet = activeSheet();
+
+ if ( sheet == 0L )
+ return;
+
+ kdDebug(36001) << "slotScrollHorz: value = " << _value << endl;
+ //kdDebug(36001) << kdBacktrace() << endl;
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ _value = horzScrollBar()->maxValue() - _value;
+
+ double unzoomedValue = d->view->doc()->unzoomItX( _value );
+ double dwidth = d->view->doc()->unzoomItX( width() );
+
+ d->view->doc()->emitBeginOperation(false);
+
+ if ( unzoomedValue < 0.0 ) {
+ kdDebug (36001)
+ << "Canvas::slotScrollHorz: value out of range (unzoomedValue: "
+ << unzoomedValue << ")" << endl;
+ unzoomedValue = 0.0;
+ }
+
+ double xpos = sheet->dblColumnPos( QMIN( KS_colMax, d->view->activeSheet()->maxColumn()+10 ) ) - d->xOffset;
+ if ( unzoomedValue > ( xpos + d->xOffset ) )
+ unzoomedValue = xpos + d->xOffset;
+
+ sheet->enableScrollBarUpdates( false );
+
+ // Relative movement
+ int dx = d->view->doc()->zoomItX( d->xOffset - unzoomedValue );
+
+
+ /* what cells will need painted now? */
+ QRect area = visibleCells();
+ double tmp;
+ if (dx > 0)
+ {
+ area.setRight( area.left() );
+ area.setLeft( sheet->leftColumn( unzoomedValue, tmp ) );
+ }
+ else
+ {
+ area.setLeft( area.right() );
+ area.setRight( sheet->rightColumn( dwidth + unzoomedValue ) );
+ }
+
+ sheet->setRegionPaintDirty(area);
+
+ // New absolute position
+ kdDebug(36001) << "slotScrollHorz(): XOffset before setting: "
+ << d->xOffset << endl;
+ d->xOffset = unzoomedValue;
+ kdDebug(36001) << "slotScrollHorz(): XOffset after setting: "
+ << d->xOffset << endl;
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ dx = -dx;
+
+ scroll( dx, 0 );
+
+ hBorderWidget()->scroll( dx, 0 );
+
+ sheet->enableScrollBarUpdates( true );
+
+ d->view->doc()->emitEndOperation( sheet->visibleRect( this ) );
+}
+
+void Canvas::slotScrollVert( int _value )
+{
+ if ( activeSheet() == 0L )
+ return;
+
+ d->view->doc()->emitBeginOperation(false);
+ double unzoomedValue = d->view->doc()->unzoomItY( _value );
+
+ if ( unzoomedValue < 0 )
+ {
+ unzoomedValue = 0;
+ kdDebug (36001) << "Canvas::slotScrollVert: value out of range (unzoomedValue: " <<
+ unzoomedValue << ")" << endl;
+ }
+
+ double ypos = activeSheet()->dblRowPos( QMIN( KS_rowMax, d->view->activeSheet()->maxRow()+10 ) );
+ if ( unzoomedValue > ypos )
+ unzoomedValue = ypos;
+
+ activeSheet()->enableScrollBarUpdates( false );
+
+ // Relative movement
+ int dy = d->view->doc()->zoomItY( d->yOffset - unzoomedValue );
+
+
+ /* what cells will need painted now? */
+ QRect area = visibleCells();
+ double tmp;
+ if (dy > 0)
+ {
+ area.setBottom(area.top());
+ area.setTop(activeSheet()->topRow(unzoomedValue, tmp));
+ }
+ else
+ {
+ area.setTop(area.bottom());
+ area.setBottom(activeSheet()->bottomRow(d->view->doc()->unzoomItY(height()) +
+ unzoomedValue));
+ }
+
+ activeSheet()->setRegionPaintDirty( area );
+
+ // New absolute position
+ d->yOffset = unzoomedValue;
+ scroll( 0, dy );
+ vBorderWidget()->scroll( 0, dy );
+
+ activeSheet()->enableScrollBarUpdates( true );
+
+ d->view->doc()->emitEndOperation( activeSheet()->visibleRect( this ) );
+}
+
+void Canvas::slotMaxColumn( int _max_column )
+{
+ int oldValue = horzScrollBar()->maxValue() - horzScrollBar()->value();
+ double xpos = activeSheet()->dblColumnPos( QMIN( KS_colMax, _max_column + 10 ) ) - xOffset();
+ double unzoomWidth = d->view->doc()->unzoomItX( width() );
+
+ //Don't go beyond the maximum column range (KS_colMax)
+ double sizeMaxX = activeSheet()->sizeMaxX();
+ if ( xpos > sizeMaxX - xOffset() - unzoomWidth )
+ xpos = sizeMaxX - xOffset() - unzoomWidth;
+
+ horzScrollBar()->setRange( 0, d->view->doc()->zoomItX( xpos + xOffset() ) );
+
+ if ( activeSheet()->layoutDirection()==Sheet::RightToLeft )
+ horzScrollBar()->setValue( horzScrollBar()->maxValue() - oldValue );
+}
+
+void Canvas::slotMaxRow( int _max_row )
+{
+ double ypos = activeSheet()->dblRowPos( QMIN( KS_rowMax, _max_row + 10 ) ) - yOffset();
+ double unzoomHeight = d->view->doc()->unzoomItY( height() );
+
+ //Don't go beyond the maximum row range (KS_rowMax)
+ double sizeMaxY = activeSheet()->sizeMaxY();
+ if ( ypos > sizeMaxY - yOffset() - unzoomHeight )
+ ypos = sizeMaxY - yOffset() - unzoomHeight;
+
+ vertScrollBar()->setRange( 0, d->view->doc()->zoomItY( ypos + yOffset() ) );
+}
+
+void Canvas::mouseMoveEvent( QMouseEvent * _ev )
+{
+ // Dont allow modifications if document is readonly. Selecting is no modification
+ if ( (!d->view->koDocument()->isReadWrite()) && (d->mouseAction!=Mark))
+ return;
+
+ if ( d->mousePressed && d->modType != MT_NONE )
+ {
+ KoPoint docPoint ( doc()->unzoomPoint( _ev->pos() ) );
+ docPoint += KoPoint( xOffset(), yOffset() );
+
+ if ( d->modType == MT_MOVE )
+ {
+ if ( !d->m_isMoving )
+ {
+ d->m_moveStartPoint = objectRect( false ).topLeft();
+ d->m_isMoving = true;
+ }
+ moveObjectsByMouse( docPoint, _ev->state() & AltButton || _ev->state() & ControlButton );
+ }
+ else if ( d->m_resizeObject )
+ {
+ if ( !d->m_isResizing )
+ d->m_isResizing = true;
+
+ bool keepRatio = d->m_resizeObject->isKeepRatio();
+ if ( _ev->state() & AltButton )
+ {
+ keepRatio = true;
+ }
+ docPoint = KoPoint( doc()->unzoomPoint( _ev->pos() ) );
+ resizeObject( d->modType, docPoint, keepRatio );
+ }
+ return;
+ }
+
+
+ /*if ( d->mousePressed && d->m_resizeObject && d->modType != MT_NONE )
+ {
+ if ( !d->m_isMoving )
+ {
+ d->m_isMoving = true;
+ update();
+ }
+ else
+ update( d->m_boundingRealRect );
+
+
+ QRect drawingRect;
+
+ if ( d->modType == MT_MOVE )
+ {
+ drawingRect = QRect( _ev->pos() - d->m_origPos, d->m_origSize );
+ d->m_boundingRealRect = drawingRect;
+ }
+ else
+ {
+ drawingRect = doc()->zoomRect( calculateNewGeometry(d->modType, _ev->pos().x(), _ev->pos().y() ) );
+ drawingRect.moveBy( (int)( -xOffset() * doc()->zoomedResolutionX() ) , (int)( -yOffset() * doc()->zoomedResolutionY() ) );
+ }
+
+ // Autoscrolling
+ if ( ( d->modType == MT_MOVE && drawingRect.top() < 0 ) || ( d->modType != MT_MOVE && _ev->pos().y() < 0 ) )
+ {
+ vertScrollBar()->setValue ((int) ( vertScrollBar()->value() -
+ autoScrollAccelerationY( - drawingRect.top() ) ) );
+ }
+ else if ( ( d->modType == MT_MOVE && drawingRect.bottom() > height() ) || ( d->modType != MT_MOVE && _ev->pos().y() > height() ) )
+ {
+ vertScrollBar()->setValue ((int) ( vertScrollBar()->value() +
+ autoScrollAccelerationY ( drawingRect.bottom() - height() ) ) );
+ }
+ if ( ( d->modType == MT_MOVE && drawingRect.left() < 0 ) || ( d->modType != MT_MOVE && _ev->pos().x() < 0 ) )
+ {
+ horzScrollBar()->setValue ((int) ( horzScrollBar()->value() -
+ autoScrollAccelerationX( - drawingRect.left() ) ) );
+ }
+ else if ( ( d->modType == MT_MOVE && drawingRect.right() > width() ) || ( d->modType != MT_MOVE && _ev->pos().x() > width() ) )
+ {
+ horzScrollBar()->setValue ((int) (horzScrollBar()->value() +
+ autoScrollAccelerationX( drawingRect.right() - width() ) ) );
+ }
+
+ if ( drawingRect.left() < 0 )
+ {
+ drawingRect.setRight( drawingRect.right() -drawingRect.left() );
+ drawingRect.setLeft( 0 );
+ }
+ if ( drawingRect.top() < 0 )
+ {
+ drawingRect.setBottom( drawingRect.bottom() -drawingRect.top() );
+ drawingRect.setTop( 0 );
+ }
+
+ d->m_boundingRealRect = drawingRect; //redraw this area next time the mouse has been moved
+
+ //update( d->m_boundingRealRect );
+ QPainter p(this);
+ p.setRasterOp( NotROP );
+ p.setPen( QPen( black, 0, DotLine ) );
+ p.drawRect( drawingRect );
+ p.end();
+ return;
+}*/
+
+ if ( d->dragging )
+ {
+ return;
+ }
+ if ( d->dragStart.x() != -1 )
+ {
+ QPoint p ( (int) _ev->pos().x() + (int) xOffset(),
+ (int) _ev->pos().y() + (int) yOffset() );
+
+ if ( ( d->dragStart - p ).manhattanLength() > 4 )
+ {
+ d->dragging = true;
+ startTheDrag();
+ d->dragStart.setX( -1 );
+ }
+ d->dragging = false;
+ return;
+ }
+
+ // Get info about where the event occurred - this is duplicated
+ // in ::mousePressEvent, needs to be separated into one function
+ Sheet *sheet = activeSheet();
+ if ( !sheet )
+ {
+ return;
+ }
+
+ if ( d->mouseSelectedObject )
+ {
+ EmbeddedObject *obj = 0;
+ QPoint p ( (int) _ev->x(),
+ (int) _ev->y() );
+ if ( ( obj = getObject( p, activeSheet() ) ) && obj->isSelected() )
+ {
+ KoRect const bound = obj->geometry();
+ QRect zoomedBound = doc()->zoomRect( KoRect(bound.left(), bound.top(),
+ bound.width(),
+ bound.height() ) );
+ zoomedBound.moveBy( (int)(-xOffset() * doc()->zoomedResolutionX() ), (int)(-yOffset() * doc()->zoomedResolutionY() ));
+ setCursor( obj->getCursor( p, d->modType, zoomedBound ) );
+ return;
+ }
+ }
+
+ double dwidth = d->view->doc()->unzoomItX( width() );
+ double ev_PosX;
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ ev_PosX = dwidth - d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
+ }
+ else
+ {
+ ev_PosX = d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
+ }
+ double ev_PosY = d->view->doc()->unzoomItY( _ev->pos().y() ) + yOffset();
+
+ // In which cell did the user click ?
+ double xpos;
+ double ypos;
+ int col = sheet->leftColumn( ev_PosX, xpos );
+ int row = sheet->topRow( ev_PosY, ypos );
+
+ // you cannot move marker when col > KS_colMax or row > KS_rowMax
+ if ( col > KS_colMax || row > KS_rowMax )
+ {
+ kdDebug(36001) << "Canvas::mouseMoveEvent: col or row is out of range: "
+ << "col: " << col << " row: " << row << endl;
+ return;
+ }
+
+
+ //*** Highlighted Range Resize Handling ***
+ if (d->mouseAction == ResizeSelection)
+ {
+ choice()->update(QPoint(col,row));
+ return;
+ }
+
+ //Check to see if the mouse is over a highlight range size grip and if it is, change the cursor
+ //shape to a resize arrow
+ if (highlightRangeSizeGripAt(ev_PosX,ev_PosY))
+ {
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ setCursor( sizeBDiagCursor );
+ else
+ setCursor( sizeFDiagCursor );
+ return;
+ }
+
+ QRect rct( (d->chooseCell ? choice() : selectionInfo())->lastRange() );
+
+ QRect r1;
+ QRect r2;
+
+ double lx = sheet->dblColumnPos( rct.left() );
+ double rx = sheet->dblColumnPos( rct.right() + 1 );
+ double ty = sheet->dblRowPos( rct.top() );
+ double by = sheet->dblRowPos( rct.bottom() + 1 );
+
+ r1.setLeft( (int) (lx - 1) );
+ r1.setTop( (int) (ty - 1) );
+ r1.setRight( (int) (rx + 1) );
+ r1.setBottom( (int) (by + 1) );
+
+ r2.setLeft( (int) (lx + 1) );
+ r2.setTop( (int) (ty + 1) );
+ r2.setRight( (int) (rx - 1) );
+ r2.setBottom( (int) (by - 1) );
+
+ // Test whether the mouse is over some anchor
+ {
+ Cell *cell = sheet->visibleCellAt( col, row );
+ QString anchor;
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ anchor = cell->testAnchor( d->view->doc()->zoomItX( cell->dblWidth() - ev_PosX + xpos ),
+ d->view->doc()->zoomItY( ev_PosY - ypos ) );
+ }
+ else
+ {
+ anchor = cell->testAnchor( d->view->doc()->zoomItX( ev_PosX - xpos ),
+ d->view->doc()->zoomItY( ev_PosY - ypos ) );
+ }
+ if ( !anchor.isEmpty() && anchor != d->anchor )
+ {
+ setCursor( KCursor::handCursor() );
+ }
+
+ d->anchor = anchor;
+ }
+
+ // Test wether mouse is over the selection handle
+ QRect selectionHandle = d->view->selectionInfo()->selectionHandleArea();
+ if ( selectionHandle.contains( QPoint( d->view->doc()->zoomItX( ev_PosX ),
+ d->view->doc()->zoomItY( ev_PosY ) ) ) )
+ {
+ //If the cursor is over the handle, than it might be already on the next cell.
+ //Recalculate the cell!
+ col = sheet->leftColumn( ev_PosX - d->view->doc()->unzoomItX( 2 ), xpos );
+ row = sheet->topRow( ev_PosY - d->view->doc()->unzoomItY( 2 ), ypos );
+
+ if ( !sheet->isProtected() )
+ {
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ setCursor( sizeBDiagCursor );
+ else
+ setCursor( sizeFDiagCursor );
+ }
+ }
+ else if ( !d->anchor.isEmpty() )
+ {
+ if ( !sheet->isProtected() )
+ setCursor( KCursor::handCursor() );
+ }
+ else if ( r1.contains( QPoint( (int) ev_PosX, (int) ev_PosY ) )
+ && !r2.contains( QPoint( (int) ev_PosX, (int) ev_PosY ) ) )
+ {
+ setCursor( KCursor::handCursor() );
+ }
+ else if ( d->chooseCell )
+ {
+ //Visual cue to indicate that the user can drag-select the choice selection
+ setCursor( KCursor::crossCursor() );
+ }
+ else
+ {
+ //Nothing special is happening, use a normal arrow cursor
+ setCursor( arrowCursor );
+ }
+
+ // No marking, selecting etc. in progess? Then quit here.
+ if ( d->mouseAction == NoAction )
+ return;
+
+ // Set the new extent of the selection
+ (d->chooseCell ? choice() : selectionInfo())->update(QPoint(col,row));
+}
+
+void Canvas::mouseReleaseEvent( QMouseEvent* /*_ev*/)
+{
+ if ( d->scrollTimer->isActive() )
+ d->scrollTimer->stop();
+
+ d->mousePressed = false;
+ d->view->disableAutoScroll();
+
+ if ( d->modType != MT_NONE /*&& d->m_resizeObject && d->m_resizeObject->isSelected() */)
+ {
+ switch ( d->modType )
+ {
+ case MT_MOVE:
+ {
+ KoPoint move( objectRect( false ).topLeft() - d->m_moveStartPosMouse );
+ if ( move != KoPoint( 0, 0 ) )
+ {
+ KCommand *cmd= activeSheet()->moveObject( view(), move.x(), move.y() );
+ if(cmd)
+ doc()->addCommand( cmd );
+ } else
+ {
+ repaint();
+ }
+ d->m_isMoving = false;
+ break;
+ }
+ case MT_RESIZE_UP: case MT_RESIZE_LF: case MT_RESIZE_RT: case MT_RESIZE_LU: case MT_RESIZE_LD: case MT_RESIZE_RU: case MT_RESIZE_RD:
+ finishResizeObject( i18n("Resize Object") );
+ break;
+ case MT_RESIZE_DN:
+ finishResizeObject( i18n("Resize Object"), false );
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+
+ Sheet *sheet = activeSheet();
+ if ( !sheet )
+ return;
+
+ Selection* selectionInfo = d->view->selectionInfo();
+ QRect s( selectionInfo->lastRange() );
+
+ // The user started the drag in the lower right corner of the marker ?
+ if ( d->mouseAction == ResizeCell && !sheet->isProtected() )
+ {
+ sheet->mergeCells(selectionInfo->lastRange());
+ d->view->updateEditWidget();
+ }
+ else if ( d->mouseAction == AutoFill && !sheet->isProtected() )
+ {
+ QRect dest = s;
+ sheet->autofill( d->autoFillSource, dest );
+
+ d->view->updateEditWidget();
+ }
+ // The user started the drag in the middle of a cell ?
+ else if ( d->mouseAction == Mark && !d->chooseCell )
+ {
+ d->view->updateEditWidget();
+ }
+
+ d->mouseAction = NoAction;
+ d->dragging = false;
+ d->dragStart.setX( -1 );
+}
+
+void Canvas::processClickSelectionHandle( QMouseEvent *event )
+{
+ // Auto fill ? That is done using the left mouse button.
+ if ( event->button() == LeftButton )
+ {
+ d->mouseAction = AutoFill;
+ d->autoFillSource = selectionInfo()->lastRange();
+ }
+ // Resize a cell (done with the right mouse button) ?
+ // But for that to work there must not be a selection.
+ else if ( event->button() == MidButton && selectionInfo()->isSingular())
+ {
+ d->mouseAction = ResizeCell;
+ }
+
+ return;
+}
+
+void Canvas::processLeftClickAnchor()
+{
+ bool isRefLink = localReferenceAnchor( d->anchor );
+ bool isLocalLink = (d->anchor.find("file:") == 0);
+ if ( !isRefLink )
+ {
+ QString type=KMimeType::findByURL(d->anchor, 0, isLocalLink)->name();
+
+ if ( KRun::isExecutableFile( d->anchor , type ) )
+ {
+ //QString question = i18n("Do you want to open this link to '%1'?\n").arg(d->anchor);
+
+ //question += i18n("Note that opening a link to a local file may "
+ // "compromise your system's security.");
+
+ QString question = i18n("This link points to the program or script '%1'.\n"
+ "Malicious programs can harm your computer. Are you sure that you want to run this program?").arg(d->anchor);
+ // this will also start local programs, so adding a "don't warn again"
+ // checkbox will probably be too dangerous
+ int choice = KMessageBox::warningYesNo(this, question, i18n("Open Link?"));
+ if ( choice != KMessageBox::Yes )
+ {
+ return;
+ //(void) new KRun( d->anchor );
+ }
+ }
+
+ new KRun(d->anchor);
+ }
+ else
+ {
+ selectionInfo()->initialize(Region(d->view, d->anchor));
+ }
+}
+
+bool Canvas::highlightRangeSizeGripAt(double x, double y)
+{
+ if (!d->chooseCell)
+ return 0;
+
+ Region::ConstIterator end = choice()->constEnd();
+ for (Region::ConstIterator it = choice()->constBegin(); it != end; ++it)
+ {
+ // TODO Stefan: adapt to Selection::selectionHandleArea
+ KoRect visibleRect;
+ sheetAreaToRect((*it)->rect().normalize(), visibleRect);
+
+ QPoint bottomRight((int) visibleRect.right(), (int) visibleRect.bottom());
+ QRect handle( ( (int) bottomRight.x() - 6 ),
+ ( (int) bottomRight.y() - 6 ),
+ ( 6 ),
+ ( 6 ) );
+
+ if (handle.contains(QPoint((int) x,(int) y)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void Canvas::mousePressEvent( QMouseEvent * _ev )
+{
+ if ( _ev->button() == LeftButton )
+ {
+ d->mousePressed = true;
+ d->view->enableAutoScroll();
+ }
+
+ if ( activeSheet() && _ev->button() == LeftButton)
+ {
+ d->m_moveStartPosMouse = objectRect( false ).topLeft();
+ EmbeddedObject *obj = getObject( _ev->pos(), activeSheet() );
+
+ if ( obj )
+ {
+ // use ctrl + Button to select / deselect object
+ if ( _ev->state() & ControlButton && obj->isSelected() )
+ deselectObject( obj );
+ else if ( _ev->state() & ControlButton )
+ {
+ if ( d->modType == MT_NONE)
+ return;
+
+ selectObject( obj );
+ raiseObject( obj );
+ d->m_moveStartPosMouse = objectRect( false ).topLeft();
+ }
+ else
+ {
+ if ( d->modType != MT_MOVE || !obj->isSelected() )
+ deselectAllObjects();
+
+ selectObject( obj );
+
+ raiseObject( obj );
+ d->m_moveStartPosMouse = objectRect( false ).topLeft();
+ }
+
+ // start resizing
+ if ( d->modType != MT_MOVE && d->modType != MT_NONE && !obj->isProtect() )
+ {
+ deselectAllObjects();
+ selectObject( obj );
+ raiseObject( obj );
+
+ d->m_resizeObject = obj;
+
+ d->m_ratio = static_cast<double>( obj->geometry().width() ) /
+ static_cast<double>( obj->geometry().height() );
+ d->m_rectBeforeResize = obj->geometry();
+ }
+
+ KoPoint docPoint ( doc()->unzoomPoint( _ev->pos() ) );
+ docPoint += KoPoint( xOffset(), yOffset() );
+ d->m_origMousePos = docPoint;
+ d->m_moveStartPosMouse = objectRect( false ).topLeft();
+ return;
+ }
+ else
+ {
+ d->modType = MT_NONE;
+ if ( !( _ev->state() & ShiftButton ) && !( _ev->state() & ControlButton ) )
+ deselectAllObjects();
+ }
+ }
+
+ // Get info about where the event occurred - this is duplicated
+ // in ::mouseMoveEvent, needs to be separated into one function
+ Sheet *sheet = activeSheet();
+ if ( !sheet )
+ {
+ return;
+ }
+
+ double dwidth = d->view->doc()->unzoomItX( width() );
+ double ev_PosX;
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ ev_PosX = dwidth - d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
+ }
+ else
+ {
+ ev_PosX = d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
+ }
+ double ev_PosY = d->view->doc()->unzoomItY( _ev->pos().y() ) + yOffset();
+
+ // In which cell did the user click ?
+ double xpos;
+ double ypos;
+ int col = sheet->leftColumn( ev_PosX, xpos );
+ int row = sheet->topRow( ev_PosY, ypos );
+ // you cannot move marker when col > KS_colMax or row > KS_rowMax
+ if ( col > KS_colMax || row > KS_rowMax )
+ {
+ kdDebug(36001) << "Canvas::mousePressEvent: col or row is out of range: "
+ << "col: " << col << " row: " << row << endl;
+ return;
+ }
+
+ // you cannot move marker when col > KS_colMax or row > KS_rowMax
+ if ( col > KS_colMax || row > KS_rowMax )
+ {
+ kdDebug(36001) << "Canvas::mousePressEvent: col or row is out of range: "
+ << "col: " << col << " row: " << row << endl;
+ return;
+ }
+
+ if (d->chooseCell && highlightRangeSizeGripAt(ev_PosX,ev_PosY))
+ {
+ choice()->setActiveElement(QPoint(col,row));
+ d->mouseAction = ResizeSelection;
+ return;
+ }
+
+ // We were editing a cell -> save value and get out of editing mode
+ if ( d->cellEditor && !d->chooseCell )
+ {
+ deleteEditor( true ); // save changes
+ }
+
+ d->scrollTimer->start( 50 );
+
+ // Did we click in the lower right corner of the marker/marked-area ?
+ if ( selectionInfo()->selectionHandleArea().contains( QPoint( d->view->doc()->zoomItX( ev_PosX ),
+ d->view->doc()->zoomItY( ev_PosY ) ) ) )
+ {
+ processClickSelectionHandle( _ev );
+ return;
+ }
+
+
+ // TODO Stefan: adapt to non-cont. selection
+ {
+ // start drag ?
+ QRect rct( selectionInfo()->lastRange() );
+
+ QRect r1;
+ QRect r2;
+ {
+ double lx = sheet->dblColumnPos( rct.left() );
+ double rx = sheet->dblColumnPos( rct.right() + 1 );
+ double ty = sheet->dblRowPos( rct.top() );
+ double by = sheet->dblRowPos( rct.bottom() + 1 );
+
+ r1.setLeft( (int) (lx - 1) );
+ r1.setTop( (int) (ty - 1) );
+ r1.setRight( (int) (rx + 1) );
+ r1.setBottom( (int) (by + 1) );
+
+ r2.setLeft( (int) (lx + 1) );
+ r2.setTop( (int) (ty + 1) );
+ r2.setRight( (int) (rx - 1) );
+ r2.setBottom( (int) (by - 1) );
+ }
+
+ d->dragStart.setX( -1 );
+
+ if ( r1.contains( QPoint( (int) ev_PosX, (int) ev_PosY ) )
+ && !r2.contains( QPoint( (int) ev_PosX, (int) ev_PosY ) ) )
+ {
+ d->dragStart.setX( (int) ev_PosX );
+ d->dragStart.setY( (int) ev_PosY );
+
+ return;
+ }
+ }
+
+ // kdDebug() << "Clicked in cell " << col << ", " << row << endl;
+
+ // Extending an existing selection with the shift button ?
+ if ((_ev->state() & ShiftButton) &&
+ d->view->koDocument()->isReadWrite() &&
+ !selectionInfo()->isColumnOrRowSelected())
+ {
+ (d->chooseCell ? choice() : selectionInfo())->update(QPoint(col,row));
+ return;
+ }
+
+
+ // Go to the upper left corner of the obscuring object if cells are merged
+ Cell *cell = sheet->cellAt( col, row );
+ if (cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ col = cell->column();
+ row = cell->row();
+ }
+
+ switch (_ev->button())
+ {
+ case LeftButton:
+ if (!d->anchor.isEmpty())
+ {
+ // Hyperlink pressed
+ processLeftClickAnchor();
+ }
+#ifdef NONCONTIGUOUSSELECTION
+ else if ( _ev->state() & ControlButton )
+ {
+ if (d->chooseCell)
+ {
+#if 0 // TODO Stefan: remove for NCS of choices
+ // Start a marking action
+ d->mouseAction = Mark;
+ // extend the existing selection
+ choice()->extend(QPoint(col,row), activeSheet());
+#endif
+ }
+ else
+ {
+ // Start a marking action
+ d->mouseAction = Mark;
+ // extend the existing selection
+ selectionInfo()->extend(QPoint(col,row), activeSheet());
+ }
+// TODO Stefan: simplification, if NCS of choices is working
+/* (d->chooseCell ? choice() : selectionInfo())->extend(QPoint(col,row), activeSheet());*/
+ }
+#endif
+ else
+ {
+ // Start a marking action
+ d->mouseAction = Mark;
+ // reinitialize the selection
+ (d->chooseCell ? choice() : selectionInfo())->initialize(QPoint(col,row), activeSheet());
+ }
+ break;
+ case MidButton:
+ // Paste operation with the middle button?
+ if ( d->view->koDocument()->isReadWrite() && !sheet->isProtected() )
+ {
+ (d->chooseCell ? choice() : selectionInfo())->initialize( QPoint( col, row ), activeSheet() );
+ sheet->paste(selectionInfo()->lastRange(), true, Paste::Normal,
+ Paste::OverWrite, false, 0, false, QClipboard::Selection);
+ sheet->setRegionPaintDirty(*selectionInfo());
+ }
+ break;
+ case RightButton:
+ if (!selectionInfo()->contains( QPoint( col, row ) ))
+ {
+ // No selection or the mouse press was outside of an existing selection?
+ (d->chooseCell ? choice() : selectionInfo())->initialize(QPoint(col,row), activeSheet());
+ }
+ break;
+ default:
+ break;
+ }
+
+ scrollToCell(selectionInfo()->marker());
+ if ( !d->chooseCell )
+ {
+ d->view->updateEditWidgetOnPress();
+ }
+ updatePosWidget();
+
+ // Context menu?
+ if ( _ev->button() == RightButton )
+ {
+ // TODO: Handle anchor // TODO Stefan: ???
+ QPoint p = mapToGlobal( _ev->pos() );
+ d->view->openPopupMenu( p );
+ }
+}
+
+void Canvas::startTheDrag()
+{
+ Sheet * sheet = activeSheet();
+ if ( !sheet )
+ return;
+
+ // right area for start dragging
+ TextDrag * d = new TextDrag( this );
+ setCursor( KCursor::handCursor() );
+
+ QDomDocument doc = sheet->saveCellRegion(*selectionInfo());
+
+ // Save to buffer
+ QBuffer buffer;
+ buffer.open( IO_WriteOnly );
+ QTextStream str( &buffer );
+ str.setEncoding( QTextStream::UnicodeUTF8 );
+ str << doc;
+ buffer.close();
+
+ d->setPlain( sheet->copyAsText( selectionInfo() ) );
+ d->setKSpread( buffer.buffer() );
+
+ d->dragCopy();
+ setCursor( KCursor::arrowCursor() );
+}
+
+void Canvas::mouseDoubleClickEvent( QMouseEvent* _ev)
+{
+
+ EmbeddedObject *obj;
+ if ( ( obj = getObject( _ev->pos(), activeSheet() ) ) )
+ {
+ switch ( obj->getType() )
+ {
+ case OBJECT_KOFFICE_PART: case OBJECT_CHART:
+ {
+ dynamic_cast<EmbeddedKOfficeObject*>(obj)->activate( view(), this );
+ return;
+ break;
+ }
+ default:
+ {
+ view()->extraProperties();
+ return;
+ break;
+ }
+ }
+ }
+
+ if ( d->view->koDocument()->isReadWrite() && activeSheet() )
+ createEditor(true);
+}
+
+void Canvas::wheelEvent( QWheelEvent* _ev )
+{
+ if ( _ev->orientation() == Qt::Vertical )
+ {
+ if ( vertScrollBar() )
+ QApplication::sendEvent( vertScrollBar(), _ev );
+ }
+ else if ( horzScrollBar() )
+ {
+ QApplication::sendEvent( horzScrollBar(), _ev );
+ }
+}
+
+void Canvas::paintEvent( QPaintEvent* _ev )
+{
+ if ( d->view->doc()->isLoading() )
+ return;
+
+ Sheet* sheet = activeSheet();
+ if ( !sheet )
+ return;
+
+ // ElapsedTime et( "Canvas::paintEvent" );
+
+ double dwidth = d->view->doc()->unzoomItX( width() );
+ KoRect rect = d->view->doc()->unzoomRect( _ev->rect() & QWidget::rect() );
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ rect.moveBy( -xOffset(), yOffset() );
+ else
+ rect.moveBy( xOffset(), yOffset() );
+
+ KoPoint tl = rect.topLeft();
+ KoPoint br = rect.bottomRight();
+
+ double tmp;
+ int left_col;
+ int right_col;
+ //Philipp: I don't know why we need the +1, but otherwise we don't get it correctly
+ //Testcase: Move a dialog slowly up left. Sometimes the top/left most points are not painted
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ right_col = sheet->leftColumn( dwidth - tl.x(), tmp );
+ left_col = sheet->rightColumn( dwidth - br.x() + 1.0 );
+ }
+ else
+ {
+ left_col = sheet->leftColumn( tl.x(), tmp );
+ right_col = sheet->rightColumn( br.x() + 1.0 );
+ }
+ int top_row = sheet->topRow( tl.y(), tmp );
+ int bottom_row = sheet->bottomRow( br.y() + 1.0 );
+
+ QRect vr( QPoint(left_col, top_row),
+ QPoint(right_col, bottom_row) );
+ d->view->doc()->emitBeginOperation( false );
+ sheet->setRegionPaintDirty( vr );
+ d->view->doc()->emitEndOperation( vr );
+}
+
+void Canvas::focusInEvent( QFocusEvent* )
+{
+ if ( !d->cellEditor )
+ return;
+
+ //kdDebug(36001) << "d->chooseCell : " << ( d->chooseCell ? "true" : "false" ) << endl;
+ // If we are in editing mode, we redirect the
+ // focus to the CellEditor or EditWidget
+ // And we know which, using lastEditorWithFocus.
+ // This screws up <Tab> though (David)
+ if ( lastEditorWithFocus() == EditWidget )
+ {
+ d->editWidget->setFocus();
+ //kdDebug(36001) << "Focus to EditWidget" << endl;
+ return;
+ }
+
+ //kdDebug(36001) << "Redirecting focus to editor" << endl;
+ d->cellEditor->setFocus();
+}
+
+void Canvas::focusOutEvent( QFocusEvent* )
+{
+ if ( d->scrollTimer->isActive() )
+ d->scrollTimer->stop();
+ d->mousePressed = false;
+ d->view->disableAutoScroll();
+}
+
+void Canvas::dragMoveEvent( QDragMoveEvent * _ev )
+{
+ Sheet * sheet = activeSheet();
+ if ( !sheet )
+ {
+ _ev->ignore();
+ return;
+ }
+
+ _ev->accept( TextDrag::canDecode( _ev ) );
+
+ double dwidth = d->view->doc()->unzoomItX( width() );
+ double xpos = sheet->dblColumnPos( selectionInfo()->lastRange().left() );
+ double ypos = sheet->dblRowPos( selectionInfo()->lastRange().top() );
+ double width = sheet->columnFormat( selectionInfo()->lastRange().left() )->dblWidth( this );
+ double height = sheet->rowFormat( selectionInfo()->lastRange().top() )->dblHeight( this );
+
+ QRect r1 ((int) xpos - 1, (int) ypos - 1, (int) width + 3, (int) height + 3);
+
+ double ev_PosX;
+ if (sheet->layoutDirection()==Sheet::RightToLeft)
+ ev_PosX = dwidth - d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
+ else
+ ev_PosX = d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
+
+ double ev_PosY = d->view->doc()->unzoomItY( _ev->pos().y() ) + yOffset();
+
+ if ( r1.contains( QPoint ((int) ev_PosX, (int) ev_PosY) ) )
+ _ev->ignore( r1 );
+}
+
+void Canvas::dragLeaveEvent( QDragLeaveEvent * )
+{
+ if ( d->scrollTimer->isActive() )
+ d->scrollTimer->stop();
+}
+
+void Canvas::dropEvent( QDropEvent * _ev )
+{
+ d->dragging = false;
+ if ( d->scrollTimer->isActive() )
+ d->scrollTimer->stop();
+ Sheet * sheet = activeSheet();
+ if ( !sheet || sheet->isProtected() )
+ {
+ _ev->ignore();
+ return;
+ }
+
+ double dwidth = d->view->doc()->unzoomItX( width() );
+ double xpos = sheet->dblColumnPos( selectionInfo()->lastRange().left() );
+ double ypos = sheet->dblRowPos( selectionInfo()->lastRange().top() );
+ double width = sheet->columnFormat( selectionInfo()->lastRange().left() )->dblWidth( this );
+ double height = sheet->rowFormat( selectionInfo()->lastRange().top() )->dblHeight( this );
+
+ QRect r1 ((int) xpos - 1, (int) ypos - 1, (int) width + 3, (int) height + 3);
+
+ double ev_PosX;
+ if (sheet->layoutDirection()==Sheet::RightToLeft)
+ ev_PosX = dwidth - d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
+ else
+ ev_PosX = d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
+
+ double ev_PosY = d->view->doc()->unzoomItY( _ev->pos().y() ) + yOffset();
+
+ if ( r1.contains( QPoint ((int) ev_PosX, (int) ev_PosY) ) )
+ {
+ _ev->ignore( );
+ return;
+ }
+ else
+ _ev->accept( );
+
+ double tmp;
+ int col = sheet->leftColumn( ev_PosX, tmp );
+ int row = sheet->topRow( ev_PosY, tmp );
+
+ if ( !TextDrag::canDecode( _ev ) )
+ {
+ _ev->ignore();
+ return;
+ }
+
+ QByteArray b;
+
+ bool makeUndo = true;
+
+ if ( _ev->provides( TextDrag::selectionMimeType() ) )
+ {
+ if ( TextDrag::target() == _ev->source() )
+ {
+ if ( !d->view->doc()->undoLocked() )
+ {
+ UndoDragDrop * undo
+ = new UndoDragDrop(d->view->doc(), sheet, *selectionInfo(),
+ QRect(col, row,
+ selectionInfo()->boundingRect().width(),
+ selectionInfo()->boundingRect().height()));
+ d->view->doc()->addCommand( undo );
+ makeUndo = false;
+ }
+ sheet->deleteSelection( selectionInfo(), false );
+ }
+
+
+ b = _ev->encodedData( TextDrag::selectionMimeType() );
+ sheet->paste( b, QRect( col, row, 1, 1 ), makeUndo );
+
+ if ( _ev->source() == this )
+ _ev->acceptAction();
+ _ev->accept();
+ }
+ else
+ {
+ QString text;
+ if ( !QTextDrag::decode( _ev, text ) )
+ {
+ _ev->ignore();
+ return;
+ }
+ // if ( TextDrag::target() == _ev->source() )
+ // sheet->deleteSelection( selectionInfo() );
+
+ sheet->pasteTextPlain( text, QRect( col, row, 1, 1 ) );
+ _ev->accept();
+ if ( _ev->source() == this )
+ _ev->acceptAction();
+
+ return;
+ }
+}
+
+void Canvas::resizeEvent( QResizeEvent* _ev )
+{
+ if (!activeSheet())
+ return;
+
+
+ double ev_Width = d->view->doc()->unzoomItX( _ev->size().width() );
+ double ev_Height = d->view->doc()->unzoomItY( _ev->size().height() );
+
+ // workaround to allow horizontal resizing and zoom changing when sheet
+ // direction and interface direction don't match (e.g. an RTL sheet on an
+ // LTR interface)
+ if ( activeSheet() && activeSheet()->layoutDirection()==Sheet::RightToLeft && !QApplication::reverseLayout() )
+ {
+ int dx = _ev->size().width() - _ev->oldSize().width();
+ scroll(dx, 0);
+ }
+ else if ( activeSheet() && activeSheet()->layoutDirection()==Sheet::LeftToRight && QApplication::reverseLayout() )
+ {
+ int dx = _ev->size().width() - _ev->oldSize().width();
+ scroll(-dx, 0);
+ }
+
+ // If we rise horizontally, then check if we are still within the valid area (KS_colMax)
+ if ( _ev->size().width() > _ev->oldSize().width() )
+ {
+ int oldValue = horzScrollBar()->maxValue() - horzScrollBar()->value();
+
+ if ( ( xOffset() + ev_Width ) >
+ d->view->doc()->zoomItX( activeSheet()->sizeMaxX() ) )
+ {
+ horzScrollBar()->setRange( 0, d->view->doc()->zoomItX( activeSheet()->sizeMaxX() - ev_Width ) );
+ if ( activeSheet()->layoutDirection()==Sheet::RightToLeft )
+ horzScrollBar()->setValue( horzScrollBar()->maxValue() - oldValue );
+ }
+ }
+ // If we lower vertically, then check if the range should represent the maximum range
+ else if ( _ev->size().width() < _ev->oldSize().width() )
+ {
+ int oldValue = horzScrollBar()->maxValue() - horzScrollBar()->value();
+
+ if ( horzScrollBar()->maxValue() ==
+ int( d->view->doc()->zoomItX( activeSheet()->sizeMaxX() ) - ev_Width ) )
+ {
+ horzScrollBar()->setRange( 0, d->view->doc()->zoomItX( activeSheet()->sizeMaxX() - ev_Width ) );
+ if ( activeSheet()->layoutDirection()==Sheet::RightToLeft )
+ horzScrollBar()->setValue( horzScrollBar()->maxValue() - oldValue );
+ }
+ }
+
+ // If we rise vertically, then check if we are still within the valid area (KS_rowMax)
+ if ( _ev->size().height() > _ev->oldSize().height() )
+ {
+ if ( ( yOffset() + ev_Height ) >
+ d->view->doc()->zoomItY( activeSheet()->sizeMaxY() ) )
+ {
+ vertScrollBar()->setRange( 0, d->view->doc()->zoomItY( activeSheet()->sizeMaxY() - ev_Height ) );
+ }
+ }
+ // If we lower vertically, then check if the range should represent the maximum range
+ else if ( _ev->size().height() < _ev->oldSize().height() )
+ {
+ if ( vertScrollBar()->maxValue() ==
+ int( d->view->doc()->zoomItY( activeSheet()->sizeMaxY() ) - ev_Height ) )
+ {
+ vertScrollBar()->setRange( 0, d->view->doc()->zoomItY( activeSheet()->sizeMaxY() - ev_Height ) );
+ }
+ }
+}
+
+QPoint Canvas::cursorPos()
+{
+ QPoint cursor;
+ if (d->chooseCell && !choice()->isEmpty())
+ cursor = choice()->cursor();
+ else
+ cursor = selectionInfo()->cursor();
+
+ return cursor;
+}
+
+QRect Canvas::moveDirection( KSpread::MoveTo direction, bool extendSelection )
+{
+ kdDebug(36001) << "Canvas::moveDirection" << endl;
+
+ QPoint destination;
+ QPoint cursor = cursorPos();
+
+ QPoint cellCorner = cursor;
+ Cell* cell = activeSheet()->cellAt(cursor.x(), cursor.y());
+
+ /* cell is either the same as the marker, or the cell that is forced obscuring
+ the marker cell
+ */
+ if (cell->isPartOfMerged())
+ {
+ cell = cell->obscuringCells().first();
+ cellCorner = QPoint(cell->column(), cell->row());
+ }
+
+ /* how many cells must we move to get to the next cell? */
+ int offset = 0;
+ RowFormat *rl = NULL;
+ ColumnFormat *cl = NULL;
+ switch (direction)
+ /* for each case, figure out how far away the next cell is and then keep
+ going one row/col at a time after that until a visible row/col is found
+
+ NEVER use cell->column() or cell->row() -- it might be a default cell
+ */
+ {
+ case Bottom:
+ offset = cell->mergedYCells() - (cursor.y() - cellCorner.y()) + 1;
+ rl = activeSheet()->rowFormat( cursor.y() + offset );
+ while ( ((cursor.y() + offset) <= KS_rowMax) && rl->isHide())
+ {
+ offset++;
+ rl = activeSheet()->rowFormat( cursor.y() + offset );
+ }
+
+ destination = QPoint(cursor.x(), QMIN(cursor.y() + offset, KS_rowMax));
+ break;
+ case Top:
+ offset = (cellCorner.y() - cursor.y()) - 1;
+ rl = activeSheet()->rowFormat( cursor.y() + offset );
+ while ( ((cursor.y() + offset) >= 1) && rl->isHide())
+ {
+ offset--;
+ rl = activeSheet()->rowFormat( cursor.y() + offset );
+ }
+ destination = QPoint(cursor.x(), QMAX(cursor.y() + offset, 1));
+ break;
+ case Left:
+ offset = (cellCorner.x() - cursor.x()) - 1;
+ cl = activeSheet()->columnFormat( cursor.x() + offset );
+ while ( ((cursor.x() + offset) >= 1) && cl->isHide())
+ {
+ offset--;
+ cl = activeSheet()->columnFormat( cursor.x() + offset );
+ }
+ destination = QPoint(QMAX(cursor.x() + offset, 1), cursor.y());
+ break;
+ case Right:
+ offset = cell->mergedXCells() - (cursor.x() - cellCorner.x()) + 1;
+ cl = activeSheet()->columnFormat( cursor.x() + offset );
+ while ( ((cursor.x() + offset) <= KS_colMax) && cl->isHide())
+ {
+ offset++;
+ cl = activeSheet()->columnFormat( cursor.x() + offset );
+ }
+ destination = QPoint(QMIN(cursor.x() + offset, KS_colMax), cursor.y());
+ break;
+ case BottomFirst:
+ offset = cell->mergedYCells() - (cursor.y() - cellCorner.y()) + 1;
+ rl = activeSheet()->rowFormat( cursor.y() + offset );
+ while ( ((cursor.y() + offset) <= KS_rowMax) && rl->isHide())
+ {
+ ++offset;
+ rl = activeSheet()->rowFormat( cursor.y() + offset );
+ }
+
+ destination = QPoint( 1, QMIN( cursor.y() + offset, KS_rowMax ) );
+ break;
+ }
+
+ if (extendSelection)
+ {
+ (d->chooseCell ? choice() : selectionInfo())->update(destination);
+ }
+ else
+ {
+ (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
+ }
+ d->view->updateEditWidget();
+
+ return QRect( cursor, destination );
+}
+
+void Canvas::processEnterKey(QKeyEvent* event)
+{
+ // array is true, if ctrl+alt are pressed
+ bool array = (event->state() & Qt::AltButton) &&
+ (event->state() & Qt::ControlButton);
+
+ /* save changes to the current editor */
+ if (!d->chooseCell)
+ {
+ deleteEditor(true, array);
+ }
+
+ /* use the configuration setting to see which direction we're supposed to move
+ when enter is pressed.
+ */
+ KSpread::MoveTo direction = d->view->doc()->getMoveToValue();
+
+ //if shift Button clicked inverse move direction
+ if (event->state() & Qt::ShiftButton)
+ {
+ switch( direction )
+ {
+ case Bottom:
+ direction = Top;
+ break;
+ case Top:
+ direction = Bottom;
+ break;
+ case Left:
+ direction = Right;
+ break;
+ case Right:
+ direction = Left;
+ break;
+ case BottomFirst:
+ direction = BottomFirst;
+ break;
+ }
+ }
+
+ /* never extend a selection with the enter key -- the shift key reverses
+ direction, not extends the selection
+ */
+ QRect r( moveDirection( direction, false ) );
+ d->view->doc()->emitEndOperation( r );
+}
+
+void Canvas::processArrowKey( QKeyEvent *event)
+{
+ /* NOTE: hitting the tab key also calls this function. Don't forget
+ to account for it
+ */
+
+ /* save changes to the current editor */
+ if (!d->chooseCell)
+ {
+ deleteEditor( true );
+ }
+
+ KSpread::MoveTo direction = Bottom;
+ bool makingSelection = event->state() & ShiftButton;
+
+ switch (event->key())
+ {
+ case Key_Down:
+ direction = Bottom;
+ break;
+ case Key_Up:
+ direction = Top;
+ break;
+ case Key_Left:
+ if (activeSheet()->layoutDirection()==Sheet::RightToLeft)
+ direction = Right;
+ else
+ direction = Left;
+ break;
+ case Key_Right:
+ if (activeSheet()->layoutDirection()==Sheet::RightToLeft)
+ direction = Left;
+ else
+ direction = Right;
+ break;
+ case Key_Tab:
+ direction = Right;
+ break;
+ case Key_Backtab:
+ //Shift+Tab moves to the left
+ direction = Left;
+ makingSelection = false;
+ break;
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ QRect r( moveDirection( direction, makingSelection ) );
+ d->view->doc()->emitEndOperation( r );
+}
+
+void Canvas::processEscapeKey(QKeyEvent * event)
+{
+ if ( d->cellEditor )
+ deleteEditor( false );
+
+ if ( view()->isInsertingObject() )
+ {
+ view()->resetInsertHandle();
+ setCursor( arrowCursor );
+ return;
+ }
+
+ event->accept(); // ?
+ QPoint cursor = cursorPos();
+
+ d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
+
+ if ( d->mousePressed /*&& toolEditMode == TEM_MOUSE */)
+ {
+ switch (d->modType)
+ {
+ case MT_RESIZE_UP:
+ case MT_RESIZE_DN:
+ case MT_RESIZE_LF:
+ case MT_RESIZE_RT:
+ case MT_RESIZE_LU:
+ case MT_RESIZE_LD:
+ case MT_RESIZE_RU:
+ case MT_RESIZE_RD:
+ {
+ QRect oldBoundingRect = doc()->zoomRect( d->m_resizeObject->geometry()/*getRepaintRect()*/);
+ d->m_resizeObject->setGeometry( d->m_rectBeforeResize );
+ oldBoundingRect.moveBy( (int)( -xOffset()*doc()->zoomedResolutionX() ) ,
+ (int)( -yOffset() * doc()->zoomedResolutionY()) );
+
+ activeSheet()->setRegionPaintDirty( oldBoundingRect );
+ repaint( oldBoundingRect );
+ repaintObject( d->m_resizeObject );
+ d->m_ratio = 0.0;
+ d->m_resizeObject = 0;
+ d->m_isResizing = false;
+ view()->disableAutoScroll();
+ d->mousePressed = false;
+ d->modType = MT_NONE;
+ break;
+ }
+ case MT_MOVE:
+ {
+ if ( d->m_isMoving )
+ {
+ KoPoint move( d->m_moveStartPoint - objectRect( false ).topLeft() );
+ activeSheet()->moveObject( view(), move, false );
+ view()->disableAutoScroll();
+ d->mousePressed = false;
+ d->modType = MT_NONE;
+ d->m_isMoving = false;
+ update();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+bool Canvas::processHomeKey(QKeyEvent* event)
+{
+ bool makingSelection = event->state() & ShiftButton;
+ Sheet* sheet = activeSheet();
+
+ if ( d->cellEditor )
+ // We are in edit mode -> go beginning of line
+ {
+ QApplication::sendEvent( d->editWidget, event );
+ return false;
+ }
+ else
+ {
+ QPoint destination;
+ /* start at the first used cell in the row and cycle through the right until
+ we find a cell that has some output text. But don't look past the current
+ marker.
+ The end result we want is to move to the left to the first cell with text,
+ or just to the first column if there is no more text to the left.
+
+ But why? In excel, home key sends you to the first column always.
+ We might want to change to that behavior.
+ */
+
+ if (event->state() & ControlButton)
+ {
+ /* ctrl + Home will always just send us to location (1,1) */
+ destination = QPoint( 1, 1 );
+ }
+ else
+ {
+ QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
+
+ Cell * cell = sheet->getFirstCellRow(marker.y());
+ while (cell != NULL && cell->column() < marker.x() && cell->isEmpty())
+ {
+ cell = sheet->getNextCellRight(cell->column(), cell->row());
+ }
+
+ int col = ( cell ? cell->column() : 1 );
+ if ( col == marker.x())
+ col = 1;
+ destination = QPoint(col, marker.y());
+ }
+
+ if ( selectionInfo()->marker() == destination )
+ {
+ d->view->doc()->emitEndOperation( QRect( destination, destination ) );
+ return false;
+ }
+
+ if (makingSelection)
+ {
+ (d->chooseCell ? choice() : selectionInfo())->update(destination);
+ }
+ else
+ {
+ (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
+ }
+ }
+ return true;
+}
+
+bool Canvas::processEndKey( QKeyEvent *event )
+{
+ bool makingSelection = event->state() & ShiftButton;
+ Sheet* sheet = activeSheet();
+ Cell* cell = NULL;
+ QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
+
+ // move to the last used cell in the row
+ // We are in edit mode -> go beginning of line
+ if ( d->cellEditor )
+ {
+ QApplication::sendEvent( d->editWidget, event );
+ d->view->doc()->emitEndOperation( QRect( marker, marker ) );
+ return false;
+ }
+ else
+ {
+ int col = 1;
+
+ cell = sheet->getLastCellRow(marker.y());
+ while (cell != NULL && cell->column() > markerColumn() && cell->isEmpty())
+ {
+ cell = sheet->getNextCellLeft(cell->column(), cell->row());
+ }
+
+ col = (cell == NULL) ? KS_colMax : cell->column();
+
+ QPoint destination( col, marker.y() );
+ if ( destination == marker )
+ {
+ d->view->doc()->emitEndOperation( QRect( destination, destination ) );
+ return false;
+ }
+
+ if (makingSelection)
+ {
+ (d->chooseCell ? choice() : selectionInfo())->update(destination);
+ }
+ else
+ {
+ (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
+ }
+ }
+ return true;
+}
+
+bool Canvas::processPriorKey(QKeyEvent *event)
+{
+ bool makingSelection = event->state() & ShiftButton;
+ if (!d->chooseCell)
+ {
+ deleteEditor( true );
+ }
+
+ QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
+
+ QPoint destination(marker.x(), QMAX(1, marker.y() - 10));
+ if ( destination == marker )
+ {
+ d->view->doc()->emitEndOperation( QRect( destination, destination ) );
+ return false;
+ }
+
+ if (makingSelection)
+ {
+ (d->chooseCell ? choice() : selectionInfo())->update(destination);
+ }
+ else
+ {
+ (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
+ }
+ return true;
+}
+
+bool Canvas::processNextKey(QKeyEvent *event)
+{
+ bool makingSelection = event->state() & ShiftButton;
+
+ if (!d->chooseCell)
+ {
+ deleteEditor( true /*save changes*/ );
+ }
+
+ QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
+ QPoint destination(marker.x(), QMAX(1, marker.y() + 10));
+
+ if ( marker == destination )
+ {
+ d->view->doc()->emitEndOperation( QRect( destination, destination ) );
+ return false;
+ }
+
+ if (makingSelection)
+ {
+ (d->chooseCell ? choice() : selectionInfo())->update(destination);
+ }
+ else
+ {
+ (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
+ }
+ return true;
+}
+
+void Canvas::processDeleteKey(QKeyEvent* /* event */)
+{
+ if ( isObjectSelected() )
+ {
+ d->view->doc()->emitEndOperation( activeSheet()->visibleRect( this ) );
+ d->view->deleteSelectedObjects();
+ return;
+ }
+
+ activeSheet()->clearTextSelection( selectionInfo() );
+ d->editWidget->setText( "" );
+
+ QPoint cursor = cursorPos();
+
+ d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
+ return;
+}
+
+void Canvas::processF2Key(QKeyEvent* /* event */)
+{
+ d->editWidget->setFocus();
+ if ( d->cellEditor )
+ d->editWidget->setCursorPosition( d->cellEditor->cursorPosition() - 1 );
+ d->editWidget->cursorForward( false );
+
+
+ QPoint cursor = cursorPos();
+
+ d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
+ return;
+}
+
+void Canvas::processF4Key(QKeyEvent* event)
+{
+ /* passes F4 to the editor (if any), which will process it
+ */
+ if ( d->cellEditor )
+ {
+ d->cellEditor->handleKeyPressEvent( event );
+// d->editWidget->setFocus();
+ d->editWidget->setCursorPosition( d->cellEditor->cursorPosition() );
+ }
+ QPoint cursor = cursorPos();
+
+ d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
+ return;
+}
+
+void Canvas::processOtherKey(QKeyEvent *event)
+{
+ // No null character ...
+ if ( event->text().isEmpty() || !d->view->koDocument()->isReadWrite()
+ || !activeSheet() || activeSheet()->isProtected() )
+ {
+ event->accept();
+ }
+ else
+ {
+ if ( !d->cellEditor && !d->chooseCell )
+ {
+ // Switch to editing mode
+ createEditor( CellEditor );
+ d->cellEditor->handleKeyPressEvent( event );
+ }
+ else if ( d->cellEditor )
+ d->cellEditor->handleKeyPressEvent( event );
+ }
+
+ QPoint cursor = cursorPos();
+
+ d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
+
+ return;
+}
+
+bool Canvas::processControlArrowKey( QKeyEvent *event )
+{
+ bool makingSelection = event->state() & ShiftButton;
+
+ Sheet* sheet = activeSheet();
+ Cell* cell = NULL;
+ Cell* lastCell;
+ QPoint destination;
+ bool searchThroughEmpty = true;
+ int row;
+ int col;
+
+ QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
+
+ /* here, we want to move to the first or last cell in the given direction that is
+ actually being used. Ignore empty cells and cells on hidden rows/columns */
+ switch ( event->key() )
+ {
+ //Ctrl+Key_Up
+ case Key_Up:
+
+ cell = sheet->cellAt( marker.x(), marker.y() );
+ if ( (cell != NULL) && (!cell->isEmpty()) && (marker.y() != 1))
+ {
+ lastCell = cell;
+ row = marker.y()-1;
+ cell = sheet->cellAt(cell->column(), row);
+ while ((cell != NULL) && (row > 0) && (!cell->isEmpty()) )
+ {
+ if (!(sheet->rowFormat(cell->row())->isHide()))
+ {
+ lastCell = cell;
+ searchThroughEmpty = false;
+ }
+ row--;
+ if ( row > 0 )
+ cell = sheet->cellAt(cell->column(), row);
+ }
+ cell = lastCell;
+ }
+ if (searchThroughEmpty)
+ {
+ cell = sheet->getNextCellUp(marker.x(), marker.y());
+
+ while ((cell != NULL) &&
+ (cell->isEmpty() || (sheet->rowFormat(cell->row())->isHide())))
+ {
+ cell = sheet->getNextCellUp(cell->column(), cell->row());
+ }
+ }
+
+ if (cell == NULL)
+ row = 1;
+ else
+ row = cell->row();
+
+ while ( sheet->rowFormat(row)->isHide() )
+ {
+ row++;
+ }
+
+ destination.setX(marker.x());
+ destination.setY(row);
+ break;
+
+ //Ctrl+Key_Down
+ case Key_Down:
+
+ cell = sheet->cellAt( marker.x(), marker.y() );
+ if ( (cell != NULL) && (!cell->isEmpty()) && (marker.y() != KS_rowMax))
+ {
+ lastCell = cell;
+ row = marker.y()+1;
+ cell = sheet->cellAt(cell->column(), row);
+ while ((cell != NULL) && (row < KS_rowMax) && (!cell->isEmpty()) )
+ {
+ if (!(sheet->rowFormat(cell->row())->isHide()))
+ {
+ lastCell = cell;
+ searchThroughEmpty = false;
+ }
+ row++;
+ cell = sheet->cellAt(cell->column(), row);
+ }
+ cell = lastCell;
+ }
+ if (searchThroughEmpty)
+ {
+ cell = sheet->getNextCellDown(marker.x(), marker.y());
+
+ while ((cell != NULL) &&
+ (cell->isEmpty() || (sheet->rowFormat(cell->row())->isHide())))
+ {
+ cell = sheet->getNextCellDown(cell->column(), cell->row());
+ }
+ }
+
+ if (cell == NULL)
+ row = marker.y();
+ else
+ row = cell->row();
+
+ while ( sheet->rowFormat(row)->isHide() )
+ {
+ row--;
+ }
+
+ destination.setX(marker.x());
+ destination.setY(row);
+ break;
+
+ //Ctrl+Key_Left
+ case Key_Left:
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ cell = sheet->cellAt( marker.x(), marker.y() );
+ if ( (cell != NULL) && (!cell->isEmpty()) && (marker.x() != KS_colMax))
+ {
+ lastCell = cell;
+ col = marker.x()+1;
+ cell = sheet->cellAt(col, cell->row());
+ while ((cell != NULL) && (col < KS_colMax) && (!cell->isEmpty()) )
+ {
+ if (!(sheet->columnFormat(cell->column())->isHide()))
+ {
+ lastCell = cell;
+ searchThroughEmpty = false;
+ }
+ col++;
+ cell = sheet->cellAt(col, cell->row());
+ }
+ cell = lastCell;
+ }
+ if (searchThroughEmpty)
+ {
+ cell = sheet->getNextCellRight(marker.x(), marker.y());
+
+ while ((cell != NULL) &&
+ (cell->isEmpty() || (sheet->columnFormat(cell->column())->isHide())))
+ {
+ cell = sheet->getNextCellRight(cell->column(), cell->row());
+ }
+ }
+
+ if (cell == NULL)
+ col = marker.x();
+ else
+ col = cell->column();
+
+ while ( sheet->columnFormat(col)->isHide() )
+ {
+ col--;
+ }
+
+ destination.setX(col);
+ destination.setY(marker.y());
+ }
+ else
+ {
+ cell = sheet->cellAt( marker.x(), marker.y() );
+ if ( (cell != NULL) && (!cell->isEmpty()) && (marker.x() != 1))
+ {
+ lastCell = cell;
+ col = marker.x()-1;
+ cell = sheet->cellAt(col, cell->row());
+ while ((cell != NULL) && (col > 0) && (!cell->isEmpty()) )
+ {
+ if (!(sheet->columnFormat(cell->column())->isHide()))
+ {
+ lastCell = cell;
+ searchThroughEmpty = false;
+ }
+ col--;
+ if ( col > 0 )
+ cell = sheet->cellAt(col, cell->row());
+ }
+ cell = lastCell;
+ }
+ if (searchThroughEmpty)
+ {
+ cell = sheet->getNextCellLeft(marker.x(), marker.y());
+
+ while ((cell != NULL) &&
+ (cell->isEmpty() || (sheet->columnFormat(cell->column())->isHide())))
+ {
+ cell = sheet->getNextCellLeft(cell->column(), cell->row());
+ }
+ }
+
+ if (cell == NULL)
+ col = 1;
+ else
+ col = cell->column();
+
+ while ( sheet->columnFormat(col)->isHide() )
+ {
+ col++;
+ }
+
+ destination.setX(col);
+ destination.setY(marker.y());
+ }
+ break;
+
+ //Ctrl+Key_Right
+ case Key_Right:
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ cell = sheet->cellAt( marker.x(), marker.y() );
+ if ( (cell != NULL) && (!cell->isEmpty()) && (marker.x() != 1))
+ {
+ lastCell = cell;
+ col = marker.x()-1;
+ cell = sheet->cellAt(col, cell->row());
+ while ((cell != NULL) && (col > 0) && (!cell->isEmpty()) )
+ {
+ if (!(sheet->columnFormat(cell->column())->isHide()))
+ {
+ lastCell = cell;
+ searchThroughEmpty = false;
+ }
+ col--;
+ if ( col > 0 )
+ cell = sheet->cellAt(col, cell->row());
+ }
+ cell = lastCell;
+ }
+ if (searchThroughEmpty)
+ {
+ cell = sheet->getNextCellLeft(marker.x(), marker.y());
+
+ while ((cell != NULL) &&
+ (cell->isEmpty() || (sheet->columnFormat(cell->column())->isHide())))
+ {
+ cell = sheet->getNextCellLeft(cell->column(), cell->row());
+ }
+ }
+
+ if (cell == NULL)
+ col = 1;
+ else
+ col = cell->column();
+
+ while ( sheet->columnFormat(col)->isHide() )
+ {
+ col++;
+ }
+
+ destination.setX(col);
+ destination.setY(marker.y());
+ }
+ else
+ {
+ cell = sheet->cellAt( marker.x(), marker.y() );
+ if ( (cell != NULL) && (!cell->isEmpty()) && (marker.x() != KS_colMax))
+ {
+ lastCell = cell;
+ col = marker.x()+1;
+ cell = sheet->cellAt(col, cell->row());
+ while ((cell != NULL) && (col < KS_colMax) && (!cell->isEmpty()) )
+ {
+ if (!(sheet->columnFormat(cell->column())->isHide()))
+ {
+ lastCell = cell;
+ searchThroughEmpty = false;
+ }
+ col++;
+ cell = sheet->cellAt(col, cell->row());
+ }
+ cell = lastCell;
+ }
+ if (searchThroughEmpty)
+ {
+ cell = sheet->getNextCellRight(marker.x(), marker.y());
+
+ while ((cell != NULL) &&
+ (cell->isEmpty() || (sheet->columnFormat(cell->column())->isHide())))
+ {
+ cell = sheet->getNextCellRight(cell->column(), cell->row());
+ }
+ }
+
+ if (cell == NULL)
+ col = marker.x();
+ else
+ col = cell->column();
+
+ while ( sheet->columnFormat(col)->isHide() )
+ {
+ col--;
+ }
+
+ destination.setX(col);
+ destination.setY(marker.y());
+ }
+ break;
+
+ }
+
+ if ( marker == destination )
+ {
+ d->view->doc()->emitEndOperation( QRect( destination, destination ) );
+ return false;
+ }
+
+ if (makingSelection)
+ {
+ (d->chooseCell ? choice() : selectionInfo())->update(destination);
+ }
+ else
+ {
+ (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
+ }
+ return true;
+}
+
+
+void Canvas::keyPressEvent ( QKeyEvent * _ev )
+{
+ Sheet * sheet = activeSheet();
+
+ if ( !sheet || formatKeyPress( _ev ))
+ return;
+
+ // Dont handle the remaining special keys.
+ if ( _ev->state() & ( Qt::AltButton | Qt::ControlButton ) &&
+ (_ev->key() != Key_Down) &&
+ (_ev->key() != Key_Up) &&
+ (_ev->key() != Key_Right) &&
+ (_ev->key() != Key_Left) &&
+ (_ev->key() != Key_Home) &&
+ (_ev->key() != Key_Enter) &&
+ (_ev->key() != Key_Return) &&
+ (_ev->key() != KGlobalSettings::contextMenuKey()))
+ {
+ QWidget::keyPressEvent( _ev );
+ return;
+ }
+
+ // Always accept so that events are not
+ // passed to the parent.
+ _ev->accept();
+
+ d->view->doc()->emitBeginOperation(false);
+ if ( _ev->key() == KGlobalSettings::contextMenuKey() ) {
+ int row = markerRow();
+ int col = markerColumn();
+ KoPoint kop(sheet->columnPos(col, this), sheet->rowPos(row, this));
+ QPoint p = d->view->doc()->zoomPoint(kop);
+ p = mapToGlobal(p);
+ d->view->openPopupMenu( p );
+ }
+ switch( _ev->key() )
+ {
+ case Key_Return:
+ case Key_Enter:
+ processEnterKey( _ev );
+ return;
+ break;
+ case Key_Down:
+ case Key_Up:
+ case Key_Left:
+ case Key_Right:
+ case Key_Tab: /* a tab behaves just like a right/left arrow */
+ case Key_Backtab: /* and so does Shift+Tab */
+ if (_ev->state() & ControlButton)
+ {
+ if ( !processControlArrowKey( _ev ) )
+ return;
+ }
+ else
+ {
+ processArrowKey( _ev );
+ return;
+ }
+ break;
+
+ case Key_Escape:
+ processEscapeKey( _ev );
+ return;
+ break;
+
+ case Key_Home:
+ if ( !processHomeKey( _ev ) )
+ return;
+ break;
+
+ case Key_End:
+ if ( !processEndKey( _ev ) )
+ return;
+ break;
+
+ case Key_Prior: /* Page Up */
+ if ( !processPriorKey( _ev ) )
+ return;
+ break;
+
+ case Key_Next: /* Page Down */
+ if ( !processNextKey( _ev ) )
+ return;
+ break;
+
+ case Key_Delete:
+ processDeleteKey( _ev );
+ return;
+ break;
+
+ case Key_F2:
+ processF2Key( _ev );
+ return;
+ break;
+
+ case Key_F4:
+ processF4Key( _ev );
+ return;
+ break;
+
+ default:
+ processOtherKey( _ev );
+ return;
+ break;
+ }
+
+ //most process*Key methods call emitEndOperation, this only gets called in some situations
+ // (after some move operations)
+ d->view->doc()->emitEndOperation( sheet->visibleRect( this ) );
+ return;
+}
+
+void Canvas::processIMEvent( QIMEvent * event )
+{
+ d->view->doc()->emitBeginOperation( false );
+ if ( !d->cellEditor && !d->chooseCell )
+ {
+ // Switch to editing mode
+ createEditor( CellEditor );
+ d->cellEditor->handleIMEvent( event );
+ }
+
+ QPoint cursor;
+
+ if ( d->chooseCell )
+ {
+ cursor = choice()->cursor();
+ /* if the cursor is unset, pretend we're starting at the regular cursor */
+ if (cursor.x() == 0 || cursor.y() == 0)
+ cursor = choice()->cursor();
+ }
+ else
+ cursor = selectionInfo()->cursor();
+
+ d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
+}
+
+bool Canvas::formatKeyPress( QKeyEvent * _ev )
+{
+ if (!(_ev->state() & ControlButton ))
+ return false;
+
+ int key = _ev->key();
+ if ( key != Key_Exclam && key != Key_At && key != Key_Ampersand
+ && key != Key_Dollar && key != Key_Percent && key != Key_AsciiCircum
+ && key != Key_NumberSign )
+ return false;
+
+ Cell * cell = 0L;
+ Sheet * sheet = activeSheet();
+
+ d->view->doc()->emitBeginOperation(false);
+
+ if ( !d->view->doc()->undoLocked() )
+ {
+ QString dummy;
+ UndoCellFormat * undo = new UndoCellFormat( d->view->doc(), sheet, *selectionInfo(), dummy );
+ d->view->doc()->addCommand( undo );
+ }
+
+ Region::ConstIterator end(selectionInfo()->constEnd());
+ for (Region::ConstIterator it = selectionInfo()->constBegin(); it != end; ++it)
+ {
+ QRect rect = (*it)->rect().normalize();
+
+ int right = rect.right();
+ int bottom = rect.bottom();
+
+ if ( util_isRowSelected(rect) )
+ {
+ for ( int r = rect.top(); r <= bottom; ++r )
+ {
+ cell = sheet->getFirstCellRow( r );
+ while ( cell )
+ {
+ if ( cell->isPartOfMerged() )
+ {
+ cell = sheet->getNextCellRight( cell->column(), r );
+ continue;
+ }
+
+ formatCellByKey (cell, _ev->key(), rect);
+
+ cell = sheet->getNextCellRight( cell->column(), r );
+ } // while (cell)
+ RowFormat * rw = sheet->nonDefaultRowFormat( r );
+ QPen pen;
+ switch ( _ev->key() )
+ {
+ case Key_Exclam:
+ rw->setFormatType (Number_format);
+ rw->setPrecision( 2 );
+ break;
+
+ case Key_Dollar:
+ rw->setFormatType (Money_format);
+ rw->setPrecision( d->view->doc()->locale()->fracDigits() );
+ break;
+
+ case Key_Percent:
+ rw->setFormatType (Percentage_format);
+ break;
+
+ case Key_At:
+ rw->setFormatType( SecondeTime_format );
+ break;
+
+ case Key_NumberSign:
+ rw->setFormatType( ShortDate_format );
+ break;
+
+ case Key_AsciiCircum:
+ rw->setFormatType( Scientific_format );
+ break;
+
+ case Key_Ampersand:
+ if ( r == rect.top() )
+ {
+ pen = QPen( d->view->borderColor(), 1, SolidLine);
+ rw->setTopBorderPen( pen );
+ }
+ if ( r == rect.bottom() )
+ {
+ pen = QPen( d->view->borderColor(), 1, SolidLine);
+ rw->setBottomBorderPen( pen );
+ }
+ break;
+
+ default:
+ d->view->doc()->emitEndOperation( rect );
+ return false;
+ }
+ sheet->emit_updateRow( rw, r );
+ }
+
+ d->view->doc()->emitEndOperation( rect );
+ return true;
+ }
+
+ if ( util_isColumnSelected(rect) )
+ {
+ for ( int c = rect.left(); c <= right; ++c )
+ {
+ cell = sheet->getFirstCellColumn( c );
+ while ( cell )
+ {
+ if ( cell->isPartOfMerged() )
+ {
+ cell = sheet->getNextCellDown( c, cell->row() );
+ continue;
+ }
+
+ formatCellByKey (cell, _ev->key(), rect);
+
+ cell = sheet->getNextCellDown( c, cell->row() );
+ }
+
+ ColumnFormat * cw = sheet->nonDefaultColumnFormat( c );
+ QPen pen;
+ switch ( _ev->key() )
+ {
+ case Key_Exclam:
+ cw->setFormatType( Number_format );
+ cw->setPrecision( 2 );
+ break;
+
+ case Key_Dollar:
+ cw->setFormatType( Money_format );
+ cw->setPrecision( d->view->doc()->locale()->fracDigits() );
+ break;
+
+ case Key_Percent:
+ cw->setFormatType( Percentage_format );
+ break;
+
+ case Key_At:
+ cw->setFormatType( SecondeTime_format );
+ break;
+
+ case Key_NumberSign:
+ cw->setFormatType( ShortDate_format );
+ break;
+
+ case Key_AsciiCircum:
+ cw->setFormatType( Scientific_format );
+ break;
+
+ case Key_Ampersand:
+ if ( c == rect.left() )
+ {
+ pen = QPen( d->view->borderColor(), 1, SolidLine);
+ cw->setLeftBorderPen( pen );
+ }
+ if ( c == rect.right() )
+ {
+ pen = QPen( d->view->borderColor(), 1, SolidLine);
+ cw->setRightBorderPen( pen );
+ }
+ break;
+
+ default:
+ d->view->doc()->emitEndOperation( rect );
+ return false;
+ }
+ sheet->emit_updateColumn( cw, c );
+ }
+ d->view->doc()->emitEndOperation( rect );
+ return true;
+ }
+
+ for ( int row = rect.top(); row <= bottom; ++row )
+ {
+ for ( int col = rect.left(); col <= right; ++ col )
+ {
+ cell = sheet->nonDefaultCell( col, row );
+
+ if ( cell->isPartOfMerged() )
+ continue;
+
+ formatCellByKey (cell, _ev->key(), rect);
+ } // for left .. right
+ } // for top .. bottom
+
+ }
+ _ev->accept();
+
+ d->view->doc()->emitEndOperation( *selectionInfo() );
+ return true;
+}
+
+bool Canvas::formatCellByKey (Cell *cell, int key, const QRect &rect)
+{
+ QPen pen;
+ switch (key)
+ {
+ case Key_Exclam:
+ cell->convertToDouble ();
+ cell->format()->setFormatType (Number_format);
+ cell->format()->setPrecision( 2 );
+ break;
+
+ case Key_Dollar:
+ cell->convertToMoney ();
+ break;
+
+ case Key_Percent:
+ cell->convertToPercent ();
+ break;
+
+ case Key_At:
+ cell->convertToTime ();
+ break;
+
+ case Key_NumberSign:
+ cell->convertToDate ();
+ break;
+
+ case Key_AsciiCircum:
+ cell->format()->setFormatType (Scientific_format);
+ cell->convertToDouble ();
+ break;
+
+ case Key_Ampersand:
+ if ( cell->row() == rect.top() )
+ {
+ pen = QPen( d->view->borderColor(), 1, SolidLine);
+ cell->setTopBorderPen( pen );
+ }
+ if ( cell->row() == rect.bottom() )
+ {
+ pen = QPen( d->view->borderColor(), 1, SolidLine);
+ cell->setBottomBorderPen( pen );
+ }
+ if ( cell->column() == rect.left() )
+ {
+ pen = QPen( d->view->borderColor(), 1, SolidLine);
+ cell->setLeftBorderPen( pen );
+ }
+ if ( cell->column() == rect.right() )
+ {
+ pen = QPen( d->view->borderColor(), 1, SolidLine);
+ cell->setRightBorderPen( pen );
+ }
+ break;
+ } // switch
+
+ return true;
+}
+
+
+void Canvas::slotAutoScroll(const QPoint &scrollDistance)
+{
+ QPoint d = scrollDistance;
+ horzScrollBar()->setValue( horzScrollBar()->value() + d.x() );
+ vertScrollBar()->setValue( vertScrollBar()->value() + d.y() );
+}
+
+void Canvas::doAutoScroll()
+{
+ if ( !d->mousePressed )
+ {
+ d->scrollTimer->stop();
+ return;
+ }
+ bool select = false;
+ QPoint pos = mapFromGlobal( QCursor::pos() );
+
+ //Provide progressive scrolling depending on the mouse position
+ if ( pos.y() < 0 )
+ {
+ vertScrollBar()->setValue ((int) (vertScrollBar()->value() -
+ autoScrollAccelerationY( - pos.y())));
+ select = true;
+ }
+ else if ( pos.y() > height() )
+ {
+ vertScrollBar()->setValue ((int) (vertScrollBar()->value() +
+ autoScrollAccelerationY (pos.y() - height())));
+ select = true;
+ }
+
+ if ( pos.x() < 0 )
+ {
+ horzScrollBar()->setValue ((int) (horzScrollBar()->value() -
+ autoScrollAccelerationX( - pos.x() )));
+ select = true;
+ }
+ else if ( pos.x() > width() )
+ {
+ horzScrollBar()->setValue ((int) (horzScrollBar()->value() +
+ autoScrollAccelerationX( pos.x() - width())));
+ select = true;
+ }
+
+ if ( select )
+ {
+ QMouseEvent * event = new QMouseEvent(QEvent::MouseMove, pos, 0, 0);
+ mouseMoveEvent( event );
+ delete event;
+ }
+
+ //Restart timer
+ d->scrollTimer->start( 50 );
+}
+
+void Canvas::speakCell(QWidget* w, const QPoint& p, uint flags)
+{
+ Q_UNUSED(flags);
+ if (w != this) return;
+ Sheet* sheet = activeSheet();
+ if (!sheet) return;
+ int row = -1;
+ int col = -1;
+ if (p == QPoint()) {
+ row = markerRow();
+ col = markerColumn();
+ if (row == d->prevSpokenFocusRow && col == d->prevSpokenFocusCol) return;
+ d->prevSpokenFocusRow = row;
+ d->prevSpokenFocusCol = col;
+ } else {
+ QPoint wp = w->mapFromGlobal(p);
+ double tmp;
+ double posX;
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ double dwidth = d->view->doc()->unzoomItX( width() );
+ posX = dwidth - d->view->doc()->unzoomItX( wp.x() );
+ }
+ else
+ posX = d->view->doc()->unzoomItX( wp.x() );
+
+ double posY = d->view->doc()->unzoomItY( wp.y() );
+ col = sheet->leftColumn( (posX + xOffset()), tmp );
+ row = sheet->topRow( (posY + yOffset()), tmp );
+ if (row == d->prevSpokenPointerRow && col == d->prevSpokenPointerCol) return;
+ d->prevSpokenPointerRow = row;
+ d->prevSpokenPointerCol = col;
+ }
+ if (row == d->prevSpokenRow && col == d->prevSpokenCol) return;
+ d->prevSpokenRow = row;
+ d->prevSpokenCol = col;
+ // kdDebug() << "Canvas::speakCell: row = " << row << " col = " << col << endl;
+ if (row >=0 && col >= 0) {
+ Cell* cell = sheet->cellAt( col, row );
+ if (!cell) return;
+ QString text = cell->strOutText();
+ if (!text.isEmpty()) {
+ text.prepend(i18n("Spreadsheet cell", "Cell ") + cell->name() + " ");
+ if (cell->isFormula()) {
+ QString f = cell->text();
+ // Try to format the formula so synth can more clearly speak it.
+ QString f2;
+ for (uint i = 0; i < f.length(); i++) f2 += f[i] + " ";
+ f2.replace("(", i18n("character (", "left paren"));
+ f2.replace(")", i18n("character )", "right paren"));
+ f2.replace(":", i18n("character :", "colon"));
+ f2.replace(";", i18n("character ;", "semicolon"));
+ f2.replace("=", i18n("character =", "equals"));
+ f2.replace(".", i18n("character .", "point"));
+ f2.replace(",", i18n("character ,", "comma"));
+ f2.replace(" . . ", i18n("characters ..", " dot dot "));
+ text.append(i18n("Spreadsheet formula", " Formula ") + f2);
+ }
+ // kdDebug() << "Canvas::speakCell: text = " << text << endl;
+ kospeaker->sayWidget(text);
+ }
+ }
+}
+
+double Canvas::autoScrollAccelerationX( int offset )
+{
+ switch( static_cast<int>( offset / 20 ) )
+ {
+ case 0: return 5.0;
+ case 1: return 20.0;
+ case 2: return d->view->doc()->unzoomItX( width() );
+ case 3: return d->view->doc()->unzoomItX( width() );
+ default: return d->view->doc()->unzoomItX( (int) (width() * 5.0) );
+ }
+}
+
+double Canvas::autoScrollAccelerationY( int offset )
+{
+ switch( static_cast<int>( offset / 20 ) )
+ {
+ case 0: return 5.0;
+ case 1: return 20.0;
+ case 2: return d->view->doc()->unzoomItY( height() );
+ case 3: return d->view->doc()->unzoomItY( height() );
+ default: return d->view->doc()->unzoomItY( (int) (height() * 5.0) );
+ }
+}
+
+
+KSpread::EmbeddedObject *Canvas::getObject( const QPoint &pos, Sheet *_sheet )
+{
+ QPoint const p ( (int) pos.x() ,
+ (int) pos.y() );
+
+ QPtrListIterator<EmbeddedObject> itObject( doc()->embeddedObjects() );
+ for( ; itObject.current(); ++itObject )
+ {
+ if ( itObject.current()->sheet() == _sheet )
+ {
+ KoRect const bound = ( itObject.current() )->geometry();
+ QRect zoomedBound = doc()->zoomRect( KoRect(bound.left(), bound.top(),
+ bound.width(),
+ bound.height() ) );
+ zoomedBound.moveBy( (int)( -xOffset() * doc()->zoomedResolutionX() ), (int)( -yOffset() * doc()->zoomedResolutionY() ) );
+ if ( zoomedBound.contains( p ) )
+ return itObject.current();
+ }
+ }
+ return 0;
+}
+
+void Canvas::selectObject( EmbeddedObject *obj )
+{
+ if ( obj->sheet() != activeSheet() || obj->isSelected() )
+ return;
+ obj->setSelected( true );
+ repaintObject( obj );
+
+ d->mouseSelectedObject = true;
+ emit objectSelectedChanged();
+ deleteEditor( true );
+}
+
+void Canvas::deselectObject( EmbeddedObject *obj )
+{
+ if ( obj->sheet() != activeSheet() || !obj->isSelected() )
+ return;
+ obj->setSelected( false );
+ repaintObject( obj );
+
+ d->mouseSelectedObject = false;
+ emit objectSelectedChanged();
+}
+
+void Canvas::selectAllObjects()
+{
+ QPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
+ for ( ; it.current() ; ++it )
+ {
+ if ( it.current()->sheet() == activeSheet() )
+ it.current()->setSelected( true );
+ }
+
+ d->mouseSelectedObject = true;
+// emit objectSelectedChanged();
+}
+
+void Canvas::deselectAllObjects()
+{
+ if( activeSheet()->numSelected() == 0 )
+ return;
+
+ //lowerObject();
+
+ QPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
+ for ( ; it.current() ; ++it )
+ deselectObject( it.current() );
+
+ d->mouseSelectedObject = false;
+// emit objectSelectedChanged();
+}
+
+
+
+void Canvas::setMouseSelectedObject(bool b)
+{
+ d->mouseSelectedObject = b;
+ emit objectSelectedChanged();
+}
+
+bool Canvas::isObjectSelected()
+{
+ return d->mouseSelectedObject;
+}
+
+
+void Canvas::moveObjectsByMouse( KoPoint &pos, bool keepXorYunchanged )
+{
+ KoRect rect( objectRect( false ) );
+ KoPoint move( 0, 0 );
+ double diffx = pos.x() - d->m_origMousePos.x();
+ double diffy = pos.y() - d->m_origMousePos.y();
+
+ move = KoPoint( diffx, diffy );
+ d->m_origMousePos = pos;
+
+ // unwind last snapping
+ KoRect movedRect( rect );
+ movedRect.moveBy( diffx, diffy );
+
+ // don't move object off canvas
+ KoPoint diffDueToBorders(0,0);
+// KoRect pageRect( m_activePage->getPageRect() );
+ if ( rect.left() + move.x() < 0/*pageRect.left()*/ )
+ diffDueToBorders.setX( -rect.left() - move.x() );
+// else if ( rect.right() + move.x() > pageRect.right() )
+// diffDueToBorders.setX( pageRect.right() - (rect.right() + move.x()) );
+
+
+ //kdDebug() << "rect.top() + move.y():" << rect.top() + move.y()<< endl;
+ if ( rect.top() + move.y() < 0 )
+ diffDueToBorders.setY( -rect.top() - move.y() );
+// else if ( rect.bottom() + move.y() > pageRect.bottom() )
+// diffDueToBorders.setY( pageRect.bottom() - (rect.bottom() + move.y()) );
+
+// m_moveSnapDiff += diffDueToBorders;
+ move += diffDueToBorders;
+
+// movedRect.moveBy( m_moveSnapDiff.x(), m_moveSnapDiff.y() );
+ if ( keepXorYunchanged )
+ {
+ KoPoint diff( d->m_moveStartPosMouse - movedRect.topLeft() );
+ if ( fabs( diff.x() ) > fabs( diff.y() ) )
+ {
+// m_moveSnapDiff.setY( /*m_moveSnapDiff.y() + */m_moveStartPosMouse.y() - movedRect.y() );
+ movedRect.moveTopLeft( KoPoint( movedRect.x(), d->m_moveStartPosMouse.y() ) );
+ move.setY( movedRect.y() - rect.y() );
+ }
+ else
+ {
+// m_moveSnapDiff.setX( /*m_moveSnapDiff.x() + */m_moveStartPosMouse.x() - movedRect.x() );
+ movedRect.moveTopLeft( KoPoint( d->m_moveStartPosMouse.x(), movedRect.y() ) );
+ move.setX( movedRect.x() - rect.x() );
+ }
+ }
+
+ if ( move != KoPoint( 0, 0 ) )
+ {
+ //kdDebug(33001) << "moveObjectsByMouse move = " << move << endl;
+ activeSheet()->moveObject( view(), move, false );
+ }
+}
+
+
+void Canvas::resizeObject( ModifyType _modType, const KoPoint & point, bool keepRatio )
+{
+ EmbeddedObject *obj = d->m_resizeObject;
+
+ KoRect objRect = obj->geometry();
+ objRect.moveBy( -xOffset(), -yOffset() );
+ QRect oldBoundingRect( doc()->zoomRect( objRect ) );
+
+ bool left = false;
+ bool right = false;
+ bool top = false;
+ bool bottom = false;
+ if ( _modType == MT_RESIZE_UP || _modType == MT_RESIZE_LU || _modType == MT_RESIZE_RU )
+ {
+ top = true;
+// snapStatus |= KoGuides::SNAP_HORIZ;
+ }
+ if ( _modType == MT_RESIZE_DN || _modType == MT_RESIZE_LD || _modType == MT_RESIZE_RD )
+ {
+ bottom = true;
+// snapStatus |= KoGuides::SNAP_HORIZ;
+ }
+ if ( _modType == MT_RESIZE_LF || _modType == MT_RESIZE_LU || _modType == MT_RESIZE_LD )
+ {
+ left = true;
+// snapStatus |= KoGuides::SNAP_VERT;
+ }
+ if ( _modType == MT_RESIZE_RT || _modType == MT_RESIZE_RU || _modType == MT_RESIZE_RD )
+ {
+ right = true;
+// snapStatus |= KoGuides::SNAP_VERT;
+ }
+
+ double newLeft = objRect.left();
+ double newRight = objRect.right();
+ double newTop = objRect.top();
+ double newBottom = objRect.bottom();
+ if ( top )
+ {
+ if ( point.y() < objRect.bottom() - MIN_SIZE )
+ {
+ newTop = point.y();
+ }
+ else
+ {
+ newTop = objRect.bottom() - MIN_SIZE;
+ }
+ }
+ if ( bottom )
+ {
+ if ( point.y() > objRect.top() + MIN_SIZE )
+ {
+ newBottom = point.y();
+ }
+ else
+ {
+ newBottom = objRect.top() + MIN_SIZE;
+ }
+ }
+ if ( left )
+ {
+ if ( point.x() < objRect.right() - MIN_SIZE )
+ {
+ newLeft = point.x();
+ }
+ else
+ {
+ newLeft = objRect.right() - MIN_SIZE;
+ }
+ }
+ if ( right )
+ {
+ if ( point.x() > objRect.left() + MIN_SIZE )
+ {
+ newRight = point.x();
+ }
+ else
+ {
+ newRight = objRect.left() + MIN_SIZE;
+ }
+ }
+
+ double width = newRight - newLeft;
+ double height = newBottom - newTop;
+
+ if ( keepRatio && d->m_ratio != 0 )
+ {
+ if ( ( top || bottom ) && ( right || left ) )
+ {
+ if ( height * height * d->m_ratio > width * width / d->m_ratio )
+ {
+ width = height * d->m_ratio;
+ }
+ else
+ {
+ height = width / d->m_ratio;
+ }
+ }
+ else if ( top || bottom )
+ {
+ width = height * d->m_ratio;
+ }
+ else
+ {
+ height = width / d->m_ratio;
+ }
+
+ if ( top )
+ {
+ newTop = objRect.bottom() - height;
+ }
+ else
+ {
+ newBottom = objRect.top() + height;
+ }
+ if ( left )
+ {
+ newLeft = objRect.right() - width;
+ }
+ else
+ {
+ newRight = objRect.right() + width;
+ }
+ }
+
+ if ( newLeft != objRect.left() || newRight != objRect.right() || newTop != objRect.top() || newBottom != objRect.bottom() )
+ {
+ // resizeBy and moveBy have to been used to make it work with rotated objects
+ obj->resizeBy( width - objRect.width(), height - objRect.height() );
+
+ if ( objRect.left() != newLeft || objRect.top() != newTop )
+ {
+ obj->moveBy( KoPoint( newLeft - objRect.left(), newTop - objRect.top() ) );
+ }
+
+// if ( doc()->showGuideLines() && !m_disableSnapping )
+// {
+// KoRect rect( obj->getRealRect() );
+// KoPoint sp( rect.topLeft() );
+// if ( right )
+// {
+// sp.setX( rect.right() );
+// }
+// if ( bottom )
+// {
+// sp.setY( rect.bottom() );
+// }
+// m_gl.repaintSnapping( sp, snapStatus );
+// }
+
+ repaint( oldBoundingRect );
+ repaintObject( obj );
+ emit objectSizeChanged();
+ }
+}
+
+
+void Canvas::finishResizeObject( const QString &/*name*/, bool /*layout*/ )
+{
+ if ( d->m_resizeObject )
+ {
+ KoPoint move = KoPoint( d->m_resizeObject->geometry().x() - d->m_rectBeforeResize.x(),
+ d->m_resizeObject->geometry().y() - d->m_rectBeforeResize.y() );
+ KoSize size = KoSize( d->m_resizeObject->geometry().width() - d->m_rectBeforeResize.width(),
+ d->m_resizeObject->geometry().height() - d->m_rectBeforeResize.height() );
+
+ if ( ( d->m_resizeObject->geometry() ) != d->m_rectBeforeResize )
+ {
+ ChangeObjectGeometryCommand *resizeCmd = new ChangeObjectGeometryCommand( d->m_resizeObject, move, size );
+ // the command is not executed as the object is allready resized.
+ doc()->addCommand( resizeCmd );
+ }
+
+// if ( layout )
+// doc()->layout( m_resizeObject );
+
+ d->m_ratio = 0.0;
+ d->m_isResizing = false;
+ repaintObject( d->m_resizeObject );
+ d->m_resizeObject = NULL;
+ }
+}
+
+void Canvas::raiseObject( EmbeddedObject *object )
+{
+ if ( doc()->embeddedObjects().count() <= 1 )
+ return;
+
+ if ( d->m_objectDisplayAbove == 0 )
+ {
+ if ( activeSheet()->numSelected() == 1 )
+ {
+ d->m_objectDisplayAbove = object;
+ }
+ }
+}
+
+void Canvas::lowerObject()
+{
+ d->m_objectDisplayAbove = 0;
+}
+
+void Canvas::displayObjectList( QPtrList<EmbeddedObject> &list )
+{
+ list = doc()->embeddedObjects();
+ list.setAutoDelete( false );
+
+ if ( d->m_objectDisplayAbove )
+ {
+ // it can happen that the object is no longer there e.g. when
+ // the insert of the object is undone
+ int pos = doc()->embeddedObjects().findRef( d->m_objectDisplayAbove );
+ if ( pos != -1 && d->m_objectDisplayAbove->isSelected() )
+ {
+ list.take( pos );
+ list.append( d->m_objectDisplayAbove );
+ }
+ else
+ {
+ //tz not possible due to const. should const be removed?
+ //m_objectDisplayAbove = 0;
+ }
+ }
+}
+
+
+KoRect Canvas::objectRect( bool all ) const
+{
+ return activeSheet()->getRealRect( all );
+}
+
+void Canvas::deleteEditor (bool saveChanges, bool array)
+{
+ if ( !d->cellEditor )
+ return;
+
+
+ //There may be highlighted areas on the sheet which will need to be erased
+ setSelectionChangePaintDirty( activeSheet() , *choice() );
+
+ d->editWidget->setEditMode( false );
+
+ QString t = d->cellEditor->text();
+ // Delete the cell editor first and after that update the document.
+ // That means we get a synchronous repaint after the cell editor
+ // widget is gone. Otherwise we may get painting errors.
+ delete d->cellEditor;
+ d->cellEditor = 0;
+
+ if ( saveChanges )
+ {
+ if ( t.at(0)=='=' )
+ {
+ //a formula
+ int openParenthese = t.contains('(' );
+ int closeParenthese = t.contains(')' );
+ int diff = QABS( openParenthese - closeParenthese );
+ if ( openParenthese > closeParenthese )
+ {
+ for (int i=0; i < diff;i++)
+ {
+ t=t+')';
+ }
+ }
+ }
+ d->view->setText (t, array);
+ }
+ else
+ {
+ d->view->updateEditWidget();
+ }
+
+ setFocus();
+}
+
+
+void Canvas::createEditor(bool captureArrowKeys)
+{
+ if (!activeSheet())
+ return;
+
+ Cell * cell = activeSheet()->nonDefaultCell( markerColumn(), markerRow(), false );
+
+ if ( !createEditor( CellEditor , true , captureArrowKeys ) )
+ return;
+ if ( cell )
+ d->cellEditor->setText( cell->text() );
+}
+
+bool Canvas::createEditor( EditorType ed, bool addFocus, bool captureArrowKeys )
+{
+ Sheet * sheet = activeSheet();
+
+ // Set the starting sheet of the choice.
+ choice()->setSheet( activeSheet() );
+
+ if ( !d->cellEditor )
+ {
+ Cell * cell = sheet->nonDefaultCell( marker().x(), marker().y(), false );
+
+ if ( sheet->isProtected() && !cell->format()->notProtected( marker().x(), marker().y() ) )
+ return false;
+
+ if ( ed == CellEditor )
+ {
+ d->editWidget->setEditMode( true );
+ d->cellEditor = new KSpread::CellEditor( cell, this, captureArrowKeys );
+ }
+
+ double w, h;
+ double min_w = cell->dblWidth( markerColumn() );
+ double min_h = cell->dblHeight( markerRow() );
+ if ( cell->isDefault() )
+ {
+ w = min_w;
+ h = min_h;
+ //kdDebug(36001) << "DEFAULT" << endl;
+ }
+ else
+ {
+ w = cell->extraWidth();
+ h = cell->extraHeight();
+ //kdDebug(36001) << "HEIGHT=" << min_h << " EXTRA=" << h << endl;
+ }
+
+ double xpos = sheet->dblColumnPos( markerColumn() ) - xOffset();
+
+ Sheet::LayoutDirection sheetDir = sheet->layoutDirection();
+ bool rtlText = cell->strOutText().isRightToLeft();
+
+ // if sheet and cell direction don't match, then the editor's location
+ // needs to be shifted backwards so that it's right above the cell's text
+ if ( w > 0 && ( ( sheetDir == Sheet::RightToLeft && !rtlText ) ||
+ ( sheetDir == Sheet::LeftToRight && rtlText ) ) )
+ xpos -= w - min_w;
+
+ // paint editor above correct cell if sheet direction is RTL
+ if ( sheetDir == Sheet::RightToLeft )
+ {
+ double dwidth = d->view->doc()->unzoomItX( width() );
+ double w2 = QMAX( w, min_w );
+ xpos = dwidth - w2 - xpos;
+ }
+
+ double ypos = sheet->dblRowPos( markerRow() ) - yOffset();
+ QPalette p = d->cellEditor->palette();
+ QColorGroup g( p.active() );
+
+ QColor color = cell->format()->textColor( markerColumn(), markerRow() );
+ if ( !color.isValid() )
+ color = QApplication::palette().active().text();
+ g.setColor( QColorGroup::Text, color);
+
+ color = cell->bgColor( markerColumn(), markerRow() );
+ if ( !color.isValid() )
+ color = g.base();
+ g.setColor( QColorGroup::Background, color );
+
+ d->cellEditor->setPalette( QPalette( g, p.disabled(), g ) );
+ QFont tmpFont = cell->format()->textFont( markerColumn(), markerRow() );
+ tmpFont.setPointSizeFloat( 0.01 * d->view->doc()->zoom() * tmpFont.pointSizeFloat() );
+ d->cellEditor->setFont( tmpFont );
+
+ KoRect rect( xpos, ypos, w, h ); //needed to circumvent rounding issue with height/width
+
+
+ QRect zoomedRect=d->view->doc()->zoomRect( rect );
+ /*zoomedRect.setLeft(zoomedRect.left()-2);
+ zoomedRect.setRight(zoomedRect.right()+4);
+ zoomedRect.setTop(zoomedRect.top()-1);
+ zoomedRect.setBottom(zoomedRect.bottom()+2);*/
+
+ d->cellEditor->setGeometry( zoomedRect );
+ d->cellEditor->setMinimumSize( QSize( d->view->doc()->zoomItX( min_w ), d->view->doc()->zoomItY( min_h ) ) );
+ d->cellEditor->show();
+ //kdDebug(36001) << "FOCUS1" << endl;
+ //Laurent 2001-12-05
+ //Don't add focus when we create a new editor and
+ //we select text in edit widget otherwise we don't delete
+ //selected text.
+ // startChoose();
+
+ if ( addFocus )
+ d->cellEditor->setFocus();
+
+ setSelectionChangePaintDirty(sheet, *selectionInfo());
+ paintUpdates();
+ }
+
+ return true;
+}
+
+void Canvas::repaintObject( EmbeddedObject *obj )
+{
+ //Calculate where the object appears on the canvas widget and then repaint that part of the widget
+ QRect canvasRelativeGeometry = doc()->zoomRect( obj->geometry() );
+ canvasRelativeGeometry.moveBy( (int)( -xOffset()*doc()->zoomedResolutionX() ) ,
+ (int)( -yOffset() * doc()->zoomedResolutionY()) );
+
+ update( canvasRelativeGeometry );
+
+ /* if ( !obj->isSelected() )
+ {
+ KoRect g = obj->geometry();
+ g.moveBy( -xOffset(), -yOffset() );
+ QRect geometry( doc()->zoomRect( g ) );
+
+ update( geometry );
+ }
+ else
+ {
+ QPainter p(this);
+ p.translate( -xOffset() * doc()->zoomedResolutionX() , -yOffset() * doc()->zoomedResolutionY() );
+ obj->draw(&p); //this goes faster than calling repaint
+ p.end();
+ }*/
+}
+
+void Canvas::copyOasisObjects()
+{
+ // We'll create a store (ZIP format) in memory
+ QBuffer buffer;
+ QCString mimeType = "application/vnd.oasis.opendocument.spreadsheet";
+ KoStore* store = KoStore::createStore( &buffer, KoStore::Write, mimeType );
+ Q_ASSERT( store );
+ Q_ASSERT( !store->bad() );
+ KoOasisStore oasisStore( store );
+
+ KoXmlWriter* manifestWriter = oasisStore.manifestWriter( mimeType );
+
+ QString plainText;
+ KoPicture picture;
+ if ( !doc()->saveOasisHelper( store, manifestWriter, Doc::SaveSelected, &plainText, &picture )
+ || !oasisStore.closeManifestWriter() )
+ {
+ delete store;
+ return;
+ }
+ delete store;
+
+ KMultipleDrag* multiDrag = new KMultipleDrag();
+ if ( !plainText.isEmpty() )
+ multiDrag->addDragObject( new QTextDrag( plainText, 0 ) );
+ if ( !picture.isNull() )
+ multiDrag->addDragObject( picture.dragObject( 0 ) );
+ KoStoreDrag* storeDrag = new KoStoreDrag( mimeType, 0 );
+ kdDebug() << k_funcinfo << "setting zip data: " << buffer.buffer().size() << " bytes." << endl;
+ storeDrag->setEncodedData( buffer.buffer() );
+ multiDrag->addDragObject( storeDrag );
+
+ //save the objects as pictures too so that other programs can access them
+ QPtrListIterator<EmbeddedObject> itObject( doc()->embeddedObjects() );
+ itObject.toFirst();
+ if ( itObject.current() )
+ {
+ KoRect kr = objectRect(false);
+ QRect r( kr.toQRect() );
+ QPixmap pixmap( r.width(), r.height() );
+ pixmap.fill( "white" );
+ QPainter p(&pixmap);
+ for( ; itObject.current(); ++itObject )
+ {
+ if ( itObject.current()->isSelected() )
+ p.drawPixmap( itObject.current()->geometry().toQRect().left() - r.left(), itObject.current()->geometry().toQRect().top() - r.top(), itObject.current()->toPixmap( 1.0 , 1.0 ) );
+ }
+ p.end();
+ if (!pixmap.isNull())
+ {
+ QImageDrag *imagedrag = new QImageDrag( pixmap.convertToImage() );
+ multiDrag->addDragObject( imagedrag );
+ }
+ }
+
+ QDragObject *dragObject = multiDrag;
+ QApplication::clipboard()->setData( dragObject, QClipboard::Clipboard );
+}
+
+void Canvas::closeEditor()
+{
+ if ( d->chooseCell )
+ return;
+
+ if ( d->cellEditor )
+ {
+ deleteEditor( true ); // save changes
+ }
+}
+
+void Canvas::updateEditor()
+{
+ if (!d->chooseCell)
+ return;
+
+ Sheet* sheet = activeSheet();
+ if (!sheet)
+ return;
+
+ if (d->cellEditor)
+ {
+ if (choice()->sheet() != sheet)
+ {
+ d->cellEditor->hide();
+ }
+ else
+ {
+ d->cellEditor->show();
+ }
+ d->cellEditor->updateChoice();
+ }
+}
+
+void Canvas::setSelectionChangePaintDirty(Sheet* sheet, const Region& region)
+{
+ sheet->setRegionPaintDirty(region); // TODO should the paintDirtyList be in Canvas?
+}
+
+
+void Canvas::updatePosWidget()
+{
+ QString buffer;
+ // No selection, or only one cell merged selected
+ if ( selectionInfo()->isSingular() )
+ {
+ if (activeSheet()->getLcMode())
+ {
+ buffer = "L" + QString::number( markerRow() ) +
+ "C" + QString::number( markerColumn() );
+ }
+ else
+ {
+ buffer = Cell::columnName( markerColumn() ) +
+ QString::number( markerRow() );
+ }
+ }
+ else
+ {
+ if (activeSheet()->getLcMode())
+ {
+ buffer = QString::number( (selectionInfo()->lastRange().bottom()-selectionInfo()->lastRange().top()+1) )+"Lx";
+ if ( util_isRowSelected( selectionInfo()->lastRange() ) )
+ buffer+=QString::number((KS_colMax-selectionInfo()->lastRange().left()+1))+"C";
+ else
+ buffer+=QString::number((selectionInfo()->lastRange().right()-selectionInfo()->lastRange().left()+1))+"C";
+ }
+ else
+ {
+ //encodeColumnLabelText return @@@@ when column >KS_colMax
+ //=> it's not a good display
+ //=> for the moment I display pos of marker
+ buffer=Cell::columnName( selectionInfo()->lastRange().left() ) +
+ QString::number(selectionInfo()->lastRange().top()) + ":" +
+ Cell::columnName( QMIN( KS_colMax, selectionInfo()->lastRange().right() ) ) +
+ QString::number(selectionInfo()->lastRange().bottom());
+ //buffer=activeSheet()->columnLabel( m_iMarkerColumn );
+ //buffer+=tmp.setNum(m_iMarkerRow);
+ }
+ }
+
+ if (buffer != d->posWidget->lineEdit()->text())
+ d->posWidget->lineEdit()->setText(buffer);
+}
+
+void Canvas::equalizeRow()
+{
+ QRect s( selection() );
+ RowFormat *rl = d->view->activeSheet()->rowFormat(s.top());
+ int size=rl->height(this);
+ if ( s.top() == s.bottom() )
+ return;
+ for(int i=s.top()+1;i<=s.bottom();i++)
+ {
+ Sheet *sheet = activeSheet();
+ if ( !sheet )
+ return;
+ size=QMAX(d->view->activeSheet()->rowFormat(i)->height(this),size);
+ }
+ d->view->vBorderWidget()->equalizeRow(size);
+}
+
+void Canvas::equalizeColumn()
+{
+ QRect s( selection() );
+ ColumnFormat *cl = d->view->activeSheet()->columnFormat(s.left());
+ int size=cl->width(this);
+ if ( s.left() == s.right() )
+ return;
+
+ for(int i=s.left()+1;i<=s.right();i++)
+ {
+ size=QMAX(d->view->activeSheet()->columnFormat(i)->width(this),size);
+ }
+ d->view->hBorderWidget()->equalizeColumn(size);
+}
+
+QRect Canvas::cellsInArea( const QRect area ) const
+{
+ KoRect unzoomedRect = d->view->doc()->unzoomRect( area );
+
+ unzoomedRect.moveBy( (int)xOffset(), (int)yOffset() );
+
+ double tmp;
+ int left_col = activeSheet()->leftColumn( unzoomedRect.left(), tmp );
+ int right_col = activeSheet()->rightColumn( unzoomedRect.right() );
+ int top_row = activeSheet()->topRow( unzoomedRect.top(), tmp );
+ int bottom_row = activeSheet()->bottomRow( unzoomedRect.bottom() );
+
+ return QRect( left_col, top_row,
+ right_col - left_col + 1, bottom_row - top_row + 1 );
+}
+
+QRect Canvas::visibleCells() const
+{
+ return cellsInArea( QRect(0,0,width(),height()) );
+
+}
+
+
+//---------------------------------------------
+//
+// Drawing Engine
+//
+//---------------------------------------------
+
+void Canvas::paintUpdates()
+{
+ if (activeSheet() == NULL)
+ return;
+
+ QPainter painter(this);
+
+ //Save clip region
+ QRegion rgnComplete( painter.clipRegion() );
+ QWMatrix matrix;
+ if ( d->view )
+ {
+ matrix = d->view->matrix();
+ }
+ else
+ {
+ matrix = painter.worldMatrix();
+ }
+
+
+ paintChildren( painter, matrix );
+
+ painter.save();
+ clipoutChildren( painter );
+
+ KoRect unzoomedRect = d->view->doc()->unzoomRect( QRect( 0, 0, width(), height() ) );
+ // unzoomedRect.moveBy( xOffset(), yOffset() );
+
+
+ /* paint any visible cell that has the paintDirty flag */
+ QRect range = visibleCells();
+ Cell* cell = NULL;
+
+ double topPos = activeSheet()->dblRowPos(range.top());
+ double leftPos = activeSheet()->dblColumnPos(range.left());
+
+ KoPoint dblCorner( leftPos - xOffset(), topPos - yOffset() );
+
+ int x;
+ int y;
+
+ int right = range.right();
+ int bottom = range.bottom();
+ Sheet * sheet = activeSheet();
+
+#if 0
+ kdDebug(36001)
+ << "================================================================"
+ << endl;
+ kdDebug(36001) << "painting dirty cells " << endl;
+#endif
+
+ QValueList<QPoint> mergedCellsPainted;
+ for ( x = range.left(); x <= right; ++x )
+ {
+ for ( y = range.top(); y <= bottom; ++y )
+ {
+ if ( sheet->cellIsPaintDirty( QPoint( x, y ) ) )
+ {
+ cell = sheet->cellAt( x, y );
+
+ // recalc and relayout only for non default cells
+ if (!cell->isDefault())
+ {
+ if (cell->calcDirtyFlag()) cell->calc();
+ if (cell->layoutDirtyFlag()) cell->makeLayout( painter, x, y );
+ }
+
+ /* bool paintBordersBottom = false;
+ bool paintBordersRight = false;
+ bool paintBordersLeft = false;
+ bool paintBordersTop = false; */
+
+ int paintBorder=Cell::Border_None;
+
+ QPen bottomPen( cell->effBottomBorderPen( x, y ) );
+ QPen rightPen( cell->effRightBorderPen( x, y ) );
+ QPen leftPen( cell->effLeftBorderPen( x, y ) );
+ QPen topPen( cell->effTopBorderPen( x, y ) );
+
+ // paint right border
+ // - if rightmost cell
+ // - if the pen is more "worth" than the left border pen of the cell
+ // on the left
+ if ( x >= KS_colMax )
+ {
+ paintBorder |= Cell::Border_Right;
+ }
+ else
+ {
+ paintBorder |= Cell::Border_Right;
+ if ( cell->effRightBorderValue( x, y ) <
+ sheet->cellAt( x + 1, y )->effLeftBorderValue( x + 1, y ) )
+ rightPen = sheet->cellAt( x + 1, y )->effLeftBorderPen( x + 1, y );
+ }
+
+ // similiar for other borders...
+ // bottom border:
+ if ( y >= KS_rowMax )
+ {
+ paintBorder |= Cell::Border_Bottom;
+ }
+ else
+ {
+ paintBorder |= Cell::Border_Bottom;
+ if ( cell->effBottomBorderValue( x, y ) <
+ sheet->cellAt( x, y + 1 )->effTopBorderValue( x, y + 1 ) )
+ bottomPen = sheet->cellAt( x, y + 1 )->effTopBorderPen( x, y + 1 );
+ }
+
+ // left border:
+ if ( x == 1 )
+ {
+ paintBorder |= Cell::Border_Left;
+ }
+ else
+ {
+ paintBorder |= Cell::Border_Left;
+ if ( cell->effLeftBorderValue( x, y ) <
+ sheet->cellAt( x - 1, y )->effRightBorderValue( x - 1, y ) )
+ leftPen = sheet->cellAt( x - 1, y )->effRightBorderPen( x - 1, y );
+ }
+
+ // top border:
+ if ( y == 1 )
+ {
+ paintBorder |= Cell::Border_Top;
+ }
+ else
+ {
+ paintBorder |= Cell::Border_Top;
+ if ( cell->effTopBorderValue( x, y ) <
+ sheet->cellAt( x, y - 1 )->effBottomBorderValue( x, y - 1 ) )
+ topPen = sheet->cellAt( x, y - 1 )->effBottomBorderPen( x, y - 1 );
+ }
+
+ cell->paintCell( unzoomedRect, painter, d->view, dblCorner,
+ QPoint( x, y), paintBorder,
+ rightPen,bottomPen,leftPen,topPen,
+ mergedCellsPainted);
+ }
+ dblCorner.setY( dblCorner.y() + sheet->rowFormat( y )->dblHeight( ) );
+ }
+ dblCorner.setY( topPos - yOffset() );
+ dblCorner.setX( dblCorner.x() + sheet->columnFormat( x )->dblWidth( ) );
+ }
+
+ /* now paint the selection */
+ //Nb. No longer necessary to paint choose selection here as the cell reference highlight
+ //stuff takes care of this anyway
+
+ paintHighlightedRanges(painter, unzoomedRect);
+ paintNormalMarker(painter, unzoomedRect);
+
+ //restore clip region with children area
+ painter.restore();
+ //painter.setClipRegion( rgnComplete );
+}
+
+
+
+void Canvas::clipoutChildren( QPainter& painter ) const
+{
+ QRegion rgn = painter.clipRegion();
+ if ( rgn.isEmpty() )
+ rgn = QRegion( QRect( 0, 0, width(), height() ) );
+
+ const double horizontalOffset = -xOffset() * doc()->zoomedResolutionX();
+ const double verticalOffset = -yOffset() * doc()->zoomedResolutionY();
+
+ QPtrListIterator<EmbeddedObject> itObject( doc()->embeddedObjects() );
+ for( ; itObject.current(); ++itObject )
+ {
+ if ( ( itObject.current() )->sheet() == activeSheet() )
+ {
+ QRect childGeometry = doc()->zoomRect( itObject.current()->geometry());
+
+ //The clipping region is given in device coordinates
+ //so subtract the current offset (scroll position) of the canvas
+ childGeometry.moveBy( (int)horizontalOffset , (int)verticalOffset );
+
+ if (painter.window().intersects(childGeometry))
+ rgn -= childGeometry;
+
+ //painter.fillRect( doc()->zoomRect( itObject.current()->geometry() ), QColor("red" ) );
+ }
+ }
+
+ painter.setClipRegion( rgn );
+}
+
+QRect Canvas::painterWindowGeometry( const QPainter& painter ) const
+{
+ QRect zoomedWindowGeometry = painter.window();
+
+ zoomedWindowGeometry.moveBy( (int)( xOffset() * doc()->zoomedResolutionX() ) , (int)( yOffset() * doc()->zoomedResolutionY() ) );
+
+ return zoomedWindowGeometry;
+}
+
+void Canvas::paintChildren( QPainter& painter, QWMatrix& /*matrix*/ )
+{
+ QPtrListIterator<EmbeddedObject> itObject( doc()->embeddedObjects() );
+ itObject.toFirst();
+ if ( !itObject.current() )
+ return;
+
+ painter.save();
+ painter.translate( -xOffset() * doc()->zoomedResolutionX() , -yOffset() * doc()->zoomedResolutionY() );
+
+ const QRect zoomedWindowGeometry = painterWindowGeometry( painter );
+ const Sheet* sheet = activeSheet();
+
+ for( ; itObject.current(); ++itObject )
+ {
+ QRect const zoomedObjectGeometry = doc()->zoomRect( itObject.current()->geometry() );
+ if ( ( itObject.current() )->sheet() == activeSheet() &&
+ zoomedWindowGeometry.intersects( zoomedObjectGeometry ) )
+ {
+ //To prevent unnecessary redrawing of the embedded object, we only repaint
+ //if one or more of the cells underneath the object has been marked as 'dirty'.
+
+ QRect canvasRelativeGeometry = zoomedObjectGeometry;
+ canvasRelativeGeometry.moveBy( (int)( -xOffset()*doc()->zoomedResolutionX() ) ,
+ (int)( -yOffset() * doc()->zoomedResolutionY()) );
+
+ const QRect cellsUnderObject=cellsInArea( canvasRelativeGeometry );
+ bool redraw=false;
+
+ for (int x=cellsUnderObject.left();x<=cellsUnderObject.right();x++)
+ {
+ for (int y=cellsUnderObject.top();y<=cellsUnderObject.bottom();y++)
+ if ( sheet->cellIsPaintDirty( QPoint(x,y) ) )
+ {
+ redraw=true;
+ break;
+ }
+ if (redraw)
+ break;
+ }
+
+ if ( redraw )
+ itObject.current()->draw( &painter );
+ }
+ }
+ painter.restore();
+}
+
+void Canvas::paintHighlightedRanges(QPainter& painter, const KoRect& /*viewRect*/)
+{
+ QValueList<QColor> colors = choice()->colors();
+ QBrush nullBrush;
+ int index = 0;
+ Region::ConstIterator end(choice()->constEnd());
+ for (Region::ConstIterator it = choice()->constBegin(); it != end; ++it)
+ {
+ //Only paint ranges or cells on the current sheet
+ if ((*it)->sheet() != activeSheet())
+ {
+ index++;
+ continue;
+ }
+
+ QRect region = (*it)->rect().normalize();
+
+ //double positions[4];
+ //bool paintSides[4];
+ KoRect unzoomedRect;
+
+ sheetAreaToVisibleRect(region,unzoomedRect);
+ //Convert region from sheet coordinates to canvas coordinates for use with the painter
+ //retrieveMarkerInfo(region,viewRect,positions,paintSides);
+
+ QPen highlightPen( colors[(index) % colors.size()] ); // (*it)->color() );
+ painter.setPen(highlightPen);
+
+ //Adjust the canvas coordinate - rect to take account of zoom level
+
+ QRect zoomedRect;
+
+ zoomedRect.setCoords ( d->view->doc()->zoomItX(unzoomedRect.left()),
+ d->view->doc()->zoomItY(unzoomedRect.top()),
+ d->view->doc()->zoomItX(unzoomedRect.right()),
+ d->view->doc()->zoomItY(unzoomedRect.bottom()) );
+
+ //Now adjust the highlight rectangle is slightly inside the cell borders (this means that multiple highlighted cells
+ //look nicer together as the borders do not clash)
+
+ zoomedRect.setLeft(zoomedRect.left()+1);
+ zoomedRect.setTop(zoomedRect.top()+1);
+ zoomedRect.setRight(zoomedRect.right()-1);
+ zoomedRect.setBottom(zoomedRect.bottom()-1);
+
+ painter.setBrush(nullBrush);
+ painter.drawRect(zoomedRect);
+
+ //Now draw the size grip (the little rectangle on the bottom right-hand corner of the range which the user can
+ //click and drag to resize the region)
+
+
+ QBrush sizeGripBrush( colors[(index) % colors.size()] ); // (*it)->color());
+ QPen sizeGripPen(Qt::white);
+
+ painter.setPen(sizeGripPen);
+ painter.setBrush(sizeGripBrush);
+
+ painter.drawRect(zoomedRect.right()-3,zoomedRect.bottom()-3,6,6);
+ index++;
+ }
+}
+
+void Canvas::paintNormalMarker(QPainter& painter, const KoRect &viewRect)
+{
+ //Only the active element (the one with the anchor) will be drawn with a border
+
+ if( d->chooseCell )
+ return;
+
+ if (d->cellEditor)
+ return;
+
+ Region::ConstIterator end(selectionInfo()->constEnd());
+ for (Region::ConstIterator it(selectionInfo()->constBegin()); it != end; ++it)
+ {
+ QRect range = (*it)->rect().normalize();
+
+ double positions[4];
+ bool paintSides[4];
+
+ bool current = QRect(selectionInfo()->anchor(), selectionInfo()->marker()).normalize() == range;
+ QPen pen( Qt::black, 2 );
+ painter.setPen( pen );
+
+ retrieveMarkerInfo( selectionInfo()->extendToMergedAreas(range), viewRect, positions, paintSides );
+
+ double left = positions[0];
+ double top = positions[1];
+ double right = positions[2];
+ double bottom = positions[3];
+
+ bool paintLeft = paintSides[0];
+ bool paintTop = paintSides[1];
+ bool paintRight = paintSides[2];
+ bool paintBottom = paintSides[3];
+
+ /* the extra '-1's thrown in here account for the thickness of the pen.
+ want to look like this: not this:
+ * * * * * * * * * *
+ * * * *
+ * * * *
+ */
+ int l = 1;
+
+ if ( paintTop )
+ {
+ painter.drawLine( d->view->doc()->zoomItX( left ) - l, d->view->doc()->zoomItY( top ),
+ d->view->doc()->zoomItX( right ) + l, d->view->doc()->zoomItY( top ) );
+ }
+ if ( activeSheet()->layoutDirection()==Sheet::RightToLeft )
+ {
+ if ( paintRight )
+ {
+ painter.drawLine( d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( top ),
+ d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( bottom ) );
+ }
+ if ( paintLeft && paintBottom && current )
+ {
+ /* then the 'handle' in the bottom left corner is visible. */
+ painter.drawLine( d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( top ),
+ d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( bottom ) - 3 );
+ painter.drawLine( d->view->doc()->zoomItX( left ) + 4, d->view->doc()->zoomItY( bottom ),
+ d->view->doc()->zoomItX( right ) + l + 1, d->view->doc()->zoomItY( bottom ) );
+ painter.fillRect( d->view->doc()->zoomItX( left ) - 2, d->view->doc()->zoomItY( bottom ) -2, 5, 5,
+ painter.pen().color() );
+ }
+ else
+ {
+ if ( paintLeft )
+ {
+ painter.drawLine( d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( top ),
+ d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( bottom ) );
+ }
+ if ( paintBottom )
+ {
+ painter.drawLine( d->view->doc()->zoomItX( left ) - l, d->view->doc()->zoomItY( bottom ),
+ d->view->doc()->zoomItX( right ) + l + 1, d->view->doc()->zoomItY( bottom ));
+ }
+ }
+ }
+ else // activeSheet()->layoutDirection()==Sheet::LeftToRight
+ {
+ if ( paintLeft )
+ {
+ painter.drawLine( d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( top ),
+ d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( bottom ) );
+ }
+ if ( paintRight && paintBottom && current )
+ {
+ /* then the 'handle' in the bottom right corner is visible. */
+ painter.drawLine( d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( top ),
+ d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( bottom ) - 3 );
+ painter.drawLine( d->view->doc()->zoomItX( left ) - l, d->view->doc()->zoomItY( bottom ),
+ d->view->doc()->zoomItX( right ) - 3, d->view->doc()->zoomItY( bottom ) );
+ painter.fillRect( d->view->doc()->zoomItX( right ) - 2, d->view->doc()->zoomItY( bottom ) - 2, 5, 5,
+ painter.pen().color() );
+ }
+ else
+ {
+ if ( paintRight )
+ {
+ painter.drawLine( d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( top ),
+ d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( bottom ) );
+ }
+ if ( paintBottom )
+ {
+ painter.drawLine( d->view->doc()->zoomItX( left ) - l, d->view->doc()->zoomItY( bottom ),
+ d->view->doc()->zoomItX( right ) + l + 1, d->view->doc()->zoomItY( bottom ) );
+ }
+ }
+ }
+ }
+}
+
+void Canvas::sheetAreaToRect(const QRect& sheetArea, KoRect& rect)
+{
+ Sheet* sheet=activeSheet();
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ rect.setLeft(sheet->dblColumnPos( sheetArea.right()+1 ) );
+ rect.setRight(sheet->dblColumnPos( sheetArea.left() ));
+ }
+ else
+ {
+ rect.setLeft(sheet->dblColumnPos( sheetArea.left() ));
+ rect.setRight(sheet->dblColumnPos( sheetArea.right()+1 ));
+ }
+
+ rect.setTop(sheet->dblRowPos(sheetArea.top()));
+ rect.setBottom(sheet->dblRowPos(sheetArea.bottom()+1));
+
+}
+
+void Canvas::sheetAreaToVisibleRect( const QRect& sheetArea,
+ KoRect& visibleRect )
+{
+ Sheet* sheet=activeSheet();
+
+ if (!sheet)
+ return;
+
+ double dwidth=d->view->doc()->unzoomItX(width());
+ double xpos;
+ double x;
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ xpos = dwidth - sheet->dblColumnPos( sheetArea.right() ) + xOffset();
+ x = dwidth - sheet->dblColumnPos( sheetArea.left() ) + xOffset();
+ }
+ else
+ {
+ xpos = sheet->dblColumnPos( sheetArea.left() ) - xOffset();
+ x = sheet->dblColumnPos( sheetArea.right() ) - xOffset();
+ }
+
+ double ypos = sheet->dblRowPos(sheetArea.top())-yOffset();
+
+ const ColumnFormat *columnFormat = sheet->columnFormat( sheetArea.right() );
+ double tw = columnFormat->dblWidth( );
+ double w = x - xpos + tw;
+
+ double y = sheet->dblRowPos( sheetArea.bottom() ) - yOffset();
+ const RowFormat* rowFormat = sheet->rowFormat( sheetArea.bottom() );
+ double th = rowFormat->dblHeight( );
+ double h = ( y - ypos ) + th;
+
+ /* left, top, right, bottom */
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ visibleRect.setLeft(xpos - tw );
+ visibleRect.setRight(xpos - tw + w );
+ }
+ else
+ {
+ visibleRect.setLeft(xpos );
+ visibleRect.setRight(xpos + w );
+ }
+ visibleRect.setTop(ypos);
+ visibleRect.setBottom(ypos + h);
+}
+
+void Canvas::retrieveMarkerInfo( const QRect &marker,
+ const KoRect &viewRect,
+ double positions[],
+ bool paintSides[] )
+{
+
+ Sheet* sheet=activeSheet();
+
+ if (!sheet) return;
+
+ KoRect visibleRect;
+ sheetAreaToVisibleRect(marker,visibleRect);
+
+
+ /* Sheet * sheet = activeSheet();
+ if ( !sheet )
+ return;
+
+ double dWidth = d->view->doc()->unzoomItX( width() );
+
+ double xpos;
+ double x;
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ xpos = dWidth - sheet->dblColumnPos( marker.right() ) + xOffset();
+ x = dWidth - sheet->dblColumnPos( marker.left() ) + xOffset();
+ }
+ else
+ {
+ xpos = sheet->dblColumnPos( marker.left() ) - xOffset();
+ x = sheet->dblColumnPos( marker.right() ) - xOffset();
+ }
+ double ypos = sheet->dblRowPos( marker.top() ) - yOffset();
+
+ const ColumnFormat *columnFormat = sheet->columnFormat( marker.right() );
+ double tw = columnFormat->dblWidth( );
+ double w = x - xpos + tw;
+
+ double y = sheet->dblRowPos( marker.bottom() ) - yOffset();
+ const RowFormat* rowFormat = sheet->rowFormat( marker.bottom() );
+ double th = rowFormat->dblHeight( );
+ double h = ( y - ypos ) + th;
+
+ //left, top, right, bottom
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ positions[0] = xpos - tw;
+ positions[2] = xpos - tw + w;
+ }
+ else
+ {
+ positions[0] = xpos;
+ positions[2] = xpos + w;
+ }
+ positions[1] = ypos;
+ positions[3] = ypos + h;*/
+
+ /* these vars are used for clarity, the array for simpler function arguments */
+ double left = visibleRect.left();
+ double top = visibleRect.top();
+ double right = visibleRect.right();
+ double bottom = visibleRect.bottom();
+
+ /* left, top, right, bottom */
+ paintSides[0] = (viewRect.left() <= left) && (left <= viewRect.right()) &&
+ (bottom >= viewRect.top()) && (top <= viewRect.bottom());
+ paintSides[1] = (viewRect.top() <= top) && (top <= viewRect.bottom())
+ && (right >= viewRect.left()) && (left <= viewRect.right());
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ paintSides[2] = (viewRect.left() <= right ) &&
+ (right - 1 <= viewRect.right()) &&
+ (bottom >= viewRect.top()) && (top <= viewRect.bottom());
+ else
+ paintSides[2] = (viewRect.left() <= right ) &&
+ (right <= viewRect.right()) &&
+ (bottom >= viewRect.top()) && (top <= viewRect.bottom());
+ paintSides[3] = (viewRect.top() <= bottom) && (bottom <= viewRect.bottom())
+ && (right >= viewRect.left()) && (left <= viewRect.right());
+
+ positions[0] = QMAX( left, viewRect.left() );
+ positions[1] = QMAX( top, viewRect.top() );
+ positions[2] = QMIN( right, viewRect.right() );
+ positions[3] = QMIN( bottom, viewRect.bottom() );
+}
+
+
+/****************************************************************
+ *
+ * VBorder
+ *
+ ****************************************************************/
+
+VBorder::VBorder( QWidget *_parent, Canvas *_canvas, View *_view)
+ : QWidget( _parent, "", /*WNorthWestGravity*/WStaticContents | WResizeNoErase | WRepaintNoErase )
+{
+ m_pView = _view;
+ m_pCanvas = _canvas;
+ m_lSize = 0L;
+
+ setBackgroundMode( PaletteButton );
+ setMouseTracking( true );
+ m_bResize = false;
+ m_bSelection = false;
+ m_iSelectionAnchor=1;
+ m_bMousePressed = false;
+
+ m_scrollTimer = new QTimer( this );
+ connect (m_scrollTimer, SIGNAL( timeout() ), this, SLOT( doAutoScroll() ) );
+}
+
+
+VBorder::~VBorder()
+{
+ delete m_scrollTimer;
+}
+
+QSize VBorder::sizeHint() const
+{
+ return QSize( 40, 10 );
+}
+
+
+void VBorder::mousePressEvent( QMouseEvent * _ev )
+{
+ if ( !m_pView->koDocument()->isReadWrite() )
+ return;
+
+ if ( _ev->button() == LeftButton )
+ m_bMousePressed = true;
+
+ const Sheet *sheet = m_pCanvas->activeSheet();
+ if (!sheet)
+ return;
+
+ double ev_PosY = m_pCanvas->d->view->doc()->unzoomItY( _ev->pos().y() ) + m_pCanvas->yOffset();
+ double dHeight = m_pCanvas->d->view->doc()->unzoomItY( height() );
+ m_bResize = false;
+ m_bSelection = false;
+
+ // We were editing a cell -> save value and get out of editing mode
+ if ( m_pCanvas->editor() )
+ {
+ m_pCanvas->deleteEditor( true ); // save changes
+ }
+
+ m_scrollTimer->start( 50 );
+
+ // Find the first visible row and the y position of this row.
+ double y;
+ int row = sheet->topRow( m_pCanvas->yOffset(), y );
+
+ // Did the user click between two rows?
+ while ( y < ( dHeight + m_pCanvas->yOffset() ) && ( !m_bResize ) )
+ {
+ double h = sheet->rowFormat( row )->dblHeight();
+ row++;
+ if ( row > KS_rowMax )
+ row = KS_rowMax;
+ if ( ( ev_PosY >= y + h - 2 ) &&
+ ( ev_PosY <= y + h + 1 ) &&
+ !( sheet->rowFormat( row )->isHide() && row == 1 ) )
+ m_bResize = true;
+ y += h;
+ }
+
+ //if row is hide and it's the first row
+ //you mustn't resize it.
+ double tmp2;
+ int tmpRow = sheet->topRow( ev_PosY - 1, tmp2 );
+ if ( sheet->rowFormat( tmpRow )->isHide() && tmpRow == 1 )
+ m_bResize = false;
+
+ // So he clicked between two rows ?
+ if ( m_bResize )
+ {
+ // Determine row to resize
+ double tmp;
+ m_iResizedRow = sheet->topRow( ev_PosY - 1, tmp );
+ if ( !sheet->isProtected() )
+ paintSizeIndicator( _ev->pos().y(), true );
+ }
+ else
+ {
+ m_bSelection = true;
+
+ double tmp;
+ int hit_row = sheet->topRow( ev_PosY, tmp );
+ if ( hit_row > KS_rowMax )
+ return;
+
+ m_iSelectionAnchor = hit_row;
+
+ if ( !m_pView->selectionInfo()->contains( QPoint(1, hit_row) ) ||
+ !( _ev->button() == RightButton ) ||
+ !m_pView->selectionInfo()->isRowSelected() )
+ {
+ QPoint newMarker( 1, hit_row );
+ QPoint newAnchor( KS_colMax, hit_row );
+#ifdef NONCONTIGUOUSSELECTION
+ if (_ev->state() == ControlButton)
+ {
+ m_pView->selectionInfo()->extend(QRect(newAnchor, newMarker));
+ }
+ else
+#endif
+ if (_ev->state() == ShiftButton)
+ {
+ m_pView->selectionInfo()->update(newMarker);
+ }
+ else
+ {
+ m_pView->selectionInfo()->initialize(QRect(newAnchor, newMarker));
+ }
+ }
+
+ if ( _ev->button() == RightButton )
+ {
+ QPoint p = mapToGlobal( _ev->pos() );
+ m_pView->popupRowMenu( p );
+ m_bSelection = false;
+ }
+ m_pView->updateEditWidget();
+ }
+}
+
+void VBorder::mouseReleaseEvent( QMouseEvent * _ev )
+{
+ if ( m_scrollTimer->isActive() )
+ m_scrollTimer->stop();
+
+ m_bMousePressed = false;
+
+ if ( !m_pView->koDocument()->isReadWrite() )
+ return;
+
+ Sheet *sheet = m_pCanvas->activeSheet();
+ if (!sheet)
+ return;
+
+ double ev_PosY = m_pCanvas->d->view->doc()->unzoomItY( _ev->pos().y() ) + m_pCanvas->yOffset();
+
+ if ( m_bResize )
+ {
+ // Remove size indicator painted by paintSizeIndicator
+ QPainter painter;
+ painter.begin( m_pCanvas );
+ painter.setRasterOp( NotROP );
+ painter.drawLine( 0, m_iResizePos, m_pCanvas->width(), m_iResizePos );
+ painter.end();
+
+ int start = m_iResizedRow;
+ int end = m_iResizedRow;
+ QRect rect;
+ rect.setCoords( 1, m_iResizedRow, KS_colMax, m_iResizedRow );
+ if ( m_pView->selectionInfo()->isRowSelected() )
+ {
+ if ( m_pView->selectionInfo()->contains( QPoint( 1, m_iResizedRow ) ) )
+ {
+ start = m_pView->selectionInfo()->lastRange().top();
+ end = m_pView->selectionInfo()->lastRange().bottom();
+ rect = m_pView->selectionInfo()->lastRange();
+ }
+ }
+
+ double height = 0.0;
+ double y = sheet->dblRowPos( m_iResizedRow );
+ if ( ev_PosY - y <= 0.0 )
+ height = 0.0;
+ else
+ height = ev_PosY - y;
+
+ if ( !sheet->isProtected() )
+ {
+ if ( !m_pCanvas->d->view->doc()->undoLocked() )
+ {
+ //just resize
+ if ( height != 0.0 )
+ {
+ // TODO Stefan: replace this
+ UndoResizeColRow *undo = new UndoResizeColRow( m_pCanvas->d->view->doc(), m_pCanvas->activeSheet(), rect );
+ m_pCanvas->d->view->doc()->addCommand( undo );
+ }
+ }
+
+ for( int i = start; i <= end; i++ )
+ {
+ RowFormat *rl = sheet->nonDefaultRowFormat( i );
+ if ( height != 0.0 )
+ {
+ if ( !rl->isHide() )
+ rl->setDblHeight( height );
+ }
+ else
+ {
+ sheet->hideRow(*m_pView->selectionInfo());
+ }
+ }
+
+ delete m_lSize;
+ m_lSize = 0;
+ }
+ }
+ else if ( m_bSelection )
+ {
+ QRect rect = m_pView->selectionInfo()->lastRange();
+
+ // TODO: please don't remove. Right now it's useless, but it's for a future feature
+ // Norbert
+ bool m_frozen = false;
+ if ( m_frozen )
+ {
+ kdDebug(36001) << "selected: T " << rect.top() << " B " << rect.bottom() << endl;
+
+ int i;
+ RowFormat * row;
+ QValueList<int>hiddenRows;
+
+ for ( i = rect.top(); i <= rect.bottom(); ++i )
+ {
+ row = m_pView->activeSheet()->rowFormat( i );
+ if ( row->isHide() )
+ {
+ hiddenRows.append(i);
+ }
+ }
+
+ if ( hiddenRows.count() > 0 )
+ m_pView->activeSheet()->showRow(*m_pView->selectionInfo());
+ }
+ }
+
+ m_bSelection = false;
+ m_bResize = false;
+}
+
+void VBorder::equalizeRow( double resize )
+{
+ Sheet *sheet = m_pCanvas->activeSheet();
+ Q_ASSERT( sheet );
+
+ QRect selection( m_pView->selectionInfo()->selection() );
+ if ( !m_pCanvas->d->view->doc()->undoLocked() )
+ {
+ UndoResizeColRow *undo = new UndoResizeColRow( m_pCanvas->d->view->doc(), m_pCanvas->activeSheet(), selection );
+ m_pCanvas->d->view->doc()->addCommand( undo );
+ }
+ RowFormat *rl;
+ for ( int i = selection.top(); i <= selection.bottom(); i++ )
+ {
+ rl = sheet->nonDefaultRowFormat( i );
+ resize = QMAX( 2.0, resize);
+ rl->setDblHeight( resize );
+ }
+}
+
+void VBorder::mouseDoubleClickEvent(QMouseEvent*)
+{
+ Sheet *sheet = m_pCanvas->activeSheet();
+ if (!sheet)
+ return;
+
+ if ( !m_pView->koDocument()->isReadWrite() || sheet->isProtected() )
+ return;
+
+ sheet->adjustRow(*m_pCanvas->selectionInfo());
+}
+
+
+void VBorder::mouseMoveEvent( QMouseEvent * _ev )
+{
+ if ( !m_pView->koDocument()->isReadWrite() )
+ return;
+
+ Sheet *sheet = m_pCanvas->activeSheet();
+
+ if (!sheet)
+ return;
+
+ double ev_PosY = m_pCanvas->d->view->doc()->unzoomItY( _ev->pos().y() ) + m_pCanvas->yOffset();
+ double dHeight = m_pCanvas->d->view->doc()->unzoomItY( height() );
+
+ // The button is pressed and we are resizing ?
+ if ( m_bResize )
+ {
+ if ( !sheet->isProtected() )
+ paintSizeIndicator( _ev->pos().y(), false );
+ }
+ // The button is pressed and we are selecting ?
+ else if ( m_bSelection )
+ {
+ double y;
+ int row = sheet->topRow( ev_PosY, y );
+ if ( row > KS_rowMax )
+ return;
+
+ QPoint newAnchor = m_pView->selectionInfo()->anchor();
+ QPoint newMarker = m_pView->selectionInfo()->marker();
+ newMarker.setY( row );
+ newAnchor.setY( m_iSelectionAnchor );
+ m_pView->selectionInfo()->update(newMarker);
+
+ if ( _ev->pos().y() < 0 )
+ m_pCanvas->vertScrollBar()->setValue( m_pCanvas->d->view->doc()->zoomItY( ev_PosY ) );
+ else if ( _ev->pos().y() > m_pCanvas->height() )
+ {
+ if ( row < KS_rowMax )
+ {
+ RowFormat *rl = sheet->rowFormat( row + 1 );
+ y = sheet->dblRowPos( row + 1 );
+ m_pCanvas->vertScrollBar()->setValue ((int) (m_pCanvas->d->view->doc()->zoomItY
+ (ev_PosY + rl->dblHeight()) - dHeight));
+ }
+ }
+ }
+ // No button is pressed and the mouse is just moved
+ else
+ {
+
+ //What is the internal size of 1 pixel
+ const double unzoomedPixel = m_pCanvas->d->view->doc()->unzoomItY( 1 );
+ double y;
+ int tmpRow = sheet->topRow( m_pCanvas->yOffset(), y );
+
+ while ( y < m_pCanvas->d->view->doc()->unzoomItY( height() ) + m_pCanvas->yOffset() )
+ {
+ double h = sheet->rowFormat( tmpRow )->dblHeight();
+ //if col is hide and it's the first column
+ //you mustn't resize it.
+ if ( ev_PosY >= y + h - 2 * unzoomedPixel &&
+ ev_PosY <= y + h + unzoomedPixel &&
+ !( sheet->rowFormat( tmpRow )->isHide() && tmpRow == 1 ) )
+ {
+ setCursor( splitVCursor );
+ return;
+ }
+ y += h;
+ tmpRow++;
+ }
+ setCursor( arrowCursor );
+ }
+}
+
+void VBorder::doAutoScroll()
+{
+ if ( !m_bMousePressed )
+ {
+ m_scrollTimer->stop();
+ return;
+ }
+
+ QPoint pos( mapFromGlobal( QCursor::pos() ) );
+
+ if ( pos.y() < 0 || pos.y() > height() )
+ {
+ QMouseEvent * event = new QMouseEvent( QEvent::MouseMove, pos, 0, 0 );
+ mouseMoveEvent( event );
+ delete event;
+ }
+
+ //Restart timer
+ m_scrollTimer->start( 50 );
+}
+
+void VBorder::wheelEvent( QWheelEvent* _ev )
+{
+ if ( m_pCanvas->vertScrollBar() )
+ QApplication::sendEvent( m_pCanvas->vertScrollBar(), _ev );
+}
+
+
+void VBorder::paintSizeIndicator( int mouseY, bool firstTime )
+{
+ Sheet *sheet = m_pCanvas->activeSheet();
+ if (!sheet)
+ return;
+
+ QPainter painter;
+ painter.begin( m_pCanvas );
+ painter.setRasterOp( NotROP );
+
+ if ( !firstTime )
+ painter.drawLine( 0, m_iResizePos, m_pCanvas->width(), m_iResizePos );
+
+ m_iResizePos = mouseY;
+
+ // Dont make the row have a height < 2 pixel.
+ int y = m_pCanvas->d->view->doc()->zoomItY( sheet->dblRowPos( m_iResizedRow ) - m_pCanvas->yOffset() );
+ if ( m_iResizePos < y + 2 )
+ m_iResizePos = y;
+
+ painter.drawLine( 0, m_iResizePos, m_pCanvas->width(), m_iResizePos );
+
+ painter.end();
+
+ QString tmpSize;
+ if ( m_iResizePos != y )
+ tmpSize = i18n("Height: %1 %2").arg( KoUnit::toUserValue( m_pCanvas->doc()->unzoomItY( m_iResizePos - y ),
+ m_pView->doc()->unit() ) )
+ .arg( m_pView->doc()->unitName() );
+ else
+ tmpSize = i18n( "Hide Row" );
+
+ painter.begin( this );
+ int len = painter.fontMetrics().width( tmpSize );
+ int hei = painter.fontMetrics().height();
+ painter.end();
+
+ if ( !m_lSize )
+ {
+ m_lSize = new QLabel( m_pCanvas );
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ m_lSize->setGeometry( m_pCanvas->width() - len - 5,
+ y + 3, len + 2, hei + 2 );
+ else
+ m_lSize->setGeometry( 3, y + 3, len + 2,hei + 2 );
+
+ m_lSize->setAlignment( Qt::AlignVCenter );
+ m_lSize->setText( tmpSize );
+ m_lSize->setPalette( QToolTip::palette() );
+ m_lSize->show();
+ }
+ else
+ {
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ m_lSize->setGeometry( m_pCanvas->width() - len - 5,
+ y + 3, len + 2, hei + 2 );
+ else
+ m_lSize->setGeometry( 3, y + 3, len + 2,hei + 2 );
+
+ m_lSize->setText( tmpSize );
+ }
+}
+
+void VBorder::updateRows( int from, int to )
+{
+ Sheet *sheet = m_pCanvas->activeSheet();
+ if ( !sheet )
+ return;
+
+ int y0 = sheet->rowPos( from, m_pCanvas );
+ int y1 = sheet->rowPos( to+1, m_pCanvas );
+ update( 0, y0, width(), y1-y0 );
+}
+
+void VBorder::paintEvent( QPaintEvent* _ev )
+{
+ Sheet *sheet = m_pCanvas->activeSheet();
+ if ( !sheet )
+ return;
+
+ QPainter painter( this );
+ QColor highlightColor = View::highlightColor();
+ QPen pen( Qt::black, 1 );
+ painter.setPen( pen );
+ // painter.setBackgroundColor( colorGroup().base() );
+
+ // painter.eraseRect( _ev->rect() );
+
+ //QFontMetrics fm = painter.fontMetrics();
+ // Matthias Elter: This causes a SEGFAULT in ~QPainter!
+ // Only god and the trolls know why ;-)
+ // bah...took me quite some time to track this one down...
+
+ painter.setClipRect( _ev->rect() );
+
+ double yPos;
+ //Get the top row and the current y-position
+ int y = sheet->topRow( (m_pCanvas->d->view->doc()->unzoomItY( _ev->rect().y() ) + m_pCanvas->yOffset()), yPos );
+ //Align to the offset
+ yPos = yPos - m_pCanvas->yOffset();
+ int width = m_pCanvas->d->view->doc()->zoomItX( YBORDER_WIDTH );
+
+ QFont normalFont = painter.font();
+ if ( m_pCanvas->d->view->doc()->zoom() < 100 )
+ {
+ normalFont.setPointSizeFloat( 0.01 * m_pCanvas->d->view->doc()->zoom() *
+ normalFont.pointSizeFloat() );
+ }
+ QFont boldFont = normalFont;
+ boldFont.setBold( true );
+
+ //Loop through the rows, until we are out of range
+ while ( yPos <= m_pCanvas->d->view->doc()->unzoomItY( _ev->rect().bottom() ) )
+ {
+ bool selected = (m_pView->selectionInfo()->isRowSelected(y));
+ bool highlighted = (!selected && m_pView->selectionInfo()->isRowAffected(y));
+
+ const RowFormat *row_lay = sheet->rowFormat( y );
+ int zoomedYPos = m_pCanvas->d->view->doc()->zoomItY( yPos );
+ int height = m_pCanvas->d->view->doc()->zoomItY( yPos + row_lay->dblHeight() ) - zoomedYPos;
+
+ if ( selected )
+ {
+ QBrush fillSelected( highlightColor );
+ qDrawPlainRect ( &painter, 0, zoomedYPos, width, height+1, highlightColor.dark(150),
+ 1, &fillSelected );
+ }
+ else if ( highlighted )
+ {
+ QBrush fillHighlighted( highlightColor );
+ qDrawPlainRect ( &painter, 0, zoomedYPos, width, height+1, highlightColor.dark(150),
+ 1, &fillHighlighted );
+ }
+ else
+ {
+ QColor c = colorGroup().background();
+ QBrush fill( c );
+ qDrawPlainRect ( &painter, 0, zoomedYPos, width, height+1, c.dark(150),
+ 1, &fill );
+ }
+
+ QString rowText = QString::number( y );
+
+ // Reset painter
+ painter.setFont( normalFont );
+ painter.setPen( colorGroup().text() );
+
+ if ( selected )
+ painter.setPen( colorGroup().highlightedText() );
+ else if ( highlighted )
+ painter.setFont( boldFont );
+
+ int len = painter.fontMetrics().width( rowText );
+ if (!row_lay->isHide())
+ painter.drawText( ( width-len )/2, zoomedYPos +
+ ( height + painter.fontMetrics().ascent() -
+ painter.fontMetrics().descent() ) / 2, rowText );
+
+ yPos += row_lay->dblHeight();
+ y++;
+ }
+}
+
+
+void VBorder::focusOutEvent( QFocusEvent* )
+{
+ if ( m_scrollTimer->isActive() )
+ m_scrollTimer->stop();
+ m_bMousePressed = false;
+}
+
+
+/****************************************************************
+ *
+ * HBorder
+ *
+ ****************************************************************/
+
+HBorder::HBorder( QWidget *_parent, Canvas *_canvas,View *_view )
+ : QWidget( _parent, "", /*WNorthWestGravity*/ WStaticContents| WResizeNoErase | WRepaintNoErase )
+{
+ m_pView = _view;
+ m_pCanvas = _canvas;
+ m_lSize = 0L;
+ setBackgroundMode( PaletteButton );
+ setMouseTracking( true );
+ m_bResize = false;
+ m_bSelection = false;
+ m_iSelectionAnchor=1;
+ m_bMousePressed = false;
+
+ m_scrollTimer = new QTimer( this );
+ connect( m_scrollTimer, SIGNAL( timeout() ), this, SLOT( doAutoScroll() ) );
+}
+
+
+HBorder::~HBorder()
+{
+ delete m_scrollTimer;
+}
+
+QSize HBorder::sizeHint() const
+{
+ return QSize( 40, 10 );
+}
+
+void HBorder::mousePressEvent( QMouseEvent * _ev )
+{
+ if (!m_pView->koDocument()->isReadWrite())
+ return;
+
+ if ( _ev->button() == LeftButton )
+ m_bMousePressed = true;
+
+ const Sheet *sheet = m_pCanvas->activeSheet();
+ if (!sheet)
+ return;
+
+ // We were editing a cell -> save value and get out of editing mode
+ if ( m_pCanvas->editor() )
+ {
+ m_pCanvas->deleteEditor( true ); // save changes
+ }
+
+ m_scrollTimer->start( 50 );
+
+ double ev_PosX;
+ double dWidth = m_pCanvas->d->view->doc()->unzoomItX( width() );
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ ev_PosX = dWidth - m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
+ else
+ ev_PosX = m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
+ m_bResize = false;
+ m_bSelection = false;
+
+ // Find the first visible column and the x position of this column.
+ double x;
+
+ const double unzoomedPixel = m_pCanvas->d->view->doc()->unzoomItX( 1 );
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ int tmpCol = sheet->leftColumn( m_pCanvas->xOffset(), x );
+
+ kdDebug() << "evPos: " << ev_PosX << ", x: " << x << ", COL: " << tmpCol << endl;
+ while ( ev_PosX > x && ( !m_bResize ) )
+ {
+ double w = sheet->columnFormat( tmpCol )->dblWidth();
+
+ kdDebug() << "evPos: " << ev_PosX << ", x: " << x << ", w: " << w << ", COL: " << tmpCol << endl;
+
+ ++tmpCol;
+ if ( tmpCol > KS_colMax )
+ tmpCol = KS_colMax;
+ //if col is hide and it's the first column
+ //you mustn't resize it.
+
+ if ( ev_PosX >= x + w - unzoomedPixel &&
+ ev_PosX <= x + w + unzoomedPixel &&
+ !( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 1 ) )
+ {
+ m_bResize = true;
+ }
+ x += w;
+ }
+
+ //if col is hide and it's the first column
+ //you mustn't resize it.
+ double tmp2;
+ tmpCol = sheet->leftColumn( dWidth - ev_PosX + 1, tmp2 );
+ if ( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 0 )
+ {
+ kdDebug() << "No resize: " << tmpCol << ", " << sheet->columnFormat( tmpCol )->isHide() << endl;
+ m_bResize = false;
+ }
+
+ kdDebug() << "Resize: " << m_bResize << endl;
+ }
+ else
+ {
+ int col = sheet->leftColumn( m_pCanvas->xOffset(), x );
+
+ // Did the user click between two columns?
+ while ( x < ( dWidth + m_pCanvas->xOffset() ) && ( !m_bResize ) )
+ {
+ double w = sheet->columnFormat( col )->dblWidth();
+ col++;
+ if ( col > KS_colMax )
+ col = KS_colMax;
+ if ( ( ev_PosX >= x + w - unzoomedPixel ) &&
+ ( ev_PosX <= x + w + unzoomedPixel ) &&
+ !( sheet->columnFormat( col )->isHide() && col == 1 ) )
+ m_bResize = true;
+ x += w;
+ }
+
+ //if col is hide and it's the first column
+ //you mustn't resize it.
+ double tmp2;
+ int tmpCol = sheet->leftColumn( ev_PosX - 1, tmp2 );
+ if ( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 1 )
+ m_bResize = false;
+ }
+
+ // So he clicked between two rows ?
+ if ( m_bResize )
+ {
+ // Determine the column to resize
+ double tmp;
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ m_iResizedColumn = sheet->leftColumn( ev_PosX - 1, tmp );
+ // kdDebug() << "RColumn: " << m_iResizedColumn << ", PosX: " << ev_PosX << endl;
+
+ if ( !sheet->isProtected() )
+ paintSizeIndicator( _ev->pos().x(), true );
+ }
+ else
+ {
+ m_iResizedColumn = sheet->leftColumn( ev_PosX - 1, tmp );
+
+ if ( !sheet->isProtected() )
+ paintSizeIndicator( _ev->pos().x(), true );
+ }
+
+ // kdDebug() << "Column: " << m_iResizedColumn << endl;
+ }
+ else
+ {
+ m_bSelection = true;
+
+ double tmp;
+ int hit_col = sheet->leftColumn( ev_PosX, tmp );
+ if ( hit_col > KS_colMax )
+ return;
+
+ m_iSelectionAnchor = hit_col;
+
+ if ( !m_pView->selectionInfo()->contains( QPoint( hit_col, 1 ) ) ||
+ !( _ev->button() == RightButton ) ||
+ !m_pView->selectionInfo()->isColumnSelected() )
+ {
+ QPoint newMarker( hit_col, 1 );
+ QPoint newAnchor( hit_col, KS_rowMax );
+#ifdef NONCONTIGUOUSSELECTION
+ if (_ev->state() == ControlButton)
+ {
+ m_pView->selectionInfo()->extend(QRect(newAnchor, newMarker));
+ }
+ else
+#endif
+ if (_ev->state() == ShiftButton)
+ {
+ m_pView->selectionInfo()->update(newMarker);
+ }
+ else
+ {
+ m_pView->selectionInfo()->initialize(QRect(newAnchor, newMarker));
+ }
+ }
+
+ if ( _ev->button() == RightButton )
+ {
+ QPoint p = mapToGlobal( _ev->pos() );
+ m_pView->popupColumnMenu( p );
+ m_bSelection = false;
+ }
+ m_pView->updateEditWidget();
+ }
+}
+
+void HBorder::mouseReleaseEvent( QMouseEvent * _ev )
+{
+ if ( m_scrollTimer->isActive() )
+ m_scrollTimer->stop();
+
+ m_bMousePressed = false;
+
+ if ( !m_pView->koDocument()->isReadWrite() )
+ return;
+
+ Sheet * sheet = m_pCanvas->activeSheet();
+ if (!sheet)
+ return;
+
+ if ( m_bResize )
+ {
+ double dWidth = m_pCanvas->d->view->doc()->unzoomItX( width() );
+ double ev_PosX;
+
+ // Remove size indicator painted by paintSizeIndicator
+ QPainter painter;
+ painter.begin( m_pCanvas );
+ painter.setRasterOp( NotROP );
+ painter.drawLine( m_iResizePos, 0, m_iResizePos, m_pCanvas->height() );
+ painter.end();
+
+ int start = m_iResizedColumn;
+ int end = m_iResizedColumn;
+ QRect rect;
+ rect.setCoords( m_iResizedColumn, 1, m_iResizedColumn, KS_rowMax );
+ if ( m_pView->selectionInfo()->isColumnSelected() )
+ {
+ if ( m_pView->selectionInfo()->contains( QPoint( m_iResizedColumn, 1 ) ) )
+ {
+ start = m_pView->selectionInfo()->lastRange().left();
+ end = m_pView->selectionInfo()->lastRange().right();
+ rect = m_pView->selectionInfo()->lastRange();
+ }
+ }
+
+ double width = 0.0;
+ double x;
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ ev_PosX = dWidth - m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
+ else
+ ev_PosX = m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
+
+ x = sheet->dblColumnPos( m_iResizedColumn );
+
+ if ( ev_PosX - x <= 0.0 )
+ width = 0.0;
+ else
+ width = ev_PosX - x;
+
+ if ( !sheet->isProtected() )
+ {
+ if ( !m_pCanvas->d->view->doc()->undoLocked() )
+ {
+ //just resize
+ if ( width != 0.0 )
+ {
+ // TODO Stefan: replace this
+ UndoResizeColRow *undo = new UndoResizeColRow( m_pCanvas->d->view->doc(), m_pCanvas->activeSheet(), rect );
+ m_pCanvas->d->view->doc()->addCommand( undo );
+ }
+ }
+
+ for( int i = start; i <= end; i++ )
+ {
+ ColumnFormat *cl = sheet->nonDefaultColumnFormat( i );
+ if ( width != 0.0 )
+ {
+ if ( !cl->isHide() )
+ cl->setDblWidth( width );
+ }
+ else
+ {
+ sheet->hideColumn(*m_pView->selectionInfo());
+ }
+ }
+
+ delete m_lSize;
+ m_lSize = 0;
+ }
+ }
+ else if ( m_bSelection )
+ {
+ QRect rect = m_pView->selectionInfo()->lastRange();
+
+ // TODO: please don't remove. Right now it's useless, but it's for a future feature
+ // Norbert
+ bool m_frozen = false;
+ if ( m_frozen )
+ {
+ kdDebug(36001) << "selected: L " << rect.left() << " R " << rect.right() << endl;
+
+ int i;
+ ColumnFormat * col;
+ QValueList<int>hiddenCols;
+
+ for ( i = rect.left(); i <= rect.right(); ++i )
+ {
+ col = m_pView->activeSheet()->columnFormat( i );
+ if ( col->isHide() )
+ {
+ hiddenCols.append(i);
+ }
+ }
+
+ if ( hiddenCols.count() > 0 )
+ m_pView->activeSheet()->showColumn(*m_pView->selectionInfo());
+ }
+ }
+
+ m_bSelection = false;
+ m_bResize = false;
+}
+
+void HBorder::equalizeColumn( double resize )
+{
+ Sheet *sheet = m_pCanvas->activeSheet();
+ Q_ASSERT( sheet );
+
+ QRect selection( m_pView->selectionInfo()->selection() );
+ if ( !m_pCanvas->d->view->doc()->undoLocked() )
+ {
+ UndoResizeColRow *undo = new UndoResizeColRow( m_pCanvas->d->view->doc(), m_pCanvas->activeSheet(), selection );
+ m_pCanvas->d->view->doc()->addCommand( undo );
+ }
+ ColumnFormat *cl;
+ for ( int i = selection.left(); i <= selection.right(); i++ )
+ {
+ cl = sheet->nonDefaultColumnFormat( i );
+ resize = QMAX( 2.0, resize );
+ cl->setDblWidth( resize );
+ }
+
+}
+
+void HBorder::mouseDoubleClickEvent(QMouseEvent*)
+{
+ Sheet *sheet = m_pCanvas->activeSheet();
+ if (!sheet)
+ return;
+
+ if ( !m_pView->koDocument()->isReadWrite() || sheet->isProtected() )
+ return;
+
+ sheet->adjustColumn(*m_pCanvas->selectionInfo());
+}
+
+void HBorder::mouseMoveEvent( QMouseEvent * _ev )
+{
+ if ( !m_pView->koDocument()->isReadWrite() )
+ return;
+
+ Sheet *sheet = m_pCanvas->activeSheet();
+
+ if (!sheet)
+ return;
+
+ double dWidth = m_pCanvas->d->view->doc()->unzoomItX( width() );
+ double ev_PosX;
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ ev_PosX = dWidth - m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
+ else
+ ev_PosX = m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
+
+ // The button is pressed and we are resizing ?
+ if ( m_bResize )
+ {
+ if ( !sheet->isProtected() )
+ paintSizeIndicator( _ev->pos().x(), false );
+ }
+ // The button is pressed and we are selecting ?
+ else if ( m_bSelection )
+ {
+ double x;
+ int col = sheet->leftColumn( ev_PosX, x );
+
+ if ( col > KS_colMax )
+ return;
+
+ QPoint newMarker = m_pView->selectionInfo()->marker();
+ QPoint newAnchor = m_pView->selectionInfo()->anchor();
+ newMarker.setX( col );
+ newAnchor.setX( m_iSelectionAnchor );
+ m_pView->selectionInfo()->update(newMarker);
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ if ( _ev->pos().x() < width() - m_pCanvas->width() )
+ {
+ ColumnFormat *cl = sheet->columnFormat( col + 1 );
+ x = sheet->dblColumnPos( col + 1 );
+ m_pCanvas->horzScrollBar()->setValue ( m_pCanvas->horzScrollBar()->maxValue() - (int)
+ (m_pCanvas->d->view->doc()->zoomItX (ev_PosX + cl->dblWidth()) - m_pCanvas->d->view->doc()->unzoomItX( m_pCanvas->width() )));
+ }
+ else if ( _ev->pos().x() > width() )
+ m_pCanvas->horzScrollBar()->setValue( m_pCanvas->horzScrollBar()->maxValue() - m_pCanvas->d->view->doc()->zoomItX( ev_PosX - dWidth + m_pCanvas->d->view->doc()->unzoomItX( m_pCanvas->width() ) ) );
+ }
+ else
+ {
+ if ( _ev->pos().x() < 0 )
+ m_pCanvas->horzScrollBar()->setValue( m_pCanvas->d->view->doc()->zoomItX( ev_PosX ) );
+ else if ( _ev->pos().x() > m_pCanvas->width() )
+ {
+ if ( col < KS_colMax )
+ {
+ ColumnFormat *cl = sheet->columnFormat( col + 1 );
+ x = sheet->dblColumnPos( col + 1 );
+ m_pCanvas->horzScrollBar()->setValue ((int)
+ (m_pCanvas->d->view->doc()->zoomItX (ev_PosX + cl->dblWidth()) - dWidth));
+ }
+ }
+ }
+
+ }
+ // No button is pressed and the mouse is just moved
+ else
+ {
+ //What is the internal size of 1 pixel
+ const double unzoomedPixel = m_pCanvas->d->view->doc()->unzoomItX( 1 );
+ double x;
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ int tmpCol = sheet->leftColumn( m_pCanvas->xOffset(), x );
+
+ while ( ev_PosX > x )
+ {
+ double w = sheet->columnFormat( tmpCol )->dblWidth();
+ ++tmpCol;
+
+ //if col is hide and it's the first column
+ //you mustn't resize it.
+ if ( ev_PosX >= x + w - unzoomedPixel &&
+ ev_PosX <= x + w + unzoomedPixel &&
+ !( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 0 ) )
+ {
+ setCursor( splitHCursor );
+ return;
+ }
+ x += w;
+ }
+ setCursor( arrowCursor );
+ }
+ else
+ {
+ int tmpCol = sheet->leftColumn( m_pCanvas->xOffset(), x );
+
+ while ( x < m_pCanvas->d->view->doc()->unzoomItY( width() ) + m_pCanvas->xOffset() )
+ {
+ double w = sheet->columnFormat( tmpCol )->dblWidth();
+ //if col is hide and it's the first column
+ //you mustn't resize it.
+ if ( ev_PosX >= x + w - unzoomedPixel &&
+ ev_PosX <= x + w + unzoomedPixel &&
+ !( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 1 ) )
+ {
+ setCursor( splitHCursor );
+ return;
+ }
+ x += w;
+ tmpCol++;
+ }
+ setCursor( arrowCursor );
+ }
+ }
+}
+
+void HBorder::doAutoScroll()
+{
+ if ( !m_bMousePressed )
+ {
+ m_scrollTimer->stop();
+ return;
+ }
+
+ QPoint pos( mapFromGlobal( QCursor::pos() ) );
+
+ if ( pos.x() < 0 || pos.x() > width() )
+ {
+ QMouseEvent * event = new QMouseEvent( QEvent::MouseMove, pos, 0, 0 );
+ mouseMoveEvent( event );
+ delete event;
+ }
+
+ //Restart timer
+ m_scrollTimer->start( 50 );
+}
+
+void HBorder::wheelEvent( QWheelEvent* _ev )
+{
+ if ( m_pCanvas->horzScrollBar() )
+ QApplication::sendEvent( m_pCanvas->horzScrollBar(), _ev );
+}
+
+void HBorder::resizeEvent( QResizeEvent* _ev )
+{
+ // workaround to allow horizontal resizing and zoom changing when sheet
+ // direction and interface direction don't match (e.g. an RTL sheet on an
+ // LTR interface)
+ if ( m_pCanvas->activeSheet() && m_pCanvas->activeSheet()->layoutDirection()==Sheet::RightToLeft && !QApplication::reverseLayout() )
+ {
+ int dx = _ev->size().width() - _ev->oldSize().width();
+ scroll(dx, 0);
+ }
+ else if ( m_pCanvas->activeSheet() && m_pCanvas->activeSheet()->layoutDirection()==Sheet::LeftToRight && QApplication::reverseLayout() )
+ {
+ int dx = _ev->size().width() - _ev->oldSize().width();
+ scroll(-dx, 0);
+ }
+}
+
+void HBorder::paintSizeIndicator( int mouseX, bool firstTime )
+{
+ Sheet *sheet = m_pCanvas->activeSheet();
+ if (!sheet)
+ return;
+
+ QPainter painter;
+ painter.begin( m_pCanvas );
+ painter.setRasterOp( NotROP );
+
+ if ( !firstTime )
+ painter.drawLine( m_iResizePos, 0, m_iResizePos, m_pCanvas->height() );
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ m_iResizePos = mouseX + m_pCanvas->width() - width();
+ else
+ m_iResizePos = mouseX;
+
+ // Dont make the column have a width < 2 pixels.
+ int x = m_pCanvas->d->view->doc()->zoomItX( sheet->dblColumnPos( m_iResizedColumn ) - m_pCanvas->xOffset() );
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ x = m_pCanvas->width() - x;
+
+ if ( m_iResizePos > x - 2 )
+ m_iResizePos = x;
+ }
+ else
+ {
+ if ( m_iResizePos < x + 2 )
+ m_iResizePos = x;
+ }
+
+ painter.drawLine( m_iResizePos, 0, m_iResizePos, m_pCanvas->height() );
+
+ painter.end();
+
+ QString tmpSize;
+ if ( m_iResizePos != x )
+ tmpSize = i18n("Width: %1 %2")
+ .arg( KGlobal::locale()->formatNumber( KoUnit::toUserValue( m_pCanvas->doc()->unzoomItX( (sheet->layoutDirection()==Sheet::RightToLeft) ? x - m_iResizePos : m_iResizePos - x ),
+ m_pView->doc()->unit() )))
+ .arg( m_pView->doc()->unitName() );
+ else
+ tmpSize = i18n( "Hide Column" );
+
+ painter.begin( this );
+ int len = painter.fontMetrics().width( tmpSize );
+ int hei = painter.fontMetrics().height();
+ painter.end();
+
+ if ( !m_lSize )
+ {
+ m_lSize = new QLabel( m_pCanvas );
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ m_lSize->setGeometry( x - len - 5, 3, len + 2, hei + 2 );
+ else
+ m_lSize->setGeometry( x + 3, 3, len + 2, hei + 2 );
+
+ m_lSize->setAlignment( Qt::AlignVCenter );
+ m_lSize->setText( tmpSize );
+ m_lSize->setPalette( QToolTip::palette() );
+ m_lSize->show();
+ }
+ else
+ {
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ m_lSize->setGeometry( x - len - 5, 3, len + 2, hei + 2 );
+ else
+ m_lSize->setGeometry( x + 3, 3, len + 2, hei + 2 );
+
+ m_lSize->setText( tmpSize );
+ }
+}
+
+void HBorder::updateColumns( int from, int to )
+{
+ Sheet *sheet = m_pCanvas->activeSheet();
+ if ( !sheet )
+ return;
+
+ int x0 = sheet->columnPos( from, m_pCanvas );
+ int x1 = sheet->columnPos( to+1, m_pCanvas );
+ update( x0, 0, x1-x0, height() );
+}
+
+void HBorder::paintEvent( QPaintEvent* _ev )
+{
+ Sheet * sheet = m_pCanvas->activeSheet();
+ if ( !sheet )
+ return;
+
+ QColor highlightColor = View::highlightColor();
+ QPainter painter( this );
+ QPen pen( Qt::black, 1 );
+ painter.setPen( pen );
+ painter.setBackgroundColor( white );
+
+ painter.setClipRect( _ev->rect() );
+
+ // painter.eraseRect( _ev->rect() );
+
+ //QFontMetrics fm = painter.fontMetrics();
+ // Matthias Elter: This causes a SEGFAULT in ~QPainter!
+ // Only god and the trolls know why ;-)
+ // bah...took me quite some time to track this one down...
+
+ double xPos;
+ int x;
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ //Get the left column and the current x-position
+ x = sheet->leftColumn( int( m_pCanvas->d->view->doc()->unzoomItX( width() ) - m_pCanvas->d->view->doc()->unzoomItX( _ev->rect().x() ) + m_pCanvas->xOffset() ), xPos );
+ //Align to the offset
+ xPos = m_pCanvas->d->view->doc()->unzoomItX( width() ) - xPos + m_pCanvas->xOffset();
+ }
+ else
+ {
+ //Get the left column and the current x-position
+ x = sheet->leftColumn( int( m_pCanvas->d->view->doc()->unzoomItX( _ev->rect().x() ) + m_pCanvas->xOffset() ), xPos );
+ //Align to the offset
+ xPos = xPos - m_pCanvas->xOffset();
+ }
+
+ int height = m_pCanvas->d->view->doc()->zoomItY( painter.font().pointSizeFloat() + 5 );
+
+ QFont normalFont = painter.font();
+ if ( m_pCanvas->d->view->doc()->zoom() < 100 )
+ {
+ normalFont.setPointSizeFloat( 0.01 * m_pCanvas->d->view->doc()->zoom() *
+ normalFont.pointSizeFloat() );
+ }
+ QFont boldFont = normalFont;
+ boldFont.setBold( true );
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ if ( x > KS_colMax )
+ x = KS_colMax;
+
+ xPos -= sheet->columnFormat( x )->dblWidth();
+
+ //Loop through the columns, until we are out of range
+ while ( xPos <= m_pCanvas->d->view->doc()->unzoomItX( _ev->rect().right() ) )
+ {
+ bool selected = (m_pView->selectionInfo()->isColumnSelected(x));
+ bool highlighted = (!selected && m_pView->selectionInfo()->isColumnAffected(x));
+
+ const ColumnFormat * col_lay = sheet->columnFormat( x );
+ int zoomedXPos = m_pCanvas->d->view->doc()->zoomItX( xPos );
+ int width = m_pCanvas->d->view->doc()->zoomItX( xPos + col_lay->dblWidth() ) - zoomedXPos;
+
+ if ( selected )
+ {
+ QBrush fillSelected( highlightColor );
+ qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, highlightColor.dark(150),
+ 1, &fillSelected );
+ }
+ else if ( highlighted )
+ {
+ QBrush fillHighlighted( highlightColor );
+ qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, highlightColor.dark(150),
+ 1, &fillHighlighted );
+ }
+ else
+ {
+ QColor c = colorGroup().background();
+ QBrush fill( c );
+ qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, c.dark(150),
+ 1, &fill );
+ }
+
+ // Reset painter
+ painter.setFont( normalFont );
+ painter.setPen( colorGroup().text() );
+
+ if ( selected )
+ painter.setPen( colorGroup().highlightedText() );
+ else if ( highlighted )
+ painter.setFont( boldFont );
+ if ( !m_pView->activeSheet()->getShowColumnNumber() )
+ {
+ QString colText = Cell::columnName( x );
+ int len = painter.fontMetrics().width( colText );
+ if ( !col_lay->isHide() )
+ painter.drawText( zoomedXPos + ( width - len ) / 2,
+ ( height + painter.fontMetrics().ascent() -
+ painter.fontMetrics().descent() ) / 2, colText );
+ }
+ else
+ {
+ QString tmp;
+ int len = painter.fontMetrics().width( tmp.setNum(x) );
+ if (!col_lay->isHide())
+ painter.drawText( zoomedXPos + ( width - len ) / 2,
+ ( height + painter.fontMetrics().ascent() -
+ painter.fontMetrics().descent() ) / 2,
+ tmp.setNum(x) );
+ }
+ xPos += col_lay->dblWidth();
+ --x;
+ }
+ }
+ else
+ {
+ //Loop through the columns, until we are out of range
+ while ( xPos <= m_pCanvas->d->view->doc()->unzoomItX( _ev->rect().right() ) )
+ {
+ bool selected = (m_pView->selectionInfo()->isColumnSelected(x));
+ bool highlighted = (!selected && m_pView->selectionInfo()->isColumnAffected(x));
+
+ const ColumnFormat *col_lay = sheet->columnFormat( x );
+ int zoomedXPos = m_pCanvas->d->view->doc()->zoomItX( xPos );
+ int width = m_pCanvas->d->view->doc()->zoomItX( xPos + col_lay->dblWidth() ) - zoomedXPos;
+
+ if ( selected )
+ {
+ QBrush fillSelected( highlightColor );
+ qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, highlightColor.dark(),
+ 1, &fillSelected );
+ }
+ else if ( highlighted )
+ {
+ QBrush fillHighlighted( highlightColor );
+ qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, highlightColor.dark(),
+ 1, &fillHighlighted );
+ }
+ else
+ {
+ QColor c = colorGroup().background();
+ QBrush fill( c );
+ qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, c.dark(150),
+ 1, &fill );
+ }
+
+ // Reset painter
+ painter.setFont( normalFont );
+ painter.setPen( colorGroup().text() );
+
+ if ( selected )
+ painter.setPen( colorGroup().highlightedText() );
+ else if ( highlighted )
+ painter.setFont( boldFont );
+ if ( !m_pView->activeSheet()->getShowColumnNumber() )
+ {
+ QString colText = Cell::columnName( x );
+ int len = painter.fontMetrics().width( colText );
+ if (!col_lay->isHide())
+ painter.drawText( zoomedXPos + ( width - len ) / 2,
+ ( height + painter.fontMetrics().ascent() -
+ painter.fontMetrics().descent() ) / 2, colText );
+ }
+ else
+ {
+ QString tmp;
+ int len = painter.fontMetrics().width( tmp.setNum(x) );
+ if (!col_lay->isHide())
+ painter.drawText( zoomedXPos + ( width - len ) / 2,
+ ( height + painter.fontMetrics().ascent() -
+ painter.fontMetrics().descent() ) / 2,
+ tmp.setNum(x) );
+ }
+ xPos += col_lay->dblWidth();
+ ++x;
+ }
+ }
+}
+
+
+void HBorder::focusOutEvent( QFocusEvent* )
+{
+ if ( m_scrollTimer->isActive() )
+ m_scrollTimer->stop();
+ m_bMousePressed = false;
+}
+
+/****************************************************************
+ *
+ * ToolTip
+ *
+ ****************************************************************/
+
+ToolTip::ToolTip( Canvas* canvas )
+ : QToolTip( canvas ), m_canvas( canvas )
+{
+}
+
+// find the label for the tip
+// this is a hack of course, because it's not available from QToolTip
+QLabel *tip_findLabel()
+{
+ QWidgetList *list = QApplication::allWidgets();
+ QWidgetListIt it( *list );
+ QWidget * w;
+ while ( (w=it.current()) != 0 )
+ {
+ if(w->isA("QTipLabel"))
+ return static_cast<QLabel*>(w);
+ ++it;
+ }
+ delete list;
+ return 0;
+}
+
+void ToolTip::maybeTip( const QPoint& p )
+{
+ Sheet *sheet = m_canvas->activeSheet();
+ if ( !sheet )
+ return;
+
+ // Over which cell is the mouse ?
+ double ypos, xpos;
+ double dwidth = m_canvas->doc()->unzoomItX( m_canvas->width() );
+ int col;
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ col = sheet->leftColumn( (dwidth - m_canvas->doc()->unzoomItX( p.x() ) +
+ m_canvas->xOffset()), xpos );
+ else
+ col = sheet->leftColumn( (m_canvas->doc()->unzoomItX( p.x() ) +
+ m_canvas->xOffset()), xpos );
+
+
+ int row = sheet->topRow( (m_canvas->doc()->unzoomItY( p.y() ) +
+ m_canvas->yOffset()), ypos );
+
+ const Cell* cell = sheet->visibleCellAt( col, row );
+ if ( !cell )
+ return;
+
+#if 0
+ // Quick cut
+ if( cell->strOutText().isEmpty() )
+ return;
+#endif
+ // displayed tool tip, which has the following priorities:
+ // - cell content if the cell dimension is too small
+ // - cell comment
+ // - hyperlink
+ QString tipText;
+ QString comment = cell->format()->comment( col, row );
+
+ // If cell is too small, show the content
+ if ( cell->testFlag( Cell::Flag_CellTooShortX ) ||
+ cell->testFlag( Cell::Flag_CellTooShortY ) )
+ {
+ tipText = cell->strOutText();
+ }
+
+ // Show hyperlink, if any
+ if ( tipText.isEmpty() )
+ {
+ tipText = cell->link();
+ }
+
+ // Nothing to display, bail out
+ if ( tipText.isEmpty() && comment.isEmpty() )
+ return;
+
+ // Cut if the tip is ridiculously long
+ const unsigned maxLen = 256;
+ if ( tipText.length() > maxLen )
+ tipText = tipText.left(maxLen).append("...");
+
+ // Determine position and width of the current cell.
+ double u = cell->dblWidth( col );
+ double v = cell->dblHeight( row );
+
+ // Special treatment for obscured cells.
+ if ( cell->isObscured() && cell->isPartOfMerged() )
+ {
+ cell = cell->obscuringCells().first();
+ const int moveX = cell->column();
+ const int moveY = cell->row();
+
+ // Use the obscuring cells dimensions
+ u = cell->dblWidth( moveX );
+ v = cell->dblHeight( moveY );
+ xpos = sheet->dblColumnPos( moveX );
+ ypos = sheet->dblRowPos( moveY );
+ }
+
+ // Get the cell dimensions
+ QRect marker;
+ bool insideMarker = false;
+
+ if ( sheet->layoutDirection()==Sheet::RightToLeft )
+ {
+ KoRect unzoomedMarker( dwidth - u - xpos + m_canvas->xOffset(),
+ ypos - m_canvas->yOffset(),
+ u,
+ v );
+
+ marker = m_canvas->doc()->zoomRect( unzoomedMarker );
+ insideMarker = marker.contains( p );
+ }
+ else
+ {
+ KoRect unzoomedMarker( xpos - m_canvas->xOffset(),
+ ypos - m_canvas->yOffset(),
+ u,
+ v );
+
+ marker = m_canvas->doc()->zoomRect( unzoomedMarker );
+ insideMarker = marker.contains( p );
+ }
+
+ // No use if mouse is somewhere else
+ if ( !insideMarker )
+ return;
+
+ // Find the tipLabel
+ // NOTE: if we failed, check again when the tip is shown already
+ QLabel* tipLabel = tip_findLabel();
+
+ // Ensure that it is plain text
+ // Not funny if (intentional or not) <a> appears as hyperlink
+ if ( tipLabel )
+ tipLabel->setTextFormat( Qt::PlainText );
+
+ QFontMetrics fm = tipLabel ? tipLabel->fontMetrics() : m_canvas->fontMetrics();
+ const QRect r( 0, 0, 200, -1 );
+ // Wrap the text if too long
+ if ( tipText.length() > 16 )
+ {
+ KWordWrap* wrap = KWordWrap::formatText( fm, r, 0, tipText );
+ tipText = wrap->wrappedString();
+ delete wrap;
+ }
+ // Wrap the comment if too long
+ if ( comment.length() > 16 )
+ {
+ KWordWrap* wrap = KWordWrap::formatText( fm, r, 0, comment );
+ comment = wrap->wrappedString();
+ delete wrap;
+ }
+
+ // Show comment, if any
+ if ( tipText.isEmpty() )
+ {
+ tipText = comment;
+ }
+ else if ( !comment.isEmpty() )
+ {
+ //Add 2 extra lines and a text, when both should be in the tooltip
+ if ( !comment.isEmpty() )
+ comment = "\n\n" + i18n("Comment:") + "\n" + comment;
+
+ tipText += comment;
+ }
+
+ // Now we shows the tip
+ tip( marker, tipText );
+
+ // Here we try to find the tip label again
+ // Reason: the previous tip_findLabel might fail if no tip has ever shown yet
+ if ( !tipLabel )
+ {
+ tipLabel = tip_findLabel();
+ if( tipLabel )
+ tipLabel->setTextFormat( Qt::PlainText );
+ }
+
+}
+
+#include "kspread_canvas.moc"