Logo Search packages:      
Sourcecode: kdeedu-kde4 version File versions  Download package

xparser.cpp

/*
* KmPlot - a math. function plotter for the KDE-Desktop
*
* Copyright (C) 1998, 1999, 2000, 2002  Klaus-Dieter Möller <kd.moeller@t-online.de>
*               2006, 2007 David Saxton <david@bluehaze.org>
*               
* 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.
*
*/


// local includes
#include "xparser.h"
#include "parseradaptor.h"
#include "maindlg.h"

// KDE includes
#include <kglobal.h>
#include <kinputdialog.h>
#include <klocale.h>
#include <kmessagebox.h>

#include <QList>

#include <assert.h>
#include <cmath>


XParser * XParser::m_self = 0;

XParser * XParser::self()
{
      if ( !m_self )
            m_self = new XParser();
      
      return m_self;
}


XParser::XParser()
{
      differentialFinite = true;
      differentialDiverge = 0;

      new ParserAdaptor(this);
      QDBusConnection::sessionBus().registerObject("/parser", this);
}

XParser::~XParser()
{
}

00068 bool XParser::getext( Function *item, const QString &fstr )
{
      bool errflg = false;
      int p1, p2, p3, pe;
      QString tstr;
      pe = fstr.length();
      if ( fstr.indexOf( 'N' ) != -1 )
            item->plotAppearance( Function::Derivative0 ).visible = false;
      else
      {
            if ( fstr.indexOf( "A1" ) != -1 )
                  item->plotAppearance( Function::Derivative1 ).visible = true;
            if ( fstr.indexOf( "A2" ) != -1 )
                  item->plotAppearance( Function::Derivative2 ).visible = true;
      }
      switch ( fstr[0].unicode() )
      {
            case 'x':
            case 'y':
            case 'r':
                  item->plotAppearance( Function::Derivative1 ).visible = item->plotAppearance( Function::Derivative2 ).visible = false;
      }

      p1 = fstr.indexOf( "D[" );
      if ( p1 != -1 )
      {
            p1 += 2;
            const QString str = fstr.mid( p1, pe - p1);
            p2 = str.indexOf(',');
            p3 = str.indexOf(']');
            if ( p2 > 0 && p2 < p3 )
            {
                  tstr = str.left( p2 );
                  errflg |= !item->dmin.updateExpression( tstr );
                  tstr = str.mid( p2 + 1, p3 - p2 - 1 );
                  errflg |= !item->dmax.updateExpression( tstr );
                  if ( item->dmin.value() > item->dmax.value() )
                        errflg = true;
            }
            else
                  errflg = true;
      }
      p1 = fstr.indexOf( "P[" );
      if ( p1 != -1 )
      {
            int i = 0;
            p1 += 2;
            QString str = fstr.mid( p1, 1000);
            p3 = str.indexOf( ']' );
            do
            {
                  p2 = str.indexOf( ',' );
                  if ( p2 == -1 || p2 > p3 )
                        p2 = p3;
                  tstr = str.left( p2++ );
                  str = str.mid( p2, 1000 );
                  Value value;
                  if ( !value.updateExpression( tstr ) )
                  {
                        errflg = true;
                        break;
                  }
                  item->m_parameters.list.append( value );
                  p3 -= p2;
            }
            while ( p3 > 0 && i < 10 );
      }

      if ( errflg )
      {
            KMessageBox::error( 0, i18n( "Error in extension." ) );
            return false;
      }
      else
            return true;
}


00146 double XParser::derivative( int n, Equation * eq, DifferentialState * state, double x, double h )
{
      if ( n < -1 )
      {
            kError() << "Can't handle derivative < -1\n";
            return 0.0;
      }
      
      switch ( n )
      {
            case -1:
                  return differential( eq, & eq->differentialStates[0], x, h );
            
            case 0:
                  if ( state )
                        return differential( eq, state, x, h );
                  else
                        return fkt( eq, x );
                  
            case 1:
                  if ( state )
                        return ( differential(eq, state, x + (h/2), h ) - differential( eq, state, x - (h/2), h ) ) / h;
                  else
                        return ( fkt(eq, x + (h/2) ) - fkt( eq, x - (h/2) ) ) / h;
                  
            default:
                  return ( derivative( n-1, eq, state, x+(h/2), (h/4) ) - derivative( n-1, eq, state, x-(h/2), (h/4) ) ) / h;
      }
}


00177 double XParser::partialDerivative( int n1, int n2, Equation * eq, DifferentialState * state, double x, double y, double h1, double h2 )
{
      if ( n1 < 0 || n2 < 0 )
      {
            kError() << "Can't handle derivative < 0\n";
            return 0.0;
      }
      
      if ( n1 > 0 )
            return ( partialDerivative( n1-1, n2, eq, state, x+(h1/2), y, (h1/4), h2 ) - partialDerivative( n1-1, n2, eq, state, x-(h1/2), y, (h1/4), h2 ) ) / h1;
      
      Function * f = eq->parent();
      f->m_implicitMode = Function::FixedX;
      f->x = x;
      
      return derivative( n2, eq, state, y, h2 );
}


00196 QString XParser::findFunctionName( const QString & preferredName, int id )
{
      // The position of the character attempting to replace
      int pos = preferredName.length()-1;
      
      QString name = preferredName;
      
      for ( ; ; ++pos)
      {
            for ( QChar lastChar = 'f'; lastChar<'x'; ++lastChar.unicode() )
            {
                  bool ok = true;
                  name[pos] = lastChar;
                  
                  foreach ( Function * it, m_ufkt )
                  {
                        if ( int(it->id()) == id )
                              continue;
                        
                        foreach ( Equation * eq, it->eq )
                        {
                              if ( eq->name() == name )
                                    ok = false;
                        }
                        
                        if (!ok)
                              break;
                  }
                  if ( !ok )
                        continue;
                  
                  // Found a free name :)
                  return name;
            }
            name[pos]='f';
            name.append('f');
      }
}


00236 void XParser::fixFunctionName( QString &str, Equation::Type const type, int const id)
{
      int p1 = str.indexOf('(');
      int p2 = str.indexOf(')');
      int p3 = str.indexOf('=');
      
      if ( p1 < 0 )
            return;
      
      for ( int i = p2+1; i < p3; ++i )
      {
            if ( !str.at(i).isSpace() )
                  return;
      }
      
      QString const fname = str.left(p1);
      foreach ( Function * it, m_ufkt )
      {
            if ( int(it->id()) == id )
                  continue;
            
            foreach ( Equation * eq, it->eq )
            {
                  if ( eq->name() != fname )
                        continue;
                  
                  str = str.mid(p1,str.length()-1);
                  QString function_name;
                  if ( type == Equation::ParametricX )
                        function_name = "x";
                  else if ( type == Equation::ParametricY )
                        function_name = "y";
                  else
                        function_name = "f";
                  function_name = findFunctionName( function_name, id );
                  str.prepend( function_name );
                  return;
            }
      }
}


Vector XParser::rk4_f( int order, Equation * eq, double x, const Vector & y )
{
      bool useParameter = eq->usesParameter();
      
      m_result.resize( order );
      m_arg.resize( order+1 + (useParameter ? 1 : 0) );
      
      m_arg[0] = x;
      
      if ( useParameter )
            m_arg[1] = eq->parent()->k;
      
      memcpy( m_arg.data() + 1 + (useParameter ? 1 : 0), y.data(), order*sizeof(double) );
      memcpy( m_result.data(), y.data() + 1, (order-1)*sizeof(double) );
      
      m_result[order-1] = XParser::fkt( eq, m_arg );
      
      return m_result;
}


