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
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.
27 #include <dcopclient.h>
28 #include <kapplication.h>
30 #include <kinputdialog.h>
32 #include <kmessagebox.h>
37 XParser::XParser(bool &mo
) : DCOPObject("Parser"), Parser(), m_modified(mo
)
39 // setup slider support
40 setDecimalSymbol( KGlobal::locale()->decimalSymbol() );
47 bool XParser::getext( Ufkt
*item
, const QString fstr
)
53 if ( fstr
.find( 'N' ) != -1 )
57 if ( fstr
.find( "A1" ) != -1 )
59 if ( fstr
.find( "A2" ) != -1 )
62 switch ( fstr
[0].latin1() )
67 item
->f1_mode
= item
->f2_mode
= false;
70 p1
= fstr
.find( "D[" );
74 const QString str
= fstr
.mid( p1
, pe
- p1
);
77 if ( p2
> 0 && p2
< p3
)
79 tstr
= str
.left( p2
);
80 item
->dmin
= eval( tstr
);
81 if ( parserError(false) )
83 tstr
= str
.mid( p2
+ 1, p3
- p2
- 1 );
84 item
->dmax
= eval( tstr
);
85 if ( parserError(false) )
87 if ( item
->dmin
> item
->dmax
)
93 p1
= fstr
.find( "P[" );
98 QString str
= fstr
.mid( p1
, 1000);
102 p2
= str
.find( ',' );
103 if ( p2
== -1 || 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) )
115 while ( p3
> 0 && i
< 10 );
120 KMessageBox::error( 0, i18n( "Error in extension." ) );
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
)
141 if ( function_name
.length()==2/*type == XParser::Polar*/ || type
== XParser::ParametricX
|| type
== XParser::ParametricY
)
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
158 if ( ok
) //a free name was found
160 //kdDebug() << "function_name:" << function_name << endl;
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' )
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
)
200 else if ( type
== XParser::ParametricY
)
204 findFunctionName(function_name
, id
, type
);
205 str
.prepend( function_name
);
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";
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
);
232 it
->oldyprim
= fkt( it
, x
); //yprim;
236 QRgb
XParser::defaultColor(int function
)
241 return Settings::color0().rgb();
244 return Settings::color1().rgb();
247 return Settings::color2().rgb();
250 return Settings::color3().rgb();
253 return Settings::color4().rgb();
256 return Settings::color5().rgb();
259 return Settings::color6().rgb();
262 return Settings::color7().rgb();
265 return Settings::color8().rgb();
268 return Settings::color9().rgb();
271 return Settings::color0().rgb();
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
;
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();
297 QStringList
XParser::listFunctionNames()
300 for( QValueVector
<Ufkt
>::iterator it
= ufkt
.begin(); it
!= ufkt
.end(); ++it
)
302 list
.append(it
->fname
);
307 bool XParser::functionFVisible(uint id
)
309 int const ix
= ixValue(id
);
312 return ufkt
[ix
].f_mode
;
314 bool XParser::functionF1Visible(uint id
)
316 int const ix
= ixValue(id
);
319 return ufkt
[ix
].f1_mode
;
321 bool XParser::functionF2Visible(uint id
)
323 int const ix
= ixValue(id
);
326 return ufkt
[ix
].f2_mode
;
328 bool XParser::functionIntVisible(uint id
)
330 int const ix
= ixValue(id
);
333 return ufkt
[ix
].integral_mode
;
336 bool XParser::setFunctionFVisible(bool visible
, uint id
)
338 int const ix
= ixValue(id
);
341 ufkt
[ix
].f_mode
= visible
;
345 bool XParser::setFunctionF1Visible(bool visible
, uint id
)
347 int const ix
= ixValue(id
);
350 ufkt
[ix
].f1_mode
= visible
;
354 bool XParser::setFunctionF2Visible(bool visible
, uint id
)
356 int const ix
= ixValue(id
);
359 ufkt
[ix
].f2_mode
= visible
;
363 bool XParser::setFunctionIntVisible(bool visible
, uint id
)
365 int const ix
= ixValue(id
);
368 ufkt
[ix
].integral_mode
= visible
;
373 QString
XParser::functionStr(uint id
)
375 int const ix
= ixValue(id
);
378 return ufkt
[ix
].fstr
;
381 QColor
XParser::functionFColor(uint id
)
383 int const ix
= ixValue(id
);
386 return QColor(ufkt
[ix
].color
);
388 QColor
XParser::functionF1Color(uint id
)
390 int const ix
= ixValue(id
);
393 return QColor(ufkt
[ix
].f1_color
);
395 QColor
XParser::functionF2Color(uint id
)
397 int const ix
= ixValue(id
);
400 return QColor(ufkt
[ix
].f2_color
);
402 QColor
XParser::functionIntColor(uint id
)
404 int const ix
= ixValue(id
);
407 return QColor(ufkt
[ix
].integral_color
);
409 bool XParser::setFunctionFColor(const QColor
&color
, uint id
)
411 int const ix
= ixValue(id
);
414 ufkt
[ix
].color
= color
.rgb();
418 bool XParser::setFunctionF1Color(const QColor
&color
, uint id
)
420 int const ix
= ixValue(id
);
423 ufkt
[ix
].color
= color
.rgb();
427 bool XParser::setFunctionF2Color(const QColor
&color
, uint id
)
429 int const ix
= ixValue(id
);
432 ufkt
[ix
].color
= color
.rgb();
436 bool XParser::setFunctionIntColor(const QColor
&color
, uint id
)
438 int const ix
= ixValue(id
);
441 ufkt
[ix
].color
= color
.rgb();
446 int XParser::functionFLineWidth(uint id
)
448 int const ix
= ixValue(id
);
451 return ufkt
[ix
].linewidth
;
453 int XParser::functionF1LineWidth(uint id
)
455 int const ix
= ixValue(id
);
458 return ufkt
[ix
].f1_linewidth
;
460 int XParser::functionF2LineWidth(uint id
)
462 int const ix
= ixValue(id
);
465 return ufkt
[ix
].f2_linewidth
;
467 int XParser::functionIntLineWidth(uint id
)
469 int const ix
= ixValue(id
);
472 return ufkt
[ix
].integral_linewidth
;
474 bool XParser::setFunctionFLineWidth(int linewidth
, uint id
)
476 int const ix
= ixValue(id
);
479 ufkt
[ix
].linewidth
= linewidth
;
483 bool XParser::setFunctionF1LineWidth(int linewidth
, uint id
)
485 int const ix
= ixValue(id
);
488 ufkt
[ix
].f1_linewidth
= linewidth
;
492 bool XParser::setFunctionF2LineWidth(int linewidth
, uint id
)
494 int const ix
= ixValue(id
);
497 ufkt
[ix
].f2_linewidth
= linewidth
;
501 bool XParser::setFunctionIntLineWidth(int linewidth
, uint id
)
503 int const ix
= ixValue(id
);
506 ufkt
[ix
].integral_linewidth
= linewidth
;
511 QString
XParser::functionMinValue(uint id
)
513 int const ix
= ixValue(id
);
516 return ufkt
[ix
].str_dmin
;
519 bool XParser::setFunctionMinValue(const QString
&min
, uint id
)
521 int const ix
= ixValue(id
);
524 ufkt
[ix
].str_dmin
= min
;
529 QString
XParser::functionMaxValue(uint id
)
531 int const ix
= ixValue(id
);
534 return ufkt
[ix
].str_dmax
;
537 bool XParser::setFunctionMaxValue(const QString
&max
, uint id
)
539 int const ix
= ixValue(id
);
542 ufkt
[ix
].str_dmax
= max
;
547 QString
XParser::functionStartXValue(uint id
)
549 int const ix
= ixValue(id
);
552 return ufkt
[ix
].str_startx
;
555 bool XParser::setFunctionStartXValue(const QString
&x
, uint id
)
557 int const ix
= ixValue(id
);
560 ufkt
[ix
].str_startx
= x
;
565 QString
XParser::functionStartYValue(uint id
)
567 int const ix
= ixValue(id
);
570 return ufkt
[ix
].str_starty
;
573 bool XParser::setFunctionStartYValue(const QString
&y
, uint id
)
575 int const ix
= ixValue(id
);
578 ufkt
[ix
].str_starty
= y
;
583 QStringList
XParser::functionParameterList(uint id
)
585 int const ix
= ixValue(id
);
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
);
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
604 double const result
= eval(new_parameter
);
605 if ( parserError(false) != 0)
607 tmp_ufkt
->parameters
.append( ParameterValueItem(new_parameter
,result
) );
611 bool XParser::functionRemoveParameter(const QString
&remove_parameter
, uint id
)
613 int const ix
= ixValue(id
);
616 Ufkt
*tmp_ufkt
= &ufkt
[ix
];
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
628 tmp_ufkt
->parameters
.remove(it
);
632 int XParser::addFunction(const QString
&f_str
)
634 QString
added_function(f_str
);
635 int const pos
= added_function
.find(';');
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
642 if ( added_function
.contains('y') != 0)
644 int const id
= addfkt( added_function
);
647 Ufkt
*tmp_ufkt
= &ufkt
.last();
648 prepareAddingFunction(tmp_ufkt
);
649 if ( pos
!=-1 && !getext( tmp_ufkt
, f_str
) )
651 Parser::delfkt( tmp_ufkt
);
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() )
665 fixFunctionName(fstr
, XParser::Polar
);
669 fixFunctionName(fstr
, XParser::ParametricX
);
672 fixFunctionName(fstr
, XParser::ParametricY
);
675 fixFunctionName(fstr
, XParser::Function
);
678 int const id
= addfkt( fstr
);
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)
726 added_function
->parameters
.append( ParameterValueItem(*it
, result
) );
732 bool XParser::setFunctionExpression(const QString
&f_str
, uint id
)
734 int const ix
= ixValue(id
);
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
;
742 if ( parserError(false) != 0)
744 tmp_ufkt
->fstr
= old_fstr
;
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"));
764 Ufkt
*item
= &ufkt
[ixValue(id
)];
765 kdDebug() << "Transferring " << item
->fname
.latin1() << endl
;
767 if ( dcopclient_target
.isEmpty() && item
->fname
.at(0) == 'y' )
769 else if ( dcopclient_target
.isEmpty() )
772 str_result
= KInputDialog::getItem(i18n("kmplot"), i18n("Choose which KmPlot instance\nyou want to copy the function to:"), str_list
, 0, false, &ok
);
777 str_result
= dcopclient_target
;
779 QByteArray parameters
;
780 QDataStream
arg( parameters
, IO_WriteOnly
);
783 if (!item
->usecustomxmin
)
784 str_dmin
= item
->str_dmin
;
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);
798 KMessageBox::error(0, i18n("An error appeared during the transfer"));
802 QDataStream
replay_arg(replay_data
, IO_ReadOnly
);
804 replay_arg
>> result
;
807 KMessageBox::error(0, i18n("An error appeared during the transfer"));
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
);