/* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 2004 Fredrik Edemar * f_edemar@linux.se * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include "kminmax.h" #include "xparser.h" KMinMax::KMinMax(View *v, TQWidget *parent, const char *name) : QMinMax(parent, name), m_view(v) { m_mode=-1; connect( cmdClose, TQT_SIGNAL( clicked() ), this, TQT_SLOT( close() )); connect( cmdFind, TQT_SIGNAL( clicked() ), this, TQT_SLOT( cmdFind_clicked() )); connect( cmdParameter, TQT_SIGNAL( clicked() ), this, TQT_SLOT( cmdParameter_clicked() )); connect( list, TQT_SIGNAL( highlighted(TQListBoxItem*) ), this, TQT_SLOT( list_highlighted(TQListBoxItem*) )); connect( list, TQT_SIGNAL( doubleClicked( TQListBoxItem * ) ), this, TQT_SLOT( list_doubleClicked(TQListBoxItem *) )); parameter=""; } void KMinMax::init(char m) { if ( m_mode==m) { if ( m_mode == 2) //get y-value max->setText(""); updateFunctions(); return; } m_mode = m; if ( m_mode < 2) //find minimum point { max->setReadOnly(false); TQString range; range.setNum(View::xmin); min->setText( range); range.setNum(View::xmax); max->setText(range); lblMin->setText(i18n("Search between the x-value:")); lblMax->setText(i18n("and:")); cmdFind->setText(i18n("&Find")); TQToolTip::add(min,i18n("Lower boundary of the plot range")); TQWhatsThis::add(min,i18n("Enter the lower boundary of the plot range. Expressions like 2*pi are allowed, too.")); TQToolTip::add(max,i18n("Upper boundary of the plot range")); TQWhatsThis::add(max,i18n("Enter the upper boundary of the plot range. Expressions like 2*pi are allowed, too.")); if ( m_mode == 1) //find maximum point { setCaption(i18n("Find Maximum Point")); TQToolTip::add( cmdFind, i18n( "Search for the maximum point in the range you specified" ) ); TQWhatsThis::add(cmdFind,i18n("Search for the highest y-value in the x-range you specified and show the result in a message box.")); } else { setCaption(i18n("Find Minimum Point")); TQToolTip::add( cmdFind, i18n( "Search for the minimum point in the range you specified" ) ); TQWhatsThis::add(cmdFind,i18n("Search for the lowest y-value in the x-range you specified and show the result in a message box.")); } } else if ( m_mode == 2) //get y-value { setCaption(i18n("Get y-Value")); lblMin->setText(i18n("X:")); lblMax->setText(i18n("Y:")); max->setReadOnly(true); min->setText(""); max->setText(""); TQToolTip::add(min,i18n("Lower boundary of the plot range")); TQWhatsThis::add(min,i18n("Enter the lower boundary of the plot range. Expressions like 2*pi are allowed, too.")); TQToolTip::add(max,i18n("No returned y-value yet")); TQWhatsThis::add(max,i18n("Here you will see the y-value which you got from the x-value in the textbox above. To calculate the y-value, press the Calculate button.")); cmdFind->setText(i18n("&Calculate")); TQToolTip::add( cmdFind, i18n( "Get the y-value from the x-value you typed" ) ); TQWhatsThis::add(cmdFind,i18n("Get the y-value from the x-value you typed and show it in the y-value box.")); } else if ( m_mode == 3) //area under a graph { max->setReadOnly(false); TQString range; range.setNum(View::xmin); min->setText( range); range.setNum(View::xmax); max->setText(range); TQToolTip::add(min,i18n("Lower boundary of the plot range")); TQWhatsThis::add(min,i18n("Enter the lower boundary of the plot range. Expressions like 2*pi are allowed, too.")); TQToolTip::add(max,i18n("Upper boundary of the plot range")); TQWhatsThis::add(max,i18n("Enter the upper boundary of the plot range. Expressions like 2*pi are allowed, too.")); setCaption(i18n("Calculate Integral")); lblMin->setText(i18n("Calculate the integral between the x-values:")); lblMax->setText(i18n("and:")); cmdFind->setText(i18n("&Calculate")); TQToolTip::add( cmdFind, i18n( "Calculate the integral between the x-values" ) ); TQWhatsThis::add(cmdFind,i18n("Calculate the numeric integral between the x-values and draw the result as an area.")); } min->setFocus(); updateFunctions(); } void KMinMax::updateFunctions() { TQString const selected_item(list->currentText() ); list->clear(); for( TQValueVector::iterator it = m_view->parser()->ufkt.begin(); it != m_view->parser()->ufkt.end(); ++it) { if( it->fname[0] != 'x' && it->fname[0] != 'y' && it->fname[0] != 'r' && !it->fname.isEmpty()) { if ( it->f_mode ) list->insertItem(it->fstr); if ( it->f1_mode ) //1st derivative { TQString function (it->fstr); int i= function.find('('); function.truncate(i); function +="\'"; list->insertItem(function ); } if ( it->f2_mode )//2nd derivative { TQString function (it->fstr); int i= function.find('('); function.truncate(i); function +="\'\'"; list->insertItem(function ); } if ( it->integral_mode )//integral { TQString function (it->fstr); int i= function.find('('); function.truncate(i); function = function.upper(); list->insertItem(function ); } } } list->sort(); if (list->count()==0) //empty list cmdFind->setEnabled(false); else cmdFind->setEnabled(true); selectItem(); TQListBoxItem *found_item = list->findItem(selected_item,TQt::ExactMatch); if ( found_item && m_view->csmode < 0) list->setSelected(found_item,true); } void KMinMax::selectItem() { cmdParameter->hide(); if ( m_view->csmode < 0) return; //kdDebug() << "cstype: " << (int)m_view->cstype << endl; Ufkt *ufkt = &m_view->parser()->ufkt[m_view->parser()->ixValue(m_view->csmode)]; TQString function = ufkt->fstr; if ( m_view->cstype == 2) { int i= function.find('('); function.truncate(i); function +="\'\'"; } else if ( m_view->cstype == 1) { int i= function.find('('); function.truncate(i); function +="\'"; } //kdDebug() << "function: " << function << endl; TQListBoxItem *item = list->findItem(function,TQt::ExactMatch); list->setSelected(item,true); if ( !ufkt->parameters.isEmpty() ) parameter = ufkt->parameters[m_view->csparam].expression; } KMinMax::~KMinMax() { } void KMinMax::cmdFind_clicked() { if ( list->currentItem() == -1) { KMessageBox::error(this, i18n("Please choose a function")); return; } double dmin, dmax; dmin = m_view->parser()->eval(min->text() ); if ( m_view->parser()->parserError()!=0 ) { min->setFocus(); min->selectAll(); return; } if ( m_mode != 2) { dmax = m_view->parser()->eval(max->text() ); if ( m_view->parser()->parserError()!=0 ) { max->setFocus(); max->selectAll(); return; } if ( dmin >= dmax) { KMessageBox::error(this,i18n("The minimum range value must be lower than the maximum range value")); min->setFocus(); min->selectAll(); return; } if ( dminView::xmax ) { KMessageBox::error(this,i18n("Please insert a minimum and maximum range between %1 and %2").arg(View::xmin).arg(View::xmax) ); min->setFocus(); min->selectAll(); return; } } TQString function( list->currentText() ); char p_mode = 0; if ( function.contains('\'') == 1) { p_mode = 1; int pos = function.find('\''); function.remove(pos,1); } else if ( function.contains('\'') == 2) { p_mode = 2; int pos = function.find('\''); function.remove(pos,2); } else if ( function.at(0).category() == TQChar::Letter_Uppercase) { p_mode = 3; function.at(0) = function.at(0).lower(); } TQString fname, fstr; Ufkt *ufkt = 0; TQString sec_function = function.section('(',0,0); for( TQValueVector::iterator it = m_view->parser()->ufkt.begin(); it != m_view->parser()->ufkt.end(); ++it) { if ( it->fstr.section('(',0,0) == sec_function) { ufkt = it; break; } } if ( !ufkt) { KMessageBox::error(this,i18n("Function could not be found")); return; } if ( ufkt->parameters.isEmpty() ) parameter = "0"; else if ( parameter.isEmpty()) { KMessageBox::error(this,i18n("You must choose a parameter for that function")); list_highlighted(list->selectedItem() ); return; } if ( m_mode == 0) { m_view->findMinMaxValue(ufkt,p_mode,true,dmin,dmax,parameter); if ( !m_view->isCalculationStopped() ) KMessageBox::information(this,i18n("Minimum value:\nx: %1\ny: %2").arg(dmin).arg(dmax) ); } else if ( m_mode == 1) { m_view->findMinMaxValue(ufkt,p_mode,false,dmin,dmax,parameter); if ( !m_view->isCalculationStopped() ) KMessageBox::information(this,i18n("Maximum value:\nx: %1\ny: %2").arg(dmin).arg(dmax)); } else if ( m_mode == 2) { m_view->getYValue(ufkt,p_mode,dmin,dmax,parameter); if ( !m_view->isCalculationStopped() ) { TQString tmp; tmp.setNum(dmax); max->setText(tmp); } TQToolTip::add(max,i18n("The returned y-value")); TQWhatsThis::add(max,i18n("Here you see the result of the calculation: the returned y-value you got from the x-value in the textbox above")); } else if ( m_mode == 3) { double dmin_tmp = dmin; m_view->areaUnderGraph(ufkt,p_mode,dmin,dmax,parameter, 0); if ( !m_view->isCalculationStopped() ) { m_view->setFocus(); m_view->update(); KMessageBox::information(this,i18n("The integral in the interval [%1, %2] is:\n%3").arg(dmin_tmp).arg(dmax).arg(dmin)); } } if ( m_view->isCalculationStopped() ) KMessageBox::error(this,i18n("The operation was cancelled by the user.")); } void KMinMax::list_highlighted(TQListBoxItem* item) { if ( !item) { cmdParameter->hide(); return; } TQString function( list->currentText() ); char p_mode = 0; if ( function.contains('\'') == 1) { p_mode = 1; int pos = function.find('\''); function.remove(pos,1); } else if ( function.contains('\'') == 2) { p_mode = 2; int pos = function.find('\''); function.remove(pos,2); } else if ( function.at(0).category() == TQChar::Letter_Uppercase) { p_mode = 3; function.at(0) = function.at(0).lower(); } TQString const sec_function = function.section('(',0,0); for(TQValueVector::iterator it = m_view->parser()->ufkt.begin(); it!=m_view->parser()->ufkt.end(); ++it) { if ( it->fstr.section('(',0,0) == sec_function) { if ( it->parameters.count() == 0) cmdParameter->hide(); else { cmdParameter->show(); if (parameter.isEmpty() ) parameter = it->parameters.first().expression; } break; } } } void KMinMax::cmdParameter_clicked() { TQString function( list->currentText() ); char p_mode = 0; if ( function.contains('\'') == 1) { p_mode = 1; int pos = function.find('\''); function.remove(pos,1); } else if ( function.contains('\'') == 2) { p_mode = 2; int pos = function.find('\''); function.remove(pos,2); } else if ( function.at(0).category() == TQChar::Letter_Uppercase) { p_mode = 3; function.at(0) = function.at(0).lower(); } TQString const sec_function = function.section('(',0,0); for(TQValueVector::iterator it = m_view->parser()->ufkt.begin() ; it!=m_view->parser()->ufkt.end(); ++it) { if ( it->fstr.section('(',0,0) == sec_function) { TQStringList str_parameters; for ( TQValueList::Iterator k = it->parameters.begin(); k != it->parameters.end(); ++k ) str_parameters.append( (*k).expression); bool ok; TQStringList result = KInputDialog::getItemList( i18n("Choose Parameter"), i18n("Choose a parameter to use:"), str_parameters, TQStringList(parameter),false,&ok,this ); if ( ok) parameter = result.first(); break; } } } void KMinMax::list_doubleClicked(TQListBoxItem *) { if ( list->currentItem() == -1) return; else if( cmdParameter->isShown() ) cmdParameter_clicked(); } #include "kminmax.moc"