00299 double XParser::differential( Equation * eq, DifferentialState * state, double x_target, double max_dx )
{
      differentialFinite = true;
      
      if ( eq->order() < 1 )
      {
            kWarning() << "Zero order!\n";
            return 0;
      }
      
      max_dx = qAbs(max_dx);
      assert( max_dx > 0 ); // in case anyone tries to pass us a zero h
      
      // the difference between h and dx is that h is only used as a hint for the
      // stepwidth; dx is made similar to h in size, yet tiles the gap between x
      // and the previous x perfectly
      
      // see if the initial integral point in the function is closer to our
      // required x value than the last one (or the last point is invalid)
      if ( qAbs( state->x0.value() - x_target ) < qAbs( state->x - x_target ) )
            state->resetToInitial();
      
      int order = eq->order();
      
      m_k1.resize( order );
      m_k2.resize( order );
      m_k3.resize( order );
      m_k4.resize( order );
      m_y_temp.resize( order );
      
      double x = state->x;
      m_y = state->y;
      if ( x_target == x )
            return m_y[0];
      
      int intervals = int( qAbs(x_target-x)/max_dx + 1 );
      double dx = (x_target-x) / double(intervals);
      
      for ( int i = 0; i < intervals; ++i )
      {
            // Update differentialDiverge before y possible becomes infinite
            differentialDiverge = x;
            
            x = state->x + i*dx;
            
            
            m_k1 = rk4_f( order, eq, x, m_y );
            
            m_y_temp.combine( m_y, dx/2, m_k1 );
            m_k2 = rk4_f( order, eq, x + dx/2, m_y_temp);
            
            m_y_temp.combine( m_y, dx/2, m_k2 );
            m_k3 = rk4_f( order, eq, x + dx/2, m_y_temp );
            
            m_y_temp.combine( m_y, dx, m_k3 );
            m_k4 = rk4_f( order, eq, x + dx, m_y_temp );
            
            m_y.addRK4( dx, m_k1, m_k2, m_k3, m_k4 );
            
            if ( !finite(m_y[0]) )
            {
                  differentialFinite = false;
                  state->resetToInitial();
                  return 0;
            }
      }
      
      state->x = x + dx;
      state->y = m_y;
      
      return m_y[0];
}


00373 QColor XParser::defaultColor(int function)
{
      switch ( function % 10 )
      {
            case 0:
                  return Settings::color0();
            case 1:
                  return Settings::color1();
            case 2:
                  return Settings::color2();
            case 3:
                  return Settings::color3();
            case 4:
                  return Settings::color4();
            case 5:
                  return Settings::color5();
            case 6:
                  return Settings::color6();
            case 7:
                  return Settings::color7();
            case 8:
                  return Settings::color8();
            case 9:
                  return Settings::color9();
      }
      
      assert( !"Shouldn't happen - XParser::defaultColor" );
      return QColor();
}

00403 QStringList XParser::listFunctionNames()
{
      return userFunctions();
}

00408 bool XParser::functionFVisible(uint id)
{
      return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance( Function::Derivative0 ).visible : false;
}
bool XParser::functionF1Visible(uint id)
{
      return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance( Function::Derivative1 ).visible : false;
}
bool XParser::functionF2Visible(uint id)
{
      return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance( Function::Derivative2 ).visible : false;
}
bool XParser::functionIntVisible(uint id)
{
      return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance( Function::Integral ).visible : false;
}

00425 bool XParser::setFunctionFVisible(uint id, bool visible)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Derivative0 ).visible = visible;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}
bool XParser::setFunctionF1Visible(uint id, bool visible)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Derivative1 ).visible = visible;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}
bool XParser::setFunctionF2Visible(uint id, bool visible)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Derivative2 ).visible = visible;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}
bool XParser::setFunctionIntVisible(uint id, bool visible)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Integral ).visible = visible;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}

00458 QString XParser::functionStr(uint id, uint eq)
{
      if ( !m_ufkt.contains( id ) || (eq>=2) )
            return "";
      return m_ufkt[id]->eq[eq]->fstr();
}

00465 QColor XParser::functionFColor(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return QColor();
      return QColor(m_ufkt[id]->plotAppearance( Function::Derivative0 ).color);
}
QColor XParser::functionF1Color(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return QColor();
      return QColor(m_ufkt[id]->plotAppearance( Function::Derivative1 ).color);
}
QColor XParser::functionF2Color(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return QColor();
      return QColor(m_ufkt[id]->plotAppearance( Function::Derivative2 ).color);
}
QColor XParser::functionIntColor(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return QColor();
      return QColor(m_ufkt[id]->plotAppearance( Function::Integral ).color);
}
00489 bool XParser::setFunctionFColor(uint id, const QColor &color)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Derivative0 ).color = color;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}
bool XParser::setFunctionF1Color(uint id, const QColor &color)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Derivative1 ).color = color;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}           
bool XParser::setFunctionF2Color(uint id, const QColor &color)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Derivative2 ).color = color;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}
bool XParser::setFunctionIntColor(uint id, const QColor &color)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Integral ).color = color;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}

00522 double XParser::functionFLineWidth(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return 0;
      return m_ufkt[id]->plotAppearance( Function::Derivative0 ).lineWidth;
}
double XParser::functionF1LineWidth(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return 0;
      return m_ufkt[id]->plotAppearance( Function::Derivative1 ).lineWidth;
}
double XParser::functionF2LineWidth(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return 0;
      return m_ufkt[id]->plotAppearance( Function::Derivative2 ).lineWidth;
}
double XParser::functionIntLineWidth(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return 0;
      return m_ufkt[id]->plotAppearance( Function::Integral ).lineWidth;
}
00546 bool XParser::setFunctionFLineWidth(uint id, double linewidth)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Derivative0 ).lineWidth = linewidth;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}
bool XParser::setFunctionF1LineWidth(uint id, double linewidth)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Derivative1 ).lineWidth = linewidth;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}           
bool XParser::setFunctionF2LineWidth(uint id, double linewidth)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Derivative2 ).lineWidth = linewidth;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}
bool XParser::setFunctionIntLineWidth(uint id, double linewidth)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->plotAppearance( Function::Integral ).lineWidth = linewidth;
      MainDlg::self()->requestSaveCurrentState();
      return true;
}

00579 QString XParser::functionMinValue(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return 0;
  return m_ufkt[id]->dmin.expression();
}

00586 bool XParser::setFunctionMinValue(uint id, const QString &min)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->dmin.expression() = min;
      MainDlg::self()->requestSaveCurrentState();
  return true;
}

QString XParser::functionMaxValue(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return 0;
  return m_ufkt[id]->dmax.expression();
}

bool XParser::setFunctionMaxValue(uint id, const QString &max)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      m_ufkt[id]->dmax.expression() = max;
      MainDlg::self()->requestSaveCurrentState();
  return true;
}

00611 bool XParser::setFunctionStartValue(uint id, const QString &x, const QString &y)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      DifferentialState * state = & m_ufkt[id]->eq[0]->differentialStates[0];
      state->x0.updateExpression( x );
      state->y0[0].updateExpression( y );
      MainDlg::self()->requestSaveCurrentState();
      return true;
}

00622 QString XParser::functionStartXValue(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return 0;
      DifferentialState * state = & m_ufkt[id]->eq[0]->differentialStates[0];
      return state->x0.expression();
}


QString XParser::functionStartYValue(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return 0;
      DifferentialState * state = & m_ufkt[id]->eq[0]->differentialStates[0];
      return state->y0[0].expression();
}

00639 QStringList XParser::functionParameterList(uint id)
{
      if ( !m_ufkt.contains( id ) )
            return QStringList();
      Function *item = m_ufkt[id];
      QStringList str_parameter;
      foreach ( const Value &it, item->m_parameters.list )
            str_parameter << it.expression();
      return str_parameter;
}
bool XParser::functionAddParameter(uint id, const QString &new_parameter)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      Function *tmp_ufkt = m_ufkt[id];
      
      //check if the parameter already exists
      foreach ( const Value &it, tmp_ufkt->m_parameters.list )
      {
            if ( it.expression() == new_parameter )
                  return false;
      }
      
      Value value;
      if ( !value.updateExpression( new_parameter ) )
            return false;
      tmp_ufkt->m_parameters.list.append( value );
      MainDlg::self()->requestSaveCurrentState();
      return true;
}
bool XParser::functionRemoveParameter(uint id, const QString &remove_parameter)
{
      if ( !m_ufkt.contains( id ) )
            return false;
      Function *tmp_ufkt = m_ufkt[id];
      
      bool found = false;
      QList<Value>::iterator it;
      for ( it = tmp_ufkt->m_parameters.list.begin(); it != tmp_ufkt->m_parameters.list.end(); ++it)
      {
            if ( (*it).expression() == remove_parameter) //check if the parameter already exists
            {
                  found = true;
                  break;
            }
      }
      if (!found)
            return false;
      tmp_ufkt->m_parameters.list.erase(it);
      MainDlg::self()->requestSaveCurrentState();
      return true;
}
int XParser::addFunction(const QString &f_str0, const QString &_f_str1)
{
      QString added_function(f_str0);
      QString f_str1(_f_str1);
      int const pos = added_function.indexOf(';');
      if (pos!=-1)
        added_function = added_function.left(pos);
      
      fixFunctionName(added_function);
      if ( !f_str1.isEmpty() )
            fixFunctionName( f_str1 );
      
      Function::Type type;
      
      if ( !f_str1.isEmpty() )
            type = Function::Parametric;
      else if ( f_str0.count( '=' ) > 1 )
            type = Function::Implicit;
      else
            type = (added_function[0] == 'r') ? Function::Polar : Function::Cartesian;
      
      int const id = Parser::addFunction( added_function, f_str1, type );
      if (id==-1)
            return -1;
      Function *tmp_ufkt = m_ufkt[id];
      if ( pos!=-1 && !getext( tmp_ufkt, f_str0 ) )
      {
            Parser::removeFunction( tmp_ufkt );
            return -1;
      }
      MainDlg::self()->requestSaveCurrentState();
      return id;
}

