kspread

kspread_canvas.cc

00001 /* This file is part of the KDE project
00002 
00003    Copyright 2006 Robert Knight <robertknight@gmail.com>
00004    Copyright 2006 Inge Wallin <inge@lysator.liu.se>
00005    Copyright 2006 Stefan Nikolaus <stefan.nikolaus@kdemail.net>
00006    Copyright 1999-2002,2004 Laurent Montel <montel@kde.org>
00007    Copyright 2002-2005 Ariya Hidayat <ariya@kde.org>
00008    Copyright 1999-2004 David Faure <faure@kde.org>
00009    Copyright 2004-2005 Meni Livne <livne@kde.org>
00010    Copyright 2001-2003 Philipp Mueller <philipp.mueller@gmx.de>
00011    Copyright 2002-2003 Norbert Andres <nandres@web.de>
00012    Copyright 2003 Hamish Rodda <rodda@kde.org>
00013    Copyright 2003 Joseph Wenninger <jowenn@kde.org>
00014    Copyright 2003 Lukas Tinkl <lukas@kde.org>
00015    Copyright 2000-2002 Werner Trobin <trobin@kde.org>
00016    Copyright 2002 Harri Porten <porten@kde.org>
00017    Copyright 2002 John Dailey <dailey@vt.edu>
00018    Copyright 2002 Daniel Naber <daniel.naber@t-online.de>
00019    Copyright 1999-2000 Torben Weis <weis@kde.org>
00020    Copyright 1999-2000 Stephan Kulow <coolo@kde.org>
00021    Copyright 2000 Bernd Wuebben <wuebben@kde.org>
00022    Copyright 2000 Wilco Greven <greven@kde.org>
00023    Copyright 2000 Simon Hausmann <hausmann@kde.org
00024    Copyright 1999 Michael Reiher <michael.reiher.gmx.de>
00025    Copyright 1999 Boris Wedl <boris.wedl@kfunigraz.ac.at>
00026    Copyright 1999 Reginald Stadlbauer <reggie@kde.org>
00027 
00028    This library is free software; you can redistribute it and/or
00029    modify it under the terms of the GNU Library General Public
00030    License as published by the Free Software Foundation; either
00031    version 2 of the License, or (at your option) any later version.
00032 
00033    This library is distributed in the hope that it will be useful,
00034    but WITHOUT ANY WARRANTY; without even the implied warranty of
00035    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00036    Library General Public License for more details.
00037 
00038    You should have received a copy of the GNU Library General Public License
00039    along with this library; see the file COPYING.LIB.  If not, write to
00040    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00041  * Boston, MA 02110-1301, USA.
00042 */
00043 
00044 #include <assert.h>
00045 #include <float.h>
00046 #include <stdlib.h>
00047 
00048 #include <qapplication.h>
00049 #include <qbuffer.h>
00050 #include <qclipboard.h>
00051 #include <qdrawutil.h>
00052 #include <qlabel.h>
00053 #include <qpoint.h>
00054 #include <qscrollbar.h>
00055 #include <qtimer.h>
00056 #include <qtooltip.h>
00057 #include <qwidgetlist.h>
00058 
00059 #include <kcursor.h>
00060 #include <kdebug.h>
00061 #include <kmessagebox.h>
00062 #include <kmultipledrag.h>
00063 #include <krun.h>
00064 #include <kmimetype.h>
00065 #include <ksharedptr.h>
00066 #include <kwordwrap.h>
00067 
00068 #include <KoOasisStore.h>
00069 #include <KoSpeaker.h>
00070 #include <KoStore.h>
00071 #include <KoStoreDrag.h>
00072 #include <KoXmlWriter.h>
00073 #include <KoDocumentChild.h>
00074 #include <KoRect.h>
00075 
00076 #include "commands.h"
00077 #include "kspread_doc.h"
00078 #include "kspread_editors.h"
00079 #include "kspread_global.h"
00080 #include "kspread_locale.h"
00081 #include "kspread_map.h"
00082 #include "kspread_sheet.h"
00083 #include "kspread_undo.h"
00084 #include "kspread_util.h"
00085 #include "kspread_view.h"
00086 #include "selection.h"
00087 
00088 #include "kspread_canvas.h"
00089 
00090 // TODO Stefan: undefine/remove, if non-contiguous selections don't work
00091 //              properly or if we are sure, that they do. ;-)
00092 #define NONCONTIGUOUSSELECTION
00093 
00094 #define MIN_SIZE 10
00095 
00096 using namespace KSpread;
00097 
00098 class Canvas::Private
00099 {
00100   public:
00101     ComboboxLocationEditWidget *posWidget;
00102     KSpread::EditWidget *editWidget;
00103     KSpread::CellEditor *cellEditor;
00104 
00105     View *view;
00106     QTimer* scrollTimer;
00107 
00108     // Non visible range left from current screen
00109     // Example: If the first visible column is 'E', then xOffset stores
00110     // the width of the invisible columns 'A' to 'D'.
00111     double xOffset;
00112 
00113     // Non visible range on top of the current screen
00114     // Example: If the first visible row is '5', then yOffset stores
00115     // the height of the invisible rows '1' to '4'.
00116     double yOffset;
00117 
00118     // Used to draw the grey grid that is usually only visible on the
00119     // screen, but not by printing on paper.
00120     QPen defaultGridPen;
00121 
00122     // see setLastEditorWithFocus, lastEditorWithFocus
00123     Canvas::EditorType focusEditorType;
00124 
00125     QLabel *validationInfo;
00126 
00127     // true if the user is to choose a cell.
00128     bool chooseCell;
00129 
00130     // True when the mouse button is pressed
00131     bool mousePressed;
00132 
00133     // If the user is dragging around with the mouse then this tells us what he is doing.
00134     // The user may want to mark cells or he started in the lower right corner
00135     // of the marker which is something special. The values for the 2 above
00136     // methods are called 'Mark' and 'ResizeCell' or 'AutoFill' depending
00137     // on the mouse button used. By default this variable holds
00138     // the value 'NoAction'.
00139     Canvas::MouseActions mouseAction;
00140 
00141     // If we use the lower right corner of the marker to start autofilling, then this
00142     // rectangle conatins all cells that were already marker when the user started
00143     // to mark the rectangle which he wants to become autofilled.
00144     QRect autoFillSource;
00145 
00146     // Start coordinates for drag and drop
00147     QPoint dragStart;
00148     bool dragging;
00149 
00150     // Used to indicate whether the user started drawing a rubber band rectangle
00151     bool rubberBandStarted;
00152     QPoint rubberBandStart;
00153     QPoint rubberBandEnd;
00154 
00155     // If the mouse is over some anchor ( in the sense of HTML anchors )
00156     QString anchor;
00157 
00158     bool mouseSelectedObject;
00159     bool drawContour;
00160     ModifyType modType;
00164     QPoint m_savedMousePos;
00165 
00166     //---- stuff needed for resizing ----
00168     EmbeddedObject *m_resizeObject;
00170     double m_ratio;
00171     bool m_isResizing;
00173     KoPoint m_origMousePos;
00174 
00175     //---- stuff needed for moving ----
00176     bool m_isMoving;
00177     KoPoint m_moveStartPoint;
00178 
00180     KoRect m_rectBeforeResize;
00182     KoPoint m_moveStartPosMouse;
00183 
00185     EmbeddedObject * m_objectDisplayAbove;
00186 
00187    // bool mouseOverHighlightRangeSizeGrip;
00188 
00189     // The row and column of 1) the last cell under mouse pointer, 2) the last focused cell, and
00190     // the last spoken cell.
00191     int prevSpokenPointerRow;
00192     int prevSpokenPointerCol;
00193     int prevSpokenFocusRow;
00194     int prevSpokenFocusCol;
00195     int prevSpokenRow;
00196     int prevSpokenCol;
00197 };
00198 
00199 
00200 
00201 /****************************************************************
00202  *
00203  * Canvas
00204  *
00205  ****************************************************************/
00206 
00207 Canvas::Canvas (View *_view)
00208   : QWidget( _view, "", /*WNorthWestGravity*/ WStaticContents| WResizeNoErase | WRepaintNoErase )
00209 {
00210   d = new Private;
00211 
00212   d->cellEditor = 0;
00213   d->chooseCell = false;
00214   d->validationInfo = 0L;
00215 
00216   QWidget::setFocusPolicy( QWidget::StrongFocus );
00217 
00218   d->dragStart = QPoint( -1, -1 );
00219   d->dragging = false;
00220 
00221 
00222   d->defaultGridPen.setColor( lightGray );
00223   d->defaultGridPen.setWidth( 1 );
00224   d->defaultGridPen.setStyle( SolidLine );
00225 
00226   d->xOffset = 0.0;
00227   d->yOffset = 0.0;
00228   d->view = _view;
00229   // m_eAction = DefaultAction;
00230   d->mouseAction = NoAction;
00231   d->rubberBandStarted = false;
00232   // m_bEditDirtyFlag = false;
00233 
00234   //Now built afterwards(David)
00235   //d->editWidget = d->view->editWidget();
00236   d->posWidget = d->view->posWidget();
00237 
00238   setBackgroundMode( PaletteBase );
00239 
00240   setMouseTracking( true );
00241   d->mousePressed = false;
00242   d->mouseSelectedObject = false;
00243   d->drawContour = false;
00244   d->modType = MT_NONE;
00245 
00246   d->m_resizeObject = 0L;
00247   d->m_ratio = 0.0;
00248   d->m_isMoving = false;
00249   d->m_objectDisplayAbove = false;
00250   d->m_isResizing = false;
00251 
00252   d->prevSpokenPointerRow = -1;
00253   d->prevSpokenPointerCol = -1;
00254   d->prevSpokenFocusRow = -1;
00255   d->prevSpokenFocusCol = -1;
00256   d->prevSpokenRow = -1;
00257   d->prevSpokenCol = -1;
00258 
00259   d->scrollTimer = new QTimer( this );
00260   connect (d->scrollTimer, SIGNAL( timeout() ), this, SLOT( doAutoScroll() ) );
00261 
00262   if( d->view)
00263   {
00264     connect( d->view, SIGNAL( autoScroll( const QPoint & )), this, SLOT( slotAutoScroll( const QPoint &)));
00265   }
00266   if (kospeaker)
00267   {
00268     connect (kospeaker, SIGNAL(customSpeakWidget(QWidget*, const QPoint&, uint)),
00269       this, SLOT(speakCell(QWidget*, const QPoint&, uint)));
00270   }
00271 
00272   setFocus();
00273   installEventFilter( this );
00274   (void)new ToolTip( this );
00275   setAcceptDrops( true );
00276   setInputMethodEnabled( true ); // ensure using the InputMethod
00277 
00278   setWFlags(Qt::WNoAutoErase);
00279 }
00280 
00281 Canvas::~Canvas()
00282 {
00283   delete d->scrollTimer;
00284   delete d->validationInfo;
00285   delete d;
00286 }
00287 
00288 KSpread::View* Canvas::view() const
00289 {
00290   return d->view;
00291 }
00292 
00293 Doc* Canvas::doc() const
00294 {
00295   return d->view->doc();
00296 }
00297 
00298 void Canvas::setEditWidget( KSpread::EditWidget * ew )
00299 {
00300   d->editWidget = ew;
00301 }
00302 
00303 KSpread::EditWidget* Canvas::editWidget() const
00304 {
00305   return d->editWidget;
00306 }
00307 
00308 CellEditor* Canvas::editor() const
00309 {
00310   return d->cellEditor;
00311 }
00312 
00313 double Canvas::xOffset() const
00314 {
00315   return d->xOffset;
00316 }
00317 
00318 double Canvas::yOffset() const
00319 {
00320   return d->yOffset;
00321 }
00322 
00323 void Canvas::setXOffset( double _xOffset )
00324 {
00325   d->xOffset = _xOffset;
00326   kdDebug(36001) << "setXOffset(): XOffset before scrollToCell: "
00327          << d->xOffset << endl;
00328   scrollToCell( marker() );
00329   kdDebug(36001) << "setXOffset(): XOffset after scrollToCell: "
00330          << d->xOffset << endl;
00331 }
00332 
00333 void Canvas::setYOffset( double _yOffset )
00334 {
00335   d->yOffset = _yOffset;
00336   kdDebug(36001) << "setyOffset(): YOffset before scrollToCell: "
00337          << d->yOffset << endl;
00338   scrollToCell( marker() );
00339   kdDebug(36001) << "setYOffset(): YOffset after scrollToCell: "
00340          << d->yOffset << endl;
00341 }
00342 
00343 const QPen& Canvas::defaultGridPen() const
00344 {
00345   return d->defaultGridPen;
00346 }
00347 
00348 void Canvas::setLastEditorWithFocus( Canvas::EditorType type )
00349 {
00350   d->focusEditorType = type;
00351 }
00352 
00353 Canvas::EditorType Canvas::lastEditorWithFocus() const
00354 {
00355   return d->focusEditorType;
00356 }
00357 
00358 
00359 bool Canvas::eventFilter( QObject *o, QEvent *e )
00360 {
00361   /* this canvas event filter acts on events sent to the line edit as well
00362      as events to this filter itself.
00363   */
00364   if ( !o || !e )
00365     return true;
00366   switch ( e->type() )
00367   {
00368   case QEvent::KeyPress:
00369   {
00370     QKeyEvent * keyev = static_cast<QKeyEvent *>(e);
00371     if ((keyev->key()==Key_Tab) || (keyev->key()==Key_Backtab))
00372     {
00373       keyPressEvent ( keyev );
00374       return true;
00375     }
00376     break;
00377   }
00378   case QEvent::IMStart:
00379   case QEvent::IMCompose:
00380   case QEvent::IMEnd:
00381   {
00382       QIMEvent * imev = static_cast<QIMEvent *>(e);
00383       processIMEvent( imev );
00384       break;
00385   }
00386   default:
00387     break;
00388   }
00389   return false;
00390 }
00391 
00392 bool Canvas::focusNextPrevChild( bool )
00393 {
00394     return true; // Don't allow to go out of the canvas widget by pressing "Tab"
00395 }
00396 
00397 Selection* Canvas::selectionInfo() const
00398 {
00399   return d->view->selectionInfo();
00400 }
00401 
00402 Selection* Canvas::choice() const
00403 {
00404   return d->view->choice();
00405 }
00406 
00407 QRect Canvas::selection() const
00408 {
00409   return d->view->selectionInfo()->selection();
00410 }
00411 
00412 QPoint Canvas::marker() const
00413 {
00414     return d->view->selectionInfo()->marker();
00415 }
00416 
00417 int Canvas::markerColumn() const
00418 {
00419     return d->view->selectionInfo()->marker().x();
00420 }
00421 
00422 int Canvas::markerRow() const
00423 {
00424     return d->view->selectionInfo()->marker().y();
00425 }
00426 
00427 double Canvas::zoom() const
00428 {
00429   return d->view->zoom();
00430 }
00431 
00432 void Canvas::setChooseMode(bool state)
00433 {
00434   d->chooseCell = state;
00435 }
00436 
00437 bool Canvas::chooseMode() const
00438 {
00439   return d->chooseCell;
00440 }
00441 
00442 void Canvas::startChoose()
00443 {
00444   if ( d->chooseCell )
00445     return;
00446 
00447   choice()->clear();
00448   choice()->setSheet(activeSheet());
00449 
00450   // It is important to enable this AFTER we set the rect!
00451   d->chooseCell = true;
00452 }
00453 
00454 void Canvas::startChoose( const QRect& rect )
00455 {
00456   if (d->chooseCell)
00457     return;
00458 
00459   choice()->setSheet(activeSheet());
00460   choice()->initialize(rect);
00461 
00462   // It is important to enable this AFTER we set the rect!
00463   d->chooseCell = true;
00464 }
00465 
00466 void Canvas::endChoose()
00467 {
00468   // While entering a formula the choose mode is turned on and off.
00469   // Clear the choice even if we are not in choose mode. Otherwise,
00470   // cell references will stay highlighted.
00471   if (!choice()->isEmpty())
00472   {
00473     choice()->clear();
00474     update();
00475   }
00476 
00477   if ( !d->chooseCell )
00478     return;
00479 
00480   d->chooseCell = false;
00481 
00482   Sheet *sheet = choice()->sheet();
00483   if (sheet)
00484   {
00485     d->view->setActiveSheet(sheet);
00486   }
00487 }
00488 
00489 HBorder* Canvas::hBorderWidget() const
00490 {
00491   return d->view->hBorderWidget();
00492 }
00493 
00494 VBorder* Canvas::vBorderWidget() const
00495 {
00496   return d->view->vBorderWidget();
00497 }
00498 
00499 QScrollBar* Canvas::horzScrollBar() const
00500 {
00501   return d->view->horzScrollBar();
00502 }
00503 
00504 QScrollBar* Canvas::vertScrollBar() const
00505 {
00506   return d->view->vertScrollBar();
00507 }
00508 
00509 Sheet* Canvas::findSheet( const QString& _name ) const
00510 {
00511   return d->view->doc()->map()->findSheet( _name );
00512 }
00513 
00514 Sheet* Canvas::activeSheet() const
00515 {
00516   return d->view->activeSheet();
00517 }
00518 
00519 void Canvas::validateSelection()
00520 {
00521   Sheet* sheet = activeSheet();
00522   if (!sheet)
00523   {
00524     return;
00525   }
00526 
00527     if ( selectionInfo()->isSingular() )
00528     {
00529         int col = selectionInfo()->marker().x();
00530         int row = selectionInfo()->marker().y();
00531         Cell * cell = sheet->cellAt( col,row );
00532         if ( cell && cell->getValidity(0) && cell->getValidity()->displayValidationInformation)
00533         {
00534             QString title = cell->getValidity(0)->titleInfo;
00535             QString message = cell->getValidity(0)->messageInfo;
00536             if ( title.isEmpty() && message.isEmpty() )
00537                 return;
00538 
00539             if ( !d->validationInfo )
00540                 d->validationInfo = new QLabel(  this );
00541             kdDebug()<<" display info validation\n";
00542             double u = cell->dblWidth( col );
00543             double v = cell->dblHeight( row );
00544             double xpos = sheet->dblColumnPos( markerColumn() ) - xOffset();
00545             double ypos = sheet->dblRowPos( markerRow() ) - yOffset();
00546             // Special treatment for obscured cells.
00547             if ( cell->isObscured() && cell->isPartOfMerged() )
00548             {
00549                 cell = cell->obscuringCells().first();
00550                 int moveX = cell->column();
00551                 int moveY = cell->row();
00552 
00553                 // Use the obscuring cells dimensions
00554                 u = cell->dblWidth( moveX );
00555                 v = cell->dblHeight( moveY );
00556                 xpos = sheet->dblColumnPos( moveX );
00557                 ypos = sheet->dblRowPos( moveY );
00558             }
00559             //d->validationInfo->setGeometry( 3, y + 3, len + 2, hei + 2 );
00560             d->validationInfo->setAlignment( Qt::AlignVCenter );
00561             QPainter painter;
00562             painter.begin( this );
00563             int len = 0;
00564             int hei = 0;
00565             QString resultText;
00566             if ( !title.isEmpty() )
00567             {
00568                 len = painter.fontMetrics().width( title );
00569                 hei = painter.fontMetrics().height();
00570                 resultText = title + "\n";
00571             }
00572             if ( !message.isEmpty() )
00573             {
00574                 int i = 0;
00575                 int pos = 0;
00576                 QString t;
00577                 do
00578                 {
00579                     i = message.find( "\n", pos );
00580                     if ( i == -1 )
00581                         t = message.mid( pos, message.length() - pos );
00582                     else
00583                     {
00584                         t = message.mid( pos, i - pos );
00585                         pos = i + 1;
00586                     }
00587                     hei += painter.fontMetrics().height();
00588                     len = QMAX( len, painter.fontMetrics().width( t ) );
00589                 }
00590                 while ( i != -1 );
00591                 resultText += message;
00592             }
00593             painter.end();
00594             d->validationInfo->setText( resultText );
00595 
00596             KoRect unzoomedMarker( xpos - xOffset()+u,
00597                                    ypos - yOffset()+v,
00598                                    len,
00599                                    hei );
00600             QRect marker( d->view->doc()->zoomRect( unzoomedMarker ) );
00601 
00602             d->validationInfo->setGeometry( marker );
00603             d->validationInfo->show();
00604         }
00605         else
00606         {
00607             delete d->validationInfo;
00608             d->validationInfo = 0L;
00609         }
00610     }
00611     else
00612     {
00613         delete d->validationInfo;
00614         d->validationInfo = 0L;
00615     }
00616 }
00617 
00618 
00619 void Canvas::scrollToCell(QPoint location) const
00620 {
00621   Sheet* sheet = activeSheet();
00622   if (sheet == NULL)
00623     return;
00624 
00625   kdDebug(36001) << "------------------------------------------------" << endl;
00626   kdDebug(36001) << "scrollToCell(): at location [" << location.x() << ","
00627          << location.y() << "]" << endl;
00628 
00629   /* we don't need this cell ptr, but this call is necessary to update the
00630      scroll bar correctly.  I don't like having that as part of the cellAt function
00631      but I suppose that's ok for now.
00632   */
00633   Cell* cell = sheet->cellAt(location.x(), location.y(), true);
00634   Q_UNUSED(cell);
00635 
00636   double  unzoomedWidth  = d->view->doc()->unzoomItX( width() );
00637   double  unzoomedHeight = d->view->doc()->unzoomItY( height() );
00638 
00639   kdDebug(36001) << "Unzoomed view size: [" << unzoomedWidth << ","
00640          << unzoomedHeight << "]" << endl;
00641 
00642   // xpos is the position of the cell in the current window in unzoomed
00643   // document coordinates.
00644   double xpos;
00645   if ( sheet->layoutDirection()==Sheet::LeftToRight )
00646     xpos = sheet->dblColumnPos( location.x() ) - xOffset();
00647   else
00648     xpos = unzoomedWidth - sheet->dblColumnPos( location.x() ) + xOffset();
00649   double ypos = sheet->dblRowPos( location.y() ) - yOffset();
00650 
00651   kdDebug(36001) << "Position: [" << xpos << "," << ypos << "]" << endl;
00652 
00653   double minY = 40.0;
00654   double maxY = unzoomedHeight - 40.0;
00655   kdDebug(36001) << "Canvas::scrollToCell : height=" << height() << endl;
00656   kdDebug(36001) << "Canvas::scrollToCell : width=" << width() << endl;
00657 
00658   if ( sheet->layoutDirection()==Sheet::RightToLeft ) {
00659     // Right to left sheet.
00660 
00661     double minX = unzoomedWidth - 100.0; // less than that, we scroll
00662     double maxX = 100.0; // more than that, we scroll
00663 
00664     // kdDebug() << "rtl2: XPos: " << xpos << ", min: " << minX << ", maxX: " << maxX << ", Offset: " << xOffset() << endl;
00665 
00666     // Do we need to scroll left?
00667     if ( xpos > minX )
00668       horzScrollBar()->setValue( horzScrollBar()->maxValue() -
00669                                   d->view->doc()->zoomItX( xOffset() - xpos + minX ) );
00670 
00671     // Do we need to scroll right?
00672     else if ( xpos < maxX )
00673     {
00674       double horzScrollBarValue = xOffset() - xpos + maxX;
00675       double horzScrollBarValueMax = sheet->sizeMaxX() - unzoomedWidth;
00676 
00677       //We don't want to display any area > KS_colMax widths
00678       if ( horzScrollBarValue > horzScrollBarValueMax )
00679         horzScrollBarValue = horzScrollBarValueMax;
00680 
00681       horzScrollBar()->setValue( horzScrollBar()->maxValue() -
00682                                   d->view->doc()->zoomItX( horzScrollBarValue ) );
00683     }
00684   }
00685   else {
00686     // Left to right sheet.
00687 
00688     double minX = 100.0; // less than that, we scroll
00689     double maxX = unzoomedWidth - 100.0; // more than that, we scroll
00690 
00691     kdDebug() << "ltr: XPos: " << xpos << ", min: " << minX << ", maxX: " << maxX << endl;
00692 
00693     // Do we need to scroll left?
00694     if ( xpos < minX )
00695       horzScrollBar()->setValue( d->view->doc()->zoomItX( xOffset() + xpos - minX ) );
00696 
00697     // Do we need to scroll right?
00698     else if ( xpos > maxX )
00699     {
00700       double horzScrollBarValue = xOffset() + xpos - maxX;
00701       double horzScrollBarValueMax = sheet->sizeMaxX() - unzoomedWidth;
00702 
00703       //We don't want to display any area > KS_colMax widths
00704       if ( horzScrollBarValue > horzScrollBarValueMax )
00705         horzScrollBarValue = horzScrollBarValueMax;
00706 
00707       horzScrollBar()->setValue( d->view->doc()->zoomItX( horzScrollBarValue ) );
00708     }
00709   }
00710 
00711   // do we need to scroll up
00712   if ( ypos < minY )
00713     vertScrollBar()->setValue( d->view->doc()->zoomItY( yOffset() + ypos - minY ) );
00714 
00715   // do we need to scroll down
00716   else if ( ypos > maxY )
00717   {
00718     double vertScrollBarValue = yOffset() + ypos - maxY;
00719     double vertScrollBarValueMax = sheet->sizeMaxY() - unzoomedHeight;
00720 
00721     //We don't want to display any area > KS_rowMax heights
00722     if ( vertScrollBarValue > vertScrollBarValueMax )
00723       vertScrollBarValue = vertScrollBarValueMax;
00724 
00725     vertScrollBar()->setValue( d->view->doc()->zoomItY( vertScrollBarValue ) );
00726   }
00727 }
00728 
00729 void Canvas::slotScrollHorz( int _value )
00730 {
00731   Sheet * sheet = activeSheet();
00732 
00733   if ( sheet == 0L )
00734     return;
00735 
00736   kdDebug(36001) << "slotScrollHorz: value = " << _value << endl;
00737   //kdDebug(36001) << kdBacktrace() << endl;
00738 
00739   if ( sheet->layoutDirection()==Sheet::RightToLeft )
00740     _value = horzScrollBar()->maxValue() - _value;
00741 
00742   double unzoomedValue = d->view->doc()->unzoomItX( _value );
00743   double dwidth = d->view->doc()->unzoomItX( width() );
00744 
00745   d->view->doc()->emitBeginOperation(false);
00746 
00747   if ( unzoomedValue < 0.0 ) {
00748     kdDebug (36001)
00749       << "Canvas::slotScrollHorz: value out of range (unzoomedValue: "
00750       << unzoomedValue << ")" << endl;
00751     unzoomedValue = 0.0;
00752   }
00753 
00754   double xpos = sheet->dblColumnPos( QMIN( KS_colMax, d->view->activeSheet()->maxColumn()+10 ) ) - d->xOffset;
00755   if ( unzoomedValue > ( xpos + d->xOffset ) )
00756     unzoomedValue = xpos + d->xOffset;
00757 
00758   sheet->enableScrollBarUpdates( false );
00759 
00760   // Relative movement
00761   int dx = d->view->doc()->zoomItX( d->xOffset - unzoomedValue );
00762 
00763 
00764   /* what cells will need painted now? */
00765   QRect area = visibleCells();
00766   double tmp;
00767   if (dx > 0)
00768   {
00769     area.setRight( area.left() );
00770     area.setLeft( sheet->leftColumn( unzoomedValue, tmp ) );
00771   }
00772   else
00773   {
00774     area.setLeft( area.right() );
00775     area.setRight( sheet->rightColumn( dwidth  + unzoomedValue ) );
00776   }
00777 
00778   sheet->setRegionPaintDirty(area);
00779 
00780   // New absolute position
00781   kdDebug(36001) << "slotScrollHorz(): XOffset before setting: "
00782          << d->xOffset << endl;
00783   d->xOffset = unzoomedValue;
00784   kdDebug(36001) << "slotScrollHorz(): XOffset after setting: "
00785          << d->xOffset << endl;
00786 
00787   if ( sheet->layoutDirection()==Sheet::RightToLeft )
00788     dx = -dx;
00789 
00790   scroll( dx, 0 );
00791 
00792   hBorderWidget()->scroll( dx, 0 );
00793 
00794   sheet->enableScrollBarUpdates( true );
00795 
00796   d->view->doc()->emitEndOperation( sheet->visibleRect( this ) );
00797 }
00798 
00799 void Canvas::slotScrollVert( int _value )
00800 {
00801   if ( activeSheet() == 0L )
00802     return;
00803 
00804   d->view->doc()->emitBeginOperation(false);
00805   double unzoomedValue = d->view->doc()->unzoomItY( _value );
00806 
00807   if ( unzoomedValue < 0 )
00808   {
00809     unzoomedValue = 0;
00810     kdDebug (36001) << "Canvas::slotScrollVert: value out of range (unzoomedValue: " <<
00811                        unzoomedValue << ")" << endl;
00812   }
00813 
00814   double ypos = activeSheet()->dblRowPos( QMIN( KS_rowMax, d->view->activeSheet()->maxRow()+10 ) );
00815   if ( unzoomedValue > ypos )
00816       unzoomedValue = ypos;
00817 
00818   activeSheet()->enableScrollBarUpdates( false );
00819 
00820   // Relative movement
00821   int dy = d->view->doc()->zoomItY( d->yOffset - unzoomedValue );
00822 
00823 
00824   /* what cells will need painted now? */
00825   QRect area = visibleCells();
00826   double tmp;
00827   if (dy > 0)
00828   {
00829     area.setBottom(area.top());
00830     area.setTop(activeSheet()->topRow(unzoomedValue, tmp));
00831   }
00832   else
00833   {
00834     area.setTop(area.bottom());
00835     area.setBottom(activeSheet()->bottomRow(d->view->doc()->unzoomItY(height()) +
00836                                             unzoomedValue));
00837   }
00838 
00839   activeSheet()->setRegionPaintDirty( area );
00840 
00841   // New absolute position
00842   d->yOffset = unzoomedValue;
00843   scroll( 0, dy );
00844   vBorderWidget()->scroll( 0, dy );
00845 
00846   activeSheet()->enableScrollBarUpdates( true );
00847 
00848   d->view->doc()->emitEndOperation( activeSheet()->visibleRect( this ) );
00849 }
00850 
00851 void Canvas::slotMaxColumn( int _max_column )
00852 {
00853   int oldValue = horzScrollBar()->maxValue() - horzScrollBar()->value();
00854   double xpos = activeSheet()->dblColumnPos( QMIN( KS_colMax, _max_column + 10 ) ) - xOffset();
00855   double unzoomWidth = d->view->doc()->unzoomItX( width() );
00856 
00857   //Don't go beyond the maximum column range (KS_colMax)
00858   double sizeMaxX = activeSheet()->sizeMaxX();
00859   if ( xpos > sizeMaxX - xOffset() - unzoomWidth )
00860     xpos = sizeMaxX - xOffset() - unzoomWidth;
00861 
00862   horzScrollBar()->setRange( 0, d->view->doc()->zoomItX( xpos + xOffset() ) );
00863 
00864   if ( activeSheet()->layoutDirection()==Sheet::RightToLeft )
00865     horzScrollBar()->setValue( horzScrollBar()->maxValue() - oldValue );
00866 }
00867 
00868 void Canvas::slotMaxRow( int _max_row )
00869 {
00870   double ypos = activeSheet()->dblRowPos( QMIN( KS_rowMax, _max_row + 10 ) ) - yOffset();
00871   double unzoomHeight = d->view->doc()->unzoomItY( height() );
00872 
00873   //Don't go beyond the maximum row range (KS_rowMax)
00874   double sizeMaxY = activeSheet()->sizeMaxY();
00875   if ( ypos > sizeMaxY - yOffset() - unzoomHeight )
00876     ypos = sizeMaxY - yOffset() - unzoomHeight;
00877 
00878   vertScrollBar()->setRange( 0, d->view->doc()->zoomItY( ypos + yOffset() ) );
00879 }
00880 
00881 void Canvas::mouseMoveEvent( QMouseEvent * _ev )
00882 {
00883   // Dont allow modifications if document is readonly. Selecting is no modification
00884   if ( (!d->view->koDocument()->isReadWrite()) && (d->mouseAction!=Mark))
00885     return;
00886 
00887   if ( d->mousePressed && d->modType != MT_NONE )
00888   {
00889     KoPoint docPoint ( doc()->unzoomPoint( _ev->pos() ) );
00890     docPoint += KoPoint( xOffset(), yOffset() );
00891 
00892     if ( d->modType == MT_MOVE )
00893     {
00894       if ( !d->m_isMoving )
00895       {
00896         d->m_moveStartPoint = objectRect( false ).topLeft();
00897         d->m_isMoving = true;
00898       }
00899       moveObjectsByMouse( docPoint, _ev->state() & AltButton || _ev->state() & ControlButton );
00900     }
00901     else if ( d->m_resizeObject )
00902     {
00903       if ( !d->m_isResizing )
00904         d->m_isResizing = true;
00905 
00906       bool keepRatio = d->m_resizeObject->isKeepRatio();
00907       if ( _ev->state() & AltButton )
00908       {
00909         keepRatio = true;
00910       }
00911       docPoint  = KoPoint( doc()->unzoomPoint( _ev->pos() ) );
00912       resizeObject( d->modType, docPoint, keepRatio );
00913     }
00914     return;
00915   }
00916 
00917 
00918   /*if ( d->mousePressed && d->m_resizeObject && d->modType != MT_NONE )
00919   {
00920     if ( !d->m_isMoving )
00921     {
00922       d->m_isMoving = true;
00923       update();
00924     }
00925     else
00926       update( d->m_boundingRealRect );
00927 
00928 
00929     QRect drawingRect;
00930 
00931     if ( d->modType == MT_MOVE )
00932     {
00933       drawingRect = QRect( _ev->pos() - d->m_origPos, d->m_origSize );
00934       d->m_boundingRealRect = drawingRect;
00935     }
00936     else
00937     {
00938       drawingRect = doc()->zoomRect( calculateNewGeometry(d->modType,  _ev->pos().x(), _ev->pos().y() ) );
00939       drawingRect.moveBy( (int)( -xOffset() * doc()->zoomedResolutionX() ) , (int)( -yOffset() * doc()->zoomedResolutionY() ) );
00940     }
00941 
00942     // Autoscrolling
00943     if ( ( d->modType == MT_MOVE && drawingRect.top() < 0 ) ||  ( d->modType != MT_MOVE && _ev->pos().y() < 0 ) )
00944     {
00945       vertScrollBar()->setValue ((int) ( vertScrollBar()->value() -
00946           autoScrollAccelerationY( - drawingRect.top() ) ) );
00947     }
00948     else if ( ( d->modType == MT_MOVE && drawingRect.bottom() > height() ) ||  ( d->modType != MT_MOVE && _ev->pos().y() > height() ) )
00949     {
00950       vertScrollBar()->setValue ((int) ( vertScrollBar()->value() +
00951           autoScrollAccelerationY ( drawingRect.bottom() - height() ) ) );
00952     }
00953     if ( ( d->modType == MT_MOVE && drawingRect.left() < 0 ) ||  ( d->modType != MT_MOVE && _ev->pos().x() < 0 ) )
00954     {
00955       horzScrollBar()->setValue ((int) ( horzScrollBar()->value() -
00956           autoScrollAccelerationX( - drawingRect.left() ) ) );
00957     }
00958     else if ( ( d->modType == MT_MOVE && drawingRect.right() > width() ) ||  ( d->modType != MT_MOVE && _ev->pos().x() > width() )  )
00959     {
00960       horzScrollBar()->setValue ((int) (horzScrollBar()->value() +
00961           autoScrollAccelerationX( drawingRect.right() - width() ) ) );
00962     }
00963 
00964     if ( drawingRect.left() < 0 )
00965     {
00966         drawingRect.setRight( drawingRect.right() -drawingRect.left() );
00967         drawingRect.setLeft( 0 );
00968     }
00969     if ( drawingRect.top() < 0 )
00970     {
00971         drawingRect.setBottom( drawingRect.bottom() -drawingRect.top() );
00972         drawingRect.setTop( 0 );
00973     }
00974 
00975     d->m_boundingRealRect = drawingRect; //redraw this area next time the mouse has been moved
00976 
00977     //update( d->m_boundingRealRect );
00978     QPainter p(this);
00979     p.setRasterOp( NotROP );
00980     p.setPen( QPen( black, 0, DotLine ) );
00981     p.drawRect( drawingRect );
00982     p.end();
00983     return;
00984 }*/
00985 
00986   if ( d->dragging )
00987   {
00988     return;
00989   }
00990   if ( d->dragStart.x() != -1 )
00991   {
00992     QPoint p ( (int) _ev->pos().x() + (int) xOffset(),
00993                (int) _ev->pos().y() + (int) yOffset() );
00994 
00995     if ( ( d->dragStart - p ).manhattanLength() > 4 )
00996     {
00997       d->dragging = true;
00998       startTheDrag();
00999       d->dragStart.setX( -1 );
01000     }
01001     d->dragging = false;
01002     return;
01003   }
01004 
01005   // Get info about where the event occurred - this is duplicated
01006   // in ::mousePressEvent, needs to be separated into one function
01007   Sheet *sheet = activeSheet();
01008   if ( !sheet )
01009   {
01010     return;
01011   }
01012 
01013   if ( d->mouseSelectedObject )
01014   {
01015     EmbeddedObject *obj = 0;
01016     QPoint p ( (int) _ev->x(),
01017               (int) _ev->y() );
01018     if ( ( obj = getObject( p, activeSheet() ) ) && obj->isSelected() )
01019     {
01020       KoRect const bound = obj->geometry();
01021       QRect zoomedBound = doc()->zoomRect( KoRect(bound.left(), bound.top(),
01022       bound.width(),
01023       bound.height() ) );
01024       zoomedBound.moveBy( (int)(-xOffset() * doc()->zoomedResolutionX() ), (int)(-yOffset() * doc()->zoomedResolutionY() ));
01025       setCursor( obj->getCursor( p, d->modType, zoomedBound ) );
01026       return;
01027     }
01028   }
01029 
01030   double dwidth = d->view->doc()->unzoomItX( width() );
01031   double ev_PosX;
01032   if ( sheet->layoutDirection()==Sheet::RightToLeft )
01033   {
01034     ev_PosX = dwidth - d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
01035   }
01036   else
01037   {
01038     ev_PosX = d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
01039   }
01040   double ev_PosY = d->view->doc()->unzoomItY( _ev->pos().y() ) + yOffset();
01041 
01042   // In which cell did the user click ?
01043   double xpos;
01044   double ypos;
01045   int col = sheet->leftColumn( ev_PosX, xpos );
01046   int row  = sheet->topRow( ev_PosY, ypos );
01047 
01048   // you cannot move marker when col > KS_colMax or row > KS_rowMax
01049   if ( col > KS_colMax || row > KS_rowMax )
01050   {
01051     kdDebug(36001) << "Canvas::mouseMoveEvent: col or row is out of range: "
01052                    << "col: " << col << " row: " << row << endl;
01053     return;
01054   }
01055 
01056 
01057   //*** Highlighted Range Resize Handling ***
01058   if (d->mouseAction == ResizeSelection)
01059   {
01060     choice()->update(QPoint(col,row));
01061     return;
01062   }
01063 
01064   //Check to see if the mouse is over a highlight range size grip and if it is, change the cursor
01065   //shape to a resize arrow
01066   if (highlightRangeSizeGripAt(ev_PosX,ev_PosY))
01067   {
01068     if ( sheet->layoutDirection()==Sheet::RightToLeft )
01069       setCursor( sizeBDiagCursor );
01070     else
01071       setCursor( sizeFDiagCursor );
01072     return;
01073   }
01074 
01075   QRect rct( (d->chooseCell ? choice() : selectionInfo())->lastRange() );
01076 
01077   QRect r1;
01078   QRect r2;
01079 
01080   double lx = sheet->dblColumnPos( rct.left() );
01081   double rx = sheet->dblColumnPos( rct.right() + 1 );
01082   double ty = sheet->dblRowPos( rct.top() );
01083   double by = sheet->dblRowPos( rct.bottom() + 1 );
01084 
01085   r1.setLeft( (int) (lx - 1) );
01086   r1.setTop( (int) (ty - 1) );
01087   r1.setRight( (int) (rx + 1) );
01088   r1.setBottom( (int) (by + 1) );
01089 
01090   r2.setLeft( (int) (lx + 1) );
01091   r2.setTop( (int) (ty + 1) );
01092   r2.setRight( (int) (rx - 1) );
01093   r2.setBottom( (int) (by - 1) );
01094 
01095   // Test whether the mouse is over some anchor
01096   {
01097     Cell *cell = sheet->visibleCellAt( col, row );
01098     QString anchor;
01099     if ( sheet->layoutDirection()==Sheet::RightToLeft )
01100     {
01101       anchor = cell->testAnchor( d->view->doc()->zoomItX( cell->dblWidth() - ev_PosX + xpos ),
01102                                  d->view->doc()->zoomItY( ev_PosY - ypos ) );
01103     }
01104     else
01105     {
01106       anchor = cell->testAnchor( d->view->doc()->zoomItX( ev_PosX - xpos ),
01107                                  d->view->doc()->zoomItY( ev_PosY - ypos ) );
01108     }
01109     if ( !anchor.isEmpty() && anchor != d->anchor )
01110     {
01111       setCursor( KCursor::handCursor() );
01112     }
01113 
01114     d->anchor = anchor;
01115   }
01116 
01117   // Test wether mouse is over the selection handle
01118   QRect selectionHandle = d->view->selectionInfo()->selectionHandleArea();
01119   if ( selectionHandle.contains( QPoint( d->view->doc()->zoomItX( ev_PosX ),
01120                                          d->view->doc()->zoomItY( ev_PosY ) ) ) )
01121   {
01122     //If the cursor is over the handle, than it might be already on the next cell.
01123     //Recalculate the cell!
01124     col  = sheet->leftColumn( ev_PosX - d->view->doc()->unzoomItX( 2 ), xpos );
01125     row  = sheet->topRow( ev_PosY - d->view->doc()->unzoomItY( 2 ), ypos );
01126 
01127     if ( !sheet->isProtected() )
01128     {
01129       if ( sheet->layoutDirection()==Sheet::RightToLeft )
01130         setCursor( sizeBDiagCursor );
01131       else
01132         setCursor( sizeFDiagCursor );
01133     }
01134   }
01135   else if ( !d->anchor.isEmpty() )
01136   {
01137     if ( !sheet->isProtected() )
01138       setCursor( KCursor::handCursor() );
01139   }
01140   else if ( r1.contains( QPoint( (int) ev_PosX, (int) ev_PosY ) )
01141             && !r2.contains( QPoint( (int) ev_PosX, (int) ev_PosY ) ) )
01142   {
01143     setCursor( KCursor::handCursor() );
01144   }
01145   else if ( d->chooseCell )
01146   {
01147     //Visual cue to indicate that the user can drag-select the choice selection
01148     setCursor( KCursor::crossCursor() );
01149   }
01150   else
01151   {
01152     //Nothing special is happening, use a normal arrow cursor
01153     setCursor( arrowCursor );
01154   }
01155 
01156   // No marking, selecting etc. in progess? Then quit here.
01157   if ( d->mouseAction == NoAction )
01158     return;
01159 
01160   // Set the new extent of the selection
01161   (d->chooseCell ? choice() : selectionInfo())->update(QPoint(col,row));
01162 }
01163 
01164 void Canvas::mouseReleaseEvent( QMouseEvent* /*_ev*/)
01165 {
01166   if ( d->scrollTimer->isActive() )
01167     d->scrollTimer->stop();
01168 
01169   d->mousePressed = false;
01170   d->view->disableAutoScroll();
01171 
01172   if ( d->modType != MT_NONE /*&& d->m_resizeObject && d->m_resizeObject->isSelected() */)
01173   {
01174     switch ( d->modType )
01175     {
01176       case MT_MOVE:
01177       {
01178         KoPoint move( objectRect( false ).topLeft() - d->m_moveStartPosMouse );
01179         if ( move != KoPoint( 0, 0 ) )
01180         {
01181           KCommand *cmd= activeSheet()->moveObject( view(), move.x(), move.y() );
01182           if(cmd)
01183             doc()->addCommand( cmd );
01184         } else
01185         {
01186           repaint();
01187         }
01188         d->m_isMoving = false;
01189         break;
01190       }
01191       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:
01192         finishResizeObject( i18n("Resize Object") );
01193         break;
01194       case MT_RESIZE_DN:
01195         finishResizeObject( i18n("Resize Object"), false );
01196         break;
01197       default:
01198         break;
01199     }
01200     return;
01201   }
01202 
01203   Sheet *sheet = activeSheet();
01204   if ( !sheet )
01205     return;
01206 
01207   Selection* selectionInfo = d->view->selectionInfo();
01208   QRect s( selectionInfo->lastRange() );
01209 
01210   // The user started the drag in the lower right corner of the marker ?
01211   if ( d->mouseAction == ResizeCell && !sheet->isProtected() )
01212   {
01213     sheet->mergeCells(selectionInfo->lastRange());
01214     d->view->updateEditWidget();
01215   }
01216   else if ( d->mouseAction == AutoFill && !sheet->isProtected() )
01217   {
01218     QRect dest = s;
01219     sheet->autofill( d->autoFillSource, dest );
01220 
01221     d->view->updateEditWidget();
01222   }
01223   // The user started the drag in the middle of a cell ?
01224   else if ( d->mouseAction == Mark && !d->chooseCell )
01225   {
01226     d->view->updateEditWidget();
01227   }
01228 
01229   d->mouseAction = NoAction;
01230   d->dragging = false;
01231   d->dragStart.setX( -1 );
01232 }
01233 
01234 void Canvas::processClickSelectionHandle( QMouseEvent *event )
01235 {
01236   // Auto fill ? That is done using the left mouse button.
01237   if ( event->button() == LeftButton )
01238   {
01239     d->mouseAction = AutoFill;
01240     d->autoFillSource = selectionInfo()->lastRange();
01241   }
01242   // Resize a cell (done with the right mouse button) ?
01243   // But for that to work there must not be a selection.
01244   else if ( event->button() == MidButton && selectionInfo()->isSingular())
01245   {
01246     d->mouseAction = ResizeCell;
01247   }
01248 
01249   return;
01250 }
01251 
01252 void Canvas::processLeftClickAnchor()
01253 {
01254     bool isRefLink = localReferenceAnchor( d->anchor );
01255     bool isLocalLink = (d->anchor.find("file:") == 0);
01256     if ( !isRefLink )
01257     {
01258     QString type=KMimeType::findByURL(d->anchor, 0, isLocalLink)->name();
01259 
01260     if ( KRun::isExecutableFile( d->anchor , type ) )
01261     {
01262             //QString question = i18n("Do you want to open this link to '%1'?\n").arg(d->anchor);
01263 
01264             //question += i18n("Note that opening a link to a local file may "
01265                           //   "compromise your system's security.");
01266 
01267         QString question = i18n("This link points to the program or script '%1'.\n"
01268                     "Malicious programs can harm your computer.  Are you sure that you want to run this program?").arg(d->anchor);
01269             // this will also start local programs, so adding a "don't warn again"
01270             // checkbox will probably be too dangerous
01271             int choice = KMessageBox::warningYesNo(this, question, i18n("Open Link?"));
01272             if ( choice != KMessageBox::Yes )
01273             {
01274             return;
01275                     //(void) new KRun( d->anchor );
01276             }
01277     }
01278 
01279     new KRun(d->anchor);
01280     }
01281     else
01282     {
01283       selectionInfo()->initialize(Region(d->view, d->anchor));
01284     }
01285 }
01286 
01287 bool Canvas::highlightRangeSizeGripAt(double x, double y)
01288 {
01289   if (!d->chooseCell)
01290         return 0;
01291 
01292   Region::ConstIterator end = choice()->constEnd();
01293   for (Region::ConstIterator it = choice()->constBegin(); it != end; ++it)
01294   {
01295     // TODO Stefan: adapt to Selection::selectionHandleArea
01296     KoRect visibleRect;
01297     sheetAreaToRect((*it)->rect().normalize(), visibleRect);
01298 
01299     QPoint bottomRight((int) visibleRect.right(), (int) visibleRect.bottom());
01300     QRect handle( ( (int) bottomRight.x() - 6 ),
01301                   ( (int) bottomRight.y() - 6 ),
01302                   ( 6 ),
01303                   ( 6 ) );
01304 
01305     if (handle.contains(QPoint((int) x,(int) y)))
01306             {
01307                 return true;
01308             }
01309     }
01310 
01311     return false;
01312 }
01313 
01314 void Canvas::mousePressEvent( QMouseEvent * _ev )
01315 {
01316   if ( _ev->button() == LeftButton )
01317   {
01318     d->mousePressed = true;
01319     d->view->enableAutoScroll();
01320   }
01321 
01322   if ( activeSheet() && _ev->button() == LeftButton)
01323   {
01324     d->m_moveStartPosMouse = objectRect( false ).topLeft();
01325     EmbeddedObject *obj = getObject( _ev->pos(), activeSheet() );
01326 
01327     if ( obj )
01328     {
01329        // use ctrl + Button to select / deselect object
01330       if ( _ev->state() & ControlButton && obj->isSelected() )
01331         deselectObject( obj );
01332       else if ( _ev->state() & ControlButton )
01333       {
01334         if ( d->modType == MT_NONE)
01335           return;
01336 
01337         selectObject( obj );
01338         raiseObject( obj );
01339         d->m_moveStartPosMouse = objectRect( false ).topLeft();
01340       }
01341       else
01342       {
01343         if ( d->modType != MT_MOVE || !obj->isSelected() )
01344             deselectAllObjects();
01345 
01346         selectObject( obj );
01347 
01348         raiseObject( obj );
01349         d->m_moveStartPosMouse = objectRect( false ).topLeft();
01350       }
01351 
01352       // start resizing
01353       if ( d->modType != MT_MOVE && d->modType != MT_NONE && !obj->isProtect() )
01354       {
01355         deselectAllObjects();
01356         selectObject( obj );
01357         raiseObject( obj );
01358 
01359         d->m_resizeObject = obj;
01360 
01361         d->m_ratio = static_cast<double>( obj->geometry().width() ) /
01362             static_cast<double>( obj->geometry().height() );
01363         d->m_rectBeforeResize = obj->geometry();
01364       }
01365 
01366       KoPoint docPoint ( doc()->unzoomPoint( _ev->pos() ) );
01367       docPoint += KoPoint( xOffset(), yOffset() );
01368       d->m_origMousePos = docPoint;
01369       d->m_moveStartPosMouse = objectRect( false ).topLeft();
01370       return;
01371     }
01372     else
01373     {
01374       d->modType = MT_NONE;
01375       if ( !( _ev->state() & ShiftButton ) && !( _ev->state() & ControlButton ) )
01376         deselectAllObjects();
01377     }
01378   }
01379 
01380   // Get info about where the event occurred - this is duplicated
01381   // in ::mouseMoveEvent, needs to be separated into one function
01382   Sheet *sheet = activeSheet();
01383   if ( !sheet )
01384   {
01385     return;
01386   }
01387 
01388   double dwidth = d->view->doc()->unzoomItX( width() );
01389   double ev_PosX;
01390   if ( sheet->layoutDirection()==Sheet::RightToLeft )
01391   {
01392     ev_PosX = dwidth - d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
01393   }
01394   else
01395   {
01396     ev_PosX = d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
01397   }
01398   double ev_PosY = d->view->doc()->unzoomItY( _ev->pos().y() ) + yOffset();
01399 
01400   // In which cell did the user click ?
01401   double xpos;
01402   double ypos;
01403   int col  = sheet->leftColumn( ev_PosX, xpos );
01404   int row  = sheet->topRow( ev_PosY, ypos );
01405   // you cannot move marker when col > KS_colMax or row > KS_rowMax
01406   if ( col > KS_colMax || row > KS_rowMax )
01407   {
01408     kdDebug(36001) << "Canvas::mousePressEvent: col or row is out of range: "
01409                    << "col: " << col << " row: " << row << endl;
01410     return;
01411   }
01412 
01413   // you cannot move marker when col > KS_colMax or row > KS_rowMax
01414   if ( col > KS_colMax || row > KS_rowMax )
01415   {
01416     kdDebug(36001) << "Canvas::mousePressEvent: col or row is out of range: "
01417                    << "col: " << col << " row: " << row << endl;
01418     return;
01419   }
01420 
01421   if (d->chooseCell && highlightRangeSizeGripAt(ev_PosX,ev_PosY))
01422   {
01423     choice()->setActiveElement(QPoint(col,row));
01424     d->mouseAction = ResizeSelection;
01425     return;
01426   }
01427 
01428   // We were editing a cell -> save value and get out of editing mode
01429   if ( d->cellEditor && !d->chooseCell )
01430   {
01431     deleteEditor( true ); // save changes
01432   }
01433 
01434   d->scrollTimer->start( 50 );
01435 
01436   // Did we click in the lower right corner of the marker/marked-area ?
01437   if ( selectionInfo()->selectionHandleArea().contains( QPoint( d->view->doc()->zoomItX( ev_PosX ),
01438                                                                 d->view->doc()->zoomItY( ev_PosY ) ) ) )
01439   {
01440     processClickSelectionHandle( _ev );
01441     return;
01442   }
01443 
01444 
01445   // TODO Stefan: adapt to non-cont. selection
01446   {
01447     // start drag ?
01448     QRect rct( selectionInfo()->lastRange() );
01449 
01450     QRect r1;
01451     QRect r2;
01452     {
01453       double lx = sheet->dblColumnPos( rct.left() );
01454       double rx = sheet->dblColumnPos( rct.right() + 1 );
01455       double ty = sheet->dblRowPos( rct.top() );
01456       double by = sheet->dblRowPos( rct.bottom() + 1 );
01457 
01458       r1.setLeft( (int) (lx - 1) );
01459       r1.setTop( (int) (ty - 1) );
01460       r1.setRight( (int) (rx + 1) );
01461       r1.setBottom( (int) (by + 1) );
01462 
01463       r2.setLeft( (int) (lx + 1) );
01464       r2.setTop( (int) (ty + 1) );
01465       r2.setRight( (int) (rx - 1) );
01466       r2.setBottom( (int) (by - 1) );
01467     }
01468 
01469     d->dragStart.setX( -1 );
01470 
01471     if ( r1.contains( QPoint( (int) ev_PosX, (int) ev_PosY ) )
01472          && !r2.contains( QPoint( (int) ev_PosX, (int) ev_PosY ) ) )
01473     {
01474       d->dragStart.setX( (int) ev_PosX );
01475       d->dragStart.setY( (int) ev_PosY );
01476 
01477       return;
01478     }
01479   }
01480 
01481   //  kdDebug() << "Clicked in cell " << col << ", " << row << endl;
01482 
01483   // Extending an existing selection with the shift button ?
01484   if ((_ev->state() & ShiftButton) &&
01485       d->view->koDocument()->isReadWrite() &&
01486       !selectionInfo()->isColumnOrRowSelected())
01487   {
01488     (d->chooseCell ? choice() : selectionInfo())->update(QPoint(col,row));
01489     return;
01490   }
01491 
01492 
01493   // Go to the upper left corner of the obscuring object if cells are merged
01494   Cell *cell = sheet->cellAt( col, row );
01495   if (cell->isPartOfMerged())
01496   {
01497     cell = cell->obscuringCells().first();
01498     col = cell->column();
01499     row = cell->row();
01500   }
01501 
01502   switch (_ev->button())
01503   {
01504     case LeftButton:
01505       if (!d->anchor.isEmpty())
01506       {
01507         // Hyperlink pressed
01508         processLeftClickAnchor();
01509       }
01510 #ifdef NONCONTIGUOUSSELECTION
01511       else if ( _ev->state() & ControlButton )
01512       {
01513         if (d->chooseCell)
01514         {
01515 #if 0 // TODO Stefan: remove for NCS of choices
01516           // Start a marking action
01517           d->mouseAction = Mark;
01518           // extend the existing selection
01519           choice()->extend(QPoint(col,row), activeSheet());
01520 #endif
01521         }
01522         else
01523         {
01524           // Start a marking action
01525           d->mouseAction = Mark;
01526           // extend the existing selection
01527           selectionInfo()->extend(QPoint(col,row), activeSheet());
01528         }
01529 // TODO Stefan: simplification, if NCS of choices is working
01530 /*        (d->chooseCell ? choice() : selectionInfo())->extend(QPoint(col,row), activeSheet());*/
01531       }
01532 #endif
01533       else
01534       {
01535         // Start a marking action
01536         d->mouseAction = Mark;
01537         // reinitialize the selection
01538         (d->chooseCell ? choice() : selectionInfo())->initialize(QPoint(col,row), activeSheet());
01539       }
01540       break;
01541     case MidButton:
01542       // Paste operation with the middle button?
01543       if ( d->view->koDocument()->isReadWrite() && !sheet->isProtected() )
01544       {
01545         (d->chooseCell ? choice() : selectionInfo())->initialize( QPoint( col, row ), activeSheet() );
01546         sheet->paste(selectionInfo()->lastRange(), true, Paste::Normal,
01547                      Paste::OverWrite, false, 0, false, QClipboard::Selection);
01548         sheet->setRegionPaintDirty(*selectionInfo());
01549       }
01550       break;
01551     case RightButton:
01552       if (!selectionInfo()->contains( QPoint( col, row ) ))
01553       {
01554         // No selection or the mouse press was outside of an existing selection?
01555         (d->chooseCell ? choice() : selectionInfo())->initialize(QPoint(col,row), activeSheet());
01556       }
01557       break;
01558     default:
01559       break;
01560   }
01561 
01562   scrollToCell(selectionInfo()->marker());
01563   if ( !d->chooseCell )
01564   {
01565     d->view->updateEditWidgetOnPress();
01566   }
01567   updatePosWidget();
01568 
01569   // Context menu?
01570   if ( _ev->button() == RightButton )
01571   {
01572     // TODO: Handle anchor // TODO Stefan: ???
01573     QPoint p = mapToGlobal( _ev->pos() );
01574     d->view->openPopupMenu( p );
01575   }
01576 }
01577 
01578 void Canvas::startTheDrag()
01579 {
01580   Sheet * sheet = activeSheet();
01581   if ( !sheet )
01582     return;
01583 
01584   // right area for start dragging
01585   TextDrag * d = new TextDrag( this );
01586   setCursor( KCursor::handCursor() );
01587 
01588   QDomDocument doc = sheet->saveCellRegion(*selectionInfo());
01589 
01590   // Save to buffer
01591   QBuffer buffer;
01592   buffer.open( IO_WriteOnly );
01593   QTextStream str( &buffer );
01594   str.setEncoding( QTextStream::UnicodeUTF8 );
01595   str << doc;
01596   buffer.close();
01597 
01598   d->setPlain( sheet->copyAsText( selectionInfo() ) );
01599   d->setKSpread( buffer.buffer() );
01600 
01601   d->dragCopy();
01602   setCursor( KCursor::arrowCursor() );
01603 }
01604 
01605 void Canvas::mouseDoubleClickEvent( QMouseEvent*  _ev)
01606 {
01607 
01608   EmbeddedObject *obj;
01609   if ( ( obj = getObject( _ev->pos(), activeSheet() ) ) )
01610   {
01611     switch ( obj->getType() )
01612     {
01613       case OBJECT_KOFFICE_PART: case OBJECT_CHART:
01614       {
01615         dynamic_cast<EmbeddedKOfficeObject*>(obj)->activate( view(), this );
01616         return;
01617         break;
01618       }
01619       default:
01620       {
01621         view()->extraProperties();
01622         return;
01623         break;
01624       }
01625     }
01626   }
01627 
01628   if ( d->view->koDocument()->isReadWrite() && activeSheet() )
01629     createEditor(true);
01630 }
01631 
01632 void Canvas::wheelEvent( QWheelEvent* _ev )
01633 {
01634   if ( _ev->orientation() == Qt::Vertical )
01635   {
01636     if ( vertScrollBar() )
01637       QApplication::sendEvent( vertScrollBar(), _ev );
01638   }
01639   else if ( horzScrollBar() )
01640   {
01641     QApplication::sendEvent( horzScrollBar(), _ev );
01642   }
01643 }
01644 
01645 void Canvas::paintEvent( QPaintEvent* _ev )
01646 {
01647   if ( d->view->doc()->isLoading() )
01648     return;
01649 
01650   Sheet* sheet = activeSheet();
01651   if ( !sheet )
01652     return;
01653 
01654   // ElapsedTime et( "Canvas::paintEvent" );
01655 
01656   double dwidth = d->view->doc()->unzoomItX( width() );
01657   KoRect rect = d->view->doc()->unzoomRect( _ev->rect() & QWidget::rect() );
01658   if ( sheet->layoutDirection()==Sheet::RightToLeft )
01659     rect.moveBy( -xOffset(), yOffset() );
01660   else
01661     rect.moveBy( xOffset(), yOffset() );
01662 
01663   KoPoint tl = rect.topLeft();
01664   KoPoint br = rect.bottomRight();
01665 
01666   double tmp;
01667   int left_col;
01668   int right_col;
01669   //Philipp: I don't know why we need the +1, but otherwise we don't get it correctly
01670   //Testcase: Move a dialog slowly up left. Sometimes the top/left most points are not painted
01671   if ( sheet->layoutDirection()==Sheet::RightToLeft )
01672   {
01673     right_col = sheet->leftColumn( dwidth - tl.x(), tmp );
01674     left_col  = sheet->rightColumn( dwidth - br.x() + 1.0 );
01675   }
01676   else
01677   {
01678     left_col  = sheet->leftColumn( tl.x(), tmp );
01679     right_col = sheet->rightColumn( br.x() + 1.0 );
01680   }
01681   int top_row = sheet->topRow( tl.y(), tmp );
01682   int bottom_row = sheet->bottomRow( br.y() + 1.0 );
01683 
01684   QRect vr( QPoint(left_col, top_row),
01685             QPoint(right_col, bottom_row) );
01686   d->view->doc()->emitBeginOperation( false );
01687   sheet->setRegionPaintDirty( vr );
01688   d->view->doc()->emitEndOperation( vr );
01689 }
01690 
01691 void Canvas::focusInEvent( QFocusEvent* )
01692 {
01693   if ( !d->cellEditor )
01694     return;
01695 
01696   //kdDebug(36001) << "d->chooseCell : " << ( d->chooseCell ? "true" : "false" ) << endl;
01697   // If we are in editing mode, we redirect the
01698   // focus to the CellEditor or EditWidget
01699   // And we know which, using lastEditorWithFocus.
01700   // This screws up <Tab> though (David)
01701   if ( lastEditorWithFocus() == EditWidget )
01702   {
01703     d->editWidget->setFocus();
01704     //kdDebug(36001) << "Focus to EditWidget" << endl;
01705     return;
01706   }
01707 
01708   //kdDebug(36001) << "Redirecting focus to editor" << endl;
01709   d->cellEditor->setFocus();
01710 }
01711 
01712 void Canvas::focusOutEvent( QFocusEvent* )
01713 {
01714     if ( d->scrollTimer->isActive() )
01715         d->scrollTimer->stop();
01716     d->mousePressed = false;
01717     d->view->disableAutoScroll();
01718 }
01719 
01720 void Canvas::dragMoveEvent( QDragMoveEvent * _ev )
01721 {
01722   Sheet * sheet = activeSheet();
01723   if ( !sheet )
01724   {
01725     _ev->ignore();
01726     return;
01727   }
01728 
01729   _ev->accept( TextDrag::canDecode( _ev ) );
01730 
01731   double dwidth = d->view->doc()->unzoomItX( width() );
01732   double xpos = sheet->dblColumnPos( selectionInfo()->lastRange().left() );
01733   double ypos = sheet->dblRowPos( selectionInfo()->lastRange().top() );
01734   double width  = sheet->columnFormat( selectionInfo()->lastRange().left() )->dblWidth( this );
01735   double height = sheet->rowFormat( selectionInfo()->lastRange().top() )->dblHeight( this );
01736 
01737   QRect r1 ((int) xpos - 1, (int) ypos - 1, (int) width + 3, (int) height + 3);
01738 
01739   double ev_PosX;
01740   if (sheet->layoutDirection()==Sheet::RightToLeft)
01741     ev_PosX = dwidth - d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
01742   else
01743     ev_PosX = d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
01744 
01745   double ev_PosY = d->view->doc()->unzoomItY( _ev->pos().y() ) + yOffset();
01746 
01747   if ( r1.contains( QPoint ((int) ev_PosX, (int) ev_PosY) ) )
01748     _ev->ignore( r1 );
01749 }
01750 
01751 void Canvas::dragLeaveEvent( QDragLeaveEvent * )
01752 {
01753   if ( d->scrollTimer->isActive() )
01754     d->scrollTimer->stop();
01755 }
01756 
01757 void Canvas::dropEvent( QDropEvent * _ev )
01758 {
01759   d->dragging = false;
01760   if ( d->scrollTimer->isActive() )
01761     d->scrollTimer->stop();
01762   Sheet * sheet = activeSheet();
01763   if ( !sheet || sheet->isProtected() )
01764   {
01765     _ev->ignore();
01766     return;
01767   }
01768 
01769   double dwidth = d->view->doc()->unzoomItX( width() );
01770   double xpos = sheet->dblColumnPos( selectionInfo()->lastRange().left() );
01771   double ypos = sheet->dblRowPos( selectionInfo()->lastRange().top() );
01772   double width  = sheet->columnFormat( selectionInfo()->lastRange().left() )->dblWidth( this );
01773   double height = sheet->rowFormat( selectionInfo()->lastRange().top() )->dblHeight( this );
01774 
01775   QRect r1 ((int) xpos - 1, (int) ypos - 1, (int) width + 3, (int) height + 3);
01776 
01777   double ev_PosX;
01778   if (sheet->layoutDirection()==Sheet::RightToLeft)
01779     ev_PosX = dwidth - d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
01780   else
01781     ev_PosX = d->view->doc()->unzoomItX( _ev->pos().x() ) + xOffset();
01782 
01783   double ev_PosY = d->view->doc()->unzoomItY( _ev->pos().y() ) + yOffset();
01784 
01785   if ( r1.contains( QPoint ((int) ev_PosX, (int) ev_PosY) ) )
01786   {
01787     _ev->ignore( );
01788     return;
01789   }
01790   else
01791     _ev->accept( );
01792 
01793   double tmp;
01794   int col = sheet->leftColumn( ev_PosX, tmp );
01795   int row = sheet->topRow( ev_PosY, tmp );
01796 
01797   if ( !TextDrag::canDecode( _ev ) )
01798   {
01799     _ev->ignore();
01800     return;
01801   }
01802 
01803   QByteArray b;
01804 
01805   bool makeUndo = true;
01806 
01807   if ( _ev->provides( TextDrag::selectionMimeType() ) )
01808   {
01809     if ( TextDrag::target() == _ev->source() )
01810     {
01811       if ( !d->view->doc()->undoLocked() )
01812       {
01813         UndoDragDrop * undo
01814           = new UndoDragDrop(d->view->doc(), sheet, *selectionInfo(),
01815                              QRect(col, row,
01816                                    selectionInfo()->boundingRect().width(),
01817                                    selectionInfo()->boundingRect().height()));
01818         d->view->doc()->addCommand( undo );
01819         makeUndo = false;
01820       }
01821       sheet->deleteSelection( selectionInfo(), false );
01822     }
01823 
01824 
01825     b = _ev->encodedData( TextDrag::selectionMimeType() );
01826     sheet->paste( b, QRect( col, row, 1, 1 ), makeUndo );
01827 
01828     if ( _ev->source() == this )
01829       _ev->acceptAction();
01830     _ev->accept();
01831   }
01832   else
01833   {
01834     QString text;
01835     if ( !QTextDrag::decode( _ev, text ) )
01836     {
01837       _ev->ignore();
01838       return;
01839     }
01840     //    if ( TextDrag::target() == _ev->source() )
01841     //      sheet->deleteSelection( selectionInfo() );
01842 
01843     sheet->pasteTextPlain( text, QRect( col, row, 1, 1 ) );
01844     _ev->accept();
01845     if ( _ev->source() == this )
01846       _ev->acceptAction();
01847 
01848     return;
01849   }
01850 }
01851 
01852 void Canvas::resizeEvent( QResizeEvent* _ev )
01853 {
01854     if (!activeSheet())
01855         return;
01856 
01857 
01858     double ev_Width = d->view->doc()->unzoomItX( _ev->size().width() );
01859     double ev_Height = d->view->doc()->unzoomItY( _ev->size().height() );
01860 
01861     // workaround to allow horizontal resizing and zoom changing when sheet
01862     // direction and interface direction don't match (e.g. an RTL sheet on an
01863     // LTR interface)
01864     if ( activeSheet() && activeSheet()->layoutDirection()==Sheet::RightToLeft && !QApplication::reverseLayout() )
01865     {
01866         int dx = _ev->size().width() - _ev->oldSize().width();
01867         scroll(dx, 0);
01868     }
01869     else if ( activeSheet() && activeSheet()->layoutDirection()==Sheet::LeftToRight && QApplication::reverseLayout() )
01870     {
01871         int dx = _ev->size().width() - _ev->oldSize().width();
01872         scroll(-dx, 0);
01873     }
01874 
01875     // If we rise horizontally, then check if we are still within the valid area (KS_colMax)
01876     if ( _ev->size().width() > _ev->oldSize().width() )
01877     {
01878         int oldValue = horzScrollBar()->maxValue() - horzScrollBar()->value();
01879 
01880         if ( ( xOffset() + ev_Width ) >
01881                d->view->doc()->zoomItX( activeSheet()->sizeMaxX() ) )
01882         {
01883             horzScrollBar()->setRange( 0, d->view->doc()->zoomItX( activeSheet()->sizeMaxX() - ev_Width ) );
01884             if ( activeSheet()->layoutDirection()==Sheet::RightToLeft )
01885                 horzScrollBar()->setValue( horzScrollBar()->maxValue() - oldValue );
01886         }
01887     }
01888     // If we lower vertically, then check if the range should represent the maximum range
01889     else if ( _ev->size().width() < _ev->oldSize().width() )
01890     {
01891         int oldValue = horzScrollBar()->maxValue() - horzScrollBar()->value();
01892 
01893         if ( horzScrollBar()->maxValue() ==
01894              int( d->view->doc()->zoomItX( activeSheet()->sizeMaxX() ) - ev_Width ) )
01895         {
01896             horzScrollBar()->setRange( 0, d->view->doc()->zoomItX( activeSheet()->sizeMaxX() - ev_Width ) );
01897             if ( activeSheet()->layoutDirection()==Sheet::RightToLeft )
01898                 horzScrollBar()->setValue( horzScrollBar()->maxValue() - oldValue );
01899         }
01900     }
01901 
01902     // If we rise vertically, then check if we are still within the valid area (KS_rowMax)
01903     if ( _ev->size().height() > _ev->oldSize().height() )
01904     {
01905         if ( ( yOffset() + ev_Height ) >
01906              d->view->doc()->zoomItY( activeSheet()->sizeMaxY() ) )
01907         {
01908             vertScrollBar()->setRange( 0, d->view->doc()->zoomItY( activeSheet()->sizeMaxY() - ev_Height ) );
01909         }
01910     }
01911     // If we lower vertically, then check if the range should represent the maximum range
01912     else if ( _ev->size().height() < _ev->oldSize().height() )
01913     {
01914         if ( vertScrollBar()->maxValue() ==
01915              int( d->view->doc()->zoomItY( activeSheet()->sizeMaxY() ) - ev_Height ) )
01916         {
01917             vertScrollBar()->setRange( 0, d->view->doc()->zoomItY( activeSheet()->sizeMaxY() - ev_Height ) );
01918         }
01919     }
01920 }
01921 
01922 QPoint Canvas::cursorPos()
01923 {
01924   QPoint cursor;
01925   if (d->chooseCell && !choice()->isEmpty())
01926     cursor = choice()->cursor();
01927   else
01928     cursor = selectionInfo()->cursor();
01929 
01930   return cursor;
01931 }
01932 
01933 QRect Canvas::moveDirection( KSpread::MoveTo direction, bool extendSelection )
01934 {
01935   kdDebug(36001) << "Canvas::moveDirection" << endl;
01936 
01937   QPoint destination;
01938   QPoint cursor = cursorPos();
01939 
01940   QPoint cellCorner = cursor;
01941   Cell* cell = activeSheet()->cellAt(cursor.x(), cursor.y());
01942 
01943   /* cell is either the same as the marker, or the cell that is forced obscuring
01944      the marker cell
01945   */
01946   if (cell->isPartOfMerged())
01947   {
01948     cell = cell->obscuringCells().first();
01949     cellCorner = QPoint(cell->column(), cell->row());
01950   }
01951 
01952   /* how many cells must we move to get to the next cell? */
01953   int offset = 0;
01954   RowFormat *rl = NULL;
01955   ColumnFormat *cl = NULL;
01956   switch (direction)
01957     /* for each case, figure out how far away the next cell is and then keep
01958        going one row/col at a time after that until a visible row/col is found
01959 
01960        NEVER use cell->column() or cell->row() -- it might be a default cell
01961     */
01962   {
01963     case Bottom:
01964       offset = cell->mergedYCells() - (cursor.y() - cellCorner.y()) + 1;
01965       rl = activeSheet()->rowFormat( cursor.y() + offset );
01966       while ( ((cursor.y() + offset) <= KS_rowMax) && rl->isHide())
01967       {
01968         offset++;
01969         rl = activeSheet()->rowFormat( cursor.y() + offset );
01970       }
01971 
01972       destination = QPoint(cursor.x(), QMIN(cursor.y() + offset, KS_rowMax));
01973       break;
01974     case Top:
01975       offset = (cellCorner.y() - cursor.y()) - 1;
01976       rl = activeSheet()->rowFormat( cursor.y() + offset );
01977       while ( ((cursor.y() + offset) >= 1) && rl->isHide())
01978       {
01979         offset--;
01980         rl = activeSheet()->rowFormat( cursor.y() + offset );
01981       }
01982       destination = QPoint(cursor.x(), QMAX(cursor.y() + offset, 1));
01983       break;
01984     case Left:
01985       offset = (cellCorner.x() - cursor.x()) - 1;
01986       cl = activeSheet()->columnFormat( cursor.x() + offset );
01987       while ( ((cursor.x() + offset) >= 1) && cl->isHide())
01988       {
01989         offset--;
01990         cl = activeSheet()->columnFormat( cursor.x() + offset );
01991       }
01992       destination = QPoint(QMAX(cursor.x() + offset, 1), cursor.y());
01993       break;
01994     case Right:
01995       offset = cell->mergedXCells() - (cursor.x() - cellCorner.x()) + 1;
01996       cl = activeSheet()->columnFormat( cursor.x() + offset );
01997       while ( ((cursor.x() + offset) <= KS_colMax) && cl->isHide())
01998       {
01999         offset++;
02000         cl = activeSheet()->columnFormat( cursor.x() + offset );
02001       }
02002       destination = QPoint(QMIN(cursor.x() + offset, KS_colMax), cursor.y());
02003       break;
02004     case BottomFirst:
02005       offset = cell->mergedYCells() - (cursor.y() - cellCorner.y()) + 1;
02006       rl = activeSheet()->rowFormat( cursor.y() + offset );
02007       while ( ((cursor.y() + offset) <= KS_rowMax) && rl->isHide())
02008       {
02009         ++offset;
02010         rl = activeSheet()->rowFormat( cursor.y() + offset );
02011       }
02012 
02013       destination = QPoint( 1, QMIN( cursor.y() + offset, KS_rowMax ) );
02014       break;
02015   }
02016 
02017   if (extendSelection)
02018   {
02019     (d->chooseCell ? choice() : selectionInfo())->update(destination);
02020   }
02021   else
02022   {
02023     (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
02024   }
02025   d->view->updateEditWidget();
02026 
02027   return QRect( cursor, destination );
02028 }
02029 
02030 void Canvas::processEnterKey(QKeyEvent* event)
02031 {
02032   // array is true, if ctrl+alt are pressed
02033   bool array = (event->state() & Qt::AltButton) &&
02034       (event->state() & Qt::ControlButton);
02035 
02036   /* save changes to the current editor */
02037   if (!d->chooseCell)
02038   {
02039     deleteEditor(true, array);
02040   }
02041 
02042   /* use the configuration setting to see which direction we're supposed to move
02043      when enter is pressed.
02044   */
02045   KSpread::MoveTo direction = d->view->doc()->getMoveToValue();
02046 
02047   //if shift Button clicked inverse move direction
02048   if (event->state() & Qt::ShiftButton)
02049   {
02050     switch( direction )
02051     {
02052      case Bottom:
02053       direction = Top;
02054       break;
02055      case Top:
02056       direction = Bottom;
02057       break;
02058      case Left:
02059       direction = Right;
02060       break;
02061      case Right:
02062       direction = Left;
02063       break;
02064      case BottomFirst:
02065       direction = BottomFirst;
02066       break;
02067     }
02068   }
02069 
02070   /* never extend a selection with the enter key -- the shift key reverses
02071      direction, not extends the selection
02072   */
02073   QRect r( moveDirection( direction, false ) );
02074   d->view->doc()->emitEndOperation( r );
02075 }
02076 
02077 void Canvas::processArrowKey( QKeyEvent *event)
02078 {
02079   /* NOTE:  hitting the tab key also calls this function.  Don't forget
02080      to account for it
02081   */
02082 
02083   /* save changes to the current editor */
02084   if (!d->chooseCell)
02085   {
02086     deleteEditor( true );
02087   }
02088 
02089   KSpread::MoveTo direction = Bottom;
02090   bool makingSelection = event->state() & ShiftButton;
02091 
02092   switch (event->key())
02093   {
02094   case Key_Down:
02095     direction = Bottom;
02096     break;
02097   case Key_Up:
02098     direction = Top;
02099     break;
02100   case Key_Left:
02101     if (activeSheet()->layoutDirection()==Sheet::RightToLeft)
02102       direction = Right;
02103     else
02104       direction = Left;
02105     break;
02106   case Key_Right:
02107     if (activeSheet()->layoutDirection()==Sheet::RightToLeft)
02108       direction = Left;
02109     else
02110       direction = Right;
02111     break;
02112   case Key_Tab:
02113       direction = Right;
02114       break;
02115   case Key_Backtab:
02116       //Shift+Tab moves to the left
02117       direction = Left;
02118       makingSelection = false;
02119       break;
02120   default:
02121     Q_ASSERT(false);
02122     break;
02123   }
02124 
02125   QRect r( moveDirection( direction, makingSelection ) );
02126   d->view->doc()->emitEndOperation( r );
02127 }
02128 
02129 void Canvas::processEscapeKey(QKeyEvent * event)
02130 {
02131   if ( d->cellEditor )
02132     deleteEditor( false );
02133 
02134   if ( view()->isInsertingObject() )
02135   {
02136     view()->resetInsertHandle();
02137     setCursor( arrowCursor );
02138     return;
02139   }
02140 
02141   event->accept(); // ?
02142   QPoint cursor = cursorPos();
02143 
02144   d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
02145 
02146   if ( d->mousePressed /*&& toolEditMode == TEM_MOUSE */)
02147   {
02148     switch (d->modType)
02149     {
02150       case MT_RESIZE_UP:
02151       case MT_RESIZE_DN:
02152       case MT_RESIZE_LF:
02153       case MT_RESIZE_RT:
02154       case MT_RESIZE_LU:
02155       case MT_RESIZE_LD:
02156       case MT_RESIZE_RU:
02157       case MT_RESIZE_RD:
02158       {
02159         QRect oldBoundingRect = doc()->zoomRect( d->m_resizeObject->geometry()/*getRepaintRect()*/);
02160         d->m_resizeObject->setGeometry( d->m_rectBeforeResize );
02161         oldBoundingRect.moveBy( (int)( -xOffset()*doc()->zoomedResolutionX() ) ,
02162                             (int)( -yOffset() * doc()->zoomedResolutionY()) );
02163 
02164         activeSheet()->setRegionPaintDirty( oldBoundingRect );
02165         repaint( oldBoundingRect );
02166         repaintObject( d->m_resizeObject );
02167         d->m_ratio = 0.0;
02168         d->m_resizeObject = 0;
02169         d->m_isResizing = false;
02170         view()->disableAutoScroll();
02171         d->mousePressed = false;
02172         d->modType = MT_NONE;
02173         break;
02174       }
02175       case MT_MOVE:
02176       {
02177         if ( d->m_isMoving )
02178         {
02179           KoPoint move( d->m_moveStartPoint - objectRect( false ).topLeft() );
02180           activeSheet()->moveObject( view(), move, false );
02181           view()->disableAutoScroll();
02182           d->mousePressed = false;
02183           d->modType = MT_NONE;
02184           d->m_isMoving = false;
02185           update();
02186         }
02187         break;
02188       }
02189       default:
02190         break;
02191     }
02192   }
02193 }
02194 
02195 bool Canvas::processHomeKey(QKeyEvent* event)
02196 {
02197   bool makingSelection = event->state() & ShiftButton;
02198   Sheet* sheet = activeSheet();
02199 
02200   if ( d->cellEditor )
02201   // We are in edit mode -> go beginning of line
02202   {
02203     QApplication::sendEvent( d->editWidget, event );
02204     return false;
02205   }
02206   else
02207   {
02208     QPoint destination;
02209     /* start at the first used cell in the row and cycle through the right until
02210        we find a cell that has some output text.  But don't look past the current
02211        marker.
02212        The end result we want is to move to the left to the first cell with text,
02213        or just to the first column if there is no more text to the left.
02214 
02215        But why?  In excel, home key sends you to the first column always.
02216        We might want to change to that behavior.
02217     */
02218 
02219     if (event->state() & ControlButton)
02220     {
02221       /* ctrl + Home will always just send us to location (1,1) */
02222       destination = QPoint( 1, 1 );
02223     }
02224     else
02225     {
02226       QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
02227 
02228       Cell * cell = sheet->getFirstCellRow(marker.y());
02229       while (cell != NULL && cell->column() < marker.x() && cell->isEmpty())
02230       {
02231         cell = sheet->getNextCellRight(cell->column(), cell->row());
02232       }
02233 
02234       int col = ( cell ? cell->column() : 1 );
02235       if ( col == marker.x())
02236         col = 1;
02237       destination = QPoint(col, marker.y());
02238     }
02239 
02240     if ( selectionInfo()->marker() == destination )
02241     {
02242       d->view->doc()->emitEndOperation( QRect( destination, destination ) );
02243       return false;
02244     }
02245 
02246     if (makingSelection)
02247     {
02248       (d->chooseCell ? choice() : selectionInfo())->update(destination);
02249     }
02250     else
02251     {
02252       (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
02253     }
02254   }
02255   return true;
02256 }
02257 
02258 bool Canvas::processEndKey( QKeyEvent *event )
02259 {
02260   bool makingSelection = event->state() & ShiftButton;
02261   Sheet* sheet = activeSheet();
02262   Cell* cell = NULL;
02263   QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
02264 
02265   // move to the last used cell in the row
02266   // We are in edit mode -> go beginning of line
02267   if ( d->cellEditor )
02268   {
02269     QApplication::sendEvent( d->editWidget, event );
02270     d->view->doc()->emitEndOperation( QRect( marker, marker ) );
02271     return false;
02272   }
02273   else
02274   {
02275     int col = 1;
02276 
02277     cell = sheet->getLastCellRow(marker.y());
02278     while (cell != NULL && cell->column() > markerColumn() && cell->isEmpty())
02279     {
02280       cell = sheet->getNextCellLeft(cell->column(), cell->row());
02281     }
02282 
02283     col = (cell == NULL) ? KS_colMax : cell->column();
02284 
02285     QPoint destination( col, marker.y() );
02286     if ( destination == marker )
02287     {
02288       d->view->doc()->emitEndOperation( QRect( destination, destination ) );
02289       return false;
02290     }
02291 
02292     if (makingSelection)
02293     {
02294       (d->chooseCell ? choice() : selectionInfo())->update(destination);
02295     }
02296     else
02297     {
02298       (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
02299     }
02300   }
02301   return true;
02302 }
02303 
02304 bool Canvas::processPriorKey(QKeyEvent *event)
02305 {
02306   bool makingSelection = event->state() & ShiftButton;
02307   if (!d->chooseCell)
02308   {
02309     deleteEditor( true );
02310   }
02311 
02312   QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
02313 
02314   QPoint destination(marker.x(), QMAX(1, marker.y() - 10));
02315   if ( destination == marker )
02316   {
02317     d->view->doc()->emitEndOperation( QRect( destination, destination ) );
02318     return false;
02319   }
02320 
02321   if (makingSelection)
02322   {
02323     (d->chooseCell ? choice() : selectionInfo())->update(destination);
02324   }
02325   else
02326   {
02327     (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
02328   }
02329   return true;
02330 }
02331 
02332 bool Canvas::processNextKey(QKeyEvent *event)
02333 {
02334   bool makingSelection = event->state() & ShiftButton;
02335 
02336   if (!d->chooseCell)
02337   {
02338     deleteEditor( true /*save changes*/ );
02339   }
02340 
02341   QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
02342   QPoint destination(marker.x(), QMAX(1, marker.y() + 10));
02343 
02344   if ( marker == destination )
02345   {
02346     d->view->doc()->emitEndOperation( QRect( destination, destination ) );
02347     return false;
02348   }
02349 
02350   if (makingSelection)
02351   {
02352     (d->chooseCell ? choice() : selectionInfo())->update(destination);
02353   }
02354   else
02355   {
02356     (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
02357   }
02358   return true;
02359 }
02360 
02361 void Canvas::processDeleteKey(QKeyEvent* /* event */)
02362 {
02363   if ( isObjectSelected() )
02364   {
02365     d->view->doc()->emitEndOperation( activeSheet()->visibleRect( this ) );
02366     d->view->deleteSelectedObjects();
02367     return;
02368   }
02369 
02370   activeSheet()->clearTextSelection( selectionInfo() );
02371   d->editWidget->setText( "" );
02372 
02373   QPoint cursor = cursorPos();
02374 
02375   d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
02376   return;
02377 }
02378 
02379 void Canvas::processF2Key(QKeyEvent* /* event */)
02380 {
02381   d->editWidget->setFocus();
02382   if ( d->cellEditor )
02383     d->editWidget->setCursorPosition( d->cellEditor->cursorPosition() - 1 );
02384   d->editWidget->cursorForward( false );
02385 
02386 
02387   QPoint cursor = cursorPos();
02388 
02389   d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
02390   return;
02391 }
02392 
02393 void Canvas::processF4Key(QKeyEvent* event)
02394 {
02395   /* passes F4 to the editor (if any), which will process it
02396    */
02397   if ( d->cellEditor )
02398   {
02399     d->cellEditor->handleKeyPressEvent( event );
02400 //    d->editWidget->setFocus();
02401     d->editWidget->setCursorPosition( d->cellEditor->cursorPosition() );
02402   }
02403   QPoint cursor = cursorPos();
02404 
02405   d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
02406   return;
02407 }
02408 
02409 void Canvas::processOtherKey(QKeyEvent *event)
02410 {
02411   // No null character ...
02412   if ( event->text().isEmpty() || !d->view->koDocument()->isReadWrite()
02413        || !activeSheet() || activeSheet()->isProtected() )
02414   {
02415     event->accept();
02416   }
02417   else
02418   {
02419     if ( !d->cellEditor && !d->chooseCell )
02420     {
02421       // Switch to editing mode
02422       createEditor( CellEditor );
02423       d->cellEditor->handleKeyPressEvent( event );
02424     }
02425     else if ( d->cellEditor )
02426       d->cellEditor->handleKeyPressEvent( event );
02427   }
02428 
02429   QPoint cursor = cursorPos();
02430 
02431   d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
02432 
02433   return;
02434 }
02435 
02436 bool Canvas::processControlArrowKey( QKeyEvent *event )
02437 {
02438   bool makingSelection = event->state() & ShiftButton;
02439 
02440   Sheet* sheet = activeSheet();
02441   Cell* cell = NULL;
02442   Cell* lastCell;
02443   QPoint destination;
02444   bool searchThroughEmpty = true;
02445   int row;
02446   int col;
02447 
02448   QPoint marker = d->chooseCell ? choice()->marker() : selectionInfo()->marker();
02449 
02450   /* here, we want to move to the first or last cell in the given direction that is
02451      actually being used.  Ignore empty cells and cells on hidden rows/columns */
02452   switch ( event->key() )
02453   {
02454     //Ctrl+Key_Up
02455    case Key_Up:
02456 
02457     cell = sheet->cellAt( marker.x(), marker.y() );
02458     if ( (cell != NULL) && (!cell->isEmpty()) && (marker.y() != 1))
02459     {
02460       lastCell = cell;
02461       row = marker.y()-1;
02462       cell = sheet->cellAt(cell->column(), row);
02463       while ((cell != NULL) && (row > 0) && (!cell->isEmpty()) )
02464       {
02465         if (!(sheet->rowFormat(cell->row())->isHide()))
02466         {
02467           lastCell = cell;
02468           searchThroughEmpty = false;
02469         }
02470         row--;
02471         if ( row > 0 )
02472           cell = sheet->cellAt(cell->column(), row);
02473       }
02474       cell = lastCell;
02475     }
02476     if (searchThroughEmpty)
02477     {
02478       cell = sheet->getNextCellUp(marker.x(), marker.y());
02479 
02480       while ((cell != NULL) &&
02481             (cell->isEmpty() || (sheet->rowFormat(cell->row())->isHide())))
02482       {
02483         cell = sheet->getNextCellUp(cell->column(), cell->row());
02484       }
02485     }
02486 
02487     if (cell == NULL)
02488       row = 1;
02489     else
02490       row = cell->row();
02491 
02492     while ( sheet->rowFormat(row)->isHide() )
02493     {
02494       row++;
02495     }
02496 
02497     destination.setX(marker.x());
02498     destination.setY(row);
02499     break;
02500 
02501     //Ctrl+Key_Down
02502    case Key_Down:
02503 
02504     cell = sheet->cellAt( marker.x(), marker.y() );
02505     if ( (cell != NULL) && (!cell->isEmpty()) && (marker.y() != KS_rowMax))
02506     {
02507       lastCell = cell;
02508       row = marker.y()+1;
02509       cell = sheet->cellAt(cell->column(), row);
02510       while ((cell != NULL) && (row < KS_rowMax) && (!cell->isEmpty()) )
02511       {
02512         if (!(sheet->rowFormat(cell->row())->isHide()))
02513         {
02514           lastCell = cell;
02515           searchThroughEmpty = false;
02516         }
02517         row++;
02518         cell = sheet->cellAt(cell->column(), row);
02519       }
02520       cell = lastCell;
02521     }
02522     if (searchThroughEmpty)
02523     {
02524       cell = sheet->getNextCellDown(marker.x(), marker.y());
02525 
02526       while ((cell != NULL) &&
02527             (cell->isEmpty() || (sheet->rowFormat(cell->row())->isHide())))
02528       {
02529         cell = sheet->getNextCellDown(cell->column(), cell->row());
02530       }
02531     }
02532 
02533     if (cell == NULL)
02534       row = marker.y();
02535     else
02536       row = cell->row();
02537 
02538     while ( sheet->rowFormat(row)->isHide() )
02539     {
02540       row--;
02541     }
02542 
02543     destination.setX(marker.x());
02544     destination.setY(row);
02545     break;
02546 
02547   //Ctrl+Key_Left
02548   case Key_Left:
02549 
02550   if ( sheet->layoutDirection()==Sheet::RightToLeft )
02551   {
02552     cell = sheet->cellAt( marker.x(), marker.y() );
02553     if ( (cell != NULL) && (!cell->isEmpty()) && (marker.x() != KS_colMax))
02554     {
02555       lastCell = cell;
02556       col = marker.x()+1;
02557       cell = sheet->cellAt(col, cell->row());
02558       while ((cell != NULL) && (col < KS_colMax) && (!cell->isEmpty()) )
02559       {
02560         if (!(sheet->columnFormat(cell->column())->isHide()))
02561         {
02562           lastCell = cell;
02563           searchThroughEmpty = false;
02564         }
02565         col++;
02566         cell = sheet->cellAt(col, cell->row());
02567       }
02568       cell = lastCell;
02569     }
02570     if (searchThroughEmpty)
02571     {
02572       cell = sheet->getNextCellRight(marker.x(), marker.y());
02573 
02574       while ((cell != NULL) &&
02575             (cell->isEmpty() || (sheet->columnFormat(cell->column())->isHide())))
02576       {
02577         cell = sheet->getNextCellRight(cell->column(), cell->row());
02578       }
02579     }
02580 
02581     if (cell == NULL)
02582       col = marker.x();
02583     else
02584       col = cell->column();
02585 
02586     while ( sheet->columnFormat(col)->isHide() )
02587     {
02588       col--;
02589     }
02590 
02591     destination.setX(col);
02592     destination.setY(marker.y());
02593   }
02594   else
02595   {
02596     cell = sheet->cellAt( marker.x(), marker.y() );
02597     if ( (cell != NULL) && (!cell->isEmpty()) && (marker.x() != 1))
02598     {
02599       lastCell = cell;
02600       col = marker.x()-1;
02601       cell = sheet->cellAt(col, cell->row());
02602       while ((cell != NULL) && (col > 0) && (!cell->isEmpty()) )
02603       {
02604         if (!(sheet->columnFormat(cell->column())->isHide()))
02605         {
02606           lastCell = cell;
02607           searchThroughEmpty = false;
02608         }
02609         col--;
02610         if ( col > 0 )
02611             cell = sheet->cellAt(col, cell->row());
02612       }
02613       cell = lastCell;
02614     }
02615     if (searchThroughEmpty)
02616     {
02617       cell = sheet->getNextCellLeft(marker.x(), marker.y());
02618 
02619       while ((cell != NULL) &&
02620             (cell->isEmpty() || (sheet->columnFormat(cell->column())->isHide())))
02621       {
02622         cell = sheet->getNextCellLeft(cell->column(), cell->row());
02623       }
02624     }
02625 
02626     if (cell == NULL)
02627       col = 1;
02628     else
02629       col = cell->column();
02630 
02631     while ( sheet->columnFormat(col)->isHide() )
02632     {
02633       col++;
02634     }
02635 
02636     destination.setX(col);
02637     destination.setY(marker.y());
02638   }
02639     break;
02640 
02641   //Ctrl+Key_Right
02642   case Key_Right:
02643 
02644   if ( sheet->layoutDirection()==Sheet::RightToLeft )
02645   {
02646     cell = sheet->cellAt( marker.x(), marker.y() );
02647     if ( (cell != NULL) && (!cell->isEmpty()) && (marker.x() != 1))
02648     {
02649       lastCell = cell;
02650       col = marker.x()-1;
02651       cell = sheet->cellAt(col, cell->row());
02652       while ((cell != NULL) && (col > 0) && (!cell->isEmpty()) )
02653       {
02654         if (!(sheet->columnFormat(cell->column())->isHide()))
02655         {
02656           lastCell = cell;
02657           searchThroughEmpty = false;
02658         }
02659         col--;
02660         if ( col > 0 )
02661             cell = sheet->cellAt(col, cell->row());
02662       }
02663       cell = lastCell;
02664     }
02665     if (searchThroughEmpty)
02666     {
02667       cell = sheet->getNextCellLeft(marker.x(), marker.y());
02668 
02669       while ((cell != NULL) &&
02670             (cell->isEmpty() || (sheet->columnFormat(cell->column())->isHide())))
02671       {
02672         cell = sheet->getNextCellLeft(cell->column(), cell->row());
02673       }
02674     }
02675 
02676     if (cell == NULL)
02677       col = 1;
02678     else
02679       col = cell->column();
02680 
02681     while ( sheet->columnFormat(col)->isHide() )
02682     {
02683       col++;
02684     }
02685 
02686     destination.setX(col);
02687     destination.setY(marker.y());
02688   }
02689   else
02690   {
02691     cell = sheet->cellAt( marker.x(), marker.y() );
02692     if ( (cell != NULL) && (!cell->isEmpty()) && (marker.x() != KS_colMax))
02693     {
02694       lastCell = cell;
02695       col = marker.x()+1;
02696       cell = sheet->cellAt(col, cell->row());
02697       while ((cell != NULL) && (col < KS_colMax) && (!cell->isEmpty()) )
02698       {
02699         if (!(sheet->columnFormat(cell->column())->isHide()))
02700         {
02701           lastCell = cell;
02702           searchThroughEmpty = false;
02703         }
02704         col++;
02705         cell = sheet->cellAt(col, cell->row());
02706       }
02707       cell = lastCell;
02708     }
02709     if (searchThroughEmpty)
02710     {
02711       cell = sheet->getNextCellRight(marker.x(), marker.y());
02712 
02713       while ((cell != NULL) &&
02714             (cell->isEmpty() || (sheet->columnFormat(cell->column())->isHide())))
02715       {
02716         cell = sheet->getNextCellRight(cell->column(), cell->row());
02717       }
02718     }
02719 
02720     if (cell == NULL)
02721       col = marker.x();
02722     else
02723       col = cell->column();
02724 
02725     while ( sheet->columnFormat(col)->isHide() )
02726     {
02727       col--;
02728     }
02729 
02730     destination.setX(col);
02731     destination.setY(marker.y());
02732   }
02733     break;
02734 
02735   }
02736 
02737   if ( marker == destination )
02738   {
02739     d->view->doc()->emitEndOperation( QRect( destination, destination ) );
02740     return false;
02741   }
02742 
02743   if (makingSelection)
02744   {
02745     (d->chooseCell ? choice() : selectionInfo())->update(destination);
02746   }
02747   else
02748   {
02749     (d->chooseCell ? choice() : selectionInfo())->initialize(destination, activeSheet());
02750   }
02751   return true;
02752 }
02753 
02754 
02755 void Canvas::keyPressEvent ( QKeyEvent * _ev )
02756 {
02757   Sheet * sheet = activeSheet();
02758 
02759   if ( !sheet || formatKeyPress( _ev ))
02760     return;
02761 
02762   // Dont handle the remaining special keys.
02763   if ( _ev->state() & ( Qt::AltButton | Qt::ControlButton ) &&
02764        (_ev->key() != Key_Down) &&
02765        (_ev->key() != Key_Up) &&
02766        (_ev->key() != Key_Right) &&
02767        (_ev->key() != Key_Left) &&
02768        (_ev->key() != Key_Home) &&
02769        (_ev->key() != Key_Enter) &&
02770        (_ev->key() != Key_Return) &&
02771        (_ev->key() != KGlobalSettings::contextMenuKey()))
02772   {
02773     QWidget::keyPressEvent( _ev );
02774     return;
02775   }
02776 
02777   // Always accept so that events are not
02778   // passed to the parent.
02779   _ev->accept();
02780 
02781   d->view->doc()->emitBeginOperation(false);
02782   if ( _ev->key() == KGlobalSettings::contextMenuKey() ) {
02783     int row = markerRow();
02784     int col = markerColumn();
02785     KoPoint kop(sheet->columnPos(col, this), sheet->rowPos(row, this));
02786     QPoint p = d->view->doc()->zoomPoint(kop);
02787     p = mapToGlobal(p);
02788     d->view->openPopupMenu( p );
02789   }
02790   switch( _ev->key() )
02791   {
02792    case Key_Return:
02793    case Key_Enter:
02794     processEnterKey( _ev );
02795     return;
02796     break;
02797    case Key_Down:
02798    case Key_Up:
02799    case Key_Left:
02800    case Key_Right:
02801    case Key_Tab: /* a tab behaves just like a right/left arrow */
02802    case Key_Backtab:  /* and so does Shift+Tab */
02803     if (_ev->state() & ControlButton)
02804     {
02805       if ( !processControlArrowKey( _ev ) )
02806         return;
02807     }
02808     else
02809     {
02810       processArrowKey( _ev );
02811       return;
02812     }
02813     break;
02814 
02815    case Key_Escape:
02816     processEscapeKey( _ev );
02817     return;
02818     break;
02819 
02820    case Key_Home:
02821     if ( !processHomeKey( _ev ) )
02822       return;
02823     break;
02824 
02825    case Key_End:
02826     if ( !processEndKey( _ev ) )
02827       return;
02828     break;
02829 
02830    case Key_Prior:  /* Page Up */
02831     if ( !processPriorKey( _ev ) )
02832       return;
02833     break;
02834 
02835    case Key_Next:   /* Page Down */
02836     if ( !processNextKey( _ev ) )
02837       return;
02838     break;
02839 
02840    case Key_Delete:
02841     processDeleteKey( _ev );
02842     return;
02843     break;
02844 
02845    case Key_F2:
02846     processF2Key( _ev );
02847     return;
02848     break;
02849 
02850    case Key_F4:
02851     processF4Key( _ev );
02852     return;
02853     break;
02854 
02855    default:
02856     processOtherKey( _ev );
02857     return;
02858     break;
02859   }
02860 
02861   //most process*Key methods call emitEndOperation, this only gets called in some situations
02862   // (after some move operations)
02863   d->view->doc()->emitEndOperation( sheet->visibleRect( this ) );
02864   return;
02865 }
02866 
02867 void Canvas::processIMEvent( QIMEvent * event )
02868 {
02869   d->view->doc()->emitBeginOperation( false );
02870   if ( !d->cellEditor && !d->chooseCell )
02871   {
02872     // Switch to editing mode
02873     createEditor( CellEditor );
02874     d->cellEditor->handleIMEvent( event );
02875   }
02876 
02877   QPoint cursor;
02878 
02879   if ( d->chooseCell )
02880   {
02881     cursor = choice()->cursor();
02882     /* if the cursor is unset, pretend we're starting at the regular cursor */
02883     if (cursor.x() == 0 || cursor.y() == 0)
02884       cursor = choice()->cursor();
02885   }
02886   else
02887     cursor = selectionInfo()->cursor();
02888 
02889   d->view->doc()->emitEndOperation( QRect( cursor, cursor ) );
02890 }
02891 
02892 bool Canvas::formatKeyPress( QKeyEvent * _ev )
02893 {
02894   if (!(_ev->state() & ControlButton ))
02895     return false;
02896 
02897   int key = _ev->key();
02898   if ( key != Key_Exclam && key != Key_At && key != Key_Ampersand
02899        && key != Key_Dollar && key != Key_Percent && key != Key_AsciiCircum
02900        && key != Key_NumberSign )
02901     return false;
02902 
02903   Cell  * cell = 0L;
02904   Sheet * sheet = activeSheet();
02905 
02906   d->view->doc()->emitBeginOperation(false);
02907 
02908   if ( !d->view->doc()->undoLocked() )
02909   {
02910     QString dummy;
02911     UndoCellFormat * undo = new UndoCellFormat( d->view->doc(), sheet, *selectionInfo(), dummy );
02912     d->view->doc()->addCommand( undo );
02913   }
02914 
02915   Region::ConstIterator end(selectionInfo()->constEnd());
02916   for (Region::ConstIterator it = selectionInfo()->constBegin(); it != end; ++it)
02917   {
02918     QRect rect = (*it)->rect().normalize();
02919 
02920   int right  = rect.right();
02921   int bottom = rect.bottom();
02922 
02923   if ( util_isRowSelected(rect) )
02924   {
02925     for ( int r = rect.top(); r <= bottom; ++r )
02926     {
02927       cell = sheet->getFirstCellRow( r );
02928       while ( cell )
02929       {
02930         if ( cell->isPartOfMerged() )
02931         {
02932           cell = sheet->getNextCellRight( cell->column(), r );
02933           continue;
02934         }
02935 
02936         formatCellByKey (cell, _ev->key(), rect);
02937 
02938         cell = sheet->getNextCellRight( cell->column(), r );
02939       } // while (cell)
02940       RowFormat * rw = sheet->nonDefaultRowFormat( r );
02941       QPen pen;
02942       switch ( _ev->key() )
02943       {
02944        case Key_Exclam:
02945         rw->setFormatType (Number_format);
02946         rw->setPrecision( 2 );
02947         break;
02948 
02949        case Key_Dollar:
02950         rw->setFormatType (Money_format);
02951         rw->setPrecision( d->view->doc()->locale()->fracDigits() );
02952         break;
02953 
02954        case Key_Percent:
02955         rw->setFormatType (Percentage_format);
02956         break;
02957 
02958        case Key_At:
02959         rw->setFormatType( SecondeTime_format );
02960         break;
02961 
02962        case Key_NumberSign:
02963         rw->setFormatType( ShortDate_format );
02964         break;
02965 
02966        case Key_AsciiCircum:
02967         rw->setFormatType( Scientific_format );
02968         break;
02969 
02970        case Key_Ampersand:
02971         if ( r == rect.top() )
02972         {
02973           pen = QPen( d->view->borderColor(), 1, SolidLine);
02974           rw->setTopBorderPen( pen );
02975         }
02976         if ( r == rect.bottom() )
02977         {
02978           pen = QPen( d->view->borderColor(), 1, SolidLine);
02979           rw->setBottomBorderPen( pen );
02980         }
02981         break;
02982 
02983        default:
02984          d->view->doc()->emitEndOperation( rect );
02985         return false;
02986       }
02987       sheet->emit_updateRow( rw, r );
02988     }
02989 
02990     d->view->doc()->emitEndOperation( rect );
02991     return true;
02992   }
02993 
02994   if ( util_isColumnSelected(rect) )
02995   {
02996     for ( int c = rect.left(); c <= right; ++c )
02997     {
02998       cell = sheet->getFirstCellColumn( c );
02999       while ( cell )
03000       {
03001         if ( cell->isPartOfMerged() )
03002         {
03003           cell = sheet->getNextCellDown( c, cell->row() );
03004           continue;
03005         }
03006 
03007         formatCellByKey (cell, _ev->key(), rect);
03008 
03009         cell = sheet->getNextCellDown( c, cell->row() );
03010       }
03011 
03012       ColumnFormat * cw = sheet->nonDefaultColumnFormat( c );
03013       QPen pen;
03014       switch ( _ev->key() )
03015       {
03016        case Key_Exclam:
03017         cw->setFormatType( Number_format );
03018         cw->setPrecision( 2 );
03019         break;
03020 
03021        case Key_Dollar:
03022         cw->setFormatType( Money_format );
03023         cw->setPrecision( d->view->doc()->locale()->fracDigits() );
03024         break;
03025 
03026        case Key_Percent:
03027         cw->setFormatType( Percentage_format );
03028         break;
03029 
03030        case Key_At:
03031         cw->setFormatType( SecondeTime_format );
03032         break;
03033 
03034        case Key_NumberSign:
03035         cw->setFormatType( ShortDate_format );
03036         break;
03037 
03038        case Key_AsciiCircum:
03039         cw->setFormatType( Scientific_format );
03040         break;
03041 
03042        case Key_Ampersand:
03043         if ( c == rect.left() )
03044         {
03045           pen = QPen( d->view->borderColor(), 1, SolidLine);
03046           cw->setLeftBorderPen( pen );
03047         }
03048         if ( c == rect.right() )
03049         {
03050           pen = QPen( d->view->borderColor(), 1, SolidLine);
03051           cw->setRightBorderPen( pen );
03052         }
03053         break;
03054 
03055        default:
03056          d->view->doc()->emitEndOperation( rect );
03057          return false;
03058       }
03059       sheet->emit_updateColumn( cw, c );
03060     }
03061     d->view->doc()->emitEndOperation( rect );
03062     return true;
03063   }
03064 
03065   for ( int row = rect.top(); row <= bottom; ++row )
03066   {
03067     for ( int col = rect.left(); col <= right; ++ col )
03068     {
03069       cell = sheet->nonDefaultCell( col, row );
03070 
03071       if ( cell->isPartOfMerged() )
03072         continue;
03073 
03074       formatCellByKey (cell, _ev->key(), rect);
03075     } // for left .. right
03076   } // for top .. bottom
03077 
03078   }
03079   _ev->accept();
03080 
03081   d->view->doc()->emitEndOperation( *selectionInfo() );
03082   return true;
03083 }
03084 
03085 bool Canvas::formatCellByKey (Cell *cell, int key, const QRect &rect)
03086 {
03087   QPen pen;
03088   switch (key)
03089   {
03090     case Key_Exclam:
03091     cell->convertToDouble ();
03092     cell->format()->setFormatType (Number_format);
03093     cell->format()->setPrecision( 2 );
03094     break;
03095 
03096     case Key_Dollar:
03097     cell->convertToMoney ();
03098     break;
03099 
03100     case Key_Percent:
03101     cell->convertToPercent ();
03102     break;
03103 
03104     case Key_At:
03105     cell->convertToTime ();
03106     break;
03107 
03108     case Key_NumberSign:
03109     cell->convertToDate ();
03110     break;
03111 
03112     case Key_AsciiCircum:
03113     cell->format()->setFormatType (Scientific_format);
03114     cell->convertToDouble ();
03115     break;
03116 
03117     case Key_Ampersand:
03118     if ( cell->row() == rect.top() )
03119     {
03120       pen = QPen( d->view->borderColor(), 1, SolidLine);
03121       cell->setTopBorderPen( pen );
03122     }
03123     if ( cell->row() == rect.bottom() )
03124     {
03125       pen = QPen( d->view->borderColor(), 1, SolidLine);
03126       cell->setBottomBorderPen( pen );
03127     }
03128     if ( cell->column() == rect.left() )
03129     {
03130       pen = QPen( d->view->borderColor(), 1, SolidLine);
03131       cell->setLeftBorderPen( pen );
03132     }
03133     if ( cell->column() == rect.right() )
03134     {
03135       pen = QPen( d->view->borderColor(), 1, SolidLine);
03136       cell->setRightBorderPen( pen );
03137     }
03138     break;
03139   } // switch
03140 
03141   return true;
03142 }
03143 
03144 
03145 void Canvas::slotAutoScroll(const QPoint &scrollDistance)
03146 {
03147   QPoint d = scrollDistance;
03148   horzScrollBar()->setValue( horzScrollBar()->value() + d.x() );
03149   vertScrollBar()->setValue( vertScrollBar()->value() + d.y() );
03150 }
03151 
03152 void Canvas::doAutoScroll()
03153 {
03154     if ( !d->mousePressed )
03155     {
03156         d->scrollTimer->stop();
03157         return;
03158     }
03159     bool select = false;
03160     QPoint pos = mapFromGlobal( QCursor::pos() );
03161 
03162     //Provide progressive scrolling depending on the mouse position
03163     if ( pos.y() < 0 )
03164     {
03165         vertScrollBar()->setValue ((int) (vertScrollBar()->value() -
03166                                    autoScrollAccelerationY( - pos.y())));
03167         select = true;
03168     }
03169     else if ( pos.y() > height() )
03170     {
03171         vertScrollBar()->setValue ((int) (vertScrollBar()->value() +
03172                                    autoScrollAccelerationY (pos.y() - height())));
03173         select = true;
03174     }
03175 
03176     if ( pos.x() < 0 )
03177     {
03178         horzScrollBar()->setValue ((int) (horzScrollBar()->value() -
03179                                    autoScrollAccelerationX( - pos.x() )));
03180         select = true;
03181     }
03182     else if ( pos.x() > width() )
03183     {
03184         horzScrollBar()->setValue ((int) (horzScrollBar()->value() +
03185                                  autoScrollAccelerationX( pos.x() - width())));
03186         select = true;
03187     }
03188 
03189     if ( select )
03190     {
03191         QMouseEvent * event = new QMouseEvent(QEvent::MouseMove, pos, 0, 0);
03192         mouseMoveEvent( event );
03193         delete event;
03194     }
03195 
03196     //Restart timer
03197     d->scrollTimer->start( 50 );
03198 }
03199 
03200 void Canvas::speakCell(QWidget* w, const QPoint& p, uint flags)
03201 {
03202   Q_UNUSED(flags);
03203   if (w != this) return;
03204   Sheet* sheet = activeSheet();
03205   if (!sheet) return;
03206   int row = -1;
03207   int col = -1;
03208   if (p == QPoint()) {
03209     row = markerRow();
03210     col = markerColumn();
03211     if (row == d->prevSpokenFocusRow && col == d->prevSpokenFocusCol) return;
03212     d->prevSpokenFocusRow = row;
03213     d->prevSpokenFocusCol = col;
03214   } else {
03215     QPoint wp = w->mapFromGlobal(p);
03216     double tmp;
03217     double posX;
03218     if ( sheet->layoutDirection()==Sheet::RightToLeft )
03219     {
03220       double dwidth = d->view->doc()->unzoomItX( width() );
03221       posX = dwidth - d->view->doc()->unzoomItX( wp.x() );
03222     }
03223     else
03224       posX = d->view->doc()->unzoomItX( wp.x() );
03225 
03226     double posY = d->view->doc()->unzoomItY( wp.y() );
03227     col = sheet->leftColumn( (posX + xOffset()), tmp );
03228     row = sheet->topRow( (posY + yOffset()), tmp );
03229     if (row == d->prevSpokenPointerRow && col == d->prevSpokenPointerCol) return;
03230     d->prevSpokenPointerRow = row;
03231     d->prevSpokenPointerCol = col;
03232   }
03233   if (row == d->prevSpokenRow && col == d->prevSpokenCol) return;
03234   d->prevSpokenRow = row;
03235   d->prevSpokenCol = col;
03236   // kdDebug() << "Canvas::speakCell: row = " << row << " col = " << col << endl;
03237   if (row >=0 && col >= 0) {
03238     Cell* cell = sheet->cellAt( col, row );
03239     if (!cell) return;
03240     QString text = cell->strOutText();
03241     if (!text.isEmpty()) {
03242       text.prepend(i18n("Spreadsheet cell", "Cell ") + cell->name() + " ");
03243       if (cell->isFormula()) {
03244         QString f = cell->text();
03245         // Try to format the formula so synth can more clearly speak it.
03246         QString f2;
03247         for (uint i = 0; i < f.length(); i++) f2 += f[i] + " ";
03248         f2.replace("(", i18n("character (", "left paren"));
03249         f2.replace(")", i18n("character )", "right paren"));
03250         f2.replace(":", i18n("character :", "colon"));
03251         f2.replace(";", i18n("character ;", "semicolon"));
03252         f2.replace("=", i18n("character =", "equals"));
03253         f2.replace(".", i18n("character .", "point"));
03254         f2.replace(",", i18n("character ,", "comma"));
03255         f2.replace(" . . ", i18n("characters ..", " dot dot "));
03256         text.append(i18n("Spreadsheet formula", " Formula ") + f2);
03257       }
03258       // kdDebug() << "Canvas::speakCell: text = " << text << endl;
03259       kospeaker->sayWidget(text);
03260     }
03261   }
03262 }
03263 
03264 double Canvas::autoScrollAccelerationX( int offset )
03265 {
03266     switch( static_cast<int>( offset / 20 ) )
03267     {
03268         case 0: return 5.0;
03269         case 1: return 20.0;
03270         case 2: return d->view->doc()->unzoomItX( width() );
03271         case 3: return d->view->doc()->unzoomItX( width() );
03272         default: return d->view->doc()->unzoomItX( (int) (width() * 5.0) );
03273     }
03274 }
03275 
03276 double Canvas::autoScrollAccelerationY( int offset )
03277 {
03278     switch( static_cast<int>( offset / 20 ) )
03279     {
03280         case 0: return 5.0;
03281         case 1: return 20.0;
03282         case 2: return d->view->doc()->unzoomItY( height() );
03283         case 3: return d->view->doc()->unzoomItY( height() );
03284         default: return d->view->doc()->unzoomItY( (int) (height() * 5.0) );
03285     }
03286 }
03287 
03288 
03289 KSpread::EmbeddedObject *Canvas::getObject( const QPoint &pos, Sheet *_sheet )
03290 {
03291   QPoint const p ( (int) pos.x() ,
03292               (int) pos.y() );
03293 
03294   QPtrListIterator<EmbeddedObject> itObject( doc()->embeddedObjects() );
03295   for( ; itObject.current(); ++itObject )
03296   {
03297     if ( itObject.current()->sheet() == _sheet )
03298     {
03299         KoRect const bound = ( itObject.current() )->geometry();
03300         QRect zoomedBound = doc()->zoomRect( KoRect(bound.left(), bound.top(),
03301                                 bound.width(),
03302                                 bound.height() ) );
03303         zoomedBound.moveBy( (int)( -xOffset() * doc()->zoomedResolutionX() ), (int)( -yOffset() * doc()->zoomedResolutionY() ) );
03304          if ( zoomedBound.contains( p ) )
03305               return itObject.current();
03306     }
03307   }
03308   return 0;
03309 }
03310 
03311 void Canvas::selectObject( EmbeddedObject *obj )
03312 {
03313   if ( obj->sheet() != activeSheet() || obj->isSelected() )
03314     return;
03315   obj->setSelected( true );
03316   repaintObject( obj );
03317 
03318   d->mouseSelectedObject = true;
03319   emit objectSelectedChanged();
03320   deleteEditor( true );
03321 }
03322 
03323 void Canvas::deselectObject( EmbeddedObject *obj )
03324 {
03325   if ( obj->sheet() != activeSheet() || !obj->isSelected() )
03326     return;
03327   obj->setSelected( false );
03328   repaintObject( obj );
03329 
03330   d->mouseSelectedObject = false;
03331   emit objectSelectedChanged();
03332 }
03333 
03334 void Canvas::selectAllObjects()
03335 {
03336   QPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
03337   for ( ; it.current() ; ++it )
03338   {
03339     if ( it.current()->sheet() == activeSheet() )
03340       it.current()->setSelected( true );
03341   }
03342 
03343    d->mouseSelectedObject = true;
03344 //   emit objectSelectedChanged();
03345 }
03346 
03347 void Canvas::deselectAllObjects()
03348 {
03349   if( activeSheet()->numSelected() == 0 )
03350     return;
03351 
03352   //lowerObject();
03353 
03354   QPtrListIterator<EmbeddedObject> it( doc()->embeddedObjects() );
03355   for ( ; it.current() ; ++it )
03356       deselectObject( it.current() );
03357 
03358    d->mouseSelectedObject = false;
03359 //   emit objectSelectedChanged();
03360 }
03361 
03362 
03363 
03364 void Canvas::setMouseSelectedObject(bool b)
03365 {
03366   d->mouseSelectedObject = b;
03367   emit objectSelectedChanged();
03368 }
03369 
03370 bool Canvas::isObjectSelected()
03371 {
03372   return d->mouseSelectedObject;
03373 }
03374 
03375 
03376 void Canvas::moveObjectsByMouse( KoPoint &pos, bool keepXorYunchanged )
03377 {
03378   KoRect rect( objectRect( false ) );
03379   KoPoint move( 0, 0 );
03380   double diffx = pos.x() - d->m_origMousePos.x();
03381   double diffy = pos.y() - d->m_origMousePos.y();
03382 
03383   move = KoPoint( diffx, diffy );
03384   d->m_origMousePos = pos;
03385 
03386     // unwind last snapping
03387   KoRect movedRect( rect );
03388   movedRect.moveBy( diffx, diffy );
03389 
03390     // don't move object off canvas
03391   KoPoint diffDueToBorders(0,0);
03392 //   KoRect pageRect( m_activePage->getPageRect() );
03393   if ( rect.left() + move.x() < 0/*pageRect.left()*/ )
03394     diffDueToBorders.setX( -rect.left() - move.x() );
03395 //   else if ( rect.right() + move.x() > pageRect.right() )
03396 //     diffDueToBorders.setX( pageRect.right() - (rect.right() + move.x()) );
03397 
03398 
03399   //kdDebug() << "rect.top() + move.y():" << rect.top() + move.y()<< endl;
03400   if ( rect.top() + move.y() < 0 )
03401     diffDueToBorders.setY( -rect.top() - move.y() );
03402 //   else if ( rect.bottom() + move.y() > pageRect.bottom() )
03403 //     diffDueToBorders.setY( pageRect.bottom() - (rect.bottom() + move.y()) );
03404 
03405 //   m_moveSnapDiff += diffDueToBorders;
03406   move += diffDueToBorders;
03407 
03408 //   movedRect.moveBy( m_moveSnapDiff.x(), m_moveSnapDiff.y() );
03409   if ( keepXorYunchanged )
03410   {
03411     KoPoint diff( d->m_moveStartPosMouse - movedRect.topLeft() );
03412     if ( fabs( diff.x() ) > fabs( diff.y() ) )
03413     {
03414 //       m_moveSnapDiff.setY( /*m_moveSnapDiff.y() + */m_moveStartPosMouse.y() - movedRect.y() );
03415       movedRect.moveTopLeft( KoPoint( movedRect.x(), d->m_moveStartPosMouse.y() ) );
03416       move.setY( movedRect.y() - rect.y() );
03417     }
03418     else
03419     {
03420 //       m_moveSnapDiff.setX( /*m_moveSnapDiff.x() + */m_moveStartPosMouse.x() - movedRect.x() );
03421       movedRect.moveTopLeft( KoPoint( d->m_moveStartPosMouse.x(), movedRect.y() ) );
03422       move.setX( movedRect.x() - rect.x() );
03423     }
03424   }
03425 
03426   if ( move != KoPoint( 0, 0 ) )
03427   {
03428         //kdDebug(33001) << "moveObjectsByMouse move = " << move << endl;
03429     activeSheet()->moveObject( view(), move, false );
03430   }
03431 }
03432 
03433 
03434 void Canvas::resizeObject( ModifyType _modType, const KoPoint & point, bool keepRatio )
03435 {
03436     EmbeddedObject *obj = d->m_resizeObject;
03437 
03438     KoRect objRect = obj->geometry();
03439     objRect.moveBy( -xOffset(), -yOffset() );
03440     QRect oldBoundingRect( doc()->zoomRect( objRect ) );
03441 
03442     bool left = false;
03443     bool right = false;
03444     bool top = false;
03445     bool bottom = false;
03446     if ( _modType == MT_RESIZE_UP || _modType == MT_RESIZE_LU || _modType == MT_RESIZE_RU )
03447     {
03448         top = true;
03449 //         snapStatus |= KoGuides::SNAP_HORIZ;
03450     }
03451     if ( _modType == MT_RESIZE_DN || _modType == MT_RESIZE_LD || _modType == MT_RESIZE_RD )
03452     {
03453         bottom = true;
03454 //         snapStatus |= KoGuides::SNAP_HORIZ;
03455     }
03456     if ( _modType == MT_RESIZE_LF || _modType == MT_RESIZE_LU || _modType == MT_RESIZE_LD )
03457     {
03458         left = true;
03459 //         snapStatus |= KoGuides::SNAP_VERT;
03460     }
03461     if ( _modType == MT_RESIZE_RT || _modType == MT_RESIZE_RU || _modType == MT_RESIZE_RD )
03462     {
03463         right = true;
03464 //         snapStatus |= KoGuides::SNAP_VERT;
03465     }
03466 
03467     double newLeft = objRect.left();
03468     double newRight = objRect.right();
03469     double newTop = objRect.top();
03470     double newBottom = objRect.bottom();
03471     if ( top )
03472     {
03473         if ( point.y() < objRect.bottom() - MIN_SIZE )
03474         {
03475             newTop = point.y();
03476         }
03477         else
03478         {
03479             newTop = objRect.bottom() - MIN_SIZE;
03480         }
03481     }
03482     if ( bottom )
03483     {
03484         if ( point.y() > objRect.top() + MIN_SIZE )
03485         {
03486             newBottom = point.y();
03487         }
03488         else
03489         {
03490             newBottom = objRect.top() + MIN_SIZE;
03491         }
03492     }
03493     if ( left )
03494     {
03495         if ( point.x() < objRect.right() - MIN_SIZE )
03496         {
03497             newLeft = point.x();
03498         }
03499         else
03500         {
03501             newLeft = objRect.right() - MIN_SIZE;
03502         }
03503     }
03504     if ( right )
03505     {
03506         if ( point.x() > objRect.left() + MIN_SIZE )
03507         {
03508             newRight = point.x();
03509         }
03510         else
03511         {
03512             newRight = objRect.left() + MIN_SIZE;
03513         }
03514     }
03515 
03516   double width = newRight - newLeft;
03517   double height = newBottom - newTop;
03518 
03519   if ( keepRatio && d->m_ratio != 0 )
03520   {
03521     if ( ( top || bottom ) && ( right || left ) )
03522     {
03523       if ( height * height * d->m_ratio > width * width / d->m_ratio )
03524       {
03525         width = height * d->m_ratio;
03526       }
03527       else
03528       {
03529         height = width / d->m_ratio;
03530       }
03531     }
03532     else if ( top || bottom )
03533     {
03534       width = height * d->m_ratio;
03535     }
03536     else
03537     {
03538       height = width / d->m_ratio;
03539     }
03540 
03541     if ( top )
03542     {
03543       newTop = objRect.bottom() - height;
03544     }
03545     else
03546     {
03547       newBottom = objRect.top() + height;
03548     }
03549     if ( left )
03550     {
03551       newLeft = objRect.right() - width;
03552     }
03553     else
03554     {
03555       newRight = objRect.right() + width;
03556     }
03557   }
03558 
03559   if ( newLeft != objRect.left() || newRight != objRect.right() || newTop != objRect.top() || newBottom != objRect.bottom() )
03560   {
03561         // resizeBy and moveBy have to been used to make it work with rotated objects
03562         obj->resizeBy( width - objRect.width(), height - objRect.height() );
03563 
03564         if ( objRect.left() != newLeft || objRect.top() != newTop )
03565         {
03566             obj->moveBy( KoPoint( newLeft - objRect.left(), newTop - objRect.top() ) );
03567         }
03568 
03569 //     if ( doc()->showGuideLines() && !m_disableSnapping )
03570 //     {
03571 //       KoRect rect( obj->getRealRect() );
03572 //       KoPoint sp( rect.topLeft() );
03573 //       if ( right )
03574 //       {
03575 //         sp.setX( rect.right() );
03576 //       }
03577 //       if ( bottom )
03578 //       {
03579 //         sp.setY( rect.bottom() );
03580 //       }
03581 //       m_gl.repaintSnapping( sp, snapStatus );
03582 //     }
03583 
03584     repaint( oldBoundingRect );
03585     repaintObject( obj );
03586     emit objectSizeChanged();
03587   }
03588 }
03589 
03590 
03591 void Canvas::finishResizeObject( const QString &/*name*/, bool /*layout*/ )
03592 {
03593   if ( d->m_resizeObject )
03594   {
03595     KoPoint move = KoPoint( d->m_resizeObject->geometry().x() - d->m_rectBeforeResize.x(),
03596                             d->m_resizeObject->geometry().y() - d->m_rectBeforeResize.y() );
03597     KoSize size = KoSize( d->m_resizeObject->geometry().width() - d->m_rectBeforeResize.width(),
03598                           d->m_resizeObject->geometry().height() - d->m_rectBeforeResize.height() );
03599 
03600     if ( ( d->m_resizeObject->geometry() ) != d->m_rectBeforeResize )
03601     {
03602         ChangeObjectGeometryCommand *resizeCmd = new ChangeObjectGeometryCommand( d->m_resizeObject, move, size );
03603         // the command is not executed as the object is allready resized.
03604         doc()->addCommand( resizeCmd );
03605     }
03606 
03607 //     if ( layout )
03608 //       doc()->layout( m_resizeObject );
03609 
03610     d->m_ratio = 0.0;
03611     d->m_isResizing = false;
03612     repaintObject( d->m_resizeObject );
03613     d->m_resizeObject = NULL;
03614   }
03615 }
03616 
03617 void Canvas::raiseObject( EmbeddedObject *object )
03618 {
03619     if ( doc()->embeddedObjects().count() <= 1 )
03620         return;
03621 
03622     if ( d->m_objectDisplayAbove == 0 )
03623     {
03624         if ( activeSheet()->numSelected() == 1 )
03625         {
03626             d->m_objectDisplayAbove = object;
03627         }
03628     }
03629 }
03630 
03631 void Canvas::lowerObject()
03632 {
03633     d->m_objectDisplayAbove = 0;
03634 }
03635 
03636 void Canvas::displayObjectList( QPtrList<EmbeddedObject> &list )
03637 {
03638   list = doc()->embeddedObjects();
03639   list.setAutoDelete( false );
03640 
03641     if ( d->m_objectDisplayAbove )
03642     {
03643         // it can happen that the object is no longer there e.g. when
03644         // the insert of the object is undone
03645         int pos = doc()->embeddedObjects().findRef( d->m_objectDisplayAbove );
03646         if ( pos != -1 && d->m_objectDisplayAbove->isSelected() )
03647         {
03648             list.take( pos );
03649             list.append( d->m_objectDisplayAbove );
03650         }
03651         else
03652         {
03653             //tz not possible due to const. should const be removed?
03654             //m_objectDisplayAbove = 0;
03655         }
03656     }
03657 }
03658 
03659 
03660 KoRect Canvas::objectRect( bool all ) const
03661 {
03662   return activeSheet()->getRealRect( all );
03663 }
03664 
03665 void Canvas::deleteEditor (bool saveChanges, bool array)
03666 {
03667   if ( !d->cellEditor )
03668     return;
03669 
03670 
03671     //There may be highlighted areas on the sheet which will need to be erased
03672     setSelectionChangePaintDirty( activeSheet() , *choice() );
03673 
03674     d->editWidget->setEditMode( false );
03675 
03676   QString t = d->cellEditor->text();
03677   // Delete the cell editor first and after that update the document.
03678   // That means we get a synchronous repaint after the cell editor
03679   // widget is gone. Otherwise we may get painting errors.
03680   delete d->cellEditor;
03681   d->cellEditor = 0;
03682 
03683   if ( saveChanges )
03684   {
03685       if ( t.at(0)=='=' )
03686       {
03687           //a formula
03688           int openParenthese = t.contains('(' );
03689           int closeParenthese = t.contains(')' );
03690           int diff = QABS( openParenthese - closeParenthese );
03691           if ( openParenthese > closeParenthese )
03692           {
03693               for (int i=0; i < diff;i++)
03694               {
03695                   t=t+')';
03696               }
03697           }
03698       }
03699     d->view->setText (t, array);
03700   }
03701   else
03702   {
03703     d->view->updateEditWidget();
03704   }
03705 
03706   setFocus();
03707 }
03708 
03709 
03710 void Canvas::createEditor(bool captureArrowKeys)
03711 {
03712   if (!activeSheet())
03713     return;
03714 
03715   Cell * cell = activeSheet()->nonDefaultCell( markerColumn(), markerRow(), false );
03716 
03717   if ( !createEditor( CellEditor , true , captureArrowKeys ) )
03718       return;
03719   if ( cell )
03720       d->cellEditor->setText( cell->text() );
03721 }
03722 
03723 bool Canvas::createEditor( EditorType ed, bool addFocus, bool captureArrowKeys )
03724 {
03725   Sheet * sheet = activeSheet();
03726 
03727   //Ensure that the choice always has a sheet associated
03728   //with it.
03729   //
03730   //FIXME:  This really doesn't make sense.  The concept of
03731   //the 'choice selection' having only one sheet is wrong - because
03732   //different parts of the choice selection may be on different
03733   //sheets (at least, this doesn't work at the moment, but it should
03734   //do).  REVIEW after KSpread 1.5 has been released.
03735   //
03736   //This is a temporary workaround for now.  It fixes the problem
03737   //where the editor would be hidden because the choice's sheet
03738   //was not the active sheet.
03739   if (!choice()->sheet())
03740     choice()->setSheet( activeSheet() );
03741 
03742   if ( !d->cellEditor )
03743   {
03744     Cell * cell = sheet->nonDefaultCell( marker().x(), marker().y(), false );
03745 
03746     if ( sheet->isProtected() && !cell->format()->notProtected( marker().x(), marker().y() ) )
03747       return false;
03748 
03749     if ( ed == CellEditor )
03750     {
03751       d->editWidget->setEditMode( true );
03752       d->cellEditor = new KSpread::CellEditor( cell, this, captureArrowKeys );
03753     }
03754 
03755     double w, h;
03756     double min_w = cell->dblWidth( markerColumn() );
03757     double min_h = cell->dblHeight( markerRow() );
03758     if ( cell->isDefault() )
03759     {
03760       w = min_w;
03761       h = min_h;
03762       //kdDebug(36001) << "DEFAULT" << endl;
03763     }
03764     else
03765     {
03766       w = cell->extraWidth();
03767       h = cell->extraHeight();
03768       //kdDebug(36001) << "HEIGHT=" << min_h << " EXTRA=" << h << endl;
03769     }
03770 
03771     double xpos = sheet->dblColumnPos( markerColumn() ) - xOffset();
03772 
03773     Sheet::LayoutDirection sheetDir = sheet->layoutDirection();
03774     bool rtlText = cell->strOutText().isRightToLeft();
03775 
03776     // if sheet and cell direction don't match, then the editor's location
03777     // needs to be shifted backwards so that it's right above the cell's text
03778     if ( w > 0 && ( ( sheetDir == Sheet::RightToLeft && !rtlText ) ||
03779                     ( sheetDir == Sheet::LeftToRight && rtlText  ) ) )
03780       xpos -= w - min_w;
03781 
03782     // paint editor above correct cell if sheet direction is RTL
03783     if ( sheetDir == Sheet::RightToLeft )
03784     {
03785       double dwidth = d->view->doc()->unzoomItX( width() );
03786       double w2 = QMAX( w, min_w );
03787       xpos = dwidth - w2 - xpos;
03788     }
03789 
03790     double ypos = sheet->dblRowPos( markerRow() ) - yOffset();
03791     QPalette p = d->cellEditor->palette();
03792     QColorGroup g( p.active() );
03793 
03794     QColor color = cell->format()->textColor( markerColumn(), markerRow() );
03795     if ( !color.isValid() )
03796         color = QApplication::palette().active().text();
03797     g.setColor( QColorGroup::Text, color);
03798 
03799     color = cell->bgColor( markerColumn(), markerRow() );
03800     if ( !color.isValid() )
03801         color = g.base();
03802     g.setColor( QColorGroup::Background, color );
03803 
03804     d->cellEditor->setPalette( QPalette( g, p.disabled(), g ) );
03805     QFont tmpFont = cell->format()->textFont( markerColumn(), markerRow() );
03806     tmpFont.setPointSizeFloat( 0.01 * d->view->doc()->zoom() * tmpFont.pointSizeFloat() );
03807     d->cellEditor->setFont( tmpFont );
03808 
03809     KoRect rect( xpos, ypos, w, h ); //needed to circumvent rounding issue with height/width
03810 
03811 
03812     QRect zoomedRect=d->view->doc()->zoomRect( rect );
03813     /*zoomedRect.setLeft(zoomedRect.left()-2);
03814     zoomedRect.setRight(zoomedRect.right()+4);
03815     zoomedRect.setTop(zoomedRect.top()-1);
03816     zoomedRect.setBottom(zoomedRect.bottom()+2);*/
03817 
03818     d->cellEditor->setGeometry( zoomedRect );
03819     d->cellEditor->setMinimumSize( QSize( d->view->doc()->zoomItX( min_w ), d->view->doc()->zoomItY( min_h ) ) );
03820     d->cellEditor->show();
03821     //kdDebug(36001) << "FOCUS1" << endl;
03822     //Laurent 2001-12-05
03823     //Don't add focus when we create a new editor and
03824     //we select text in edit widget otherwise we don't delete
03825     //selected text.
03826   //  startChoose();
03827 
03828     if ( addFocus )
03829         d->cellEditor->setFocus();
03830 
03831     setSelectionChangePaintDirty(sheet, *selectionInfo());
03832     paintUpdates();
03833   }
03834 
03835   return true;
03836 }
03837 
03838 void Canvas::repaintObject( EmbeddedObject *obj )
03839 {
03840     //Calculate where the object appears on the canvas widget and then repaint that part of the widget
03841     QRect canvasRelativeGeometry = doc()->zoomRect( obj->geometry() );
03842     canvasRelativeGeometry.moveBy( (int)( -xOffset()*doc()->zoomedResolutionX() ) ,
03843                         (int)( -yOffset() * doc()->zoomedResolutionY()) );
03844 
03845     update( canvasRelativeGeometry );
03846 
03847  /* if ( !obj->isSelected() )
03848   {
03849     KoRect g = obj->geometry();
03850     g.moveBy( -xOffset(), -yOffset() );
03851     QRect geometry( doc()->zoomRect( g ) );
03852 
03853     update( geometry );
03854   }
03855   else
03856   {
03857     QPainter p(this);
03858     p.translate( -xOffset() * doc()->zoomedResolutionX() , -yOffset() * doc()->zoomedResolutionY() );
03859     obj->draw(&p); //this goes faster than calling repaint
03860     p.end();
03861   }*/
03862 }
03863 
03864 void Canvas::copyOasisObjects()
03865 {
03866     // We'll create a store (ZIP format) in memory
03867     QBuffer buffer;
03868     QCString mimeType = "application/vnd.oasis.opendocument.spreadsheet";
03869     KoStore* store = KoStore::createStore( &buffer, KoStore::Write, mimeType );
03870     Q_ASSERT( store );
03871     Q_ASSERT( !store->bad() );
03872     KoOasisStore oasisStore( store );
03873 
03874     KoXmlWriter* manifestWriter = oasisStore.manifestWriter( mimeType );
03875 
03876     QString plainText;
03877     KoPicture picture;
03878     if ( !doc()->saveOasisHelper( store, manifestWriter, Doc::SaveSelected, &plainText, &picture )
03879          || !oasisStore.closeManifestWriter() )
03880     {
03881         delete store;
03882         return;
03883     }
03884     delete store;
03885 
03886     KMultipleDrag* multiDrag = new KMultipleDrag();
03887     if ( !plainText.isEmpty() )
03888         multiDrag->addDragObject( new QTextDrag( plainText, 0 ) );
03889     if ( !picture.isNull() )
03890         multiDrag->addDragObject( picture.dragObject( 0 ) );
03891     KoStoreDrag* storeDrag = new KoStoreDrag( mimeType, 0 );
03892     kdDebug() << k_funcinfo << "setting zip data: " << buffer.buffer().size() << " bytes." << endl;
03893     storeDrag->setEncodedData( buffer.buffer() );
03894     multiDrag->addDragObject( storeDrag );
03895 
03896     //save the objects as pictures too so that other programs can access them
03897     QPtrListIterator<EmbeddedObject> itObject( doc()->embeddedObjects() );
03898     itObject.toFirst();
03899     if ( itObject.current() )
03900     {
03901       KoRect kr = objectRect(false);
03902       QRect r( kr.toQRect() );
03903       QPixmap pixmap( r.width(), r.height() );
03904       pixmap.fill( "white" );
03905       QPainter p(&pixmap);
03906       for( ; itObject.current(); ++itObject )
03907       {
03908         if ( itObject.current()->isSelected() )
03909           p.drawPixmap( itObject.current()->geometry().toQRect().left() - r.left(), itObject.current()->geometry().toQRect().top() - r.top(), itObject.current()->toPixmap( 1.0 , 1.0 ) );
03910       }
03911       p.end();
03912       if (!pixmap.isNull())
03913       {
03914         QImageDrag *imagedrag = new QImageDrag( pixmap.convertToImage() );
03915         multiDrag->addDragObject( imagedrag );
03916       }
03917     }
03918 
03919     QDragObject *dragObject = multiDrag;
03920     QApplication::clipboard()->setData( dragObject, QClipboard::Clipboard );
03921 }
03922 
03923 void Canvas::closeEditor()
03924 {
03925   if ( d->chooseCell )
03926     return;
03927 
03928   if ( d->cellEditor )
03929   {
03930     deleteEditor( true ); // save changes
03931   }
03932 }
03933 
03934 void Canvas::updateEditor()
03935 {
03936   if (!d->chooseCell)
03937     return;
03938 
03939   Sheet* sheet = activeSheet();
03940   if (!sheet)
03941     return;
03942 
03943   if (d->cellEditor)
03944   {
03945     if (choice()->sheet() != sheet)
03946     {
03947       d->cellEditor->hide();
03948     }
03949     else
03950     {
03951       d->cellEditor->show();
03952     }
03953     d->cellEditor->updateChoice();
03954   }
03955 }
03956 
03957 void Canvas::setSelectionChangePaintDirty(Sheet* sheet, const Region& region)
03958 {
03959   sheet->setRegionPaintDirty(region); // TODO should the paintDirtyList be in Canvas?
03960 }
03961 
03962 
03963 void Canvas::updatePosWidget()
03964 {
03965     QString buffer;
03966     // No selection, or only one cell merged selected
03967     if ( selectionInfo()->isSingular() )
03968     {
03969         if (activeSheet()->getLcMode())
03970         {
03971             buffer = "L" + QString::number( markerRow() ) +
03972         "C" + QString::number( markerColumn() );
03973         }
03974         else
03975         {
03976             buffer = Cell::columnName( markerColumn() ) +
03977         QString::number( markerRow() );
03978         }
03979     }
03980     else
03981     {
03982         if (activeSheet()->getLcMode())
03983         {
03984           buffer = QString::number( (selectionInfo()->lastRange().bottom()-selectionInfo()->lastRange().top()+1) )+"Lx";
03985           if ( util_isRowSelected( selectionInfo()->lastRange() ) )
03986             buffer+=QString::number((KS_colMax-selectionInfo()->lastRange().left()+1))+"C";
03987             else
03988               buffer+=QString::number((selectionInfo()->lastRange().right()-selectionInfo()->lastRange().left()+1))+"C";
03989         }
03990         else
03991         {
03992                 //encodeColumnLabelText return @@@@ when column >KS_colMax
03993                 //=> it's not a good display
03994                 //=> for the moment I display pos of marker
03995           buffer=Cell::columnName( selectionInfo()->lastRange().left() ) +
03996                     QString::number(selectionInfo()->lastRange().top()) + ":" +
03997                     Cell::columnName( QMIN( KS_colMax, selectionInfo()->lastRange().right() ) ) +
03998                     QString::number(selectionInfo()->lastRange().bottom());
03999                 //buffer=activeSheet()->columnLabel( m_iMarkerColumn );
04000                 //buffer+=tmp.setNum(m_iMarkerRow);
04001         }
04002   }
04003 
04004     if (buffer != d->posWidget->lineEdit()->text())
04005       d->posWidget->lineEdit()->setText(buffer);
04006 }
04007 
04008 void Canvas::equalizeRow()
04009 {
04010   QRect s( selection() );
04011   RowFormat *rl = d->view->activeSheet()->rowFormat(s.top());
04012   int size=rl->height(this);
04013   if ( s.top() == s.bottom() )
04014       return;
04015   for(int i=s.top()+1;i<=s.bottom();i++)
04016   {
04017       Sheet *sheet = activeSheet();
04018       if ( !sheet )
04019           return;
04020       size=QMAX(d->view->activeSheet()->rowFormat(i)->height(this),size);
04021   }
04022   d->view->vBorderWidget()->equalizeRow(size);
04023 }
04024 
04025 void Canvas::equalizeColumn()
04026 {
04027   QRect s( selection() );
04028   ColumnFormat *cl = d->view->activeSheet()->columnFormat(s.left());
04029   int size=cl->width(this);
04030   if ( s.left() == s.right() )
04031       return;
04032 
04033   for(int i=s.left()+1;i<=s.right();i++)
04034   {
04035     size=QMAX(d->view->activeSheet()->columnFormat(i)->width(this),size);
04036   }
04037   d->view->hBorderWidget()->equalizeColumn(size);
04038 }
04039 
04040 QRect Canvas::cellsInArea( const QRect area ) const
04041 {
04042     KoRect unzoomedRect = d->view->doc()->unzoomRect( area );
04043 
04044         unzoomedRect.moveBy( (int)xOffset(), (int)yOffset() );
04045 
04046     double tmp;
04047     int left_col = activeSheet()->leftColumn( unzoomedRect.left(), tmp );
04048     int right_col = activeSheet()->rightColumn( unzoomedRect.right() );
04049     int top_row = activeSheet()->topRow( unzoomedRect.top(), tmp );
04050     int bottom_row = activeSheet()->bottomRow( unzoomedRect.bottom() );
04051 
04052     return QRect( left_col, top_row,
04053                 right_col - left_col + 1, bottom_row - top_row + 1 );
04054 }
04055 
04056 QRect Canvas::visibleCells() const
04057 {
04058     return cellsInArea( QRect(0,0,width(),height()) );
04059 
04060 }
04061 
04062 
04063 //---------------------------------------------
04064 //
04065 // Drawing Engine
04066 //
04067 //---------------------------------------------
04068 
04069 void Canvas::paintUpdates()
04070 {
04071   if (activeSheet() == NULL)
04072     return;
04073 
04074   QPainter painter(this);
04075 
04076   //Save clip region
04077   QRegion rgnComplete( painter.clipRegion() );
04078   QWMatrix matrix;
04079   if ( d->view )
04080   {
04081     matrix = d->view->matrix();
04082   }
04083   else
04084   {
04085     matrix = painter.worldMatrix();
04086   }
04087 
04088 
04089   paintChildren( painter, matrix );
04090 
04091   painter.save();
04092   clipoutChildren( painter );
04093 
04094   KoRect unzoomedRect = d->view->doc()->unzoomRect( QRect( 0, 0, width(), height() ) );
04095   // unzoomedRect.moveBy( xOffset(), yOffset() );
04096 
04097 
04098   /* paint any visible cell that has the paintDirty flag */
04099   QRect range = visibleCells();
04100   Cell* cell = NULL;
04101 
04102   double topPos = activeSheet()->dblRowPos(range.top());
04103   double leftPos = activeSheet()->dblColumnPos(range.left());
04104 
04105   KoPoint dblCorner( leftPos - xOffset(), topPos - yOffset() );
04106 
04107   int x;
04108   int y;
04109 
04110   int right  = range.right();
04111   int bottom = range.bottom();
04112   Sheet * sheet = activeSheet();
04113 
04114 #if 0
04115   kdDebug(36001)
04116     << "================================================================"
04117     << endl;
04118   kdDebug(36001) << "painting dirty cells " << endl;
04119 #endif
04120 
04121   QValueList<QPoint>  mergedCellsPainted;
04122   for ( x = range.left(); x <= right; ++x )
04123   {
04124     for ( y = range.top(); y <= bottom; ++y )
04125     {
04126       if ( sheet->cellIsPaintDirty( QPoint( x, y ) ) )
04127       {
04128         cell = sheet->cellAt( x, y );
04129 
04130         // recalc and relayout only for non default cells
04131         if (!cell->isDefault())
04132         {
04133           if (cell->calcDirtyFlag()) cell->calc();
04134           if (cell->layoutDirtyFlag()) cell->makeLayout( painter, x, y );
04135         }
04136 
04137        /* bool paintBordersBottom = false;
04138         bool paintBordersRight = false;
04139         bool paintBordersLeft = false;
04140     bool paintBordersTop = false; */
04141 
04142     int paintBorder=Cell::Border_None;
04143 
04144         QPen bottomPen( cell->effBottomBorderPen( x, y ) );
04145         QPen rightPen( cell->effRightBorderPen( x, y ) );
04146         QPen leftPen( cell->effLeftBorderPen( x, y ) );
04147         QPen topPen( cell->effTopBorderPen( x, y ) );
04148 
04149         // paint right border if rightmost cell or if the pen is more "worth" than the left border pen
04150         // of the cell on the left or if the cell on the right is not painted. In the latter case get
04151         // the pen that is of more "worth"
04152         if ( x >= KS_colMax )
04153          // paintBordersRight = true;
04154         paintBorder |= Cell::Border_Right;
04155         else
04156           if ( sheet->cellIsPaintDirty( QPoint( x + 1, y ) ) )
04157           {
04158             //paintBordersRight = true;
04159           paintBorder |= Cell::Border_Right;
04160             if ( cell->effRightBorderValue( x, y ) < sheet->cellAt( x + 1, y )->effLeftBorderValue( x + 1, y ) )
04161               rightPen = sheet->cellAt( x + 1, y )->effLeftBorderPen( x + 1, y );
04162           }
04163         else
04164         {
04165          // paintBordersRight = true;
04166         paintBorder |= Cell::Border_Right;
04167           if ( cell->effRightBorderValue( x, y ) < sheet->cellAt( x + 1, y )->effLeftBorderValue( x + 1, y ) )
04168             rightPen = sheet->cellAt( x + 1, y )->effLeftBorderPen( x + 1, y );
04169         }
04170 
04171         // similiar for other borders...
04172         // bottom border:
04173         if ( y >= KS_rowMax )
04174          // paintBordersBottom = true;
04175         paintBorder |= Cell::Border_Bottom;
04176         else
04177           if ( sheet->cellIsPaintDirty( QPoint( x, y + 1 ) ) )
04178           {
04179             if ( cell->effBottomBorderValue( x, y ) > sheet->cellAt( x, y + 1 )->effTopBorderValue( x, y + 1 ) )
04180              // paintBordersBottom = true;
04181             paintBorder |= Cell::Border_Bottom;
04182           }
04183         else
04184         {
04185           //paintBordersBottom = true;
04186         paintBorder |= Cell::Border_Bottom;
04187           if ( cell->effBottomBorderValue( x, y ) < sheet->cellAt( x, y + 1 )->effTopBorderValue( x, y + 1 ) )
04188             bottomPen = sheet->cellAt( x, y + 1 )->effTopBorderPen( x, y + 1 );
04189         }
04190 
04191         // left border:
04192         if ( x == 1 )
04193          // paintBordersLeft = true;
04194         paintBorder |= Cell::Border_Left;
04195         else
04196           if ( sheet->cellIsPaintDirty( QPoint( x - 1, y ) ) )
04197           {
04198            // paintBordersLeft = true;
04199           paintBorder |= Cell::Border_Left;
04200             if ( cell->effLeftBorderValue( x, y ) < sheet->cellAt( x - 1, y )->effRightBorderValue( x - 1, y ) )
04201               leftPen = sheet->cellAt( x - 1, y )->effRightBorderPen( x - 1, y );
04202           }
04203         else
04204         {
04205         paintBorder |= Cell::Border_Left;
04206           if ( cell->effLeftBorderValue( x, y ) < sheet->cellAt( x - 1, y )->effRightBorderValue( x - 1, y ) )
04207             leftPen = sheet->cellAt( x - 1, y )->effRightBorderPen( x - 1, y );
04208         }
04209 
04210         // top border:
04211         if ( y == 1 )
04212         //  paintBordersTop = true;
04213         paintBorder |= Cell::Border_Top;
04214         else
04215           if ( sheet->cellIsPaintDirty( QPoint( x, y - 1 ) ) )
04216           {
04217           //  paintBordersTop = true;
04218           paintBorder |= Cell::Border_Top;
04219             if ( cell->effTopBorderValue( x, y ) < sheet->cellAt( x, y - 1 )->effBottomBorderValue( x, y - 1 ) )
04220               topPen = sheet->cellAt( x, y - 1 )->effBottomBorderPen( x, y - 1 );
04221           }
04222         else
04223         {
04224         //  paintBordersTop = true;
04225         paintBorder |= Cell::Border_Top;
04226           if ( cell->effTopBorderValue( x, y ) < sheet->cellAt( x, y - 1 )->effBottomBorderValue( x, y - 1 ) )
04227             topPen = sheet->cellAt( x, y - 1 )->effBottomBorderPen( x, y - 1 );
04228         }
04229 
04230     cell->paintCell( unzoomedRect, painter, d->view, dblCorner,
04231              QPoint( x, y), paintBorder,
04232              rightPen,bottomPen,leftPen,topPen,
04233              mergedCellsPainted);
04234 
04235 
04236       }
04237       dblCorner.setY( dblCorner.y() + sheet->rowFormat( y )->dblHeight( ) );
04238     }
04239     dblCorner.setY( topPos - yOffset() );
04240     dblCorner.setX( dblCorner.x() + sheet->columnFormat( x )->dblWidth( ) );
04241   }
04242 
04243   /* now paint the selection */
04244   //Nb.  No longer necessary to paint choose selection here as the cell reference highlight
04245   //stuff takes care of this anyway
04246 
04247   paintHighlightedRanges(painter, unzoomedRect);
04248   paintNormalMarker(painter, unzoomedRect);
04249 
04250   //restore clip region with children area
04251   painter.restore();
04252   //painter.setClipRegion( rgnComplete );
04253 }
04254 
04255 
04256 
04257 void Canvas::clipoutChildren( QPainter& painter ) const
04258 {
04259   QRegion rgn = painter.clipRegion();
04260   if ( rgn.isEmpty() )
04261     rgn = QRegion( QRect( 0, 0, width(), height() ) );
04262 
04263   const double horizontalOffset = -xOffset() * doc()->zoomedResolutionX();
04264   const double verticalOffset = -yOffset() * doc()->zoomedResolutionY();
04265 
04266   QPtrListIterator<EmbeddedObject> itObject( doc()->embeddedObjects() );
04267   for( ; itObject.current(); ++itObject )
04268   {
04269     if ( ( itObject.current() )->sheet() == activeSheet() )
04270     {
04271     QRect childGeometry = doc()->zoomRect( itObject.current()->geometry());
04272 
04273     //The clipping region is given in device coordinates
04274     //so subtract the current offset (scroll position) of the canvas
04275     childGeometry.moveBy( (int)horizontalOffset , (int)verticalOffset );
04276 
04277     if (painter.window().intersects(childGeometry))
04278         rgn -= childGeometry;
04279 
04280       //painter.fillRect( doc()->zoomRect( itObject.current()->geometry() ), QColor("red" ) );
04281     }
04282   }
04283 
04284   painter.setClipRegion( rgn );
04285 }
04286 
04287 QRect Canvas::painterWindowGeometry( const QPainter& painter ) const
04288 {
04289   QRect zoomedWindowGeometry = painter.window();
04290 
04291   zoomedWindowGeometry.moveBy( (int)( xOffset() * doc()->zoomedResolutionX() ) , (int)( yOffset() * doc()->zoomedResolutionY() ) );
04292 
04293     return zoomedWindowGeometry;
04294 }
04295 
04296 void Canvas::paintChildren( QPainter& painter, QWMatrix& /*matrix*/ )
04297 {
04298   QPtrListIterator<EmbeddedObject> itObject( doc()->embeddedObjects() );
04299   itObject.toFirst();
04300   if ( !itObject.current() )
04301     return;
04302 
04303   painter.save();
04304   painter.translate( -xOffset() * doc()->zoomedResolutionX() , -yOffset() * doc()->zoomedResolutionY() );
04305 
04306   const QRect zoomedWindowGeometry = painterWindowGeometry( painter );
04307   const Sheet* sheet = activeSheet();
04308 
04309   for( ; itObject.current(); ++itObject )
04310   {
04311     QRect const zoomedObjectGeometry = doc()->zoomRect( itObject.current()->geometry() );
04312     if ( ( itObject.current() )->sheet() == activeSheet() &&
04313            zoomedWindowGeometry.intersects( zoomedObjectGeometry ) )
04314     {
04315         //To prevent unnecessary redrawing of the embedded object, we only repaint
04316         //if one or more of the cells underneath the object has been marked as 'dirty'.
04317 
04318        QRect canvasRelativeGeometry = zoomedObjectGeometry;
04319        canvasRelativeGeometry.moveBy( (int)( -xOffset()*doc()->zoomedResolutionX() ) ,
04320                         (int)( -yOffset() * doc()->zoomedResolutionY()) );
04321 
04322        const QRect cellsUnderObject=cellsInArea( canvasRelativeGeometry );
04323        bool redraw=false;
04324 
04325        for (int x=cellsUnderObject.left();x<=cellsUnderObject.right();x++)
04326        {
04327         for (int y=cellsUnderObject.top();y<=cellsUnderObject.bottom();y++)
04328                 if ( sheet->cellIsPaintDirty( QPoint(x,y) ) )
04329             {
04330                 redraw=true;
04331                 break;
04332             }
04333         if (redraw)
04334             break;
04335        }
04336 
04337           if ( redraw )
04338             itObject.current()->draw( &painter );
04339     }
04340   }
04341   painter.restore();
04342 }
04343 
04344 void Canvas::paintHighlightedRanges(QPainter& painter, const KoRect& /*viewRect*/)
04345 {
04346   QValueList<QColor> colors = choice()->colors();
04347   QBrush nullBrush;
04348   int index = 0;
04349   Region::ConstIterator end(choice()->constEnd());
04350   for (Region::ConstIterator it = choice()->constBegin(); it != end; ++it)
04351   {
04352     //Only paint ranges or cells on the current sheet
04353     if ((*it)->sheet() != activeSheet())
04354     {
04355       index++;
04356       continue;
04357     }
04358 
04359     QRect region = (*it)->rect().normalize();
04360 
04361         //double positions[4];
04362         //bool paintSides[4];
04363         KoRect unzoomedRect;
04364 
04365         sheetAreaToVisibleRect(region,unzoomedRect);
04366         //Convert region from sheet coordinates to canvas coordinates for use with the painter
04367         //retrieveMarkerInfo(region,viewRect,positions,paintSides);
04368 
04369     QPen highlightPen( colors[(index) % colors.size()] ); // (*it)->color() );
04370         painter.setPen(highlightPen);
04371 
04372         //Adjust the canvas coordinate - rect to take account of zoom level
04373 
04374         QRect zoomedRect;
04375 
04376         zoomedRect.setCoords (  d->view->doc()->zoomItX(unzoomedRect.left()),
04377                     d->view->doc()->zoomItY(unzoomedRect.top()),
04378                     d->view->doc()->zoomItX(unzoomedRect.right()),
04379                     d->view->doc()->zoomItY(unzoomedRect.bottom()) );
04380 
04381         //Now adjust the highlight rectangle is slightly inside the cell borders (this means that multiple highlighted cells
04382         //look nicer together as the borders do not clash)
04383 
04384         zoomedRect.setLeft(zoomedRect.left()+1);
04385         zoomedRect.setTop(zoomedRect.top()+1);
04386         zoomedRect.setRight(zoomedRect.right()-1);
04387         zoomedRect.setBottom(zoomedRect.bottom()-1);
04388 
04389         painter.setBrush(nullBrush);
04390         painter.drawRect(zoomedRect);
04391 
04392         //Now draw the size grip (the little rectangle on the bottom right-hand corner of the range which the user can
04393         //click and drag to resize the region)
04394 
04395 
04396     QBrush sizeGripBrush( colors[(index) % colors.size()] ); // (*it)->color());
04397         QPen   sizeGripPen(Qt::white);
04398 
04399         painter.setPen(sizeGripPen);
04400         painter.setBrush(sizeGripBrush);
04401 
04402         painter.drawRect(zoomedRect.right()-3,zoomedRect.bottom()-3,6,6);
04403     index++;
04404   }
04405 }
04406 
04407 void Canvas::paintNormalMarker(QPainter& painter, const KoRect &viewRect)
04408 {
04409   //Only the active element (the one with the anchor) will be drawn with a border
04410 
04411   if( d->chooseCell )
04412     return;
04413 
04414   if (d->cellEditor)
04415     return;
04416 
04417     if (!selectionInfo()->activeElement())
04418             return;
04419 
04420     QRect range=selectionInfo()->activeElement()->rect().normalize();
04421 
04422     double positions[4];
04423     bool paintSides[4];
04424 
04425     bool current = QRect(selectionInfo()->anchor(), selectionInfo()->marker()).normalize() == range;
04426     QPen pen( Qt::black, 2 );
04427     painter.setPen( pen );
04428 
04429     retrieveMarkerInfo( selectionInfo()->extendToMergedAreas(range), viewRect, positions, paintSides );
04430 
04431     double left =   positions[0];
04432     double top =    positions[1];
04433     double right =  positions[2];
04434     double bottom = positions[3];
04435 
04436     bool paintLeft =   paintSides[0];
04437     bool paintTop =    paintSides[1];
04438     bool paintRight =  paintSides[2];
04439     bool paintBottom = paintSides[3];
04440 
04441     /* the extra '-1's thrown in here account for the thickness of the pen.
04442       want to look like this:                     not this:
04443                               * * * * * *                     * * * *
04444                               *         *                   *         *
04445                               *         *                   *         *
04446     */
04447     int l = 1;
04448 
04449     if ( paintTop )
04450     {
04451       painter.drawLine( d->view->doc()->zoomItX( left ) - l,      d->view->doc()->zoomItY( top ),
04452                         d->view->doc()->zoomItX( right ) + l, d->view->doc()->zoomItY( top ) );
04453     }
04454     if ( activeSheet()->layoutDirection()==Sheet::RightToLeft )
04455     {
04456       if ( paintRight )
04457       {
04458         painter.drawLine( d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( top ),
04459                           d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( bottom ) );
04460       }
04461       if ( paintLeft && paintBottom && current )
04462       {
04463         /* then the 'handle' in the bottom left corner is visible. */
04464         painter.drawLine( d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( top ),
04465                           d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( bottom ) - 3 );
04466         painter.drawLine( d->view->doc()->zoomItX( left ) + 4,  d->view->doc()->zoomItY( bottom ),
04467                           d->view->doc()->zoomItX( right ) + l + 1, d->view->doc()->zoomItY( bottom ) );
04468         painter.fillRect( d->view->doc()->zoomItX( left ) - 2, d->view->doc()->zoomItY( bottom ) -2, 5, 5,
04469                           painter.pen().color() );
04470       }
04471       else
04472       {
04473         if ( paintLeft )
04474         {
04475           painter.drawLine( d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( top ),
04476                             d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( bottom ) );
04477         }
04478         if ( paintBottom )
04479         {
04480           painter.drawLine( d->view->doc()->zoomItX( left ) - l,  d->view->doc()->zoomItY( bottom ),
04481                             d->view->doc()->zoomItX( right ) + l + 1, d->view->doc()->zoomItY( bottom ));
04482         }
04483       }
04484     }
04485     else // activeSheet()->layoutDirection()==Sheet::LeftToRight
04486     {
04487       if ( paintLeft )
04488       {
04489         painter.drawLine( d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( top ),
04490                           d->view->doc()->zoomItX( left ), d->view->doc()->zoomItY( bottom ) );
04491       }
04492       if ( paintRight && paintBottom && current )
04493       {
04494         /* then the 'handle' in the bottom right corner is visible. */
04495         painter.drawLine( d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( top ),
04496                           d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( bottom ) - 3 );
04497         painter.drawLine( d->view->doc()->zoomItX( left ) - l,  d->view->doc()->zoomItY( bottom ),
04498                           d->view->doc()->zoomItX( right ) - 3, d->view->doc()->zoomItY( bottom ) );
04499         painter.fillRect( d->view->doc()->zoomItX( right ) - 2, d->view->doc()->zoomItY( bottom ) - 2, 5, 5,
04500                           painter.pen().color() );
04501       }
04502       else
04503       {
04504         if ( paintRight )
04505         {
04506           painter.drawLine( d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( top ),
04507                             d->view->doc()->zoomItX( right ), d->view->doc()->zoomItY( bottom ) );
04508         }
04509         if ( paintBottom )
04510         {
04511           painter.drawLine( d->view->doc()->zoomItX( left ) - l,  d->view->doc()->zoomItY( bottom ),
04512                             d->view->doc()->zoomItX( right ) + l + 1, d->view->doc()->zoomItY( bottom ) );
04513         }
04514       }
04515     }
04516 }
04517 
04518 void Canvas::sheetAreaToRect(const QRect& sheetArea, KoRect& rect)
04519 {
04520     Sheet* sheet=activeSheet();
04521 
04522     if ( sheet->layoutDirection()==Sheet::RightToLeft )
04523     {
04524         rect.setLeft(sheet->dblColumnPos( sheetArea.right()+1 ) );
04525         rect.setRight(sheet->dblColumnPos( sheetArea.left() ));
04526     }
04527     else
04528     {
04529         rect.setLeft(sheet->dblColumnPos( sheetArea.left() ));
04530         rect.setRight(sheet->dblColumnPos( sheetArea.right()+1 ));
04531     }
04532 
04533     rect.setTop(sheet->dblRowPos(sheetArea.top()));
04534     rect.setBottom(sheet->dblRowPos(sheetArea.bottom()+1));
04535 
04536 }
04537 
04538 void Canvas::sheetAreaToVisibleRect( const QRect& sheetArea,
04539                         KoRect& visibleRect )
04540 {
04541     Sheet* sheet=activeSheet();
04542 
04543     if (!sheet)
04544         return;
04545 
04546     double dwidth=d->view->doc()->unzoomItX(width());
04547     double xpos;
04548     double x;
04549 
04550     if ( sheet->layoutDirection()==Sheet::RightToLeft )
04551     {
04552         xpos = dwidth - sheet->dblColumnPos( sheetArea.right() ) + xOffset();
04553         x    = dwidth - sheet->dblColumnPos( sheetArea.left() ) + xOffset();
04554     }
04555     else
04556     {
04557         xpos = sheet->dblColumnPos( sheetArea.left() ) - xOffset();
04558         x    = sheet->dblColumnPos( sheetArea.right() ) - xOffset();
04559     }
04560 
04561     double ypos = sheet->dblRowPos(sheetArea.top())-yOffset();
04562 
04563     const ColumnFormat *columnFormat = sheet->columnFormat( sheetArea.right() );
04564     double tw = columnFormat->dblWidth( );
04565     double w = x - xpos + tw;
04566 
04567     double y = sheet->dblRowPos( sheetArea.bottom() ) - yOffset();
04568     const RowFormat* rowFormat = sheet->rowFormat( sheetArea.bottom() );
04569     double th = rowFormat->dblHeight( );
04570     double h = ( y - ypos ) + th;
04571 
04572     /* left, top, right, bottom */
04573     if ( sheet->layoutDirection()==Sheet::RightToLeft )
04574     {
04575         visibleRect.setLeft(xpos - tw );
04576         visibleRect.setRight(xpos - tw + w );
04577     }
04578     else
04579     {
04580         visibleRect.setLeft(xpos );
04581         visibleRect.setRight(xpos + w );
04582     }
04583     visibleRect.setTop(ypos);
04584     visibleRect.setBottom(ypos + h);
04585 }
04586 
04587 void Canvas::retrieveMarkerInfo( const QRect &marker,
04588                                         const KoRect &viewRect,
04589                                         double positions[],
04590                                         bool paintSides[] )
04591 {
04592 
04593     Sheet* sheet=activeSheet();
04594 
04595     if (!sheet) return;
04596 
04597     KoRect visibleRect;
04598     sheetAreaToVisibleRect(marker,visibleRect);
04599 
04600 
04601  /* Sheet * sheet = activeSheet();
04602   if ( !sheet )
04603     return;
04604 
04605   double dWidth = d->view->doc()->unzoomItX( width() );
04606 
04607   double xpos;
04608   double x;
04609   if ( sheet->layoutDirection()==Sheet::RightToLeft )
04610   {
04611     xpos = dWidth - sheet->dblColumnPos( marker.right() ) + xOffset();
04612     x    = dWidth - sheet->dblColumnPos( marker.left() ) + xOffset();
04613   }
04614   else
04615   {
04616     xpos = sheet->dblColumnPos( marker.left() ) - xOffset();
04617     x    = sheet->dblColumnPos( marker.right() ) - xOffset();
04618   }
04619   double ypos = sheet->dblRowPos( marker.top() ) - yOffset();
04620 
04621   const ColumnFormat *columnFormat = sheet->columnFormat( marker.right() );
04622   double tw = columnFormat->dblWidth( );
04623   double w = x - xpos + tw;
04624 
04625   double y = sheet->dblRowPos( marker.bottom() ) - yOffset();
04626   const RowFormat* rowFormat = sheet->rowFormat( marker.bottom() );
04627   double th = rowFormat->dblHeight( );
04628   double h = ( y - ypos ) + th;
04629 
04630     //left, top, right, bottom
04631   if ( sheet->layoutDirection()==Sheet::RightToLeft )
04632   {
04633     positions[0] = xpos - tw;
04634     positions[2] = xpos - tw + w;
04635   }
04636   else
04637   {
04638     positions[0] = xpos;
04639     positions[2] = xpos + w;
04640   }
04641   positions[1] = ypos;
04642     positions[3] = ypos + h;*/
04643 
04644   /* these vars are used for clarity, the array for simpler function arguments  */
04645     double left = visibleRect.left();
04646     double top = visibleRect.top();
04647     double right = visibleRect.right();
04648     double bottom = visibleRect.bottom();
04649 
04650   /* left, top, right, bottom */
04651   paintSides[0] = (viewRect.left() <= left) && (left <= viewRect.right()) &&
04652                 (bottom >= viewRect.top()) && (top <= viewRect.bottom());
04653   paintSides[1] = (viewRect.top() <= top) && (top <= viewRect.bottom())
04654                && (right >= viewRect.left()) && (left <= viewRect.right());
04655   if ( sheet->layoutDirection()==Sheet::RightToLeft )
04656     paintSides[2] = (viewRect.left() <= right ) &&
04657                     (right - 1 <= viewRect.right()) &&
04658                     (bottom >= viewRect.top()) && (top <= viewRect.bottom());
04659   else
04660     paintSides[2] = (viewRect.left() <= right ) &&
04661                     (right <= viewRect.right()) &&
04662                     (bottom >= viewRect.top()) && (top <= viewRect.bottom());
04663   paintSides[3] = (viewRect.top() <= bottom) && (bottom <= viewRect.bottom())
04664                && (right >= viewRect.left()) && (left <= viewRect.right());
04665 
04666   positions[0] = QMAX( left,   viewRect.left() );
04667   positions[1] = QMAX( top,    viewRect.top() );
04668   positions[2] = QMIN( right,  viewRect.right() );
04669   positions[3] = QMIN( bottom, viewRect.bottom() );
04670 }
04671 
04672 
04673 /****************************************************************
04674  *
04675  * VBorder
04676  *
04677  ****************************************************************/
04678 
04679 VBorder::VBorder( QWidget *_parent, Canvas *_canvas, View *_view)
04680     : QWidget( _parent, "", /*WNorthWestGravity*/WStaticContents | WResizeNoErase | WRepaintNoErase )
04681 {
04682   m_pView = _view;
04683   m_pCanvas = _canvas;
04684   m_lSize = 0L;
04685 
04686   setBackgroundMode( PaletteButton );
04687   setMouseTracking( true );
04688   m_bResize = false;
04689   m_bSelection = false;
04690   m_iSelectionAnchor=1;
04691   m_bMousePressed = false;
04692 
04693   m_scrollTimer = new QTimer( this );
04694   connect (m_scrollTimer, SIGNAL( timeout() ), this, SLOT( doAutoScroll() ) );
04695 }
04696 
04697 
04698 VBorder::~VBorder()
04699 {
04700     delete m_scrollTimer;
04701 }
04702 
04703 QSize VBorder::sizeHint() const
04704 {
04705   return QSize( 40, 10 );
04706 }
04707 
04708 
04709 void VBorder::mousePressEvent( QMouseEvent * _ev )
04710 {
04711   if ( !m_pView->koDocument()->isReadWrite() )
04712     return;
04713 
04714   if ( _ev->button() == LeftButton )
04715     m_bMousePressed = true;
04716 
04717   const Sheet *sheet = m_pCanvas->activeSheet();
04718   if (!sheet)
04719       return;
04720 
04721   double ev_PosY = m_pCanvas->d->view->doc()->unzoomItY( _ev->pos().y() ) + m_pCanvas->yOffset();
04722   double dHeight = m_pCanvas->d->view->doc()->unzoomItY( height() );
04723   m_bResize = false;
04724   m_bSelection = false;
04725 
04726   // We were editing a cell -> save value and get out of editing mode
04727   if ( m_pCanvas->editor() )
04728   {
04729     m_pCanvas->deleteEditor( true ); // save changes
04730   }
04731 
04732   m_scrollTimer->start( 50 );
04733 
04734   // Find the first visible row and the y position of this row.
04735   double y;
04736   int row = sheet->topRow( m_pCanvas->yOffset(), y );
04737 
04738   // Did the user click between two rows?
04739   while ( y < ( dHeight + m_pCanvas->yOffset() ) && ( !m_bResize ) )
04740   {
04741     double h = sheet->rowFormat( row )->dblHeight();
04742     row++;
04743     if ( row > KS_rowMax )
04744       row = KS_rowMax;
04745     if ( ( ev_PosY >= y + h - 2 ) &&
04746          ( ev_PosY <= y + h + 1 ) &&
04747          !( sheet->rowFormat( row )->isHide() && row == 1 ) )
04748       m_bResize = true;
04749     y += h;
04750   }
04751 
04752   //if row is hide and it's the first row
04753   //you mustn't resize it.
04754   double tmp2;
04755   int tmpRow = sheet->topRow( ev_PosY - 1, tmp2 );
04756   if ( sheet->rowFormat( tmpRow )->isHide() && tmpRow == 1 )
04757       m_bResize = false;
04758 
04759   // So he clicked between two rows ?
04760   if ( m_bResize )
04761   {
04762     // Determine row to resize
04763     double tmp;
04764     m_iResizedRow = sheet->topRow( ev_PosY - 1, tmp );
04765     if ( !sheet->isProtected() )
04766       paintSizeIndicator( _ev->pos().y(), true );
04767   }
04768   else
04769   {
04770     m_bSelection = true;
04771 
04772     double tmp;
04773     int hit_row = sheet->topRow( ev_PosY, tmp );
04774     if ( hit_row > KS_rowMax )
04775         return;
04776 
04777     m_iSelectionAnchor = hit_row;
04778 
04779     if ( !m_pView->selectionInfo()->contains( QPoint(1, hit_row) ) ||
04780          !( _ev->button() == RightButton ) ||
04781          !m_pView->selectionInfo()->isRowSelected() )
04782     {
04783       QPoint newMarker( 1, hit_row );
04784       QPoint newAnchor( KS_colMax, hit_row );
04785 #ifdef NONCONTIGUOUSSELECTION
04786       if (_ev->state() == ControlButton)
04787       {
04788         m_pView->selectionInfo()->extend(QRect(newAnchor, newMarker));
04789       }
04790       else
04791 #endif
04792       if (_ev->state() == ShiftButton)
04793       {
04794         m_pView->selectionInfo()->update(newMarker);
04795       }
04796       else
04797       {
04798         m_pView->selectionInfo()->initialize(QRect(newAnchor, newMarker));
04799       }
04800     }
04801 
04802     if ( _ev->button() == RightButton )
04803     {
04804       QPoint p = mapToGlobal( _ev->pos() );
04805       m_pView->popupRowMenu( p );
04806       m_bSelection = false;
04807     }
04808     m_pView->updateEditWidget();
04809   }
04810 }
04811 
04812 void VBorder::mouseReleaseEvent( QMouseEvent * _ev )
04813 {
04814     if ( m_scrollTimer->isActive() )
04815         m_scrollTimer->stop();
04816 
04817     m_bMousePressed = false;
04818 
04819     if ( !m_pView->koDocument()->isReadWrite() )
04820         return;
04821 
04822     Sheet *sheet = m_pCanvas->activeSheet();
04823     if (!sheet)
04824         return;
04825 
04826     double ev_PosY = m_pCanvas->d->view->doc()->unzoomItY( _ev->pos().y() ) + m_pCanvas->yOffset();
04827 
04828     if ( m_bResize )
04829     {
04830         // Remove size indicator painted by paintSizeIndicator
04831         QPainter painter;
04832         painter.begin( m_pCanvas );
04833         painter.setRasterOp( NotROP );
04834         painter.drawLine( 0, m_iResizePos, m_pCanvas->width(), m_iResizePos );
04835         painter.end();
04836 
04837         int start = m_iResizedRow;
04838         int end = m_iResizedRow;
04839         QRect rect;
04840         rect.setCoords( 1, m_iResizedRow, KS_colMax, m_iResizedRow );
04841         if ( m_pView->selectionInfo()->isRowSelected() )
04842         {
04843           if ( m_pView->selectionInfo()->contains( QPoint( 1, m_iResizedRow ) ) )
04844             {
04845                 start = m_pView->selectionInfo()->lastRange().top();
04846                 end = m_pView->selectionInfo()->lastRange().bottom();
04847                 rect = m_pView->selectionInfo()->lastRange();
04848             }
04849         }
04850 
04851         double height = 0.0;
04852         double y = sheet->dblRowPos( m_iResizedRow );
04853         if ( ev_PosY - y <= 0.0 )
04854             height = 0.0;
04855         else
04856             height = ev_PosY - y;
04857 
04858         if ( !sheet->isProtected() )
04859         {
04860           if ( !m_pCanvas->d->view->doc()->undoLocked() )
04861           {
04862             //just resize
04863             if ( height != 0.0 )
04864             {
04865               // TODO Stefan: replace this
04866               UndoResizeColRow *undo = new UndoResizeColRow( m_pCanvas->d->view->doc(), m_pCanvas->activeSheet(), rect );
04867                 m_pCanvas->d->view->doc()->addCommand( undo );
04868             }
04869           }
04870 
04871           for( int i = start; i <= end; i++ )
04872           {
04873             RowFormat *rl = sheet->nonDefaultRowFormat( i );
04874             if ( height != 0.0 )
04875             {
04876               if ( !rl->isHide() )
04877                 rl->setDblHeight( height );
04878             }
04879             else
04880             {
04881               sheet->hideRow(*m_pView->selectionInfo());
04882             }
04883           }
04884 
04885           delete m_lSize;
04886           m_lSize = 0;
04887         }
04888     }
04889     else if ( m_bSelection )
04890     {
04891       QRect rect = m_pView->selectionInfo()->lastRange();
04892 
04893         // TODO: please don't remove. Right now it's useless, but it's for a future feature
04894         // Norbert
04895         bool m_frozen = false;
04896         if ( m_frozen )
04897         {
04898             kdDebug(36001) << "selected: T " << rect.top() << " B " << rect.bottom() << endl;
04899 
04900             int i;
04901             RowFormat * row;
04902             QValueList<int>hiddenRows;
04903 
04904             for ( i = rect.top(); i <= rect.bottom(); ++i )
04905             {
04906                 row = m_pView->activeSheet()->rowFormat( i );
04907                 if ( row->isHide() )
04908                 {
04909                     hiddenRows.append(i);
04910                 }
04911             }
04912 
04913             if ( hiddenRows.count() > 0 )
04914               m_pView->activeSheet()->showRow(*m_pView->selectionInfo());
04915         }
04916     }
04917 
04918     m_bSelection = false;
04919     m_bResize = false;
04920 }
04921 
04922 void VBorder::equalizeRow( double resize )
04923 {
04924   Sheet *sheet = m_pCanvas->activeSheet();
04925   Q_ASSERT( sheet );
04926 
04927   QRect selection( m_pView->selectionInfo()->selection() );
04928   if ( !m_pCanvas->d->view->doc()->undoLocked() )
04929   {
04930      UndoResizeColRow *undo = new UndoResizeColRow( m_pCanvas->d->view->doc(), m_pCanvas->activeSheet(), selection );
04931      m_pCanvas->d->view->doc()->addCommand( undo );
04932   }
04933   RowFormat *rl;
04934   for ( int i = selection.top(); i <= selection.bottom(); i++ )
04935   {
04936      rl = sheet->nonDefaultRowFormat( i );
04937      resize = QMAX( 2.0, resize);
04938      rl->setDblHeight( resize );
04939   }
04940 }
04941 
04942 void VBorder::mouseDoubleClickEvent(QMouseEvent*)
04943 {
04944   Sheet *sheet = m_pCanvas->activeSheet();
04945   if (!sheet)
04946     return;
04947 
04948   if ( !m_pView->koDocument()->isReadWrite() || sheet->isProtected() )
04949     return;
04950 
04951   sheet->adjustRow(*m_pCanvas->selectionInfo());
04952 }
04953 
04954 
04955 void VBorder::mouseMoveEvent( QMouseEvent * _ev )
04956 {
04957   if ( !m_pView->koDocument()->isReadWrite() )
04958     return;
04959 
04960   Sheet *sheet = m_pCanvas->activeSheet();
04961 
04962   if (!sheet)
04963      return;
04964 
04965   double ev_PosY = m_pCanvas->d->view->doc()->unzoomItY( _ev->pos().y() ) + m_pCanvas->yOffset();
04966   double dHeight = m_pCanvas->d->view->doc()->unzoomItY( height() );
04967 
04968   // The button is pressed and we are resizing ?
04969   if ( m_bResize )
04970   {
04971     if ( !sheet->isProtected() )
04972       paintSizeIndicator( _ev->pos().y(), false );
04973   }
04974   // The button is pressed and we are selecting ?
04975   else if ( m_bSelection )
04976   {
04977     double y;
04978     int row = sheet->topRow( ev_PosY, y );
04979     if ( row > KS_rowMax )
04980       return;
04981 
04982     QPoint newAnchor = m_pView->selectionInfo()->anchor();
04983     QPoint newMarker = m_pView->selectionInfo()->marker();
04984     newMarker.setY( row );
04985     newAnchor.setY( m_iSelectionAnchor );
04986     m_pView->selectionInfo()->update(newMarker);
04987 
04988     if ( _ev->pos().y() < 0 )
04989       m_pCanvas->vertScrollBar()->setValue( m_pCanvas->d->view->doc()->zoomItY( ev_PosY ) );
04990     else if ( _ev->pos().y() > m_pCanvas->height() )
04991     {
04992       if ( row < KS_rowMax )
04993       {
04994         RowFormat *rl = sheet->rowFormat( row + 1 );
04995         y = sheet->dblRowPos( row + 1 );
04996         m_pCanvas->vertScrollBar()->setValue ((int) (m_pCanvas->d->view->doc()->zoomItY
04997               (ev_PosY + rl->dblHeight()) - dHeight));
04998       }
04999     }
05000   }
05001   // No button is pressed and the mouse is just moved
05002   else
05003   {
05004 
05005      //What is the internal size of 1 pixel
05006     const double unzoomedPixel = m_pCanvas->d->view->doc()->unzoomItY( 1 );
05007     double y;
05008     int tmpRow = sheet->topRow( m_pCanvas->yOffset(), y );
05009 
05010     while ( y < m_pCanvas->d->view->doc()->unzoomItY( height() ) + m_pCanvas->yOffset() )
05011     {
05012       double h = sheet->rowFormat( tmpRow )->dblHeight();
05013       //if col is hide and it's the first column
05014       //you mustn't resize it.
05015       if ( ev_PosY >= y + h - 2 * unzoomedPixel &&
05016            ev_PosY <= y + h + unzoomedPixel &&
05017            !( sheet->rowFormat( tmpRow )->isHide() && tmpRow == 1 ) )
05018       {
05019         setCursor( splitVCursor );
05020         return;
05021       }
05022       y += h;
05023       tmpRow++;
05024     }
05025     setCursor( arrowCursor );
05026   }
05027 }
05028 
05029 void VBorder::doAutoScroll()
05030 {
05031     if ( !m_bMousePressed )
05032     {
05033         m_scrollTimer->stop();
05034         return;
05035     }
05036 
05037     QPoint pos( mapFromGlobal( QCursor::pos() ) );
05038 
05039     if ( pos.y() < 0 || pos.y() > height() )
05040     {
05041         QMouseEvent * event = new QMouseEvent( QEvent::MouseMove, pos, 0, 0 );
05042         mouseMoveEvent( event );
05043         delete event;
05044     }
05045 
05046     //Restart timer
05047     m_scrollTimer->start( 50 );
05048 }
05049 
05050 void VBorder::wheelEvent( QWheelEvent* _ev )
05051 {
05052   if ( m_pCanvas->vertScrollBar() )
05053     QApplication::sendEvent( m_pCanvas->vertScrollBar(), _ev );
05054 }
05055 
05056 
05057 void VBorder::paintSizeIndicator( int mouseY, bool firstTime )
05058 {
05059     Sheet *sheet = m_pCanvas->activeSheet();
05060     if (!sheet)
05061         return;
05062 
05063     QPainter painter;
05064     painter.begin( m_pCanvas );
05065     painter.setRasterOp( NotROP );
05066 
05067     if ( !firstTime )
05068       painter.drawLine( 0, m_iResizePos, m_pCanvas->width(), m_iResizePos );
05069 
05070     m_iResizePos = mouseY;
05071 
05072     // Dont make the row have a height < 2 pixel.
05073     int y = m_pCanvas->d->view->doc()->zoomItY( sheet->dblRowPos( m_iResizedRow ) - m_pCanvas->yOffset() );
05074     if ( m_iResizePos < y + 2 )
05075         m_iResizePos = y;
05076 
05077     painter.drawLine( 0, m_iResizePos, m_pCanvas->width(), m_iResizePos );
05078 
05079     painter.end();
05080 
05081     QString tmpSize;
05082     if ( m_iResizePos != y )
05083         tmpSize = i18n("Height: %1 %2").arg( KoUnit::toUserValue( m_pCanvas->doc()->unzoomItY( m_iResizePos - y ),
05084                                                                m_pView->doc()->unit() ) )
05085                                        .arg( m_pView->doc()->unitName() );
05086     else
05087         tmpSize = i18n( "Hide Row" );
05088 
05089     painter.begin( this );
05090     int len = painter.fontMetrics().width( tmpSize );
05091     int hei = painter.fontMetrics().height();
05092     painter.end();
05093 
05094     if ( !m_lSize )
05095     {
05096           m_lSize = new QLabel( m_pCanvas );
05097 
05098           if ( sheet->layoutDirection()==Sheet::RightToLeft )
05099             m_lSize->setGeometry( m_pCanvas->width() - len - 5,
05100                                                   y + 3, len + 2, hei + 2 );
05101           else
05102             m_lSize->setGeometry( 3, y + 3, len + 2,hei + 2 );
05103 
05104           m_lSize->setAlignment( Qt::AlignVCenter );
05105           m_lSize->setText( tmpSize );
05106           m_lSize->setPalette( QToolTip::palette() );
05107           m_lSize->show();
05108     }
05109     else
05110     {
05111           if ( sheet->layoutDirection()==Sheet::RightToLeft )
05112             m_lSize->setGeometry( m_pCanvas->width() - len - 5,
05113                                                   y + 3, len + 2, hei + 2 );
05114           else
05115             m_lSize->setGeometry( 3, y + 3, len + 2,hei + 2 );
05116 
05117           m_lSize->setText( tmpSize );
05118     }
05119 }
05120 
05121 void VBorder::updateRows( int from, int to )
05122 {
05123     Sheet *sheet = m_pCanvas->activeSheet();
05124     if ( !sheet )
05125         return;
05126 
05127     int y0 = sheet->rowPos( from, m_pCanvas );
05128     int y1 = sheet->rowPos( to+1, m_pCanvas );
05129     update( 0, y0, width(), y1-y0 );
05130 }
05131 
05132 void VBorder::paintEvent( QPaintEvent* _ev )
05133 {
05134   Sheet *sheet = m_pCanvas->activeSheet();
05135   if ( !sheet )
05136     return;
05137 
05138   QPainter painter( this );
05139   QColor highlightColor = View::highlightColor();
05140   QPen pen( Qt::black, 1 );
05141   painter.setPen( pen );
05142   // painter.setBackgroundColor( colorGroup().base() );
05143 
05144   // painter.eraseRect( _ev->rect() );
05145 
05146   //QFontMetrics fm = painter.fontMetrics();
05147   // Matthias Elter: This causes a SEGFAULT in ~QPainter!
05148   // Only god and the trolls know why ;-)
05149   // bah...took me quite some time to track this one down...
05150 
05151   painter.setClipRect( _ev->rect() );
05152 
05153   double yPos;
05154   //Get the top row and the current y-position
05155   int y = sheet->topRow( (m_pCanvas->d->view->doc()->unzoomItY( _ev->rect().y() ) + m_pCanvas->yOffset()), yPos );
05156   //Align to the offset
05157   yPos = yPos - m_pCanvas->yOffset();
05158   int width = m_pCanvas->d->view->doc()->zoomItX( YBORDER_WIDTH );
05159 
05160   QFont normalFont = painter.font();
05161   if ( m_pCanvas->d->view->doc()->zoom() < 100 )
05162   {
05163     normalFont.setPointSizeFloat( 0.01 * m_pCanvas->d->view->doc()->zoom() *
05164                                   normalFont.pointSizeFloat() );
05165   }
05166   QFont boldFont = normalFont;
05167   boldFont.setBold( true );
05168 
05169   //Loop through the rows, until we are out of range
05170   while ( yPos <= m_pCanvas->d->view->doc()->unzoomItY( _ev->rect().bottom() ) )
05171   {
05172     bool selected = (m_pView->selectionInfo()->isRowSelected(y));
05173     bool highlighted = (!selected && m_pView->selectionInfo()->isRowAffected(y));
05174 
05175     const RowFormat *row_lay = sheet->rowFormat( y );
05176     int zoomedYPos = m_pCanvas->d->view->doc()->zoomItY( yPos );
05177     int height = m_pCanvas->d->view->doc()->zoomItY( yPos + row_lay->dblHeight() ) - zoomedYPos;
05178 
05179     if ( selected )
05180     {
05181       QBrush fillSelected( highlightColor );
05182       qDrawPlainRect ( &painter, 0, zoomedYPos, width, height+1, highlightColor.dark(150),
05183            1, &fillSelected );
05184     }
05185     else if ( highlighted )
05186     {
05187       QBrush fillHighlighted( highlightColor );
05188       qDrawPlainRect ( &painter, 0, zoomedYPos, width, height+1, highlightColor.dark(150),
05189            1, &fillHighlighted );
05190     }
05191     else
05192     {
05193       QColor c = colorGroup().background();
05194       QBrush fill( c );
05195       qDrawPlainRect ( &painter, 0, zoomedYPos, width, height+1, c.dark(150),
05196            1, &fill );
05197     }
05198 
05199     QString rowText = QString::number( y );
05200 
05201     // Reset painter
05202     painter.setFont( normalFont );
05203     painter.setPen( colorGroup().text() );
05204 
05205     if ( selected )
05206       painter.setPen( colorGroup().highlightedText() );
05207     else if ( highlighted )
05208       painter.setFont( boldFont );
05209 
05210     int len = painter.fontMetrics().width( rowText );
05211     if (!row_lay->isHide())
05212         painter.drawText( ( width-len )/2, zoomedYPos +
05213                           ( height + painter.fontMetrics().ascent() -
05214                             painter.fontMetrics().descent() ) / 2, rowText );
05215 
05216     yPos += row_lay->dblHeight();
05217     y++;
05218   }
05219 }
05220 
05221 
05222 void VBorder::focusOutEvent( QFocusEvent* )
05223 {
05224     if ( m_scrollTimer->isActive() )
05225         m_scrollTimer->stop();
05226     m_bMousePressed = false;
05227 }
05228 
05229 
05230 /****************************************************************
05231  *
05232  * HBorder
05233  *
05234  ****************************************************************/
05235 
05236 HBorder::HBorder( QWidget *_parent, Canvas *_canvas,View *_view )
05237     : QWidget( _parent, "", /*WNorthWestGravity*/ WStaticContents| WResizeNoErase | WRepaintNoErase )
05238 {
05239   m_pView = _view;
05240   m_pCanvas = _canvas;
05241   m_lSize = 0L;
05242   setBackgroundMode( PaletteButton );
05243   setMouseTracking( true );
05244   m_bResize = false;
05245   m_bSelection = false;
05246   m_iSelectionAnchor=1;
05247   m_bMousePressed = false;
05248 
05249   m_scrollTimer = new QTimer( this );
05250   connect( m_scrollTimer, SIGNAL( timeout() ), this, SLOT( doAutoScroll() ) );
05251 }
05252 
05253 
05254 HBorder::~HBorder()
05255 {
05256     delete m_scrollTimer;
05257 }
05258 
05259 QSize HBorder::sizeHint() const
05260 {
05261   return QSize( 40, 10 );
05262 }
05263 
05264 void HBorder::mousePressEvent( QMouseEvent * _ev )
05265 {
05266   if (!m_pView->koDocument()->isReadWrite())
05267     return;
05268 
05269   if ( _ev->button() == LeftButton )
05270     m_bMousePressed = true;
05271 
05272   const Sheet *sheet = m_pCanvas->activeSheet();
05273   if (!sheet)
05274     return;
05275 
05276   // We were editing a cell -> save value and get out of editing mode
05277   if ( m_pCanvas->editor() )
05278   {
05279       m_pCanvas->deleteEditor( true ); // save changes
05280   }
05281 
05282   m_scrollTimer->start( 50 );
05283 
05284   double ev_PosX;
05285   double dWidth = m_pCanvas->d->view->doc()->unzoomItX( width() );
05286   if ( sheet->layoutDirection()==Sheet::RightToLeft )
05287     ev_PosX = dWidth - m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
05288   else
05289     ev_PosX = m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
05290   m_bResize = false;
05291   m_bSelection = false;
05292 
05293   // Find the first visible column and the x position of this column.
05294   double x;
05295 
05296   const double unzoomedPixel = m_pCanvas->d->view->doc()->unzoomItX( 1 );
05297   if ( sheet->layoutDirection()==Sheet::RightToLeft )
05298   {
05299     int tmpCol = sheet->leftColumn( m_pCanvas->xOffset(), x );
05300 
05301     kdDebug() << "evPos: " << ev_PosX << ", x: " << x << ", COL: " << tmpCol << endl;
05302     while ( ev_PosX > x && ( !m_bResize ) )
05303     {
05304       double w = sheet->columnFormat( tmpCol )->dblWidth();
05305 
05306       kdDebug() << "evPos: " << ev_PosX << ", x: " << x << ", w: " << w << ", COL: " << tmpCol << endl;
05307 
05308       ++tmpCol;
05309       if ( tmpCol > KS_colMax )
05310         tmpCol = KS_colMax;
05311       //if col is hide and it's the first column
05312       //you mustn't resize it.
05313 
05314       if ( ev_PosX >= x + w - unzoomedPixel &&
05315            ev_PosX <= x + w + unzoomedPixel &&
05316            !( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 1 ) )
05317       {
05318         m_bResize = true;
05319       }
05320       x += w;
05321     }
05322 
05323     //if col is hide and it's the first column
05324     //you mustn't resize it.
05325     double tmp2;
05326     tmpCol = sheet->leftColumn( dWidth - ev_PosX + 1, tmp2 );
05327     if ( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 0 )
05328     {
05329       kdDebug() << "No resize: " << tmpCol << ", " << sheet->columnFormat( tmpCol )->isHide() << endl;
05330       m_bResize = false;
05331     }
05332 
05333     kdDebug() << "Resize: " << m_bResize << endl;
05334   }
05335   else
05336   {
05337     int col = sheet->leftColumn( m_pCanvas->xOffset(), x );
05338 
05339     // Did the user click between two columns?
05340     while ( x < ( dWidth + m_pCanvas->xOffset() ) && ( !m_bResize ) )
05341     {
05342       double w = sheet->columnFormat( col )->dblWidth();
05343       col++;
05344       if ( col > KS_colMax )
05345         col = KS_colMax;
05346       if ( ( ev_PosX >= x + w - unzoomedPixel ) &&
05347          ( ev_PosX <= x + w + unzoomedPixel ) &&
05348            !( sheet->columnFormat( col )->isHide() && col == 1 ) )
05349         m_bResize = true;
05350       x += w;
05351     }
05352 
05353     //if col is hide and it's the first column
05354     //you mustn't resize it.
05355     double tmp2;
05356     int tmpCol = sheet->leftColumn( ev_PosX - 1, tmp2 );
05357     if ( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 1 )
05358       m_bResize = false;
05359   }
05360 
05361   // So he clicked between two rows ?
05362   if ( m_bResize )
05363   {
05364     // Determine the column to resize
05365     double tmp;
05366     if ( sheet->layoutDirection()==Sheet::RightToLeft )
05367     {
05368       m_iResizedColumn = sheet->leftColumn( ev_PosX - 1, tmp );
05369       // kdDebug() << "RColumn: " << m_iResizedColumn << ", PosX: " << ev_PosX << endl;
05370 
05371       if ( !sheet->isProtected() )
05372         paintSizeIndicator( _ev->pos().x(), true );
05373     }
05374     else
05375     {
05376       m_iResizedColumn = sheet->leftColumn( ev_PosX - 1, tmp );
05377 
05378       if ( !sheet->isProtected() )
05379         paintSizeIndicator( _ev->pos().x(), true );
05380     }
05381 
05382     // kdDebug() << "Column: " << m_iResizedColumn << endl;
05383   }
05384   else
05385   {
05386     m_bSelection = true;
05387 
05388     double tmp;
05389     int hit_col = sheet->leftColumn( ev_PosX, tmp );
05390     if ( hit_col > KS_colMax )
05391         return;
05392 
05393     m_iSelectionAnchor = hit_col;
05394 
05395     if ( !m_pView->selectionInfo()->contains( QPoint( hit_col, 1 ) ) ||
05396          !( _ev->button() == RightButton ) ||
05397          !m_pView->selectionInfo()->isColumnSelected() )
05398     {
05399       QPoint newMarker( hit_col, 1 );
05400       QPoint newAnchor( hit_col, KS_rowMax );
05401 #ifdef NONCONTIGUOUSSELECTION
05402       if (_ev->state() == ControlButton)
05403       {
05404         m_pView->selectionInfo()->extend(QRect(newAnchor, newMarker));
05405       }
05406       else
05407 #endif
05408       if (_ev->state() == ShiftButton)
05409       {
05410         m_pView->selectionInfo()->update(newMarker);
05411       }
05412       else
05413       {
05414         m_pView->selectionInfo()->initialize(QRect(newAnchor, newMarker));
05415       }
05416     }
05417 
05418     if ( _ev->button() == RightButton )
05419     {
05420       QPoint p = mapToGlobal( _ev->pos() );
05421       m_pView->popupColumnMenu( p );
05422       m_bSelection = false;
05423     }
05424     m_pView->updateEditWidget();
05425   }
05426 }
05427 
05428 void HBorder::mouseReleaseEvent( QMouseEvent * _ev )
05429 {
05430     if ( m_scrollTimer->isActive() )
05431         m_scrollTimer->stop();
05432 
05433     m_bMousePressed = false;
05434 
05435     if ( !m_pView->koDocument()->isReadWrite() )
05436       return;
05437 
05438     Sheet * sheet = m_pCanvas->activeSheet();
05439     if (!sheet)
05440         return;
05441 
05442     if ( m_bResize )
05443     {
05444         double dWidth = m_pCanvas->d->view->doc()->unzoomItX( width() );
05445         double ev_PosX;
05446 
05447         // Remove size indicator painted by paintSizeIndicator
05448         QPainter painter;
05449         painter.begin( m_pCanvas );
05450         painter.setRasterOp( NotROP );
05451         painter.drawLine( m_iResizePos, 0, m_iResizePos, m_pCanvas->height() );
05452         painter.end();
05453 
05454         int start = m_iResizedColumn;
05455         int end   = m_iResizedColumn;
05456         QRect rect;
05457         rect.setCoords( m_iResizedColumn, 1, m_iResizedColumn, KS_rowMax );
05458         if ( m_pView->selectionInfo()->isColumnSelected() )
05459         {
05460             if ( m_pView->selectionInfo()->contains( QPoint( m_iResizedColumn, 1 ) ) )
05461             {
05462                 start = m_pView->selectionInfo()->lastRange().left();
05463                 end   = m_pView->selectionInfo()->lastRange().right();
05464                 rect  = m_pView->selectionInfo()->lastRange();
05465             }
05466         }
05467 
05468         double width = 0.0;
05469         double x;
05470 
05471         if ( sheet->layoutDirection()==Sheet::RightToLeft )
05472           ev_PosX = dWidth - m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
05473         else
05474           ev_PosX = m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
05475 
05476         x = sheet->dblColumnPos( m_iResizedColumn );
05477 
05478         if ( ev_PosX - x <= 0.0 )
05479           width = 0.0;
05480         else
05481           width = ev_PosX - x;
05482 
05483         if ( !sheet->isProtected() )
05484         {
05485           if ( !m_pCanvas->d->view->doc()->undoLocked() )
05486           {
05487             //just resize
05488             if ( width != 0.0 )
05489             {
05490               // TODO Stefan: replace this
05491                 UndoResizeColRow *undo = new UndoResizeColRow( m_pCanvas->d->view->doc(), m_pCanvas->activeSheet(), rect );
05492                 m_pCanvas->d->view->doc()->addCommand( undo );
05493             }
05494           }
05495 
05496           for( int i = start; i <= end; i++ )
05497           {
05498             ColumnFormat *cl = sheet->nonDefaultColumnFormat( i );
05499             if ( width != 0.0 )
05500             {
05501                 if ( !cl->isHide() )
05502                     cl->setDblWidth( width );
05503             }
05504             else
05505             {
05506               sheet->hideColumn(*m_pView->selectionInfo());
05507             }
05508           }
05509 
05510           delete m_lSize;
05511           m_lSize = 0;
05512         }
05513     }
05514     else if ( m_bSelection )
05515     {
05516         QRect rect = m_pView->selectionInfo()->lastRange();
05517 
05518         // TODO: please don't remove. Right now it's useless, but it's for a future feature
05519         // Norbert
05520         bool m_frozen = false;
05521         if ( m_frozen )
05522         {
05523             kdDebug(36001) << "selected: L " << rect.left() << " R " << rect.right() << endl;
05524 
05525             int i;
05526             ColumnFormat * col;
05527             QValueList<int>hiddenCols;
05528 
05529             for ( i = rect.left(); i <= rect.right(); ++i )
05530             {
05531                 col = m_pView->activeSheet()->columnFormat( i );
05532                 if ( col->isHide() )
05533                 {
05534                     hiddenCols.append(i);
05535                 }
05536             }
05537 
05538             if ( hiddenCols.count() > 0 )
05539               m_pView->activeSheet()->showColumn(*m_pView->selectionInfo());
05540         }
05541     }
05542 
05543     m_bSelection = false;
05544     m_bResize = false;
05545 }
05546 
05547 void HBorder::equalizeColumn( double resize )
05548 {
05549   Sheet *sheet = m_pCanvas->activeSheet();
05550   Q_ASSERT( sheet );
05551 
05552   QRect selection( m_pView->selectionInfo()->selection() );
05553   if ( !m_pCanvas->d->view->doc()->undoLocked() )
05554   {
05555       UndoResizeColRow *undo = new UndoResizeColRow( m_pCanvas->d->view->doc(), m_pCanvas->activeSheet(), selection );
05556       m_pCanvas->d->view->doc()->addCommand( undo );
05557   }
05558   ColumnFormat *cl;
05559   for ( int i = selection.left(); i <= selection.right(); i++ )
05560   {
05561       cl = sheet->nonDefaultColumnFormat( i );
05562       resize = QMAX( 2.0, resize );
05563       cl->setDblWidth( resize );
05564   }
05565 
05566 }
05567 
05568 void HBorder::mouseDoubleClickEvent(QMouseEvent*)
05569 {
05570   Sheet *sheet = m_pCanvas->activeSheet();
05571   if (!sheet)
05572     return;
05573 
05574   if ( !m_pView->koDocument()->isReadWrite() || sheet->isProtected() )
05575     return;
05576 
05577   sheet->adjustColumn(*m_pCanvas->selectionInfo());
05578 }
05579 
05580 void HBorder::mouseMoveEvent( QMouseEvent * _ev )
05581 {
05582   if ( !m_pView->koDocument()->isReadWrite() )
05583     return;
05584 
05585   Sheet *sheet = m_pCanvas->activeSheet();
05586 
05587   if (!sheet)
05588     return;
05589 
05590   double dWidth = m_pCanvas->d->view->doc()->unzoomItX( width() );
05591   double ev_PosX;
05592   if ( sheet->layoutDirection()==Sheet::RightToLeft )
05593     ev_PosX = dWidth - m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
05594   else
05595     ev_PosX = m_pCanvas->d->view->doc()->unzoomItX( _ev->pos().x() ) + m_pCanvas->xOffset();
05596 
05597   // The button is pressed and we are resizing ?
05598   if ( m_bResize )
05599   {
05600     if ( !sheet->isProtected() )
05601         paintSizeIndicator( _ev->pos().x(), false );
05602   }
05603   // The button is pressed and we are selecting ?
05604   else if ( m_bSelection )
05605   {
05606     double x;
05607     int col = sheet->leftColumn( ev_PosX, x );
05608 
05609     if ( col > KS_colMax )
05610       return;
05611 
05612     QPoint newMarker = m_pView->selectionInfo()->marker();
05613     QPoint newAnchor = m_pView->selectionInfo()->anchor();
05614     newMarker.setX( col );
05615     newAnchor.setX( m_iSelectionAnchor );
05616     m_pView->selectionInfo()->update(newMarker);
05617 
05618     if ( sheet->layoutDirection()==Sheet::RightToLeft )
05619     {
05620       if ( _ev->pos().x() < width() - m_pCanvas->width() )
05621       {
05622         ColumnFormat *cl = sheet->columnFormat( col + 1 );
05623         x = sheet->dblColumnPos( col + 1 );
05624         m_pCanvas->horzScrollBar()->setValue ( m_pCanvas->horzScrollBar()->maxValue() - (int)
05625             (m_pCanvas->d->view->doc()->zoomItX (ev_PosX + cl->dblWidth()) - m_pCanvas->d->view->doc()->unzoomItX( m_pCanvas->width() )));
05626       }
05627       else if ( _ev->pos().x() > width() )
05628         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() ) ) );
05629     }
05630     else
05631     {
05632       if ( _ev->pos().x() < 0 )
05633         m_pCanvas->horzScrollBar()->setValue( m_pCanvas->d->view->doc()->zoomItX( ev_PosX ) );
05634       else if ( _ev->pos().x() > m_pCanvas->width() )
05635       {
05636         if ( col < KS_colMax )
05637         {
05638           ColumnFormat *cl = sheet->columnFormat( col + 1 );
05639           x = sheet->dblColumnPos( col + 1 );
05640           m_pCanvas->horzScrollBar()->setValue ((int)
05641               (m_pCanvas->d->view->doc()->zoomItX (ev_PosX + cl->dblWidth()) - dWidth));
05642         }
05643       }
05644     }
05645 
05646   }
05647   // No button is pressed and the mouse is just moved
05648   else
05649   {
05650      //What is the internal size of 1 pixel
05651     const double unzoomedPixel = m_pCanvas->d->view->doc()->unzoomItX( 1 );
05652     double x;
05653 
05654     if ( sheet->layoutDirection()==Sheet::RightToLeft )
05655     {
05656       int tmpCol = sheet->leftColumn( m_pCanvas->xOffset(), x );
05657 
05658       while ( ev_PosX > x )
05659       {
05660         double w = sheet->columnFormat( tmpCol )->dblWidth();
05661         ++tmpCol;
05662 
05663         //if col is hide and it's the first column
05664         //you mustn't resize it.
05665         if ( ev_PosX >= x + w - unzoomedPixel &&
05666              ev_PosX <= x + w + unzoomedPixel &&
05667              !( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 0 ) )
05668         {
05669           setCursor( splitHCursor );
05670           return;
05671         }
05672         x += w;
05673       }
05674       setCursor( arrowCursor );
05675     }
05676     else
05677     {
05678       int tmpCol = sheet->leftColumn( m_pCanvas->xOffset(), x );
05679 
05680       while ( x < m_pCanvas->d->view->doc()->unzoomItY( width() ) + m_pCanvas->xOffset() )
05681       {
05682         double w = sheet->columnFormat( tmpCol )->dblWidth();
05683         //if col is hide and it's the first column
05684         //you mustn't resize it.
05685         if ( ev_PosX >= x + w - unzoomedPixel &&
05686              ev_PosX <= x + w + unzoomedPixel &&
05687              !( sheet->columnFormat( tmpCol )->isHide() && tmpCol == 1 ) )
05688         {
05689           setCursor( splitHCursor );
05690           return;
05691         }
05692         x += w;
05693         tmpCol++;
05694       }
05695       setCursor( arrowCursor );
05696     }
05697   }
05698 }
05699 
05700 void HBorder::doAutoScroll()
05701 {
05702     if ( !m_bMousePressed )
05703     {
05704         m_scrollTimer->stop();
05705         return;
05706     }
05707 
05708     QPoint pos( mapFromGlobal( QCursor::pos() ) );
05709 
05710     if ( pos.x() < 0 || pos.x() > width() )
05711     {
05712         QMouseEvent * event = new QMouseEvent( QEvent::MouseMove, pos, 0, 0 );
05713         mouseMoveEvent( event );
05714         delete event;
05715     }
05716 
05717     //Restart timer
05718     m_scrollTimer->start( 50 );
05719 }
05720 
05721 void HBorder::wheelEvent( QWheelEvent* _ev )
05722 {
05723   if ( m_pCanvas->horzScrollBar() )
05724     QApplication::sendEvent( m_pCanvas->horzScrollBar(), _ev );
05725 }
05726 
05727 void HBorder::resizeEvent( QResizeEvent* _ev )
05728 {
05729   // workaround to allow horizontal resizing and zoom changing when sheet
05730   // direction and interface direction don't match (e.g. an RTL sheet on an
05731   // LTR interface)
05732   if ( m_pCanvas->activeSheet() && m_pCanvas->activeSheet()->layoutDirection()==Sheet::RightToLeft && !QApplication::reverseLayout() )
05733   {
05734     int dx = _ev->size().width() - _ev->oldSize().width();
05735     scroll(dx, 0);
05736   }
05737   else if ( m_pCanvas->activeSheet() && m_pCanvas->activeSheet()->layoutDirection()==Sheet::LeftToRight && QApplication::reverseLayout() )
05738   {
05739     int dx = _ev->size().width() - _ev->oldSize().width();
05740     scroll(-dx, 0);
05741   }
05742 }
05743 
05744 void HBorder::paintSizeIndicator( int mouseX, bool firstTime )
05745 {
05746     Sheet *sheet = m_pCanvas->activeSheet();
05747     if (!sheet)
05748         return;
05749 
05750     QPainter painter;
05751     painter.begin( m_pCanvas );
05752     painter.setRasterOp( NotROP );
05753 
05754     if ( !firstTime )
05755       painter.drawLine( m_iResizePos, 0, m_iResizePos, m_pCanvas->height() );
05756 
05757     if ( sheet->layoutDirection()==Sheet::RightToLeft )
05758       m_iResizePos = mouseX + m_pCanvas->width() - width();
05759     else
05760       m_iResizePos = mouseX;
05761 
05762     // Dont make the column have a width < 2 pixels.
05763     int x = m_pCanvas->d->view->doc()->zoomItX( sheet->dblColumnPos( m_iResizedColumn ) - m_pCanvas->xOffset() );
05764 
05765     if ( sheet->layoutDirection()==Sheet::RightToLeft )
05766     {
05767       x = m_pCanvas->width() - x;
05768 
05769       if ( m_iResizePos > x - 2 )
05770           m_iResizePos = x;
05771     }
05772     else
05773     {
05774       if ( m_iResizePos < x + 2 )
05775           m_iResizePos = x;
05776     }
05777 
05778     painter.drawLine( m_iResizePos, 0, m_iResizePos, m_pCanvas->height() );
05779 
05780     painter.end();
05781 
05782     QString tmpSize;
05783     if ( m_iResizePos != x )
05784         tmpSize = i18n("Width: %1 %2")
05785                   .arg( KGlobal::locale()->formatNumber( KoUnit::toUserValue( m_pCanvas->doc()->unzoomItX( (sheet->layoutDirection()==Sheet::RightToLeft) ? x - m_iResizePos : m_iResizePos - x ),
05786                                                                            m_pView->doc()->unit() )))
05787                   .arg( m_pView->doc()->unitName() );
05788     else
05789         tmpSize = i18n( "Hide Column" );
05790 
05791     painter.begin( this );
05792     int len = painter.fontMetrics().width( tmpSize );
05793     int hei = painter.fontMetrics().height();
05794     painter.end();
05795 
05796     if ( !m_lSize )
05797     {
05798         m_lSize = new QLabel( m_pCanvas );
05799 
05800         if ( sheet->layoutDirection()==Sheet::RightToLeft )
05801           m_lSize->setGeometry( x - len - 5, 3, len + 2, hei + 2 );
05802         else
05803           m_lSize->setGeometry( x + 3, 3, len + 2, hei + 2 );
05804 
05805         m_lSize->setAlignment( Qt::AlignVCenter );
05806         m_lSize->setText( tmpSize );
05807         m_lSize->setPalette( QToolTip::palette() );
05808         m_lSize->show();
05809     }
05810     else
05811     {
05812         if ( sheet->layoutDirection()==Sheet::RightToLeft )
05813           m_lSize->setGeometry( x - len - 5, 3, len + 2, hei + 2 );
05814         else
05815           m_lSize->setGeometry( x + 3, 3, len + 2, hei + 2 );
05816 
05817         m_lSize->setText( tmpSize );
05818     }
05819 }
05820 
05821 void HBorder::updateColumns( int from, int to )
05822 {
05823     Sheet *sheet = m_pCanvas->activeSheet();
05824     if ( !sheet )
05825         return;
05826 
05827     int x0 = sheet->columnPos( from, m_pCanvas );
05828     int x1 = sheet->columnPos( to+1, m_pCanvas );
05829     update( x0, 0, x1-x0, height() );
05830 }
05831 
05832 void HBorder::paintEvent( QPaintEvent* _ev )
05833 {
05834   Sheet * sheet = m_pCanvas->activeSheet();
05835   if ( !sheet )
05836     return;
05837 
05838   QColor   highlightColor = View::highlightColor();
05839   QPainter painter( this );
05840   QPen pen( Qt::black, 1 );
05841   painter.setPen( pen );
05842   painter.setBackgroundColor( white );
05843 
05844   painter.setClipRect( _ev->rect() );
05845 
05846   // painter.eraseRect( _ev->rect() );
05847 
05848   //QFontMetrics fm = painter.fontMetrics();
05849   // Matthias Elter: This causes a SEGFAULT in ~QPainter!
05850   // Only god and the trolls know why ;-)
05851   // bah...took me quite some time to track this one down...
05852 
05853   double xPos;
05854   int x;
05855 
05856   if ( sheet->layoutDirection()==Sheet::RightToLeft )
05857   {
05858     //Get the left column and the current x-position
05859     x = sheet->leftColumn( int( m_pCanvas->d->view->doc()->unzoomItX( width() ) - m_pCanvas->d->view->doc()->unzoomItX( _ev->rect().x() ) + m_pCanvas->xOffset() ), xPos );
05860     //Align to the offset
05861     xPos = m_pCanvas->d->view->doc()->unzoomItX( width() ) - xPos + m_pCanvas->xOffset();
05862   }
05863   else
05864   {
05865     //Get the left column and the current x-position
05866     x = sheet->leftColumn( int( m_pCanvas->d->view->doc()->unzoomItX( _ev->rect().x() ) + m_pCanvas->xOffset() ), xPos );
05867     //Align to the offset
05868     xPos = xPos - m_pCanvas->xOffset();
05869   }
05870 
05871   int height = m_pCanvas->d->view->doc()->zoomItY( Format::globalRowHeight() + 2 );
05872 
05873   QFont normalFont = painter.font();
05874   if ( m_pCanvas->d->view->doc()->zoom() < 100 )
05875   {
05876     normalFont.setPointSizeFloat( 0.01 * m_pCanvas->d->view->doc()->zoom() *
05877                                   normalFont.pointSizeFloat() );
05878   }
05879   QFont boldFont = normalFont;
05880   boldFont.setBold( true );
05881 
05882   if ( sheet->layoutDirection()==Sheet::RightToLeft )
05883   {
05884     if ( x > KS_colMax )
05885       x = KS_colMax;
05886 
05887     xPos -= sheet->columnFormat( x )->dblWidth();
05888 
05889     //Loop through the columns, until we are out of range
05890     while ( xPos <= m_pCanvas->d->view->doc()->unzoomItX( _ev->rect().right() ) )
05891     {
05892       bool selected = (m_pView->selectionInfo()->isColumnSelected(x));
05893       bool highlighted = (!selected && m_pView->selectionInfo()->isColumnAffected(x));
05894 
05895       const ColumnFormat * col_lay = sheet->columnFormat( x );
05896       int zoomedXPos = m_pCanvas->d->view->doc()->zoomItX( xPos );
05897       int width = m_pCanvas->d->view->doc()->zoomItX( xPos + col_lay->dblWidth() ) - zoomedXPos;
05898 
05899       if ( selected )
05900       {
05901         QBrush fillSelected( highlightColor );
05902         qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, highlightColor.dark(150),
05903            1, &fillSelected );
05904       }
05905       else if ( highlighted )
05906       {
05907         QBrush fillHighlighted( highlightColor );
05908         qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, highlightColor.dark(150),
05909            1, &fillHighlighted );
05910       }
05911       else
05912       {
05913         QColor c = colorGroup().background();
05914         QBrush fill( c );
05915         qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, c.dark(150),
05916            1, &fill );
05917       }
05918 
05919       // Reset painter
05920       painter.setFont( normalFont );
05921       painter.setPen( colorGroup().text() );
05922 
05923       if ( selected )
05924         painter.setPen( colorGroup().highlightedText() );
05925       else if ( highlighted )
05926         painter.setFont( boldFont );
05927       if ( !m_pView->activeSheet()->getShowColumnNumber() )
05928       {
05929         QString colText = Cell::columnName( x );
05930         int len = painter.fontMetrics().width( colText );
05931         if ( !col_lay->isHide() )
05932           painter.drawText( zoomedXPos + ( width - len ) / 2,
05933                             ( height + painter.fontMetrics().ascent() -
05934                               painter.fontMetrics().descent() ) / 2, colText );
05935       }
05936       else
05937       {
05938         QString tmp;
05939         int len = painter.fontMetrics().width( tmp.setNum(x) );
05940         if (!col_lay->isHide())
05941           painter.drawText( zoomedXPos + ( width - len ) / 2,
05942                             ( height + painter.fontMetrics().ascent() -
05943                               painter.fontMetrics().descent() ) / 2,
05944                             tmp.setNum(x) );
05945       }
05946       xPos += col_lay->dblWidth();
05947       --x;
05948     }
05949   }
05950   else
05951   {
05952     //Loop through the columns, until we are out of range
05953     while ( xPos <= m_pCanvas->d->view->doc()->unzoomItX( _ev->rect().right() ) )
05954     {
05955       bool selected = (m_pView->selectionInfo()->isColumnSelected(x));
05956       bool highlighted = (!selected && m_pView->selectionInfo()->isColumnAffected(x));
05957 
05958       const ColumnFormat *col_lay = sheet->columnFormat( x );
05959       int zoomedXPos = m_pCanvas->d->view->doc()->zoomItX( xPos );
05960       int width = m_pCanvas->d->view->doc()->zoomItX( xPos + col_lay->dblWidth() ) - zoomedXPos;
05961 
05962       if ( selected )
05963       {
05964         QBrush fillSelected( highlightColor );
05965         qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, highlightColor.dark(),
05966            1, &fillSelected );
05967       }
05968       else if ( highlighted )
05969       {
05970         QBrush fillHighlighted( highlightColor );
05971         qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, highlightColor.dark(),
05972            1, &fillHighlighted );
05973       }
05974       else
05975       {
05976         QColor c = colorGroup().background();
05977         QBrush fill( c );
05978         qDrawPlainRect ( &painter, zoomedXPos, 0, width+1, height, c.dark(150),
05979            1, &fill );
05980       }
05981 
05982       // Reset painter
05983       painter.setFont( normalFont );
05984       painter.setPen( colorGroup().text() );
05985 
05986       if ( selected )
05987         painter.setPen( colorGroup().highlightedText() );
05988       else if ( highlighted )
05989         painter.setFont( boldFont );
05990       if ( !m_pView->activeSheet()->getShowColumnNumber() )
05991       {
05992         QString colText = Cell::columnName( x );
05993         int len = painter.fontMetrics().width( colText );
05994         if (!col_lay->isHide())
05995           painter.drawText( zoomedXPos + ( width - len ) / 2,
05996                             ( height + painter.fontMetrics().ascent() -
05997                               painter.fontMetrics().descent() ) / 2, colText );
05998       }
05999       else
06000       {
06001         QString tmp;
06002         int len = painter.fontMetrics().width( tmp.setNum(x) );
06003         if (!col_lay->isHide())
06004           painter.drawText( zoomedXPos + ( width - len ) / 2,
06005                             ( height + painter.fontMetrics().ascent() -
06006                               painter.fontMetrics().descent() ) / 2,
06007                             tmp.setNum(x) );
06008       }
06009       xPos += col_lay->dblWidth();
06010       ++x;
06011     }
06012   }
06013 }
06014 
06015 
06016 void HBorder::focusOutEvent( QFocusEvent* )
06017 {
06018     if ( m_scrollTimer->isActive() )
06019         m_scrollTimer->stop();
06020     m_bMousePressed = false;
06021 }
06022 
06023 /****************************************************************
06024  *
06025  * ToolTip
06026  *
06027  ****************************************************************/
06028 
06029 ToolTip::ToolTip( Canvas* canvas )
06030     : QToolTip( canvas ), m_canvas( canvas )
06031 {
06032 }
06033 
06034 // find the label for the tip
06035 // this is a hack of course, because it's not available from QToolTip
06036 QLabel *tip_findLabel()
06037 {
06038     QWidgetList  *list = QApplication::allWidgets();
06039     QWidgetListIt it( *list );
06040     QWidget * w;
06041     while ( (w=it.current()) != 0 )
06042     {
06043         if(w->isA("QTipLabel"))
06044             return static_cast<QLabel*>(w);
06045         ++it;
06046     }
06047     delete list;
06048     return 0;
06049 }
06050 
06051 void ToolTip::maybeTip( const QPoint& p )
06052 {
06053     Sheet *sheet = m_canvas->activeSheet();
06054     if ( !sheet )
06055         return;
06056 
06057     // Over which cell is the mouse ?
06058     double ypos, xpos;
06059     double dwidth = m_canvas->doc()->unzoomItX( m_canvas->width() );
06060     int col;
06061     if ( sheet->layoutDirection()==Sheet::RightToLeft )
06062       col = sheet->leftColumn( (dwidth - m_canvas->doc()->unzoomItX( p.x() ) +
06063                                               m_canvas->xOffset()), xpos );
06064     else
06065       col = sheet->leftColumn( (m_canvas->doc()->unzoomItX( p.x() ) +
06066                                      m_canvas->xOffset()), xpos );
06067 
06068 
06069     int row = sheet->topRow( (m_canvas->doc()->unzoomItY( p.y() ) +
06070                                    m_canvas->yOffset()), ypos );
06071 
06072     Cell* cell = sheet->visibleCellAt( col, row );
06073     if ( !cell )
06074         return;
06075 
06076 #if 0
06077     // Quick cut
06078     if( cell->strOutText().isEmpty() )
06079         return;
06080 #endif
06081     // displayed tool tip, which has the following priorities:
06082     //  - cell content if the cell dimension is too small
06083     //  - cell comment
06084     //  - hyperlink
06085     QString tipText;
06086 
06087     // If cell is too small, show the content
06088     if ( cell->testFlag( Cell::Flag_CellTooShortX ) ||
06089          cell->testFlag( Cell::Flag_CellTooShortY ) )
06090     {
06091         tipText = cell->strOutText();
06092 
06093         //Add 2 extra lines and a text, when both should be in the tooltip
06094         QString comment = cell->format()->comment( col, row );
06095         if ( !comment.isEmpty() )
06096             comment = "\n\n" + i18n("Comment:") + "\n" + comment;
06097 
06098         tipText += comment;
06099     }
06100 
06101     // Show comment, if any
06102     if( tipText.isEmpty() )
06103     {
06104       tipText = cell->format()->comment( col, row );
06105     }
06106 
06107     // Show hyperlink, if any
06108     if( tipText.isEmpty() )
06109     {
06110         tipText = cell->link();
06111     }
06112 
06113     // Nothing to display, bail out
06114     if( tipText.isEmpty() )
06115       return;
06116 
06117     // Cut if the tip is ridiculously long
06118     unsigned maxLen = 256;
06119     if(tipText.length() > maxLen )
06120         tipText = tipText.left(maxLen).append("...");
06121 
06122     // Determine position and width of the current cell.
06123     cell = sheet->cellAt( col, row );
06124     double u = cell->dblWidth( col );
06125     double v = cell->dblHeight( row );
06126 
06127     // Special treatment for obscured cells.
06128     if ( cell->isObscured() && cell->isPartOfMerged() )
06129     {
06130       cell = cell->obscuringCells().first();
06131       int moveX = cell->column();
06132       int moveY = cell->row();
06133 
06134       // Use the obscuring cells dimensions
06135       u = cell->dblWidth( moveX );
06136       v = cell->dblHeight( moveY );
06137       xpos = sheet->dblColumnPos( moveX );
06138       ypos = sheet->dblRowPos( moveY );
06139     }
06140 
06141     // Get the cell dimensions
06142     QRect marker;
06143     bool insideMarker = false;
06144 
06145     if ( sheet->layoutDirection()==Sheet::RightToLeft )
06146     {
06147       KoRect unzoomedMarker( dwidth - u - xpos + m_canvas->xOffset(),
06148                              ypos - m_canvas->yOffset(),
06149                              u,
06150                              v );
06151 
06152       marker = m_canvas->doc()->zoomRect( unzoomedMarker );
06153       insideMarker = marker.contains( p );
06154     }
06155     else
06156     {
06157       KoRect unzoomedMarker( xpos - m_canvas->xOffset(),
06158                              ypos - m_canvas->yOffset(),
06159                              u,
06160                              v );
06161 
06162       marker = m_canvas->doc()->zoomRect( unzoomedMarker );
06163       insideMarker = marker.contains( p );
06164     }
06165 
06166     // No use if mouse is somewhere else
06167     if( !insideMarker )
06168         return;
06169 
06170     // Find the tipLabel
06171     // NOTE: if we failed, check again when the tip is shown already
06172     QLabel* tipLabel = tip_findLabel();
06173 
06174     // Ensure that it is plain text
06175     // Not funny if (intentional or not) <a> appears as hyperlink
06176     if( tipLabel )
06177          tipLabel->setTextFormat( Qt::PlainText );
06178 
06179     // Wrap the text if too long
06180     if( tipText.length() > 16 )
06181     {
06182         QFontMetrics fm = tipLabel? tipLabel->fontMetrics() : m_canvas->fontMetrics();
06183         QRect r( 0, 0, 200, -1 );
06184         KWordWrap* wrap = KWordWrap::formatText( fm, r, 0, tipText );
06185         tipText = wrap->wrappedString();
06186         delete wrap;
06187     }
06188 
06189     // Now we shows the tip
06190     tip( marker, tipText );
06191 
06192     // Here we try to find the tip label again
06193     // Reason: the previous tip_findLabel might fail if no tip has ever shown yet
06194     if( !tipLabel )
06195     {
06196       tipLabel = tip_findLabel();
06197       if( tipLabel )
06198             tipLabel->setTextFormat( Qt::PlainText );
06199     }
06200 
06201 }
06202 
06203 #include "kspread_canvas.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys