moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kmplot / kmplot / xparser.cpp
blob39fa414e2d4615fcafb306e4fdf033de6f891573
1 /*
2 * KmPlot - a math. function plotter for the KDE-Desktop
4 * Copyright (C) 1998, 1999 Klaus-Dieter Möller
5 * 2000, 2002 kd.moeller@t-online.de
6 *
7 * This file is part of the KDE Project.
8 * KmPlot is part of the KDE-EDU Project.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 // KDE includes
27 #include <dcopclient.h>
28 #include <kapplication.h>
29 #include <kglobal.h>
30 #include <kinputdialog.h>
31 #include <klocale.h>
32 #include <kmessagebox.h>
34 // local includes
35 #include "xparser.h"
37 XParser::XParser(bool &mo) : DCOPObject("Parser"), Parser(), m_modified(mo)
39 // setup slider support
40 setDecimalSymbol( KGlobal::locale()->decimalSymbol() );
43 XParser::~XParser()
47 bool XParser::getext( Ufkt *item, const QString fstr )
49 bool errflg = false;
50 int p1, p2, p3, pe;
51 QString tstr;
52 pe = fstr.length();
53 if ( fstr.find( 'N' ) != -1 )
54 item->f_mode = false;
55 else
57 if ( fstr.find( "A1" ) != -1 )
58 item->f1_mode = true;
59 if ( fstr.find( "A2" ) != -1 )
60 item->f2_mode = true;
62 switch ( fstr[0].latin1() )
64 case 'x':
65 case 'y':
66 case 'r':
67 item->f1_mode = item->f2_mode = false;
70 p1 = fstr.find( "D[" );
71 if ( p1 != -1 )
73 p1 += 2;
74 const QString str = fstr.mid( p1, pe - p1);
75 p2 = str.find(',');
76 p3 = str.find(']');
77 if ( p2 > 0 && p2 < p3 )
79 tstr = str.left( p2 );
80 item->dmin = eval( tstr );
81 if ( parserError(false) )
82 errflg = true;
83 tstr = str.mid( p2 + 1, p3 - p2 - 1 );
84 item->dmax = eval( tstr );
85 if ( parserError(false) )
86 errflg = true;
87 if ( item->dmin > item->dmax )
88 errflg = true;
90 else
91 errflg = true;
93 p1 = fstr.find( "P[" );
94 if ( p1 != -1 )
96 int i = 0;
97 p1 += 2;
98 QString str = fstr.mid( p1, 1000);
99 p3 = str.find( ']' );
102 p2 = str.find( ',' );
103 if ( p2 == -1 || p2 > p3 )
104 p2 = p3;
105 tstr = str.left( p2++ );
106 str = str.mid( p2, 1000 );
107 item->parameters.append( ParameterValueItem(tstr, eval( tstr )) );
108 if ( parserError(false) )
110 errflg = true;
111 break;
113 p3 -= p2;
115 while ( p3 > 0 && i < 10 );
118 if ( errflg )
120 KMessageBox::error( 0, i18n( "Error in extension." ) );
121 return false;
123 else
124 return true;
127 double XParser::a1fkt( Ufkt *u_item, double x, double h )
129 return ( fkt(u_item, x + h ) - fkt( u_item, x ) ) / h;
132 double XParser::a2fkt( Ufkt *u_item, double x, double h )
134 return ( fkt( u_item, x + h + h ) - 2 * fkt( u_item, x + h ) + fkt( u_item, x ) ) / h / h;
137 void XParser::findFunctionName(QString &function_name, int const id, int const type)
139 char last_character;
140 int pos;
141 if ( function_name.length()==2/*type == XParser::Polar*/ || type == XParser::ParametricX || type == XParser::ParametricY)
142 pos=1;
143 else
144 pos=0;
145 for ( ; ; ++pos)
147 last_character = 'f';
148 for (bool ok=true; last_character<'x'; ++last_character)
150 if ( pos==0 && last_character == 'r') continue;
151 function_name.at(pos)=last_character;
152 for( QValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
154 if (it == ufkt.begin() && it->fname.isEmpty() ) continue;
155 if ( it->fstr.startsWith(function_name+'(') && (int)it->id!=id) //check if the name is free
156 ok = false;
158 if ( ok) //a free name was found
160 //kdDebug() << "function_name:" << function_name << endl;
161 return;
163 ok = true;
165 function_name.at(pos)='f';
166 function_name.append('f');
168 function_name = "e"; //this should never happen
171 void XParser::fixFunctionName( QString &str, int const type, int const id)
173 int p1=str.find('(');
174 int p2=str.find(')');
175 if( p1>=0 && str.at(p2+1)=='=')
177 if ( type == XParser::Polar && str.at(0)!='r' )
179 if (str.at(0)=='(')
181 str.prepend('f');
182 p1++;
183 p2++;
185 str.prepend('r');
186 p1++;
187 p2++;
189 QString const fname = str.left(p1);
190 for ( QValueVector<Ufkt>::iterator it = ufkt.begin(); it!=ufkt.end(); ++it )
192 if (it->fname == fname)
194 str = str.mid(p1,str.length()-1);
195 QString function_name;
196 if ( type == XParser::Polar )
197 function_name = "rf";
198 else if ( type == XParser::ParametricX )
199 function_name = "x";
200 else if ( type == XParser::ParametricY )
201 function_name = "y";
202 else
203 function_name = "f";
204 findFunctionName(function_name, id, type);
205 str.prepend( function_name );
206 return;
210 else if ( p1==-1 || !str.at(p1+1).isLetter() || p2==-1 || str.at(p2+1 )!= '=')
212 QString function_name;
213 if ( type == XParser::Polar )
214 function_name = "rf";
215 else if ( type == XParser::ParametricX )
216 function_name = "xf";
217 else if ( type == XParser::ParametricY )
218 function_name = "yf";
219 else
220 function_name = "f";
221 str.prepend("(x)=");
222 findFunctionName(function_name, id, type);
223 str.prepend( function_name );
227 double XParser::euler_method(const double x, const QValueVector<Ufkt>::iterator it)
229 double const y = it->oldy + ((x-it->oldx) * it->oldyprim);
230 it->oldy = y;
231 it->oldx = x;
232 it->oldyprim = fkt( it, x ); //yprim;
233 return y;
236 QRgb XParser::defaultColor(int function)
238 switch ( function )
240 case 1:
241 return Settings::color0().rgb();
242 break;
243 case 2:
244 return Settings::color1().rgb();
245 break;
246 case 3:
247 return Settings::color2().rgb();
248 break;
249 case 4:
250 return Settings::color3().rgb();
251 break;
252 case 5:
253 return Settings::color4().rgb();
254 break;
255 case 6:
256 return Settings::color5().rgb();
257 break;
258 case 7:
259 return Settings::color6().rgb();
260 break;
261 case 8:
262 return Settings::color7().rgb();
263 break;
264 case 9:
265 return Settings::color8().rgb();
266 break;
267 case 10:
268 return Settings::color9().rgb();
269 break;
270 default:
271 return Settings::color0().rgb();
272 break;
276 void XParser::prepareAddingFunction(Ufkt *temp)
278 temp->color = temp->f1_color = temp->f2_color = temp->integral_color = defaultColor(getNextIndex() );
279 temp->linewidth = temp->f1_linewidth = temp->f2_linewidth = temp->integral_linewidth = linewidth0;
280 temp->f_mode = true;
281 temp->f1_mode = false;
282 temp->f2_mode = false;
283 temp->integral_mode = false;
284 temp->integral_precision = Settings::stepWidth();
285 temp->usecustomxmin = false;
286 temp->usecustomxmax = false;
287 temp->use_slider = -1;
288 //TODO temp->slider_min = 0; temp->slider_max = 50;
291 int XParser::getNextIndex()
293 //return ufkt.count();
294 return getNewId();
297 QStringList XParser::listFunctionNames()
299 QStringList list;
300 for( QValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
302 list.append(it->fname);
304 return list;
307 bool XParser::functionFVisible(uint id)
309 int const ix = ixValue(id);
310 if (ix==-1)
311 return false;
312 return ufkt[ix].f_mode;
314 bool XParser::functionF1Visible(uint id)
316 int const ix = ixValue(id);
317 if (ix==-1)
318 return false;
319 return ufkt[ix].f1_mode;
321 bool XParser::functionF2Visible(uint id)
323 int const ix = ixValue(id);
324 if (ix==-1)
325 return false;
326 return ufkt[ix].f2_mode;
328 bool XParser::functionIntVisible(uint id)
330 int const ix = ixValue(id);
331 if (ix==-1)
332 return false;
333 return ufkt[ix].integral_mode;
336 bool XParser::setFunctionFVisible(bool visible, uint id)
338 int const ix = ixValue(id);
339 if (ix==-1)
340 return false;
341 ufkt[ix].f_mode = visible;
342 m_modified = true;
343 return true;
345 bool XParser::setFunctionF1Visible(bool visible, uint id)
347 int const ix = ixValue(id);
348 if (ix==-1)
349 return false;
350 ufkt[ix].f1_mode = visible;
351 m_modified = true;
352 return true;
354 bool XParser::setFunctionF2Visible(bool visible, uint id)
356 int const ix = ixValue(id);
357 if (ix==-1)
358 return false;
359 ufkt[ix].f2_mode = visible;
360 m_modified = true;
361 return true;
363 bool XParser::setFunctionIntVisible(bool visible, uint id)
365 int const ix = ixValue(id);
366 if (ix==-1)
367 return false;
368 ufkt[ix].integral_mode = visible;
369 m_modified = true;
370 return true;
373 QString XParser::functionStr(uint id)
375 int const ix = ixValue(id);
376 if (ix==-1)
377 return "";
378 return ufkt[ix].fstr;
381 QColor XParser::functionFColor(uint id)
383 int const ix = ixValue(id);
384 if (ix==-1)
385 return QColor();
386 return QColor(ufkt[ix].color);
388 QColor XParser::functionF1Color(uint id)
390 int const ix = ixValue(id);
391 if (ix==-1)
392 return QColor();
393 return QColor(ufkt[ix].f1_color);
395 QColor XParser::functionF2Color(uint id)
397 int const ix = ixValue(id);
398 if (ix==-1)
399 return QColor();
400 return QColor(ufkt[ix].f2_color);
402 QColor XParser::functionIntColor(uint id)
404 int const ix = ixValue(id);
405 if (ix==-1)
406 return QColor();
407 return QColor(ufkt[ix].integral_color);
409 bool XParser::setFunctionFColor(const QColor &color, uint id)
411 int const ix = ixValue(id);
412 if (ix==-1)
413 return false;
414 ufkt[ix].color = color.rgb();
415 m_modified = true;
416 return true;
418 bool XParser::setFunctionF1Color(const QColor &color, uint id)
420 int const ix = ixValue(id);
421 if (ix==-1)
422 return false;
423 ufkt[ix].color = color.rgb();
424 m_modified = true;
425 return true;
427 bool XParser::setFunctionF2Color(const QColor &color, uint id)
429 int const ix = ixValue(id);
430 if (ix==-1)
431 return false;
432 ufkt[ix].color = color.rgb();
433 m_modified = true;
434 return true;
436 bool XParser::setFunctionIntColor(const QColor &color, uint id)
438 int const ix = ixValue(id);
439 if (ix==-1)
440 return false;
441 ufkt[ix].color = color.rgb();
442 m_modified = true;
443 return true;
446 int XParser::functionFLineWidth(uint id)
448 int const ix = ixValue(id);
449 if (ix==-1)
450 return 0;
451 return ufkt[ix].linewidth;
453 int XParser::functionF1LineWidth(uint id)
455 int const ix = ixValue(id);
456 if (ix==-1)
457 return int();
458 return ufkt[ix].f1_linewidth;
460 int XParser::functionF2LineWidth(uint id)
462 int const ix = ixValue(id);
463 if (ix==-1)
464 return int();
465 return ufkt[ix].f2_linewidth;
467 int XParser::functionIntLineWidth(uint id)
469 int const ix = ixValue(id);
470 if (ix==-1)
471 return int();
472 return ufkt[ix].integral_linewidth;
474 bool XParser::setFunctionFLineWidth(int linewidth, uint id)
476 int const ix = ixValue(id);
477 if (ix==-1)
478 return false;
479 ufkt[ix].linewidth = linewidth;
480 m_modified = true;
481 return true;
483 bool XParser::setFunctionF1LineWidth(int linewidth, uint id)
485 int const ix = ixValue(id);
486 if (ix==-1)
487 return false;
488 ufkt[ix].f1_linewidth = linewidth;
489 m_modified = true;
490 return true;
492 bool XParser::setFunctionF2LineWidth(int linewidth, uint id)
494 int const ix = ixValue(id);
495 if (ix==-1)
496 return false;
497 ufkt[ix].f2_linewidth = linewidth;
498 m_modified = true;
499 return true;
501 bool XParser::setFunctionIntLineWidth(int linewidth, uint id)
503 int const ix = ixValue(id);
504 if (ix==-1)
505 return false;
506 ufkt[ix].integral_linewidth = linewidth;
507 m_modified = true;
508 return true;
511 QString XParser::functionMinValue(uint id)
513 int const ix = ixValue(id);
514 if (ix==-1)
515 return int();
516 return ufkt[ix].str_dmin;
519 bool XParser::setFunctionMinValue(const QString &min, uint id)
521 int const ix = ixValue(id);
522 if (ix==-1)
523 return false;
524 ufkt[ix].str_dmin = min;
525 m_modified = true;
526 return true;
529 QString XParser::functionMaxValue(uint id)
531 int const ix = ixValue(id);
532 if (ix==-1)
533 return int();
534 return ufkt[ix].str_dmax;
537 bool XParser::setFunctionMaxValue(const QString &max, uint id)
539 int const ix = ixValue(id);
540 if (ix==-1)
541 return false;
542 ufkt[ix].str_dmax = max;
543 m_modified = true;
544 return true;
547 QString XParser::functionStartXValue(uint id)
549 int const ix = ixValue(id);
550 if (ix==-1)
551 return int();
552 return ufkt[ix].str_startx;
555 bool XParser::setFunctionStartXValue(const QString &x, uint id)
557 int const ix = ixValue(id);
558 if (ix==-1)
559 return false;
560 ufkt[ix].str_startx = x;
561 m_modified = true;
562 return true;
565 QString XParser::functionStartYValue(uint id)
567 int const ix = ixValue(id);
568 if (ix==-1)
569 return int();
570 return ufkt[ix].str_starty;
573 bool XParser::setFunctionStartYValue(const QString &y, uint id)
575 int const ix = ixValue(id);
576 if (ix==-1)
577 return false;
578 ufkt[ix].str_starty = y;
579 m_modified = true;
580 return true;
583 QStringList XParser::functionParameterList(uint id)
585 int const ix = ixValue(id);
586 if (ix==-1)
587 return QStringList();
588 Ufkt *item = &ufkt[ix];
589 QStringList str_parameter;
590 for ( QValueList<ParameterValueItem>::iterator it = item->parameters.begin(); it != item->parameters.end(); ++it)
591 str_parameter.append( (*it).expression);
592 return str_parameter;
594 bool XParser::functionAddParameter(const QString &new_parameter, uint id)
596 int const ix = ixValue(id);
597 if (ix==-1)
598 return false;
599 Ufkt *tmp_ufkt = &ufkt[ix];
600 for ( QValueList<ParameterValueItem>::iterator it = tmp_ufkt->parameters.begin(); it != tmp_ufkt->parameters.end(); ++it)
601 if ( (*it).expression == new_parameter) //check if the parameter already exists
602 return false;
604 double const result = eval(new_parameter);
605 if ( parserError(false) != 0)
606 return false;
607 tmp_ufkt->parameters.append( ParameterValueItem(new_parameter,result) );
608 m_modified = true;
609 return true;
611 bool XParser::functionRemoveParameter(const QString &remove_parameter, uint id)
613 int const ix = ixValue(id);
614 if (ix==-1)
615 return false;
616 Ufkt *tmp_ufkt = &ufkt[ix];
618 bool found = false;
619 QValueList<ParameterValueItem>::iterator it;
620 for ( it = tmp_ufkt->parameters.begin(); it != tmp_ufkt->parameters.end(); ++it)
621 if ( (*it).expression == remove_parameter) //check if the parameter already exists
623 found = true;
624 break;
626 if (!found)
627 return false;
628 tmp_ufkt->parameters.remove(it);
629 m_modified = true;
630 return true;
632 int XParser::addFunction(const QString &f_str)
634 QString added_function(f_str);
635 int const pos = added_function.find(';');
636 if (pos!=-1)
637 added_function = added_function.left(pos);
639 fixFunctionName(added_function);
640 if ( added_function.at(0)== 'x' || added_function.at(0)== 'y') //TODO: Make it possible to define parametric functions
641 return -1;
642 if ( added_function.contains('y') != 0)
643 return -1;
644 int const id = addfkt( added_function );
645 if (id==-1)
646 return -1;
647 Ufkt *tmp_ufkt = &ufkt.last();
648 prepareAddingFunction(tmp_ufkt);
649 if ( pos!=-1 && !getext( tmp_ufkt, f_str ) )
651 Parser::delfkt( tmp_ufkt );
652 return -1;
654 m_modified = true;
655 return id;
658 bool XParser::addFunction(const QString &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 QString &str_dmin, const QString &str_dmax, const QString &str_startx, const QString &str_starty, double integral_precision, QRgb color, QRgb f1_color, QRgb f2_color, QRgb integral_color, QStringList str_parameter, int use_slider)
660 QString fstr(fstr_const);
661 switch ( fstr.at(0).latin1() )
663 case 'r':
665 fixFunctionName(fstr, XParser::Polar);
666 break;
668 case 'x':
669 fixFunctionName(fstr, XParser::ParametricX);
670 break;
671 case 'y':
672 fixFunctionName(fstr, XParser::ParametricY);
673 break;
674 default:
675 fixFunctionName(fstr, XParser::Function);
676 break;
678 int const id = addfkt( fstr );
679 if ( id==-1 )
680 return false;
681 Ufkt *added_function = &ufkt.last();
682 added_function->f_mode = f_mode;
683 added_function->f1_mode = f1_mode;
684 added_function->f2_mode = f2_mode;
685 added_function->integral_mode = integral_mode;
686 added_function->integral_use_precision = integral_use_precision;
687 added_function->linewidth = linewidth;
688 added_function->f1_linewidth = f1_linewidth;
689 added_function->f2_linewidth = f2_linewidth;
690 added_function->integral_linewidth = integral_linewidth;
692 if ( str_dmin.isEmpty() )
693 added_function->usecustomxmin = false;
694 else //custom minimum range
696 added_function->usecustomxmin = true;
697 added_function->str_dmin = str_dmin;
698 added_function->dmin = eval(str_dmin);
700 if ( str_dmax.isEmpty() )
701 added_function->usecustomxmax = false;
702 else //custom maximum range
704 added_function->usecustomxmax = true;
705 added_function->str_dmax = str_dmax;
706 added_function->dmax = eval(str_dmax);
708 added_function->str_startx = str_startx;
709 added_function->str_starty = str_starty;
710 if ( !str_starty.isEmpty() )
711 added_function->starty = eval(str_starty);
712 if ( !str_startx.isEmpty() )
713 added_function->startx = eval(str_startx);
714 added_function->oldx = 0;
715 added_function->integral_precision = integral_precision;
716 added_function->color = color;
717 added_function->f1_color = f1_color;
718 added_function->f2_color = f2_color;
719 added_function->integral_color = integral_color;
720 added_function->use_slider = use_slider;
721 for( QStringList::Iterator it = str_parameter.begin(); it != str_parameter.end(); ++it )
723 double result = eval(*it);
724 if ( parserError(false) != 0)
725 continue;
726 added_function->parameters.append( ParameterValueItem(*it, result ) );
728 m_modified = true;
729 return true;
732 bool XParser::setFunctionExpression(const QString &f_str, uint id)
734 int const ix = ixValue(id);
735 if (ix==-1)
736 return false;
737 Ufkt *tmp_ufkt = &ufkt[ix];
738 QString const old_fstr = tmp_ufkt->fstr;
739 QString const fstr_begin = tmp_ufkt->fstr.left(tmp_ufkt->fstr.find('=')+1);
740 tmp_ufkt->fstr = fstr_begin+f_str;
741 reparse(tmp_ufkt);
742 if ( parserError(false) != 0)
744 tmp_ufkt->fstr = old_fstr;
745 reparse(tmp_ufkt);
746 return false;
748 return true;
751 bool XParser::sendFunction(int id, const QString &dcopclient_target)
753 QCStringList cstr_list = kapp->dcopClient()->registeredApplications();
754 QStringList str_list;
755 for ( QCStringList::iterator it = cstr_list.begin(); it!=cstr_list.end();++it )
756 if ( QString(*it).startsWith("kmplot") && *it!=kapp->dcopClient()->appId() )
757 str_list.append(*it);
758 if ( str_list.isEmpty() )
760 KMessageBox::error(0, i18n("There are no other Kmplot instances running"));
761 return false;
764 Ufkt *item = &ufkt[ixValue(id)];
765 kdDebug() << "Transferring " << item->fname.latin1() << endl;
766 QString str_result;
767 if ( dcopclient_target.isEmpty() && item->fname.at(0) == 'y' )
768 return false;
769 else if ( dcopclient_target.isEmpty() )
771 bool ok;
772 str_result = KInputDialog::getItem(i18n("kmplot"), i18n("Choose which KmPlot instance\nyou want to copy the function to:"), str_list, 0, false, &ok);
773 if (!ok)
774 return false;
776 else
777 str_result = dcopclient_target;
779 QByteArray parameters;
780 QDataStream arg( parameters, IO_WriteOnly);
782 QString str_dmin;
783 if (!item->usecustomxmin)
784 str_dmin = item->str_dmin;
785 QString str_dmax;
786 if (!item->usecustomxmax)
787 str_dmax = item->str_dmax;
789 QStringList str_parameters;
790 for ( QValueList<ParameterValueItem>::Iterator it = item->parameters.begin(); it != item->parameters.end(); ++it )
791 str_parameters.append( (*it).expression);
792 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;
793 QByteArray replay_data;
794 QCString replay_type;
795 bool ok = kapp->dcopClient()->call( str_result.utf8(), "Parser", "addFunction(QString,bool,bool,bool,bool,bool,int,int,int,int,QString,QString,QString,QString,double,QRgb,QRgb,QRgb,QRgb,QStringList,int)", parameters, replay_type, replay_data, false);
796 if (!ok)
798 KMessageBox::error(0, i18n("An error appeared during the transfer"));
799 return false;
802 QDataStream replay_arg(replay_data, IO_ReadOnly);
803 bool result;
804 replay_arg >> result;
805 if (!result)
807 KMessageBox::error(0, i18n("An error appeared during the transfer"));
808 return false;
811 kapp->dcopClient()->send(str_result.utf8(), "View","drawPlot()",QByteArray() ); //update the other window
813 if (item->fname.at(0) == 'x') // a parametric function
814 return sendFunction(id+1, str_result);
815 else
816 return true;