You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeedu/kmplot/kmplot/editfunction.cpp

447 lines
16 KiB

/*
* KmPlot - a math. function plotter for the KDE-Desktop
*
* Copyright (C) 1998, 1999 Klaus-Dieter Möller
* 2000, 2002 kd.moeller@t-online.de
*
* 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.
*
*/
// TQt includes
#include <tqcheckbox.h>
#include <tqcombobox.h>
#include <tqdialog.h>
#include <tqframe.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqradiobutton.h>
#include <tqstringlist.h>
#include <tqvbox.h>
// KDE includes
#include <tdeapplication.h>
#include <kcolorbutton.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <knuminput.h>
#include <kpushbutton.h>
#include <kdebug.h>
// local includes
#include "editfunction.h"
#include "editfunction.moc"
#include "View.h"
#include "editfunctionpage.h"
#include "editderivativespage.h"
#include "editintegralpage.h"
#include "kparametereditor.h"
EditFunction::EditFunction( XParser* parser, TQWidget* parent, const char* name ) :
KDialogBase( IconList, "Caption", Help|Ok|Cancel, Ok, parent, name ), m_parser(parser)
{
TQVBox *page0 = addVBoxPage( i18n("Function"), i18n( "Function" ), SmallIcon( "func", 32 ) );
editfunctionpage = new EditFunctionPage( page0 );
TQVBox *page1 = addVBoxPage( i18n("Derivatives"), i18n( "Derivatives" ), SmallIcon( "deriv_func", 32 ) );
editderivativespage = new EditDerivativesPage( page1 );
TQVBox *page2 = addVBoxPage( i18n("Integral"), i18n( "Integral" ), SmallIcon( "integral_func", 32 ) );
editintegralpage = new EditIntegralPage( page2 );
for( int number = 0; number < SLIDER_COUNT; number++ )
{
editfunctionpage->listOfSliders->insertItem( i18n( "Slider No. %1" ).arg( number +1) );
}
connect( editfunctionpage->cmdParameter, TQT_SIGNAL ( clicked() ), this, TQT_SLOT( cmdParameter_clicked() ) );
connect( editfunctionpage->useNoParameter, TQT_SIGNAL ( toggled(bool) ), this, TQT_SLOT( noParameter_toggled(bool) ) );
connect( editfunctionpage->customMinRange, TQT_SIGNAL ( toggled(bool) ), this, TQT_SLOT( customMinRange_toggled(bool) ) );
connect( editfunctionpage->customMaxRange, TQT_SIGNAL ( toggled(bool) ), this, TQT_SLOT( customMaxRange_toggled(bool) ) );
m_updatedfunction = 0;
}
void EditFunction::initDialog( int id )
{
m_id = id;
if( m_id == -1 ) clearWidgets(); //new function, so clear all values
else setWidgets();
editfunctionpage->equation->setFocus();
}
void EditFunction::clearWidgets()
{
// Clear the Function page
editfunctionpage->equation->clear();
editfunctionpage->hide->setChecked( false );
editfunctionpage->customMinRange->setChecked( false );
editfunctionpage->customMaxRange->setChecked( false );
editfunctionpage->min->clear();
editfunctionpage->max->clear();
editfunctionpage->lineWidth->setValue( m_parser->linewidth0 );
editfunctionpage->color->setColor( m_parser->defaultColor(m_parser->getNextIndex() ) );
// Clear the Derivatives page
editderivativespage->showDerivative1->setChecked( false );
editderivativespage->lineWidthDerivative1->setValue( editfunctionpage->lineWidth->value() );
editderivativespage->colorDerivative1->setColor( editfunctionpage->color->color() );
editderivativespage->showDerivative2->setChecked( false );
editderivativespage->lineWidthDerivative2->setValue( editfunctionpage->lineWidth->value() );
editderivativespage->colorDerivative2->setColor( editfunctionpage->color->color() );
// Clear the Integral page
editintegralpage->precision->setValue( Settings::stepWidth());
editintegralpage->color->setColor( editfunctionpage->color->color() );
editintegralpage->lineWidth->setValue(editfunctionpage->lineWidth->value());
}
void EditFunction::setWidgets()
{
Ufkt *ufkt = &m_parser->ufkt[ m_parser->ixValue(m_id) ];
editfunctionpage->equation->setText( ufkt->fstr );
editfunctionpage->hide->setChecked( !ufkt->f_mode);
editfunctionpage->lineWidth->setValue( ufkt->linewidth );
editfunctionpage->color->setColor( ufkt->color );
if (ufkt->usecustomxmin)
{
editfunctionpage->customMinRange->setChecked(true);
editfunctionpage->min->setText( ufkt->str_dmin );
}
else
editfunctionpage->customMinRange->setChecked(false);
if (ufkt->usecustomxmax)
{
editfunctionpage->customMaxRange->setChecked(true);
editfunctionpage->max->setText( ufkt->str_dmax );
}
else
editfunctionpage->customMaxRange->setChecked(false);
m_parameter = ufkt->parameters;
if( ufkt->use_slider == -1 )
if ( ufkt->parameters.isEmpty() )
editfunctionpage->useNoParameter->setChecked( true );
else
editfunctionpage->useList->setChecked( true );
else
{
editfunctionpage->useSlider->setChecked( true );
editfunctionpage->listOfSliders->setCurrentItem( ufkt->use_slider );
}
editderivativespage->showDerivative1->setChecked( ufkt->f1_mode );
editderivativespage->lineWidthDerivative1->setValue( ufkt->f1_linewidth );
editderivativespage->colorDerivative1->setColor( ufkt->f1_color );
editderivativespage->showDerivative2->setChecked( ufkt->f2_mode );
editderivativespage->lineWidthDerivative2->setValue( ufkt->f2_linewidth );
editderivativespage->colorDerivative2->setColor( ufkt->f2_color );
editintegralpage->precision->setValue( ufkt->integral_precision );
editintegralpage->lineWidth->setValue( ufkt->integral_linewidth );
editintegralpage->color->setColor( ufkt->integral_color );
if ( ufkt->integral_mode )
{
editintegralpage->showIntegral->setChecked( ufkt->integral_mode );
editintegralpage->customPrecision->setChecked( ufkt->integral_use_precision );
editintegralpage->txtInitX->setText(ufkt->str_startx);
editintegralpage->txtInitY->setText(ufkt->str_starty);
}
}
void EditFunction::accept()
{
TQString f_str( editfunctionpage->equation->text() );
if ( m_id!=-1 )
m_parser->fixFunctionName(f_str, XParser::Function, m_id);
else
m_parser->fixFunctionName(f_str, XParser::Function);
if ( f_str.at(0)== 'x' || f_str.at(0)== 'y' || f_str.at(0)== 'r')
{
KMessageBox::error( this, i18n("You can only define plot functions in this dialog"));
return;
}
Ufkt tmp_ufkt; //all settings are saved here until we know that no errors have appeared
if( editfunctionpage->customMinRange->isChecked() )
{
tmp_ufkt.usecustomxmin = true;
tmp_ufkt.str_dmin = editfunctionpage->min->text();
tmp_ufkt.dmin = m_parser->eval( editfunctionpage->min->text() );
if (m_parser->parserError() != 0)
{
showPage(0);
editfunctionpage->min->setFocus();
editfunctionpage->min->selectAll();
return;
}
}
else
tmp_ufkt.usecustomxmin = false;
if( editfunctionpage->customMaxRange->isChecked() )
{
tmp_ufkt.usecustomxmax = true;
tmp_ufkt.str_dmax= editfunctionpage->max->text();
tmp_ufkt.dmax = m_parser->eval( editfunctionpage->max->text() );
if (m_parser->parserError() != 0)
{
showPage(0);
editfunctionpage->max->setFocus();
editfunctionpage->max->selectAll();
return;
}
}
else
tmp_ufkt.usecustomxmax = false;
if( tmp_ufkt.usecustomxmin && tmp_ufkt.usecustomxmax )
{
if ( tmp_ufkt.dmin >= tmp_ufkt.dmax)
{
KMessageBox::error(this,i18n("The minimum range value must be lower than the maximum range value"));
showPage(0);
editfunctionpage->min->setFocus();
editfunctionpage->min->selectAll();
return;
}
if ( tmp_ufkt.dmin<View::xmin || tmp_ufkt.dmax>View::xmax )
{
KMessageBox::error(this,i18n("Please insert a minimum and maximum range between %1 and %2").arg(View::xmin).arg(View::xmax) );
showPage(0);
editfunctionpage->min->setFocus();
editfunctionpage->min->selectAll();
return;
}
}
tmp_ufkt.linewidth = editfunctionpage->lineWidth->value();
tmp_ufkt.color = editfunctionpage->color->color().rgb();
if (editintegralpage->showIntegral->isChecked() )
{
double initx = m_parser->eval(editintegralpage->txtInitX->text());
tmp_ufkt.startx = initx;
tmp_ufkt.str_startx = editintegralpage->txtInitX->text();
if (m_parser->parserError(false) != 0)
{
KMessageBox::error(this,i18n("Please insert a valid x-value"));
showPage(2);
editintegralpage->txtInitX->setFocus();
editintegralpage->txtInitX->selectAll();
return;
}
double inity = m_parser->eval(editintegralpage->txtInitY->text());
tmp_ufkt.starty = inity;
tmp_ufkt.str_starty = editintegralpage->txtInitY->text();
if (m_parser->parserError(false) != 0)
{
KMessageBox::error(this,i18n("Please insert a valid y-value"));
showPage(2);
editintegralpage->txtInitY->setFocus();
editintegralpage->txtInitY->selectAll();
return;
}
tmp_ufkt.integral_mode = 1;
}
else
tmp_ufkt.integral_mode = 0;
tmp_ufkt.integral_color = editintegralpage->color->color().rgb();
tmp_ufkt.integral_use_precision = editintegralpage->customPrecision->isChecked();
tmp_ufkt.integral_precision = editintegralpage->precision->value();
tmp_ufkt.integral_linewidth = editintegralpage->lineWidth->value();
tmp_ufkt.f_mode = !editfunctionpage->hide->isChecked();
if( editfunctionpage->useSlider->isChecked() )
tmp_ufkt.use_slider = editfunctionpage->listOfSliders->currentItem(); //specify which slider that will be used
else
{
tmp_ufkt.use_slider = -1;
if ( editfunctionpage->useNoParameter->isChecked() || m_parameter.isEmpty() )
m_parameter.clear();
else
{
tmp_ufkt.parameters = m_parameter;
}
}
tmp_ufkt.f1_mode = editderivativespage->showDerivative1->isChecked();
tmp_ufkt.f1_linewidth = editderivativespage->lineWidthDerivative1->value();
tmp_ufkt.f1_color = editderivativespage->colorDerivative1->color().rgb();
tmp_ufkt.f2_mode = editderivativespage->showDerivative2->isChecked();
tmp_ufkt.f2_linewidth = editderivativespage->lineWidthDerivative2->value();
tmp_ufkt.f2_color = editderivativespage->colorDerivative2->color().rgb();
if ( f_str.contains('y') != 0 && ( tmp_ufkt.f_mode || tmp_ufkt.f1_mode || tmp_ufkt.f2_mode) )
{
KMessageBox::error( this, i18n( "Recursive function is only allowed when drawing integral graphs") );
return;
}
Ufkt *added_ufkt;
if( m_id != -1 ) //when editing a function:
{
int const ix = m_parser->ixValue(m_id);
if ( ix == -1) //The function could have been deleted
{
KMessageBox::error(this,i18n("Function could not be found"));
return;
}
added_ufkt = &m_parser->ufkt[ix];
TQString const old_fstr = added_ufkt->fstr;
if(( (!m_parameter.isEmpty() && editfunctionpage->useList->isChecked() ) || editfunctionpage->useSlider->isChecked() ) && !functionHas2Arguments() )
fixFunctionArguments(f_str); //adding an extra argument for the parameter value
added_ufkt->fstr = f_str;
m_parser->reparse(added_ufkt); //reparse the funcion
if ( m_parser->parserError() != 0)
{
added_ufkt->fstr = old_fstr;
m_parser->reparse(added_ufkt);
raise();
showPage(0);
editfunctionpage->equation->setFocus();
editfunctionpage->equation->selectAll();
return;
}
}
else //creating a new function
{
if(( (!m_parameter.isEmpty() && editfunctionpage->useList->isChecked() ) || editfunctionpage->useSlider->isChecked() ) && !functionHas2Arguments() )
fixFunctionArguments(f_str); //adding an extra argument for the parameter value
int const id = m_parser->addfkt( f_str ); //create a new function otherwise
if( id == -1)
{
m_parser->parserError();
raise();
showPage(0);
editfunctionpage->equation->setFocus();
editfunctionpage->equation->selectAll();
return;
}
added_ufkt = &m_parser->ufkt.last();
}
//save all settings in the function now when we know no errors have appeared
added_ufkt->f_mode = tmp_ufkt.f_mode;
added_ufkt->f1_mode = tmp_ufkt.f1_mode;
added_ufkt->f2_mode = tmp_ufkt.f2_mode;
added_ufkt->integral_mode = tmp_ufkt.integral_mode;
added_ufkt->integral_use_precision = tmp_ufkt.integral_use_precision;
added_ufkt->linewidth = tmp_ufkt.linewidth;
added_ufkt->f1_linewidth = tmp_ufkt.f1_linewidth;
added_ufkt->f2_linewidth = tmp_ufkt.f2_linewidth;
added_ufkt->integral_linewidth = tmp_ufkt.integral_linewidth;
added_ufkt->str_dmin = tmp_ufkt.str_dmin;
added_ufkt->str_dmax = tmp_ufkt.str_dmax;
added_ufkt->dmin = tmp_ufkt.dmin;
added_ufkt->dmax = tmp_ufkt.dmax;
added_ufkt->str_startx = tmp_ufkt.str_startx;
added_ufkt->str_starty = tmp_ufkt.str_starty;
added_ufkt->oldx = tmp_ufkt.oldx;
added_ufkt->starty = tmp_ufkt.starty;
added_ufkt->startx = tmp_ufkt.startx;
added_ufkt->integral_precision = tmp_ufkt.integral_precision;
added_ufkt->color = tmp_ufkt.color;
added_ufkt->f1_color = tmp_ufkt.f1_color;
added_ufkt->f2_color = tmp_ufkt.f2_color;
added_ufkt->integral_color = tmp_ufkt.integral_color;
added_ufkt->parameters = tmp_ufkt.parameters;
added_ufkt->use_slider = tmp_ufkt.use_slider;
added_ufkt->usecustomxmin = tmp_ufkt.usecustomxmin;
added_ufkt->usecustomxmax = tmp_ufkt.usecustomxmax;
m_updatedfunction = added_ufkt;
// call inherited method
KDialogBase::accept();
}
Ufkt * EditFunction::functionItem()
{
return m_updatedfunction;
}
void EditFunction::slotHelp()
{
kapp->invokeHelp( "", "kmplot" );
}
bool EditFunction::functionHas2Arguments()
{
int const openBracket = editfunctionpage->equation->text().find( "(" );
int const closeBracket = editfunctionpage->equation->text().find( ")" );
return editfunctionpage->equation->text().mid( openBracket+1, closeBracket-openBracket-1 ).find( "," ) != -1;
}
void EditFunction::cmdParameter_clicked()
{
editfunctionpage->useList->setChecked(true);
KParameterEditor *dlg = new KParameterEditor(m_parser,&m_parameter);
dlg->show();
}
void EditFunction::noParameter_toggled(bool status)
{
if (status)
{
editfunctionpage->cmdParameter->setEnabled(false);
editfunctionpage->listOfSliders->setEnabled(false);
}
}
void EditFunction::customMinRange_toggled(bool status)
{
if (status)
editfunctionpage->min->setEnabled(true);
else
editfunctionpage->min->setEnabled(false);
}
void EditFunction::customMaxRange_toggled(bool status)
{
if (status)
editfunctionpage->max->setEnabled(true);
else
editfunctionpage->max->setEnabled(false);
}
void EditFunction::fixFunctionArguments(TQString &f_str)
{
int const openBracket = f_str.find( "(" );
int const closeBracket = f_str.find( ")" );
char parameter_name;
if ( closeBracket-openBracket == 2) //the function atribute is only one character
{
char const function_name = f_str.at(openBracket+1).latin1();
parameter_name = 'a';
while ( parameter_name == function_name)
parameter_name++;
}
else
parameter_name = 'a';
f_str.insert(closeBracket,parameter_name);
f_str.insert(closeBracket,',');
}