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