1
/* This file is part of the KDE project
2
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3
Copyright (C) 1999, 2000,2001 Montel Laurent <lmontel@mandrakesoft.com>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License as published by the Free Software Foundation; either
7
version 2 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Library General Public License for more details.
14
You should have received a copy of the GNU Library General Public License
15
along with this library; see the file COPYING.LIB. If not, write to
16
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
Boston, MA 02111-1307, USA.
20
#include <qtextbrowser.h>
21
#include <qtabwidget.h>
23
#include "kspread_dlg_formula.h"
24
#include "kspread_canvas.h"
25
#include "kspread_util.h"
26
#include "kspread_editors.h"
27
#include "kspread_doc.h"
28
#include "kspread_map.h"
30
#include <kapplication.h>
32
#include <kbuttonbox.h>
33
#include <knumvalidator.h>
34
#include <qcombobox.h>
38
#include <qpushbutton.h>
39
#include <klineedit.h>
42
KSpreadDlgFormula::KSpreadDlgFormula( KSpreadView* parent, const char* name,const QString& formulaName)
43
: KDialogBase( parent, name,false,i18n("Function"), Ok|Cancel )
45
setWFlags( Qt::WDestructiveClose );
51
KSpreadCell* cell = m_pView->activeTable()->cellAt( m_pView->canvasWidget()->markerColumn(),
52
m_pView->canvasWidget()->markerRow() );
53
m_oldText=cell->text();
54
// Make sure that there is a cell editor running.
55
if ( !m_pView->canvasWidget()->editor() )
57
m_pView->canvasWidget()->createEditor( KSpreadCanvas::CellEditor );
58
if(cell->text().isEmpty())
59
m_pView->canvasWidget()->editor()->setText( "=" );
61
if(cell->text().at(0)!='=')
62
m_pView->canvasWidget()->editor()->setText( "="+cell->text() );
64
m_pView->canvasWidget()->editor()->setText( cell->text() );
67
Q_ASSERT( m_pView->canvasWidget()->editor() );
69
QWidget *page = new QWidget( this );
72
QGridLayout *grid1 = new QGridLayout(page,11,2,KDialog::marginHint(), KDialog::spacingHint());
74
searchFunct = new KLineEdit(page);
75
QSizePolicy sp3( QSizePolicy::Preferred, QSizePolicy::Fixed );
76
searchFunct->setSizePolicy( sp3 );
78
grid1->addWidget( searchFunct, 0, 0 );
80
typeFunction = new QComboBox(page);
81
QStringList cats = KSpreadFunctionRepository::self()->groups();
82
cats.prepend( i18n("All") );
83
typeFunction->insertStringList( cats );
84
grid1->addWidget( typeFunction, 1, 0 );
86
functions = new QListBox(page);
87
QSizePolicy sp1( QSizePolicy::Preferred, QSizePolicy::Expanding );
88
functions->setSizePolicy( sp1 );
89
grid1->addWidget( functions, 2, 0 );
91
selectFunction = new QPushButton( page );
92
QToolTip::add(selectFunction, i18n("Insert function") );
93
selectFunction->setPixmap( BarIcon( "down", KIcon::SizeSmall ) );
94
grid1->addWidget( selectFunction, 3, 0 );
96
result = new QLineEdit( page );
97
grid1->addMultiCellWidget( result, 4, 4, 0, 1 );
99
m_tabwidget = new QTabWidget( page );
100
QSizePolicy sp2( QSizePolicy::Expanding, QSizePolicy::Expanding );
101
m_tabwidget->setSizePolicy( sp2 );
102
grid1->addMultiCellWidget( m_tabwidget, 0, 2, 1, 1 );
104
m_browser = new QTextBrowser( m_tabwidget );
105
m_browser->setMinimumWidth( 300 );
107
m_tabwidget->addTab( m_browser, i18n("&Help") );
108
int index = m_tabwidget->currentPageIndex();
110
m_input = new QWidget( m_tabwidget );
111
QVBoxLayout *grid2 = new QVBoxLayout( m_input, KDialog::marginHint(), KDialog::spacingHint() );
113
// grid2->setResizeMode (QLayout::Minimum);
115
label1 = new QLabel(m_input);
116
grid2->addWidget( label1 );
118
firstElement=new QLineEdit(m_input);
119
grid2->addWidget( firstElement );
121
label2=new QLabel(m_input);
122
grid2->addWidget( label2 );
124
secondElement=new QLineEdit(m_input);
125
grid2->addWidget( secondElement );
127
label3=new QLabel(m_input);
128
grid2->addWidget( label3 );
130
thirdElement=new QLineEdit(m_input);
131
grid2->addWidget( thirdElement );
133
label4=new QLabel(m_input);
134
grid2->addWidget( label4 );
136
fourElement=new QLineEdit(m_input);
137
grid2->addWidget( fourElement );
139
label5=new QLabel(m_input);
140
grid2->addWidget( label5 );
142
fiveElement=new QLineEdit(m_input);
143
grid2->addWidget( fiveElement );
145
grid2->addStretch( 10 );
147
m_tabwidget->addTab( m_input, i18n("&Parameters") );
148
m_tabwidget->setTabEnabled( m_input, FALSE );
150
m_tabwidget->setCurrentPage( index );
152
refresh_result = true;
154
connect( this, SIGNAL( cancelClicked() ), this, SLOT( slotClose() ) );
155
connect( this, SIGNAL( okClicked() ), this, SLOT( slotOk() ) );
156
connect( typeFunction, SIGNAL( activated(const QString &) ),
157
this, SLOT( slotActivated(const QString &) ) );
158
connect( functions, SIGNAL( highlighted(const QString &) ),
159
this, SLOT( slotSelected(const QString &) ) );
160
connect( functions, SIGNAL( selected(const QString &) ),
161
this, SLOT( slotSelected(const QString &) ) );
162
connect( functions, SIGNAL( doubleClicked(QListBoxItem * ) ),
163
this ,SLOT( slotDoubleClicked(QListBoxItem *) ) );
165
slotActivated(i18n("All"));
167
connect( selectFunction, SIGNAL(clicked()),
168
this,SLOT(slotSelectButton()));
170
connect( firstElement,SIGNAL(textChanged ( const QString & )),
171
this,SLOT(slotChangeText(const QString &)));
172
connect( secondElement,SIGNAL(textChanged ( const QString & )),
173
this,SLOT(slotChangeText(const QString &)));
174
connect( thirdElement,SIGNAL(textChanged ( const QString & )),
175
this,SLOT(slotChangeText(const QString &)));
176
connect( fourElement,SIGNAL(textChanged ( const QString & )),
177
this,SLOT(slotChangeText(const QString &)));
178
connect( fiveElement,SIGNAL(textChanged ( const QString & )),
179
this,SLOT(slotChangeText(const QString &)));
181
connect( m_pView, SIGNAL( sig_chooseSelectionChanged( KSpreadSheet*, const QRect& ) ),
182
this, SLOT( slotSelectionChanged( KSpreadSheet*, const QRect& ) ) );
184
connect( m_browser, SIGNAL( linkClicked( const QString& ) ),
185
this, SLOT( slotShowFunction( const QString& ) ) );
187
// Save the name of the active table.
188
m_tableName = m_pView->activeTable()->tableName();
189
// Save the cells current text.
190
QString tmp_oldText = m_pView->canvasWidget()->editor()->text();
191
// Position of the cell.
192
m_column = m_pView->canvasWidget()->markerColumn();
193
m_row = m_pView->canvasWidget()->markerRow();
195
if( tmp_oldText.isEmpty() )
196
result->setText("=");
199
if( tmp_oldText.at(0)!='=')
200
result->setText( "=" + tmp_oldText );
202
result->setText( tmp_oldText );
205
// Allow the user to select cells on the spreadsheet.
206
m_pView->canvasWidget()->startChoose();
208
qApp->installEventFilter( this );
210
// Was a function name passed along with the constructor ? Then activate it.
211
if( !formulaName.isEmpty() )
213
functions->setCurrentItem( functions->index( functions->findItem( formulaName ) ) );
214
slotDoubleClicked( functions->findItem( formulaName ) );
218
// Set keyboard focus to allow selection of a formula.
219
searchFunct->setFocus();
222
// Add auto completion.
223
searchFunct->setCompletionMode( KGlobalSettings::CompletionAuto );
224
searchFunct->setCompletionObject( &listFunct, true );
226
if( functions->currentItem() == -1 )
227
selectFunction->setEnabled( false );
229
connect( searchFunct, SIGNAL( textChanged( const QString & ) ),
230
this, SLOT( slotSearchText(const QString &) ) );
231
connect( searchFunct, SIGNAL( returnPressed() ),
232
this, SLOT( slotPressReturn() ) );
235
KSpreadDlgFormula::~KSpreadDlgFormula()
237
kdDebug(36001)<<"KSpreadDlgFormula::~KSpreadDlgFormula() \n";
241
void KSpreadDlgFormula::slotPressReturn()
243
//laurent 2001-07-07 desactivate this code
244
//because kspread crash.
247
if( !functions->currentText().isEmpty() )
248
slotDoubleClicked( functions->findItem( functions->currentText() ) );
252
void KSpreadDlgFormula::slotSearchText(const QString &_text)
254
QString result = listFunct.makeCompletion( _text.upper() );
255
if( !result.isNull() )
256
functions->setCurrentItem( functions->index( functions->findItem( result ) ) );
259
bool KSpreadDlgFormula::eventFilter( QObject* obj, QEvent* ev )
261
if ( obj == firstElement && ev->type() == QEvent::FocusIn )
262
m_focus = firstElement;
263
else if ( obj == secondElement && ev->type() == QEvent::FocusIn )
264
m_focus = secondElement;
265
else if ( obj == thirdElement && ev->type() == QEvent::FocusIn )
266
m_focus = thirdElement;
267
else if ( obj == fourElement && ev->type() == QEvent::FocusIn )
268
m_focus = fourElement;
269
else if ( obj == fiveElement && ev->type() == QEvent::FocusIn )
270
m_focus = fiveElement;
275
m_pView->canvasWidget()->startChoose();
280
void KSpreadDlgFormula::slotOk()
282
m_pView->doc()->emitBeginOperation( false );
284
m_pView->canvasWidget()->endChoose();
285
// Switch back to the old table
286
if( m_pView->activeTable()->tableName() != m_tableName )
288
KSpreadSheet *table=m_pView->doc()->map()->findTable(m_tableName);
290
m_pView->setActiveTable(table);
293
// Revert the marker to its original position
294
m_pView->selectionInfo()->setMarker( QPoint( m_column, m_row ),
295
m_pView->activeTable());
297
// If there is still an editor then set the text.
298
// Usually the editor is always in place.
299
if( m_pView->canvasWidget()->editor() != 0 )
301
Q_ASSERT( m_pView->canvasWidget()->editor() );
302
QString tmp = result->text();
303
if( tmp.at(0) != '=')
305
int pos = m_pView->canvasWidget()->editor()->cursorPosition()+ tmp.length();
306
m_pView->canvasWidget()->editor()->setText( tmp );
307
m_pView->canvasWidget()->editor()->setFocus();
308
m_pView->canvasWidget()->editor()->setCursorPosition( pos );
311
m_pView->slotUpdateView( m_pView->activeTable() );
316
void KSpreadDlgFormula::slotClose()
318
m_pView->doc()->emitBeginOperation( false );
320
m_pView->canvasWidget()->endChoose();
322
// Switch back to the old table
323
if(m_pView->activeTable()->tableName() != m_tableName )
325
KSpreadSheet *table=m_pView->doc()->map()->findTable(m_tableName);
328
m_pView->setActiveTable(table);
332
// Revert the marker to its original position
333
m_pView->selectionInfo()->setMarker( QPoint( m_column, m_row ),
334
m_pView->activeTable() );
336
// If there is still an editor then reset the text.
337
// Usually the editor is always in place.
338
if( m_pView->canvasWidget()->editor() != 0 )
340
Q_ASSERT( m_pView->canvasWidget()->editor() );
341
m_pView->canvasWidget()->editor()->setText( m_oldText );
342
m_pView->canvasWidget()->editor()->setFocus();
345
m_pView->slotUpdateView( m_pView->activeTable() );
347
//laurent 2002-01-03 comment this line otherwise kspread crash
348
//but dialog box is not deleted => not good
352
void KSpreadDlgFormula::slotSelectButton()
354
if( functions->currentItem() != -1 )
356
slotDoubleClicked(functions->findItem(functions->text(functions->currentItem())));
360
void KSpreadDlgFormula::slotChangeText( const QString& )
363
if( !refresh_result )
369
QString tmp = m_leftText+m_funcName+"(";
370
tmp += createFormula();
371
tmp = tmp+ ")" + m_rightText;
373
result->setText( tmp );
376
QString KSpreadDlgFormula::createFormula()
381
return QString::null;
385
int count = m_desc->params();
387
if(!firstElement->text().isEmpty() && count >= 1 )
389
tmp=tmp+createParameter(firstElement->text(), 0 );
393
if(!secondElement->text().isEmpty() && count >= 2 )
397
tmp=tmp+";"+createParameter(secondElement->text(), 1 );
399
tmp=tmp+createParameter(secondElement->text(), 1 );
401
if(!thirdElement->text().isEmpty() && count >= 3 )
405
tmp=tmp+";"+createParameter(thirdElement->text(), 2 );
407
tmp=tmp+createParameter(thirdElement->text(), 2 );
409
if(!fourElement->text().isEmpty() && count >= 4 )
413
tmp=tmp+";"+createParameter(fourElement->text(), 3 );
415
tmp=tmp+createParameter(fourElement->text(), 3 );
417
if(!fiveElement->text().isEmpty() && count >= 5 )
421
tmp=tmp+";"+createParameter(fiveElement->text(), 4 );
423
tmp=tmp+createParameter(fiveElement->text(), 4 );
429
QString KSpreadDlgFormula::createParameter( const QString& _text, int param )
431
if ( _text.isEmpty() )
432
return QString( "" );
435
return QString( "" );
439
KSpreadParameterType elementType = m_desc->param( param ).type();
441
switch( elementType )
446
double tmp = m_pView->doc()->locale()->readNumber( _text, &isNumber );
449
//In case of number or boolean return _text, else return value as KSpread_String
450
if ( isNumber || _text.upper() =="FALSE" || _text.upper() == "TRUE" )
455
// Does the text start with quotes?
456
if ( _text[0] == '"' )
458
text = "\\"; // changed: was "\""
464
while( ( pos = tmp.find( '"', start ) ) != -1 )
466
if (tmp[pos - 1] != '\\')
467
tmp.replace( pos, 1, "\\\"" );
477
KSpreadPoint p = KSpreadPoint( _text, m_pView->doc()->map() );
478
KSpreadRange r = KSpreadRange( _text, m_pView->doc()->map() );
480
if( !p.isValid() && !r.isValid() )
488
while( ( pos = tmp.find( '"', start ) ) != -1 )
490
if (tmp[pos - 1] != '\\')
491
tmp.replace( pos, 1, "\\\"" );
506
case KSpread_Boolean:
516
static void showEntry( QLineEdit* edit, QLabel* label, KSpreadFunctionDescription* desc, int param )
520
label->setText( desc->param( param ).helpText()+":" );
522
KSpreadParameterType elementType = desc->param( param ).type();
523
KFloatValidator *validate=0L;
524
switch( elementType )
527
case KSpread_Boolean:
529
edit->clearValidator ();
532
validate=new KFloatValidator (edit);
533
validate->setAcceptLocalizedNumbers(true);
534
edit->setValidator(validate);
535
edit->setText( "0" );
538
edit->setValidator(new QIntValidator (edit));
539
edit->setText( "0" );
545
void KSpreadDlgFormula::slotDoubleClicked( QListBoxItem* item )
549
refresh_result = false;
552
m_browser->setText( "" );
557
int old_length = result->text().length();
559
// Dont change order of these function calls due to a bug in Qt 2.2
560
m_browser->setText( m_desc->toQML() );
561
m_tabwidget->setTabEnabled( m_input, TRUE );
562
m_tabwidget->setCurrentPage( 1 );
565
// Show as many QLineEdits as needed.
567
if( m_desc->params() > 0 )
569
m_focus = firstElement;
570
firstElement->setFocus();
572
showEntry( firstElement, label1, m_desc, 0 );
577
firstElement->hide();
580
if( m_desc->params() > 1 )
582
showEntry( secondElement, label2, m_desc, 1 );
587
secondElement->hide();
590
if( m_desc->params() > 2 )
592
showEntry( thirdElement, label3, m_desc, 2 );
597
thirdElement->hide();
600
if( m_desc->params() > 3 )
602
showEntry( fourElement, label4, m_desc, 3 );
610
if( m_desc->params() > 4 )
612
showEntry( fiveElement, label5, m_desc, 4 );
620
if( m_desc->params() > 5 )
622
kdDebug(36001) << "Error in param->nb_param" << endl;
624
refresh_result = true;
626
// Put the new function call in the result.
628
if( result->cursorPosition() < old_length )
630
m_rightText=result->text().right(old_length-result->cursorPosition());
631
m_leftText=result->text().left(result->cursorPosition());
636
m_leftText=result->text();
638
int pos = result->cursorPosition();
639
result->setText( m_leftText+functions->text( functions->currentItem() ) + "()" + m_rightText);
641
if (result->text()[0] != '=')
642
result->setText("=" + result->text());
645
// Put focus somewhere is there are no QLineEdits visible
647
if( m_desc->params() == 0 )
650
label1->setText( i18n("This function has no parameters.") );
653
result->setCursorPosition(pos+functions->text(functions->currentItem()).length()+2);
655
slotChangeText( "" );
658
void KSpreadDlgFormula::slotSelected( const QString& function )
660
KSpreadFunctionDescription* desc =
661
KSpreadFunctionRepository::self()->functionInfo( function );
664
m_browser->setText( "" );
668
if( functions->currentItem() !=- 1 )
669
selectFunction->setEnabled( TRUE );
672
refresh_result = false;
674
m_funcName = function;
678
m_browser->setText( m_desc->toQML() );
679
m_browser->setContentsPos( 0, 0 );
683
m_tabwidget->setCurrentPage( 0 );
684
m_tabwidget->setTabEnabled( m_input, FALSE );
690
// from hyperlink in the "Related Function"
691
void KSpreadDlgFormula::slotShowFunction( const QString& function )
693
KSpreadFunctionDescription* desc =
694
KSpreadFunctionRepository::self()->functionInfo( function );
697
// select the category
698
QString category = desc->group();
699
typeFunction->setCurrentText( category );
700
slotActivated( category );
702
// select the function
703
QListBoxItem* item = functions->findItem( function,
704
Qt::ExactMatch | Qt::CaseSensitive );
705
if( item ) functions->setCurrentItem( item );
707
slotSelected( function );
710
void KSpreadDlgFormula::slotSelectionChanged( KSpreadSheet* _table, const QRect& _selection )
715
if ( _selection.left() == 0 )
718
if ( _selection.left() >= _selection.right() && _selection.top() >= _selection.bottom() )
720
int dx = _selection.right();
721
int dy = _selection.bottom();
724
tmp = _table->tableName() + "!" + util_encodeColumnLabelText( dx ) + tmp;
725
m_focus->setText( tmp );
729
QString area = util_rangeName( _table, _selection );
730
m_focus->setText( area );
734
void KSpreadDlgFormula::slotActivated( const QString& category )
737
if ( category == i18n("All") )
738
lst = KSpreadFunctionRepository::self()->functionNames();
740
lst = KSpreadFunctionRepository::self()->functionNames( category );
742
kdDebug(36001)<<"category: "<<category<<" ("<<lst.count()<<"functions)" << endl;
745
functions->insertStringList( lst );
747
QStringList upperList;
748
for ( QStringList::Iterator it = lst.begin(); it != lst.end();++it )
749
upperList.append((*it).upper());
751
listFunct.setItems( upperList );
753
// Go to the first function in the list.
754
functions->setCurrentItem(0);
755
slotSelected( functions->text(0) );
758
void KSpreadDlgFormula::closeEvent ( QCloseEvent * e )
763
#include "kspread_dlg_formula.moc"