bool XParser::addFunction(const QString &fstr_const0, const QString &fstr_const1, bool f_mode, bool f1_mode, bool f2_mode, bool integral_mode, double linewidth, double f1_linewidth, double f2_linewidth, double integral_linewidth, const QString &str_dmin, const QString &str_dmax, const QString &str_startx, const QString &str_starty, double integral_precision, const QColor &color, const QColor &f1_color, const QColor &f2_color, const QColor &integral_color, const QStringList & str_parameter, int use_slider)
{
      QString fstr[2] = { fstr_const0, fstr_const1 };
      Function::Type type = Function::Cartesian;
      for ( unsigned i = 0; i < 2; ++i )
      {
            if ( fstr[i].isEmpty() )
                  continue;
            
            switch ( fstr[i][0].unicode() )
            {
                  case 'r':
                  {
                        fixFunctionName(fstr[i], Equation::Polar);
                        type = Function::Polar;
                        break;
                  }
                  case 'x':
                        fixFunctionName(fstr[i], Equation::ParametricX);
                        type = Function::Parametric;
                        break;
                  case 'y':
                        fixFunctionName(fstr[i], Equation::ParametricY);
                        type = Function::Parametric;
                        break;
                  default:
                        fixFunctionName(fstr[i], Equation::Cartesian );
                        type = Function::Cartesian;
                        break;
            }
      }
      
      int const id = Parser::addFunction( fstr[0], fstr[1], type );
      if ( id==-1 )
            return false;
      Function *added_function = m_ufkt[id];
      
      PlotAppearance appearance;
      
      // f0
      appearance.visible = f_mode;
      appearance.color = color;
      appearance.lineWidth = linewidth;
      added_function->plotAppearance( Function::Derivative0 ) = appearance;
      
      // f1
      appearance.visible = f1_mode;
      appearance.color = f1_color;
      appearance.lineWidth = f1_linewidth;
      added_function->plotAppearance( Function::Derivative1 ) = appearance;
      
      // f2
      appearance.visible = f2_mode;
      appearance.color = f2_color;
      appearance.lineWidth = f2_linewidth;
      added_function->plotAppearance( Function::Derivative2 ) = appearance;
      
      // integral
      appearance.visible = integral_mode;
      appearance.color = integral_color;
      appearance.lineWidth = integral_linewidth;
      added_function->plotAppearance( Function::Integral ) = appearance;
      
      added_function->dmin.updateExpression( str_dmin );
      added_function->usecustomxmin = !str_dmin.isEmpty();
      
      added_function->dmax.updateExpression( str_dmax );
      added_function->usecustomxmax = !str_dmax.isEmpty();
      
      DifferentialState * state = & added_function->eq[0]->differentialStates[0];
      state->x0.updateExpression( str_startx );
      state->y0[0].updateExpression( str_starty );
      
      added_function->eq[0]->differentialStates.setStep( Value( integral_precision ) );
      
      added_function->m_parameters.sliderID = use_slider;
      for( QStringList::ConstIterator it = str_parameter.begin(); it != str_parameter.end(); ++it )
      {
            added_function->m_parameters.list.append( *it );
      }
      MainDlg::self()->requestSaveCurrentState();
      return true;
}

bool XParser::setFunctionExpression(uint id, uint eq, const QString &f_str)
{
      Function * tmp_ufkt = functionWithID( id );
      if ( !tmp_ufkt )
            return false;
      QString const old_fstr = tmp_ufkt->eq[eq]->fstr();
      QString const fstr_begin = tmp_ufkt->eq[eq]->fstr().left(tmp_ufkt->eq[eq]->fstr().indexOf('=')+1);
      
      return tmp_ufkt->eq[eq]->setFstr( fstr_begin+f_str );
}


Generated by  Doxygen 1.6.0   Back to index