kspread

kspread_editors.cpp
1/* This file is part of the KDE project
2
3 Copyright 1999-2006 The KSpread Team <koffice-devel@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include "kspread_editors.h"
22#include "kspread_canvas.h"
23#include "kspread_cell.h"
24#include "kspread_doc.h"
25#include "selection.h"
26#include "kspread_sheet.h"
27#include "kspread_view.h"
28#include "kspread_util.h"
29#include "formula.h"
30#include "functions.h"
31
32#include <tdelistbox.h>
33
34#include <tqapplication.h>
35#include <tqlistbox.h>
36#include <tqtimer.h>
37#include <tqlabel.h>
38#include <tqvbox.h>
39#include <tqvaluelist.h>
40#include <tqrichtext_p.h>
41
42//#include <klineedit.h>
43#include <ktextedit.h>
44#include <tqapplication.h>
45#include <tqbutton.h>
46#include <tqfont.h>
47#include <tqfontmetrics.h>
48#include <tqregexp.h>
49#include <kdebug.h>
50
51using namespace KSpread;
52
53
54
55/*****************************************************************************
56 *
57 * FormulaEditorHighlighter
58 *
59 ****************************************************************************/
60
61namespace KSpread
62{
63
64class FormulaEditorHighlighter::Private
65{
66public:
67 Private()
68 {
69 canvas = 0;
70 tokens = Tokens();
71 rangeCount = 0;
72 rangeChanged = false;
73 }
74
75 // source for cell reference checking
76 Canvas* canvas;
77 Tokens tokens;
78 uint rangeCount;
79 bool rangeChanged;
80};
81
82
84 : TQSyntaxHighlighter(textEdit)
85{
86 d = new Private();
87 d->canvas = canvas;
88}
89
90FormulaEditorHighlighter::~FormulaEditorHighlighter()
91{
92 delete d;
93}
94
95const Tokens& FormulaEditorHighlighter::formulaTokens() const
96{
97 return d->tokens;
98}
99
100int FormulaEditorHighlighter::highlightParagraph(const TQString& text, int /* endStateOfLastPara */)
101{
102 // reset syntax highlighting
103 setFormat(0, text.length(), TQt::black);
104
105 // save the old ones to identify range changes
106 Tokens oldTokens = d->tokens;
107
108 // interpret the text as formula
109 // we accept invalid/incomplete formulas
110 Formula f;
111 d->tokens = f.scan(text);
112
113 TQFont editorFont = textEdit()->currentFont();
114 TQFont font;
115
116 uint oldRangeCount = d->rangeCount;
117
118 d->rangeCount = 0;
119 TQValueList<TQColor> colors = d->canvas->choice()->colors();
120 TQValueList<Range> alreadyFoundRanges;
121
122 for (uint i = 0; i < d->tokens.count(); ++i)
123 {
124 Token token = d->tokens[i];
125 Token::Type type = token.type();
126
127 switch (type)
128 {
129 case Token::Cell:
130 case Token::Range:
131 {
132 // don't compare, if we have already found a change
133 if (!d->rangeChanged && i < oldTokens.count() && token.text() != oldTokens[i].text())
134 {
135 d->rangeChanged = true;
136 }
137
138 Range newRange( token.text() );
139
140 if (!alreadyFoundRanges.contains(newRange))
141 {
142 alreadyFoundRanges.append(newRange);
143 d->rangeCount++;
144 }
145 setFormat(token.pos() + 1, token.text().length(), colors[ alreadyFoundRanges.findIndex(newRange) % colors.size()] );
146 }
147 break;
148 case Token::Boolean: // True, False (also i18n-ized)
149/* font = TQFont(editorFont);
150 font.setBold(true);
151 setFormat(token.pos() + 1, token.text().length(), font);*/
152 break;
153 case Token::Identifier: // function name or named area*/
154/* font = TQFont(editorFont);
155 font.setBold(true);
156 setFormat(token.pos() + 1, token.text().length(), font);*/
157 break;
158
159 case Token::Unknown:
160 case Token::Integer: // 14, 3, 1977
161 case Token::Float: // 3.141592, 1e10, 5.9e-7
162 case Token::String: // "KOffice", "The quick brown fox..."
163 case Token::Operator: // +, *, /, -
164 {
165 switch (token.asOperator())
166 {
167 case Token::LeftPar:
168 case Token::RightPar:
169 //Check where this brace is in relation to the cursor and highlight it if necessary.
170 handleBrace( i );
171 break;
172 default:
173 break;
174 }
175 }
176 break;
177 }
178 }
179
180 if (oldRangeCount != d->rangeCount)
181 d->rangeChanged = true;
182
183 return 0;
184}
185
187{
188 int cursorParagraph;
189 int cursorPos;
190 const Token& token = d->tokens.at( index );
191
192 textEdit()->getCursorPosition( &cursorParagraph , &cursorPos );
193
194 int distance = cursorPos-token.pos();
195 int opType = token.asOperator();
196 bool highlightBrace=false;
197
198 //Check where the cursor is in relation to this left or right parenthesis token.
199 //Only one pair of braces should be highlighted at a time, and if the cursor
200 //is between two braces, the inner-most pair should be highlighted.
201
202 if ( opType == Token::LeftPar )
203 {
204 //If cursor is directly to the left of this left brace, highlight it
205 if ( distance == 1 )
206 highlightBrace=true;
207 else
208 //Cursor is directly to the right of this left brace, highlight it unless
209 //there is another left brace to the right (in which case that should be highlighted instead as it
210 //is the inner-most brace)
211 if (distance==2)
212 if ( (index == d->tokens.count()-1) || ( d->tokens.at(index+1).asOperator() != Token::LeftPar) )
213 highlightBrace=true;
214
215 }
216 else
217 {
218 //If cursor is directly to the right of this right brace, highlight it
219 if ( distance == 2 )
220 highlightBrace=true;
221 else
222 //Cursor is directly to the left of this right brace, so highlight it unless
223 //there is another right brace to the left (in which case that should be highlighted instead as it
224 //is the inner-most brace)
225 if ( distance == 1 )
226 if ( (index == 0) || (d->tokens.at(index-1).asOperator() != Token::RightPar) )
227 highlightBrace=true;
228 }
229
230 if (highlightBrace)
231 {
232 TQFont font = TQFont( textEdit()->currentFont() );
233 font.setBold(true);
234 setFormat(token.pos() + 1, token.text().length(), font);
235
236 int matching = findMatchingBrace( index );
237
238 if (matching != -1)
239 {
240 Token matchingBrace = d->tokens.at(matching);
241 setFormat( matchingBrace.pos() + 1 , matchingBrace.text().length() , font);
242 }
243 }
244}
245
247{
248 int depth=0;
249 int step=0;
250
251 Tokens tokens = d->tokens;
252
253 //If this is a left brace we need to step forwards through the text to find the matching right brace,
254 //otherwise, it is a right brace so we need to step backwards through the text to find the matching left
255 //brace.
256 if (tokens.at(pos).asOperator() == Token::LeftPar)
257 step = 1;
258 else
259 step = -1;
260
261 for (int index=pos ; (index >= 0) && (index < (int) tokens.count() ) ; index += step )
262 {
263 if (tokens.at(index).asOperator() == Token::LeftPar)
264 depth++;
265 if (tokens.at(index).asOperator() == Token::RightPar)
266 depth--;
267
268 if (depth == 0)
269 {
270 return index;
271 }
272 }
273
274 return -1;
275}
276
277uint FormulaEditorHighlighter::rangeCount() const
278{
279 return d->rangeCount;
280}
281
283{
284 return d->rangeChanged;
285}
286
288{
289 d->rangeChanged=false;
290}
291
292} // namespace KSpread
293
294
295
296/*****************************************************************************
297 *
298 * FunctionCompletion
299 *
300 ****************************************************************************/
301
302class FunctionCompletion::Private
303{
304public:
305 CellEditor* editor;
306 TQVBox *completionPopup;
307 TDEListBox *completionListBox;
308 TQLabel* hintLabel;
309};
310
311FunctionCompletion::FunctionCompletion( CellEditor* editor ):
312TQObject( editor )
313{
314 d = new Private;
315 d->editor = editor;
316 d->hintLabel = 0;
317
318 d->completionPopup = new TQVBox( editor->topLevelWidget(), 0, WType_Popup );
319 d->completionPopup->setFrameStyle( TQFrame::Box | TQFrame::Plain );
320 d->completionPopup->setLineWidth( 1 );
321 d->completionPopup->installEventFilter( this );
322 d->completionPopup->setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Minimum);
323
324 d->completionListBox = new TDEListBox( d->completionPopup );
325 d->completionPopup->setFocusProxy( d->completionListBox );
326 d->completionListBox->setFrameStyle( TQFrame::NoFrame );
327 d->completionListBox->setVariableWidth( true );
328 d->completionListBox->installEventFilter( this );
329 connect( d->completionListBox, TQ_SIGNAL(selected(const TQString&)), this,
330 TQ_SLOT(itemSelected(const TQString&)) );
331 connect( d->completionListBox, TQ_SIGNAL(highlighted(const TQString&)), this,
332 TQ_SLOT(itemSelected(const TQString&)) );
333
334 d->hintLabel = new TQLabel( 0, "autocalc", TQt::WStyle_StaysOnTop |
335 TQt::WStyle_Customize | TQt::WStyle_NoBorder | TQt::WStyle_Tool | TQt::WX11BypassWM );
336 d->hintLabel->setFrameStyle( TQFrame::Plain | TQFrame::Box );
337 d->hintLabel->setPalette( TQToolTip::palette() );
338 d->hintLabel->hide();
339}
340
341FunctionCompletion::~FunctionCompletion()
342{
343 delete d->hintLabel;
344 delete d;
345}
346
347void FunctionCompletion::itemSelected( const TQString& item )
348{
349 KSpread::FunctionDescription* desc;
350 desc = KSpread::FunctionRepository::self()->functionInfo(item);
351 if(!desc)
352 {
353 d->hintLabel->hide();
354 return;
355 }
356
357 TQString helpText = desc->helpText()[0];
358 if( helpText.isEmpty() )
359 {
360 d->hintLabel->hide();
361 return;
362 }
363
364 helpText.append("</qt>").prepend("<qt>");
365 d->hintLabel->setText( helpText );
366 d->hintLabel->adjustSize();
367
368 // reposition nicely
369 TQPoint pos = d->editor->mapToGlobal( TQPoint( d->editor->width(), 0 ) );
370 pos.setY( pos.y() - d->hintLabel->height() - 1 );
371 d->hintLabel->move( pos );
372 d->hintLabel->show();
373 d->hintLabel->raise();
374
375 // do not show it forever
376 //TQTimer::singleShot( 5000, d->hintLabel, TQ_SLOT( hide()) );
377}
378
379bool FunctionCompletion::eventFilter( TQObject *obj, TQEvent *ev )
380{
381 if ( obj == d->completionPopup || obj == d->completionListBox )
382 {
383 if ( ev->type() == TQEvent::KeyPress )
384 {
385 TQKeyEvent *ke = (TQKeyEvent*)ev;
386 if ( ke->key() == Key_Enter || ke->key() == Key_Return )
387 {
389 return true;
390 }
391 else if ( ke->key() == Key_Left || ke->key() == Key_Right ||
392 ke->key() == Key_Up || ke->key() == Key_Down ||
393 ke->key() == Key_Home || ke->key() == Key_End ||
394 ke->key() == Key_Prior || ke->key() == Key_Next )
395 return false;
396
397 d->hintLabel->hide();
398 d->completionPopup->close();
399 d->editor->setFocus();
400 TQApplication::sendEvent( d->editor, ev );
401 return true;
402 }
403
404 if ( ev->type() == TQEvent::MouseButtonDblClick )
405 {
407 return true;
408 }
409 }
410
411 return false;
412}
413
415{
416 d->hintLabel->hide();
417 d->completionPopup->close();
418 d->editor->setFocus();
419 emit selectedCompletion( d->completionListBox->currentText() );
420}
421
422void FunctionCompletion::showCompletion( const TQStringList &choices )
423{
424 if( !choices.count() ) return;
425
426 d->completionListBox->clear();
427 for( unsigned i = 0; i < choices.count(); i++ )
428 new TQListBoxText( (TQListBox*)d->completionListBox, choices[i] );
429 d->completionListBox->setCurrentItem( 0 );
430
431 // size of the pop-up
432 d->completionPopup->setMaximumHeight( 100 );
433 d->completionPopup->resize( d->completionListBox->sizeHint() +
434 TQSize( d->completionListBox->verticalScrollBar()->width() + 4,
435 d->completionListBox->horizontalScrollBar()->height() + 4 ) );
436 int h = d->completionListBox->height();
437 int w = d->completionListBox->width();
438
439 TQPoint pos = d->editor->globalCursorPosition();
440
441 // if popup is partially invisible, move to other position
442 // FIXME check it if it works in Xinerama multihead
443 int screen_num = TQApplication::desktop()->screenNumber( d->completionPopup );
444 TQRect screen = TQApplication::desktop()->screenGeometry( screen_num );
445 if( pos.y() + h > screen.y()+screen.height() )
446 pos.setY( pos.y() - h - d->editor->height() );
447 if( pos.x() + w > screen.x()+screen.width() )
448 pos.setX( screen.x()+screen.width() - w );
449
450 d->completionPopup->move( pos );
451 d->completionListBox->setFocus();
452 d->completionPopup->show();
453}
454
455
456
457/****************************************************************************
458 *
459 * CellEditor
460 *
461 ****************************************************************************/
462
463class CellEditor::Private
464{
465public:
466 Cell* cell;
467 Canvas* canvas;
468 KTextEdit* textEdit;
469 FormulaEditorHighlighter* highlighter;
470 FunctionCompletion* functionCompletion;
471 TQTimer* functionCompletionTimer;
472
473 TQPoint globalCursorPos;
474
475 bool captureAllKeyEvents : 1;
476 bool checkChoice : 1;
477 bool updateChoice : 1;
478 bool updatingChoice : 1;
479
480 uint length;
481 uint fontLength;
482 uint length_namecell;
483 uint length_text;
484 uint currentToken;
485 uint rangeCount;
486};
487
488
489CellEditor::CellEditor( Cell* _cell, Canvas* _parent, bool captureAllKeyEvents, const char* _name )
490 : TQWidget( _parent, _name )
491{
492 d = new Private();
493 d->cell = _cell;
494 d->canvas = _parent;
495 d->textEdit = new KTextEdit(this);
496 d->globalCursorPos = TQPoint();
497 d->captureAllKeyEvents = captureAllKeyEvents;
498 d->checkChoice = true;
499 d->updateChoice = true;
500 d->updatingChoice = false;
501 d->length = 0;
502 d->fontLength = 0;
503 d->length_namecell = 0;
504 d->length_text = 0;
505 d->currentToken = 0;
506 d->rangeCount = 0;
507
508//TODO - Get rid of TQTextEdit margins, this doesn't seem easily possible in TQt 3.3, so a job for TQt 4 porting.
509
510 d->textEdit->setHScrollBarMode(TQScrollView::AlwaysOff);
511 d->textEdit->setVScrollBarMode(TQScrollView::AlwaysOff);
512 d->textEdit->setFrameStyle(TQFrame::NoFrame);
513 d->textEdit->setLineWidth(0);
514 d->textEdit->installEventFilter( this );
515
516 d->highlighter = new FormulaEditorHighlighter(d->textEdit, _parent);
517
518 d->functionCompletion = new FunctionCompletion( this );
519 d->functionCompletionTimer = new TQTimer( this );
520 connect( d->functionCompletion, TQ_SIGNAL( selectedCompletion( const TQString& ) ),
521 TQ_SLOT( functionAutoComplete( const TQString& ) ) );
522 connect( d->textEdit, TQ_SIGNAL( textChanged() ), TQ_SLOT( checkFunctionAutoComplete() ) );
523 connect( d->functionCompletionTimer, TQ_SIGNAL( timeout() ),
524 TQ_SLOT( triggerFunctionAutoComplete() ) );
525
526 if (!cell()->format()->multiRow(cell()->column(),cell()->row()))
527 d->textEdit->setWordWrap(TQTextEdit::NoWrap);
528 else
529 d->textEdit->setWrapPolicy(TQTextEdit::AtWordOrDocumentBoundary);
530
531//TODO - Custom KTextEdit class which supports text completion
532/*
533 d->textEdit->setFrame( false );
534 d->textEdit->setCompletionMode((TDEGlobalSettings::Completion)canvas()->view()->doc()->completionMode() );
535 d->textEdit->setCompletionObject( &canvas()->view()->doc()->completion(),true );
536*/
537 setFocusProxy( d->textEdit );
538
539 connect( d->textEdit, TQ_SIGNAL( cursorPositionChanged(int,int) ), this, TQ_SLOT (slotCursorPositionChanged(int,int)));
540 connect( d->textEdit, TQ_SIGNAL( cursorPositionChanged(TQTextCursor*) ), this, TQ_SLOT (slotTextCursorChanged(TQTextCursor*)));
541 connect( d->textEdit, TQ_SIGNAL( textChanged() ), this, TQ_SLOT( slotTextChanged() ) );
542
543// connect( d->textEdit, TQ_SIGNAL(completionModeChanged( TDEGlobalSettings::Completion )),this,TQ_SLOT (slotCompletionModeChanged(TDEGlobalSettings::Completion)));
544
545 // A choose should always start at the edited cell
546// canvas()->setChooseMarkerRow( canvas()->markerRow() );
547// canvas()->setChooseMarkerColumn( canvas()->markerColumn() );
548
549 // set font size according to zoom factor
550 TQFont font( _cell->format()->font() );
551 font.setPointSizeFloat( 0.01 * _parent->doc()->zoom() * font.pointSizeFloat() );
552 d->textEdit->setFont( font );
553
554 if (d->fontLength == 0)
555 {
556 TQFontMetrics fm( d->textEdit->font() );
557 d->fontLength = fm.width('x');
558 }
559}
560
561CellEditor::~CellEditor()
562{
563 canvas()->endChoose();
564
565 delete d->highlighter;
566 delete d->functionCompletion;
567 delete d->functionCompletionTimer;
568 delete d;
569}
570
571Cell* CellEditor::cell() const
572{
573 return d->cell;
574}
575
576Canvas* CellEditor::canvas() const
577{
578 return d->canvas;
579}
580
581TQPoint CellEditor::globalCursorPosition() const
582{
583 return d->globalCursorPos;
584}
585
586void CellEditor::checkFunctionAutoComplete()
587{
588 d->functionCompletionTimer->stop();
589 d->functionCompletionTimer->start( 2000, true );
590}
591
592void CellEditor::triggerFunctionAutoComplete()
593{
594 // tokenize the expression (don't worry, this is very fast)
595 int para = 0, curPos = 0;
596 d->textEdit->getCursorPosition( &para, &curPos );
597 TQString subtext = d->textEdit->text().left( curPos );
598
600 KSpread::Tokens tokens = f.scan( subtext );
601 if( !tokens.valid() ) return;
602 if( tokens.count()<1 ) return;
603
604 KSpread::Token lastToken = tokens[ tokens.count()-1 ];
605
606 // last token must be an identifier
607 if( !lastToken.isIdentifier() ) return;
608 TQString id = lastToken.text();
609 if( id.length() < 1 ) return;
610
611 // find matches in function names
612 TQStringList fnames = KSpread::FunctionRepository::self()->functionNames();
613 TQStringList choices;
614 for( unsigned i=0; i<fnames.count(); i++ )
615 if( fnames[i].startsWith( id, false ) )
616 choices.append( fnames[i] );
617 choices.sort();
618
619 // no match, don't bother with completion
620 if( !choices.count() ) return;
621
622 // single perfect match, no need to give choices
623 if( choices.count()==1 )
624 if( choices[0].lower() == id.lower() )
625 return;
626
627 // present the user with completion choices
628 d->functionCompletion->showCompletion( choices );
629}
630
631void CellEditor::functionAutoComplete( const TQString& item )
632{
633 if( item.isEmpty() ) return;
634
635 int para = 0, curPos = 0;
636 d->textEdit->getCursorPosition( &para, &curPos );
637 TQString subtext = text().left( curPos );
638
640 KSpread::Tokens tokens = f.scan( subtext );
641 if( !tokens.valid() ) return;
642 if( tokens.count()<1 ) return;
643
644 KSpread::Token lastToken = tokens[ tokens.count()-1 ];
645 if( !lastToken.isIdentifier() ) return;
646
647 d->textEdit->blockSignals( true );
648 d->textEdit->setSelection( 0, lastToken.pos()+1, 0, lastToken.pos()+lastToken.text().length()+1 );
649 d->textEdit->insert( item );
650 d->textEdit->blockSignals( false );
651}
652
653void CellEditor::slotCursorPositionChanged(int /* para */, int pos)
654{
655// kdDebug() << k_funcinfo << endl;
656
657 // TODO Stefan: optimize this function!
658
659 // turn choose mode on/off
660 if (!checkChoice())
661 return;
662
663 d->highlighter->rehighlight();
664
665 Tokens tokens = d->highlighter->formulaTokens();
666 uint rangeCounter = 0;
667 uint currentRange = 0;
668 uint regionStart = 0;
669 uint regionEnd = 0;
670 bool lastWasASemicolon = false;
671 d->currentToken = 0;
672 uint rangeCount = d->highlighter->rangeCount();
673 d->rangeCount = rangeCount;
674
675 Token token;
676 Token::Type type;
677 // search the current token
678 // determine the subregion number, btw
679 for (uint i = 0; i < tokens.count(); ++i)
680 {
681 if (tokens[i].pos() >= pos - 1) // without '='
682 {
683/* kdDebug() << "token.pos >= cursor.pos" << endl;*/
684 type = tokens[i].type();
685 if (type == Token::Cell || type == Token::Range)
686 {
687 if (lastWasASemicolon)
688 {
689 regionEnd = rangeCounter++;
690 lastWasASemicolon = false;
691 continue;
692 }
693 }
694 if (type == Token::Operator && tokens[i].asOperator() == Token::Semicolon)
695 {
696 lastWasASemicolon = true;
697 continue;
698 }
699 lastWasASemicolon = false;
700 break;
701 }
702 token = tokens[i];
703 d->currentToken = i;
704
705 type = token.type();
706 if (type == Token::Cell || type == Token::Range)
707 {
708 if (!lastWasASemicolon)
709 {
710 regionStart = rangeCounter;
711 }
712 regionEnd = rangeCounter;
713 currentRange = rangeCounter++;
714 }
715 // semicolons are use as deliminiters in regions
716 if (type == Token::Operator)
717 {
718 if (token.asOperator() == Token::Semicolon)
719 {
720 lastWasASemicolon = true;
721 }
722 else
723 {
724 lastWasASemicolon = false;
725 // set the region start to the next element
726 regionStart = currentRange + 1;
727 regionEnd = regionStart - 1; // len = 0
728 }
729 }
730 }
731
732// kdDebug() << "regionStart = " << regionStart/* << endl*/
733// << ", regionEnd = " << regionEnd/* << endl*/
734// << ", currentRange = " << currentRange << endl;
735
736 d->canvas->choice()->setActiveElement(currentRange);
737 d->canvas->choice()->setActiveSubRegion(regionStart, regionEnd-regionStart+1);
738
739 // triggered by keyboard action?
740 if (!d->updatingChoice)
741 {
742 if (d->highlighter->rangeChanged())
743 {
744 d->highlighter->resetRangeChanged();
745
746 disconnect( d->canvas->choice(), TQ_SIGNAL(changed(const Region&)),
747 d->canvas->view(), TQ_SLOT(slotScrollChoice(const Region&)) );
748 d->canvas->doc()->emitBeginOperation();
749 setUpdateChoice(false);
750
751 Tokens tokens = d->highlighter->formulaTokens();
752 d->canvas->choice()->update(); // set the old one dirty
753 d->canvas->choice()->clear();
754 Region tmpRegion;
755 Region::ConstIterator it;
756
757 //A list of regions which have already been highlighted on the spreadsheet.
758 //This is so that we don't end up highlighting the same region twice in two different
759 //colours.
760 TQValueList<Region> alreadyUsedRegions;
761
762 for (uint i = 0; i < tokens.count(); ++i)
763 {
764 Token token = tokens[i];
765 Token::Type type = token.type();
766 if (type == Token::Cell || type == Token::Range)
767 {
768 Region region(d->canvas->view(), token.text());
769 it = region.constBegin();
770
771 if (!alreadyUsedRegions.contains(region))
772 {
773 TQRect r=(*it)->rect();
774
775 if (d->canvas->choice()->isEmpty())
776 d->canvas->choice()->initialize((*it)->rect(), (*it)->sheet());
777 else
778 d->canvas->choice()->extend((*it)->rect(), (*it)->sheet());
779
780 alreadyUsedRegions.append(region);
781 }
782 }
783 }
784 setUpdateChoice(true);
785 d->canvas->doc()->emitEndOperation(*d->canvas->choice());
786 connect( d->canvas->choice(), TQ_SIGNAL(changed(const Region&)),
787 d->canvas->view(), TQ_SLOT(slotScrollChoice(const Region&)) );
788 }
789 }
790}
791
792void CellEditor::slotTextCursorChanged(TQTextCursor* cursor)
793{
794 TQTextStringChar *chr = cursor->paragraph()->at( cursor->index() );
795 int h = cursor->paragraph()->lineHeightOfChar( cursor->index() );
796 int x = cursor->paragraph()->rect().x() + chr->x;
797 int y, dummy;
798 cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y );
799 y += cursor->paragraph()->rect().y();
800
801 d->globalCursorPos = d->textEdit->mapToGlobal( d->textEdit-> contentsToViewport( TQPoint( x, y + h ) ) );
802}
803
805{
806 d->textEdit->cut();
807}
808
810{
811 d->textEdit->paste();
812}
813
815{
816 d->textEdit->copy();
817}
818
819void CellEditor::setEditorFont(TQFont const & font, bool updateSize)
820{
821 TQFont tmpFont( font );
822 tmpFont.setPointSizeFloat( 0.01 * canvas()->doc()->zoom() * tmpFont.pointSizeFloat() );
823 d->textEdit->setFont( tmpFont );
824
825 if (updateSize)
826 {
827 TQFontMetrics fm( d->textEdit->font() );
828 d->fontLength = fm.width('x');
829
830 int mw = fm.width( d->textEdit->text() ) + d->fontLength;
831 // don't make it smaller: then we would have to repaint the obscured cells
832 if (mw < width())
833 mw = width();
834
835 int mh = fm.height();
836 if (mh < height())
837 mh = height();
838
839 setGeometry(x(), y(), mw, mh);
840 }
841}
842
843void CellEditor::slotCompletionModeChanged(TDEGlobalSettings::Completion _completion)
844{
845 canvas()->view()->doc()->setCompletionMode( _completion );
846}
847
848void CellEditor::slotTextChanged()
849{
850// kdDebug() << k_funcinfo << endl;
851
852 //FIXME - text() may return richtext?
853 TQString t = text();
854
855 if (t.length() > d->length)
856 {
857 d->length = t.length();
858
859 TQFontMetrics fm(d->textEdit->font());
860 // - requiredWidth = width of text plus some spacer characters
861 int requiredWidth = fm.width(t) + (2*fm.width('x'));
862
863 //For normal single-row cells, the text editor must be expanded horizontally to
864 //allow the text to fit if the new text is too wide
865 //For multi-row (word-wrap enabled) cells, the text editor must expand vertically to
866 //allow for new rows of text & the width of the text editor is not affected
867 if (d->textEdit->wordWrap() == TQTextEdit::NoWrap)
868 {
869 if (requiredWidth > width())
870 {
871 if (t.isRightToLeft())
872 {
873 setGeometry(x() - requiredWidth + width(), y(), requiredWidth,height());
874 }
875 else
876 {
877 setGeometry(x(), y(), requiredWidth,height());
878 }
879 }
880 }
881 else
882 {
883 int requiredHeight = d->textEdit->heightForWidth(width());
884
885 if (requiredHeight > height())
886 {
887 setGeometry(x(), y(), width(), requiredHeight);
888 }
889 }
890
891 /* // allocate more space than needed. Otherwise it might be too slow
892 d->length = t.length();
893
894 // Too slow for long texts
895 // TQFontMetrics fm( d->textEdit->font() );
896 // int mw = fm.width( t ) + fm.width('x');
897 int mw = d->fontLength * d->length;
898
899 if (mw < width())
900 mw = width();
901
902 if (t.isRightToLeft())
903 setGeometry(x() - mw + width(), y(), mw, height());
904 else
905 setGeometry(x(), y(), mw, height());
906
907 d->length -= 2; */
908 }
909
910 if ( (cell()->formatType()) == Percentage_format )
911 {
912 if ( (t.length() == 1) && t[0].isDigit() )
913 {
914 TQString tmp = t + " %";
915 d->textEdit->setText(tmp);
916 d->textEdit->setCursorPosition(0,1);
917 return;
918 }
919 }
920
921 canvas()->view()->editWidget()->setText( t );
922 // canvas()->view()->editWidget()->setCursorPosition( d->textEdit->cursorPosition() );
923}
924
925void CellEditor::setCheckChoice(bool state)
926{
927 d->checkChoice = state;
928}
929
930bool CellEditor::checkChoice()
931{
932 if (!d->checkChoice)
933 return false;
934
935// // prevent recursion
936// d->checkChoice = false; // TODO nescessary?
937
938 d->length_namecell = 0;
939 d->currentToken = 0;
940
941 TQString text = d->textEdit->text();
942 if ( text[0] != '=' )
943 {
944 canvas()->setChooseMode(false);
945 }
946 else
947 {
948 int para, cur;
949 d->textEdit->getCursorPosition(&para, &cur);
950
951 Tokens tokens = d->highlighter->formulaTokens();
952
953 // empty formula?
954 if (tokens.count() < 1)
955 {
956 canvas()->startChoose();
957 }
958 else
959 {
960 Token token;
961 for (uint i = 0; i < tokens.count(); ++i)
962 {
963 if (tokens[i].pos() >= cur - 1) // without '='
964 {
965 break;
966 }
967 token = tokens[i];
968 d->currentToken = i;
969 }
970
971 Token::Type type = token.type();
972 if (type == Token::Operator && token.asOperator() != Token::RightPar)
973 {
974 canvas()->setChooseMode(true);
975 }
976 else if (type == Token::Cell || type == Token::Range)
977 {
978 d->length_namecell = token.text().length();
979 canvas()->setChooseMode(true);
980 }
981 else
982 {
983 canvas()->setChooseMode(false);
984 }
985 }
986 }
987
988// d->checkChoice = true;
989
990 return true;
991}
992
993void CellEditor::setUpdateChoice(bool state)
994{
995 d->updateChoice = state;
996}
997
998void CellEditor::updateChoice()
999{
1000// kdDebug() << k_funcinfo << endl;
1001
1002 if (!d->updateChoice)
1003 return;
1004
1005// // prevent recursion
1006// d->updateChoice = false; // TODO nescessary?
1007 d->updatingChoice = true;
1008
1009 Selection* choice = d->canvas->choice();
1010
1011 if (choice->isEmpty())
1012 return;
1013
1014 if (!choice->activeElement())
1015 return;
1016
1017 // only one element TODO
1018 if (++choice->constBegin() == choice->constEnd())
1019 {
1020 }
1021
1022 TQString name_cell = choice->activeSubRegionName();
1023
1024 Tokens tokens = d->highlighter->formulaTokens();
1025 uint start = 1;
1026 uint length = 0;
1027 if (!tokens.empty())
1028 {
1029 Token token = tokens[d->currentToken];
1030 Token::Type type = token.type();
1031 if (type == Token::Cell || type == Token::Range)
1032 {
1033 start = token.pos() + 1; // don't forget the '='!
1034 length = token.text().length();
1035 }
1036 else
1037 {
1038 start = token.pos() + token.text().length() + 1;
1039 }
1040 }
1041
1042 d->length_namecell = name_cell.length();
1043 d->length_text = text().length();
1044 //kdDebug(36001) << "updateChooseMarker2 len=" << d->length_namecell << endl;
1045
1046 TQString oldText = text();
1047 TQString newText = oldText.left(start) + name_cell + oldText.right(d->length_text - start - length);
1048
1049 setCheckChoice( false );
1050 setText( newText );
1051 setCheckChoice( true );
1052 setCursorPosition( start + d->length_namecell );
1053
1054 d->canvas->view()->editWidget()->setText( newText );
1055 //kdDebug(36001) << "old=" << old << " len=" << d->length_namecell << " pos=" << pos << endl;
1056
1057// d->updateChoice = false;
1058 d->updatingChoice = false;
1059}
1060
1061void CellEditor::resizeEvent( TQResizeEvent* )
1062{
1063 d->textEdit->setGeometry( 0, 0, width(), height() );
1064}
1065
1066void CellEditor::handleKeyPressEvent( TQKeyEvent * _ev )
1067{
1068 if (_ev->key() == TQt::Key_F4)
1069 {
1070 if (d->textEdit == 0)
1071 {
1072 TQApplication::sendEvent( d->textEdit, _ev );
1073 return;
1074 }
1075
1076 TQRegExp exp("(\\$?)([a-zA-Z]+)(\\$?)([0-9]+)$");
1077
1078 int para,cur;
1079 d->textEdit->getCursorPosition(&para,&cur);
1080 // int cur = d->textEdit->cursorPosition();
1081 TQString tmp, tmp2;
1082 int n = -1;
1083
1084 // this is ugly, and sort of hack
1085 // FIXME rewrite to use the real Tokenizer
1086 unsigned i;
1087 for( i = 0; i < 10; i++ )
1088 {
1089 tmp = d->textEdit->text().left( cur+i );
1090 tmp2 = d->textEdit->text().right( d->textEdit->text().length() - cur - i );
1091
1092 n = exp.search(tmp);
1093 if( n >= 0 ) break;
1094 }
1095
1096 if (n == -1) return;
1097
1098 TQString newPart;
1099 if ((exp.cap(1) == "$") && (exp.cap(3) == "$"))
1100 newPart = "$" + exp.cap(2) + exp.cap(4);
1101 else if ((exp.cap(1) != "$") && (exp.cap(3) != "$"))
1102 newPart = "$" + exp.cap(2) + "$" + exp.cap(4);
1103 else if ((exp.cap(1) == "$") && (exp.cap(3) != "$"))
1104 newPart = exp.cap(2) + "$" + exp.cap(4);
1105 else if ((exp.cap(1) != "$") && (exp.cap(3) == "$"))
1106 newPart = exp.cap(2) + exp.cap(4);
1107
1108 TQString newString = tmp.left(n);
1109 newString += newPart;
1110 cur = newString.length() - i;
1111 newString += tmp2;
1112
1113 d->textEdit->setText(newString);
1114 d->textEdit->setCursorPosition( 0, cur );
1115
1116 _ev->accept();
1117
1118 return;
1119 }
1120
1121 // Send the key event to the KLineEdit
1122 TQApplication::sendEvent( d->textEdit, _ev );
1123}
1124
1125void CellEditor::handleIMEvent( TQIMEvent * _ev )
1126{
1127 // send the IM event to the KLineEdit
1128 TQApplication::sendEvent( d->textEdit, _ev );
1129}
1130
1131TQString CellEditor::text() const
1132{
1133 return d->textEdit->text();
1134}
1135
1136void CellEditor::setText(TQString text)
1137{
1138 d->textEdit->setText(text);
1139 //Usability : It is usually more convenient if the cursor is positioned at the end of the text so it can
1140 //be quickly deleted using the backspace key
1141
1142 //This also ensures that the caret is sized correctly for the text
1143 d->textEdit->setCursorPosition(0,text.length());
1144
1145 if (d->fontLength == 0)
1146 {
1147 TQFontMetrics fm( d->textEdit->font() );
1148 d->fontLength = fm.width('x');
1149 }
1150}
1151
1152int CellEditor::cursorPosition() const
1153{
1154 int para,cur;
1155 d->textEdit->getCursorPosition(&para,&cur);
1156 return cur;
1157 // return d->textEdit->cursorPosition();
1158}
1159
1160void CellEditor::setCursorPosition( int pos )
1161{
1162 d->textEdit->setCursorPosition(0,pos);
1163 canvas()->view()->editWidget()->setCursorPosition( pos );
1164}
1165
1166bool CellEditor::eventFilter( TQObject* o, TQEvent* e )
1167{
1168 // Only interested in KTextEdit
1169 if ( o != d->textEdit )
1170 return false;
1171 if ( e->type() == TQEvent::FocusOut )
1172 {
1173 canvas()->setLastEditorWithFocus( Canvas::CellEditor );
1174 return false;
1175 }
1176
1177 if ( e->type() == TQEvent::KeyPress || e->type() == TQEvent::KeyRelease )
1178 {
1179 TQKeyEvent* k = (TQKeyEvent*)e;
1180 if (!(k->state() & TQt::ShiftButton) || canvas()->chooseMode())
1181 {
1182 //If the user presses the return key to finish editing this cell, choose mode must be turned off first
1183 //otherwise it will merely select a different cell
1184 if (k->key() == Key_Return || k->key() == Key_Enter)
1185 {
1186 kdDebug() << "CellEditor::eventFilter: canvas()->endChoose();" << endl;
1187 canvas()->endChoose();
1188 }
1189
1190 //NB - Added check for Key_Return when migrating text edit from KLineEdit to KTextEdit, since
1191 //normal behaviour for KTextEdit is to swallow return key presses
1192 if ( k->key() == Key_Up || k->key() == Key_Down ||
1193 k->key() == Key_Next || k->key() == Key_Prior ||
1194 k->key() == Key_Escape || k->key() == Key_Tab ||
1195 k->key() == Key_Return || k->key() == Key_Enter)
1196 {
1197 // Send directly to canvas
1198 TQApplication::sendEvent( parent(), e );
1199 return true;
1200 }
1201 }
1202 else if ( k->state() & TQt::ShiftButton && ( k->key() == Key_Return || k->key() == Key_Enter ) )
1203 {
1204 // enable content wrapping
1205 d->cell->format()->setMultiRow( true );
1206 }
1207 // End choosing. May be restarted by CellEditor::slotTextChanged
1208 if ( e->type() == TQEvent::KeyPress && !k->text().isEmpty() )
1209 {
1210 canvas()->setChooseMode(false);
1211 }
1212 // forward Left/Right keys - so that pressing left/right in this
1213 // editor leaves editing mode ... otherwise editing is annoying
1214 // left/right arrows still work with the F2-editor.
1215
1216 // Forward left & right arrows to parent, unless this editor has been set to capture arrow key events
1217 // Changed to this behaviour for consistancy with OO Calc & MS Office.
1218 if ( ((k->key() == TQt::Key_Left) || (k->key() == TQt::Key_Right)) && (!d->captureAllKeyEvents)) {
1219 TQApplication::sendEvent (parent(), e);
1220 return true;
1221 }
1222 }
1223
1224 return false;
1225}
1226
1227void CellEditor::setCursorToRange(uint pos)
1228{
1229// kdDebug() << k_funcinfo << endl;
1230
1231 d->updatingChoice = true;
1232 uint counter = 0;
1233 Tokens tokens = d->highlighter->formulaTokens();
1234 for (uint i = 0; i < tokens.count(); ++i)
1235 {
1236 Token token = tokens[i];
1237 Token::Type type = token.type();
1238 if (type == Token::Cell || type == Token::Range)
1239 {
1240 if (counter == pos)
1241 {
1242 setCursorPosition(token.pos() + token.text().length() + 1);
1243 }
1244 counter++;
1245 }
1246 }
1247 d->updatingChoice = false;
1248}
1249
1250
1251
1252/*****************************************************************************
1253 *
1254 * ComboboxLocationEditWidget
1255 *
1256 ****************************************************************************/
1257
1258ComboboxLocationEditWidget::ComboboxLocationEditWidget( TQWidget * _parent,
1259 View * _view )
1260 : KComboBox( _parent, "ComboboxLocationEditWidget" )
1261{
1262 m_locationWidget = new LocationEditWidget( _parent, _view );
1263 setLineEdit( m_locationWidget );
1264 insertItem( "" );
1265
1266 TQValueList<Reference>::Iterator it;
1267 TQValueList<Reference> area = _view->doc()->listArea();
1268 for ( it = area.begin(); it != area.end(); ++it )
1269 slotAddAreaName( (*it).ref_name);
1270 connect( this, TQ_SIGNAL( activated ( const TQString & ) ), m_locationWidget, TQ_SLOT( slotActivateItem() ) );
1271}
1272
1273
1274void ComboboxLocationEditWidget::slotAddAreaName( const TQString &_name)
1275{
1276 insertItem( _name );
1277 m_locationWidget->addCompletionItem( _name );
1278}
1279
1280void ComboboxLocationEditWidget::slotRemoveAreaName( const TQString &_name )
1281{
1282 for ( int i = 0; i<count(); i++ )
1283 {
1284 if ( text(i)==_name )
1285 {
1286 removeItem( i );
1287 break;
1288 }
1289 }
1290 m_locationWidget->removeCompletionItem( _name );
1291}
1292
1293
1294
1295/*****************************************************************************
1296 *
1297 * LocationEditWidget
1298 *
1299 ****************************************************************************/
1300
1301LocationEditWidget::LocationEditWidget( TQWidget * _parent,
1302 View * _view )
1303 : KLineEdit( _parent, "LocationEditWidget" ),
1304 m_pView(_view)
1305{
1306 setCompletionObject( &completionList,true );
1307 setCompletionMode(TDEGlobalSettings::CompletionAuto );
1308}
1309
1310void LocationEditWidget::addCompletionItem( const TQString &_item )
1311{
1312 kdDebug()<<" LocationEditWidget::addCompletionItem add :"<<_item<<endl;
1313 if ( completionList.items().contains( _item) == 0 )
1314 {
1315 completionList.addItem( _item );
1316 kdDebug()<<" _utem :"<<_item<<endl;
1317 kdDebug()<<" completionList.items().count()"<<completionList.items().count()<<endl;
1318 }
1319}
1320
1321void LocationEditWidget::removeCompletionItem( const TQString &_item )
1322{
1323 completionList.removeItem( _item );
1324}
1325
1326void LocationEditWidget::slotActivateItem()
1327{
1328 activateItem();
1329}
1330
1331bool LocationEditWidget::activateItem()
1332{
1333 TQString ltext = text();
1334 TQString tmp = ltext.lower();
1335 TQValueList<Reference>::Iterator it;
1336 TQValueList<Reference> area = m_pView->doc()->listArea();
1337 for ( it = area.begin(); it != area.end(); ++it )
1338 {
1339 if ((*it).ref_name == tmp)
1340 {
1341 TQString tmp = (*it).sheet_name;
1342 tmp += "!";
1343 tmp += util_rangeName((*it).rect);
1344 m_pView->selectionInfo()->initialize( Region(m_pView,tmp) );
1345 return true;
1346 }
1347 }
1348
1349 // Set the cell component to uppercase:
1350 // Sheet1!a1 -> Sheet1!A2
1351 int pos = ltext.find('!');
1352 if ( pos !=- 1 )
1353 tmp = ltext.left(pos)+ltext.mid(pos).upper();
1354 else
1355 tmp = ltext.upper();
1356
1357 // Selection entered in location widget
1358 if ( ltext.contains( ':' ) )
1359 m_pView->selectionInfo()->initialize( Region(m_pView,tmp) );
1360 // Location entered in location widget
1361 else
1362 {
1363 Region region(m_pView,tmp);
1364 bool validName = true;
1365 for (unsigned int i = 0; i < ltext.length(); ++i)
1366 {
1367 if (!ltext[i].isLetter())
1368 {
1369 validName = false;
1370 break;
1371 }
1372 }
1373 if ( !region.isValid() && validName)
1374 {
1375 TQRect rect( m_pView->selectionInfo()->selection() );
1376 Sheet * t = m_pView->activeSheet();
1377 // set area name on current selection/cell
1378
1379 m_pView->doc()->addAreaName(rect, ltext.lower(), t->sheetName());
1380 }
1381
1382 if (!validName)
1383 {
1384 m_pView->selectionInfo()->initialize(region);
1385 }
1386 }
1387
1388 // Set the focus back on the canvas.
1389 m_pView->canvasWidget()->setFocus();
1390 return false;
1391}
1392
1393
1394void LocationEditWidget::keyPressEvent( TQKeyEvent * _ev )
1395{
1396 // Do not handle special keys and accelerators. This is
1397 // done by TQLineEdit.
1398 if ( _ev->state() & ( TQt::AltButton | TQt::ControlButton ) )
1399 {
1400 TQLineEdit::keyPressEvent( _ev );
1401 // Never allow that keys are passed on to the parent.
1402 _ev->accept();
1403
1404 return;
1405 }
1406
1407 // Handle some special keys here. Eve
1408 switch( _ev->key() )
1409 {
1410 case Key_Return:
1411 case Key_Enter:
1412 {
1413 if ( activateItem() )
1414 return;
1415 _ev->accept();
1416 }
1417 break;
1418 // Escape pressed, restore original value
1419 case Key_Escape:
1420 // #### Torben says: This is duplicated code. Bad.
1421 if ( m_pView->selectionInfo()->isSingular() ) {
1422 setText( Cell::columnName( m_pView->canvasWidget()->markerColumn() )
1423 + TQString::number( m_pView->canvasWidget()->markerRow() ) );
1424 } else {
1425 setText( Cell::columnName( m_pView->selectionInfo()->lastRange().left() )
1426 + TQString::number( m_pView->selectionInfo()->lastRange().top() )
1427 + ":"
1428 + Cell::columnName( m_pView->selectionInfo()->lastRange().right() )
1429 + TQString::number( m_pView->selectionInfo()->lastRange().bottom() ) );
1430 }
1431 m_pView->canvasWidget()->setFocus();
1432 _ev->accept();
1433 break;
1434 default:
1435 TQLineEdit::keyPressEvent( _ev );
1436 // Never allow that keys are passed on to the parent.
1437 _ev->accept();
1438 }
1439}
1440
1441
1442
1443/****************************************************************
1444 *
1445 * EditWidget
1446 * The line-editor that appears above the sheet and allows to
1447 * edit the cells content.
1448 *
1449 ****************************************************************/
1450
1451EditWidget::EditWidget( TQWidget *_parent, Canvas *_canvas,
1452 TQButton *cancelButton, TQButton *okButton )
1453 : TQLineEdit( _parent, "EditWidget" )
1454{
1455 m_pCanvas = _canvas;
1456 Q_ASSERT(m_pCanvas != NULL);
1457 // Those buttons are created by the caller, so that they are inserted
1458 // properly in the layout - but they are then managed here.
1459 m_pCancelButton = cancelButton;
1460 m_pOkButton = okButton;
1461 isArray = false;
1462
1463 installEventFilter(m_pCanvas);
1464
1465 if ( !m_pCanvas->doc()->isReadWrite() || !m_pCanvas->activeSheet() )
1466 setEnabled( false );
1467
1468 TQObject::connect( m_pCancelButton, TQ_SIGNAL( clicked() ),
1469 this, TQ_SLOT( slotAbortEdit() ) );
1470 TQObject::connect( m_pOkButton, TQ_SIGNAL( clicked() ),
1471 this, TQ_SLOT( slotDoneEdit() ) );
1472
1473 setEditMode( false ); // disable buttons
1474}
1475
1476void EditWidget::showEditWidget(bool _show)
1477{
1478 if (_show)
1479 {
1480 m_pCancelButton->show();
1481 m_pOkButton->show();
1482 show();
1483 }
1484 else
1485 {
1486 m_pCancelButton->hide();
1487 m_pOkButton->hide();
1488 hide();
1489 }
1490}
1491
1492void EditWidget::slotAbortEdit()
1493{
1494 m_pCanvas->deleteEditor( false /*discard changes*/ );
1495 // will take care of the buttons
1496}
1497
1498void EditWidget::slotDoneEdit()
1499{
1500 m_pCanvas->deleteEditor( true /*keep changes*/, isArray);
1501 isArray = false;
1502 // will take care of the buttons
1503}
1504
1505void EditWidget::keyPressEvent ( TQKeyEvent* _ev )
1506{
1507 // Dont handle special keys and accelerators, except Enter ones
1508 if (( ( _ev->state() & ( TQt::AltButton | TQt::ControlButton ) )
1509 || ( _ev->state() & TQt::ShiftButton )
1510 || ( _ev->key() == Key_Shift )
1511 || ( _ev->key() == Key_Control ) )
1512 && (_ev->key() != Key_Return) && (_ev->key() != Key_Enter))
1513 {
1514 TQLineEdit::keyPressEvent( _ev );
1515 _ev->accept();
1516 return;
1517 }
1518
1519 if ( !m_pCanvas->doc()->isReadWrite() )
1520 return;
1521
1522 if ( !m_pCanvas->editor() )
1523 {
1524 // Start editing the current cell
1525 m_pCanvas->createEditor( Canvas::CellEditor,false );
1526 }
1527 CellEditor * cellEditor = (CellEditor*) m_pCanvas->editor();
1528
1529 switch ( _ev->key() )
1530 {
1531 case Key_Down:
1532 case Key_Up:
1533 case Key_Return:
1534 case Key_Enter:
1535 cellEditor->setText( text());
1536 // Don't allow to start a chooser when pressing the arrow keys
1537 // in this widget, since only up and down would work anyway.
1538 // This is why we call slotDoneEdit now, instead of sending
1539 // to the canvas.
1540 //TQApplication::sendEvent( m_pCanvas, _ev );
1541 isArray = (_ev->state() & TQt::AltButton) &&
1542 (_ev->state() & TQt::ControlButton);
1543 slotDoneEdit();
1544 m_pCanvas->view()->updateEditWidget();
1545 _ev->accept();
1546 break;
1547 case Key_F2:
1548 cellEditor->setFocus();
1549 cellEditor->setText( text());
1550 cellEditor->setCursorPosition(cursorPosition());
1551 break;
1552 default:
1553
1554 TQLineEdit::keyPressEvent( _ev );
1555
1556 setFocus();
1557 cellEditor->setCheckChoice( false );
1558 cellEditor->setText( text() );
1559 cellEditor->setCheckChoice( true );
1560 cellEditor->setCursorPosition( cursorPosition() );
1561 }
1562}
1563
1564void EditWidget::setEditMode( bool mode )
1565{
1566 m_pCancelButton->setEnabled(mode);
1567 m_pOkButton->setEnabled(mode);
1568}
1569
1570void EditWidget::focusOutEvent( TQFocusEvent* ev )
1571{
1572 //kdDebug(36001) << "EditWidget lost focus" << endl;
1573 // See comment about setLastEditorWithFocus
1574 m_pCanvas->setLastEditorWithFocus( Canvas::EditWidget );
1575
1576 TQLineEdit::focusOutEvent( ev );
1577}
1578
1579void EditWidget::setText( const TQString& t )
1580{
1581 if ( t == text() ) // Why this? (David)
1582 return;
1583
1584 TQLineEdit::setText( t );
1585}
1586
1587
1588
1589#include "kspread_editors.moc"
The canvas builds a part of the GUI of KSpread.
int markerRow() const
convenience function.
void deleteEditor(bool saveChanges, bool array=false)
Deletes the current cell editor.
void setChooseMode(bool state)
Switches the choose mode on and off.
int markerColumn() const
convenience function.
void endChoose()
Switches to selection mode.
void startChoose()
Switches to choose mode and sets the initial selection to the position returned by marker().
void createEditor(bool captureArrowKeys=false)
Chooses the correct EditorType by looking at the current cells value.
bool chooseMode() const
void setLastEditorWithFocus(EditorType type)
Called from EditWidget and CellEditor if they loose the focus because the user started a "choose sele...
class CellEditor
void copy()
wrapper to KTextEdit::copy()
bool eventFilter(TQObject *o, TQEvent *e)
Steals some key events from the TQLineEdit and sends it to the Canvas ( its parent ) instead.
void paste()
wrapper to KTextEdit::paste()
TQString text() const
wrapper to KTextEdit::text()
CellEditor(Cell *cell, Canvas *_parent=0, bool captureAllKeyEvents=false, const char *_name=0)
Creates a new CellEditor.
void cut()
wrapper to KTextEdit::cut()
For every cell in the spread sheet there is a Cell object.
Format * format() const
Returns the format object of this cell.
TQString columnName() const
Returns the column name of the cell.
Colours cell references in formulas.
FormulaEditorHighlighter(TQTextEdit *textEdit, Canvas *canvas)
Constructs a FormulaHighlighter to colour-code cell references in a TQTextEdit.
virtual int highlightParagraph(const TQString &text, int endStateOfLastPara)
Called automatically by KTextEditor to highlight text when modified.
bool rangeChanged() const
Returns true if any of the ranges or cells in the formula have changed since the last call to Formula...
void resetRangeChanged()
Sets the highlighter's range changed flag to false.
void handleBrace(uint index)
Examines the brace (Token::LeftPar or Token::RightPar) operator token at the given index in the token...
int findMatchingBrace(int pos)
Returns the position of the brace matching the one found at position pos.
Class Formula encapsulates a formula for a cell.
Definition formula.h:239
Tokens scan(const TQString &expr, TDELocale *locale=0) const
Given an expression, this function separates it into tokens.
Definition formula.cpp:464
Provides autocompletition facilities in formula editors.
void doneCompletion()
Hides the autocompletion list box if it is visible and emits the selectedCompletion signal.
bool eventFilter(TQObject *o, TQEvent *e)
Handles various keyboard and mouse actions which may occur on the autocompletion popup list.
void selectedCompletion(const TQString &item)
Emitted, if the user selects a function name from the list.
void showCompletion(const TQStringList &choices)
Populates the autocompletion list box with the specified choices and shows it so that the user can vi...
A widget that allows the user to enter an arbitrary cell location to goto or cell selection to highli...
Represents a region within a workbook.
The one for all class for points and ranges.
Definition region.h:44
@ Semicolon
; (argument separator)
Definition formula.h:70
TQString text() const
Returns text associated with the token.
Definition formula.h:103
Type type() const
Returns type of the token.
Definition formula.h:94
bool isIdentifier() const
Returns true if token is an identifier.
Definition formula.h:150
Type
token types
Definition formula.h:44
@ Identifier
function name or named area
Definition formula.h:53
@ Integer
14, 3, 1977
Definition formula.h:47
@ Cell
$A$1, F4, Sheet2!B5, 'Sales Forecast'!Sum
Definition formula.h:51
@ Boolean
True, False (also i18n-ized)
Definition formula.h:46
@ Float
3.141592, 1e10, 5.9e-7
Definition formula.h:48
@ Range
C1:C100.
Definition formula.h:52
@ Operator
+, *, /, -
Definition formula.h:50
@ String
"KOffice", "The quick brown fox..."
Definition formula.h:49
@ Unknown
unknown type
Definition formula.h:45
Op asOperator() const
Returns operator value for an operator token.
Definition formula.cpp:261
Class Tokens represents array of tokens.
Definition formula.h:220
The View class displays a KSpread document.
Canvas * canvasWidget() const
Returns the canvas of the view.
void updateEditWidget()
Fills the EditWidget with the current cells content.
KSpread::EditWidget * editWidget() const
Returns the editor widget.
The KSpread namespace.
Definition commands.h:39