00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <qtextbrowser.h>
00028 #include <qtabwidget.h>
00029
00030 #include "kspread_dlg_formula.h"
00031 #include "kspread_canvas.h"
00032 #include "kspread_util.h"
00033 #include "kspread_editors.h"
00034 #include "kspread_doc.h"
00035 #include "kspread_locale.h"
00036 #include "kspread_map.h"
00037 #include "selection.h"
00038 #include "kspread_sheet.h"
00039 #include "kspread_view.h"
00040 #include "functions.h"
00041
00042 #include <kapplication.h>
00043 #include <kdebug.h>
00044 #include <kbuttonbox.h>
00045 #include <knumvalidator.h>
00046 #include <qcombobox.h>
00047 #include <qevent.h>
00048 #include <qlistbox.h>
00049 #include <qlabel.h>
00050 #include <qpushbutton.h>
00051 #include <klineedit.h>
00052 #include <qlayout.h>
00053
00054 using namespace KSpread;
00055
00056 FormulaDialog::FormulaDialog( View* parent, const char* name,const QString& formulaName)
00057 : KDialogBase( parent, name,false,i18n("Function"), Ok|Cancel )
00058 {
00059 setWFlags( Qt::WDestructiveClose );
00060
00061 m_pView = parent;
00062 m_focus = 0;
00063 m_desc = 0;
00064
00065 Cell* cell = m_pView->activeSheet()->cellAt( m_pView->canvasWidget()->markerColumn(),
00066 m_pView->canvasWidget()->markerRow() );
00067 m_oldText=cell->text();
00068
00069 if ( !m_pView->canvasWidget()->editor() )
00070 {
00071 m_pView->canvasWidget()->createEditor( Canvas::CellEditor );
00072 if(cell->text().isEmpty())
00073 m_pView->canvasWidget()->editor()->setText( "=" );
00074 else
00075 if(cell->text().at(0)!='=')
00076 m_pView->canvasWidget()->editor()->setText( "="+cell->text() );
00077 else
00078 m_pView->canvasWidget()->editor()->setText( cell->text() );
00079 }
00080
00081 Q_ASSERT( m_pView->canvasWidget()->editor() );
00082
00083 QWidget *page = new QWidget( this );
00084 setMainWidget(page);
00085
00086 QGridLayout *grid1 = new QGridLayout(page,11,2,KDialog::marginHint(), KDialog::spacingHint());
00087
00088 searchFunct = new KLineEdit(page);
00089 QSizePolicy sp3( QSizePolicy::Preferred, QSizePolicy::Fixed );
00090 searchFunct->setSizePolicy( sp3 );
00091
00092 grid1->addWidget( searchFunct, 0, 0 );
00093
00094 typeFunction = new QComboBox(page);
00095 QStringList cats = FunctionRepository::self()->groups();
00096 cats.prepend( i18n("All") );
00097 typeFunction->insertStringList( cats );
00098 grid1->addWidget( typeFunction, 1, 0 );
00099
00100 functions = new QListBox(page);
00101 QSizePolicy sp1( QSizePolicy::Preferred, QSizePolicy::Expanding );
00102 functions->setSizePolicy( sp1 );
00103 grid1->addWidget( functions, 2, 0 );
00104
00105 selectFunction = new QPushButton( page );
00106 QToolTip::add(selectFunction, i18n("Insert function") );
00107 selectFunction->setPixmap( BarIcon( "down", KIcon::SizeSmall ) );
00108 grid1->addWidget( selectFunction, 3, 0 );
00109
00110 result = new QLineEdit( page );
00111 grid1->addMultiCellWidget( result, 4, 4, 0, 1 );
00112
00113 m_tabwidget = new QTabWidget( page );
00114 QSizePolicy sp2( QSizePolicy::Expanding, QSizePolicy::Expanding );
00115 m_tabwidget->setSizePolicy( sp2 );
00116 grid1->addMultiCellWidget( m_tabwidget, 0, 2, 1, 1 );
00117
00118 m_browser = new QTextBrowser( m_tabwidget );
00119 m_browser->setMinimumWidth( 300 );
00120
00121 m_tabwidget->addTab( m_browser, i18n("&Help") );
00122 int index = m_tabwidget->currentPageIndex();
00123
00124 m_input = new QWidget( m_tabwidget );
00125 QVBoxLayout *grid2 = new QVBoxLayout( m_input, KDialog::marginHint(), KDialog::spacingHint() );
00126
00127
00128
00129 label1 = new QLabel(m_input);
00130 grid2->addWidget( label1 );
00131
00132 firstElement=new QLineEdit(m_input);
00133 grid2->addWidget( firstElement );
00134
00135 label2=new QLabel(m_input);
00136 grid2->addWidget( label2 );
00137
00138 secondElement=new QLineEdit(m_input);
00139 grid2->addWidget( secondElement );
00140
00141 label3=new QLabel(m_input);
00142 grid2->addWidget( label3 );
00143
00144 thirdElement=new QLineEdit(m_input);
00145 grid2->addWidget( thirdElement );
00146
00147 label4=new QLabel(m_input);
00148 grid2->addWidget( label4 );
00149
00150 fourElement=new QLineEdit(m_input);
00151 grid2->addWidget( fourElement );
00152
00153 label5=new QLabel(m_input);
00154 grid2->addWidget( label5 );
00155
00156 fiveElement=new QLineEdit(m_input);
00157 grid2->addWidget( fiveElement );
00158
00159 grid2->addStretch( 10 );
00160
00161 m_tabwidget->addTab( m_input, i18n("&Parameters") );
00162 m_tabwidget->setTabEnabled( m_input, FALSE );
00163
00164 m_tabwidget->setCurrentPage( index );
00165
00166 refresh_result = true;
00167
00168 connect( this, SIGNAL( cancelClicked() ), this, SLOT( slotClose() ) );
00169 connect( this, SIGNAL( okClicked() ), this, SLOT( slotOk() ) );
00170 connect( typeFunction, SIGNAL( activated(const QString &) ),
00171 this, SLOT( slotActivated(const QString &) ) );
00172 connect( functions, SIGNAL( highlighted(const QString &) ),
00173 this, SLOT( slotSelected(const QString &) ) );
00174 connect( functions, SIGNAL( selected(const QString &) ),
00175 this, SLOT( slotSelected(const QString &) ) );
00176 connect( functions, SIGNAL( doubleClicked(QListBoxItem * ) ),
00177 this ,SLOT( slotDoubleClicked(QListBoxItem *) ) );
00178
00179 slotActivated(i18n("All"));
00180
00181 connect( selectFunction, SIGNAL(clicked()),
00182 this,SLOT(slotSelectButton()));
00183
00184 connect( firstElement,SIGNAL(textChanged ( const QString & )),
00185 this,SLOT(slotChangeText(const QString &)));
00186 connect( secondElement,SIGNAL(textChanged ( const QString & )),
00187 this,SLOT(slotChangeText(const QString &)));
00188 connect( thirdElement,SIGNAL(textChanged ( const QString & )),
00189 this,SLOT(slotChangeText(const QString &)));
00190 connect( fourElement,SIGNAL(textChanged ( const QString & )),
00191 this,SLOT(slotChangeText(const QString &)));
00192 connect( fiveElement,SIGNAL(textChanged ( const QString & )),
00193 this,SLOT(slotChangeText(const QString &)));
00194
00195 connect( m_pView->choice(), SIGNAL(changed(const Region&)),
00196 this, SLOT(slotSelectionChanged()));
00197
00198 connect( m_browser, SIGNAL( linkClicked( const QString& ) ),
00199 this, SLOT( slotShowFunction( const QString& ) ) );
00200
00201
00202 m_sheetName = m_pView->activeSheet()->sheetName();
00203
00204 QString tmp_oldText = m_pView->canvasWidget()->editor()->text();
00205
00206 m_column = m_pView->canvasWidget()->markerColumn();
00207 m_row = m_pView->canvasWidget()->markerRow();
00208
00209 if( tmp_oldText.isEmpty() )
00210 result->setText("=");
00211 else
00212 {
00213 if( tmp_oldText.at(0)!='=')
00214 result->setText( "=" + tmp_oldText );
00215 else
00216 result->setText( tmp_oldText );
00217 }
00218
00219
00220 m_pView->canvasWidget()->startChoose();
00221
00222 qApp->installEventFilter( this );
00223
00224
00225 if( !formulaName.isEmpty() )
00226 {
00227 functions->setCurrentItem( functions->index( functions->findItem( formulaName ) ) );
00228 slotDoubleClicked( functions->findItem( formulaName ) );
00229 }
00230 else
00231 {
00232
00233 searchFunct->setFocus();
00234 }
00235
00236
00237 searchFunct->setCompletionMode( KGlobalSettings::CompletionAuto );
00238 searchFunct->setCompletionObject( &listFunct, true );
00239
00240 if( functions->currentItem() == -1 )
00241 selectFunction->setEnabled( false );
00242
00243 connect( searchFunct, SIGNAL( textChanged( const QString & ) ),
00244 this, SLOT( slotSearchText(const QString &) ) );
00245 connect( searchFunct, SIGNAL( returnPressed() ),
00246 this, SLOT( slotPressReturn() ) );
00247 }
00248
00249 FormulaDialog::~FormulaDialog()
00250 {
00251 kdDebug(36001)<<"FormulaDialog::~FormulaDialog() \n";
00252 }
00253
00254 void FormulaDialog::slotPressReturn()
00255 {
00256
00257
00258
00259
00260
00261
00262
00263 }
00264
00265 void FormulaDialog::slotSearchText(const QString &_text)
00266 {
00267 QString result = listFunct.makeCompletion( _text.upper() );
00268 if( !result.isNull() )
00269 functions->setCurrentItem( functions->index( functions->findItem( result ) ) );
00270 }
00271
00272 bool FormulaDialog::eventFilter( QObject* obj, QEvent* ev )
00273 {
00274 if ( obj == firstElement && ev->type() == QEvent::FocusIn )
00275 m_focus = firstElement;
00276 else if ( obj == secondElement && ev->type() == QEvent::FocusIn )
00277 m_focus = secondElement;
00278 else if ( obj == thirdElement && ev->type() == QEvent::FocusIn )
00279 m_focus = thirdElement;
00280 else if ( obj == fourElement && ev->type() == QEvent::FocusIn )
00281 m_focus = fourElement;
00282 else if ( obj == fiveElement && ev->type() == QEvent::FocusIn )
00283 m_focus = fiveElement;
00284 else
00285 return FALSE;
00286
00287 if ( m_focus )
00288 m_pView->canvasWidget()->startChoose();
00289
00290 return FALSE;
00291 }
00292
00293 void FormulaDialog::slotOk()
00294 {
00295 m_pView->doc()->emitBeginOperation( false );
00296
00297 m_pView->canvasWidget()->endChoose();
00298
00299 if( m_pView->activeSheet()->sheetName() != m_sheetName )
00300 {
00301 Sheet *sheet=m_pView->doc()->map()->findSheet(m_sheetName);
00302 if( sheet)
00303 m_pView->setActiveSheet(sheet);
00304 }
00305
00306
00307 m_pView->selectionInfo()->initialize( QPoint( m_column, m_row ) );
00308
00309
00310
00311 if( m_pView->canvasWidget()->editor() != 0 )
00312 {
00313 Q_ASSERT( m_pView->canvasWidget()->editor() );
00314 QString tmp = result->text();
00315 if( tmp.at(0) != '=')
00316 tmp = "=" + tmp;
00317 int pos = m_pView->canvasWidget()->editor()->cursorPosition()+ tmp.length();
00318 m_pView->canvasWidget()->editor()->setText( tmp );
00319 m_pView->canvasWidget()->editor()->setFocus();
00320 m_pView->canvasWidget()->editor()->setCursorPosition( pos );
00321 }
00322
00323 m_pView->slotUpdateView( m_pView->activeSheet() );
00324 accept();
00325
00326 }
00327
00328 void FormulaDialog::slotClose()
00329 {
00330 m_pView->doc()->emitBeginOperation( false );
00331
00332 m_pView->canvasWidget()->endChoose();
00333
00334
00335 if(m_pView->activeSheet()->sheetName() != m_sheetName )
00336 {
00337 Sheet *sheet=m_pView->doc()->map()->findSheet(m_sheetName);
00338 if( !sheet )
00339 return;
00340 m_pView->setActiveSheet(sheet);
00341 }
00342
00343
00344
00345 m_pView->selectionInfo()->initialize( QPoint( m_column, m_row ) );
00346
00347
00348
00349 if( m_pView->canvasWidget()->editor() != 0 )
00350 {
00351 Q_ASSERT( m_pView->canvasWidget()->editor() );
00352 m_pView->canvasWidget()->editor()->setText( m_oldText );
00353 m_pView->canvasWidget()->editor()->setFocus();
00354 }
00355
00356 m_pView->slotUpdateView( m_pView->activeSheet() );
00357 reject();
00358
00359
00360
00361 }
00362
00363 void FormulaDialog::slotSelectButton()
00364 {
00365 if( functions->currentItem() != -1 )
00366 {
00367 slotDoubleClicked(functions->findItem(functions->text(functions->currentItem())));
00368 }
00369 }
00370
00371 void FormulaDialog::slotChangeText( const QString& )
00372 {
00373
00374 if( !refresh_result )
00375 return;
00376
00377 if ( m_focus == 0 )
00378 return;
00379
00380 QString tmp = m_leftText+m_funcName+"(";
00381 tmp += createFormula();
00382 tmp = tmp+ ")" + m_rightText;
00383
00384 result->setText( tmp );
00385 }
00386
00387 QString FormulaDialog::createFormula()
00388 {
00389 QString tmp( "" );
00390
00391 if ( !m_desc )
00392 return QString::null;
00393
00394 bool first = TRUE;
00395
00396 int count = m_desc->params();
00397
00398 if(!firstElement->text().isEmpty() && count >= 1 )
00399 {
00400 tmp=tmp+createParameter(firstElement->text(), 0 );
00401 first = FALSE;
00402 }
00403
00404 if(!secondElement->text().isEmpty() && count >= 2 )
00405 {
00406 first = FALSE;
00407 if ( !first )
00408 tmp=tmp+";"+createParameter(secondElement->text(), 1 );
00409 else
00410 tmp=tmp+createParameter(secondElement->text(), 1 );
00411 }
00412 if(!thirdElement->text().isEmpty() && count >= 3 )
00413 {
00414 first = FALSE;
00415 if ( !first )
00416 tmp=tmp+";"+createParameter(thirdElement->text(), 2 );
00417 else
00418 tmp=tmp+createParameter(thirdElement->text(), 2 );
00419 }
00420 if(!fourElement->text().isEmpty() && count >= 4 )
00421 {
00422 first = FALSE;
00423 if ( !first )
00424 tmp=tmp+";"+createParameter(fourElement->text(), 3 );
00425 else
00426 tmp=tmp+createParameter(fourElement->text(), 3 );
00427 }
00428 if(!fiveElement->text().isEmpty() && count >= 5 )
00429 {
00430 first = FALSE;
00431 if ( !first )
00432 tmp=tmp+";"+createParameter(fiveElement->text(), 4 );
00433 else
00434 tmp=tmp+createParameter(fiveElement->text(), 4 );
00435 }
00436
00437 return(tmp);
00438 }
00439
00440 QString FormulaDialog::createParameter( const QString& _text, int param )
00441 {
00442 if ( _text.isEmpty() )
00443 return QString( "" );
00444
00445 if ( !m_desc )
00446 return QString( "" );
00447
00448 QString text;
00449
00450 ParameterType elementType = m_desc->param( param ).type();
00451
00452 switch( elementType )
00453 {
00454 case KSpread_Any:
00455 {
00456 bool isNumber;
00457 double tmp = m_pView->doc()->locale()->readNumber( _text, &isNumber );
00458 Q_UNUSED( tmp );
00459
00460
00461 if ( isNumber || _text.upper() =="FALSE" || _text.upper() == "TRUE" )
00462 return _text;
00463 }
00464 case KSpread_String:
00465 {
00466
00467 if ( _text[0] == '"' )
00468 {
00469 text = "\\";
00470
00471
00472 QString tmp = _text;
00473 int pos;
00474 int start = 1;
00475 while( ( pos = tmp.find( '"', start ) ) != -1 )
00476 {
00477 if (tmp[pos - 1] != '\\')
00478 tmp.replace( pos, 1, "\\\"" );
00479 else
00480 start = pos + 1;
00481 }
00482
00483 text += tmp;
00484 text += "\"";
00485 }
00486 else
00487 {
00488 Point p = Point( _text, m_pView->doc()->map() );
00489 Range r = Range( _text, m_pView->doc()->map() );
00490
00491 if( !p.isValid() && !r.isValid() )
00492 {
00493 text = "\"";
00494
00495
00496 QString tmp = _text;
00497 int pos;
00498 int start = 1;
00499 while( ( pos = tmp.find( '"', start ) ) != -1 )
00500 {
00501 if (tmp[pos - 1] != '\\')
00502 tmp.replace( pos, 1, "\\\"" );
00503 else
00504 start = pos + 1;
00505 }
00506
00507 text += tmp;
00508 text += "\"";
00509 }
00510 else
00511 text = _text;
00512 }
00513 }
00514 return text;
00515 case KSpread_Float:
00516 return _text;
00517 case KSpread_Boolean:
00518 return _text;
00519 case KSpread_Int:
00520 return _text;
00521 }
00522
00523
00524 return text;
00525 }
00526
00527 static void showEntry( QLineEdit* edit, QLabel* label,
00528 FunctionDescription* desc, int param )
00529 {
00530 edit->show();
00531 label->setText( desc->param( param ).helpText()+":" );
00532 label->show();
00533 ParameterType elementType = desc->param( param ).type();
00534 KFloatValidator *validate=0L;
00535 switch( elementType )
00536 {
00537 case KSpread_String:
00538 case KSpread_Boolean:
00539 case KSpread_Any:
00540 edit->clearValidator ();
00541 break;
00542 case KSpread_Float:
00543 validate=new KFloatValidator (edit);
00544 validate->setAcceptLocalizedNumbers(true);
00545 edit->setValidator(validate);
00546 edit->setText( "0" );
00547 break;
00548 case KSpread_Int:
00549 edit->setValidator(new QIntValidator (edit));
00550 edit->setText( "0" );
00551 break;
00552 }
00553
00554 }
00555
00556 void FormulaDialog::slotDoubleClicked( QListBoxItem* item )
00557 {
00558 if ( !item )
00559 return;
00560 refresh_result = false;
00561 if ( !m_desc )
00562 {
00563 m_browser->setText( "" );
00564 return;
00565 }
00566
00567 m_focus = 0;
00568 int old_length = result->text().length();
00569
00570
00571 m_browser->setText( m_desc->toQML() );
00572 m_tabwidget->setTabEnabled( m_input, TRUE );
00573 m_tabwidget->setCurrentPage( 1 );
00574
00575
00576
00577
00578 if( m_desc->params() > 0 )
00579 {
00580 m_focus = firstElement;
00581 firstElement->setFocus();
00582
00583 showEntry( firstElement, label1, m_desc, 0 );
00584 }
00585 else
00586 {
00587 label1->hide();
00588 firstElement->hide();
00589 }
00590
00591 if( m_desc->params() > 1 )
00592 {
00593 showEntry( secondElement, label2, m_desc, 1 );
00594 }
00595 else
00596 {
00597 label2->hide();
00598 secondElement->hide();
00599 }
00600
00601 if( m_desc->params() > 2 )
00602 {
00603 showEntry( thirdElement, label3, m_desc, 2 );
00604 }
00605 else
00606 {
00607 label3->hide();
00608 thirdElement->hide();
00609 }
00610
00611 if( m_desc->params() > 3 )
00612 {
00613 showEntry( fourElement, label4, m_desc, 3 );
00614 }
00615 else
00616 {
00617 label4->hide();
00618 fourElement->hide();
00619 }
00620
00621 if( m_desc->params() > 4 )
00622 {
00623 showEntry( fiveElement, label5, m_desc, 4 );
00624 }
00625 else
00626 {
00627 label5->hide();
00628 fiveElement->hide();
00629 }
00630
00631 if( m_desc->params() > 5 )
00632 {
00633 kdDebug(36001) << "Error in param->nb_param" << endl;
00634 }
00635 refresh_result= true;
00636
00637
00638
00639 if( result->cursorPosition() < old_length )
00640 {
00641 m_rightText=result->text().right(old_length-result->cursorPosition());
00642 m_leftText=result->text().left(result->cursorPosition());
00643 }
00644 else
00645 {
00646 m_rightText="";
00647 m_leftText=result->text();
00648 }
00649 int pos = result->cursorPosition();
00650 result->setText( m_leftText+functions->text( functions->currentItem() ) + "()" + m_rightText);
00651
00652 if (result->text()[0] != '=')
00653 result->setText("=" + result->text());
00654
00655
00656
00657
00658 if( m_desc->params() == 0 )
00659 {
00660 label1->show();
00661 label1->setText( i18n("This function has no parameters.") );
00662
00663 result->setFocus();
00664 result->setCursorPosition(pos+functions->text(functions->currentItem()).length()+2);
00665 }
00666 slotChangeText( "" );
00667 }
00668
00669 void FormulaDialog::slotSelected( const QString& function )
00670 {
00671 FunctionDescription* desc =
00672 FunctionRepository::self()->functionInfo (function);
00673 if ( !desc )
00674 {
00675 m_browser->setText (i18n ("Description is not available."));
00676 return;
00677 }
00678
00679 if( functions->currentItem() !=- 1 )
00680 selectFunction->setEnabled( TRUE );
00681
00682
00683 refresh_result = false;
00684
00685 m_funcName = function;
00686 m_desc = desc;
00687
00688
00689 m_browser->setText( m_desc->toQML() );
00690 m_browser->setContentsPos( 0, 0 );
00691
00692 m_focus=0;
00693
00694 m_tabwidget->setCurrentPage( 0 );
00695 m_tabwidget->setTabEnabled( m_input, FALSE );
00696
00697
00698 refresh_result=true;
00699 }
00700
00701
00702 void FormulaDialog::slotShowFunction( const QString& function )
00703 {
00704 FunctionDescription* desc =
00705 FunctionRepository::self()->functionInfo( function );
00706 if ( !desc ) return;
00707
00708
00709 QString category = desc->group();
00710 typeFunction->setCurrentText( category );
00711 slotActivated( category );
00712
00713
00714 QListBoxItem* item = functions->findItem( function,
00715 Qt::ExactMatch | Qt::CaseSensitive );
00716 if( item ) functions->setCurrentItem( item );
00717
00718 slotSelected( function );
00719 }
00720
00721 void FormulaDialog::slotSelectionChanged()
00722 {
00723 if ( !m_focus )
00724 return;
00725
00726 if (m_pView->choice()->isValid())
00727 {
00728 QString area = m_pView->choice()->name();
00729 m_focus->setText( area );
00730 }
00731 }
00732
00733 void FormulaDialog::slotActivated( const QString& category )
00734 {
00735 QStringList lst;
00736 if ( category == i18n("All") )
00737 lst = FunctionRepository::self()->functionNames();
00738 else
00739 lst = FunctionRepository::self()->functionNames( category );
00740
00741 kdDebug(36001)<<"category: "<<category<<" ("<<lst.count()<<"functions)" << endl;
00742
00743 functions->clear();
00744 functions->insertStringList( lst );
00745
00746 QStringList upperList;
00747 for ( QStringList::Iterator it = lst.begin(); it != lst.end();++it )
00748 upperList.append((*it).upper());
00749
00750 listFunct.setItems( upperList );
00751
00752
00753 functions->setCurrentItem(0);
00754 slotSelected( functions->text(0) );
00755 }
00756
00757 void FormulaDialog::closeEvent ( QCloseEvent * e )
00758 {
00759 e->accept();
00760 }
00761
00762 #include "kspread_dlg_formula.moc"