/* * 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. * */ // KDE includes #include #include #include #include #include #include // local includes #include "xparser.h" XParser::XParser(bool &mo) : DCOPObject("Parser"), Parser(), m_modified(mo) { // setup slider support setDecimalSymbol( TDEGlobal::locale()->decimalSymbol() ); } XParser::~XParser() { } bool XParser::getext( Ufkt *item, const TQString fstr ) { bool errflg = false; int p1, p2, p3, pe; TQString tstr; pe = fstr.length(); if ( fstr.find( 'N' ) != -1 ) item->f_mode = false; else { if ( fstr.find( "A1" ) != -1 ) item->f1_mode = true; if ( fstr.find( "A2" ) != -1 ) item->f2_mode = true; } switch ( fstr[0].latin1() ) { case 'x': case 'y': case 'r': item->f1_mode = item->f2_mode = false; } p1 = fstr.find( "D[" ); if ( p1 != -1 ) { p1 += 2; const TQString str = fstr.mid( p1, pe - p1); p2 = str.find(','); p3 = str.find(']'); if ( p2 > 0 && p2 < p3 ) { tstr = str.left( p2 ); item->dmin = eval( tstr ); if ( parserError(false) ) errflg = true; tstr = str.mid( p2 + 1, p3 - p2 - 1 ); item->dmax = eval( tstr ); if ( parserError(false) ) errflg = true; if ( item->dmin > item->dmax ) errflg = true; } else errflg = true; } p1 = fstr.find( "P[" ); if ( p1 != -1 ) { int i = 0; p1 += 2; TQString str = fstr.mid( p1, 1000); p3 = str.find( ']' ); do { p2 = str.find( ',' ); if ( p2 == -1 || p2 > p3 ) p2 = p3; tstr = str.left( p2++ ); str = str.mid( p2, 1000 ); item->parameters.append( ParameterValueItem(tstr, eval( tstr )) ); if ( parserError(false) ) { errflg = true; break; } p3 -= p2; } while ( p3 > 0 && i < 10 ); } if ( errflg ) { KMessageBox::error( 0, i18n( "Error in extension." ) ); return false; } else return true; } double XParser::a1fkt( Ufkt *u_item, double x, double h ) { return ( fkt(u_item, x + h ) - fkt( u_item, x ) ) / h; } double XParser::a2fkt( Ufkt *u_item, double x, double h ) { return ( fkt( u_item, x + h + h ) - 2 * fkt( u_item, x + h ) + fkt( u_item, x ) ) / h / h; } void XParser::findFunctionName(TQString &function_name, int const id, int const type) { char last_character; int pos; if ( function_name.length()==2/*type == XParser::Polar*/ || type == XParser::ParametricX || type == XParser::ParametricY) pos=1; else pos=0; for ( ; ; ++pos) { last_character = 'f'; for (bool ok=true; last_character<'x'; ++last_character) { if ( pos==0 && last_character == 'r') continue; function_name.at(pos)=last_character; for( TQValueVector::iterator it = ufkt.begin(); it != ufkt.end(); ++it) { if (it == ufkt.begin() && it->fname.isEmpty() ) continue; if ( it->fstr.startsWith(function_name+'(') && (int)it->id!=id) //check if the name is free ok = false; } if ( ok) //a free name was found { //kdDebug() << "function_name:" << function_name << endl; return; } ok = true; } function_name.at(pos)='f'; function_name.append('f'); } function_name = "e"; //this should never happen } void XParser::fixFunctionName( TQString &str, int const type, int const id) { if ( str.startsWith( "y=" ) ) //we find a free function name { str.remove( 0, 2 ); str.prepend("(x)="); TQString function_name; findFunctionName(function_name, id, type); str.prepend( function_name ); } int p1=str.find('('); int p2=str.find(')'); if( p1>=0 && str.at(p2+1)=='=') { if ( type == XParser::Polar && str.at(0)!='r' ) { if (str.at(0)=='(') { str.prepend('f'); p1++; p2++; } str.prepend('r'); p1++; p2++; } TQString const fname = str.left(p1); for ( TQValueVector::iterator it = ufkt.begin(); it!=ufkt.end(); ++it ) { if (it->fname == fname) { str = str.mid(p1,str.length()-1); TQString function_name; if ( type == XParser::Polar ) function_name = "rf"; else if ( type == XParser::ParametricX ) function_name = "x"; else if ( type == XParser::ParametricY ) function_name = "y"; else function_name = "f"; findFunctionName(function_name, id, type); str.prepend( function_name ); return; } } } else if ( p1==-1 || !str.at(p1+1).isLetter() || p2==-1 || str.at(p2+1 )!= '=') { TQString function_name; if ( type == XParser::Polar ) function_name = "rf"; else if ( type == XParser::ParametricX ) function_name = "xf"; else if ( type == XParser::ParametricY ) function_name = "yf"; else function_name = "f"; str.prepend("(x)="); findFunctionName(function_name, id, type); str.prepend( function_name ); } } double XParser::euler_method(const double x, const TQValueVector::iterator it) { double const y = it->oldy + ((x-it->oldx) * it->oldyprim); it->oldy = y; it->oldx = x; it->oldyprim = fkt( it, x ); //yprim; return y; } TQRgb XParser::defaultColor(int function) { switch ( function%10 ) { case 0: return Settings::color0().rgb(); break; case 1: return Settings::color1().rgb(); break; case 2: return Settings::color2().rgb(); break; case 3: return Settings::color3().rgb(); break; case 4: return Settings::color4().rgb(); break; case 5: return Settings::color5().rgb(); break; case 6: return Settings::color6().rgb(); break; case 7: return Settings::color7().rgb(); break; case 8: return Settings::color8().rgb(); break; case 9: return Settings::color9().rgb(); break; default: return Settings::color0().rgb(); break; } } void XParser::prepareAddingFunction(Ufkt *temp) { temp->color = temp->f1_color = temp->f2_color = temp->integral_color = defaultColor(getNextIndex() ); temp->linewidth = temp->f1_linewidth = temp->f2_linewidth = temp->integral_linewidth = linewidth0; temp->f_mode = true; temp->f1_mode = false; temp->f2_mode = false; temp->integral_mode = false; temp->integral_precision = Settings::stepWidth(); temp->usecustomxmin = false; temp->usecustomxmax = false; temp->use_slider = -1; //TODO temp->slider_min = 0; temp->slider_max = 50; } int XParser::getNextIndex() { //return ufkt.count(); return getNewId(); } TQStringList XParser::listFunctionNames() { TQStringList list; for( TQValueVector::iterator it = ufkt.begin(); it != ufkt.end(); ++it) { list.append(it->fname); } return list; } bool XParser::functionFVisible(uint id) { int const ix = ixValue(id); if (ix==-1) return false; return ufkt[ix].f_mode; } bool XParser::functionF1Visible(uint id) { int const ix = ixValue(id); if (ix==-1) return false; return ufkt[ix].f1_mode; } bool XParser::functionF2Visible(uint id) { int const ix = ixValue(id); if (ix==-1) return false; return ufkt[ix].f2_mode; } bool XParser::functionIntVisible(uint id) { int const ix = ixValue(id); if (ix==-1) return false; return ufkt[ix].integral_mode; } bool XParser::setFunctionFVisible(bool visible, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].f_mode = visible; m_modified = true; return true; } bool XParser::setFunctionF1Visible(bool visible, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].f1_mode = visible; m_modified = true; return true; } bool XParser::setFunctionF2Visible(bool visible, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].f2_mode = visible; m_modified = true; return true; } bool XParser::setFunctionIntVisible(bool visible, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].integral_mode = visible; m_modified = true; return true; } TQString XParser::functionStr(uint id) { int const ix = ixValue(id); if (ix==-1) return ""; return ufkt[ix].fstr; } TQColor XParser::functionFColor(uint id) { int const ix = ixValue(id); if (ix==-1) return TQColor(); return TQColor(ufkt[ix].color); } TQColor XParser::functionF1Color(uint id) { int const ix = ixValue(id); if (ix==-1) return TQColor(); return TQColor(ufkt[ix].f1_color); } TQColor XParser::functionF2Color(uint id) { int const ix = ixValue(id); if (ix==-1) return TQColor(); return TQColor(ufkt[ix].f2_color); } TQColor XParser::functionIntColor(uint id) { int const ix = ixValue(id); if (ix==-1) return TQColor(); return TQColor(ufkt[ix].integral_color); } bool XParser::setFunctionFColor(const TQColor &color, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].color = color.rgb(); m_modified = true; return true; } bool XParser::setFunctionF1Color(const TQColor &color, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].color = color.rgb(); m_modified = true; return true; } bool XParser::setFunctionF2Color(const TQColor &color, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].color = color.rgb(); m_modified = true; return true; } bool XParser::setFunctionIntColor(const TQColor &color, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].color = color.rgb(); m_modified = true; return true; } int XParser::functionFLineWidth(uint id) { int const ix = ixValue(id); if (ix==-1) return 0; return ufkt[ix].linewidth; } int XParser::functionF1LineWidth(uint id) { int const ix = ixValue(id); if (ix==-1) return int(); return ufkt[ix].f1_linewidth; } int XParser::functionF2LineWidth(uint id) { int const ix = ixValue(id); if (ix==-1) return int(); return ufkt[ix].f2_linewidth; } int XParser::functionIntLineWidth(uint id) { int const ix = ixValue(id); if (ix==-1) return int(); return ufkt[ix].integral_linewidth; } bool XParser::setFunctionFLineWidth(int linewidth, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].linewidth = linewidth; m_modified = true; return true; } bool XParser::setFunctionF1LineWidth(int linewidth, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].f1_linewidth = linewidth; m_modified = true; return true; } bool XParser::setFunctionF2LineWidth(int linewidth, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].f2_linewidth = linewidth; m_modified = true; return true; } bool XParser::setFunctionIntLineWidth(int linewidth, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].integral_linewidth = linewidth; m_modified = true; return true; } TQString XParser::functionMinValue(uint id) { int const ix = ixValue(id); if (ix==-1) return int(); return ufkt[ix].str_dmin; } bool XParser::setFunctionMinValue(const TQString &min, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].str_dmin = min; m_modified = true; return true; } TQString XParser::functionMaxValue(uint id) { int const ix = ixValue(id); if (ix==-1) return int(); return ufkt[ix].str_dmax; } bool XParser::setFunctionMaxValue(const TQString &max, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].str_dmax = max; m_modified = true; return true; } TQString XParser::functionStartXValue(uint id) { int const ix = ixValue(id); if (ix==-1) return int(); return ufkt[ix].str_startx; } bool XParser::setFunctionStartXValue(const TQString &x, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].str_startx = x; m_modified = true; return true; } TQString XParser::functionStartYValue(uint id) { int const ix = ixValue(id); if (ix==-1) return int(); return ufkt[ix].str_starty; } bool XParser::setFunctionStartYValue(const TQString &y, uint id) { int const ix = ixValue(id); if (ix==-1) return false; ufkt[ix].str_starty = y; m_modified = true; return true; } TQStringList XParser::functionParameterList(uint id) { int const ix = ixValue(id); if (ix==-1) return TQStringList(); Ufkt *item = &ufkt[ix]; TQStringList str_parameter; for ( TQValueList::iterator it = item->parameters.begin(); it != item->parameters.end(); ++it) str_parameter.append( (*it).expression); return str_parameter; } bool XParser::functionAddParameter(const TQString &new_parameter, uint id) { int const ix = ixValue(id); if (ix==-1) return false; Ufkt *tmp_ufkt = &ufkt[ix]; for ( TQValueList::iterator it = tmp_ufkt->parameters.begin(); it != tmp_ufkt->parameters.end(); ++it) if ( (*it).expression == new_parameter) //check if the parameter already exists return false; double const result = eval(new_parameter); if ( parserError(false) != 0) return false; tmp_ufkt->parameters.append( ParameterValueItem(new_parameter,result) ); m_modified = true; return true; } bool XParser::functionRemoveParameter(const TQString &remove_parameter, uint id) { int const ix = ixValue(id); if (ix==-1) return false; Ufkt *tmp_ufkt = &ufkt[ix]; bool found = false; TQValueList::iterator it; for ( it = tmp_ufkt->parameters.begin(); it != tmp_ufkt->parameters.end(); ++it) if ( (*it).expression == remove_parameter) //check if the parameter already exists { found = true; break; } if (!found) return false; tmp_ufkt->parameters.remove(it); m_modified = true; return true; } int XParser::addFunction(const TQString &f_str) { TQString added_function(f_str); int const pos = added_function.find(';'); if (pos!=-1) added_function = added_function.left(pos); fixFunctionName(added_function); if ( added_function.at(0)== 'x' || added_function.at(0)== 'y') //TODO: Make it possible to define parametric functions return -1; if ( added_function.contains('y') != 0) return -1; int const id = addfkt( added_function ); if (id==-1) return -1; Ufkt *tmp_ufkt = &ufkt.last(); prepareAddingFunction(tmp_ufkt); if ( pos!=-1 && !getext( tmp_ufkt, f_str ) ) { Parser::delfkt( tmp_ufkt ); return -1; } m_modified = true; return id; } bool XParser::addFunction(const TQString &fstr_const, bool f_mode, bool f1_mode, bool f2_mode, bool integral_mode, bool integral_use_precision, int linewidth, int f1_linewidth, int f2_linewidth, int integral_linewidth, const TQString &str_dmin, const TQString &str_dmax, const TQString &str_startx, const TQString &str_starty, double integral_precision, TQRgb color, TQRgb f1_color, TQRgb f2_color, TQRgb integral_color, TQStringList str_parameter, int use_slider) { TQString fstr(fstr_const); switch ( fstr.at(0).latin1() ) { case 'r': { fixFunctionName(fstr, XParser::Polar); break; } case 'x': fixFunctionName(fstr, XParser::ParametricX); break; case 'y': fixFunctionName(fstr, XParser::ParametricY); break; default: fixFunctionName(fstr, XParser::Function); break; } int const id = addfkt( fstr ); if ( id==-1 ) return false; Ufkt *added_function = &ufkt.last(); added_function->f_mode = f_mode; added_function->f1_mode = f1_mode; added_function->f2_mode = f2_mode; added_function->integral_mode = integral_mode; added_function->integral_use_precision = integral_use_precision; added_function->linewidth = linewidth; added_function->f1_linewidth = f1_linewidth; added_function->f2_linewidth = f2_linewidth; added_function->integral_linewidth = integral_linewidth; if ( str_dmin.isEmpty() ) added_function->usecustomxmin = false; else //custom minimum range { added_function->usecustomxmin = true; added_function->str_dmin = str_dmin; added_function->dmin = eval(str_dmin); } if ( str_dmax.isEmpty() ) added_function->usecustomxmax = false; else //custom maximum range { added_function->usecustomxmax = true; added_function->str_dmax = str_dmax; added_function->dmax = eval(str_dmax); } added_function->str_startx = str_startx; added_function->str_starty = str_starty; if ( !str_starty.isEmpty() ) added_function->starty = eval(str_starty); if ( !str_startx.isEmpty() ) added_function->startx = eval(str_startx); added_function->oldx = 0; added_function->integral_precision = integral_precision; added_function->color = color; added_function->f1_color = f1_color; added_function->f2_color = f2_color; added_function->integral_color = integral_color; added_function->use_slider = use_slider; for( TQStringList::Iterator it = str_parameter.begin(); it != str_parameter.end(); ++it ) { double result = eval(*it); if ( parserError(false) != 0) continue; added_function->parameters.append( ParameterValueItem(*it, result ) ); } m_modified = true; return true; } bool XParser::setFunctionExpression(const TQString &f_str, uint id) { int const ix = ixValue(id); if (ix==-1) return false; Ufkt *tmp_ufkt = &ufkt[ix]; TQString const old_fstr = tmp_ufkt->fstr; TQString const fstr_begin = tmp_ufkt->fstr.left(tmp_ufkt->fstr.find('=')+1); tmp_ufkt->fstr = fstr_begin+f_str; reparse(tmp_ufkt); if ( parserError(false) != 0) { tmp_ufkt->fstr = old_fstr; reparse(tmp_ufkt); return false; } return true; } bool XParser::sendFunction(int id, const TQString &dcopclient_target) { QCStringList cstr_list = kapp->dcopClient()->registeredApplications(); TQStringList str_list; for ( QCStringList::iterator it = cstr_list.begin(); it!=cstr_list.end();++it ) if ( TQString(*it).startsWith("kmplot") && *it!=kapp->dcopClient()->appId() ) str_list.append(*it); if ( str_list.isEmpty() ) { KMessageBox::error(0, i18n("There are no other Kmplot instances running")); return false; } Ufkt *item = &ufkt[ixValue(id)]; kdDebug() << "Transferring " << item->fname.latin1() << endl; TQString str_result; if ( dcopclient_target.isEmpty() && item->fname.at(0) == 'y' ) return false; else if ( dcopclient_target.isEmpty() ) { bool ok; str_result = KInputDialog::getItem(i18n("kmplot"), i18n("Choose which KmPlot instance\nyou want to copy the function to:"), str_list, 0, false, &ok); if (!ok) return false; } else str_result = dcopclient_target; TQByteArray parameters; TQDataStream arg( parameters, IO_WriteOnly); TQString str_dmin; if (!item->usecustomxmin) str_dmin = item->str_dmin; TQString str_dmax; if (!item->usecustomxmax) str_dmax = item->str_dmax; TQStringList str_parameters; for ( TQValueList::Iterator it = item->parameters.begin(); it != item->parameters.end(); ++it ) str_parameters.append( (*it).expression); arg << item->fstr << item->f_mode << item->f1_mode << item->f2_mode << item->integral_mode << item->integral_use_precision << item->linewidth << item->f1_linewidth << item->f2_linewidth << item->integral_linewidth << str_dmin << str_dmax << item->str_startx << item->str_starty << item->integral_precision << item->color << item->f1_color << item->f2_color << item->integral_color << str_parameters << item->use_slider; TQByteArray replay_data; TQCString replay_type; bool ok = kapp->dcopClient()->call( str_result.utf8(), "Parser", "addFunction(TQString,bool,bool,bool,bool,bool,int,int,int,int,TQString,TQString,TQString,TQString,double,TQRgb,TQRgb,TQRgb,TQRgb,TQStringList,int)", parameters, replay_type, replay_data, false); if (!ok) { KMessageBox::error(0, i18n("An error appeared during the transfer")); return false; } TQDataStream replay_arg(replay_data, IO_ReadOnly); bool result; replay_arg >> result; if (!result) { KMessageBox::error(0, i18n("An error appeared during the transfer")); return false; } kapp->dcopClient()->send(str_result.utf8(), "View","drawPlot()",TQByteArray() ); //update the other window if (item->fname.at(0) == 'x') // a parametric function return sendFunction(id+1, str_result); else return true; }