kspread Library API Documentation

kspread_canvas.cc

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