kspread Library API Documentation

kspread_editors.cc

00001 /* This file is part of the KDE project
00002 
00003    Copyright 1999-2004 The KSpread Team <koffice-devel@mail.kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
00019 */
00020 
00021 
00022 #include "kspread_editors.h"
00023 #include "kspread_canvas.h"
00024 #include "kspread_cell.h"
00025 #include "kspread_doc.h"
00026 #include "kspread_selection.h"
00027 #include "kspread_sheet.h"
00028 #include "kspread_view.h"
00029 
00030 #include <klineedit.h>
00031 #include <qapplication.h>
00032 #include <qbutton.h>
00033 #include <qfont.h>
00034 #include <qfontmetrics.h>
00035 #include <qregexp.h>
00036 #include <kdebug.h>
00037 
00038 /********************************************
00039  *
00040  * KSpreadCellEditor
00041  *
00042  ********************************************/
00043 
00044 KSpreadCellEditor::KSpreadCellEditor( KSpreadCell* _cell, KSpreadCanvas* _parent, const char* _name )
00045   : QWidget( _parent, _name )
00046 {
00047   m_pCell = _cell;
00048   m_pCanvas = _parent;
00049   setFocusPolicy( QWidget::StrongFocus );
00050 }
00051 
00052 KSpreadCellEditor::~KSpreadCellEditor()
00053 {
00054 }
00055 
00056 /********************************************
00057  *
00058  * KSpreadTextEditor
00059  *
00060  ********************************************/
00061 
00062 KSpreadTextEditor::KSpreadTextEditor( KSpreadCell* _cell, KSpreadCanvas* _parent, const char* _name )
00063   : KSpreadCellEditor( _cell, _parent, _name ),
00064     m_sizeUpdate(false),
00065     m_length(0),
00066     m_fontLength(0)
00067 {
00068   m_pEdit = new KLineEdit( this );
00069   m_pEdit->installEventFilter( this );
00070   m_pEdit->setFrame( FALSE );
00071   m_pEdit->setCompletionMode((KGlobalSettings::Completion)canvas()->view()->doc()->completionMode()  );
00072   m_pEdit->setCompletionObject( &canvas()->view()->doc()->completion(),true );
00073   setFocusProxy( m_pEdit );
00074 
00075   connect( m_pEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotTextChanged( const QString& ) ) );
00076   connect( m_pEdit, SIGNAL(completionModeChanged( KGlobalSettings::Completion )),this,SLOT (slotCompletionModeChanged(KGlobalSettings::Completion)));
00077 
00078   // A choose should always start at the edited cell
00079 //  canvas()->setChooseMarkerRow( canvas()->markerRow() );
00080 //  canvas()->setChooseMarkerColumn( canvas()->markerColumn() );
00081 
00082   m_blockCheck = FALSE;
00083 
00084   // set font size according to zoom factor
00085   QFont font( _cell->font() );
00086   font.setPointSizeFloat( 0.01 * _parent->doc()->zoom() * font.pointSizeFloat() );
00087   m_pEdit->setFont( font );
00088 
00089   if (m_fontLength == 0)
00090   {
00091     QFontMetrics fm( m_pEdit->font() );
00092     m_fontLength = fm.width('x');
00093   }
00094 }
00095 
00096 KSpreadTextEditor::~KSpreadTextEditor()
00097 {
00098   canvas()->endChoose();
00099 }
00100 
00101 void KSpreadTextEditor::cut()
00102 {
00103     if(m_pEdit)
00104         m_pEdit->cut();
00105 }
00106 
00107 void KSpreadTextEditor::paste()
00108 {
00109     if( m_pEdit)
00110         m_pEdit->paste();
00111 }
00112 
00113 void KSpreadTextEditor::copy()
00114 {
00115     if( m_pEdit)
00116         m_pEdit->copy();
00117 }
00118 
00119 void KSpreadTextEditor::setEditorFont(QFont const & font, bool updateSize)
00120 {
00121   if (!m_pEdit)
00122     return;
00123 
00124   QFont tmpFont( font );
00125   tmpFont.setPointSizeFloat( 0.01 * canvas()->doc()->zoom() * tmpFont.pointSizeFloat() );
00126   m_pEdit->setFont( tmpFont );
00127 
00128   if (updateSize)
00129   {
00130     QFontMetrics fm( m_pEdit->font() );
00131     m_fontLength = fm.width('x');
00132 
00133     int mw = fm.width( m_pEdit->text() ) + m_fontLength;
00134     // don't make it smaller: then we would have to repaint the obscured cells
00135     if (mw < width())
00136       mw = width();
00137 
00138     int mh = fm.height();
00139     if (mh < height())
00140       mh = height();
00141 
00142     setGeometry(x(), y(), mw, mh);
00143     m_sizeUpdate = true;
00144   }
00145 }
00146 
00147 void KSpreadTextEditor::slotCompletionModeChanged(KGlobalSettings::Completion _completion)
00148 {
00149   canvas()->view()->doc()->setCompletionMode( _completion );
00150 }
00151 
00152 void KSpreadTextEditor::slotTextChanged( const QString& t )
00153 {
00154   // if ( canvas->chooseCursorPosition() >= 0 )
00155   // m_pEdit->setCursorPosition( canvas->chooseCursorPosition() );
00156   if (!checkChoose())
00157     return;
00158 
00159   if (t.length() > m_length)
00160   {
00161     // allocate more space than needed. Otherwise it might be too slow
00162     m_length = t.length() + 5;
00163 
00164     // Too slow for long texts
00165     // QFontMetrics fm( m_pEdit->font() );
00166     //  int mw = fm.width( t ) + fm.width('x');
00167     int mw = m_fontLength * m_length;
00168 
00169     if (mw < width())
00170       mw = width();
00171 
00172     if (t.isRightToLeft())
00173       setGeometry(x() - mw + width(), y(), mw, height());
00174     else
00175       setGeometry(x(), y(), mw, height());
00176 
00177     m_length -= 2;
00178   }
00179 
00180   if ( (cell()->formatType()) == Percentage_format )
00181   {
00182     if ( (t.length() == 1) && t[0].isDigit() )
00183     {
00184       QString tmp = t + " %";
00185       m_pEdit->setText(tmp);
00186       m_pEdit->setCursorPosition(1);
00187       return;
00188     }
00189   }
00190 
00191   canvas()->view()->editWidget()->setText( t );
00192   // canvas()->view()->editWidget()->setCursorPosition( m_pEdit->cursorPosition() );
00193 }
00194 
00195 bool KSpreadTextEditor::checkChoose()
00196 {
00197     if ( m_blockCheck )
00198         return false;
00199 
00200     QString t = m_pEdit->text();
00201     if ( t[0] != '=' )
00202         canvas()->endChoose();
00203     else
00204     {
00205       QChar r = t[ m_pEdit->cursorPosition() - 1 - canvas()->chooseTextLen() ];
00206       if ( ( r == '*' || r == '|' || r == '&' || r == '-' ||
00207              r == '+' || r == '/' || r == '!' || r == '(' ||
00208              r == '^' || r == ',' || r == '%' || r == '[' ||
00209              r == '{' || r == '~' || r == '=' || r == ';' ||
00210          r == '>' || r == '<') )
00211       {
00212           canvas()->startChoose();
00213       }
00214       else
00215       {
00216           canvas()->endChoose();
00217       }
00218     }
00219     return true;
00220 }
00221 
00222 void KSpreadTextEditor::resizeEvent( QResizeEvent* )
00223 {
00224     m_pEdit->setGeometry( 0, 0, width(), height() );
00225 }
00226 
00227 void KSpreadTextEditor::handleKeyPressEvent( QKeyEvent * _ev )
00228 {
00229   if (_ev->key() == Qt::Key_F4)
00230   {
00231     if (m_pEdit == 0)
00232     {
00233       QApplication::sendEvent( m_pEdit, _ev );
00234       return;
00235     }
00236 
00237     QRegExp exp("(\\$?)([a-zA-Z]+)(\\$?)([0-9]+)$");
00238 
00239     int cur = m_pEdit->cursorPosition();
00240     QString tmp, tmp2;
00241     int n = -1;
00242 
00243     // this is ugly, and sort of hack
00244     // FIXME rewrite to use the real KSpreadTokenizer
00245     unsigned i;
00246     for( i = 0; i < 10; i++ )
00247     {
00248       tmp =  m_pEdit->text().left( cur+i );
00249       tmp2 = m_pEdit->text().right( m_pEdit->text().length() - cur - i );
00250 
00251       n = exp.search(tmp);
00252       if( n >= 0 ) break;
00253     }
00254 
00255     if (n == -1) return;
00256 
00257     QString newPart;
00258     if ((exp.cap(1) == "$") && (exp.cap(3) == "$"))
00259       newPart = "$" + exp.cap(2) + exp.cap(4);
00260     else if ((exp.cap(1) != "$") && (exp.cap(3) != "$"))
00261       newPart = "$" + exp.cap(2) + "$" + exp.cap(4);
00262     else if ((exp.cap(1) == "$") && (exp.cap(3) != "$"))
00263       newPart = exp.cap(2) + "$" + exp.cap(4);
00264     else if ((exp.cap(1) != "$") && (exp.cap(3) == "$"))
00265       newPart = exp.cap(2) + exp.cap(4);
00266 
00267     QString newString = tmp.left(n);
00268     newString += newPart;
00269     cur = newString.length() - i;
00270     newString += tmp2;
00271 
00272     m_pEdit->setText(newString);
00273     m_pEdit->setCursorPosition( cur );
00274 
00275     _ev->accept();
00276 
00277     return;
00278   }
00279 
00280   // Send the key event to the KLineEdit
00281   QApplication::sendEvent( m_pEdit, _ev );
00282 }
00283 
00284 void KSpreadTextEditor::handleIMEvent( QIMEvent * _ev )
00285 {
00286     // send the IM event to the KLineEdit
00287     QApplication::sendEvent( m_pEdit, _ev );
00288 }
00289 
00290 QString KSpreadTextEditor::text() const
00291 {
00292     return m_pEdit->text();
00293 }
00294 
00295 void KSpreadTextEditor::setText(QString text)
00296 {
00297     if (m_pEdit != 0)
00298         m_pEdit->setText(text);
00299 
00300     if (m_fontLength == 0)
00301     {
00302       QFontMetrics fm( m_pEdit->font() );
00303       m_fontLength = fm.width('x');
00304     }
00305 }
00306 
00307 int KSpreadTextEditor::cursorPosition() const
00308 {
00309     return m_pEdit->cursorPosition();
00310 }
00311 
00312 void KSpreadTextEditor::setCursorPosition( int pos )
00313 {
00314     m_pEdit->setCursorPosition(pos);
00315     canvas()->view()->editWidget()->setCursorPosition( pos );
00316     checkChoose();
00317 }
00318 
00319 void KSpreadTextEditor::insertFormulaChar(int /*c*/)
00320 {
00321 }
00322 
00323 bool KSpreadTextEditor::eventFilter( QObject* o, QEvent* e )
00324 {
00325     // Only interested in KLineEdit
00326     if ( o != m_pEdit )
00327         return FALSE;
00328     if ( e->type() == QEvent::FocusOut )
00329     {
00330         canvas()->setLastEditorWithFocus( KSpreadCanvas::CellEditor );
00331         return FALSE;
00332     }
00333 
00334     if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease )
00335     {
00336         QKeyEvent* k = (QKeyEvent*)e;
00337         if ( !( k->state() & Qt::ShiftButton )|| canvas()->chooseFormulaArea())
00338         {
00339             if ( k->key() == Key_Up || k->key() == Key_Down || 
00340                  k->key() == Key_Next || k->key() == Key_Prior || 
00341                  k->key() == Key_Escape || k->key() == Key_Tab )
00342             {
00343                 // Send directly to canvas
00344                 QApplication::sendEvent( parent(), e );
00345                 return TRUE;
00346             }
00347         }
00348         // End choosing. May be restarted by KSpreadTextEditor::slotTextChanged
00349         if ( e->type() == QEvent::KeyPress && !k->text().isEmpty() )
00350         {
00351             //kdDebug(36001) << "eventFilter End Choose" << endl;
00352             canvas()->endChoose();
00353             //kdDebug(36001) << "Cont" << endl;
00354         }
00355     }
00356 
00357     return FALSE;
00358 }
00359 
00360 KSpreadComboboxLocationEditWidget::KSpreadComboboxLocationEditWidget( QWidget * _parent,
00361                                                       KSpreadView * _view )
00362     : KComboBox( _parent, "KSpreadComboboxLocationEditWidget" )
00363 {
00364     m_locationWidget = new KSpreadLocationEditWidget( _parent, _view );
00365     setLineEdit( m_locationWidget );
00366     insertItem( "" );
00367 
00368     QValueList<Reference>::Iterator it;
00369     QValueList<Reference> area = _view->doc()->listArea();
00370     for ( it = area.begin(); it != area.end(); ++it )
00371         slotAddAreaName( (*it).ref_name);
00372 }
00373 
00374 void KSpreadComboboxLocationEditWidget::slotAddAreaName( const QString &_name)
00375 {
00376     insertItem( _name );
00377 }
00378 
00379 void KSpreadComboboxLocationEditWidget::slotRemoveAreaName( const QString &_name )
00380 {
00381     for ( int i = 0; i<count(); i++ )
00382         if ( text(i)==_name )
00383         {
00384             removeItem( i );
00385             return;
00386         }
00387 }
00388 
00389 KSpreadLocationEditWidget::KSpreadLocationEditWidget( QWidget * _parent,
00390                                                       KSpreadView * _view )
00391     : QLineEdit( _parent, "KSpreadLocationEditWidget" ),
00392       m_pView(_view)
00393 {
00394 }
00395 
00396 void KSpreadLocationEditWidget::keyPressEvent( QKeyEvent * _ev )
00397 {
00398     // Do not handle special keys and accelerators. This is
00399     // done by QLineEdit.
00400     if ( _ev->state() & ( Qt::AltButton | Qt::ControlButton ) )
00401     {
00402         QLineEdit::keyPressEvent( _ev );
00403         // Never allow that keys are passed on to the parent.
00404         _ev->accept();
00405 
00406         return;
00407     }
00408 
00409     // Handle some special keys here. Eve
00410     switch( _ev->key() )
00411     {
00412     case Key_Return:
00413     case Key_Enter:
00414         {
00415             QString ltext = text();
00416             QString tmp = ltext.lower();
00417             QValueList<Reference>::Iterator it;
00418         QValueList<Reference> area = m_pView->doc()->listArea();
00419         for ( it = area.begin(); it != area.end(); ++it )
00420             {
00421                 if ((*it).ref_name == tmp)
00422                 {
00423                     QString tmp = (*it).sheet_name;
00424                     tmp += "!";
00425                     tmp += util_rangeName((*it).rect);
00426                     m_pView->canvasWidget()->gotoLocation( KSpreadRange(tmp, m_pView->doc()->map()));
00427                     return;
00428                 }
00429             }
00430 
00431             // Set the cell component to uppercase:
00432             // Sheet1!a1 -> Sheet1!A2
00433             int pos = ltext.find('!');
00434             if ( pos !=- 1 )
00435                 tmp = ltext.left(pos)+ltext.mid(pos).upper();
00436             else
00437                 tmp = ltext.upper();
00438 
00439             // Selection entered in location widget
00440             if ( ltext.contains( ':' ) )
00441                 m_pView->canvasWidget()->gotoLocation( KSpreadRange( tmp, m_pView->doc()->map() ) );
00442             // Location entered in location widget
00443             else
00444             {
00445                 KSpreadPoint point( tmp, m_pView->doc()->map());
00446                 bool validName = true;
00447                 for (unsigned int i = 0; i < ltext.length(); ++i)
00448                 {
00449                     if (!ltext[i].isLetter())
00450                     {
00451                         validName = false;
00452                         break;
00453                     }
00454                 }
00455                 if ( !point.isValid() && validName)
00456                 {
00457                     QRect rect( m_pView->selection() );
00458                     KSpreadSheet * t = m_pView->activeSheet();
00459                     // set area name on current selection/cell
00460 
00461                     m_pView->doc()->addAreaName(rect, ltext.lower(),
00462                                                 t->sheetName());
00463                 }
00464 
00465                 if (!validName)
00466                     m_pView->canvasWidget()->gotoLocation( point );
00467             }
00468 
00469             // Set the focus back on the canvas.
00470             m_pView->canvasWidget()->setFocus();
00471             _ev->accept();
00472         }
00473         break;
00474     // Escape pressed, restore original value
00475     case Key_Escape:
00476         // #### Torben says: This is duplicated code. Bad.
00477         if ( m_pView->selectionInfo()->singleCellSelection() ) {
00478             setText( KSpreadCell::columnName( m_pView->canvasWidget()->markerColumn() )
00479                      + QString::number( m_pView->canvasWidget()->markerRow() ) );
00480         } else {
00481             setText( KSpreadCell::columnName( m_pView->selection().left() )
00482                      + QString::number( m_pView->selection().top() )
00483                      + ":"
00484                      + KSpreadCell::columnName( m_pView->selection().right() )
00485                      + QString::number( m_pView->selection().bottom() ) );
00486         }
00487         m_pView->canvasWidget()->setFocus();
00488         _ev->accept();
00489         break;
00490     default:
00491         QLineEdit::keyPressEvent( _ev );
00492         // Never allow that keys are passed on to the parent.
00493         _ev->accept();
00494     }
00495 }
00496 
00497 /****************************************************************
00498  *
00499  * KSpreadEditWidget
00500  * The line-editor that appears above the sheet and allows to
00501  * edit the cells content.
00502  *
00503  ****************************************************************/
00504 
00505 KSpreadEditWidget::KSpreadEditWidget( QWidget *_parent, KSpreadCanvas *_canvas,
00506                                       QButton *cancelButton, QButton *okButton )
00507   : QLineEdit( _parent, "KSpreadEditWidget" )
00508 {
00509   m_pCanvas = _canvas;
00510   Q_ASSERT(m_pCanvas != NULL);
00511   // Those buttons are created by the caller, so that they are inserted
00512   // properly in the layout - but they are then managed here.
00513   m_pCancelButton = cancelButton;
00514   m_pOkButton = okButton;
00515 
00516   installEventFilter(m_pCanvas);
00517 
00518   if ( !m_pCanvas->doc()->isReadWrite() || !m_pCanvas->activeSheet() )
00519     setEnabled( false );
00520 
00521   QObject::connect( m_pCancelButton, SIGNAL( clicked() ),
00522                     this, SLOT( slotAbortEdit() ) );
00523   QObject::connect( m_pOkButton, SIGNAL( clicked() ),
00524                     this, SLOT( slotDoneEdit() ) );
00525 
00526   setEditMode( false ); // disable buttons
00527 }
00528 
00529 void KSpreadEditWidget::showEditWidget(bool _show)
00530 {
00531     if (_show)
00532     {
00533         m_pCancelButton->show();
00534         m_pOkButton->show();
00535         show();
00536     }
00537     else
00538     {
00539         m_pCancelButton->hide();
00540         m_pOkButton->hide();
00541         hide();
00542     }
00543 }
00544 
00545 void KSpreadEditWidget::slotAbortEdit()
00546 {
00547     m_pCanvas->deleteEditor( false /*discard changes*/ );
00548     // will take care of the buttons
00549 }
00550 
00551 void KSpreadEditWidget::slotDoneEdit()
00552 {
00553     m_pCanvas->deleteEditor( true /*keep changes*/ );
00554     // will take care of the buttons
00555 }
00556 
00557 void KSpreadEditWidget::keyPressEvent ( QKeyEvent* _ev )
00558 {
00559     // Dont handle special keys and accelerators
00560     if ( ( _ev->state() & ( Qt::AltButton | Qt::ControlButton ) )
00561          || ( _ev->state() & Qt::ShiftButton )
00562          || ( _ev->key() == Key_Shift )
00563          || ( _ev->key() == Key_Control ) )
00564     {
00565         QLineEdit::keyPressEvent( _ev );
00566         _ev->accept();
00567         return;
00568     }
00569 
00570   if ( !m_pCanvas->doc()->isReadWrite() )
00571     return;
00572 
00573   if ( !m_pCanvas->editor() )
00574   {
00575     // Start editing the current cell
00576     m_pCanvas->createEditor( KSpreadCanvas::CellEditor,false );
00577   }
00578   KSpreadTextEditor * cellEditor = (KSpreadTextEditor*) m_pCanvas->editor();
00579 
00580   switch ( _ev->key() )
00581   {
00582     case Key_Down:
00583     case Key_Up:
00584     case Key_Return:
00585     case Key_Enter:
00586       cellEditor->setText( text());
00587       // Don't allow to start a chooser when pressing the arrow keys
00588       // in this widget, since only up and down would work anyway.
00589       // This is why we call slotDoneEdit now, instead of sending
00590       // to the canvas.
00591       //QApplication::sendEvent( m_pCanvas, _ev );
00592       slotDoneEdit();
00593       m_pCanvas->view()->updateEditWidget();
00594       _ev->accept();
00595       break;
00596     case Key_F2:
00597       cellEditor->setFocus();
00598       cellEditor->setText( text());
00599       cellEditor->setCursorPosition(cursorPosition());
00600       break;
00601     default:
00602 
00603       QLineEdit::keyPressEvent( _ev );
00604 
00605       setFocus();
00606       cellEditor->blockCheckChoose( TRUE );
00607       cellEditor->setText( text() );
00608       cellEditor->blockCheckChoose( FALSE );
00609       cellEditor->setCursorPosition( cursorPosition() );
00610   }
00611 }
00612 
00613 void KSpreadEditWidget::setEditMode( bool mode )
00614 {
00615   m_pCancelButton->setEnabled(mode);
00616   m_pOkButton->setEnabled(mode);
00617 }
00618 
00619 void KSpreadEditWidget::focusOutEvent( QFocusEvent* ev )
00620 {
00621   //kdDebug(36001) << "EditWidget lost focus" << endl;
00622   // See comment about setLastEditorWithFocus
00623   m_pCanvas->setLastEditorWithFocus( KSpreadCanvas::EditWidget );
00624 
00625   QLineEdit::focusOutEvent( ev );
00626 }
00627 
00628 void KSpreadEditWidget::setText( const QString& t )
00629 {
00630   if ( t == text() ) // Why this? (David)
00631     return;
00632 
00633   QLineEdit::setText( t );
00634 }
00635 
00636 
00637 
00638 #include "kspread_editors.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:43:03 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003