00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kspread_editors.h"
00022 #include "kspread_canvas.h"
00023 #include "kspread_cell.h"
00024 #include "kspread_doc.h"
00025 #include "selection.h"
00026 #include "kspread_sheet.h"
00027 #include "kspread_view.h"
00028 #include "kspread_util.h"
00029 #include "formula.h"
00030 #include "functions.h"
00031
00032 #include <klistbox.h>
00033
00034 #include <qapplication.h>
00035 #include <qlistbox.h>
00036 #include <qtimer.h>
00037 #include <qlabel.h>
00038 #include <qvbox.h>
00039 #include <qvaluelist.h>
00040 #include <private/qrichtext_p.h>
00041
00042
00043 #include <ktextedit.h>
00044 #include <qapplication.h>
00045 #include <qbutton.h>
00046 #include <qfont.h>
00047 #include <qfontmetrics.h>
00048 #include <qregexp.h>
00049 #include <kdebug.h>
00050
00051 using namespace KSpread;
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 namespace KSpread
00062 {
00063
00064 class FormulaEditorHighlighter::Private
00065 {
00066 public:
00067 Private()
00068 {
00069 canvas = 0;
00070 tokens = Tokens();
00071 rangeCount = 0;
00072 rangeChanged = false;
00073 }
00074
00075
00076 Canvas* canvas;
00077 Tokens tokens;
00078 uint rangeCount;
00079 bool rangeChanged;
00080 };
00081
00082
00083 FormulaEditorHighlighter::FormulaEditorHighlighter(QTextEdit* textEdit, Canvas* canvas)
00084 : QSyntaxHighlighter(textEdit)
00085 {
00086 d = new Private();
00087 d->canvas = canvas;
00088 }
00089
00090 FormulaEditorHighlighter::~FormulaEditorHighlighter()
00091 {
00092 delete d;
00093 }
00094
00095 const Tokens& FormulaEditorHighlighter::formulaTokens() const
00096 {
00097 return d->tokens;
00098 }
00099
00100 int FormulaEditorHighlighter::highlightParagraph(const QString& text, int )
00101 {
00102
00103 setFormat(0, text.length(), Qt::black);
00104
00105
00106 Tokens oldTokens = d->tokens;
00107
00108
00109
00110 Formula f;
00111 d->tokens = f.scan(text);
00112
00113 QFont editorFont = textEdit()->currentFont();
00114 QFont font;
00115
00116 uint oldRangeCount = d->rangeCount;
00117
00118 d->rangeCount = 0;
00119 QValueList<QColor> colors = d->canvas->choice()->colors();
00120 QValueList<Range> alreadyFoundRanges;
00121
00122 for (uint i = 0; i < d->tokens.count(); ++i)
00123 {
00124 Token token = d->tokens[i];
00125 Token::Type type = token.type();
00126
00127 switch (type)
00128 {
00129 case Token::Cell:
00130 case Token::Range:
00131 {
00132
00133 if (!d->rangeChanged && i < oldTokens.count() && token.text() != oldTokens[i].text())
00134 {
00135 d->rangeChanged = true;
00136 }
00137
00138 Range newRange( token.text() );
00139
00140 if (!alreadyFoundRanges.contains(newRange))
00141 {
00142 alreadyFoundRanges.append(newRange);
00143 d->rangeCount++;
00144 }
00145 setFormat(token.pos() + 1, token.text().length(), colors[ alreadyFoundRanges.findIndex(newRange) % colors.size()] );
00146 }
00147 break;
00148 case Token::Boolean:
00149
00150
00151
00152 break;
00153 case Token::Identifier:
00154
00155
00156
00157 break;
00158
00159 case Token::Unknown:
00160 case Token::Integer:
00161 case Token::Float:
00162 case Token::String:
00163 case Token::Operator:
00164 {
00165 switch (token.asOperator())
00166 {
00167 case Token::LeftPar:
00168 case Token::RightPar:
00169
00170 handleBrace( i );
00171 break;
00172 default:
00173 break;
00174 }
00175 }
00176 break;
00177 }
00178 }
00179
00180 if (oldRangeCount != d->rangeCount)
00181 d->rangeChanged = true;
00182
00183 return 0;
00184 }
00185
00186 void FormulaEditorHighlighter::handleBrace( uint index )
00187 {
00188 int cursorParagraph;
00189 int cursorPos;
00190 const Token& token = d->tokens.at( index );
00191
00192 textEdit()->getCursorPosition( &cursorParagraph , &cursorPos );
00193
00194 int distance = cursorPos-token.pos();
00195 int opType = token.asOperator();
00196 bool highlightBrace=false;
00197
00198
00199
00200
00201
00202 if ( opType == Token::LeftPar )
00203 {
00204
00205 if ( distance == 1 )
00206 highlightBrace=true;
00207 else
00208
00209
00210
00211 if (distance==2)
00212 if ( (index == d->tokens.count()-1) || ( d->tokens.at(index+1).asOperator() != Token::LeftPar) )
00213 highlightBrace=true;
00214
00215 }
00216 else
00217 {
00218
00219 if ( distance == 2 )
00220 highlightBrace=true;
00221 else
00222
00223
00224
00225 if ( distance == 1 )
00226 if ( (index == 0) || (d->tokens.at(index-1).asOperator() != Token::RightPar) )
00227 highlightBrace=true;
00228 }
00229
00230 if (highlightBrace)
00231 {
00232 QFont font = QFont( textEdit()->currentFont() );
00233 font.setBold(true);
00234 setFormat(token.pos() + 1, token.text().length(), font);
00235
00236 int matching = findMatchingBrace( index );
00237
00238 if (matching != -1)
00239 {
00240 Token matchingBrace = d->tokens.at(matching);
00241 setFormat( matchingBrace.pos() + 1 , matchingBrace.text().length() , font);
00242 }
00243 }
00244 }
00245
00246 int FormulaEditorHighlighter::findMatchingBrace(int pos)
00247 {
00248 int depth=0;
00249 int step=0;
00250
00251 Tokens tokens = d->tokens;
00252
00253
00254
00255
00256 if (tokens.at(pos).asOperator() == Token::LeftPar)
00257 step = 1;
00258 else
00259 step = -1;
00260
00261 for (int index=pos ; (index >= 0) && (index < (int) tokens.count() ) ; index += step )
00262 {
00263 if (tokens.at(index).asOperator() == Token::LeftPar)
00264 depth++;
00265 if (tokens.at(index).asOperator() == Token::RightPar)
00266 depth--;
00267
00268 if (depth == 0)
00269 {
00270 return index;
00271 }
00272 }
00273
00274 return -1;
00275 }
00276
00277 uint FormulaEditorHighlighter::rangeCount() const
00278 {
00279 return d->rangeCount;
00280 }
00281
00282 bool FormulaEditorHighlighter::rangeChanged() const
00283 {
00284 return d->rangeChanged;
00285 }
00286
00287 void FormulaEditorHighlighter::resetRangeChanged()
00288 {
00289 d->rangeChanged=false;
00290 }
00291
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 class FunctionCompletion::Private
00303 {
00304 public:
00305 CellEditor* editor;
00306 QVBox *completionPopup;
00307 KListBox *completionListBox;
00308 QLabel* hintLabel;
00309 };
00310
00311 FunctionCompletion::FunctionCompletion( CellEditor* editor ):
00312 QObject( editor )
00313 {
00314 d = new Private;
00315 d->editor = editor;
00316 d->hintLabel = 0;
00317
00318 d->completionPopup = new QVBox( editor->topLevelWidget(), 0, WType_Popup );
00319 d->completionPopup->setFrameStyle( QFrame::Box | QFrame::Plain );
00320 d->completionPopup->setLineWidth( 1 );
00321 d->completionPopup->installEventFilter( this );
00322 d->completionPopup->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum);
00323
00324 d->completionListBox = new KListBox( d->completionPopup );
00325 d->completionPopup->setFocusProxy( d->completionListBox );
00326 d->completionListBox->setFrameStyle( QFrame::NoFrame );
00327 d->completionListBox->setVariableWidth( true );
00328 d->completionListBox->installEventFilter( this );
00329 connect( d->completionListBox, SIGNAL(selected(const QString&)), this,
00330 SLOT(itemSelected(const QString&)) );
00331 connect( d->completionListBox, SIGNAL(highlighted(const QString&)), this,
00332 SLOT(itemSelected(const QString&)) );
00333
00334 d->hintLabel = new QLabel( 0, "autocalc", Qt::WStyle_StaysOnTop |
00335 Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WStyle_Tool | Qt::WX11BypassWM );
00336 d->hintLabel->setFrameStyle( QFrame::Plain | QFrame::Box );
00337 d->hintLabel->setPalette( QToolTip::palette() );
00338 d->hintLabel->hide();
00339 }
00340
00341 FunctionCompletion::~FunctionCompletion()
00342 {
00343 delete d->hintLabel;
00344 delete d;
00345 }
00346
00347 void FunctionCompletion::itemSelected( const QString& item )
00348 {
00349 KSpread::FunctionDescription* desc;
00350 desc = KSpread::FunctionRepository::self()->functionInfo(item);
00351 if(!desc)
00352 {
00353 d->hintLabel->hide();
00354 return;
00355 }
00356
00357 QString helpText = desc->helpText()[0];
00358 if( helpText.isEmpty() )
00359 {
00360 d->hintLabel->hide();
00361 return;
00362 }
00363
00364 helpText.append("</qt>").prepend("<qt>");
00365 d->hintLabel->setText( helpText );
00366 d->hintLabel->adjustSize();
00367
00368
00369 QPoint pos = d->editor->mapToGlobal( QPoint( d->editor->width(), 0 ) );
00370 pos.setY( pos.y() - d->hintLabel->height() - 1 );
00371 d->hintLabel->move( pos );
00372 d->hintLabel->show();
00373 d->hintLabel->raise();
00374
00375
00376
00377 }
00378
00379 bool FunctionCompletion::eventFilter( QObject *obj, QEvent *ev )
00380 {
00381 if ( obj == d->completionPopup || obj == d->completionListBox )
00382 {
00383 if ( ev->type() == QEvent::KeyPress )
00384 {
00385 QKeyEvent *ke = (QKeyEvent*)ev;
00386 if ( ke->key() == Key_Enter || ke->key() == Key_Return )
00387 {
00388 doneCompletion();
00389 return true;
00390 }
00391 else if ( ke->key() == Key_Left || ke->key() == Key_Right ||
00392 ke->key() == Key_Up || ke->key() == Key_Down ||
00393 ke->key() == Key_Home || ke->key() == Key_End ||
00394 ke->key() == Key_Prior || ke->key() == Key_Next )
00395 return false;
00396
00397 d->hintLabel->hide();
00398 d->completionPopup->close();
00399 d->editor->setFocus();
00400 QApplication::sendEvent( d->editor, ev );
00401 return true;
00402 }
00403
00404 if ( ev->type() == QEvent::MouseButtonDblClick )
00405 {
00406 doneCompletion();
00407 return true;
00408 }
00409 }
00410
00411 return false;
00412 }
00413
00414 void FunctionCompletion::doneCompletion()
00415 {
00416 d->hintLabel->hide();
00417 d->completionPopup->close();
00418 d->editor->setFocus();
00419 emit selectedCompletion( d->completionListBox->currentText() );
00420 }
00421
00422 void FunctionCompletion::showCompletion( const QStringList &choices )
00423 {
00424 if( !choices.count() ) return;
00425
00426 d->completionListBox->clear();
00427 for( unsigned i = 0; i < choices.count(); i++ )
00428 new QListBoxText( (QListBox*)d->completionListBox, choices[i] );
00429 d->completionListBox->setCurrentItem( 0 );
00430
00431
00432 d->completionPopup->setMaximumHeight( 100 );
00433 d->completionPopup->resize( d->completionListBox->sizeHint() +
00434 QSize( d->completionListBox->verticalScrollBar()->width() + 4,
00435 d->completionListBox->horizontalScrollBar()->height() + 4 ) );
00436 int h = d->completionListBox->height();
00437 int w = d->completionListBox->width();
00438
00439 QPoint pos = d->editor->globalCursorPosition();
00440
00441
00442
00443 int screen_num = QApplication::desktop()->screenNumber( d->completionPopup );
00444 QRect screen = QApplication::desktop()->screenGeometry( screen_num );
00445 if( pos.y() + h > screen.y()+screen.height() )
00446 pos.setY( pos.y() - h - d->editor->height() );
00447 if( pos.x() + w > screen.x()+screen.width() )
00448 pos.setX( screen.x()+screen.width() - w );
00449
00450 d->completionPopup->move( pos );
00451 d->completionListBox->setFocus();
00452 d->completionPopup->show();
00453 }
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463 class CellEditor::Private
00464 {
00465 public:
00466 Cell* cell;
00467 Canvas* canvas;
00468 KTextEdit* textEdit;
00469 FormulaEditorHighlighter* highlighter;
00470 FunctionCompletion* functionCompletion;
00471 QTimer* functionCompletionTimer;
00472
00473 QPoint globalCursorPos;
00474
00475 bool captureAllKeyEvents : 1;
00476 bool checkChoice : 1;
00477 bool updateChoice : 1;
00478 bool updatingChoice : 1;
00479
00480 uint length;
00481 uint fontLength;
00482 uint length_namecell;
00483 uint length_text;
00484 uint currentToken;
00485 uint rangeCount;
00486 };
00487
00488
00489 CellEditor::CellEditor( Cell* _cell, Canvas* _parent, bool captureAllKeyEvents, const char* _name )
00490 : QWidget( _parent, _name )
00491 {
00492 d = new Private();
00493 d->cell = _cell;
00494 d->canvas = _parent;
00495 d->textEdit = new KTextEdit(this);
00496 d->globalCursorPos = QPoint();
00497 d->captureAllKeyEvents = captureAllKeyEvents;
00498 d->checkChoice = true;
00499 d->updateChoice = true;
00500 d->updatingChoice = false;
00501 d->length = 0;
00502 d->fontLength = 0;
00503 d->length_namecell = 0;
00504 d->length_text = 0;
00505 d->currentToken = 0;
00506 d->rangeCount = 0;
00507
00508
00509
00510 d->textEdit->setHScrollBarMode(QScrollView::AlwaysOff);
00511 d->textEdit->setVScrollBarMode(QScrollView::AlwaysOff);
00512 d->textEdit->setFrameStyle(QFrame::NoFrame);
00513 d->textEdit->setLineWidth(0);
00514 d->textEdit->installEventFilter( this );
00515
00516 d->highlighter = new FormulaEditorHighlighter(d->textEdit, _parent);
00517
00518 d->functionCompletion = new FunctionCompletion( this );
00519 d->functionCompletionTimer = new QTimer( this );
00520 connect( d->functionCompletion, SIGNAL( selectedCompletion( const QString& ) ),
00521 SLOT( functionAutoComplete( const QString& ) ) );
00522 connect( d->textEdit, SIGNAL( textChanged() ), SLOT( checkFunctionAutoComplete() ) );
00523 connect( d->functionCompletionTimer, SIGNAL( timeout() ),
00524 SLOT( triggerFunctionAutoComplete() ) );
00525
00526 if (!cell()->format()->multiRow(cell()->column(),cell()->row()))
00527 d->textEdit->setWordWrap(QTextEdit::NoWrap);
00528 else
00529 d->textEdit->setWrapPolicy(QTextEdit::AtWordOrDocumentBoundary);
00530
00531
00532
00533
00534
00535
00536
00537 setFocusProxy( d->textEdit );
00538
00539 connect( d->textEdit, SIGNAL( cursorPositionChanged(int,int) ), this, SLOT (slotCursorPositionChanged(int,int)));
00540 connect( d->textEdit, SIGNAL( cursorPositionChanged(QTextCursor*) ), this, SLOT (slotTextCursorChanged(QTextCursor*)));
00541 connect( d->textEdit, SIGNAL( textChanged() ), this, SLOT( slotTextChanged() ) );
00542
00543
00544
00545
00546
00547
00548
00549
00550 QFont font( _cell->format()->font() );
00551 font.setPointSizeFloat( 0.01 * _parent->doc()->zoom() * font.pointSizeFloat() );
00552 d->textEdit->setFont( font );
00553
00554 if (d->fontLength == 0)
00555 {
00556 QFontMetrics fm( d->textEdit->font() );
00557 d->fontLength = fm.width('x');
00558 }
00559 }
00560
00561 CellEditor::~CellEditor()
00562 {
00563 canvas()->endChoose();
00564
00565 delete d->highlighter;
00566 delete d->functionCompletion;
00567 delete d->functionCompletionTimer;
00568 delete d;
00569 }
00570
00571 Cell* CellEditor::cell() const
00572 {
00573 return d->cell;
00574 }
00575
00576 Canvas* CellEditor::canvas() const
00577 {
00578 return d->canvas;
00579 }
00580
00581 QPoint CellEditor::globalCursorPosition() const
00582 {
00583 return d->globalCursorPos;
00584 }
00585
00586 void CellEditor::checkFunctionAutoComplete()
00587 {
00588 d->functionCompletionTimer->stop();
00589 d->functionCompletionTimer->start( 2000, true );
00590 }
00591
00592 void CellEditor::triggerFunctionAutoComplete()
00593 {
00594
00595 int para = 0, curPos = 0;
00596 d->textEdit->getCursorPosition( ¶, &curPos );
00597 QString subtext = d->textEdit->text().left( curPos );
00598
00599 KSpread::Formula f;
00600 KSpread::Tokens tokens = f.scan( subtext );
00601 if( !tokens.valid() ) return;
00602 if( tokens.count()<1 ) return;
00603
00604 KSpread::Token lastToken = tokens[ tokens.count()-1 ];
00605
00606
00607 if( !lastToken.isIdentifier() ) return;
00608 QString id = lastToken.text();
00609 if( id.length() < 1 ) return;
00610
00611
00612 QStringList fnames = KSpread::FunctionRepository::self()->functionNames();
00613 QStringList choices;
00614 for( unsigned i=0; i<fnames.count(); i++ )
00615 if( fnames[i].startsWith( id, false ) )
00616 choices.append( fnames[i] );
00617 choices.sort();
00618
00619
00620 if( !choices.count() ) return;
00621
00622
00623 if( choices.count()==1 )
00624 if( choices[0].lower() == id.lower() )
00625 return;
00626
00627
00628 d->functionCompletion->showCompletion( choices );
00629 }
00630
00631 void CellEditor::functionAutoComplete( const QString& item )
00632 {
00633 if( item.isEmpty() ) return;
00634
00635 int para = 0, curPos = 0;
00636 d->textEdit->getCursorPosition( ¶, &curPos );
00637 QString subtext = text().left( curPos );
00638
00639 KSpread::Formula f;
00640 KSpread::Tokens tokens = f.scan( subtext );
00641 if( !tokens.valid() ) return;
00642 if( tokens.count()<1 ) return;
00643
00644 KSpread::Token lastToken = tokens[ tokens.count()-1 ];
00645 if( !lastToken.isIdentifier() ) return;
00646
00647 d->textEdit->blockSignals( true );
00648 d->textEdit->setSelection( 0, lastToken.pos()+1, 0, lastToken.pos()+lastToken.text().length()+1 );
00649 d->textEdit->insert( item );
00650 d->textEdit->blockSignals( false );
00651 }
00652
00653 void CellEditor::slotCursorPositionChanged(int , int pos)
00654 {
00655
00656
00657
00658
00659
00660 if (!checkChoice())
00661 return;
00662
00663 d->highlighter->rehighlight();
00664
00665 Tokens tokens = d->highlighter->formulaTokens();
00666 uint rangeCounter = 0;
00667 uint currentRange = 0;
00668 uint regionStart = 0;
00669 uint regionEnd = 0;
00670 bool lastWasASemicolon = false;
00671 d->currentToken = 0;
00672 uint rangeCount = d->highlighter->rangeCount();
00673 d->rangeCount = rangeCount;
00674
00675 Token token;
00676 Token::Type type;
00677
00678
00679 for (uint i = 0; i < tokens.count(); ++i)
00680 {
00681 if (tokens[i].pos() >= pos - 1)
00682 {
00683
00684 type = tokens[i].type();
00685 if (type == Token::Cell || type == Token::Range)
00686 {
00687 if (lastWasASemicolon)
00688 {
00689 regionEnd = rangeCounter++;
00690 lastWasASemicolon = false;
00691 continue;
00692 }
00693 }
00694 if (type == Token::Operator && tokens[i].asOperator() == Token::Semicolon)
00695 {
00696 lastWasASemicolon = true;
00697 continue;
00698 }
00699 lastWasASemicolon = false;
00700 break;
00701 }
00702 token = tokens[i];
00703 d->currentToken = i;
00704
00705 type = token.type();
00706 if (type == Token::Cell || type == Token::Range)
00707 {
00708 if (!lastWasASemicolon)
00709 {
00710 regionStart = rangeCounter;
00711 }
00712 regionEnd = rangeCounter;
00713 currentRange = rangeCounter++;
00714 }
00715
00716 if (type == Token::Operator)
00717 {
00718 if (token.asOperator() == Token::Semicolon)
00719 {
00720 lastWasASemicolon = true;
00721 }
00722 else
00723 {
00724 lastWasASemicolon = false;
00725
00726 regionStart = currentRange + 1;
00727 regionEnd = regionStart - 1;
00728 }
00729 }
00730 }
00731
00732
00733
00734
00735
00736 d->canvas->choice()->setActiveElement(currentRange);
00737 d->canvas->choice()->setActiveSubRegion(regionStart, regionEnd-regionStart+1);
00738
00739
00740 if (!d->updatingChoice)
00741 {
00742 if (d->highlighter->rangeChanged())
00743 {
00744 d->highlighter->resetRangeChanged();
00745
00746 d->canvas->doc()->emitBeginOperation();
00747 setUpdateChoice(false);
00748
00749 Tokens tokens = d->highlighter->formulaTokens();
00750 d->canvas->choice()->update();
00751 d->canvas->choice()->clear();
00752 Region tmpRegion;
00753 Region::ConstIterator it;
00754
00755
00756
00757
00758 QValueList<Region> alreadyUsedRegions;
00759
00760 for (uint i = 0; i < tokens.count(); ++i)
00761 {
00762 Token token = tokens[i];
00763 Token::Type type = token.type();
00764 if (type == Token::Cell || type == Token::Range)
00765 {
00766 Region region(d->canvas->view(), token.text());
00767 it = region.constBegin();
00768
00769 if (!alreadyUsedRegions.contains(region))
00770 {
00771 QRect r=(*it)->rect();
00772
00773 if (d->canvas->choice()->isEmpty())
00774 d->canvas->choice()->initialize((*it)->rect(), (*it)->sheet());
00775 else
00776 d->canvas->choice()->extend((*it)->rect(), (*it)->sheet());
00777
00778 alreadyUsedRegions.append(region);
00779 }
00780 }
00781 }
00782 setUpdateChoice(true);
00783 d->canvas->doc()->emitEndOperation(*d->canvas->choice());
00784 }
00785 }
00786 }
00787
00788 void CellEditor::slotTextCursorChanged(QTextCursor* cursor)
00789 {
00790 QTextStringChar *chr = cursor->paragraph()->at( cursor->index() );
00791 int h = cursor->paragraph()->lineHeightOfChar( cursor->index() );
00792 int x = cursor->paragraph()->rect().x() + chr->x;
00793 int y, dummy;
00794 cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y );
00795 y += cursor->paragraph()->rect().y();
00796
00797 d->globalCursorPos = d->textEdit->mapToGlobal( d->textEdit-> contentsToViewport( QPoint( x, y + h ) ) );
00798 }
00799
00800 void CellEditor::cut()
00801 {
00802 d->textEdit->cut();
00803 }
00804
00805 void CellEditor::paste()
00806 {
00807 d->textEdit->paste();
00808 }
00809
00810 void CellEditor::copy()
00811 {
00812 d->textEdit->copy();
00813 }
00814
00815 void CellEditor::setEditorFont(QFont const & font, bool updateSize)
00816 {
00817 QFont tmpFont( font );
00818 tmpFont.setPointSizeFloat( 0.01 * canvas()->doc()->zoom() * tmpFont.pointSizeFloat() );
00819 d->textEdit->setFont( tmpFont );
00820
00821 if (updateSize)
00822 {
00823 QFontMetrics fm( d->textEdit->font() );
00824 d->fontLength = fm.width('x');
00825
00826 int mw = fm.width( d->textEdit->text() ) + d->fontLength;
00827
00828 if (mw < width())
00829 mw = width();
00830
00831 int mh = fm.height();
00832 if (mh < height())
00833 mh = height();
00834
00835 setGeometry(x(), y(), mw, mh);
00836 }
00837 }
00838
00839 void CellEditor::slotCompletionModeChanged(KGlobalSettings::Completion _completion)
00840 {
00841 canvas()->view()->doc()->setCompletionMode( _completion );
00842 }
00843
00844 void CellEditor::slotTextChanged()
00845 {
00846
00847
00848
00849 QString t = text();
00850
00851 if (t.length() > d->length)
00852 {
00853 d->length = t.length();
00854
00855 QFontMetrics fm(d->textEdit->font());
00856
00857 int requiredWidth = fm.width(t) + (2*fm.width('x'));
00858
00859
00860
00861
00862
00863 if (d->textEdit->wordWrap() == QTextEdit::NoWrap)
00864 {
00865 if (requiredWidth > width())
00866 {
00867 if (t.isRightToLeft())
00868 {
00869 setGeometry(x() - requiredWidth + width(), y(), requiredWidth,height());
00870 }
00871 else
00872 {
00873 setGeometry(x(), y(), requiredWidth,height());
00874 }
00875 }
00876 }
00877 else
00878 {
00879 int requiredHeight = d->textEdit->heightForWidth(width());
00880
00881 if (requiredHeight > height())
00882 {
00883 setGeometry(x(), y(), width(), requiredHeight);
00884 }
00885 }
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904 }
00905
00906 if ( (cell()->formatType()) == Percentage_format )
00907 {
00908 if ( (t.length() == 1) && t[0].isDigit() )
00909 {
00910 QString tmp = t + " %";
00911 d->textEdit->setText(tmp);
00912 d->textEdit->setCursorPosition(0,1);
00913 return;
00914 }
00915 }
00916
00917 canvas()->view()->editWidget()->setText( t );
00918
00919 }
00920
00921 void CellEditor::setCheckChoice(bool state)
00922 {
00923 d->checkChoice = state;
00924 }
00925
00926 bool CellEditor::checkChoice()
00927 {
00928 if (!d->checkChoice)
00929 return false;
00930
00931
00932
00933
00934 d->length_namecell = 0;
00935 d->currentToken = 0;
00936
00937 QString text = d->textEdit->text();
00938 if ( text[0] != '=' )
00939 {
00940 canvas()->setChooseMode(false);
00941 }
00942 else
00943 {
00944 int para, cur;
00945 d->textEdit->getCursorPosition(¶, &cur);
00946
00947 Tokens tokens = d->highlighter->formulaTokens();
00948
00949
00950 if (tokens.count() < 1)
00951 {
00952 canvas()->startChoose();
00953 }
00954 else
00955 {
00956 Token token;
00957 for (uint i = 0; i < tokens.count(); ++i)
00958 {
00959 if (tokens[i].pos() >= cur - 1)
00960 {
00961 break;
00962 }
00963 token = tokens[i];
00964 d->currentToken = i;
00965 }
00966
00967 Token::Type type = token.type();
00968 if (type == Token::Operator && token.asOperator() != Token::RightPar)
00969 {
00970 canvas()->setChooseMode(true);
00971 }
00972 else if (type == Token::Cell || type == Token::Range)
00973 {
00974 d->length_namecell = token.text().length();
00975 canvas()->setChooseMode(true);
00976 }
00977 else
00978 {
00979 canvas()->setChooseMode(false);
00980 }
00981 }
00982 }
00983
00984
00985
00986 return true;
00987 }
00988
00989 void CellEditor::setUpdateChoice(bool state)
00990 {
00991 d->updateChoice = state;
00992 }
00993
00994 void CellEditor::updateChoice()
00995 {
00996
00997
00998 if (!d->updateChoice)
00999 return;
01000
01001
01002
01003 d->updatingChoice = true;
01004
01005 Selection* choice = d->canvas->choice();
01006
01007 if (choice->isEmpty())
01008 return;
01009
01010 if (!choice->activeElement())
01011 return;
01012
01013
01014 if (++choice->constBegin() == choice->constEnd())
01015 {
01016 }
01017
01018 QString name_cell = choice->activeSubRegionName();
01019
01020 Tokens tokens = d->highlighter->formulaTokens();
01021 uint start = 1;
01022 uint length = 0;
01023 if (!tokens.empty())
01024 {
01025 Token token = tokens[d->currentToken];
01026 Token::Type type = token.type();
01027 if (type == Token::Cell || type == Token::Range)
01028 {
01029 start = token.pos() + 1;
01030 length = token.text().length();
01031 }
01032 else
01033 {
01034 start = token.pos() + token.text().length() + 1;
01035 }
01036 }
01037
01038 d->length_namecell = name_cell.length();
01039 d->length_text = text().length();
01040
01041
01042 QString oldText = text();
01043 QString newText = oldText.left(start) + name_cell + oldText.right(d->length_text - start - length);
01044
01045 setCheckChoice( false );
01046 setText( newText );
01047 setCheckChoice( true );
01048 setCursorPosition( start + d->length_namecell );
01049
01050 d->canvas->view()->editWidget()->setText( newText );
01051
01052
01053
01054 d->updatingChoice = false;
01055 }
01056
01057 void CellEditor::resizeEvent( QResizeEvent* )
01058 {
01059 d->textEdit->setGeometry( 0, 0, width(), height() );
01060 }
01061
01062 void CellEditor::handleKeyPressEvent( QKeyEvent * _ev )
01063 {
01064 if (_ev->key() == Qt::Key_F4)
01065 {
01066 if (d->textEdit == 0)
01067 {
01068 QApplication::sendEvent( d->textEdit, _ev );
01069 return;
01070 }
01071
01072 QRegExp exp("(\\$?)([a-zA-Z]+)(\\$?)([0-9]+)$");
01073
01074 int para,cur;
01075 d->textEdit->getCursorPosition(¶,&cur);
01076
01077 QString tmp, tmp2;
01078 int n = -1;
01079
01080
01081
01082 unsigned i;
01083 for( i = 0; i < 10; i++ )
01084 {
01085 tmp = d->textEdit->text().left( cur+i );
01086 tmp2 = d->textEdit->text().right( d->textEdit->text().length() - cur - i );
01087
01088 n = exp.search(tmp);
01089 if( n >= 0 ) break;
01090 }
01091
01092 if (n == -1) return;
01093
01094 QString newPart;
01095 if ((exp.cap(1) == "$") && (exp.cap(3) == "$"))
01096 newPart = "$" + exp.cap(2) + exp.cap(4);
01097 else if ((exp.cap(1) != "$") && (exp.cap(3) != "$"))
01098 newPart = "$" + exp.cap(2) + "$" + exp.cap(4);
01099 else if ((exp.cap(1) == "$") && (exp.cap(3) != "$"))
01100 newPart = exp.cap(2) + "$" + exp.cap(4);
01101 else if ((exp.cap(1) != "$") && (exp.cap(3) == "$"))
01102 newPart = exp.cap(2) + exp.cap(4);
01103
01104 QString newString = tmp.left(n);
01105 newString += newPart;
01106 cur = newString.length() - i;
01107 newString += tmp2;
01108
01109 d->textEdit->setText(newString);
01110 d->textEdit->setCursorPosition( 0, cur );
01111
01112 _ev->accept();
01113
01114 return;
01115 }
01116
01117
01118 QApplication::sendEvent( d->textEdit, _ev );
01119 }
01120
01121 void CellEditor::handleIMEvent( QIMEvent * _ev )
01122 {
01123
01124 QApplication::sendEvent( d->textEdit, _ev );
01125 }
01126
01127 QString CellEditor::text() const
01128 {
01129 return d->textEdit->text();
01130 }
01131
01132 void CellEditor::setText(QString text)
01133 {
01134 d->textEdit->setText(text);
01135
01136
01137
01138
01139 d->textEdit->setCursorPosition(0,text.length());
01140
01141 if (d->fontLength == 0)
01142 {
01143 QFontMetrics fm( d->textEdit->font() );
01144 d->fontLength = fm.width('x');
01145 }
01146 }
01147
01148 int CellEditor::cursorPosition() const
01149 {
01150 int para,cur;
01151 d->textEdit->getCursorPosition(¶,&cur);
01152 return cur;
01153
01154 }
01155
01156 void CellEditor::setCursorPosition( int pos )
01157 {
01158 d->textEdit->setCursorPosition(0,pos);
01159 canvas()->view()->editWidget()->setCursorPosition( pos );
01160 }
01161
01162 bool CellEditor::eventFilter( QObject* o, QEvent* e )
01163 {
01164
01165 if ( o != d->textEdit )
01166 return false;
01167 if ( e->type() == QEvent::FocusOut )
01168 {
01169 canvas()->setLastEditorWithFocus( Canvas::CellEditor );
01170 return false;
01171 }
01172
01173 if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease )
01174 {
01175 QKeyEvent* k = (QKeyEvent*)e;
01176 if (!(k->state() & Qt::ShiftButton) || canvas()->chooseMode())
01177 {
01178
01179
01180 if (k->key() == Key_Return || k->key() == Key_Enter)
01181 {
01182 kdDebug() << "CellEditor::eventFilter: canvas()->endChoose();" << endl;
01183 canvas()->endChoose();
01184 }
01185
01186
01187
01188 if ( k->key() == Key_Up || k->key() == Key_Down ||
01189 k->key() == Key_Next || k->key() == Key_Prior ||
01190 k->key() == Key_Escape || k->key() == Key_Tab ||
01191 k->key() == Key_Return || k->key() == Key_Enter)
01192 {
01193
01194 QApplication::sendEvent( parent(), e );
01195 return true;
01196 }
01197 }
01198
01199 if ( e->type() == QEvent::KeyPress && !k->text().isEmpty() )
01200 {
01201 canvas()->setChooseMode(false);
01202 }
01203
01204
01205
01206
01207
01208
01209 if ( ((k->key() == Qt::Key_Left) || (k->key() == Qt::Key_Right)) && (!d->captureAllKeyEvents)) {
01210 QApplication::sendEvent (parent(), e);
01211 return true;
01212 }
01213 }
01214
01215 return false;
01216 }
01217
01218 void CellEditor::setCursorToRange(uint pos)
01219 {
01220
01221
01222 d->updatingChoice = true;
01223 uint counter = 0;
01224 Tokens tokens = d->highlighter->formulaTokens();
01225 for (uint i = 0; i < tokens.count(); ++i)
01226 {
01227 Token token = tokens[i];
01228 Token::Type type = token.type();
01229 if (type == Token::Cell || type == Token::Range)
01230 {
01231 if (counter == pos)
01232 {
01233 setCursorPosition(token.pos() + token.text().length() + 1);
01234 }
01235 counter++;
01236 }
01237 }
01238 d->updatingChoice = false;
01239 }
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249 ComboboxLocationEditWidget::ComboboxLocationEditWidget( QWidget * _parent,
01250 View * _view )
01251 : KComboBox( _parent, "ComboboxLocationEditWidget" )
01252 {
01253 m_locationWidget = new LocationEditWidget( _parent, _view );
01254 setLineEdit( m_locationWidget );
01255 insertItem( "" );
01256
01257 QValueList<Reference>::Iterator it;
01258 QValueList<Reference> area = _view->doc()->listArea();
01259 for ( it = area.begin(); it != area.end(); ++it )
01260 slotAddAreaName( (*it).ref_name);
01261 connect( this, SIGNAL( activated ( const QString & ) ), m_locationWidget, SLOT( slotActivateItem() ) );
01262 }
01263
01264
01265 void ComboboxLocationEditWidget::slotAddAreaName( const QString &_name)
01266 {
01267 insertItem( _name );
01268 m_locationWidget->addCompletionItem( _name );
01269 }
01270
01271 void ComboboxLocationEditWidget::slotRemoveAreaName( const QString &_name )
01272 {
01273 for ( int i = 0; i<count(); i++ )
01274 {
01275 if ( text(i)==_name )
01276 {
01277 removeItem( i );
01278 break;
01279 }
01280 }
01281 m_locationWidget->removeCompletionItem( _name );
01282 }
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292 LocationEditWidget::LocationEditWidget( QWidget * _parent,
01293 View * _view )
01294 : KLineEdit( _parent, "LocationEditWidget" ),
01295 m_pView(_view)
01296 {
01297 setCompletionObject( &completionList,true );
01298 setCompletionMode(KGlobalSettings::CompletionAuto );
01299 }
01300
01301 void LocationEditWidget::addCompletionItem( const QString &_item )
01302 {
01303 kdDebug()<<" LocationEditWidget::addCompletionItem add :"<<_item<<endl;
01304 if ( completionList.items().contains( _item) == 0 )
01305 {
01306 completionList.addItem( _item );
01307 kdDebug()<<" _utem :"<<_item<<endl;
01308 kdDebug()<<" completionList.items().count()"<<completionList.items().count()<<endl;
01309 }
01310 }
01311
01312 void LocationEditWidget::removeCompletionItem( const QString &_item )
01313 {
01314 completionList.removeItem( _item );
01315 }
01316
01317 void LocationEditWidget::slotActivateItem()
01318 {
01319 activateItem();
01320 }
01321
01322 bool LocationEditWidget::activateItem()
01323 {
01324 QString ltext = text();
01325 QString tmp = ltext.lower();
01326 QValueList<Reference>::Iterator it;
01327 QValueList<Reference> area = m_pView->doc()->listArea();
01328 for ( it = area.begin(); it != area.end(); ++it )
01329 {
01330 if ((*it).ref_name == tmp)
01331 {
01332 QString tmp = (*it).sheet_name;
01333 tmp += "!";
01334 tmp += util_rangeName((*it).rect);
01335 m_pView->selectionInfo()->initialize( Region(m_pView,tmp) );
01336 return true;
01337 }
01338 }
01339
01340
01341
01342 int pos = ltext.find('!');
01343 if ( pos !=- 1 )
01344 tmp = ltext.left(pos)+ltext.mid(pos).upper();
01345 else
01346 tmp = ltext.upper();
01347
01348
01349 if ( ltext.contains( ':' ) )
01350 m_pView->selectionInfo()->initialize( Region(m_pView,tmp) );
01351
01352 else
01353 {
01354 Region region(m_pView,tmp);
01355 bool validName = true;
01356 for (unsigned int i = 0; i < ltext.length(); ++i)
01357 {
01358 if (!ltext[i].isLetter())
01359 {
01360 validName = false;
01361 break;
01362 }
01363 }
01364 if ( !region.isValid() && validName)
01365 {
01366 QRect rect( m_pView->selectionInfo()->selection() );
01367 Sheet * t = m_pView->activeSheet();
01368
01369
01370 m_pView->doc()->addAreaName(rect, ltext.lower(), t->sheetName());
01371 }
01372
01373 if (!validName)
01374 {
01375 m_pView->selectionInfo()->initialize(region);
01376 }
01377 }
01378
01379
01380 m_pView->canvasWidget()->setFocus();
01381 return false;
01382 }
01383
01384
01385 void LocationEditWidget::keyPressEvent( QKeyEvent * _ev )
01386 {
01387
01388
01389 if ( _ev->state() & ( Qt::AltButton | Qt::ControlButton ) )
01390 {
01391 QLineEdit::keyPressEvent( _ev );
01392
01393 _ev->accept();
01394
01395 return;
01396 }
01397
01398
01399 switch( _ev->key() )
01400 {
01401 case Key_Return:
01402 case Key_Enter:
01403 {
01404 if ( activateItem() )
01405 return;
01406 _ev->accept();
01407 }
01408 break;
01409
01410 case Key_Escape:
01411
01412 if ( m_pView->selectionInfo()->isSingular() ) {
01413 setText( Cell::columnName( m_pView->canvasWidget()->markerColumn() )
01414 + QString::number( m_pView->canvasWidget()->markerRow() ) );
01415 } else {
01416 setText( Cell::columnName( m_pView->selectionInfo()->lastRange().left() )
01417 + QString::number( m_pView->selectionInfo()->lastRange().top() )
01418 + ":"
01419 + Cell::columnName( m_pView->selectionInfo()->lastRange().right() )
01420 + QString::number( m_pView->selectionInfo()->lastRange().bottom() ) );
01421 }
01422 m_pView->canvasWidget()->setFocus();
01423 _ev->accept();
01424 break;
01425 default:
01426 QLineEdit::keyPressEvent( _ev );
01427
01428 _ev->accept();
01429 }
01430 }
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442 EditWidget::EditWidget( QWidget *_parent, Canvas *_canvas,
01443 QButton *cancelButton, QButton *okButton )
01444 : QLineEdit( _parent, "EditWidget" )
01445 {
01446 m_pCanvas = _canvas;
01447 Q_ASSERT(m_pCanvas != NULL);
01448
01449
01450 m_pCancelButton = cancelButton;
01451 m_pOkButton = okButton;
01452 isArray = false;
01453
01454 installEventFilter(m_pCanvas);
01455
01456 if ( !m_pCanvas->doc()->isReadWrite() || !m_pCanvas->activeSheet() )
01457 setEnabled( false );
01458
01459 QObject::connect( m_pCancelButton, SIGNAL( clicked() ),
01460 this, SLOT( slotAbortEdit() ) );
01461 QObject::connect( m_pOkButton, SIGNAL( clicked() ),
01462 this, SLOT( slotDoneEdit() ) );
01463
01464 setEditMode( false );
01465 }
01466
01467 void EditWidget::showEditWidget(bool _show)
01468 {
01469 if (_show)
01470 {
01471 m_pCancelButton->show();
01472 m_pOkButton->show();
01473 show();
01474 }
01475 else
01476 {
01477 m_pCancelButton->hide();
01478 m_pOkButton->hide();
01479 hide();
01480 }
01481 }
01482
01483 void EditWidget::slotAbortEdit()
01484 {
01485 m_pCanvas->deleteEditor( false );
01486
01487 }
01488
01489 void EditWidget::slotDoneEdit()
01490 {
01491 m_pCanvas->deleteEditor( true , isArray);
01492 isArray = false;
01493
01494 }
01495
01496 void EditWidget::keyPressEvent ( QKeyEvent* _ev )
01497 {
01498
01499 if (( ( _ev->state() & ( Qt::AltButton | Qt::ControlButton ) )
01500 || ( _ev->state() & Qt::ShiftButton )
01501 || ( _ev->key() == Key_Shift )
01502 || ( _ev->key() == Key_Control ) )
01503 && (_ev->key() != Key_Return) && (_ev->key() != Key_Enter))
01504 {
01505 QLineEdit::keyPressEvent( _ev );
01506 _ev->accept();
01507 return;
01508 }
01509
01510 if ( !m_pCanvas->doc()->isReadWrite() )
01511 return;
01512
01513 if ( !m_pCanvas->editor() )
01514 {
01515
01516 m_pCanvas->createEditor( Canvas::CellEditor,false );
01517 }
01518 CellEditor * cellEditor = (CellEditor*) m_pCanvas->editor();
01519
01520 switch ( _ev->key() )
01521 {
01522 case Key_Down:
01523 case Key_Up:
01524 case Key_Return:
01525 case Key_Enter:
01526 cellEditor->setText( text());
01527
01528
01529
01530
01531
01532 isArray = (_ev->state() & Qt::AltButton) &&
01533 (_ev->state() & Qt::ControlButton);
01534 slotDoneEdit();
01535 m_pCanvas->view()->updateEditWidget();
01536 _ev->accept();
01537 break;
01538 case Key_F2:
01539 cellEditor->setFocus();
01540 cellEditor->setText( text());
01541 cellEditor->setCursorPosition(cursorPosition());
01542 break;
01543 default:
01544
01545 QLineEdit::keyPressEvent( _ev );
01546
01547 setFocus();
01548 cellEditor->setCheckChoice( false );
01549 cellEditor->setText( text() );
01550 cellEditor->setCheckChoice( true );
01551 cellEditor->setCursorPosition( cursorPosition() );
01552 }
01553 }
01554
01555 void EditWidget::setEditMode( bool mode )
01556 {
01557 m_pCancelButton->setEnabled(mode);
01558 m_pOkButton->setEnabled(mode);
01559 }
01560
01561 void EditWidget::focusOutEvent( QFocusEvent* ev )
01562 {
01563
01564
01565 m_pCanvas->setLastEditorWithFocus( Canvas::EditWidget );
01566
01567 QLineEdit::focusOutEvent( ev );
01568 }
01569
01570 void EditWidget::setText( const QString& t )
01571 {
01572 if ( t == text() )
01573 return;
01574
01575 QLineEdit::setText( t );
01576 }
01577
01578
01579
01580 #include "kspread_editors.moc"