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 disconnect( d->canvas->choice(), SIGNAL(changed(const Region&)),
00747 d->canvas->view(), SLOT(slotScrollChoice(const Region&)) );
00748 d->canvas->doc()->emitBeginOperation();
00749 setUpdateChoice(false);
00750
00751 Tokens tokens = d->highlighter->formulaTokens();
00752 d->canvas->choice()->update();
00753 d->canvas->choice()->clear();
00754 Region tmpRegion;
00755 Region::ConstIterator it;
00756
00757
00758
00759
00760 QValueList<Region> alreadyUsedRegions;
00761
00762 for (uint i = 0; i < tokens.count(); ++i)
00763 {
00764 Token token = tokens[i];
00765 Token::Type type = token.type();
00766 if (type == Token::Cell || type == Token::Range)
00767 {
00768 Region region(d->canvas->view(), token.text());
00769 it = region.constBegin();
00770
00771 if (!alreadyUsedRegions.contains(region))
00772 {
00773 QRect r=(*it)->rect();
00774
00775 if (d->canvas->choice()->isEmpty())
00776 d->canvas->choice()->initialize((*it)->rect(), (*it)->sheet());
00777 else
00778 d->canvas->choice()->extend((*it)->rect(), (*it)->sheet());
00779
00780 alreadyUsedRegions.append(region);
00781 }
00782 }
00783 }
00784 setUpdateChoice(true);
00785 d->canvas->doc()->emitEndOperation(*d->canvas->choice());
00786 connect( d->canvas->choice(), SIGNAL(changed(const Region&)),
00787 d->canvas->view(), SLOT(slotScrollChoice(const Region&)) );
00788 }
00789 }
00790 }
00791
00792 void CellEditor::slotTextCursorChanged(QTextCursor* cursor)
00793 {
00794 QTextStringChar *chr = cursor->paragraph()->at( cursor->index() );
00795 int h = cursor->paragraph()->lineHeightOfChar( cursor->index() );
00796 int x = cursor->paragraph()->rect().x() + chr->x;
00797 int y, dummy;
00798 cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y );
00799 y += cursor->paragraph()->rect().y();
00800
00801 d->globalCursorPos = d->textEdit->mapToGlobal( d->textEdit-> contentsToViewport( QPoint( x, y + h ) ) );
00802 }
00803
00804 void CellEditor::cut()
00805 {
00806 d->textEdit->cut();
00807 }
00808
00809 void CellEditor::paste()
00810 {
00811 d->textEdit->paste();
00812 }
00813
00814 void CellEditor::copy()
00815 {
00816 d->textEdit->copy();
00817 }
00818
00819 void CellEditor::setEditorFont(QFont const & font, bool updateSize)
00820 {
00821 QFont tmpFont( font );
00822 tmpFont.setPointSizeFloat( 0.01 * canvas()->doc()->zoom() * tmpFont.pointSizeFloat() );
00823 d->textEdit->setFont( tmpFont );
00824
00825 if (updateSize)
00826 {
00827 QFontMetrics fm( d->textEdit->font() );
00828 d->fontLength = fm.width('x');
00829
00830 int mw = fm.width( d->textEdit->text() ) + d->fontLength;
00831
00832 if (mw < width())
00833 mw = width();
00834
00835 int mh = fm.height();
00836 if (mh < height())
00837 mh = height();
00838
00839 setGeometry(x(), y(), mw, mh);
00840 }
00841 }
00842
00843 void CellEditor::slotCompletionModeChanged(KGlobalSettings::Completion _completion)
00844 {
00845 canvas()->view()->doc()->setCompletionMode( _completion );
00846 }
00847
00848 void CellEditor::slotTextChanged()
00849 {
00850
00851
00852
00853 QString t = text();
00854
00855 if (t.length() > d->length)
00856 {
00857 d->length = t.length();
00858
00859 QFontMetrics fm(d->textEdit->font());
00860
00861 int requiredWidth = fm.width(t) + (2*fm.width('x'));
00862
00863
00864
00865
00866
00867 if (d->textEdit->wordWrap() == QTextEdit::NoWrap)
00868 {
00869 if (requiredWidth > width())
00870 {
00871 if (t.isRightToLeft())
00872 {
00873 setGeometry(x() - requiredWidth + width(), y(), requiredWidth,height());
00874 }
00875 else
00876 {
00877 setGeometry(x(), y(), requiredWidth,height());
00878 }
00879 }
00880 }
00881 else
00882 {
00883 int requiredHeight = d->textEdit->heightForWidth(width());
00884
00885 if (requiredHeight > height())
00886 {
00887 setGeometry(x(), y(), width(), requiredHeight);
00888 }
00889 }
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908 }
00909
00910 if ( (cell()->formatType()) == Percentage_format )
00911 {
00912 if ( (t.length() == 1) && t[0].isDigit() )
00913 {
00914 QString tmp = t + " %";
00915 d->textEdit->setText(tmp);
00916 d->textEdit->setCursorPosition(0,1);
00917 return;
00918 }
00919 }
00920
00921 canvas()->view()->editWidget()->setText( t );
00922
00923 }
00924
00925 void CellEditor::setCheckChoice(bool state)
00926 {
00927 d->checkChoice = state;
00928 }
00929
00930 bool CellEditor::checkChoice()
00931 {
00932 if (!d->checkChoice)
00933 return false;
00934
00935
00936
00937
00938 d->length_namecell = 0;
00939 d->currentToken = 0;
00940
00941 QString text = d->textEdit->text();
00942 if ( text[0] != '=' )
00943 {
00944 canvas()->setChooseMode(false);
00945 }
00946 else
00947 {
00948 int para, cur;
00949 d->textEdit->getCursorPosition(¶, &cur);
00950
00951 Tokens tokens = d->highlighter->formulaTokens();
00952
00953
00954 if (tokens.count() < 1)
00955 {
00956 canvas()->startChoose();
00957 }
00958 else
00959 {
00960 Token token;
00961 for (uint i = 0; i < tokens.count(); ++i)
00962 {
00963 if (tokens[i].pos() >= cur - 1)
00964 {
00965 break;
00966 }
00967 token = tokens[i];
00968 d->currentToken = i;
00969 }
00970
00971 Token::Type type = token.type();
00972 if (type == Token::Operator && token.asOperator() != Token::RightPar)
00973 {
00974 canvas()->setChooseMode(true);
00975 }
00976 else if (type == Token::Cell || type == Token::Range)
00977 {
00978 d->length_namecell = token.text().length();
00979 canvas()->setChooseMode(true);
00980 }
00981 else
00982 {
00983 canvas()->setChooseMode(false);
00984 }
00985 }
00986 }
00987
00988
00989
00990 return true;
00991 }
00992
00993 void CellEditor::setUpdateChoice(bool state)
00994 {
00995 d->updateChoice = state;
00996 }
00997
00998 void CellEditor::updateChoice()
00999 {
01000
01001
01002 if (!d->updateChoice)
01003 return;
01004
01005
01006
01007 d->updatingChoice = true;
01008
01009 Selection* choice = d->canvas->choice();
01010
01011 if (choice->isEmpty())
01012 return;
01013
01014 if (!choice->activeElement())
01015 return;
01016
01017
01018 if (++choice->constBegin() == choice->constEnd())
01019 {
01020 }
01021
01022 QString name_cell = choice->activeSubRegionName();
01023
01024 Tokens tokens = d->highlighter->formulaTokens();
01025 uint start = 1;
01026 uint length = 0;
01027 if (!tokens.empty())
01028 {
01029 Token token = tokens[d->currentToken];
01030 Token::Type type = token.type();
01031 if (type == Token::Cell || type == Token::Range)
01032 {
01033 start = token.pos() + 1;
01034 length = token.text().length();
01035 }
01036 else
01037 {
01038 start = token.pos() + token.text().length() + 1;
01039 }
01040 }
01041
01042 d->length_namecell = name_cell.length();
01043 d->length_text = text().length();
01044
01045
01046 QString oldText = text();
01047 QString newText = oldText.left(start) + name_cell + oldText.right(d->length_text - start - length);
01048
01049 setCheckChoice( false );
01050 setText( newText );
01051 setCheckChoice( true );
01052 setCursorPosition( start + d->length_namecell );
01053
01054 d->canvas->view()->editWidget()->setText( newText );
01055
01056
01057
01058 d->updatingChoice = false;
01059 }
01060
01061 void CellEditor::resizeEvent( QResizeEvent* )
01062 {
01063 d->textEdit->setGeometry( 0, 0, width(), height() );
01064 }
01065
01066 void CellEditor::handleKeyPressEvent( QKeyEvent * _ev )
01067 {
01068 if (_ev->key() == Qt::Key_F4)
01069 {
01070 if (d->textEdit == 0)
01071 {
01072 QApplication::sendEvent( d->textEdit, _ev );
01073 return;
01074 }
01075
01076 QRegExp exp("(\\$?)([a-zA-Z]+)(\\$?)([0-9]+)$");
01077
01078 int para,cur;
01079 d->textEdit->getCursorPosition(¶,&cur);
01080
01081 QString tmp, tmp2;
01082 int n = -1;
01083
01084
01085
01086 unsigned i;
01087 for( i = 0; i < 10; i++ )
01088 {
01089 tmp = d->textEdit->text().left( cur+i );
01090 tmp2 = d->textEdit->text().right( d->textEdit->text().length() - cur - i );
01091
01092 n = exp.search(tmp);
01093 if( n >= 0 ) break;
01094 }
01095
01096 if (n == -1) return;
01097
01098 QString newPart;
01099 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 else if ((exp.cap(1) == "$") && (exp.cap(3) != "$"))
01104 newPart = exp.cap(2) + "$" + exp.cap(4);
01105 else if ((exp.cap(1) != "$") && (exp.cap(3) == "$"))
01106 newPart = exp.cap(2) + exp.cap(4);
01107
01108 QString newString = tmp.left(n);
01109 newString += newPart;
01110 cur = newString.length() - i;
01111 newString += tmp2;
01112
01113 d->textEdit->setText(newString);
01114 d->textEdit->setCursorPosition( 0, cur );
01115
01116 _ev->accept();
01117
01118 return;
01119 }
01120
01121
01122 QApplication::sendEvent( d->textEdit, _ev );
01123 }
01124
01125 void CellEditor::handleIMEvent( QIMEvent * _ev )
01126 {
01127
01128 QApplication::sendEvent( d->textEdit, _ev );
01129 }
01130
01131 QString CellEditor::text() const
01132 {
01133 return d->textEdit->text();
01134 }
01135
01136 void CellEditor::setText(QString text)
01137 {
01138 d->textEdit->setText(text);
01139
01140
01141
01142
01143 d->textEdit->setCursorPosition(0,text.length());
01144
01145 if (d->fontLength == 0)
01146 {
01147 QFontMetrics fm( d->textEdit->font() );
01148 d->fontLength = fm.width('x');
01149 }
01150 }
01151
01152 int CellEditor::cursorPosition() const
01153 {
01154 int para,cur;
01155 d->textEdit->getCursorPosition(¶,&cur);
01156 return cur;
01157
01158 }
01159
01160 void CellEditor::setCursorPosition( int pos )
01161 {
01162 d->textEdit->setCursorPosition(0,pos);
01163 canvas()->view()->editWidget()->setCursorPosition( pos );
01164 }
01165
01166 bool CellEditor::eventFilter( QObject* o, QEvent* e )
01167 {
01168
01169 if ( o != d->textEdit )
01170 return false;
01171 if ( e->type() == QEvent::FocusOut )
01172 {
01173 canvas()->setLastEditorWithFocus( Canvas::CellEditor );
01174 return false;
01175 }
01176
01177 if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease )
01178 {
01179 QKeyEvent* k = (QKeyEvent*)e;
01180 if (!(k->state() & Qt::ShiftButton) || canvas()->chooseMode())
01181 {
01182
01183
01184 if (k->key() == Key_Return || k->key() == Key_Enter)
01185 {
01186 kdDebug() << "CellEditor::eventFilter: canvas()->endChoose();" << endl;
01187 canvas()->endChoose();
01188 }
01189
01190
01191
01192 if ( k->key() == Key_Up || k->key() == Key_Down ||
01193 k->key() == Key_Next || k->key() == Key_Prior ||
01194 k->key() == Key_Escape || k->key() == Key_Tab ||
01195 k->key() == Key_Return || k->key() == Key_Enter)
01196 {
01197
01198 QApplication::sendEvent( parent(), e );
01199 return true;
01200 }
01201 }
01202 else if ( k->state() & Qt::ShiftButton && ( k->key() == Key_Return || k->key() == Key_Enter ) )
01203 {
01204
01205 d->cell->format()->setMultiRow( true );
01206 }
01207
01208 if ( e->type() == QEvent::KeyPress && !k->text().isEmpty() )
01209 {
01210 canvas()->setChooseMode(false);
01211 }
01212
01213
01214
01215
01216
01217
01218 if ( ((k->key() == Qt::Key_Left) || (k->key() == Qt::Key_Right)) && (!d->captureAllKeyEvents)) {
01219 QApplication::sendEvent (parent(), e);
01220 return true;
01221 }
01222 }
01223
01224 return false;
01225 }
01226
01227 void CellEditor::setCursorToRange(uint pos)
01228 {
01229
01230
01231 d->updatingChoice = true;
01232 uint counter = 0;
01233 Tokens tokens = d->highlighter->formulaTokens();
01234 for (uint i = 0; i < tokens.count(); ++i)
01235 {
01236 Token token = tokens[i];
01237 Token::Type type = token.type();
01238 if (type == Token::Cell || type == Token::Range)
01239 {
01240 if (counter == pos)
01241 {
01242 setCursorPosition(token.pos() + token.text().length() + 1);
01243 }
01244 counter++;
01245 }
01246 }
01247 d->updatingChoice = false;
01248 }
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258 ComboboxLocationEditWidget::ComboboxLocationEditWidget( QWidget * _parent,
01259 View * _view )
01260 : KComboBox( _parent, "ComboboxLocationEditWidget" )
01261 {
01262 m_locationWidget = new LocationEditWidget( _parent, _view );
01263 setLineEdit( m_locationWidget );
01264 insertItem( "" );
01265
01266 QValueList<Reference>::Iterator it;
01267 QValueList<Reference> area = _view->doc()->listArea();
01268 for ( it = area.begin(); it != area.end(); ++it )
01269 slotAddAreaName( (*it).ref_name);
01270 connect( this, SIGNAL( activated ( const QString & ) ), m_locationWidget, SLOT( slotActivateItem() ) );
01271 }
01272
01273
01274 void ComboboxLocationEditWidget::slotAddAreaName( const QString &_name)
01275 {
01276 insertItem( _name );
01277 m_locationWidget->addCompletionItem( _name );
01278 }
01279
01280 void ComboboxLocationEditWidget::slotRemoveAreaName( const QString &_name )
01281 {
01282 for ( int i = 0; i<count(); i++ )
01283 {
01284 if ( text(i)==_name )
01285 {
01286 removeItem( i );
01287 break;
01288 }
01289 }
01290 m_locationWidget->removeCompletionItem( _name );
01291 }
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301 LocationEditWidget::LocationEditWidget( QWidget * _parent,
01302 View * _view )
01303 : KLineEdit( _parent, "LocationEditWidget" ),
01304 m_pView(_view)
01305 {
01306 setCompletionObject( &completionList,true );
01307 setCompletionMode(KGlobalSettings::CompletionAuto );
01308 }
01309
01310 void LocationEditWidget::addCompletionItem( const QString &_item )
01311 {
01312 kdDebug()<<" LocationEditWidget::addCompletionItem add :"<<_item<<endl;
01313 if ( completionList.items().contains( _item) == 0 )
01314 {
01315 completionList.addItem( _item );
01316 kdDebug()<<" _utem :"<<_item<<endl;
01317 kdDebug()<<" completionList.items().count()"<<completionList.items().count()<<endl;
01318 }
01319 }
01320
01321 void LocationEditWidget::removeCompletionItem( const QString &_item )
01322 {
01323 completionList.removeItem( _item );
01324 }
01325
01326 void LocationEditWidget::slotActivateItem()
01327 {
01328 activateItem();
01329 }
01330
01331 bool LocationEditWidget::activateItem()
01332 {
01333 QString ltext = text();
01334 QString tmp = ltext.lower();
01335 QValueList<Reference>::Iterator it;
01336 QValueList<Reference> area = m_pView->doc()->listArea();
01337 for ( it = area.begin(); it != area.end(); ++it )
01338 {
01339 if ((*it).ref_name == tmp)
01340 {
01341 QString tmp = (*it).sheet_name;
01342 tmp += "!";
01343 tmp += util_rangeName((*it).rect);
01344 m_pView->selectionInfo()->initialize( Region(m_pView,tmp) );
01345 return true;
01346 }
01347 }
01348
01349
01350
01351 int pos = ltext.find('!');
01352 if ( pos !=- 1 )
01353 tmp = ltext.left(pos)+ltext.mid(pos).upper();
01354 else
01355 tmp = ltext.upper();
01356
01357
01358 if ( ltext.contains( ':' ) )
01359 m_pView->selectionInfo()->initialize( Region(m_pView,tmp) );
01360
01361 else
01362 {
01363 Region region(m_pView,tmp);
01364 bool validName = true;
01365 for (unsigned int i = 0; i < ltext.length(); ++i)
01366 {
01367 if (!ltext[i].isLetter())
01368 {
01369 validName = false;
01370 break;
01371 }
01372 }
01373 if ( !region.isValid() && validName)
01374 {
01375 QRect rect( m_pView->selectionInfo()->selection() );
01376 Sheet * t = m_pView->activeSheet();
01377
01378
01379 m_pView->doc()->addAreaName(rect, ltext.lower(), t->sheetName());
01380 }
01381
01382 if (!validName)
01383 {
01384 m_pView->selectionInfo()->initialize(region);
01385 }
01386 }
01387
01388
01389 m_pView->canvasWidget()->setFocus();
01390 return false;
01391 }
01392
01393
01394 void LocationEditWidget::keyPressEvent( QKeyEvent * _ev )
01395 {
01396
01397
01398 if ( _ev->state() & ( Qt::AltButton | Qt::ControlButton ) )
01399 {
01400 QLineEdit::keyPressEvent( _ev );
01401
01402 _ev->accept();
01403
01404 return;
01405 }
01406
01407
01408 switch( _ev->key() )
01409 {
01410 case Key_Return:
01411 case Key_Enter:
01412 {
01413 if ( activateItem() )
01414 return;
01415 _ev->accept();
01416 }
01417 break;
01418
01419 case Key_Escape:
01420
01421 if ( m_pView->selectionInfo()->isSingular() ) {
01422 setText( Cell::columnName( m_pView->canvasWidget()->markerColumn() )
01423 + QString::number( m_pView->canvasWidget()->markerRow() ) );
01424 } else {
01425 setText( Cell::columnName( m_pView->selectionInfo()->lastRange().left() )
01426 + QString::number( m_pView->selectionInfo()->lastRange().top() )
01427 + ":"
01428 + Cell::columnName( m_pView->selectionInfo()->lastRange().right() )
01429 + QString::number( m_pView->selectionInfo()->lastRange().bottom() ) );
01430 }
01431 m_pView->canvasWidget()->setFocus();
01432 _ev->accept();
01433 break;
01434 default:
01435 QLineEdit::keyPressEvent( _ev );
01436
01437 _ev->accept();
01438 }
01439 }
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451 EditWidget::EditWidget( QWidget *_parent, Canvas *_canvas,
01452 QButton *cancelButton, QButton *okButton )
01453 : QLineEdit( _parent, "EditWidget" )
01454 {
01455 m_pCanvas = _canvas;
01456 Q_ASSERT(m_pCanvas != NULL);
01457
01458
01459 m_pCancelButton = cancelButton;
01460 m_pOkButton = okButton;
01461 isArray = false;
01462
01463 installEventFilter(m_pCanvas);
01464
01465 if ( !m_pCanvas->doc()->isReadWrite() || !m_pCanvas->activeSheet() )
01466 setEnabled( false );
01467
01468 QObject::connect( m_pCancelButton, SIGNAL( clicked() ),
01469 this, SLOT( slotAbortEdit() ) );
01470 QObject::connect( m_pOkButton, SIGNAL( clicked() ),
01471 this, SLOT( slotDoneEdit() ) );
01472
01473 setEditMode( false );
01474 }
01475
01476 void EditWidget::showEditWidget(bool _show)
01477 {
01478 if (_show)
01479 {
01480 m_pCancelButton->show();
01481 m_pOkButton->show();
01482 show();
01483 }
01484 else
01485 {
01486 m_pCancelButton->hide();
01487 m_pOkButton->hide();
01488 hide();
01489 }
01490 }
01491
01492 void EditWidget::slotAbortEdit()
01493 {
01494 m_pCanvas->deleteEditor( false );
01495
01496 }
01497
01498 void EditWidget::slotDoneEdit()
01499 {
01500 m_pCanvas->deleteEditor( true , isArray);
01501 isArray = false;
01502
01503 }
01504
01505 void EditWidget::keyPressEvent ( QKeyEvent* _ev )
01506 {
01507
01508 if (( ( _ev->state() & ( Qt::AltButton | Qt::ControlButton ) )
01509 || ( _ev->state() & Qt::ShiftButton )
01510 || ( _ev->key() == Key_Shift )
01511 || ( _ev->key() == Key_Control ) )
01512 && (_ev->key() != Key_Return) && (_ev->key() != Key_Enter))
01513 {
01514 QLineEdit::keyPressEvent( _ev );
01515 _ev->accept();
01516 return;
01517 }
01518
01519 if ( !m_pCanvas->doc()->isReadWrite() )
01520 return;
01521
01522 if ( !m_pCanvas->editor() )
01523 {
01524
01525 m_pCanvas->createEditor( Canvas::CellEditor,false );
01526 }
01527 CellEditor * cellEditor = (CellEditor*) m_pCanvas->editor();
01528
01529 switch ( _ev->key() )
01530 {
01531 case Key_Down:
01532 case Key_Up:
01533 case Key_Return:
01534 case Key_Enter:
01535 cellEditor->setText( text());
01536
01537
01538
01539
01540
01541 isArray = (_ev->state() & Qt::AltButton) &&
01542 (_ev->state() & Qt::ControlButton);
01543 slotDoneEdit();
01544 m_pCanvas->view()->updateEditWidget();
01545 _ev->accept();
01546 break;
01547 case Key_F2:
01548 cellEditor->setFocus();
01549 cellEditor->setText( text());
01550 cellEditor->setCursorPosition(cursorPosition());
01551 break;
01552 default:
01553
01554 QLineEdit::keyPressEvent( _ev );
01555
01556 setFocus();
01557 cellEditor->setCheckChoice( false );
01558 cellEditor->setText( text() );
01559 cellEditor->setCheckChoice( true );
01560 cellEditor->setCursorPosition( cursorPosition() );
01561 }
01562 }
01563
01564 void EditWidget::setEditMode( bool mode )
01565 {
01566 m_pCancelButton->setEnabled(mode);
01567 m_pOkButton->setEnabled(mode);
01568 }
01569
01570 void EditWidget::focusOutEvent( QFocusEvent* ev )
01571 {
01572
01573
01574 m_pCanvas->setLastEditorWithFocus( Canvas::EditWidget );
01575
01576 QLineEdit::focusOutEvent( ev );
01577 }
01578
01579 void EditWidget::setText( const QString& t )
01580 {
01581 if ( t == text() )
01582 return;
01583
01584 QLineEdit::setText( t );
01585 }
01586
01587
01588
01589 #include "kspread_editors.moc"