Logo Search packages:      
Sourcecode: qalculate-kde version File versions  Download package

kqalculate.cpp

/***************************************************************************
 *   Copyright (C) 2005 by Niklas Knutsson   *
 *   nq@altern.org   *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <kdialog.h>
#include <klocale.h>

#include "kqalculate.h"
#include "qalculateinsertfunctiondialog.h"
#include "qalculate_kde_utils.h"
#include "preferences.h"
#include "qalculatepreferencesdialog.h"
#include "qalculateimportcsvdialog.h"
#include "qalculateexportcsvdialog.h"
#include "qalculateexpressionedit.h"
#include "qalculateprecisiondialog.h"
#include "qalculatedecimalsdialog.h"
#include "qalculateeditvariabledialog.h"
#include "qalculateeditmatrixvectordialog.h"
#include "qalculateeditunitdialog.h"
#include "qalculateeditfunctiondialog.h"
#include "qalculateeditdatasetdialog.h"
#include "qalculateeditunknownvariabledialog.h"
#include "qalculatevariablesdialog.h"
#include "qalculatefunctionsdialog.h"
#include "qalculateunitsdialog.h"
#include "qalculatedatasetsdialog.h"
#include "qalculateconvertunitsdialog.h"
#include "qalculateconvertnumberbasesdialog.h"
#include "qalculateperiodictabledialog.h"
#include "qalculateplotdialog.h"
#include "qalculatesetbaseinexpressiondialog.h"
#include "qalculatesetbaseotherdialog.h"
#include "qalculateinsertmatrixvectordialog.h"

#include <kstringhandler.h>
#include <qtable.h>
#include <kseparator.h>
#include <kiconloader.h>
#include <qframe.h>
#include <qvariant.h>
#include <qtooltip.h>
#include <qwhatsthis.h>
#include <qclipboard.h>
#include <qstylesheet.h>
#include <kcompletion.h>
#include <klineedit.h>
#include <qlabel.h>
#include <kmessagebox.h>
#include <qpixmap.h>
#include <qpicture.h>
#include <qpainter.h>
#include <qfontmetrics.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <math.h>
#include <dirent.h>
#include <pthread.h>
#include <qsimplerichtext.h>
#include <qstatusbar.h>
#include <qwidgetstack.h>
#include <ktextbrowser.h>
#include <kpushbutton.h>
#include "qalculateresultdisplay.h"
#include <qbitmap.h>
#include <qscrollview.h>
#include <qobject.h>
#include <kapplication.h>
#include <kaction.h>
#include <qspinbox.h>
#include <kprogress.h>
#include <kpopupmenu.h>
#include <kmenubar.h>
#include <qlayout.h>
#include <qtimer.h>
#include <kcompletionbox.h>
#include <qstringlist.h>
#include <qcombobox.h>
#include <ksystemtray.h>
#if KDE_VERSION_MAJOR > 3 || KDE_VERSION_MINOR > 1
#include <kactionclasses.h>
#endif
#if KDE_VERSION_MAJOR > 3 || KDE_VERSION_MINOR >= 4
#include <kaccelmanager.h>
#endif
#include <qbuttongroup.h>
#include <qvbuttongroup.h>
#include <qradiobutton.h>
#include <qgrid.h>
#include <kfiledialog.h>
#include <qimage.h>
#include <kaccel.h>
#include <kio/netaccess.h>
#include <kinputdialog.h>
#include <kdeversion.h>
#include <qstyle.h>

KnownVariable *vans[5];
MathStructure *mstruct, *matrix_mstruct, *parsed_mstruct, *parsed_tostruct;
QString result_text, result_history_text, parsed_text;
QWidget *expressionWidget, *resultWidget, *statusWidget_l;
QWidget *topWidget;
KQalculate *mainWin = 0;
bool prev_result_approx;
extern bool close_to_systray;
extern bool display_expression_status;
extern QColor status_error_color;
extern QColor status_warning_color;
extern int use_icon_buttons;
extern bool enable_expression_completion;

extern QString initial_history;
extern tree_struct function_cats, unit_cats, variable_cats;
extern vector<void*> ia_units, ia_variables, ia_functions;
extern vector<MathFunction*> recent_functions;
extern vector<Variable*> recent_variables;
extern vector<Unit*> recent_units;
vector<MathStructure> result_parts;

extern KnownVariable *vans[5];

extern PrintOptions printops;
extern EvaluationOptions evalops;
extern bool save_mode_on_exit, save_defs_on_exit;

extern bool canplot;

extern bool use_custom_result_font, use_custom_expression_font, use_custom_status_font;
extern QString custom_result_font, custom_expression_font, custom_status_font;

extern QTimer *error_timer;

extern QStringList expression_history;

bool expression_has_changed, expression_has_changed2, had_errors_before, had_warnings_before, block_result_update;

FILE *view_pipe_r, *view_pipe_w, *command_pipe_r, *command_pipe_w;
pthread_t view_thread, command_thread;
pthread_attr_t view_thread_attr, command_thread_attr;
bool b_busy, command_thread_started;
int saved_divisionline_height = 0;
uint initial_result_index = 0;

extern bool show_keypad, show_history;

extern vector<mode_struct> modes;

const MathStructure *KQalculate::getResultPart(int i) {
      if(i < 1 || (size_t) i > result_parts.size()) return NULL;
      return &result_parts[(size_t) i - 1];
}

#if KDE_VERSION_MAJOR < 4 && KDE_VERSION_MINOR < 2
#include <kiconloader.h>
#include <kconfig.h>
QPixmap loadSystrayIcon(const QString &icon) {
      KConfig *appCfg = kapp->config();
      KConfigGroupSaver configSaver(appCfg, "System Tray");
      int iconWidth = appCfg->readNumEntry("systrayIconWidth", 22);
      return KGlobal::instance()->iconLoader()->loadIcon(icon, KIcon::Panel, iconWidth);
}
#endif


KQalculate::KQalculate(QWidget* parent, const char* name, WFlags fl) : KMainWindow(parent, name, fl) {

      if(!name) setName("kqalculate");
      
      QStyleSheet::setDefaultSheet(new QalculateStyleSheet());

      insert_matrix_dialog = NULL;
      preferences_dialog = NULL;
      precisionDialog = NULL;
      decimalsDialog = NULL;
      variable_edit_dialog = NULL;
      store_dialog = NULL;
      matrix_edit_dialog = NULL;
      import_csv_dialog = NULL;
      export_csv_dialog = NULL;
      unit_edit_dialog = NULL;
      function_edit_dialog = NULL;
      dataset_edit_dialog = NULL;
      unknown_edit_dialog = NULL;
      variables_dialog = NULL;
      functions_dialog = NULL;
      units_dialog = NULL;
      datasets_dialog = NULL;
      convert_to_unit_expression_dialog = NULL;
      convert_number_bases_dialog = NULL;
      periodic_table_dialog = NULL;
      plot_dialog = NULL;
      set_base_in_expression_dialog = NULL;
      set_base_other_dialog = NULL;
      
      prev_result_approx = false;
      expression_has_changed = false;
      expression_has_changed2 = false;
      had_errors_before = false;
      had_warnings_before = false;
      block_result_update = false;
      
      history_height = 0;
      
      trayicon = NULL; 
      showSystemTrayIcon(close_to_systray);

      setCentralWidget(new QWidget(this));
      QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget(), 11, 6);
      mainLayout->setResizeMode(QLayout::Minimum);

      QHBoxLayout *topLayout = new QHBoxLayout(0, 0, 6);

      bool use_button_pixmaps = false;
      if(use_icon_buttons > 0) {
            use_button_pixmaps = true;
      } else if(use_icon_buttons < 0) {
            KConfig config("kdeglobals", true, false);      
            config.setGroup("KDE"); 
            use_button_pixmaps = config.readBoolEntry("ShowIconsOnPushButtons", false);
      }

      if(use_button_pixmaps) leftButtonsLayout = new QVBoxLayout(0, 0, 3);
      else leftButtonsLayout = new QVBoxLayout(0, 0, 6);
      if(use_button_pixmaps) executeButton = new QalculateButton(KApplication::kApplication()->iconLoader()->loadIconSet("exec", KIcon::Small, KIcon::SizeSmallMedium), "", centralWidget());
      else executeButton = new QalculateButton(i18n("="), centralWidget());
      executeButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, false);
      QToolTip::add(executeButton, i18n("Calculate expression"));
      leftButtonsLayout->addWidget(executeButton);
      leftButtonsSeparator = new KSeparator(Qt::Horizontal, centralWidget());
      leftButtonsLayout->addWidget(leftButtonsSeparator);
      if(use_button_pixmaps) leftButtonsSeparator->hide();
      if(use_button_pixmaps) storeButton = new QalculateButton(KApplication::kApplication()->iconLoader()->loadIconSet("filesaveas", KIcon::Small, KIcon::SizeSmallMedium), "", centralWidget());
      else storeButton = new QalculateButton(i18n("Store"), centralWidget());
      storeButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, false);
      QToolTip::add(storeButton, i18n("Store result as variable"));
      leftButtonsLayout->addWidget(storeButton);
      if(use_button_pixmaps) convertButton = new QalculateButton(KApplication::kApplication()->iconLoader()->loadIconSet("qalculate_convert", KIcon::Small, KIcon::SizeSmallMedium), "", centralWidget());
      else convertButton = new QalculateButton(i18n("Convert"), centralWidget());
      convertButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed, false);
      QToolTip::add(convertButton, i18n("Convert units in result"));
      leftButtonsLayout->addWidget(convertButton);
      leftButtonsLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Minimum));
      
      QVBoxLayout *expressionLayout = new QVBoxLayout(0, 0, 0);
      expressionEdit = new QalculateExpressionEdit(true, centralWidget());
      expressionLayout->addWidget(expressionEdit);
      expressionEdit->setFocus();
      expressionEdit->expression_history = expression_history;
      if(!enable_expression_completion) expressionEdit->disableCompletion();
      QToolTip::add(expressionEdit, i18n("Enter expression here"));
      QHBoxLayout *statusLayout = new QHBoxLayout(0, 0, 6);
      statusLabel_l = new QalculateParseLabel(centralWidget());
      //statusLabel_l->setSizePolicy(QSizePolicy((QSizePolicy::SizeType) 7, (QSizePolicy::SizeType) 1, 10, 0, statusLabel_l->sizePolicy().hasHeightForWidth()));
      statusLabel_l->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum, false);
      statusLabel_l->setLineWidth(0);
      statusLabel_l->setMargin(0);
      statusLabel_l->setAlignment(int(QLabel::AlignTop | QLabel::AlignLeft));
      if(!display_expression_status) statusLabel_l->hide();
      statusLayout->addWidget(statusLabel_l);
      statusLabel_r = new QLabel(i18n("status"), centralWidget());
      //statusLabel_r->setSizePolicy(QSizePolicy((QSizePolicy::SizeType) 7, (QSizePolicy::SizeType) 1, 1, 0, statusLabel_r->sizePolicy().hasHeightForWidth()));
      statusLabel_r->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum, false);
      statusLabel_r->setLineWidth(0);
      statusLabel_r->setMargin(0);
      statusLabel_r->setTextFormat(Qt::RichText);
      statusLabel_r->setAlignment(int(QLabel::AlignTop | QLabel::AlignRight));      
      statusLayout->addWidget(statusLabel_r);
      expressionLayout->addLayout(statusLayout);
      resultLabel = new QalculateResultDisplay(centralWidget());
      resultLabel->setRightMargin(10);
      expressionLayout->addWidget(resultLabel);
      
      topLayout->addLayout(expressionLayout);
      topLayout->addLayout(leftButtonsLayout);
      mainLayout->addLayout(topLayout);
      
      resultLabel->setWordWrap(QTextEdit::WidgetWidth);
      resultLabel->setMargin(0);

      bottomLine = new KSeparator(Qt::Horizontal, centralWidget());
      mainLayout->addWidget(bottomLine);

      mainStack = new QWidgetStack(centralWidget());
      mainStack->setEnabled(true);
      mainStack->setSizePolicy(QSizePolicy((QSizePolicy::SizeType) 5, (QSizePolicy::SizeType) 7, 0, 0, mainStack->sizePolicy().hasHeightForWidth()));

      keypadPage = new QWidget(mainStack);
      QVBoxLayout *keypadPageLayout = new QVBoxLayout(keypadPage, 0, 12);
      
      keypadPageLayout->addWidget(new KSeparator(Qt::Horizontal, keypadPage));

      QHBoxLayout *keypadTopLayout = new QHBoxLayout(0, 0, 6);
      kpExact = new QalculateButton(i18n("Exact"), keypadPage);
      QToolTip::add(kpExact, i18n("Toggle exact mode"));
      kpExact->setToggleButton(true);
      keypadTopLayout->addWidget(kpExact);
      kpFraction = new QalculateButton(i18n("Fraction"), keypadPage);
      QToolTip::add(kpFraction, i18n("Toggle fractional display"));
      kpFraction->setToggleButton(true);
      keypadTopLayout->addWidget(kpFraction);
      kpNumericCombo = new QComboBox(true, keypadPage);
      QToolTip::add(kpNumericCombo, i18n("Numerical display"));
      kpNumericCombo->setEditable(false);
      keypadTopLayout->addWidget(kpNumericCombo);
      kpNumericCombo->insertItem(i18n("Normal"));
      kpNumericCombo->insertItem(i18n("Scientific"));
      kpNumericCombo->insertItem(i18n("Pure"));
      kpNumericCombo->insertItem(i18n("Simple"));
      kpBaseCombo = new QComboBox(true, keypadPage);
      QToolTip::add(kpBaseCombo, i18n("Base in result"));
      kpBaseCombo->setEditable(false);
      keypadTopLayout->addWidget(kpBaseCombo);
      keypadPageLayout->addLayout(keypadTopLayout);
      kpBaseCombo->insertItem(i18n("Binary"));
      kpBaseCombo->insertItem(i18n("Octal"));
      kpBaseCombo->insertItem(i18n("Decimal"));
      kpBaseCombo->insertItem(i18n("Hexadecimal"));
      kpBaseCombo->insertItem(i18n("Sexagesimal"));
      kpBaseCombo->insertItem(i18n("Time Format"));
      kpBaseCombo->insertItem(i18n("Roman"));
      kpBaseCombo->insertItem(i18n("Other..."));

      QHBoxLayout *keypadBottomLayout = new QHBoxLayout(0, 0, 24);

      QGridLayout *keypadFunctionsLayout = new QGridLayout(0, 5, 3, 0, 6);
      
      functionsButton = new QalculateButton(i18n("f(x)"), keypadPage);
      QFont fb_font(functionsButton->font());
      fb_font.setItalic(true);
      functionsButton->setFont(fb_font);
      QToolTip::add(functionsButton, i18n("Open functions manager"));
      keypadFunctionsLayout->addWidget(functionsButton, 0, 0);
      kpSqrt = new QalculateButton(i18n("sqrt"), keypadPage);
      QToolTip::add(kpSqrt, i18n("Square root"));
      keypadFunctionsLayout->addWidget(kpSqrt, 1, 0);
      kpRaise = new QalculateButton(keypadPage);
      kpRaise->setMarkup(i18n("x<sup>y</sup>"));
      QToolTip::add(kpRaise, i18n("Raise"));
      keypadFunctionsLayout->addWidget(kpRaise, 0, 1);
      kpSquare = new QalculateButton(keypadPage);
      kpSquare->setMarkup(i18n("x<sup>2</sup>"));
      QToolTip::add(kpSquare, i18n("Square"));
      keypadFunctionsLayout->addWidget(kpSquare, 0, 2);
      kpLog = new QalculateButton(i18n("log"), keypadPage);
      QToolTip::add(kpLog, i18n("Base-10 logarithm"));
      keypadFunctionsLayout->addWidget(kpLog, 1, 1);
      kpLn = new QalculateButton(i18n("ln"), keypadPage);
      QToolTip::add(kpLn, i18n("Natural logarithm"));
      keypadFunctionsLayout->addWidget(kpLn, 1, 2);
      kpFactorial = new QalculateButton(i18n("x!"), keypadPage);
      QToolTip::add(kpFactorial, i18n("Factorial"));
      keypadFunctionsLayout->addWidget(kpFactorial, 2, 0);
      kpCos = new QalculateButton(i18n("cos"), keypadPage);
      QToolTip::add(kpCos, i18n("Cosine"));
      keypadFunctionsLayout->addWidget(kpCos, 2, 1);
      kpTan = new QalculateButton(i18n("tan"), keypadPage);
      QToolTip::add(kpTan, i18n("Tangent"));
      keypadFunctionsLayout->addWidget(kpTan, 2, 2);
      kpHyp = new QalculateButton(i18n("hyp"), keypadPage);
      QToolTip::add(kpHyp, i18n("Toggle hyperbolic functions"));
      kpHyp->setToggleButton(true);
      keypadFunctionsLayout->addWidget(kpHyp, 3, 0);
      kpInv = new QalculateButton(i18n("inv"), keypadPage);
      QToolTip::add(kpInv, i18n("Toggle inverse functions"));
      kpInv->setToggleButton(true);
      keypadFunctionsLayout->addWidget(kpInv, 3, 1);
      kpSin = new QalculateButton(i18n("sin"), keypadPage);
      QToolTip::add(kpSin, i18n("Sine"));
      keypadFunctionsLayout->addWidget(kpSin, 3, 2);
      QHBoxLayout *keypadAngleLayout = new QHBoxLayout(0, 0, 6);
      kpAngleGroup = new QButtonGroup();
      kpAngleGroup->setExclusive(true);
      kpDegreesButton = new QRadioButton(i18n("Deg"), keypadPage);
      kpAngleGroup->insert(kpDegreesButton, 0);
      keypadAngleLayout->addWidget(kpDegreesButton);
      kpRadiansButton = new QRadioButton(i18n("Rad"), keypadPage);
      kpAngleGroup->insert(kpRadiansButton, 1);
      keypadAngleLayout->addWidget(kpRadiansButton);
      kpGradiansButton = new QRadioButton(i18n("Gra"), keypadPage);
      kpAngleGroup->insert(kpGradiansButton, 2);
      keypadAngleLayout->addWidget(kpGradiansButton);
      kpNoAngleUnitButton = new QRadioButton(i18n("None"), keypadPage);
      kpAngleGroup->insert(kpNoAngleUnitButton, 3);
      keypadAngleLayout->addWidget(kpNoAngleUnitButton);
      kpNoAngleUnitButton->hide();
      keypadAngleLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
      keypadFunctionsLayout->addMultiCellLayout(keypadAngleLayout, 4, 4, 0, 2);
      
#if KDE_VERSION_MAJOR > 3 || KDE_VERSION_MINOR >= 4   
      KAcceleratorManager::setNoAccel(kpDegreesButton);
      KAcceleratorManager::setNoAccel(kpRadiansButton);
      KAcceleratorManager::setNoAccel(kpGradiansButton);
      KAcceleratorManager::setNoAccel(kpNoAngleUnitButton);
#endif            
      
      keypadBottomLayout->addLayout(keypadFunctionsLayout);
      
      QGridLayout *keypadBasicsLayout = new QGridLayout(0, 1, 1, 0, 6);
      kp7 = new QalculateButton(i18n("7"), keypadPage);
      keypadBasicsLayout->addWidget(kp7, 0, 0);
      kp8 = new QalculateButton(i18n("8"), keypadPage);
      keypadBasicsLayout->addWidget(kp8, 0, 1);
      kp9 = new QalculateButton(i18n("9"), keypadPage);
      keypadBasicsLayout->addWidget(kp9, 0, 2);
      kp4 = new QalculateButton(i18n("4"), keypadPage);
      keypadBasicsLayout->addWidget(kp4, 1, 0);
      kp5 = new QalculateButton(i18n("5"), keypadPage);
      keypadBasicsLayout->addWidget(kp5, 1, 1);
      kp6 = new QalculateButton(i18n("6"), keypadPage);
      keypadBasicsLayout->addWidget(kp6, 1, 2);
      kp1 = new QalculateButton(i18n("1"), keypadPage);
      keypadBasicsLayout->addWidget(kp1, 2, 0);
      kp2 = new QalculateButton(i18n("2"), keypadPage);
      keypadBasicsLayout->addWidget(kp2, 2, 1);
      kp3 = new QalculateButton(i18n("3"), keypadPage);
      keypadBasicsLayout->addWidget(kp3, 2, 2);
      kp0 = new QalculateButton(i18n("0"), keypadPage);
      keypadBasicsLayout->addWidget(kp0, 3, 0);
      kpDot = new QalculateButton(".", keypadPage);
      QToolTip::add(kpDot, i18n("Decimal point"));
      keypadBasicsLayout->addWidget(kpDot, 3, 1);
      kpExp = new QalculateButton(i18n("EXP"), keypadPage);
      QToolTip::add(kpExp, i18n("10^x"));
      keypadBasicsLayout->addWidget(kpExp, 3, 2);
      
      kpDel = new QalculateButton(i18n("Del"), keypadPage);
      QToolTip::add(kpDel, i18n("Delete"));
      keypadBasicsLayout->addWidget(kpDel, 0, 3);
      kpClear = new QalculateButton(i18n("AC"), keypadPage);
      QToolTip::add(kpClear, i18n("Clear"));
      keypadBasicsLayout->addWidget(kpClear, 0, 4);
      kpTimes = new QalculateButton("*", keypadPage);
      QToolTip::add(kpTimes, i18n("Multiply"));
      keypadBasicsLayout->addWidget(kpTimes, 1, 3);
      kpDivision = new QalculateButton("/", keypadPage);
      QToolTip::add(kpDivision, i18n("Divide"));
      keypadBasicsLayout->addWidget(kpDivision, 1, 4);
      kpPlus = new QalculateButton("+", keypadPage);
      QToolTip::add(kpPlus, i18n("Add"));
      keypadBasicsLayout->addWidget(kpPlus, 2, 3);
      kpMinus = new QalculateButton("-", keypadPage);
      QToolTip::add(kpMinus, i18n("Subtract"));
      keypadBasicsLayout->addWidget(kpMinus, 2, 4);
      kpAns = new QalculateButton(i18n("Ans"), keypadPage);
      QToolTip::add(kpAns, i18n("Previous result"));
      keypadBasicsLayout->addWidget(kpAns, 3, 3);
      kpEquals = new QalculateButton(i18n("="), keypadPage);
      QToolTip::add(kpEquals, i18n("Calculate expression"));
      keypadBasicsLayout->addWidget(kpEquals, 3, 4);
      keypadBottomLayout->addLayout(keypadBasicsLayout);
      
      keypadPageLayout->addLayout(keypadBottomLayout);

      keypadPageLayout->addWidget(new KSeparator(Qt::Horizontal, keypadPage));
      mainStack->addWidget(keypadPage, 0);

      historyPage = new QWidget(mainStack, "historyPage");
      QVBoxLayout *historyPageLayout = new QVBoxLayout(historyPage, 0, 0);
      historyBrowser = new QalculateHistoryBrowser(historyPage, "historyBrowser");
      historyBrowser->setTextFormat(KTextBrowser::RichText);
      historyBrowser->setWordWrap(KTextBrowser::NoWrap);
      historyPageLayout->addWidget(historyBrowser);
      mainStack->addWidget(historyPage, 1);
      mainLayout->addWidget(mainStack);
      
      QHBoxLayout *bottomLayout = new QHBoxLayout(0, 0, 6);
      historyButton = new QPushButton(i18n("History"), centralWidget());
      QToolTip::add(historyButton, i18n("Show/hide history"));
      historyButton->setToggleButton(true);
      bottomLayout->addWidget(historyButton);
      keypadButton = new QPushButton(i18n("Keypad"), centralWidget());
      QToolTip::add(keypadButton, i18n("Show/hide keypad"));
      keypadButton->setToggleButton(true);
      bottomLayout->addWidget(keypadButton);
      bottomLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
      mainLayout->addLayout(bottomLayout);

      connect(historyButton, SIGNAL(toggled(bool)), this, SLOT(toggleHistory(bool)));
      connect(keypadButton, SIGNAL(toggled(bool)), this, SLOT(toggleKeypad(bool)));
      connect(kp0, SIGNAL(clicked()), this, SLOT(insertKP0()));
      connect(kp1, SIGNAL(clicked()), this, SLOT(insertKP1()));
      connect(kp2, SIGNAL(clicked()), this, SLOT(insertKP2()));
      connect(kp3, SIGNAL(clicked()), this, SLOT(insertKP3()));
      connect(kp4, SIGNAL(clicked()), this, SLOT(insertKP4()));
      connect(kp5, SIGNAL(clicked()), this, SLOT(insertKP5()));
      connect(kp6, SIGNAL(clicked()), this, SLOT(insertKP6()));
      connect(kp7, SIGNAL(clicked()), this, SLOT(insertKP7()));
      connect(kp8, SIGNAL(clicked()), this, SLOT(insertKP8()));
      connect(kp9, SIGNAL(clicked()), this, SLOT(insertKP9()));
      connect(kpDot, SIGNAL(clicked()), this, SLOT(insertDot()));
      connect(kpExp, SIGNAL(clicked()), this, SLOT(insertExp()));
      connect(kpAns, SIGNAL(clicked()), this, SLOT(insertAns()));
      connect(kpEquals, SIGNAL(clicked()), this, SLOT(execute()));
      connect(kpPlus, SIGNAL(clicked()), this, SLOT(insertPlus()));
      connect(kpMinus, SIGNAL(clicked()), this, SLOT(insertMinus()));
      connect(kpTimes, SIGNAL(clicked()), this, SLOT(insertTimes()));
      connect(kpDivision, SIGNAL(clicked()), this, SLOT(insertDivision()));
      connect(kpDel, SIGNAL(clicked()), this, SLOT(expressionDel()));
      connect(kpClear, SIGNAL(clicked()), this, SLOT(clearExpression()));
      connect(kpSin, SIGNAL(clicked()), this, SLOT(insertSin()));
      connect(kpCos, SIGNAL(clicked()), this, SLOT(insertCos()));
      connect(kpTan, SIGNAL(clicked()), this, SLOT(insertTan()));
      connect(kpSqrt, SIGNAL(clicked()), this, SLOT(insertSqrt()));
      connect(kpLog, SIGNAL(clicked()), this, SLOT(insertLog()));
      connect(kpLn, SIGNAL(clicked()), this, SLOT(insertLn()));
      connect(kpRaise, SIGNAL(clicked()), this, SLOT(insertRaise()));
      connect(kpSquare, SIGNAL(clicked()), this, SLOT(insertSquare()));
      connect(kpFraction, SIGNAL(toggled(bool)), this, SLOT(setFractionMode(bool)));
      connect(kpExact, SIGNAL(toggled(bool)), this, SLOT(setExactMode(bool)));
      connect(kpAngleGroup, SIGNAL(clicked(int)), this, SLOT(kpSetAngleUnit(int)));
      connect(kpBaseCombo->listBox(), SIGNAL(selected(int)), this, SLOT(kpSetBaseSelected(int)));
      connect(kpBaseCombo, SIGNAL(activated(int)), this, SLOT(kpSetBase(int)));
      connect(kpNumericCombo, SIGNAL(activated(int)), this, SLOT(kpSetNumericalMode(int)));
      //connect(kpMod, SIGNAL(clicked()), this, SLOT(insertMod()));
      connect(kpFactorial, SIGNAL(clicked()), this, SLOT(insertFactorial()));
      connect(expressionEdit, SIGNAL(returnPressed()), this, SLOT(execute()));
      connect(expressionEdit, SIGNAL(textChanged(const QString&)), this, SLOT(onExpressionChanged()));
      connect(storeButton, SIGNAL(clicked()), this, SLOT(storeResult()));
      connect(executeButton, SIGNAL(clicked()), this, SLOT(execute()));
      connect(convertButton, SIGNAL(clicked()), this, SLOT(convertToUnitExpression()));
      connect(functionsButton, SIGNAL(clicked()), this, SLOT(manageFunctions()));
      connect(expressionEdit, SIGNAL(cursorMoved()), this, SLOT(displayParseStatus()));
      connect(expressionEdit->qalculateCompletionBox, SIGNAL(hidden()), statusLabel_l, SLOT(update()));

      //tab order
      setTabOrder(expressionEdit, resultLabel);
      setTabOrder(resultLabel, historyBrowser);
      setTabOrder(historyBrowser, keypadButton);
      setTabOrder(keypadButton, historyButton);

      if(show_keypad) {
            bottomLine->hide();
            keypadButton->setOn(true);
            mainStack->raiseWidget(0);
            mainStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum, false);
            resultLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, false);
      } else if(show_history) {
            bottomLine->hide();
            historyButton->setOn(true);
            mainStack->raiseWidget(1);
            mainStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, false);
            resultLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum, false);
      } else {
            mainStack->hide();
            mainStack->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum, false);
            resultLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, false);
      }
      
      /*if(!initial_history.isEmpty() && !initial_history.startsWith("-----------------------")) {
            initial_history.prepend("-----------------------<br>");
      }*/
      historyBrowser->setText(initial_history);
      initial_history = "";

      if(use_custom_result_font) {
            QFont new_font(resultLabel->font());
            new_font.fromString(custom_result_font);
            resultLabel->setFont(new_font);
      } else {
            resultLabel->unsetFont();
      }
      if(use_custom_expression_font) {
            QFont new_font(expressionEdit->font());
            new_font.fromString(custom_expression_font);
            expressionEdit->setFont(new_font);
      } else {
            expressionEdit->unsetFont();
      }
      updateStatusLabelFonts();
      
      set_unicode_buttons();

      setupActions();

      update_status_text();

      bottomLine->setMinimumWidth(1000);

      createGUI("qalculate_kdeui.rc");
      
      menuBar()->sizeHint();
      int h = menuBar()->height();
      int w = 300;
      while(menuBar()->heightForWidth(w) > h && w < 1000) {
            w += 10;
      }
      if(w >= 1000) {
            bottomLine->setMinimumWidth(0);
            w = 0;
      } else {
            bottomLine->setMinimumWidth(w - 22);
      }

      if(!isShown()) adjustSize();
      setAutoSaveSettings();
      
      if(show_keypad) {
            resize(minimumSizeHint());
      } else if(show_history) {
            resize(QSize(10, height()).expandedTo(minimumSizeHint()));
      } else {
            resize(QSize(width(), 10).expandedTo(minimumSizeHint()));
      }

      menu_functions = (QPopupMenu*) factory()->container("functions", this);
      menu_variables = (QPopupMenu*) factory()->container("variables", this);
      menu_units = (QPopupMenu*) factory()->container("units", this);
      menu_to_unit = (QPopupMenu*) factory()->container("convert_to_unit", this);
      menu_set_prefix = (QPopupMenu*) factory()->container("set_prefix", this);
      menu_modes = (QPopupMenu*) factory()->container("modes", this);
      
      QObject::connect(menu_modes, SIGNAL(activated(int)), this, SLOT(onModesMenuItemActivated(int)));
      for(size_t i = 0; i < modes.size(); i++) {
            menu_modes->insertItem(modes[i].name, -1, i);
      }

      QObject::connect(menu_functions, SIGNAL(activated(int)), this, SLOT(onFunctionMenuItemActivated(int)));
      QObject::connect(menu_variables, SIGNAL(activated(int)), this, SLOT(onVariableMenuItemActivated(int)));
      QObject::connect(menu_units, SIGNAL(activated(int)), this, SLOT(onUnitMenuItemActivated(int)));
      QObject::connect(menu_to_unit, SIGNAL(activated(int)), this, SLOT(onConvertToUnitMenuItemActivated(int)));
      QObject::connect(menu_set_prefix, SIGNAL(activated(int)), this, SLOT(onSetPrefixMenuItemActivated(int)));
      
}

KQalculate::~KQalculate() {}

void KQalculate::updateStatusLabelFonts() {
      if(use_custom_status_font) {
            QFont new_font(statusLabel_l->font());
            new_font.fromString(custom_status_font);
            statusLabel_l->setFont(new_font);
            new_font.setPointSizeFloat(new_font.pointSizeFloat() / 1.2);
            statusLabel_r->setFont(new_font);
      } else {
            statusLabel_l->unsetFont();
            statusLabel_r->unsetFont();
            QFont new_font = statusLabel_l->font();
            new_font.setPointSizeFloat(new_font.pointSizeFloat() / 1.2);
            statusLabel_l->setFont(new_font);
            new_font = statusLabel_r->font();
            new_font.setPointSizeFloat(new_font.pointSizeFloat() / 1.44);
            statusLabel_r->setFont(new_font);
      }
}

void KQalculate::fontChange(const QFont &old_font) {
      updateStatusLabelFonts();
      functionsButton->unsetFont();
      QFont fb_font(functionsButton->font());
      fb_font.setItalic(true);
      functionsButton->setFont(fb_font);
      kpSquare->setMarkup(i18n("x<sup>2</sup>"));
      kpRaise->setMarkup(i18n("x<sup>y</sup>"));
      result_display_updated();
      KMainWindow::fontChange(old_font);
}

void KQalculate::showSystemTrayIcon(bool do_show) {
      if(do_show && !trayicon) {
            trayicon = new KSystemTray(this);
            QObject::connect(trayicon, SIGNAL(quitSelected()), qApp, SLOT(quit()));
#if KDE_VERSION_MAJOR < 4 && KDE_VERSION_MINOR < 2    
            trayicon->setPixmap(loadSystrayIcon(PACKAGE));
#else
            trayicon->setPixmap(trayicon->loadIcon(PACKAGE));
#endif
            QToolTip::add(trayicon, i18n("Qalculate! - Scientific Calculator"));
      }
      if(do_show) trayicon->show();
      else if(trayicon) trayicon->hide();
      
}

#define SET_TOGGLE_ACTION(action, value)  action->blockSignals(true); action->setChecked(value); action->blockSignals(false);
#define SET_TOGGLE_ACTION_ON(action)      action->blockSignals(true); action->setChecked(true); action->blockSignals(false);

void KQalculate::setupActions() {

      ActionNewVariable = new KAction(i18n("Variable"), "filenew", 0, this, SLOT(newVariable()), actionCollection(), "new_variable");
      ActionNewMatrix = new KAction(i18n("Matrix"), "filenew", 0, this, SLOT(newMatrix()), actionCollection(), "new_matrix");
      ActionNewVector = new KAction(i18n("Vector"), "filenew", 0, this, SLOT(newVector()), actionCollection(), "new_vector");
      ActionNewUnknownVariable = new KAction(i18n("Unknown Variable"), "filenew", 0, this, SLOT(newUnknownVariable()), actionCollection(), "new_unknown_variable");
      ActionNewFunction = new KAction(i18n("Function"), "filenew", 0, this, SLOT(newFunction()), actionCollection(), "new_function");
      ActionNewDataSet = new KAction(i18n("Data Set"), "filenew", 0, this, SLOT(newDataSet()), actionCollection(), "new_data_set");
      ActionNewUnit = new KAction(i18n("Unit"), "filenew", 0, this, SLOT(newUnit()), actionCollection(), "new_unit");
      ActionImportCSVFile = new KAction(i18n("Import CSV File..."), "fileimport", 0, this, SLOT(importCSVFile()), actionCollection(), "import_csv_file");
      ActionExportCSVFile = new KAction(i18n("Export CSV File..."), "filexport", 0, this, SLOT(exportCSVFile()), actionCollection(), "export_csv_file");
      ActionStoreResult = new KAction(i18n("Store Result..."), "filesave", CTRL+Key_S, this, SLOT(storeResult()), actionCollection(), "store_result");
      ActionSaveAsImage = new KAction(i18n("Save Result Image..."), "filesave", 0, this, SLOT(saveAsImage()), actionCollection(), "save_as_image");
      ActionSaveDefinitions = new KAction(i18n("Save Definitions"), "filesave", 0, this, SLOT(saveDefinitions()), actionCollection(), "save_definitions");
      ActionUpdateExchangeRates = new KAction(i18n("Update Exchange Rates"), "reload", 0, this, SLOT(updateExchangeRates()), actionCollection(), "update_exchange_rates");
      ActionPlotFunctionsData = new KAction(i18n("Plot Functions/Data"), 0, this, SLOT(plotFunctionsData()), actionCollection(), "plot_functions_data");
      ActionPlotFunctionsData->setEnabled(canplot);
      ActionConvertNumberBases = new KAction(i18n("Convert Number Bases"), CTRL+Key_B, this, SLOT(convertNumberBases()), actionCollection(), "convert_number_bases");
      ActionPeriodicTable = new KAction(i18n("Periodic Table"), 0, this, SLOT(periodicTable()), actionCollection(), "periodic_table");
      if(close_to_systray) {
            ActionClose = KStdAction::close(this, SLOT(close()), actionCollection());
      } else {
            ActionClose = NULL;
      }
      ActionQuit = KStdAction::quit(qApp, SLOT(quit()), actionCollection());
      ActionManageVariables = new KAction(i18n("Manage Variables"), Key_F2, this, SLOT(manageVariables()), actionCollection(), "manage_variables");
      ActionManageFunctions = new KAction(i18n("Manage Functions"), Key_F3, this, SLOT(manageFunctions()), actionCollection(), "manage_functions");
      ActionManageUnits = new KAction(i18n("Manage Units"), Key_F4, this, SLOT(manageUnits()), actionCollection(), "manage_units");
      ActionManageDataSets = new KAction(i18n("Manage Data Sets"), 0, this, SLOT(manageDataSets()), actionCollection(), "manage_data_sets");
      ActionFactorize = new KAction(i18n("Factorize"), 0, this, SLOT(factorize()), actionCollection(), "factorize");
      ActionSimplify = new KAction(i18n("Simplify"), 0, this, SLOT(simplify()), actionCollection(), "simplify");
      ActionSetUnknowns = new KAction(i18n("Set Unknowns..."), 0, this, SLOT(setUnknowns()), actionCollection(), "set_unknowns");
      ActionConvertToUnitExpression = new KAction(i18n("Convert To Unit Expression..."), CTRL+Key_T, this, SLOT(convertToUnitExpression()), actionCollection(), "convert_to_unit_expression");
      ActionConvertToBaseUnits = new KAction(i18n("Convert To Base Units"), 0, this, SLOT(convertToBaseUnits()), actionCollection(), "convert_to_base_units");
      ActionConvertToBestUnit = new KAction(i18n("Convert To Best Unit"), 0, this, SLOT(convertToBestUnit()), actionCollection(), "convert_to_best_unit");
      ActionInsertMatrix = new KAction(i18n("Insert Matrix..."), 0, this, SLOT(insertMatrix()), actionCollection(), "insert_matrix");
      ActionInsertVector = new KAction(i18n("Insert Vector..."), 0, this, SLOT(insertVector()), actionCollection(), "insert_vector");
      ActionCopyResult = new KAction(i18n("Copy Result"), "editcopy", Key_F5, this, SLOT(copyResult()), actionCollection(), "copy_result");
      ActionClearHistory = new KAction(i18n("Clear History"), "editclear", 0, this, SLOT(clearHistory()), actionCollection(), "clear_history");
      ActionPreferences = new KAction(i18n("Configure Qalculate!"), "configure", 0, this, SLOT(preferences()), actionCollection(), "preferences");
      KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()), actionCollection(), "keybindings");
      ActionNumberBaseBinary = new KRadioAction(i18n("Binary"), 0, this, SLOT(numberBaseBinary()), actionCollection(), "number_base_binary");
      ActionNumberBaseBinary->setExclusiveGroup("group_number_base");
      ActionNumberBaseOctal = new KRadioAction(i18n("Octal"), 0, this, SLOT(numberBaseOctal()), actionCollection(), "number_base_octal");
      ActionNumberBaseOctal->setExclusiveGroup("group_number_base");
      ActionNumberBaseDecimal = new KRadioAction(i18n("Decimal"), 0, this, SLOT(numberBaseDecimal()), actionCollection(), "number_base_decimal");
      ActionNumberBaseDecimal->setExclusiveGroup("group_number_base");
      ActionNumberBaseHexadecimal = new KRadioAction(i18n("Hexadecimal"), 0, this, SLOT(numberBaseHexadecimal()), actionCollection(), "number_base_hexadecimal");
      ActionNumberBaseHexadecimal->setExclusiveGroup("group_number_base");
      ActionNumberBaseOther = new KAction(i18n("Set Other Base..."), 0, this, SLOT(numberBaseOther()), actionCollection(), "number_base_other");
      ActionNumberBaseSexagesimal = new KRadioAction(i18n("Sexagesimal"), 0, this, SLOT(numberBaseSexagesimal()), actionCollection(), "number_base_sexagesimal");
      ActionNumberBaseSexagesimal->setExclusiveGroup("group_number_base");
      ActionNumberBaseTimeFormat = new KRadioAction(i18n("Time Format"), 0, this, SLOT(numberBaseTimeFormat()), actionCollection(), "number_base_time_format");
      ActionNumberBaseTimeFormat->setExclusiveGroup("group_number_base");
      ActionNumberBaseRomanNumerals = new KRadioAction(i18n("Roman Numerals"), 0, this, SLOT(numberBaseRomanNumerals()), actionCollection(), "number_base_roman_numerals");
      ActionNumberBaseRomanNumerals->setExclusiveGroup("group_number_base");
      ActionSetBaseInExpression = new KAction(i18n("Set Base In Expression..."), 0, this, SLOT(setBaseInExpression()), actionCollection(), "set_base_in_expression");
      ActionNumericalDisplayNormal = new KRadioAction(i18n("Normal"), 0, this, SLOT(numericalDisplayNormal()), actionCollection(), "numerical_display_normal");
      ActionNumericalDisplayNormal->setExclusiveGroup("group_numberical_display");
      ActionNumericalDisplayScientific = new KRadioAction(i18n("Scientific"), 0, this, SLOT(numericalDisplayScientific()), actionCollection(), "numerical_display_scientific");
      ActionNumericalDisplayScientific->setExclusiveGroup("group_numberical_display");
      ActionNumericalDisplayPurelyScientific = new KRadioAction(i18n("Purely Scientific"), 0, this, SLOT(numericalDisplayPurelyScientific()), actionCollection(), "numerical_display_purely_scientific");
      ActionNumericalDisplayPurelyScientific->setExclusiveGroup("group_numberical_display");
      ActionNumericalDisplaySimple = new KRadioAction(i18n("Simple"), 0, this, SLOT(numericalDisplaySimple()), actionCollection(), "numerical_display_simple");
      ActionNumericalDisplaySimple->setExclusiveGroup("group_numberical_display");
      ActionIndicateInfiniteSeries = new KToggleAction(i18n("Indicate Infinite Series"), 0, actionCollection(), "indicate_infinite_series");
      QObject::connect(ActionIndicateInfiniteSeries, SIGNAL(toggled(bool)), this, SLOT(indicateInfiniteSeries(bool)));
      ActionShowEndingZeroes = new KToggleAction(i18n("Show Ending Zeroes"), 0, actionCollection(), "show_ending_zeroes");
      QObject::connect(ActionShowEndingZeroes, SIGNAL(toggled(bool)), this, SLOT(showEndingZeroes(bool)));
      ActionRoundHalfwayNumbersToEven = new KToggleAction(i18n("Round Halfway Numbers To Even"), 0, actionCollection(), "round_halfway_numbers_to_even");
      QObject::connect(ActionRoundHalfwayNumbersToEven, SIGNAL(toggled(bool)), this, SLOT(roundHalfwayNumbersToEven(bool)));
      ActionFractionalDisplayDecimal = new KRadioAction(i18n("Decimal"), 0, this, SLOT(fractionalDisplayDecimal()), actionCollection(), "fractional_display_decimal");
      ActionFractionalDisplayDecimal->setExclusiveGroup("group_fractional_display");
      ActionFractionalDisplayDecimalTryExact = new KRadioAction(i18n("Decimal (Try Exact)"), 0, this, SLOT(fractionalDisplayDecimalTryExact()), actionCollection(), "fractional_display_decimal_try_exact");
      ActionFractionalDisplayDecimalTryExact->setExclusiveGroup("group_fractional_display");
      ActionFractionalDisplayFraction = new KRadioAction(i18n("Fraction"), 0, this, SLOT(fractionalDisplayFraction()), actionCollection(), "fractional_display_fraction");
      ActionFractionalDisplayFraction->setExclusiveGroup("group_fractional_display");
      ActionFractionalDisplayCombined = new KRadioAction(i18n("Combined"), 0, this, SLOT(fractionalDisplayCombined()), actionCollection(), "fractional_display_combined");
      ActionFractionalDisplayCombined->setExclusiveGroup("group_fractional_display");
      ActionEnablePrefixes = new KToggleAction(i18n("Enable Prefixes"), 0, actionCollection(), "enable_prefixes");
      QObject::connect(ActionEnablePrefixes, SIGNAL(toggled(bool)), this, SLOT(enablePrefixes(bool)));
      ActionEnableUseOfAllPrefixes = new KToggleAction(i18n("Enable Use Of All SI Prefixes"), 0, actionCollection(), "enable_use_of_all_prefixes");
      QObject::connect(ActionEnableUseOfAllPrefixes, SIGNAL(toggled(bool)), this, SLOT(enableUseOfAllPrefixes(bool)));
      ActionEnableDenominatorPrefixes = new KToggleAction(i18n("Enable Denominator Prefixes"), 0, actionCollection(), "enable_denominator_prefixes");
      QObject::connect(ActionEnableDenominatorPrefixes, SIGNAL(toggled(bool)), this, SLOT(enableDenominatorPrefixes(bool)));
      ActionPlaceUnitsSeparately = new KToggleAction(i18n("Place Units Separately"), 0, actionCollection(), "place_units_separately");
      QObject::connect(ActionPlaceUnitsSeparately, SIGNAL(toggled(bool)), this, SLOT(placeUnitsSeparately(bool)));
      ActionAutoNoConversion = new KRadioAction(i18n("No Automatic Conversion"), 0, this, SLOT(autoNoConversion()), actionCollection(), "auto_no_conversion");
      ActionAutoNoConversion->setExclusiveGroup("group_auto_conversion");
      ActionAutoConvertToBaseUnits = new KRadioAction(i18n("Convert To Base Units"), 0, this, SLOT(autoConvertToBaseUnits()), actionCollection(), "auto_convert_to_base_units");
      ActionAutoConvertToBaseUnits->setExclusiveGroup("group_auto_conversion");
      ActionAutoConvertToBestUnit = new KRadioAction(i18n("Convert To Best Unit"), 0, this, SLOT(autoConvertToBestUnit()), actionCollection(), "auto_convert_to_best_unit");
      ActionAutoConvertToBestUnit->setExclusiveGroup("group_auto_conversion");
      ActionAngleUnitDegrees = new KRadioAction(i18n("Degrees"), 0, this, SLOT(angleUnitDegrees()), actionCollection(), "angle_unit_degrees");
      ActionAngleUnitDegrees->setExclusiveGroup("group_angle_unit");
      ActionAngleUnitRadians = new KRadioAction(i18n("Radians"), 0, this, SLOT(angleUnitRadians()), actionCollection(), "angle_unit_radians");
      ActionAngleUnitRadians->setExclusiveGroup("group_angle_unit");
      ActionAngleUnitGradians = new KRadioAction(i18n("Gradians"), 0, this, SLOT(angleUnitGradians()), actionCollection(), "angle_unit_gradians");
      ActionAngleUnitGradians->setExclusiveGroup("group_angle_unit");
      ActionAngleUnitNone = new KRadioAction(i18n("None"), 0, this, SLOT(angleUnitNone()), actionCollection(), "angle_unit_none");
      ActionAngleUnitNone->setExclusiveGroup("group_angle_unit");
      ActionAbbreviateNames = new KToggleAction(i18n("Abbreviate Names"), 0, actionCollection(), "abbreviate_names");
      QObject::connect(ActionAbbreviateNames, SIGNAL(toggled(bool)), this, SLOT(abbreviateNames(bool)));
      ActionEnableVariables = new KToggleAction(i18n("Enable Variables"), 0, actionCollection(), "enable_variables");
      QObject::connect(ActionEnableVariables, SIGNAL(toggled(bool)), this, SLOT(enableVariables(bool)));
      ActionEnableFunctions = new KToggleAction(i18n("Enable Functions"), 0, actionCollection(), "enable_functions");
      QObject::connect(ActionEnableFunctions, SIGNAL(toggled(bool)), this, SLOT(enableFunctions(bool)));
      ActionEnableUnits = new KToggleAction(i18n("Enable Units"), 0, actionCollection(), "enable_units");
      QObject::connect(ActionEnableUnits, SIGNAL(toggled(bool)), this, SLOT(enableUnits(bool)));
      ActionEnableUnknowns = new KToggleAction(i18n("Enable Unknowns"), 0, actionCollection(), "enable_unknowns");
      QObject::connect(ActionEnableUnknowns, SIGNAL(toggled(bool)), this, SLOT(enableUnknowns(bool)));
      ActionCalculateVariables = new KToggleAction(i18n("Calculate Variables"), 0, actionCollection(), "calculate_variables");
      QObject::connect(ActionCalculateVariables, SIGNAL(toggled(bool)), this, SLOT(calculateVariables(bool)));
      ActionAllowComplexResult = new KToggleAction(i18n("Allow Complex Result"), 0, actionCollection(), "allow_complex_result");
      QObject::connect(ActionAllowComplexResult, SIGNAL(toggled(bool)), this, SLOT(allowComplexResult(bool)));
      ActionAllowInfiniteResult = new KToggleAction(i18n("Allow Infinite Result"), 0, actionCollection(), "allow_infinite_result");
      QObject::connect(ActionAllowInfiniteResult, SIGNAL(toggled(bool)), this, SLOT(allowInfiniteResult(bool)));
      ActionApproximationTryExact = new KRadioAction(i18n("Try Exact"), 0, this, SLOT(approximationTryExact()), actionCollection(), "approximation_try_exact");
      ActionApproximationTryExact->setExclusiveGroup("group_approximation");
      ActionApproximationAlwaysExact = new KRadioAction(i18n("Always Exact"), 0, this, SLOT(approximationAlwaysExact()), actionCollection(), "approximation_always_exact");
      ActionApproximationAlwaysExact->setExclusiveGroup("group_approximation");
      ActionApproximationApproximate = new KRadioAction(i18n("Approximate"), 0, this, SLOT(approximationApproximate()), actionCollection(), "approximation_approximate");
      ActionApproximationApproximate->setExclusiveGroup("group_approximation");
      ActionAssumptionTypeUnknown = new KRadioAction(i18n("Unknown"), 0, this, SLOT(assumptionTypeUnknown()), actionCollection(), "assumption_type_unknown");
      ActionAssumptionTypeUnknown->setExclusiveGroup("group_assumption_type");
      ActionAssumptionTypeNonMatrix = new KRadioAction(i18n("Not Matrix"), 0, this, SLOT(assumptionTypeNonMatrix()), actionCollection(), "assumption_type_nonmatrix");
      ActionAssumptionTypeNonMatrix->setExclusiveGroup("group_assumption_type");
      ActionAssumptionTypeNumber = new KRadioAction(i18n("Number"), 0, this, SLOT(assumptionTypeNumber()), actionCollection(), "assumption_type_number");
      ActionAssumptionTypeNumber->setExclusiveGroup("group_assumption_type");
      ActionAssumptionTypeComplex = new KRadioAction(i18n("Complex"), 0, this, SLOT(assumptionTypeComplex()), actionCollection(), "assumption_type_complex");
      ActionAssumptionTypeComplex->setExclusiveGroup("group_assumption_type");
      ActionAssumptionTypeReal = new KRadioAction(i18n("Real"), 0, this, SLOT(assumptionTypeReal()), actionCollection(), "assumption_type_real");
      ActionAssumptionTypeReal->setExclusiveGroup("group_assumption_type");
      ActionAssumptionTypeRational = new KRadioAction(i18n("Rational"), 0, this, SLOT(assumptionTypeRational()), actionCollection(), "assumption_type_rational");
      ActionAssumptionTypeRational->setExclusiveGroup("group_assumption_type");
      ActionAssumptionTypeInteger = new KRadioAction(i18n("Integer"), 0, this, SLOT(assumptionTypeInteger()), actionCollection(), "assumption_type_integer");
      ActionAssumptionTypeInteger->setExclusiveGroup("group_assumption_type");
      ActionAssumptionSignUnknown = new KRadioAction(i18n("Unknown"), 0, this, SLOT(assumptionSignUnknown()), actionCollection(), "assumption_sign_unknown");
      ActionAssumptionSignUnknown->setExclusiveGroup("group_assumption_sign");
      ActionAssumptionSignNonZero = new KRadioAction(i18n("Non-Zero"), 0, this, SLOT(assumptionSignNonZero()), actionCollection(), "assumption_sign_non_zero");
      ActionAssumptionSignNonZero->setExclusiveGroup("group_assumption_sign");
      ActionAssumptionSignPositive = new KRadioAction(i18n("Positive"), 0, this, SLOT(assumptionSignPositive()), actionCollection(), "assumption_sign_positive");
      ActionAssumptionSignPositive->setExclusiveGroup("group_assumption_sign");
      ActionAssumptionSignNonNegative = new KRadioAction(i18n("Non-Negative"), 0, this, SLOT(assumptionSignNonNegative()), actionCollection(), "assumption_sign_non_negative");
      ActionAssumptionSignNonNegative->setExclusiveGroup("group_assumption_sign");
      ActionAssumptionSignNegative = new KRadioAction(i18n("Negative"), 0, this, SLOT(assumptionSignNegative()), actionCollection(), "assumption_sign_negative");
      ActionAssumptionSignNegative->setExclusiveGroup("group_assumption_sign");
      ActionAssumptionSignNonPositive = new KRadioAction(i18n("Non-Positive"), 0, this, SLOT(assumptionSignNonPositive()), actionCollection(), "assumption_sign_non_positive");
      ActionAssumptionSignNonPositive->setExclusiveGroup("group_assumption_sign");
      ActionNonZeroDenominators = new KToggleAction(i18n("Non-Zero Denominators"), 0, actionCollection(), "non_zero_denominators");
      QObject::connect(ActionNonZeroDenominators, SIGNAL(toggled(bool)), this, SLOT(nonZeroDenominators(bool)));
      ActionWarnAboutDenominatorsAssumedNonZero = new KToggleAction(i18n("Warn About Denominators Assumed Non-Zero"), 0, actionCollection(), "warn_about_denominators_assumed_nonzero");
      QObject::connect(ActionWarnAboutDenominatorsAssumedNonZero, SIGNAL(toggled(bool)), this, SLOT(warnAboutDenominatorsAssumedNonZero(bool)));
      ActionAlgebraicModeSimplify = new KRadioAction(i18n("Simplify"), 0, this, SLOT(algebraicModeSimplify()), actionCollection(), "algebraic_mode_simplify");
      ActionAlgebraicModeSimplify->setExclusiveGroup("group_alebraic_mode");
      ActionAlgebraicModeFactorize = new KRadioAction(i18n("Factorize"), 0, this, SLOT(algebraicModeFactorize()), actionCollection(), "algebraic_mode_factorize");
      ActionAlgebraicModeFactorize->setExclusiveGroup("group_alebraic_mode");
      ActionAlgebraicModeNone = new KRadioAction(i18n("None"), 0, this, SLOT(algebraicModeNone()), actionCollection(), "algebraic_mode_none");
      ActionAlgebraicModeNone->setExclusiveGroup("group_alebraic_mode");
      ActionReadPrecision = new KToggleAction(i18n("Read Precision"), 0, actionCollection(), "read_precision");
      QObject::connect(ActionReadPrecision, SIGNAL(toggled(bool)), this, SLOT(readPrecision(bool)));
      ActionLimitImplicitMultiplication = new KToggleAction(i18n("Limit Implicit Multiplication"), 0, actionCollection(), "limit_implicit_multiplication");
      QObject::connect(ActionLimitImplicitMultiplication, SIGNAL(toggled(bool)), this, SLOT(limitImplicitMultiplication(bool)));
      ActionRPNMode = new KToggleAction(i18n("RPN Mode"), 0, actionCollection(), "rpn_mode");
      QObject::connect(ActionRPNMode, SIGNAL(toggled(bool)), this, SLOT(rpnMode(bool)));
      ActionPrecision = new KAction(i18n("Precision"), 0, this, SLOT(precision()), actionCollection(), "precision");
      ActionDecimals = new KAction(i18n("Decimals"), 0, this, SLOT(decimals()), actionCollection(), "decimals");
      ActionSaveModeAs = new KAction(i18n("Save Mode..."), "filesave", 0, this, SLOT(saveModeAs()), actionCollection(), "save_mode_as");
      ActionDeleteMode = new KAction(i18n("Delete Mode..."), "editdelete", 0, this, SLOT(deleteMode()), actionCollection(), "delete_mode");
      ActionDeleteMode->setEnabled(modes.size() > 2);
      ActionSaveMode = new KAction(i18n("Save Default Mode"), "filesave", 0, this, SLOT(saveMode()), actionCollection(), "save_mode");
      
      setModeActions();

}
void KQalculate::setAssumptionsMenu() {
      switch(CALCULATOR->defaultAssumptions()->sign()) {
            case ASSUMPTION_SIGN_POSITIVE: {SET_TOGGLE_ACTION_ON(ActionAssumptionSignPositive); break;}
            case ASSUMPTION_SIGN_NONPOSITIVE: {SET_TOGGLE_ACTION_ON(ActionAssumptionSignNonPositive); break;}
            case ASSUMPTION_SIGN_NEGATIVE: {SET_TOGGLE_ACTION_ON(ActionAssumptionSignNegative); break;}
            case ASSUMPTION_SIGN_NONNEGATIVE: {SET_TOGGLE_ACTION_ON(ActionAssumptionSignNonNegative); break;}
            case ASSUMPTION_SIGN_NONZERO: {SET_TOGGLE_ACTION_ON(ActionAssumptionSignNonZero); break;}
            default: {SET_TOGGLE_ACTION_ON(ActionAssumptionSignUnknown); }
      }
      switch(CALCULATOR->defaultAssumptions()->type()) {
            case ASSUMPTION_TYPE_INTEGER: {SET_TOGGLE_ACTION_ON(ActionAssumptionTypeInteger); break;}
            case ASSUMPTION_TYPE_RATIONAL: {SET_TOGGLE_ACTION_ON(ActionAssumptionTypeRational); break;}
            case ASSUMPTION_TYPE_COMPLEX: {SET_TOGGLE_ACTION_ON(ActionAssumptionTypeComplex); break;}
            case ASSUMPTION_TYPE_NUMBER: {SET_TOGGLE_ACTION_ON(ActionAssumptionTypeNumber); break;}
            case ASSUMPTION_TYPE_REAL: {SET_TOGGLE_ACTION_ON(ActionAssumptionTypeReal); break;}
            case ASSUMPTION_TYPE_NONMATRIX: {SET_TOGGLE_ACTION_ON(ActionAssumptionTypeNonMatrix); break;}
            default: {SET_TOGGLE_ACTION_ON(ActionAssumptionTypeUnknown); }
      }
}
void KQalculate::setModeActions() {
      
      SET_TOGGLE_ACTION(ActionAllowComplexResult, evalops.allow_complex)
      SET_TOGGLE_ACTION(ActionAllowInfiniteResult, evalops.allow_infinite)
      SET_TOGGLE_ACTION(ActionEnableVariables, evalops.parse_options.variables_enabled)
      SET_TOGGLE_ACTION(ActionEnableFunctions, evalops.parse_options.functions_enabled)
      SET_TOGGLE_ACTION(ActionEnableUnits, evalops.parse_options.units_enabled)
      SET_TOGGLE_ACTION(ActionEnableUnknowns, evalops.parse_options.unknowns_enabled)
      SET_TOGGLE_ACTION(ActionCalculateVariables, evalops.calculate_variables)
      SET_TOGGLE_ACTION(ActionReadPrecision, evalops.parse_options.read_precision != DONT_READ_PRECISION)
      SET_TOGGLE_ACTION(ActionLimitImplicitMultiplication, evalops.parse_options.limit_implicit_multiplication)
      SET_TOGGLE_ACTION(ActionRPNMode, evalops.parse_options.rpn)
      SET_TOGGLE_ACTION(ActionNonZeroDenominators, evalops.assume_denominators_nonzero)
      SET_TOGGLE_ACTION(ActionWarnAboutDenominatorsAssumedNonZero, evalops.warn_about_denominators_assumed_nonzero)
      SET_TOGGLE_ACTION(ActionAbbreviateNames, printops.abbreviate_names)
      SET_TOGGLE_ACTION(ActionIndicateInfiniteSeries, printops.indicate_infinite_series)
      SET_TOGGLE_ACTION(ActionShowEndingZeroes, printops.show_ending_zeroes)
      SET_TOGGLE_ACTION(ActionRoundHalfwayNumbersToEven, printops.round_halfway_to_even)
      SET_TOGGLE_ACTION(ActionEnablePrefixes, printops.use_unit_prefixes)
      SET_TOGGLE_ACTION(ActionEnableUseOfAllPrefixes, printops.use_all_prefixes)
      SET_TOGGLE_ACTION(ActionEnableDenominatorPrefixes, printops.use_denominator_prefix)
      SET_TOGGLE_ACTION(ActionPlaceUnitsSeparately, printops.place_units_separately)

      kpExact->blockSignals(true);
      switch(evalops.approximation) {
            case APPROXIMATION_EXACT: {
                  SET_TOGGLE_ACTION_ON(ActionApproximationAlwaysExact);
                  kpExact->setOn(true);
                  break;
            }
            case APPROXIMATION_TRY_EXACT: {
                  SET_TOGGLE_ACTION_ON(ActionApproximationTryExact);
                  kpExact->setOn(false);
                  break;
            }
            case APPROXIMATION_APPROXIMATE: {
                  SET_TOGGLE_ACTION_ON(ActionApproximationApproximate);
                  kpExact->setOn(false);
                  break;
            }
      }
      kpExact->blockSignals(false);
      switch(evalops.auto_post_conversion) {
            case POST_CONVERSION_BEST: {
                  SET_TOGGLE_ACTION_ON(ActionAutoConvertToBestUnit);
                  break;
            }
            case POST_CONVERSION_BASE: {
                  SET_TOGGLE_ACTION_ON(ActionAutoConvertToBaseUnits);
                  break;
            }
            default: {
                  SET_TOGGLE_ACTION_ON(ActionAutoNoConversion);
            }
      }
      kpAngleGroup->blockSignals(true);
      switch(evalops.parse_options.angle_unit) {
            case ANGLE_UNIT_DEGREES: {
                  SET_TOGGLE_ACTION_ON(ActionAngleUnitDegrees);
                  kpAngleGroup->setButton(0);
                  break;
            }
            case ANGLE_UNIT_RADIANS: {
                  SET_TOGGLE_ACTION_ON(ActionAngleUnitRadians);
                  kpAngleGroup->setButton(1);
                  break;
            }
            case ANGLE_UNIT_GRADIANS: {
                  SET_TOGGLE_ACTION_ON(ActionAngleUnitGradians);
                  kpAngleGroup->setButton(2);
                  break;
            }
            default: {
                  SET_TOGGLE_ACTION_ON(ActionAngleUnitNone);
                  kpAngleGroup->setButton(3);
            }
      }
      kpAngleGroup->blockSignals(false);

      kpBaseCombo->blockSignals(true);
      switch(printops.base) {
            case BASE_BINARY: {
                  SET_TOGGLE_ACTION_ON(ActionNumberBaseBinary);
                  kpBaseCombo->setCurrentItem(0);
                  break;
            }
            case BASE_OCTAL: {
                  SET_TOGGLE_ACTION_ON(ActionNumberBaseOctal);
                  kpBaseCombo->setCurrentItem(1);
                  break;
            }
            case BASE_DECIMAL: {
                  SET_TOGGLE_ACTION_ON(ActionNumberBaseDecimal);
                  kpBaseCombo->setCurrentItem(2);
                  break;
            }
            case BASE_HEXADECIMAL: {
                  SET_TOGGLE_ACTION_ON(ActionNumberBaseHexadecimal);
                  kpBaseCombo->setCurrentItem(3);
                  break;
            }
            case BASE_ROMAN_NUMERALS: {
                  SET_TOGGLE_ACTION_ON(ActionNumberBaseRomanNumerals);
                  kpBaseCombo->setCurrentItem(6);
                  break;
            }
            case BASE_SEXAGESIMAL: {
                  SET_TOGGLE_ACTION_ON(ActionNumberBaseSexagesimal);
                  kpBaseCombo->setCurrentItem(4);
                  break;
            }
            case BASE_TIME: {
                  SET_TOGGLE_ACTION_ON(ActionNumberBaseTimeFormat);
                  kpBaseCombo->setCurrentItem(5);
                  break;
            }
            default: {
                  kpBaseCombo->setCurrentItem(7);
            }
      }
      kpBaseCombo->blockSignals(false);

      kpNumericCombo->blockSignals(true);
      switch(printops.min_exp) {
            case EXP_PRECISION: {
                  SET_TOGGLE_ACTION_ON(ActionNumericalDisplayNormal);
                  kpNumericCombo->setCurrentItem(0);
                  break;
            }
            case EXP_SCIENTIFIC: {
                  SET_TOGGLE_ACTION_ON(ActionNumericalDisplayScientific);
                  kpNumericCombo->setCurrentItem(1);
                  break;
            }
            case EXP_PURE: {
                  SET_TOGGLE_ACTION_ON(ActionNumericalDisplayPurelyScientific);
                  kpNumericCombo->setCurrentItem(2);
                  break;
            }
            case EXP_NONE: {
                  SET_TOGGLE_ACTION_ON(ActionNumericalDisplaySimple);
                  kpNumericCombo->setCurrentItem(3);
                  break;
            }
      }
      kpNumericCombo->blockSignals(false);

      kpFraction->blockSignals(true);
      switch (printops.number_fraction_format) {
            case FRACTION_DECIMAL: {
                  SET_TOGGLE_ACTION_ON(ActionFractionalDisplayDecimal);
                  kpFraction->setOn(false);
                  break;
            }
            case FRACTION_DECIMAL_EXACT: {
                  SET_TOGGLE_ACTION_ON(ActionFractionalDisplayDecimalTryExact);
                  kpFraction->setOn(false);
                  break;
            }
            case FRACTION_COMBINED: {
                  SET_TOGGLE_ACTION_ON(ActionFractionalDisplayCombined);
                  kpFraction->setOn(true);
                  break;
            }
            case FRACTION_FRACTIONAL: {
                  SET_TOGGLE_ACTION_ON(ActionFractionalDisplayFraction);
                  kpFraction->setOn(true);
                  break;
            }
      }
      kpFraction->blockSignals(false);

      setAssumptionsMenu();
      switch(evalops.structuring) {
            case STRUCTURING_SIMPLIFY: {SET_TOGGLE_ACTION_ON(ActionAlgebraicModeSimplify); break;}
            case STRUCTURING_FACTORIZE: {SET_TOGGLE_ACTION_ON(ActionAlgebraicModeFactorize); break;}
            default: {SET_TOGGLE_ACTION_ON(ActionAlgebraicModeNone); }
      }
      
}

#define TEXT_TAGS             "<font size=6>"
#define TEXT_TAGS_END               "</font>"
#define TEXT_TAGS_SMALL             "<font size=5>"
#define TEXT_TAGS_SMALL_END         "</font>"
#define TEXT_TAGS_XSMALL            "<font size=4>"
#define TEXT_TAGS_XSMALL_END        "</font>"

#define STR_MARKUP_ADD_SMALL(str, str_add)                  if(ips.power_depth > 0) {str += TEXT_TAGS "<sup>"; str += str_add; str += "</sup>" TEXT_TAGS_END;} else {str += TEXT_TAGS_SMALL; str += str_add; str += TEXT_TAGS_SMALL_END;}

#define STR_MARKUP_ADD(str, str_add)                        if(ips.power_depth > 0) {str += TEXT_TAGS "<sup>"; str += str_add; str += "</sup>" TEXT_TAGS_END;} else {str += str_add;}

#define STR_MARKUP_PREPEND(str, str_add)              QString str_prepend; if(ips.power_depth > 0) {str_prepend += TEXT_TAGS "<sup>"; str_prepend += str_add; str_prepend += "</sup>" TEXT_TAGS_END;} else {str_prepend += str_add;} str.prepend(str_prepend);

#define STR_MARKUP_BEGIN(str)                               if(ips.power_depth > 0) {str += TEXT_TAGS "<sup>";}
#define STR_MARKUP_END(str)                           if(ips.power_depth > 0) {str +="</sup>" TEXT_TAGS_END;}

#define STR_MARKUP_BEGIN_SMALL(str)                         if(ips.power_depth > 0) {str += TEXT_TAGS_SMALL "<sup>";} else {str += TEXT_TAGS_SMALL;}
#define STR_MARKUP_END_SMALL(str)                     if(ips.power_depth > 0) {str +="</sup>" TEXT_TAGS_SMALL_END;} else {str += TEXT_TAGS_SMALL_END;}

#define STR_MARKUP_BEGIN_CURSIVE(str)                       if(ips.power_depth > 0) {str += TEXT_TAGS "<i><sup>";} else {str += "<i>";}
#define STR_MARKUP_END_CURSIVE(str)                         if(ips.power_depth > 0) {str +="</sup></i>" TEXT_TAGS_END;} else {str += "</i>";}

QString draw_structure(MathStructure &m, const QFont &font, const QColorGroup &cg, PrintOptions po = default_print_options, InternalPrintStruct ips = top_ips, bool in_matrix = false) {

      if(ips.depth == 0 && po.is_approximate) *po.is_approximate = false;

      QString mstr;
      
      InternalPrintStruct ips_n = ips;
      if(m.isApproximate()) ips_n.parent_approximate = true;
      if(m.precision() > 0 && (ips_n.parent_precision < 1 || m.precision() < ips_n.parent_precision)) ips_n.parent_precision = m.precision();
      switch(m.type()) {
            case STRUCT_NUMBER: {
                  string exp = "";
                  bool exp_minus;
                  ips_n.exp = &exp;
                  ips_n.exp_minus = &exp_minus;
                  STR_MARKUP_BEGIN(mstr);
                  mstr += m.number().print(po, ips_n).c_str();
                  if(!exp.empty()) {
                        if(po.lower_case_e) {
                              mstr += "e";
                        } else {
                              STR_MARKUP_ADD_SMALL(mstr, "E");
                        }
                        if(exp_minus) {
                              mstr += "-";
                        }
                        mstr += exp.c_str();
                  }
                  if(po.base != BASE_DECIMAL && po.base != BASE_HEXADECIMAL && po.base > 0 && po.base <= 36) {
                        if(ips.power_depth == 0) {
                              mstr += "<sub>";
                              mstr += QString::number(po.base);
                              mstr += "</sub>";
                        } else {
                              mstr += TEXT_TAGS_SMALL "<sup>"; 
                              mstr += QString::number(po.base); 
                              mstr += "</sup>" TEXT_TAGS_SMALL_END;
                        }
                  }
                  STR_MARKUP_END(mstr);
                  break;
            }
            case STRUCT_SYMBOLIC: {
                  result_parts.push_back(m);
                  mstr = "<a name=\"";
                  mstr += QString::number(result_parts.size());
                  mstr += "\">";
                  STR_MARKUP_BEGIN_CURSIVE(mstr);
                  mstr += m.symbol().c_str();
                  STR_MARKUP_END_CURSIVE(mstr);
                  mstr += "</a>";
                  mstr += "<a name=\"";
                  mstr += QString::number(result_parts.size());
                  mstr += "\"></a>";
                  break;
            }
            case STRUCT_ADDITION: {

                  ips_n.depth++;

                  vector<QString> terms;
                  vector<bool> do_space;
                  for(size_t i = 0; i < m.size(); i++) {
                        if(m[i].type() == STRUCT_NEGATE && i > 0) {
                              ips_n.wrap = m[i][0].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                              terms.push_back(draw_structure(m[i][0], font, cg, po, ips_n));
                        } else {
                              ips_n.wrap = m[i].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                              terms.push_back(draw_structure(m[i], font, cg, po, ips_n));
                        }
                        do_space.push_back(!terms[i].endsWith("valign=\"middle\">"));
                  }
                  for(size_t i = 0; i < terms.size(); i++) {
                        if(i > 0) {
                              if(do_space[i  - 1]) STR_MARKUP_ADD(mstr, " ");
                              if(m[i].type() == STRUCT_NEGATE) {
                                    if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MINUS, po.can_display_unicode_string_arg))) {
                                          STR_MARKUP_ADD(mstr, SIGN_MINUS);
                                    } else {
                                          STR_MARKUP_ADD(mstr, "-");
                                    }
                              } else {
                                    STR_MARKUP_ADD(mstr, "+");
                              }     
                              if(do_space[i]) STR_MARKUP_ADD(mstr, " ");
                        }
                        mstr += terms[i];
                  }
                  break;
            }
            case STRUCT_NEGATE: {

                  ips_n.depth++;

                  ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                  if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MINUS, po.can_display_unicode_string_arg))) {
                        STR_MARKUP_ADD(mstr, SIGN_MINUS);
                  } else {
                        STR_MARKUP_ADD(mstr, "-");
                  }
                  mstr += draw_structure(m[0], font, cg, po, ips_n);
                  break;
            }
            case STRUCT_MULTIPLICATION: {

                  ips_n.depth++;

                  QString mul_str;
                  if(po.use_unicode_signs && po.multiplication_sign == MULTIPLICATION_SIGN_DOT && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MULTIDOT, po.can_display_unicode_string_arg))) {
                        STR_MARKUP_ADD(mul_str, SIGN_MULTIDOT);
                  } else if(po.use_unicode_signs && po.multiplication_sign == MULTIPLICATION_SIGN_DOT && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MULTIBULLET, po.can_display_unicode_string_arg))) {
                        STR_MARKUP_ADD(mul_str, SIGN_MULTIBULLET);
                  } else if(po.use_unicode_signs && po.multiplication_sign == MULTIPLICATION_SIGN_DOT && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_SMALLCIRCLE, po.can_display_unicode_string_arg))) {
                        STR_MARKUP_ADD(mul_str, SIGN_SMALLCIRCLE);
                  } else if(po.use_unicode_signs && po.multiplication_sign == MULTIPLICATION_SIGN_X && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MULTIPLICATION, po.can_display_unicode_string_arg))) {
                        STR_MARKUP_ADD(mul_str, SIGN_MULTIPLICATION);
                  } else {
                        STR_MARKUP_ADD(mul_str, "*");
                  }

                  bool par_prev = false;
                  vector<int> nm;
                  vector<QString> terms;
                  vector<bool> do_space;
                  for(size_t i = 0; i < m.size(); i++) {
                        ips_n.wrap = m[i].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                        terms.push_back(draw_structure(m[i], font, cg, po, ips_n));
                        if(!po.short_multiplication && i > 0) {
                              nm.push_back(-1);
                        } else if(i > 0) {
                              nm.push_back(m[i].neededMultiplicationSign(po, ips_n, m, i + 1, ips_n.wrap || (m[i].isPower() && m[i][0].needsParenthesis(po, ips_n, m[i], 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0)), par_prev, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0));
                        } else {
                              nm.push_back(-1);
                        }
                        do_space.push_back(!terms[i].endsWith("valign=\"middle\">"));
                        par_prev = ips_n.wrap;
                  }
                  for(size_t i = 0; i < terms.size(); i++) {
                        if(!po.short_multiplication && i > 0) {
                              if(do_space[i - 1]) STR_MARKUP_ADD(mstr, " ");
                              mstr += mul_str;
                              if(do_space[i]) STR_MARKUP_ADD(mstr, " ");
                        } else if(i > 0) {
                              switch(nm[i]) {
                                    case MULTIPLICATION_SIGN_SPACE: {
                                          if(do_space[i - 1] && do_space[i]) STR_MARKUP_ADD(mstr, " ");
                                          break;
                                    }
                                    case MULTIPLICATION_SIGN_OPERATOR: {
                                          if(do_space[i - 1]) STR_MARKUP_ADD(mstr, " ");
                                          mstr += mul_str;
                                          if(do_space[i]) STR_MARKUP_ADD(mstr, " ");
                                          break;
                                    }
                                    case MULTIPLICATION_SIGN_OPERATOR_SHORT: {
                                          mstr += mul_str;
                                          break;
                                    }
                              }
                        }
                        mstr += terms[i];
                  }
                  break;
            }
            case STRUCT_INVERSE: {}
            case STRUCT_DIVISION: {
                  
                  ips_n.depth++;
                  ips_n.division_depth++;
                  
                  bool flat = ips.division_depth > 0 || ips.power_depth > 0;
                  if(!flat && po.place_units_separately) {
                        flat = true;
                        size_t i = 0;
                        if(m.isDivision()) {
                              i = 1;
                        }
                        if(m[i].isMultiplication()) {
                              for(size_t i2 = 0; i2 < m[i].size(); i2++) {
                                    if(!m[i][i2].isUnit_exp()) {
                                          flat = false;
                                          break;
                                    }
                              }
                        } else if(!m[i].isUnit_exp()) {
                              flat = false;
                        }
                        if(flat) {
                              ips_n.division_depth--;
                        }
                  }
                  QString num_str, den_str;
                  if(m.type() == STRUCT_DIVISION) {
                        ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                        num_str = draw_structure(m[0], font, cg, po, ips_n);
                  } else {
                        MathStructure onestruct(1, 1);
                        ips_n.wrap = false;
                        num_str = draw_structure(onestruct, font, cg, po, ips_n);
                  }
                  if(m.type() == STRUCT_DIVISION) {
                        ips_n.wrap = m[1].needsParenthesis(po, ips_n, m, 2, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                        den_str = draw_structure(m[1], font, cg, po, ips_n);
                  } else {
                        ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 2, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                        den_str = draw_structure(m[0], font, cg, po, ips_n);
                  }

                  if(flat) {
                        QString div_str;
                        if(po.use_unicode_signs && po.division_sign == DIVISION_SIGN_DIVISION && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_DIVISION, po.can_display_unicode_string_arg))) {
                              STR_MARKUP_ADD(div_str, " " SIGN_DIVISION " ");
                        } else if(po.use_unicode_signs && po.division_sign == DIVISION_SIGN_DIVISION_SLASH && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_DIVISION_SLASH, po.can_display_unicode_string_arg))) {
                              STR_MARKUP_ADD(div_str, " " SIGN_DIVISION_SLASH " ");
                        } else {
                              STR_MARKUP_ADD(div_str, " / ");
                        }
                        mstr = num_str;
                        mstr += div_str;
                        mstr += den_str;
                  } else {

                        int den_w, num_w, w = 0, h = 0;
            
                        num_str.prepend(TEXT_TAGS);
                        num_str += TEXT_TAGS_END;
                        den_str.prepend(TEXT_TAGS);
                        den_str += TEXT_TAGS_END;
                        
                        QSimpleRichText text_r(num_str, font); text_r.setWidth(10000);
                        num_w = text_r.widthUsed();
                        QSimpleRichText text_rn(den_str, font); text_rn.setWidth(10000);                    
                        den_w = text_rn.widthUsed();

                        w = den_w;
                        if(num_w > w) w = num_w;
                        w += 2;

                        QSimpleRichText textsmall("<font size=\"1\">X</font>", font);
                        h = (int) (textsmall.height() / 1.5);
                        h += h % 2;

                        string filename = getLocalDir();
                        if(saved_divisionline_height != h) {
                        
                              QPixmap *pixmap = new QPixmap(10, h);
                              pixmap->fill(cg.background());
                              QPainter p(pixmap);
                              QPen ppen = p.pen();
                              ppen.setColor(cg.foreground());
                              p.setPen(ppen);
                              p.drawLine(0, h / 2, 10, h / 2);
                              p.drawLine(0, h / 2 + 1, 10, h / 2 + 1);
                              p.flush();
                              p.end();

                              pixmap->setMask(pixmap->createHeuristicMask());                         
                              mkdir(filename.c_str(), S_IRWXU);
                              filename += "tmp/";
                              mkdir(filename.c_str(), S_IRWXU);
                              filename += "divline.png";
                              pixmap->save(filename.c_str(), "PNG", 100);

                              delete pixmap;
                              
                              saved_divisionline_height = h;
                              
                        } else {

                              filename += "tmp/divline.png";
                              
                        }

                        mstr = TEXT_TAGS_END;
                        mstr = "</td><td width=1 align=\"center\" valign=\"middle\">";
                        mstr += num_str;
                        mstr += "<br><font size=1><img align=\"middle\" width=";
                        mstr += QString::number(w);
                        mstr += " height=";
                        mstr += QString::number(h);
                        mstr += " src=\"";
                        mstr += filename.c_str();
                        mstr += "\"><br></font>";
                        mstr += den_str;
                        mstr += "</td><td width=1 align=\"center\" valign=\"middle\">";
                        mstr += TEXT_TAGS;

                  }
                  break;
            }
            case STRUCT_POWER: {

                  ips_n.depth++;

                  ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);

                  ips_n.division_depth++;
                  mstr += draw_structure(m[0], font, cg, po, ips_n);
                  ips_n.division_depth--;

                  ips_n.power_depth++;
                  ips_n.wrap = m[1].needsParenthesis(po, ips_n, m, 2, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);

                  PrintOptions po2 = po;
                  po2.show_ending_zeroes = false;
                  if(ips.power_depth > 0) {
                        mstr += TEXT_TAGS "<sup>" "^" "</sup>" TEXT_TAGS_END;
                        mstr += draw_structure(m[1], font, cg, po2, ips_n);
                  } else {
                        mstr += draw_structure(m[1], font, cg, po2, ips_n);
                  }

                  break;
            }
            case STRUCT_LOGICAL_AND: {
                  if(!po.preserve_format && m.size() == 2 && m[0].isComparison() && m[1].isComparison() && m[0].comparisonType() != COMPARISON_EQUALS && m[0].comparisonType() != COMPARISON_NOT_EQUALS && m[1].comparisonType() != COMPARISON_EQUALS && m[1].comparisonType() != COMPARISON_NOT_EQUALS && m[0][0] == m[1][0]) {
                  
                        ips_n.depth++;

                        bool do_space = true;
                        QString tstr;
                        ips_n.wrap = m[0][1].needsParenthesis(po, ips_n, m[0], 2, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                        tstr = draw_structure(m[0][1], font, cg, po, ips_n);
                        do_space = !tstr.endsWith("valign=\"middle\">");
                        mstr += tstr;
                        STR_MARKUP_BEGIN(mstr);
                        if(do_space) mstr += " ";
                        switch(m[0].comparisonType()) {
                              case COMPARISON_LESS: {
                                    mstr += "&gt;";
                                    break;
                              }
                              case COMPARISON_GREATER: {
                                    mstr += "&lt;";
                                    break;
                              }
                              case COMPARISON_EQUALS_LESS: {
                                    if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_GREATER_OR_EQUAL, po.can_display_unicode_string_arg))) {
                                          mstr += SIGN_GREATER_OR_EQUAL;
                                    } else {
                                          mstr += "&gt;=";
                                    }
                                    break;
                              }
                              case COMPARISON_EQUALS_GREATER: {
                                    if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_LESS_OR_EQUAL, po.can_display_unicode_string_arg))) {
                                          mstr += SIGN_LESS_OR_EQUAL;
                                    } else {
                                          mstr += "&lt;=";
                                    }
                                    break;
                              }
                              default: {}
                        }                       
                        
                        ips_n.wrap = m[0][0].needsParenthesis(po, ips_n, m[0], 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                        tstr = draw_structure(m[0][0], font, cg, po, ips_n);
                        do_space = !tstr.endsWith("valign=\"middle\">");
                        if(do_space) mstr += " ";
                        STR_MARKUP_END(mstr);
                        mstr += tstr;
                        STR_MARKUP_BEGIN(mstr);
                        if(do_space) mstr += " ";
                        
                        switch(m[1].comparisonType()) {
                              case COMPARISON_GREATER: {
                                    mstr += "&gt;";
                                    break;
                              }
                              case COMPARISON_LESS: {
                                    mstr += "&lt;";
                                    break;
                              }
                              case COMPARISON_EQUALS_GREATER: {
                                    if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_GREATER_OR_EQUAL, po.can_display_unicode_string_arg))) {
                                          mstr += SIGN_GREATER_OR_EQUAL;
                                    } else {
                                          mstr += "&gt;=";
                                    }
                                    break;
                              }
                              case COMPARISON_EQUALS_LESS: {
                                    if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_LESS_OR_EQUAL, po.can_display_unicode_string_arg))) {
                                          mstr += SIGN_LESS_OR_EQUAL;
                                    } else {
                                          mstr += "&lt;=";
                                    }
                                    break;
                              }
                              default: {}
                        }                       
                        
                        ips_n.wrap = m[1][1].needsParenthesis(po, ips_n, m[1], 2, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                        tstr = draw_structure(m[1][1], font, cg, po, ips_n);
                        do_space = !tstr.endsWith("valign=\"middle\">");
                        if(do_space) mstr += " ";
                        STR_MARKUP_END(mstr);
                        mstr += tstr;
                  
                        break;
                  }
            }
            case STRUCT_COMPARISON: {}
            case STRUCT_LOGICAL_XOR: {}
            case STRUCT_LOGICAL_OR: {}
            case STRUCT_BITWISE_AND: {}
            case STRUCT_BITWISE_XOR: {}
            case STRUCT_BITWISE_OR: {
                  
                  ips_n.depth++;

                  QString str;
                  if(m.type() == STRUCT_COMPARISON) {
                        switch(m.comparisonType()) {
                              case COMPARISON_EQUALS: {
                                    if(ips.depth == 0 && po.use_unicode_signs && (*po.is_approximate || m.isApproximate()) && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_ALMOST_EQUAL, po.can_display_unicode_string_arg))) {
                                          str += SIGN_ALMOST_EQUAL;
                                    } else {
                                          str += "=";
                                    }
                                    break;
                              }
                              case COMPARISON_NOT_EQUALS: {
                                    if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_NOT_EQUAL, po.can_display_unicode_string_arg))) {
                                          str += SIGN_NOT_EQUAL;
                                    } else {
                                          str += "!=";
                                    }
                                    break;
                              }
                              case COMPARISON_GREATER: {
                                    str += "&gt;";
                                    break;
                              }
                              case COMPARISON_LESS: {
                                    str += "&lt;";
                                    break;
                              }
                              case COMPARISON_EQUALS_GREATER: {
                                    if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_GREATER_OR_EQUAL, po.can_display_unicode_string_arg))) {
                                          str += SIGN_GREATER_OR_EQUAL;
                                    } else {
                                          str += "&gt;=";
                                    }
                                    break;
                              }
                              case COMPARISON_EQUALS_LESS: {
                                    if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_LESS_OR_EQUAL, po.can_display_unicode_string_arg))) {
                                          str += SIGN_LESS_OR_EQUAL;
                                    } else {
                                          str += "&lt;=";
                                    }
                                    break;
                              }
                        }
                  } else if(m.type() == STRUCT_LOGICAL_AND) {
                        str += "<a name=\"+Logical AND\">";
                        if(po.spell_out_logical_operators) str += i18n("and");
                        else str += "&amp;&amp;";
                        str += "</a>";
                  } else if(m.type() == STRUCT_LOGICAL_OR) {
                        str += "<a name=\"+Logical inclusive OR\">";
                        if(po.spell_out_logical_operators) str += i18n("or");
                        else str += "||";
                        str += "</a>";
                  } else if(m.type() == STRUCT_LOGICAL_XOR) {
                        str += "<a name=\"+Logical exclusive OR\">XOR</a>";                     
                  } else if(m.type() == STRUCT_BITWISE_AND) {
                        str += "<a name=\"+Bitwise AND\">&amp;</a>";
                  } else if(m.type() == STRUCT_BITWISE_OR) {
                        str += "<a name=\"+Bitwise inclusive OR\">|</a>";
                  } else if(m.type() == STRUCT_BITWISE_XOR) {
                        str += "<a name=\"+Bitwise exclusive XOR\">XOR</a>";
                  }

                  bool do_space = true, do_space_prev = true;
                  QString tstr;
                  for(size_t i = 0; i < m.size(); i++) {
                        do_space_prev = do_space;
                        ips_n.wrap = m[i].needsParenthesis(po, ips_n, m, i + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                        tstr = draw_structure(m[i], font, cg, po, ips_n);
                        do_space = !tstr.endsWith("valign=\"middle\">");
                        if(i > 0) {
                              STR_MARKUP_BEGIN(mstr);
                              if(do_space_prev) mstr += " ";
                              mstr += str;
                              if(do_space) mstr += " ";
                              STR_MARKUP_END(mstr);
                        }
                        mstr += tstr;
                  }
                  break;
            }
            case STRUCT_BITWISE_NOT: {

                  ips_n.depth++;

                  STR_MARKUP_BEGIN(mstr);

                  mstr += "<a name=\"+Bitwise NOT\">~</a>";

                  ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                  mstr += draw_structure(m[0], font, cg, po, ips_n);
                  
                  STR_MARKUP_END(mstr);

                  break;
            }
            case STRUCT_LOGICAL_NOT: {

                  ips_n.depth++;

                  STR_MARKUP_BEGIN(mstr);

                  mstr += "<a name=\"+Logical NOT\">!</a>";

                  ips_n.wrap = m[0].needsParenthesis(po, ips_n, m, 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                  mstr += draw_structure(m[0], font, cg, po, ips_n);
                  
                  STR_MARKUP_END(mstr);

                  break;
            }
            case STRUCT_VECTOR: {
                  
                  ips_n.depth++;
                  
                  bool is_matrix = m.isMatrix();
                  if(!in_matrix) {
                        result_parts.push_back(m);
                        mstr = "<a name=\"";
                        mstr += QString::number(result_parts.size());
                        mstr += "\">";
                  }

                  if(m.size() == 0) {
                        STR_MARKUP_ADD(mstr, "( ");
                  } else {
                        STR_MARKUP_ADD(mstr, "(");
                  }
                  for(size_t index = 0; index < m.size(); index++) {
                        if(index > 0) {
                              STR_MARKUP_BEGIN(mstr);
                              mstr += CALCULATOR->getComma().c_str();
                              mstr += " ";
                              STR_MARKUP_END(mstr);
                        }
                        ips_n.wrap = m[index].needsParenthesis(po, ips_n, m, index + 1, ips.division_depth > 0 || ips.power_depth > 0, ips.power_depth > 0);
                        mstr += draw_structure(m[index], font, cg, po, ips_n, is_matrix);
                  }
                  STR_MARKUP_ADD(mstr, ")");
                  if(!in_matrix) mstr += "</a>";
                  break;
            }
            case STRUCT_UNIT: {

                  result_parts.push_back(m);
                  mstr = "<a name=\"";
                  mstr += QString::number(result_parts.size());
                  mstr += "\">";

                  STR_MARKUP_BEGIN(mstr);
                  
                  QString str;
                  const ExpressionName *ename = &m.unit()->preferredDisplayName(po.abbreviate_names, po.use_unicode_signs, m.isPlural(), po.use_reference_names, po.can_display_unicode_string_function, po.can_display_unicode_string_arg);
                  if(m.prefix()) {
                        str += m.prefix()->name(po.abbreviate_names && ename->abbreviation && (ename->suffix || ename->name.find("_") == string::npos), po.use_unicode_signs, po.can_display_unicode_string_function, po.can_display_unicode_string_arg).c_str();
                  }
                  if(ename->suffix && ename->name.length() > 1) {
                        size_t i = ename->name.rfind('_');
                        bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
                        size_t i2 = 1;
                        if(b) {
                              if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
                                    while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
                                          i2++;
                                    }
                              }
                              str += ename->name.substr(0, ename->name.length() - i2).c_str();
                        } else {
                              str += ename->name.substr(0, i).c_str();
                        }
                        if(ips.power_depth == 0) str += "<sub>";
                        else str += TEXT_TAGS_SMALL "<sup>";
                        if(b) str += ename->name.substr(ename->name.length() - i2, i2).c_str();
                        else str += ename->name.substr(i + 1, ename->name.length() - (i + 1)).c_str();
                        if(ips.power_depth == 0) str += "</sub>";
                        else str += "</sup>" TEXT_TAGS_SMALL_END;
                  } else {
                        str += ename->name.c_str();                     
                  }
                  str.replace("_", " ");
                  mstr += str;

                  STR_MARKUP_END(mstr);
                  mstr += "</a>";
                  mstr += "<a name=\"";
                  mstr += QString::number(result_parts.size());
                  mstr += "\"></a>";
                  
                  break;
            }
            case STRUCT_VARIABLE: {

                  result_parts.push_back(m);
                  mstr = "<a name=\"";
                  mstr += QString::number(result_parts.size());
                  mstr += "\">";
                  if(m.variable() == CALCULATOR->v_i) {
                        STR_MARKUP_BEGIN(mstr);
                  } else {
                        STR_MARKUP_BEGIN_CURSIVE(mstr);
                  }
                  
                  QString str;
                  const ExpressionName *ename = &m.variable()->preferredDisplayName(po.abbreviate_names, po.use_unicode_signs, false, po.use_reference_names, po.can_display_unicode_string_function, po.can_display_unicode_string_arg);
                  if(ename->suffix && ename->name.length() > 1) {
                        size_t i = ename->name.rfind('_');
                        bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
                        size_t i2 = 1;
                        if(b) {
                              if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
                                    while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
                                          i2++;
                                    }
                              }
                              str += ename->name.substr(0, ename->name.length() - i2).c_str();
                        } else {
                              str += ename->name.substr(0, i).c_str();
                        }
                        if(ips.power_depth == 0) str += "<sub>";
                        else str += TEXT_TAGS_SMALL "<sup>";
                        if(b) str += ename->name.substr(ename->name.length() - i2, i2).c_str();
                        else str += ename->name.substr(i + 1, ename->name.length() - (i + 1)).c_str();
                        if(ips.power_depth == 0) str += "</sub>";
                        else str += "</sup>" TEXT_TAGS_SMALL_END;
                  } else {
                        str += ename->name.c_str();
                  }
                  str.replace("_", " ");
                  mstr += str;
                  
                  if(m.variable() == CALCULATOR->v_i) {
                        STR_MARKUP_END(mstr);
                  } else {
                        STR_MARKUP_END_CURSIVE(mstr);
                  }
                  mstr += "</a>";
                  mstr += "<a name=\"";
                  mstr += QString::number(result_parts.size());
                  mstr += "\"></a>";
                  break;
            }
            case STRUCT_FUNCTION: {

                  ips_n.depth++;
                  
                  result_parts.push_back(m);
                  mstr = "<a name=\"";
                  mstr += QString::number(result_parts.size());
                  mstr += "\">";
                  
                  STR_MARKUP_BEGIN(mstr);
                  
                  QString str;
                  const ExpressionName *ename = &m.function()->preferredDisplayName(po.abbreviate_names, po.use_unicode_signs, false, po.use_reference_names, po.can_display_unicode_string_function, po.can_display_unicode_string_arg);
                  if(ename->suffix && ename->name.length() > 1) {
                        size_t i = ename->name.rfind('_');
                        bool b = i == string::npos || i == ename->name.length() - 1 || i == 0;
                        size_t i2 = 1;
                        if(b) {
                              if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) {
                                    while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) {
                                          i2++;
                                    }
                              }
                              str += ename->name.substr(0, ename->name.length() - i2).c_str();
                        } else {
                              str += ename->name.substr(0, i).c_str();
                        }
                        if(ips.power_depth == 0) str += "<sub>";
                        else str += TEXT_TAGS_SMALL "<sup>";
                        if(b) str += ename->name.substr(ename->name.length() - i2, i2).c_str();
                        else str += ename->name.substr(i + 1, ename->name.length() - (i + 1)).c_str();
                        if(ips.power_depth == 0) str += "</sub>";
                        else str += "</sup>" TEXT_TAGS_SMALL_END;
                  } else {
                        str += ename->name.c_str();
                  }
                  str.replace("_", " ");
                  mstr += str;

                  mstr += "(";
                  STR_MARKUP_END(mstr);
                  mstr += "</a>";

                  for(size_t index = 0; index < m.size(); index++) {
                        if(index > 0) {
                              STR_MARKUP_BEGIN(mstr);
                              mstr += po.comma().c_str();
                              mstr += " ";
                              STR_MARKUP_END(mstr);
                        }
                        mstr += draw_structure(m[index], font, cg, po, ips_n);
                  }
                  STR_MARKUP_ADD(mstr, ")");
                  
                  break;
            }
            case STRUCT_UNDEFINED: {
                  STR_MARKUP_ADD(mstr, i18n("undefined"));
                  break;
            }
            default: {
            }
      }
      if(ips.wrap) {
            STR_MARKUP_PREPEND(mstr, "(");
            STR_MARKUP_ADD(mstr, ")");
      }
      if(ips.depth == 0 && !(m.isComparison() && (!(*po.is_approximate || m.isApproximate()) || (m.comparisonType() == COMPARISON_EQUALS && po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_ALMOST_EQUAL, po.can_display_unicode_string_arg)))))) {
            QString equals_str;
            if(*po.is_approximate || m.isApproximate()) {
                  if(po.use_unicode_signs && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_ALMOST_EQUAL, po.can_display_unicode_string_arg))) {
                        equals_str = SIGN_ALMOST_EQUAL " ";
                  } else {
                        equals_str += i18n("approx.");
                        equals_str += " ";
                  }
            } else {
                  equals_str = "= ";
            }
            mstr.prepend(equals_str);
      }
      if(ips.depth == 0) {
            mstr.prepend(TEXT_TAGS);
            mstr += TEXT_TAGS_END;
      }
      
      return mstr;
      
}

#define STATUS_SPACE    if(b) str += "  "; else b = true;

void KQalculate::update_status_text() {

      QString str;
      bool b = false;
      
      if(evalops.approximation == APPROXIMATION_EXACT) {
            STATUS_SPACE
            str += i18n("EXACT");
      } else if(evalops.approximation == APPROXIMATION_APPROXIMATE) {
            STATUS_SPACE
            str += i18n("APPROX");
      }
      if(evalops.parse_options.rpn) {
            STATUS_SPACE
            str += i18n("RPN");
      }
      switch(evalops.parse_options.base) {
            case BASE_DECIMAL: {
                  break;
            }
            case BASE_BINARY: {
                  STATUS_SPACE
                  str += i18n("BIN");
                  break;
            }
            case BASE_OCTAL: {
                  STATUS_SPACE
                  str += i18n("OCT");
                  break;
            }
            case BASE_HEXADECIMAL: {
                  STATUS_SPACE
                  str += i18n("HEX");
                  break;
            }
            case BASE_ROMAN_NUMERALS: {
                  STATUS_SPACE
                  str += i18n("ROMAN");
                  break;
            }
            default: {
                  STATUS_SPACE
                  str += QString::number(evalops.parse_options.base);
                  break;
            }
      }
      switch (evalops.parse_options.angle_unit) {
            case ANGLE_UNIT_DEGREES: {
                  STATUS_SPACE
                  str += i18n("DEG");
                  break;
            }
            case ANGLE_UNIT_RADIANS: {
                  STATUS_SPACE
                  str += i18n("RAD");
                  break;
            }
            case ANGLE_UNIT_GRADIANS: {
                  STATUS_SPACE
                  str += i18n("GRA");
                  break;
            }
            default: {}
      }
      if(evalops.parse_options.read_precision != DONT_READ_PRECISION) {
            STATUS_SPACE
            str += i18n("PREC");
      }
      if(!evalops.parse_options.functions_enabled) {
            STATUS_SPACE
            str += "<s>";
            str += i18n("FUNC");
            str += "</s>";
      }
      if(!evalops.parse_options.units_enabled) {
            STATUS_SPACE
            str += "<s>";
            str += i18n("UNIT");
            str += "</s>";
      }
      if(!evalops.parse_options.variables_enabled) {
            STATUS_SPACE
            str += "<s>";
            str += i18n("VAR");
            str += "</s>";
      }
      if(!evalops.allow_infinite) {
            STATUS_SPACE
            str += "<s>";
            str += i18n("INF");
            str += "</s>";
      }
      if(!evalops.allow_complex) {
            STATUS_SPACE
            str += "<s>";
            str += i18n("CPLX");
            str += "</s>";
      }
      str = str.stripWhiteSpace();
      if(b) str += "&nbsp;";
      else str += "&nbsp;&nbsp;";
      
      if(str != statusLabel_r->text()) {
            statusLabel_r->setText(str);
            qApp->processEvents();
            displayParseStatus();
      }
      
}


void on_abort_display() {
      pthread_cancel(view_thread);
      CALCULATOR->restoreState();
      CALCULATOR->clearBuffers();
      b_busy = false;
      pthread_create(&view_thread, &view_thread_attr, view_proc, view_pipe_r);
}

void *view_proc(void *pipe) {

      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);   
      FILE *view_pipe = (FILE*) pipe;

      while(true) {

            bool *do_wrap;
            void *x = NULL;
            fread(&x, sizeof(void*), 1, view_pipe);
            KQalculate *win = (KQalculate*) x;
            fread(&x, sizeof(void*), 1, view_pipe);
            MathStructure m(*((MathStructure*) x));
            fread(&x, sizeof(void*), 1, view_pipe);
            MathStructure *mm = (MathStructure*) x;
            fread(&do_wrap, sizeof(bool*), 1, view_pipe);
            fread(&x, sizeof(void*), 1, view_pipe);
            printops.can_display_unicode_string_arg = (void*) win->historyBrowser;
            if(x) {
                  PrintOptions po;
                  po.preserve_format = true;
                  po.show_ending_zeroes = true;
                  po.lower_case_e = printops.lower_case_e;
                  po.lower_case_numbers = printops.lower_case_numbers;
                  po.abbreviate_names = false;
                  po.use_unicode_signs = printops.use_unicode_signs;
                  po.multiplication_sign = printops.multiplication_sign;
                  po.division_sign = printops.division_sign;
                  po.short_multiplication = false;
                  po.excessive_parenthesis = true;
                  po.improve_division_multipliers = false;
                  po.can_display_unicode_string_function = &can_display_unicode_string_function;
                  po.can_display_unicode_string_arg = (void*) win->statusLabel_l;
                  po.spell_out_logical_operators = printops.spell_out_logical_operators;
                  MathStructure mp(*((MathStructure*) x));
                  fread(&po.is_approximate, sizeof(bool*), 1, view_pipe);
                  mp.format(po);
                  parsed_text = mp.print(po).c_str();
                  fread(&x, sizeof(void*), 1, view_pipe);
                  mp.set(*((MathStructure*) x));
                  if(!mp.isUndefined()) {
                        mp.format(po);
                        parsed_text += CALCULATOR->localToString().c_str();
                        parsed_text += mp.print(po).c_str();
                  }
            }
            printops.allow_non_usable = false;
            if(m.isMatrix()) {
                  mm->set(m);
                  MathStructure mm2(m);
                  string mstr;
                  int c = mm->columns(), r = mm->rows();
                  for(int index_r = 0; index_r < r; index_r++) {
                        for(int index_c = 0; index_c < c; index_c++) {
                              mm->getElement(index_r + 1, index_c + 1)->set(i18n("aborted").ascii());
                        }
                  }
                  for(int index_r = 0; index_r < r; index_r++) {
                        for(int index_c = 0; index_c < c; index_c++) {
                              mm2.getElement(index_r + 1, index_c + 1)->format(printops);
                              mstr = mm2.getElement(index_r + 1, index_c + 1)->print(printops);
                              mm->getElement(index_r + 1, index_c + 1)->set(mstr);
                        }
                  }
            }
            m.format(printops);
            result_history_text = m.print(printops).c_str();
            printops.can_display_unicode_string_arg = NULL;
            /*if(result_history_text.length() > 5000) {
                  result_text = i18n("result is too long\nsee history");
                  *printops.is_approximate = false;
            } else */
            if(result_text == i18n("aborted")) {
                  result_text = i18n("calculation was aborted");
                  *printops.is_approximate = false;
            } else {
                  printops.allow_non_usable = true;
                  printops.can_display_unicode_string_arg = (void*) win->resultLabel;
                  QFont font(win->resultLabel->font());
                  result_text = draw_structure(m, font, win->resultLabel->colorGroup(), printops);
                  if(result_text.find("</td>") >= 0) {
                        result_text.prepend("<div align=\"right\"><table width=1 cellspacing=0 cellpadding=0 border=0><tr><td width=1 align=\"center\" valign=\"middle\">");
                        result_text += "</td></tr></table></div>";
                        *do_wrap = false;
                  } else {
                        result_text.prepend("<div align=\"right\"><font size=2>&nbsp;<br></font>");
                        result_text += "</div>";
                        *do_wrap = true;
                  }
                  printops.can_display_unicode_string_arg = NULL;
                  printops.allow_non_usable = false;
            }
            b_busy = false;
      }
      return NULL;
}

void KQalculate::clearresult() {    
      resultLabel->setRightMargin(10);
      resultLabel->setText("<font size=6> </font>");
      parsed_text = "";
      result_parts.clear();
}

void reduceDivLineSize(QalculateResultDisplay *resultLabel) {

      QString str = result_text;
      QColorGroup cg = resultLabel->colorGroup();
      int rt_i = 0;
      while(true) {
                  
            int i2 = str.find("</td><td width=1 align=\"center\" valign=\"middle\">", 0);
            if(i2 < 0) break;
            str.remove(0, i2 + 48);
            rt_i += i2 + 48;
            i2 = str.find("<br>", 0);
            if(i2 < 0) break;
            int width_i = rt_i + i2 + 43;
            QString num_str = str;
            num_str.truncate(i2);
            
            i2 = str.find("<br>", i2 + 4);
            if(i2 < 0) break;
            str.remove(0, i2 + 11);
            rt_i += i2 + 11;
            i2 = str.find("</td><td width=1 align=\"center\" valign=\"middle\">", 0);
            if(i2 < 0) break;
            QString den_str = str;
            den_str.truncate(i2);
            str.remove(0, i2 + 48);
            rt_i += i2 + 48;
                        
            int den_w, num_w, w = 0, h = 0;
            QSimpleRichText text_r(num_str, resultLabel->font()); text_r.setWidth(10000);
            num_w = text_r.widthUsed();
            QSimpleRichText text_rn(den_str, resultLabel->font()); text_rn.setWidth(10000);                       
            den_w = text_rn.widthUsed();
                  
            w = den_w;
            if(num_w > w) w = num_w;
            w += 2;
                        
            QSimpleRichText textsmall("<font size=\"1\">X</font>", resultLabel->font());
            h = (int) (textsmall.height() / 1.5);
            h += h % 2;

            string filename = getLocalDir();
            if(saved_divisionline_height != h) {
                        
                  QPixmap *pixmap = new QPixmap(10, h);
                  pixmap->fill(cg.background());
                  QPainter p(pixmap);
                  QPen ppen = p.pen();
                  ppen.setColor(cg.foreground());
                  p.setPen(ppen);
                  p.drawLine(0, h / 2, 10, h / 2);
                  p.drawLine(0, h / 2 + 1, 10, h / 2 + 1);
                  p.flush();
                  p.end();

                  pixmap->setMask(pixmap->createHeuristicMask());                         
                  mkdir(filename.c_str(), S_IRWXU);
                  filename += "tmp/";
                  mkdir(filename.c_str(), S_IRWXU);
                  filename += "divline.png";
                  pixmap->save(filename.c_str(), "PNG", 100);

                  delete pixmap;
                              
                  saved_divisionline_height = h;
                              
            } else {

                  filename += "tmp/divline.png";
                              
            }
                        
            int height_i = result_text.find(" height=", width_i);
            if(height_i < 0) break;
            num_str = QString::number(w);
            result_text.replace(width_i, height_i - width_i, num_str);
            int i_diff = num_str.length() - (height_i - width_i);
            rt_i += i_diff;
            height_i += i_diff;
            height_i += 8;
            int height_i_end = result_text.find(" src=", height_i);
            if(height_i_end < 0) break;
            num_str = QString::number(h);
            result_text.replace(height_i, height_i_end - height_i, num_str);
            i_diff = num_str.length() - (height_i_end - height_i);
            rt_i += i_diff;
                        
      }
      
}

Prefix *set_result_prefix;
bool set_result_update_history;
bool set_result_update_parse;
bool set_result_force;
QString set_result_transformation;

void KQalculate::setResult(Prefix *prefix, bool update_history, bool update_parse, bool force, QString transformation) {
      if(expression_has_changed) {
            if(!force) return;
            execute_expression();
            if(!prefix) return;
      }
      set_result_prefix = prefix;
      set_result_update_history = update_history;
      set_result_update_parse = update_parse;
      set_result_force = force;
      set_result_transformation = transformation;
      QTimer::singleShot(0, this, SLOT(setResult2()));
}
void KQalculate::setResult2() {

      if(block_result_update) return;

      Prefix *prefix = set_result_prefix;
      bool update_history = set_result_update_history;
      bool update_parse = set_result_update_parse;
      bool force = set_result_force;
      QString transformation = set_result_transformation;
      
      error_timer->stop();
      b_busy = true;    

      uint history_index = 0;
      if(update_history) {
            if(update_parse) {
                  QString text = result_history_text;
                  text.replace("&", "&amp;");
                  text.replace(">", "&gt;");
                  text.replace("<", "&lt;");
                  int l = text.length();
                  text += " <br><hr>";
                  text += historyBrowser->text();
                  history_index = l + 1;
                  historyBrowser->setText(text);
            } else if(initial_result_index == 0) {
                  b_busy = false;
                  error_timer->start(100);
                  return;
            } else {
                  if(!transformation.isEmpty()) {
                        transformation.replace("&", "&amp;");
                        transformation.replace(">", "&gt;");
                        transformation.replace("<", "&lt;");
                        transformation.insert(0, "<i>");
                        transformation += ":  </i><br>";
                        QString text = historyBrowser->text();
                        text.insert(initial_result_index, transformation);
                        historyBrowser->setText(text);
                        initial_result_index += transformation.length() - 4;
                  }
                  history_index = initial_result_index;
            }
            result_history_text = "?";
      }
      if(update_parse) {
            parsed_text = i18n("aborted");
      }

      resultLabel->setRightMargin(10);
      resultLabel->setText("<font size=6> </font>");
      result_parts.clear();

      result_text = i18n("result processing was aborted");
      *printops.is_approximate = false;

      printops.prefix = prefix;

      CALCULATOR->saveState();

      bool parsed_approx = false;
      bool do_wrap = true;
      KQalculate *win = this;
      fwrite(&win, sizeof(void*), 1, view_pipe_w);
      fwrite(&mstruct, sizeof(void*), 1, view_pipe_w);
      matrix_mstruct->clear();
      fwrite(&matrix_mstruct, sizeof(void*), 1, view_pipe_w);
      bool *b = &do_wrap;
      fwrite(&b, sizeof(bool*), 1, view_pipe_w);
      if(update_parse) {
            fwrite(&parsed_mstruct, sizeof(void*), 1, view_pipe_w);
            bool *parsed_approx_p = &parsed_approx;
            fwrite(&parsed_approx_p, sizeof(void*), 1, view_pipe_w);
            fwrite(&parsed_tostruct, sizeof(void*), 1, view_pipe_w);
      } else {
            void *x = NULL;
            fwrite(&x, sizeof(void*), 1, view_pipe_w);
      }
      fflush(view_pipe_w);

      struct timespec rtime;
      rtime.tv_sec = 0;
      rtime.tv_nsec = 20000000;
      int i = 0;
      while(b_busy && i < 50) {
            nanosleep(&rtime, NULL);
            i++;
      }
      i = 0;

      KProgressDialog *dialog = NULL;
      if(b_busy) {
            dialog = new KProgressDialog(this, "display_progress_dialog", i18n("Processing..."), i18n("Processing..."), true);
            dialog->progressBar()->setPercentageVisible(false);
            dialog->progressBar()->setTotalSteps(0);
            dialog->showCancelButton(true);
            dialog->setButtonText(i18n("Abort"));
            dialog->show();
      }
      if(dialog && dialog->wasCancelled()) on_abort_display();
      rtime.tv_nsec = 100000000;
      while(b_busy) {
            dialog->progressBar()->advance(1);
            qApp->processEvents();
            nanosleep(&rtime, NULL);
            if(dialog->wasCancelled()) on_abort_display();
      }

      b_busy = true;
      if(dialog) {
            dialog->hide();
            delete dialog;
      }
      
      if(do_wrap) {
            resultLabel->setVScrollBarMode(QScrollView::Auto);
            resultLabel->setRightMargin(10);
            resultLabel->setWordWrap(QTextEdit::NoWrap);
      } else {
            resultLabel->setVScrollBarMode(QScrollView::AlwaysOff);
            resultLabel->setWordWrap(QTextEdit::NoWrap);
            resultLabel->setRightMargin(0);
            QString str = result_text;
            str.replace("width=1 ", "");
            QSimpleRichText testrt(str, resultLabel->font());
            testrt.setWidth(resultLabel->visibleWidth() * 4);
            if(testrt.widthUsed() > resultLabel->visibleWidth()) {
                  result_text.replace("<font size=5", "<font size=4");
                  result_text.replace("<font size=6", "<font size=5");              
                  reduceDivLineSize(resultLabel);
            }
      }

      resultLabel->setText(result_text);
      
      if(update_history) {
            if(result_history_text.length() > 500000) {
                  result_history_text = "(...)";
            }
            if(parsed_text.length() > 500000) {
                  parsed_text = "(...)";
            }
            QString new_text;
            if(update_parse) {
                  QString str = "&nbsp;&nbsp;";
                  if(!parsed_approx) {
                        str += "=";
                  } else {
                        if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyBrowser)) {
                              str += SIGN_ALMOST_EQUAL;
                        } else {
                              str += i18n("approx.");
                        }
                  }
                  str += " ";
                  QString str2 = parsed_text;
                  str2.replace("&", "&amp;");
                  str2.replace(">", "&gt;");
                  str2.replace("<", "&lt;");
                  str += str2;
                  new_text += "<font color=\"gray40\"><i>";
                  new_text += str;
                  new_text += "</i></font>";
                  new_text += "<br>";
                  
            }
            display_errors(&new_text);
            if(!(*printops.is_approximate) && !mstruct->isApproximate() && (update_parse || !prev_result_approx)) {
                  new_text += "=";
            } else {
                  if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) historyBrowser)) {
                        new_text += SIGN_ALMOST_EQUAL;
                  } else {
                        QString str_approx = "= ";
                        str_approx += i18n("approx.");
                        new_text += str_approx;
                  }
            }
            new_text += " ";
            QString str2 = result_history_text;
            str2.replace("&", "&amp;");
            str2.replace(">", "&gt;");
            str2.replace("<", "&lt;");
            new_text += "<b>";
            new_text += str2;
            new_text += "</b>";
            QString text = historyBrowser->text();
            initial_result_index = history_index + new_text.length() + 4;
            if(!update_parse && transformation.isEmpty()) {
                  new_text += "<br>";     
            }
            text.insert(history_index, new_text);
            historyBrowser->setText(text);
            prev_result_approx = *printops.is_approximate;
      }
      printops.prefix = NULL;
      
      b_busy = false;
      display_errors();
      
      if(mstruct->isMatrix() && matrix_mstruct->isMatrix()) {
            qApp->processEvents();
            expressionEdit->setFocus();
            if(update_history && update_parse && force) expressionEdit->selectAll();
            insertMatrixVector(matrix_mstruct, false, true, true);
      }
      
      error_timer->start(100);
      
}


void on_abort_command() {
      pthread_cancel(command_thread);
      CALCULATOR->restoreState();
      CALCULATOR->clearBuffers();
      b_busy = false;
      command_thread_started = false;
}

void *command_proc(void *pipe) {

      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);   
      FILE *command_pipe = (FILE*) pipe;
      
      while(true) {
      
            void *x = NULL;
            int command_type;
            fread(&command_type, sizeof(int), 1, command_pipe);
            fread(&x, sizeof(void*), 1, command_pipe);
            switch(command_type) {
                  case COMMAND_FACTORIZE: {
                        ((MathStructure*) x)->factorize(evalops);
                        break;
                  }
                  case COMMAND_SIMPLIFY: {
                        ((MathStructure*) x)->simplify(evalops);
                        break;
                  }
            }
            b_busy = false;
            
      }
      return NULL;
}

int execute_command_command_type;

void KQalculate::executeCommand(int command_type) {
      execute_command_command_type = command_type;
      if(expression_has_changed) {
            execute_expression();
      }
      QTimer::singleShot(0, this, SLOT(executeCommand2()));
}
void KQalculate::executeCommand2() {
      int command_type = execute_command_command_type;

      error_timer->stop();    

      b_busy = true;    
      bool command_aborted = false;
      CALCULATOR->saveState();

      if(!command_thread_started) {
            pthread_create(&command_thread, &command_thread_attr, command_proc, command_pipe_r);
            command_thread_started = true;
      }

      fwrite(&command_type, sizeof(int), 1, command_pipe_w);
      MathStructure *mfactor = new MathStructure(*mstruct);
      fwrite(&mfactor, sizeof(void*), 1, command_pipe_w);
      
      fflush(command_pipe_w);

      struct timespec rtime;
      rtime.tv_sec = 0;
      rtime.tv_nsec = 20000000;
      int i = 0;
      while(b_busy && i < 50) {
            nanosleep(&rtime, NULL);
            i++;
      }
      i = 0;
      
      KProgressDialog *dialog = NULL;
      if(b_busy) {
            QString progress_str;
            switch(command_type) {
                  case COMMAND_FACTORIZE: {
                        progress_str = i18n("Factorizing...");
                        break;
                  }
                  case COMMAND_SIMPLIFY: {
                        progress_str = i18n("Simplifying...");
                        break;
                  }
            }
            dialog = new KProgressDialog(this, "display_progress_dialog", progress_str, progress_str, true);
            dialog->progressBar()->setPercentageVisible(false);
            dialog->progressBar()->setTotalSteps(0);
            dialog->showCancelButton(true);
            dialog->setButtonText(i18n("Abort"));
            dialog->show();
      }
      if(dialog && dialog->wasCancelled()) {
            on_abort_command();
            command_aborted = true;
      }
      rtime.tv_nsec = 100000000;
      while(b_busy) {
            dialog->progressBar()->advance(1);
            qApp->processEvents();
            nanosleep(&rtime, NULL);
            if(dialog->wasCancelled()) {              
                  on_abort_command();
                  command_aborted = true;
            }
      }

      b_busy = true;
      if(dialog) {
            dialog->hide();
            delete dialog;
      }

      b_busy = false;
      
      if(!command_aborted) {
            mstruct->unref();
            mstruct = mfactor;
            switch(command_type) {
                  case COMMAND_FACTORIZE: {
                        printops.allow_factorization = true;
                        break;
                  }
                  case COMMAND_SIMPLIFY: {
                        printops.allow_factorization = false;
                        break;
                  }
            }
            set_result_prefix = NULL;
            set_result_update_history = true;
            set_result_update_parse = false;
            set_result_force = true;
            set_result_transformation = "";
            setResult2();
            expressionEdit->setFocus();
      }

      error_timer->start(100);

}

void KQalculate::result_display_updated() {
      setResult(NULL, false, false, false);
      update_status_text();
      expressionEdit->setFocus();
}
void KQalculate::result_format_updated() {
      setResult(NULL, true, false, false);
      update_status_text();
      expressionEdit->setFocus();
}
void KQalculate::result_action_executed() {
      //display_errors();
      printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
      setResult(NULL, true, false, true);
      expressionEdit->setFocus();
}
void KQalculate::result_prefix_changed(Prefix *prefix) {
      setResult(prefix, true, false, true);
      expressionEdit->setFocus();
}
void KQalculate::expression_calculation_updated() {
      expression_has_changed2 = true;
      displayParseStatus();
      execute_expression(false);
      update_status_text();
      expressionEdit->setFocus();
}
void KQalculate::expression_format_updated(bool recalculate) {
      expression_has_changed2 = true;
      displayParseStatus();
      if(!expression_has_changed && !recalculate) {   
            clearresult();
      }
      if(recalculate) {
            execute_expression(false);
      }
      update_status_text();
      expressionEdit->setFocus();
}

/*
      calculate entered expression and display result
*/
bool execute_expression_force;
void KQalculate::execute_expression(bool force) {
      execute_expression_force = force;
      QTimer::singleShot(0, this, SLOT(execute_expression2()));
}
void KQalculate::execute_expression2() {
      bool force = execute_expression_force;

      QString str = expressionEdit->text().stripWhiteSpace();
      if(!force && (expression_has_changed || str.isEmpty())) return;
      error_timer->stop();
      expression_has_changed = false;
      
      expressionEdit->addToHistory(expressionEdit->text());

      b_busy = true;
      parsed_text = "";
      CALCULATOR->calculate(mstruct, CALCULATOR->unlocalizeExpression(str.ascii()), 0, evalops, parsed_mstruct, parsed_tostruct, !printops.negative_exponents);
      struct timespec rtime;
      rtime.tv_sec = 0;
      rtime.tv_nsec = 20000000;
      int i = 0;
      while(CALCULATOR->busy() && i < 50) {
            nanosleep(&rtime, NULL);
            i++;
      }
      i = 0;
      KProgressDialog *dialog = NULL;
      if(CALCULATOR->busy()) {
            dialog = new KProgressDialog(this, "calculation_progress_dialog", i18n("Calculating..."), i18n("Calculating..."), true);
            dialog->progressBar()->setPercentageVisible(false);
            dialog->progressBar()->setTotalSteps(0);
            dialog->showCancelButton(true);
            dialog->setButtonText(i18n("Abort"));
            dialog->show();
      }
      if(dialog && dialog->wasCancelled()) CALCULATOR->abort();
      rtime.tv_nsec = 100000000;
      while(CALCULATOR->busy()) {
            dialog->progressBar()->advance(1);
            qApp->processEvents();
            nanosleep(&rtime, NULL);
            if(dialog->wasCancelled()) CALCULATOR->abort();
      }
      if(dialog) {
            dialog->hide();
            delete dialog;
            expressionEdit->setFocus();
      }
      b_busy = false;
      
      //update "ans" variables
      vans[4]->set(vans[3]->get());
      vans[3]->set(vans[2]->get());
      vans[2]->set(vans[1]->get());
      vans[1]->set(vans[0]->get());
      vans[0]->set(*mstruct);
      
      result_history_text = str;
      printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
      set_result_prefix = NULL;
      set_result_update_history = true;
      set_result_update_parse = true;
      set_result_force = true;
      set_result_transformation = "";
      setResult2();
      expressionEdit->setFocus();
      expressionEdit->selectAll();
      error_timer->start(100);
}

void KQalculate::display_errors(QString *new_text) {
      if(!CALCULATOR->message()) return;
      error_timer->stop();
      bool error = false;
      MessageType mtype;
      QStringList strlst;
      QString error_str = "";
      while(true) {
            mtype = CALCULATOR->message()->type();
            if(mtype == MESSAGE_ERROR || mtype == MESSAGE_WARNING) {
                  strlst.push_back(CALCULATOR->message()->message().c_str());
                  if(mtype == MESSAGE_ERROR) error = true;
                  if(mtype == MESSAGE_ERROR) error_str += "<font color=\"red\">";
                  else error_str += "<font color=\"blue\">";
                  error_str += "- ";
                  error_str += CALCULATOR->message()->message().c_str();
                  error_str += "</font>";
                  error_str += "<br>";
            } else {
                  KMessageBox::information(this, CALCULATOR->message()->message().c_str());
            }
            if(!CALCULATOR->nextMessage()) break;
      }
      if(!error_str.isEmpty() && new_text) {
            new_text->append(error_str);
      }
      if(strlst.size() > 1) { 
            if(error) KMessageBox::error(this, strlst.join("\n"), i18n("Errors"));
            else KMessageBox::error(this, strlst.join("\n"), i18n("Warnings"));
      } else if(strlst.size() == 1) {
            if(error) KMessageBox::error(this, strlst[0], i18n("Error"));
            else KMessageBox::error(this, strlst[0], i18n("Warning"));
      }
      error_timer->start(100);
}

void save_defs() {
      if(!CALCULATOR->saveDefinitions()) {
            KMessageBox::error(0, i18n("Couldn't write definitions"));
      }
}


void KQalculate::create_vmenu() {

      QPopupMenu *sub, *sub3;

      menu_variables->clear();
      sub = menu_variables;
      Variable *v;
      tree_struct *titem, *titem2;
      variable_cats.rit = variable_cats.items.rbegin();
      if(variable_cats.rit != variable_cats.items.rend()) {
            titem = &*variable_cats.rit;
            ++variable_cats.rit;
            titem->rit = titem->items.rbegin();
      } else {
            titem = NULL;
      }

      menu_variables_ids.clear();

      stack<QPopupMenu*> menus;
      menus.push(sub);
      sub3 = sub;
      while(titem) {
            sub = new QPopupMenu();
            QObject::connect(sub, SIGNAL(activated(int)), this, SLOT(onVariableMenuItemActivated(int)));
            if(titem->item.find('&') != string::npos) {
                  QString str2 = titem->item.c_str();
                  str2.replace("&", "&&");
                  sub3->insertItem(str2, sub, -1, 0);
            } else {
                  sub3->insertItem(titem->item.c_str(), sub, -1, 0);
            }
            menus.push(sub);
            sub3 = sub;
            for(size_t i = 0; i < titem->objects.size(); i++) {
                  v = (Variable*) titem->objects[i];
                  if(v->isActive() && !v->isHidden()) {
                        if(v->title(true).find('&') != string::npos) {
                              QString str2 = v->title(true).c_str();
                              str2.replace("&", "&&");
                              menu_variables_ids[sub->insertItem(str2)] = v;
                        } else {
                              menu_variables_ids[sub->insertItem(v->title(true).c_str())] = v;
                        }
                  }
            }
            while(titem && titem->rit == titem->items.rend()) {
                  titem = titem->parent;
                  menus.pop();
                  if(menus.size() > 0) sub3 = menus.top();
            }     
            if(titem) {
                  titem2 = &*titem->rit;
                  ++titem->rit;
                  titem = titem2;
                  titem->rit = titem->items.rbegin(); 
            }

      }

      for(size_t i = 0; i < variable_cats.objects.size(); i++) {        
            v = (Variable*) variable_cats.objects[i];
            if(v->isActive() && !v->isHidden()) {
                  menu_variables_ids[menu_variables->insertItem(v->title(true).c_str())] = v;
            }
      }           

}

void KQalculate::recreate_recent_variables() {
      recent_variable_ids.clear();
      bool b = false;
      for(size_t i = 0; i < recent_variables.size(); i++) {
            if(!CALCULATOR->stillHasVariable(recent_variables[i])) {
                  recent_variables.erase(recent_variables.begin() + i);
                  i--;
            } else {
                  if(!b) {
                        menu_variables->insertSeparator(0);
                        b = true;
                  }
                  int id = menu_variables->insertItem(recent_variables[i]->title(true).c_str(), -1, 0);
                  recent_variable_ids.push_back(id);
                  menu_variables_ids[id] = recent_variables[i];
            }
      }
}
void KQalculate::update_vmenu() {
      generate_variables_tree_struct();
      create_vmenu();
      recreate_recent_variables();
      if(variables_dialog) variables_dialog->updateVariableTree();
      update_completion();
}

void KQalculate::create_fmenu() {

      QPopupMenu *sub, *sub3;

      menu_functions->clear();
      sub = menu_functions;
      MathFunction *f;
      tree_struct *titem, *titem2;
      function_cats.rit = function_cats.items.rbegin();
      if(function_cats.rit != function_cats.items.rend()) {
            titem = &*function_cats.rit;
            ++function_cats.rit;
            titem->rit = titem->items.rbegin();
      } else {
            titem = NULL;
      }

      menu_functions_ids.clear();

      stack<QPopupMenu*> menus;
      menus.push(sub);
      sub3 = sub;
      while(titem) {
            sub = new QPopupMenu();
            QObject::connect(sub, SIGNAL(activated(int)), this, SLOT(onFunctionMenuItemActivated(int)));
            if(titem->item.find('&') != string::npos) {
                  QString str2 = titem->item.c_str();
                  str2.replace("&", "&&");
                  sub3->insertItem(str2, sub, -1, 0);
            } else {
                  sub3->insertItem(titem->item.c_str(), sub, -1, 0);
            }
            menus.push(sub);
            sub3 = sub;
            for(size_t i = 0; i < titem->objects.size(); i++) {
                  f = (MathFunction*) titem->objects[i];
                  if(f->isActive() && !f->isHidden()) {
                        if(f->title(true).find('&') != string::npos) {
                              QString str2 = f->title(true).c_str();
                              str2.replace("&", "&&");
                              menu_functions_ids[sub->insertItem(str2)] = f;
                        } else {
                              menu_functions_ids[sub->insertItem(f->title(true).c_str())] = f;
                        }
                  }
            }
            while(titem && titem->rit == titem->items.rend()) {
                  titem = titem->parent;
                  menus.pop();
                  if(menus.size() > 0) sub3 = menus.top();
            }     
            if(titem) {
                  titem2 = &*titem->rit;
                  ++titem->rit;
                  titem = titem2;
                  titem->rit = titem->items.rbegin(); 
            }

      }

      for(size_t i = 0; i < function_cats.objects.size(); i++) {
            f = (MathFunction*) function_cats.objects[i];
            if(f->isActive() && !f->isHidden()) {
                  menu_functions_ids[menu_functions->insertItem(f->title(true).c_str())] = f;
            }
      }           

}
void KQalculate::recreate_recent_functions() {
      recent_function_ids.clear();
      bool b = false;
      for(size_t i = 0; i < recent_functions.size(); i++) {
            if(!CALCULATOR->stillHasFunction(recent_functions[i])) {
                  recent_functions.erase(recent_functions.begin() + i);
                  i--;
            } else {
                  if(!b) {
                        menu_functions->insertSeparator(0);
                        b = true;
                  }
                  int id = menu_functions->insertItem(recent_functions[i]->title(true).c_str(), -1, 0);
                  recent_function_ids.push_back(id);
                  menu_functions_ids[id] = recent_functions[i];
            }
      }
}
void KQalculate::update_fmenu() {
      generate_functions_tree_struct();
      create_fmenu();
      recreate_recent_functions();
      if(functions_dialog) functions_dialog->updateFunctionTree();
      if(datasets_dialog) datasets_dialog->updateDataSetTree();
      update_completion();
}

void KQalculate::create_umenu() {

      QPopupMenu *sub, *sub3;

      menu_units->clear();
      sub = menu_units;
      Unit *u;
      tree_struct *titem, *titem2;
      unit_cats.rit = unit_cats.items.rbegin();
      if(unit_cats.rit != unit_cats.items.rend()) {
            titem = &*unit_cats.rit;
            ++unit_cats.rit;
            titem->rit = titem->items.rbegin();
      } else {
            titem = NULL;
      }

      menu_units_ids.clear();

      stack<QPopupMenu*> menus;
      menus.push(sub);
      sub3 = sub;
      while(titem) {
            sub = new QPopupMenu();
            QObject::connect(sub, SIGNAL(activated(int)), this, SLOT(onUnitMenuItemActivated(int)));
            if(titem->item.find('&') != string::npos) {
                  QString str2 = titem->item.c_str();
                  str2.replace("&", "&&");
                  sub3->insertItem(str2, sub, -1, 0);
            } else {
                  sub3->insertItem(titem->item.c_str(), sub, -1, 0);
            }
            menus.push(sub);
            sub3 = sub;
            for(size_t i = 0; i < titem->objects.size(); i++) {
                  u = (Unit*) titem->objects[i];
                  if(u->isActive() && !u->isHidden()) {
                        if(u->title(true).find('&') != string::npos) {
                              QString str2 = u->title(true).c_str();
                              str2.replace("&", "&&");
                              menu_units_ids[sub->insertItem(str2)] = u;
                        } else {
                              menu_units_ids[sub->insertItem(u->title(true).c_str())] = u;
                        }
                  }
            }
            while(titem && titem->rit == titem->items.rend()) {
                  titem = titem->parent;
                  menus.pop();
                  if(menus.size() > 0) sub3 = menus.top();
            }     
            if(titem) {
                  titem2 = &*titem->rit;
                  ++titem->rit;
                  titem = titem2;
                  titem->rit = titem->items.rbegin(); 
            }

      }

      for(size_t i = 0; i < unit_cats.objects.size(); i++) {
            u = (Unit*) unit_cats.objects[i];
            if(u->isActive() && !u->isHidden()) {
                  menu_units_ids[menu_units->insertItem(u->title(true).c_str())] = u;
            }
      }

      sub = new QPopupMenu();
      QObject::connect(sub, SIGNAL(activated(int)), this, SLOT(onUnitsPrefixMenuItemActivated(int)));
      menu_units->insertSeparator();
      menu_units->insertItem(i18n("Prefixes"), sub);
      int index = 0;
      Prefix *p = CALCULATOR->getPrefix(index);
      while(p) {
            QString pstr;
            switch(p->type()) {
                  case PREFIX_DECIMAL: {
                        QTextOStream(&pstr) << p->name(false, true, &can_display_unicode_string_function, (void*) menu_units).c_str() << "\t(10e" << ((DecimalPrefix*) p)->exponent() << ")";                     
                        break;
                  }
                  case PREFIX_BINARY: {
                        QTextOStream(&pstr) << p->name(false, true, &can_display_unicode_string_function, (void*) menu_units).c_str() << "\t(2e" << ((BinaryPrefix*) p)->exponent() << ")";
                        break;
                  }
                  case PREFIX_NUMBER: {                     
                        QTextOStream(&pstr) << p->name(false, true, &can_display_unicode_string_function, (void*) menu_units).c_str();
                        break;
                  }                 
            }
            menu_units_prefixes_ids[sub->insertItem(pstr)] = p;
            index++;
            p = CALCULATOR->getPrefix(index);
      }

}

void KQalculate::recreate_recent_units() {
      recent_unit_ids.clear();
      bool b = false;
      for(size_t i = 0; i < recent_units.size(); i++) {
            if(!CALCULATOR->stillHasUnit(recent_units[i])) {
                  recent_units.erase(recent_units.begin() + i);
                  i--;
            } else {
                  if(!b) {
                        menu_units->insertSeparator(0);
                        b = true;
                  }
                  int id = menu_units->insertItem(recent_units[i]->title(true).c_str(), -1, 0);
                  recent_unit_ids.push_back(id);
                  menu_units_ids[id] = recent_units[i];
            }
      }
}
void KQalculate::update_umenus() {
      generate_units_tree_struct();
      create_umenu();
      recreate_recent_units();
      create_toumenu();
      if(units_dialog) units_dialog->updateUnitTree();
      if(convert_to_unit_expression_dialog) convert_to_unit_expression_dialog->updateUnitTree();
      update_completion();
}

void KQalculate::create_toumenu() {

      QPopupMenu *sub, *sub3;

      menu_to_unit->clear();
      sub = menu_to_unit;
      Unit *u;
      tree_struct *titem, *titem2;
      unit_cats.rit = unit_cats.items.rbegin();
      if(unit_cats.rit != unit_cats.items.rend()) {
            titem = &*unit_cats.rit;
            ++unit_cats.rit;
            titem->rit = titem->items.rbegin();
      } else {
            titem = NULL;
      }

      menu_to_unit_ids.clear();

      stack<QPopupMenu*> menus;
      menus.push(sub);
      sub3 = sub;
      while(titem) {
            sub = new QPopupMenu();
            QObject::connect(sub, SIGNAL(activated(int)), this, SLOT(onConvertToUnitMenuItemActivated(int)));
            if(titem->item.find('&') != string::npos) {
                  QString str2 = titem->item.c_str();
                  str2.replace("&", "&&");
                  sub3->insertItem(str2, sub, -1, 0);
            } else {
                  sub3->insertItem(titem->item.c_str(), sub, -1, 0);
            }
            menus.push(sub);
            sub3 = sub;
            for(size_t i = 0; i < titem->objects.size(); i++) {
                  u = (Unit*) titem->objects[i];
                  if(u->isActive() && !u->isHidden()) {
                        if(u->title(true).find('&') != string::npos) {
                              QString str2 = u->title(true).c_str();
                              str2.replace("&", "&&");
                              menu_to_unit_ids[sub->insertItem(str2)] = u;
                        } else {
                              menu_to_unit_ids[sub->insertItem(u->title(true).c_str())] = u;
                        }
                  }
            }
            while(titem && titem->rit == titem->items.rend()) {
                  titem = titem->parent;
                  menus.pop();
                  if(menus.size() > 0) sub3 = menus.top();
            }     
            if(titem) {
                  titem2 = &*titem->rit;
                  ++titem->rit;
                  titem = titem2;
                  titem->rit = titem->items.rbegin(); 
            }

      }

      for(size_t i = 0; i < unit_cats.objects.size(); i++) {
            u = (Unit*) unit_cats.objects[i];
            if(u->isActive() && !u->isHidden()) {
                  menu_to_unit_ids[menu_to_unit->insertItem(u->title(true).c_str())] = u;
            }
      }

}

void KQalculate::create_setpmenu() {
      menu_set_prefix->clear();
      QObject::connect(menu_set_prefix, SIGNAL(activated(int)), this, SLOT(onSetPrefixMenuItemActivated(int)));
      int index = 0;
      menu_set_prefix_ids[menu_set_prefix->insertItem(i18n("No Prefix"))] = CALCULATOR->decimal_null_prefix;
      Prefix *p = CALCULATOR->getPrefix(index);
      while(p) {
            QString pstr;
            switch(p->type()) {
                  case PREFIX_DECIMAL: {
                        QTextOStream(&pstr) << p->name(false, true, &can_display_unicode_string_function, (void*) menu_units).c_str() << "\t(10e" << ((DecimalPrefix*) p)->exponent() << ")";                     
                        break;
                  }
                  case PREFIX_BINARY: {
                        QTextOStream(&pstr) << p->name(false, true, &can_display_unicode_string_function, (void*) menu_units).c_str() << "\t(2e" << ((BinaryPrefix*) p)->exponent() << ")";
                        break;
                  }
                  case PREFIX_NUMBER: {                     
                        QTextOStream(&pstr) << p->name(false, true, &can_display_unicode_string_function, (void*) menu_units).c_str();
                        break;
                  }                 
            }
            menu_set_prefix_ids[menu_set_prefix->insertItem(pstr)] = p;
            index++;
            p = CALCULATOR->getPrefix(index);
      }
}


void KQalculate::insert_text(QString name) {
      expressionEdit->insert(name);
      expressionEdit->setFocus();
}
/*
      insert one-argument function when button clicked
*/
void KQalculate::insertButtonFunction(QString text, bool append_space) {
      if(expressionEdit->hasSelectedText()) {
            //set selection as argument
            text += "(";
            text += expressionEdit->selectedText();
            text += ")";
            insert_text(text);
      } else {
            //one-argument functions do not need parenthesis
            if(append_space) {
                  text += " ";
            }
            insert_text(text);
      }
}
void KQalculate::insertButtonFunction(MathFunction *f) {
      const ExpressionName *ename = &f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressionEdit);
      if(f->minargs() > 1) {
            QString text = ename->name.c_str();
            bool b = expressionEdit->hasSelectedText();
            text += "(";
            if(b) text += expressionEdit->selectedText();
            for(int i = 1; i < f->minargs(); i++) {
                  text += CALCULATOR->getComma().c_str();
                  text += " ";
            }
            text += ")";
            insert_text(text);
            if(b) expressionEdit->cursorBackward(false, 1 + (f->minargs() - 2) * 2);
            else expressionEdit->cursorBackward(false, 1 + (f->minargs() - 1) * 2);
      } else {
            insertButtonFunction(ename->name.c_str(), !text_length_is_one(ename->name));
      }
}

void KQalculate::function_inserted(MathFunction *object) {
      if(!object) {
            return;
      }
      if(recent_function_ids.size() <= 0) {
            menu_functions->insertSeparator(0);
      }
      for(size_t i = 0; i < recent_functions.size(); i++) {
            if(recent_functions[i] == object) {
                  recent_functions.erase(recent_functions.begin() + i);
                  menu_functions->removeItem(recent_function_ids[i]);
                  recent_function_ids.erase(recent_function_ids.begin() + i);
                  break;
            }
      }
      if(recent_function_ids.size() >= 5) {
            recent_functions.erase(recent_functions.begin());
            menu_functions->removeItem(recent_function_ids[0]);
            recent_function_ids.erase(recent_function_ids.begin());
      }
      int id = menu_functions->insertItem(object->title(true).c_str(), -1, 0);
      menu_functions_ids[id] = object;
      recent_function_ids.push_back(id);
      recent_functions.push_back(object);
}
void KQalculate::variable_inserted(Variable *object) {
      if(!object) {
            return;
      }
      if(recent_variable_ids.size() <= 0) {
            menu_variables->insertSeparator(0);
      }
      for(size_t i = 0; i < recent_variables.size(); i++) {
            if(recent_variables[i] == object) {
                  recent_variables.erase(recent_variables.begin() + i);
                  menu_variables->removeItem(recent_variable_ids[i]);
                  recent_variable_ids.erase(recent_variable_ids.begin() + i);
                  break;
            }
      }
      if(recent_variable_ids.size() >= 5) {
            recent_variables.erase(recent_variables.begin());
            menu_variables->removeItem(recent_variable_ids[0]);
            recent_variable_ids.erase(recent_variable_ids.begin());
      }
      int id = menu_variables->insertItem(object->title(true).c_str(), -1, 0);
      menu_variables_ids[id] = object;
      recent_variable_ids.push_back(id);
      recent_variables.push_back(object);
}
void KQalculate::unit_inserted(Unit *object) {
      if(!object) {
            return;
      }
      if(recent_unit_ids.size() <= 0) {
            menu_units->insertSeparator(0);
      }
      for(size_t i = 0; i < recent_units.size(); i++) {
            if(recent_units[i] == object) {
                  recent_units.erase(recent_units.begin() + i);
                  menu_units->removeItem(recent_unit_ids[i]);
                  recent_unit_ids.erase(recent_unit_ids.begin() + i);
                  break;
            }
      }
      if(recent_unit_ids.size() >= 5) {
            recent_units.erase(recent_units.begin());
            menu_units->removeItem(recent_unit_ids[0]);
            recent_unit_ids.erase(recent_unit_ids.begin());
      }
      int id = menu_units->insertItem(object->title(true).c_str(), -1, 0);
      menu_units_ids[id] = object;
      recent_unit_ids.push_back(id);
      recent_units.push_back(object);
}

void KQalculate::onVariableMenuItemActivated(int id) {
      if(!menu_variables_ids.contains(id)) return;
      Variable *v = menu_variables_ids[id];
      if(!CALCULATOR->stillHasVariable(v)) {
            KMessageBox::error(this, i18n("Variable does not exist anymore."));
            update_vmenu();
            return;
      }
      insert_text(v->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressionEdit).name.c_str());
      variable_inserted(v);
}
void KQalculate::onFunctionMenuItemActivated(int id) {
      if(!menu_functions_ids.contains(id)) return;
      MathFunction *f = menu_functions_ids[id];
      insertFunction(f, this);
}
void KQalculate::onUnitMenuItemActivated(int id) {
      if(!menu_units_ids.contains(id)) return;
      Unit *u = menu_units_ids[id];
      if(!CALCULATOR->stillHasUnit(u)) {
            KMessageBox::error(this, i18n("Unit does not exist anymore."));
            update_umenus();
            return;
      }
      if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
            insert_text(((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressionEdit).c_str());
      } else {
            insert_text(u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressionEdit).name.c_str());
      }
      unit_inserted(u);
}
void KQalculate::onUnitsPrefixMenuItemActivated(int id) {
      if(!menu_units_prefixes_ids.contains(id)) return;
      insert_text(menu_units_prefixes_ids[id]->name(printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressionEdit).c_str());
}

void KQalculate::update_completion() {
      expressionEdit->updateCompletion();
      if(plot_dialog) {
            plot_dialog->expressionEdit->updateCompletion();
      }
}

void KQalculate::set_unicode_buttons() {
      if(printops.use_unicode_signs) {
            if(can_display_unicode_string_function(SIGN_MINUS, (void*) kpMinus)) kpMinus->setText(SIGN_MINUS);
            else kpMinus->setText(MINUS);
            if(can_display_unicode_string_function(SIGN_PLUS, (void*) kpPlus)) kpPlus->setText(SIGN_PLUS);
            else kpPlus->setText(PLUS);
            if(can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) kpTimes)) kpTimes->setText(SIGN_MULTIPLICATION);
            else kpTimes->setText(MULTIPLICATION);
            if(can_display_unicode_string_function(SIGN_DIVISION_SLASH, (void*) kpDivision)) kpDivision->setText(SIGN_DIVISION_SLASH);
            else if(can_display_unicode_string_function(SIGN_DIVISION, (void*) kpDivision)) kpDivision->setText(SIGN_DIVISION);
            else kpDivision->setText(DIVISION); 
            if(can_display_unicode_string_function(SIGN_SQRT, (void*) kpSqrt)) kpSqrt->setText(SIGN_SQRT);
            else kpSqrt->setText("Sqrt");
            if(can_display_unicode_string_function(SIGN_MULTIDOT, (void*) kpDot)) kpDot->setText(SIGN_MULTIDOT);
            else kpDot->setText(CALCULATOR->getDecimalPoint().c_str());
      } else {
            kpMinus->setText(MINUS);
            kpPlus->setText(PLUS);
            kpTimes->setText(MULTIPLICATION);
            kpDivision->setText(DIVISION);      
            kpSqrt->setText("Sqrt");
            kpDot->setText(CALCULATOR->getDecimalPoint().c_str());
      }
}

void KQalculate::onExpressionChanged() {
      expression_has_changed = true;
      expression_has_changed2 = true;
      clearresult();    
      if(!expressionEdit->dont_change_index) expressionEdit->expression_history_index = -1;
      displayParseStatus();
}

void KQalculate::execute() {
      execute_expression_force = true;
      execute_expression2();
}

bool KQalculate::fetch_exchange_rates(int) {
      KURL url(CALCULATOR->getExchangeRatesUrl().c_str());
      QString filename(CALCULATOR->getExchangeRatesFileName().c_str());
#if KDE_VERSION_MAJOR < 4 && KDE_VERSION_MINOR < 2
      if(KIO::NetAccess::download(url, filename)) {
#else
      if(KIO::NetAccess::download(url, filename, this)) {
#endif
            return true;
      } else {
            QString errorstr = i18n("Failed to download exchange rates from ECB.");
            errorstr += "\n";
            errorstr += KIO::NetAccess::lastErrorString();
            KMessageBox::error(this, errorstr);
            return false;
      }
}

void KQalculate::onErrorTimeout() {
      if(CALCULATOR->checkSaveFunctionCalled()) {
            update_vmenu();
      }
      display_errors();
}

void KQalculate::toggleHistory(bool on) {
      if(on) {
            bool b = mainStack->isVisible();
            int new_height = height() - bottomLine->height();
            if(mainStack->height() > history_height) history_height = mainStack->height();
            bottomLine->hide();
            mainStack->show();
            mainStack->raiseWidget(1);
            keypadButton->setOn(false);
            mainStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, false);
            resultLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum, false);
            if(!b) {
                  new_height += history_height;
                  resize(width(), new_height);
            } else if(history_height != mainStack->height()) {
                  resize(width(), height() - mainStack->height() + history_height);
            }
      } else {
            if(!keypadButton->isOn()) {
                  history_height = mainStack->height();
                  int new_height = height() - mainStack->height();
                  mainStack->hide();
                  bottomLine->show();
                  qApp->processEvents();
                  if(new_height < height()) resize(width(), new_height + bottomLine->height());
                  mainStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum, false);
                  resultLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, false);
            }
      }
}

void KQalculate::toggleKeypad(bool on) {
      if(on) {
            bool b = mainStack->isVisible();
            if(b) history_height = mainStack->height();
            int new_height = height() - bottomLine->height();
            mainStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum, false);
            resultLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, false);
            mainStack->show();
            bottomLine->hide();
            mainStack->raiseWidget(0);
            historyButton->setOn(false);
            if(!b) {
                  qApp->processEvents();
                  new_height += mainStack->height();
                  resize(width(), new_height);
            } else {
                  resize(width(), minimumSizeHint().height());
            }
      } else {
            if(!historyButton->isOn()) {        
                  int new_height = height() - mainStack->height();
                  mainStack->hide();
                  bottomLine->show();
                  qApp->processEvents();
                  if(new_height < height()) resize(width(), new_height + bottomLine->height());
                  mainStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum, false);
                  resultLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding, false);
            }
      }
}

void KQalculate::abbreviateNames(bool b) {
      printops.abbreviate_names = b;
      result_format_updated();
}

void KQalculate::approximationAlwaysExact() {
      kpExact->blockSignals(true);
      evalops.approximation = APPROXIMATION_EXACT;
      expression_calculation_updated();
      kpExact->setOn(true);
      kpExact->blockSignals(false);
}
void KQalculate::approximationTryExact() {
      kpExact->blockSignals(true);
      evalops.approximation = APPROXIMATION_TRY_EXACT;
      expression_calculation_updated();
      kpExact->setOn(false);
      kpExact->blockSignals(false);
}
void KQalculate::approximationApproximate() {
      kpExact->blockSignals(true);
      evalops.approximation = APPROXIMATION_APPROXIMATE;
      expression_calculation_updated();
      kpExact->setOn(false);
      kpExact->blockSignals(false);
}

void KQalculate::fractionalDisplayDecimal() {
      kpFraction->blockSignals(true);
      printops.number_fraction_format = FRACTION_DECIMAL;
      result_format_updated();
      kpFraction->setOn(false);
      kpFraction->blockSignals(false);
}
void KQalculate::fractionalDisplayDecimalTryExact() {
      kpFraction->blockSignals(true);
      printops.number_fraction_format = FRACTION_DECIMAL_EXACT;
      result_format_updated();
      kpFraction->setOn(false);
      kpFraction->blockSignals(false);
}
void KQalculate::fractionalDisplayFraction() {
      kpFraction->blockSignals(true);
      printops.number_fraction_format = FRACTION_FRACTIONAL;
      result_format_updated();
      kpFraction->setOn(true);
      kpFraction->blockSignals(false);
}
void KQalculate::fractionalDisplayCombined() {
      kpFraction->blockSignals(true);
      printops.number_fraction_format = FRACTION_COMBINED;
      result_format_updated();
      kpFraction->setOn(true);
      kpFraction->blockSignals(false);
}

void KQalculate::numericalDisplayNormal() {
      kpNumericCombo->blockSignals(true);
      printops.min_exp = EXP_PRECISION;
      printops.negative_exponents = false;
      printops.sort_options.minus_last = true;
      result_format_updated();
      kpNumericCombo->setCurrentItem(0);
      kpNumericCombo->blockSignals(false);
}
void KQalculate::numericalDisplayScientific() {
      kpNumericCombo->blockSignals(true);
      printops.min_exp = EXP_SCIENTIFIC;
      printops.negative_exponents = true;
      printops.sort_options.minus_last = false;
      result_format_updated();
      kpNumericCombo->setCurrentItem(1);
      kpNumericCombo->blockSignals(false);
}
void KQalculate::numericalDisplayPurelyScientific() {
      kpNumericCombo->blockSignals(true);
      printops.min_exp = EXP_PURE;
      printops.negative_exponents = true;
      printops.sort_options.minus_last = false;
      result_format_updated();
      kpNumericCombo->setCurrentItem(2);
      kpNumericCombo->blockSignals(false);
}
void KQalculate::numericalDisplaySimple() {
      kpNumericCombo->blockSignals(true);
      printops.min_exp = EXP_NONE;
      printops.negative_exponents = false;
      printops.sort_options.minus_last = true;
      result_format_updated();
      kpNumericCombo->setCurrentItem(3);
      kpNumericCombo->blockSignals(false);
}

void KQalculate::roundHalfwayNumbersToEven(bool b) {
      printops.round_halfway_to_even = b;
      result_format_updated();
}


void KQalculate::indicateInfiniteSeries(bool b) {
      printops.indicate_infinite_series = b;
      result_format_updated();
}

void KQalculate::showEndingZeroes(bool b) {
      printops.show_ending_zeroes = b;
      result_format_updated();
}

void KQalculate::updateBaseOther() {
      if(set_base_other_dialog && printops.base >= 2 && printops.base <= 36) {
            set_base_other_dialog->baseBox->blockSignals(true);
            set_base_other_dialog->baseBox->setValue(printops.base);
            set_base_other_dialog->baseBox->blockSignals(false);
      }
}
void KQalculate::numberBaseBinary() {
      kpBaseCombo->blockSignals(true);
      printops.base = BASE_BINARY;
      updateBaseOther();
      result_format_updated();
      kpBaseCombo->setCurrentItem(0);
      kpBaseCombo->blockSignals(false);
}
void KQalculate::numberBaseOctal() {
      kpBaseCombo->blockSignals(true);
      printops.base = BASE_OCTAL;
      updateBaseOther();
      result_format_updated();
      kpBaseCombo->setCurrentItem(1);
      kpBaseCombo->blockSignals(false);
}
void KQalculate::numberBaseDecimal() {
      kpBaseCombo->blockSignals(true);
      printops.base = BASE_DECIMAL;
      updateBaseOther();
      result_format_updated();
      kpBaseCombo->setCurrentItem(2);
      kpBaseCombo->blockSignals(false);
}
void KQalculate::numberBaseHexadecimal() {
      kpBaseCombo->blockSignals(true);
      printops.base = BASE_HEXADECIMAL;
      updateBaseOther();
      result_format_updated();
      kpBaseCombo->setCurrentItem(3);
      kpBaseCombo->blockSignals(false);
}
void KQalculate::numberBaseSexagesimal() {
      kpBaseCombo->blockSignals(true);
      printops.base = BASE_SEXAGESIMAL;
      updateBaseOther();
      result_format_updated();
      kpBaseCombo->setCurrentItem(4);
      kpBaseCombo->blockSignals(false);
}
void KQalculate::numberBaseTimeFormat() {
      kpBaseCombo->blockSignals(true);
      printops.base = BASE_TIME;
      updateBaseOther();
      result_format_updated();
      kpBaseCombo->setCurrentItem(5);
      kpBaseCombo->blockSignals(false);
}
void KQalculate::numberBaseRomanNumerals() {
      kpBaseCombo->blockSignals(true);
      printops.base = BASE_ROMAN_NUMERALS;
      updateBaseOther();
      result_format_updated();
      kpBaseCombo->setCurrentItem(6);
      kpBaseCombo->blockSignals(false);
}
void KQalculate::setOtherNumberBase(int value) {
      switch(value) {
            case BASE_BINARY: {
                  if(printops.base == value) {
                        ActionNumberBaseBinary->setChecked(true);
                        kpBaseCombo->blockSignals(true);
                        kpBaseCombo->setCurrentItem(0);
                        kpBaseCombo->blockSignals(false);
                  } else {
                        ActionNumberBaseBinary->activate();
                  }
                  break;
            }
            case BASE_OCTAL: {
                  if(printops.base == value) {
                        ActionNumberBaseOctal->setChecked(true);
                        kpBaseCombo->blockSignals(true);
                        kpBaseCombo->setCurrentItem(1);
                        kpBaseCombo->blockSignals(false);
                  } else {
                        ActionNumberBaseOctal->activate();
                  }
                  break;
            }
            case BASE_DECIMAL: {
                  if(printops.base == value) {
                        ActionNumberBaseDecimal->setChecked(true);
                        kpBaseCombo->blockSignals(true);
                        kpBaseCombo->setCurrentItem(2);
                        kpBaseCombo->blockSignals(false);
                  } else {
                        ActionNumberBaseDecimal->activate();
                  }
                  break;
            }
            case BASE_HEXADECIMAL: {
                  if(printops.base == value) {
                        ActionNumberBaseHexadecimal->setChecked(true);
                        kpBaseCombo->blockSignals(true);
                        kpBaseCombo->setCurrentItem(3);
                        kpBaseCombo->blockSignals(false);
                  } else {
                        ActionNumberBaseHexadecimal->activate();
                  }
                  break;
            }
            default: {
                  ActionNumberBaseBinary->setChecked(false);
                  ActionNumberBaseOctal->setChecked(false);
                  ActionNumberBaseDecimal->setChecked(false);
                  ActionNumberBaseHexadecimal->setChecked(false);
                  ActionNumberBaseSexagesimal->setChecked(false);
                  ActionNumberBaseTimeFormat->setChecked(false);
                  ActionNumberBaseRomanNumerals->setChecked(false);
                  kpBaseCombo->blockSignals(true);
                  bool b = (printops.base == value);
                  printops.base = value;
                  kpBaseCombo->setCurrentItem(7);
                  kpBaseCombo->blockSignals(false);
                  if(!b) result_format_updated();
                  break;
            }
      }
}
void KQalculate::numberBaseOther() {
      if(!set_base_other_dialog) {
            set_base_other_dialog = new QalculateSetBaseOtherDialog(this);
            if(printops.base >= 2 && printops.base <= 36) set_base_other_dialog->baseBox->setValue(printops.base);
            else set_base_other_dialog->baseBox->setValue(10);
            QObject::connect(set_base_other_dialog->baseBox, SIGNAL(valueChanged(int)), this, SLOT(setOtherNumberBase(int)));
      }
      setOtherNumberBase(set_base_other_dialog->baseBox->value());
      set_base_other_dialog->show();
}

void KQalculate::setBaseInExpressionFromDialogBox(int value) {
      evalops.parse_options.base = value;
      expression_format_updated(true);
}
void KQalculate::setBaseInExpressionFromDialogGroup(int id) {
      switch(id) {
            case 0: {
                  set_base_in_expression_dialog->baseBox->setEnabled(false);
                  evalops.parse_options.base = BASE_BINARY;
                  break;
            }
            case 1: {
                  set_base_in_expression_dialog->baseBox->setEnabled(false);
                  evalops.parse_options.base = BASE_OCTAL;
                  break;
            }
            case 2: {
                  set_base_in_expression_dialog->baseBox->setEnabled(false);
                  evalops.parse_options.base = BASE_DECIMAL;
                  break;
            }
            case 3: {
                  set_base_in_expression_dialog->baseBox->setEnabled(false);
                  evalops.parse_options.base = BASE_HEXADECIMAL;
                  break;
            }
            case 4: {
                  set_base_in_expression_dialog->baseBox->setEnabled(true);
                  evalops.parse_options.base = set_base_in_expression_dialog->baseBox->value();
                  break;
            }
            case 5: {
                  set_base_in_expression_dialog->baseBox->setEnabled(false);
                  evalops.parse_options.base = BASE_ROMAN_NUMERALS;
                  break;
            }
      }
      expression_format_updated(true);
}
void KQalculate::setBaseInExpression() {
      if(!set_base_in_expression_dialog) {
            set_base_in_expression_dialog = new QalculateSetBaseInExpressionDialog(this);
            QObject::connect(set_base_in_expression_dialog->radiogroup, SIGNAL(clicked(int)), this, SLOT(setBaseInExpressionFromDialogGroup(int)));
            QObject::connect(set_base_in_expression_dialog->baseBox, SIGNAL(valueChanged(int)), this, SLOT(setBaseInExpressionFromDialogBox(int)));
      }
      set_base_in_expression_dialog->baseBox->blockSignals(true);
      set_base_in_expression_dialog->radiogroup->blockSignals(true);
      set_base_in_expression_dialog->baseBox->setEnabled(false);
      switch(evalops.parse_options.base) {
            case BASE_BINARY: {
                  set_base_in_expression_dialog->radiogroup->setButton(0);
                  break;
            }
            case BASE_OCTAL: {
                  set_base_in_expression_dialog->radiogroup->setButton(1);
                  break;
            }
            case BASE_DECIMAL: {
                  set_base_in_expression_dialog->radiogroup->setButton(2);
                  break;
            }
            case BASE_HEXADECIMAL: {
                  set_base_in_expression_dialog->radiogroup->setButton(3);
                  break;
            }
            case BASE_ROMAN_NUMERALS: {
                  set_base_in_expression_dialog->radiogroup->setButton(5);
                  break;
            }
            default: {
                  set_base_in_expression_dialog->radiogroup->setButton(4);
                  set_base_in_expression_dialog->baseBox->setEnabled(true);
                  set_base_in_expression_dialog->baseBox->setValue(evalops.parse_options.base);
            }
      }
      set_base_in_expression_dialog->baseBox->blockSignals(false);
      set_base_in_expression_dialog->radiogroup->blockSignals(false);
      set_base_in_expression_dialog->show();
}

void KQalculate::nonZeroDenominators(bool b) {
      evalops.assume_denominators_nonzero = b;
      expression_calculation_updated();
}
void KQalculate::warnAboutDenominatorsAssumedNonZero(bool b) {
      evalops.warn_about_denominators_assumed_nonzero = b;
      if(evalops.warn_about_denominators_assumed_nonzero) expression_calculation_updated();
}

void KQalculate::readPrecision(bool b) {
      if(b) evalops.parse_options.read_precision = READ_PRECISION_WHEN_DECIMALS;
      else evalops.parse_options.read_precision = DONT_READ_PRECISION;
      expression_format_updated(true);
}

void KQalculate::limitImplicitMultiplication(bool b) {
      evalops.parse_options.limit_implicit_multiplication = b;
      printops.limit_implicit_multiplication = b;
      expression_format_updated(true);
      result_format_updated();
}

void KQalculate::rpnMode(bool b) {
      evalops.parse_options.rpn = b;
      expression_format_updated(false);
}

void KQalculate::setMinDecimals(int i) {
      printops.min_decimals = i;
      if(i <= 0) printops.use_min_decimals = false;
      else printops.use_min_decimals = true;
      result_format_updated();      
}
void KQalculate::setMaxDecimals(int i) {
      printops.max_decimals = i;
      if(i < 0) printops.use_max_decimals = false;
      else printops.use_max_decimals = true;
      result_format_updated();      
}

void KQalculate::decimals() {
      if(!decimalsDialog) {
            decimalsDialog = new QalculateDecimalsDialog(this);
            QObject::connect(decimalsDialog->minDecimalsBox, SIGNAL(valueChanged(int)), this, SLOT(setMinDecimals(int)));
            QObject::connect(decimalsDialog->maxDecimalsBox, SIGNAL(valueChanged(int)), this, SLOT(setMaxDecimals(int)));
      }
      decimalsDialog->minDecimalsBox->blockSignals(true);
      decimalsDialog->maxDecimalsBox->blockSignals(true);
      if(printops.use_min_decimals && printops.min_decimals > 0) decimalsDialog->minDecimalsBox->setValue(printops.min_decimals);
      else decimalsDialog->minDecimalsBox->setValue(0);
      if(printops.use_max_decimals && printops.max_decimals >= 0) decimalsDialog->maxDecimalsBox->setValue(printops.max_decimals);
      else decimalsDialog->maxDecimalsBox->setValue(-1);
      decimalsDialog->minDecimalsBox->blockSignals(false);
      decimalsDialog->maxDecimalsBox->blockSignals(false);
      decimalsDialog->show();
}

void KQalculate::setPrecision(int i) {
      if(i != CALCULATOR->getPrecision()) CALCULATOR->setPrecision(i);
}
void KQalculate::precision() {
      if(!precisionDialog) {
            precisionDialog = new QalculatePrecisionDialog(this);
            QObject::connect(precisionDialog, SIGNAL(applyClicked()), this, SLOT(precisionRecalculate()));
            QObject::connect(precisionDialog->precisionBox, SIGNAL(valueChanged(int)), this, SLOT(setPrecision(int)));
      }
      precisionDialog->precisionBox->setValue(CALCULATOR->getPrecision());
      precisionDialog->show();
}

void KQalculate::precisionRecalculate() {
      if(precisionDialog->precisionBox->value() != CALCULATOR->getPrecision()) CALCULATOR->setPrecision(precisionDialog->precisionBox->value());
      expression_calculation_updated();
}

void KQalculate::assumptionTypeUnknown() {
      CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NONE);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionTypeNonMatrix() {
      CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NONMATRIX);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionTypeNumber() {
      CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_NUMBER);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionTypeComplex() {
      CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_COMPLEX);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionTypeReal() {
      CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_REAL);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionTypeRational() {
      CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_RATIONAL);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionTypeInteger() {
      CALCULATOR->defaultAssumptions()->setType(ASSUMPTION_TYPE_INTEGER);
      setAssumptionsMenu();
      expression_calculation_updated();
}

void KQalculate::assumptionSignUnknown() {
      CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_UNKNOWN);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionSignNonZero() {
      CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONZERO);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionSignPositive() {
      CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_POSITIVE);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionSignNonNegative() {
      CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONNEGATIVE);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionSignNegative() {
      CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NEGATIVE);
      setAssumptionsMenu();
      expression_calculation_updated();
}
void KQalculate::assumptionSignNonPositive() {
      CALCULATOR->defaultAssumptions()->setSign(ASSUMPTION_SIGN_NONPOSITIVE);
      setAssumptionsMenu();
      expression_calculation_updated();
}

void KQalculate::algebraicModeSimplify() {
      evalops.structuring = STRUCTURING_SIMPLIFY;
      printops.allow_factorization = false;
      expression_calculation_updated();
}
void KQalculate::algebraicModeFactorize() {
      evalops.structuring = STRUCTURING_FACTORIZE;
      printops.allow_factorization = true;
      expression_calculation_updated();
}
void KQalculate::algebraicModeNone() {
      evalops.structuring = STRUCTURING_NONE;
      printops.allow_factorization = false;
      expression_calculation_updated();
}

void KQalculate::onModesMenuItemActivated(int id) {
      loadMode(menu_modes->indexOf(id));
}
void KQalculate::loadMode(int index) {
      if(index < 0) return;
      size_t i = (size_t) index;
      if(i >= modes.size()) return;
      printops.min_decimals = modes[i].po.min_decimals;
      printops.use_min_decimals = modes[i].po.use_min_decimals;
      printops.max_decimals = modes[i].po.max_decimals;
      printops.use_max_decimals = modes[i].po.use_max_decimals;   
      CALCULATOR->setPrecision(modes[i].precision);
      printops.min_exp = modes[i].po.min_exp;
      printops.negative_exponents = modes[i].po.negative_exponents;
      printops.sort_options.minus_last = modes[i].po.sort_options.minus_last;
      printops.number_fraction_format = modes[i].po.number_fraction_format;   
      printops.use_unit_prefixes = modes[i].po.use_unit_prefixes;
      printops.abbreviate_names = modes[i].po.abbreviate_names;
      printops.use_all_prefixes = modes[i].po.use_all_prefixes;
      printops.use_denominator_prefix = modes[i].po.use_denominator_prefix;
      printops.place_units_separately = modes[i].po.place_units_separately;
      evalops.auto_post_conversion = modes[i].eo.auto_post_conversion;  
      printops.base = modes[i].po.base;
      evalops.parse_options.base = modes[i].eo.parse_options.base;
      evalops.parse_options.read_precision = modes[i].eo.parse_options.read_precision;
      evalops.assume_denominators_nonzero = modes[i].eo.assume_denominators_nonzero;
      evalops.warn_about_denominators_assumed_nonzero = modes[i].eo.warn_about_denominators_assumed_nonzero;
      evalops.parse_options.angle_unit = modes[i].eo.parse_options.angle_unit;
      evalops.parse_options.functions_enabled = modes[i].eo.parse_options.functions_enabled;
      evalops.parse_options.variables_enabled = modes[i].eo.parse_options.variables_enabled;
      evalops.calculate_functions = modes[i].eo.calculate_functions;    
      evalops.calculate_variables = modes[i].eo.calculate_variables;    
      evalops.sync_units = modes[i].eo.sync_units;    
      evalops.parse_options.unknowns_enabled = modes[i].eo.parse_options.unknowns_enabled;
      evalops.parse_options.units_enabled = modes[i].eo.parse_options.units_enabled;
      evalops.allow_complex = modes[i].eo.allow_complex;
      evalops.allow_infinite = modes[i].eo.allow_infinite;
      printops.indicate_infinite_series = modes[i].po.indicate_infinite_series;
      printops.show_ending_zeroes = modes[i].po.show_ending_zeroes;
      printops.round_halfway_to_even = modes[i].po.round_halfway_to_even;
      evalops.approximation = modes[i].eo.approximation;    
      evalops.parse_options.rpn = modes[i].eo.parse_options.rpn;
      evalops.parse_options.limit_implicit_multiplication = modes[i].eo.parse_options.limit_implicit_multiplication;
      printops.limit_implicit_multiplication = modes[i].po.limit_implicit_multiplication;
      printops.spacious = modes[i].po.spacious;
      printops.excessive_parenthesis = modes[i].po.excessive_parenthesis;
      printops.short_multiplication = modes[i].po.short_multiplication;
      CALCULATOR->defaultAssumptions()->setType(modes[i].at);
      CALCULATOR->defaultAssumptions()->setSign(modes[i].as);
      
      setModeActions();
      
      if(decimalsDialog) {
            decimalsDialog->minDecimalsBox->blockSignals(true);
            decimalsDialog->maxDecimalsBox->blockSignals(true);
            if(printops.use_min_decimals && printops.min_decimals > 0) decimalsDialog->minDecimalsBox->setValue(printops.min_decimals);
            else decimalsDialog->minDecimalsBox->setValue(0);
            if(printops.use_max_decimals && printops.max_decimals >= 0) decimalsDialog->maxDecimalsBox->setValue(printops.max_decimals);
            else decimalsDialog->maxDecimalsBox->setValue(-1);
            decimalsDialog->minDecimalsBox->blockSignals(false);
            decimalsDialog->maxDecimalsBox->blockSignals(false);
      }
      if(precisionDialog) {
            precisionDialog->precisionBox->setValue(CALCULATOR->getPrecision());
      }
      updateBaseOther();
      if(set_base_in_expression_dialog) {
            set_base_in_expression_dialog->baseBox->blockSignals(true);
            set_base_in_expression_dialog->radiogroup->blockSignals(true);
            set_base_in_expression_dialog->baseBox->setEnabled(false);
            switch(evalops.parse_options.base) {
                  case BASE_BINARY: {
                        set_base_in_expression_dialog->radiogroup->setButton(0);
                        break;
                  }
                  case BASE_OCTAL: {
                        set_base_in_expression_dialog->radiogroup->setButton(1);
                        break;
                  }
                  case BASE_DECIMAL: {
                        set_base_in_expression_dialog->radiogroup->setButton(2);
                        break;
                  }
                  case BASE_HEXADECIMAL: {
                        set_base_in_expression_dialog->radiogroup->setButton(3);
                        break;
                  }
                  case BASE_ROMAN_NUMERALS: {
                        set_base_in_expression_dialog->radiogroup->setButton(5);
                        break;
                  }
                  default: {
                        set_base_in_expression_dialog->radiogroup->setButton(4);
                        set_base_in_expression_dialog->baseBox->setEnabled(true);
                        set_base_in_expression_dialog->baseBox->setValue(evalops.parse_options.base);
                  }
            }
            set_base_in_expression_dialog->baseBox->blockSignals(false);
            set_base_in_expression_dialog->radiogroup->blockSignals(false);
      }
      
      update_status_text();
      printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
      setResult(NULL, true, false, false);      
      expression_has_changed2 = true;
      displayParseStatus();
      execute_expression(false);
      expressionEdit->setFocus();
      
} 
void KQalculate::saveModeAs() {
      bool b_ok = false;
      QStringList mode_names;
      for(size_t i = 2; i < modes.size(); i++) {
            mode_names += modes[i].name;
      }
      QString name;
run_save_mode_dialog:   
      name = KInputDialog::getItem(i18n("Save Mode"), i18n("Mode Name:"), mode_names, modes.size() - 3, true, &b_ok, this).stripWhiteSpace();
      if(b_ok) {
            bool new_mode = true;
            if(name.isEmpty()) {
                  KMessageBox::error(this, i18n("Empty mode name."));
                  goto run_save_mode_dialog;
            }
            if(name == modes[0].name) {
                  KMessageBox::error(this, i18n("Preset mode cannot be overwritten."));
                  goto run_save_mode_dialog;
            }
            size_t index = save_mode_as(name, &new_mode);
            if(new_mode) {
                  menu_modes->insertItem(modes[index].name, -1, index);
                  ActionDeleteMode->setEnabled(true);
            }
      }
}
void KQalculate::deleteMode() {
      bool b_ok = false;
      QStringList mode_names;
      for(size_t i = 2; i < modes.size(); i++) {
            mode_names += modes[i].name;
      }
      QString name = KInputDialog::getItem(i18n("Delete Mode"), i18n("Mode:"), mode_names, 0, false, &b_ok, this).stripWhiteSpace();
      if(b_ok) {
            for(size_t i = 2; i < modes.size(); i++) {
                  if(modes[i].name == name) {
                        modes.erase(modes.begin() + i);
                        menu_modes->removeItemAt(i);
                        if(modes.size() < 3) {
                              ActionDeleteMode->setEnabled(false);
                        }
                  }
            }
      }
}
void KQalculate::saveMode() {
      save_mode();
}

void KQalculate::aboutToQuit() {
      if(plot_dialog) plot_dialog->saveMode();
      if(save_mode_on_exit) {
            save_mode();
      } else {
            save_preferences();
      }
      if(save_defs_on_exit) {
            save_defs();
      }
      pthread_cancel(view_thread);
      CALCULATOR->terminateThreads();
}

void KQalculate::angleUnitDegrees() {
      kpAngleGroup->blockSignals(true);
      evalops.parse_options.angle_unit = ANGLE_UNIT_DEGREES;
      expression_format_updated(true);
      kpAngleGroup->setButton(0);
      kpAngleGroup->blockSignals(false);
}
void KQalculate::angleUnitRadians() {
      kpAngleGroup->blockSignals(true);
      evalops.parse_options.angle_unit = ANGLE_UNIT_RADIANS;
      expression_format_updated(true);
      kpAngleGroup->setButton(1);
      kpAngleGroup->blockSignals(false);
}
void KQalculate::angleUnitGradians() {
      kpAngleGroup->blockSignals(true);
      evalops.parse_options.angle_unit = ANGLE_UNIT_GRADIANS;
      expression_format_updated(true);
      kpAngleGroup->setButton(2);
      kpAngleGroup->blockSignals(false);
}
void KQalculate::angleUnitNone() {
      kpAngleGroup->blockSignals(true);
      evalops.parse_options.angle_unit = ANGLE_UNIT_NONE;
      expression_format_updated(true);
      kpAngleGroup->setButton(3);
      kpAngleGroup->blockSignals(false);
}

void KQalculate::placeUnitsSeparately(bool b) {
      printops.place_units_separately = b;
      result_format_updated();
}


void KQalculate::enableDenominatorPrefixes(bool b) {
      printops.use_denominator_prefix = b;
      result_format_updated();
}


void KQalculate::enableUseOfAllPrefixes(bool b) {
      printops.use_all_prefixes = b;
      result_format_updated();
}


void KQalculate::enablePrefixes(bool b) {
      printops.use_unit_prefixes = b;
      result_format_updated();
}

void KQalculate::autoNoConversion() {
      evalops.auto_post_conversion = POST_CONVERSION_NONE;
      expression_calculation_updated();
}
void KQalculate::autoConvertToBaseUnits() {
      evalops.auto_post_conversion = POST_CONVERSION_BASE;
      expression_calculation_updated();
}
void KQalculate::autoConvertToBestUnit() {
      evalops.auto_post_conversion = POST_CONVERSION_BEST;
      expression_calculation_updated();
}

void KQalculate::allowInfiniteResult(bool b) {
      evalops.allow_infinite = b;
      expression_calculation_updated();
}


void KQalculate::allowComplexResult(bool b) {
      evalops.allow_complex = b;
      expression_calculation_updated();
}


void KQalculate::calculateVariables(bool b) {
      evalops.calculate_variables = b;
      expression_calculation_updated();
}


void KQalculate::enableUnknowns(bool b) {
      evalops.parse_options.unknowns_enabled = b;
      expression_format_updated(b);
}


void KQalculate::enableUnits(bool b) {
      evalops.parse_options.units_enabled = b;
      expression_format_updated(b);
}


void KQalculate::enableFunctions(bool b) {
      evalops.parse_options.functions_enabled = b;
      expression_format_updated(b);
}


void KQalculate::enableVariables(bool b) {
      evalops.parse_options.variables_enabled = b;
      expression_format_updated(b);
}

void KQalculate::updateExchangeRates() {
      if(fetch_exchange_rates(15)) {
            CALCULATOR->loadExchangeRates();
      }
      expression_calculation_updated();
}

void KQalculate::insertRaise() {
      expressionEdit->wrapSelection();
      expressionEdit->deselect();
      insert_text("^");
}


void KQalculate::insertLn() {
      insertButtonFunction(CALCULATOR->f_ln);
}


void KQalculate::insertLog() {
      insertButtonFunction("log10");
}


void KQalculate::insertSqrt() {
      insertButtonFunction(CALCULATOR->f_sqrt);
}


void KQalculate::insertTan() {
      if(kpHyp->isOn()) {
            if(kpInv->isOn()) {
                  insertButtonFunction(CALCULATOR->f_atanh);
            } else {
                  insertButtonFunction(CALCULATOR->f_tanh);
            }
      } else {
            if(kpInv->isOn()) {
                  insertButtonFunction(CALCULATOR->f_atan);
            } else {
                  insertButtonFunction(CALCULATOR->f_tan);
            }
      }
}


void KQalculate::insertSin() {
      if(kpHyp->isOn()) {
            kpHyp->setOn(false);
            if(kpInv->isOn()) {
                  kpInv->setOn(false);
                  insertButtonFunction(CALCULATOR->f_asinh);
            } else {
                  insertButtonFunction(CALCULATOR->f_sinh);
            }
      } else {
            if(kpInv->isOn()) {
                  kpInv->setOn(false);
                  insertButtonFunction(CALCULATOR->f_asin);
            } else {
                  insertButtonFunction(CALCULATOR->f_sin);
            }
      }
}


void KQalculate::insertCos() {
      if(kpHyp->isOn()) {
            kpHyp->setOn(false);
            if(kpInv->isOn()) {
                  kpInv->setOn(false);
                  insertButtonFunction(CALCULATOR->f_acosh);
            } else {
                  insertButtonFunction(CALCULATOR->f_cosh);
            }
      } else {
            if(kpInv->isOn()) {
                  kpInv->setOn(false);
                  insertButtonFunction(CALCULATOR->f_acos);
            } else {
                  insertButtonFunction(CALCULATOR->f_cos);
            }
      }
}


void KQalculate::insertDivision() {
      expressionEdit->wrapSelection();
      expressionEdit->deselect();
      if(printops.use_unicode_signs && printops.division_sign == DIVISION_SIGN_DIVISION && can_display_unicode_string_function(SIGN_DIVISION, (void*) expressionEdit)) {
            insert_text(SIGN_DIVISION);
      } else {
            insert_text("/");
      }
}


void KQalculate::insertTimes() {
      expressionEdit->wrapSelection();
      expressionEdit->deselect();
      if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_DOT && can_display_unicode_string_function(SIGN_MULTIDOT, (void*) expressionEdit)) {
            insert_text(SIGN_MULTIDOT);
      } else if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_DOT && can_display_unicode_string_function(SIGN_SMALLCIRCLE, (void*) expressionEdit)) {
            insert_text(SIGN_SMALLCIRCLE);
      } else if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_X && can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) expressionEdit)) {
            insert_text(SIGN_MULTIPLICATION);
      } else {
            insert_text("*");
      }
}


void KQalculate::insertPlus() {
      expressionEdit->wrapSelection();
      expressionEdit->deselect();
      insert_text("+");
}


void KQalculate::insertMinus() {
      expressionEdit->wrapSelection();
      expressionEdit->deselect();
      if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_MINUS, (void*) expressionEdit)) insert_text(SIGN_MINUS);
      else insert_text("-");
}


void KQalculate::insertAns() {
      insert_text(vans[0]->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressionEdit).name.c_str());
}


void KQalculate::insertExp() {
      expressionEdit->wrapSelection();
      expressionEdit->deselect();
      if(printops.lower_case_e) insert_text("e");
      else insert_text("E");  
}


void KQalculate::insertDot() {
      insert_text(CALCULATOR->getDecimalPoint().c_str());
}


void KQalculate::insertKP0() {
      insert_text("0");
}


void KQalculate::insertKP9() {
      insert_text("9");
}


void KQalculate::insertKP8() {
      insert_text("8");
}


void KQalculate::insertKP7() {
      insert_text("7");
}


void KQalculate::insertKP6() {
      insert_text("6");
}


void KQalculate::insertKP5() {
      insert_text("5");
}


void KQalculate::insertKP4() {
      insert_text("4");
}


void KQalculate::insertKP3() {
      insert_text("3");
}


void KQalculate::insertKP2() {
      insert_text("2");
}


void KQalculate::insertKP1() {
      insert_text("1");
}

void KQalculate::expressionDel() {
      expressionEdit->del();
}


void KQalculate::clearExpression() {
      expressionEdit->clear();
}

void KQalculate::insertSquare() {
      expressionEdit->wrapSelection();
      expressionEdit->deselect();
      insert_text("^2");
}

void KQalculate::setFractionMode(bool b) {
      if(b) {
            ActionFractionalDisplayFraction->activate();
      } else {
            ActionFractionalDisplayDecimal->activate();
      }
}

void KQalculate::setExactMode(bool b) {
      if(b) {
            ActionApproximationAlwaysExact->activate();
      } else {
            ActionApproximationTryExact->activate();
      }
}

void KQalculate::kpSetAngleUnit(int index) {
      switch(index) {
            case 0: {
                  ActionAngleUnitDegrees->activate();
                  break;
            }
            case 1: {
                  ActionAngleUnitRadians->activate();
                  break;
            }
            case 2: {
                  ActionAngleUnitGradians->activate();
                  break;
            }
            case 3: {
                  ActionAngleUnitNone->activate();
                  break;
            }
      }
}

void KQalculate::kpSetNumericalMode(int index) {
      switch(index) {
            case 0: {
                  ActionNumericalDisplayNormal->activate();
                  break;
            }
            case 1: {
                  ActionNumericalDisplayScientific->activate();
                  break;
            }
            case 2: {
                  ActionNumericalDisplayPurelyScientific->activate();
                  break;
            }
            case 3: {
                  ActionNumericalDisplaySimple->activate();
                  break;
            }
      }
}


void KQalculate::kpSetBaseSelected(int index) {
      switch(index) {
            case 7: {
                  ActionNumberBaseOther->activate();
                  break;
            }
      }
}
void KQalculate::kpSetBase(int index) {
      switch(index) {
            case 0: {
                  ActionNumberBaseBinary->activate();
                  break;
            }
            case 1: {
                  ActionNumberBaseOctal->activate();
                  break;
            }
            case 2: {
                  ActionNumberBaseDecimal->activate();
                  break;
            }
            case 3: {
                  ActionNumberBaseHexadecimal->activate();
                  break;
            }
            case 4: {
                  ActionNumberBaseSexagesimal->activate();
                  break;
            }
            case 5: {
                  ActionNumberBaseTimeFormat->activate();
                  break;
            }
            case 6: {
                  ActionNumberBaseRomanNumerals->activate();
                  break;
            }
            case 7: {
                  ActionNumberBaseOther->activate();
                  break;
            }
      }
}

void KQalculate::insertMod() {
      insertButtonFunction(CALCULATOR->f_mod);
}


void KQalculate::insertFactorial() {
      expressionEdit->wrapSelection();
      expressionEdit->deselect();
      insert_text("!");
}

void KQalculate::storeResult() {
      if(!store_dialog) {
            store_dialog = new QalculateEditVariableDialog(this);
      }
      Variable *v = store_dialog->editVariable(i18n("Temporary"), NULL, mstruct, true);
      if(v) {
            update_vmenu();
            variable_inserted(v);
      }
}

void KQalculate::manageVariables() {
      if(!variables_dialog) {
            variables_dialog = new QalculateVariablesDialog();
            variables_dialog->updateVariableTree();
            QObject::connect(variables_dialog, SIGNAL(variablesChanged()), this, SLOT(update_vmenu()));
            QObject::connect(variables_dialog, SIGNAL(insertRequest(Variable*)), this, SLOT(insertVariable(Variable*)));
      }
      variables_dialog->show();
}
void KQalculate::insertVariable(Variable *v) {
      insert_text(v->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressionEdit).name.c_str());
      variable_inserted(v);
}
void KQalculate::insertFunction(MathFunction *f, QWidget *parent) {
      if(!CALCULATOR->stillHasFunction(f)) {
            KMessageBox::error(this, i18n("Function does not exist anymore."));
            update_fmenu();
            return;
      }
      if(f->args() == 0) {
            QString str = f->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) expressionEdit).name.c_str();
            str += "()";
            insert_text(str);
            function_inserted(f);
      } else {
            QalculateInsertFunctionDialog *dialog = new QalculateInsertFunctionDialog(f, parent, expressionEdit->selectedText());
            int rcode = dialog->exec();
            if(rcode != QDialog::Rejected) {
                  if(rcode == QDialog::Accepted) {
                        insert_text(dialog->functionExpression());
                  } else {
                        expressionEdit->setText(dialog->functionExpression());
                        execute();
                        expressionEdit->setFocus();
                  }
                  function_inserted(f);
            }
            delete dialog;
      }
}

void KQalculate::convertToUnitConvertToDialogExpression() {
      error_timer->stop();
      mstruct->set(CALCULATOR->convert(*mstruct, convert_to_unit_expression_dialog->unitExpressionEdit->text().ascii(), evalops));
      result_action_executed();
      error_timer->start(100);
}

void KQalculate::convertToUnitExpression() {
      if(!convert_to_unit_expression_dialog) {
            convert_to_unit_expression_dialog = new QalculateConvertUnitsDialog(this);
            convert_to_unit_expression_dialog->updateUnitTree();
            QObject::connect(convert_to_unit_expression_dialog, SIGNAL(applyClicked()), this, SLOT(convertToUnitConvertToDialogExpression()));
            QObject::connect(convert_to_unit_expression_dialog, SIGNAL(okClicked()), this, SLOT(convertToUnitConvertToDialogExpression()));
            QObject::connect(convert_to_unit_expression_dialog, SIGNAL(unitsChanged()), this, SLOT(update_umenus()));
      }
      convert_to_unit_expression_dialog->show();
}

void KQalculate::convertNumberBases() {
      if(!convert_number_bases_dialog) {
            convert_number_bases_dialog = new QalculateConvertNumberBasesDialog();
      }
      convert_number_bases_dialog->show();
}

void KQalculate::insertManagedFunction(MathFunction *f) {
      insertFunction(f, functions_dialog);
}
void KQalculate::manageFunctions() {
      if(!functions_dialog) {
            functions_dialog = new QalculateFunctionsDialog();
            functions_dialog->updateFunctionTree();
            QObject::connect(functions_dialog, SIGNAL(functionsChanged()), this, SLOT(update_fmenu()));
            QObject::connect(functions_dialog, SIGNAL(insertRequest(MathFunction*)), this, SLOT(insertManagedFunction(MathFunction*)));
      }
      functions_dialog->show();
}

void KQalculate::newUnit() {
      if(!unit_edit_dialog) {
            unit_edit_dialog = new QalculateEditUnitDialog(this);
      }
      Unit *u = unit_edit_dialog->editUnit();
      if(u) {
            update_umenus();
            unit_inserted(u);
      }
}


void KQalculate::newDataSet() {
      if(!dataset_edit_dialog) {
            dataset_edit_dialog = new QalculateEditDataSetDialog(this);
      }
      MathFunction *f = dataset_edit_dialog->editDataSet();
      if(f) {
            update_fmenu();
            function_inserted(f);
      }
}


void KQalculate::newFunction() {
      if(!function_edit_dialog) {
            function_edit_dialog = new QalculateEditFunctionDialog(this);
      }
      MathFunction *f = function_edit_dialog->editFunction();
      if(f) {
            update_fmenu();
            function_inserted(f);
      }
}


void KQalculate::newUnknownVariable() {
      if(!unknown_edit_dialog) {
            unknown_edit_dialog = new QalculateEditUnknownVariableDialog(this);
      }
      Variable *v = unknown_edit_dialog->editVariable(i18n("My Variables"));
      if(v) {
            update_vmenu();
            variable_inserted(v);
      }
}


void KQalculate::newVector() {
      if(!matrix_edit_dialog) {
            matrix_edit_dialog = new QalculateEditMatrixVectorDialog(this);
      }
      Variable *v = matrix_edit_dialog->newVector(i18n("Vectors"));
      if(v) {
            update_vmenu();
            variable_inserted(v);
      }
}


void KQalculate::newMatrix() {
      if(!matrix_edit_dialog) {
            matrix_edit_dialog = new QalculateEditMatrixVectorDialog(this);
      }
      Variable *v = matrix_edit_dialog->newMatrix(i18n("Matrices"));
      if(v) {
            update_vmenu();
            variable_inserted(v);
      }
}


void KQalculate::newVariable() {
      if(!variable_edit_dialog) {
            variable_edit_dialog = new QalculateEditVariableDialog(false);
      }
      Variable *v = variable_edit_dialog->editVariable(i18n("My Variables"));
      if(v) {
            update_vmenu();
            variable_inserted(v);
      }
}


void KQalculate::exportCSVFile() {
      if(!export_csv_dialog) {
            export_csv_dialog = new QalculateExportCSVDialog(this);
      }
      export_csv_dialog->exportCSVFile();
}


void KQalculate::importCSVFile() {
      if(!import_csv_dialog) {
            import_csv_dialog = new QalculateImportCSVDialog(this);
      }
      if(import_csv_dialog->importCSVFile()) {
            update_vmenu();
      }
}


void KQalculate::saveAsImage() {
      QString filename;
      while(true) {
            filename = KFileDialog::getSaveFileName("qalculate.png", "image/png", this, i18n("Save Image"));
            if(filename.isEmpty()) {
                  return;
            } else {
                  if(QFile::exists(filename)) {
                        if(KMessageBox::warningContinueCancel(this, i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?" ).arg(filename), i18n("Overwrite File?"), i18n( "&Overwrite" )) != KMessageBox::Cancel) {
                              break;
                        }
                  } else {
                        break;
                  }
            }
      }
      QString str = result_text;
      str.replace("width=1 ", "");
      QSimpleRichText text(str, resultLabel->font());
      QPicture picture;
      QPainter p(&picture);
      text.setWidth(1000);
      text.draw(&p, 0, 0, QRect(), QColorGroup(Qt::black, Qt::white, Qt::white, Qt::white, Qt::white, Qt::black, Qt::white));
      p.flush();
      p.end();
      QPixmap pixmap(picture.boundingRect().width(), picture.boundingRect().height());
      pixmap.fill(Qt::white);
      QPainter p2(&pixmap);
      p2.drawPicture(-picture.boundingRect().x(), -picture.boundingRect().y(), picture);
      p2.flush();
      p2.end();
      QImage image(pixmap.convertToImage());
      image.setAlphaBuffer(true);
      int h = image.height(), w = image.width();
      QRgb pixel;
      for(int r =0; r < h; r++) {
            for(int c =0; c < w; c++) {
                  pixel = image.pixel(c, r);
                  image.setPixel(c, r, qRgba(0, 0, 0, 0xff - ((qRed(pixel) + qBlue(pixel) + qGreen(pixel))/ 3)));
            }
      }
      if(!image.save(filename, "PNG")) {
            KMessageBox::error(this, i18n("Failed to save image."));
      }
}


void KQalculate::saveDefinitions() {
      save_defs();
}


void KQalculate::plotFunctionsData() {
      if(!plot_dialog) {
            plot_dialog = new QalculatePlotDialog();
      }
      plot_dialog->expressionEdit->setText(expressionEdit->text());
      plot_dialog->show();
}


void KQalculate::periodicTable() {
      if(!periodic_table_dialog) {
            periodic_table_dialog = new QalculatePeriodicTableDialog();
      }
      periodic_table_dialog->show();
}


void KQalculate::onSetPrefixMenuItemActivated(int id) {
      if(!menu_set_prefix_ids.contains(id)) return;
      result_prefix_changed(menu_set_prefix_ids[id]);
}


void KQalculate::onConvertToUnitMenuItemActivated(int id) {
      if(!menu_to_unit_ids.contains(id)) return;
      error_timer->stop();
      mstruct->set(CALCULATOR->convert(*mstruct, menu_to_unit_ids[id], evalops));
      result_action_executed();
      error_timer->start(100);
}



void KQalculate::preferences() {
      if(!preferences_dialog) {
            preferences_dialog = new QalculatePreferencesDialog(this);
      }
      close_to_systray_was = close_to_systray;
      display_expression_status_was = display_expression_status;
      preferences_dialog->editPreferences();
}

void KQalculate::applyPreferences() {
      if(use_custom_result_font) {
            QFont font(resultLabel->font());
            font.fromString(custom_result_font);
            resultLabel->setFont(font);
      } else {
            resultLabel->unsetFont();
      }
      if(use_custom_expression_font) {
            QFont font(expressionEdit->font());
            font.fromString(custom_expression_font);
            expressionEdit->setFont(font);
      } else {
            expressionEdit->unsetFont();
      }
      updateStatusLabelFonts();
      set_unicode_buttons();
      result_display_updated();
      if(close_to_systray != close_to_systray_was) {
            showSystemTrayIcon(close_to_systray);
      }
      if(display_expression_status != display_expression_status_was) {
            if(display_expression_status) {
                  statusLabel_l->show();                    
            } else {
                  statusLabel_l->hide();
            }
      }
      displayParseStatus();
            
      bool use_button_pixmaps = false;
      if(use_icon_buttons > 0) {
            use_button_pixmaps = true;
      } else if(use_icon_buttons < 0) {
            KConfig config("kdeglobals", true, false);      
            config.setGroup("KDE"); 
            use_button_pixmaps = config.readBoolEntry("ShowIconsOnPushButtons", false);
      }

      if(leftButtonsSeparator->isVisible() == use_button_pixmaps) {
            if(use_button_pixmaps) {
                  leftButtonsLayout->setSpacing(3);
                  executeButton->setText("");   
                  executeButton->setIconSet(KApplication::kApplication()->iconLoader()->loadIconSet("exec", KIcon::Small, KIcon::SizeSmallMedium));
                  storeButton->setText("");     
                  storeButton->setIconSet(KApplication::kApplication()->iconLoader()->loadIconSet("filesaveas", KIcon::Small, KIcon::SizeSmallMedium));
                  convertButton->setText("");   
                  convertButton->setIconSet(KApplication::kApplication()->iconLoader()->loadIconSet("qalculate_convert", KIcon::Small, KIcon::SizeSmallMedium));
                  leftButtonsSeparator->hide();
            } else {
                  leftButtonsLayout->setSpacing(6);
                  executeButton->setText(i18n("="));  
                  executeButton->setIconSet(QIconSet());
                  storeButton->setText(i18n("Store"));      
                  storeButton->setIconSet(QIconSet());
                  convertButton->setText(i18n("Convert"));  
                  convertButton->setIconSet(QIconSet());
                  leftButtonsSeparator->show();
            }
      }
}


void KQalculate::copyResult() {
      QApplication::clipboard()->setText(result_history_text, QClipboard::Clipboard);
}

void KQalculate::clearHistory() {
      historyBrowser->setText("&nbsp;");
      expressionEdit->setFocus();
}

void KQalculate::convertToBestUnit() {
      error_timer->stop();
      mstruct->set(CALCULATOR->convertToBaseUnits(*mstruct, evalops));
      result_action_executed();
      error_timer->start(100);
}


void KQalculate::convertToBaseUnits() {
      error_timer->stop();
      mstruct->set(CALCULATOR->convertToBestUnit(*mstruct, evalops));
      result_action_executed();
      error_timer->start(100);
}

void KQalculate::applySetUnknowns(bool okclicked) {
      QString str;
      QString result_mod = "";
      bool b = false;
      mstruct->set(*mstruct_before_unknowns);
      for(size_t i = 1; i <= unknowns_mstruct->size(); i++) {
            str = unknowns_entries[i - 1]->text().stripWhiteSpace();
            if(unknown_changed[i - 1] || !str.isEmpty()) {
                  if(!result_mod.isEmpty()) {
                        result_mod += CALCULATOR->getComma().c_str();
                        result_mod += " ";
                  }
                  result_mod += unknowns_mstruct->getChild(i)->print().c_str();
                  result_mod += "=";
                  if(str.isEmpty()) {
                        result_mod += "?";
                  } else {
                        result_mod += str;
                        mstruct->replace(*unknowns_mstruct->getChild(i), CALCULATOR->calculate(CALCULATOR->unlocalizeExpression(str.ascii()), evalops));
                        b = true;
                        unknown_changed[i - 1] = true;
                  }
            }
      }
      if(b) {
            b_unknowns_changed = true;
            if(okclicked) {
                  MathStructure mp(*mstruct);
                  printops.can_display_unicode_string_arg = historyBrowser;
                  mp.format(printops);
                  str = mp.print(printops).c_str();
                  expressionEdit->blockSignals(true);             
                  expressionEdit->setText(str);
                  printops.can_display_unicode_string_arg = NULL;
                  //expressionEdit->addToHistory(str);
                  expressionEdit->expression_history_index = -1;
                  expressionEdit->blockSignals(false);
                  expressionEdit->setFocus();
                  expressionEdit->selectAll();
                  expression_has_changed2 = true;
                  displayParseStatus();
            }
            mstruct->eval(evalops);
      }
      if(b_unknowns_changed) {
            printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
            setResult(NULL, true, false, false, result_mod);
      }     
      //if(!okclicked && b) mstruct->set(*mstruct_before_unknowns);
}
void KQalculate::setUnknownsApplyClicked() {
      applySetUnknowns(false);
}
void KQalculate::setUnknowns() {
      if(expression_has_changed) execute_expression(true);
      unknowns_mstruct = new MathStructure();
      mstruct->findAllUnknowns(*unknowns_mstruct);
      if(unknowns_mstruct->size() == 0) {
            KMessageBox::error(this, i18n("No unknowns in result."));
            return;
      }
      KDialogBase *dialog = new KDialogBase(this, 0, true, i18n("Set Unknowns"));
      QObject::connect(dialog, SIGNAL(applyClicked()), this, SLOT(setUnknownsApplyClicked()));
      QGrid *grid = dialog->makeGridMainWidget(2, Qt::Horizontal);
      unknowns_entries.clear();
      for(size_t i = 1; i <= unknowns_mstruct->size(); i++) {
            new QLabel(unknowns_mstruct->getChild(i)->print().c_str(), grid);
            unknowns_entries.push_back(new KLineEdit(grid));
            if(i == 1) unknowns_entries[0]->setFocus();
      }
      mstruct_before_unknowns = new MathStructure(*mstruct);
      b_unknowns_changed = false;
      unknown_changed.clear();
      unknown_changed.resize(unknowns_mstruct->size(), false);
      int response = dialog->exec();
      if(response == QDialog::Accepted) {
            applySetUnknowns(true);
      } else {
            if(b_unknowns_changed) {
                  QString result_mod = "";
                  for(size_t i = 1; i <= unknowns_mstruct->size(); i++) {
                        if(unknown_changed[i - 1]) {
                              if(!result_mod.isEmpty()) {
                                    result_mod += CALCULATOR->getComma().c_str();
                                    result_mod += " ";
                              }
                              result_mod += unknowns_mstruct->getChild(i)->print().c_str();
                              result_mod += "=";
                              result_mod += "?";
                        }
                  }
                  mstruct->set(*mstruct_before_unknowns);
                  printops.allow_factorization = (evalops.structuring == STRUCTURING_FACTORIZE);
                  setResult(NULL, true, false, false, result_mod);
                  expressionEdit->setFocus();
            }
      }
      delete dialog;
      delete mstruct_before_unknowns;
      delete unknowns_mstruct;
}


void KQalculate::manageDataSets() {
      if(!datasets_dialog) {
            datasets_dialog = new QalculateDataSetsDialog();
            datasets_dialog->updateDataSetTree();
            QObject::connect(datasets_dialog, SIGNAL(dataSetsChanged()), this, SLOT(update_fmenu()));
      }
      datasets_dialog->show();
}

void KQalculate::factorize() {
      executeCommand(COMMAND_FACTORIZE);
}
void KQalculate::simplify() {
      executeCommand(COMMAND_SIMPLIFY);
}

void KQalculate::manageUnits() {
      if(!units_dialog) {
            units_dialog = new QalculateUnitsDialog();
            units_dialog->updateUnitTree();
            QObject::connect(units_dialog, SIGNAL(unitsChanged()), this, SLOT(update_umenus()));
            QObject::connect(units_dialog, SIGNAL(insertRequest(Unit*)), this, SLOT(insertUnit(Unit*)));
            QObject::connect(units_dialog, SIGNAL(convertRequest(Unit*)), this, SLOT(convertResult(Unit*)));
      }
      units_dialog->show();
}
void KQalculate::insertUnit(Unit *u) {
      if(u->subtype() == SUBTYPE_COMPOSITE_UNIT) {
            insert_text(((CompositeUnit*) u)->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) expressionEdit).c_str());
      } else {
            insert_text(u->preferredInputName(printops.abbreviate_names, printops.use_unicode_signs, true, false, &can_display_unicode_string_function, (void*) expressionEdit).name.c_str());
      }
      unit_inserted(u);
}
void KQalculate::convertResult(Unit *u) {
      error_timer->stop();
      mstruct->set(CALCULATOR->convert(*mstruct, u, evalops));
      result_action_executed();
      error_timer->start(100);
}
void KQalculate::insertMatrixVector(const MathStructure *m, bool do_vector, bool is_text_struct, bool is_result) {
      if(!insert_matrix_dialog) {
            insert_matrix_dialog = new QalculateInsertMatrixVectorDialog(this);
      }
      QString str = insert_matrix_dialog->editMatrixVector(m, do_vector, is_text_struct, is_result);
      if(!str.isEmpty()) {
            insert_text(str);
      }
}
void KQalculate::insertMatrix() {
      QString str = expressionEdit->selectedText();
      if(!str.isEmpty()) {
            MathStructure mstruct;
            CALCULATOR->parse(&mstruct, CALCULATOR->unlocalizeExpression(str.ascii()), evalops.parse_options);
            if(mstruct.isMatrix()) {
                  insertMatrixVector(&mstruct, false);
                  return;
            }
      }
      insertMatrixVector(NULL, false);
}
void KQalculate::insertVector() {
      QString str = expressionEdit->selectedText();
      if(!str.isEmpty()) {
            MathStructure mstruct;
            CALCULATOR->parse(&mstruct, CALCULATOR->unlocalizeExpression(str.ascii()), evalops.parse_options);
            if(mstruct.isVector() && !mstruct.isMatrix()) {
                  insertMatrixVector(&mstruct, true);
                  return;
            }
      }
      insertMatrixVector(NULL, true);
}

void KQalculate::keyPressEvent(QKeyEvent *e) {
      if(!expressionEdit->hasFocus() && e->key() != Key_Return && e->key() != Key_Enter && (((e->state() == 0 || e->state() == ShiftButton) && !e->text().isEmpty()) || (e->state() == 0 && (e->key() == Key_Backspace || e->key() == Key_Delete)))) {
            expressionEdit->setFocus();
            expressionEdit->keyPressEvent(e);
      } else {
            KMainWindow::keyPressEvent(e);
      }
}

bool KQalculate::queryClose() {
      if(!close_to_systray) return true;
      hide();
      setShown(false);
      return false;
}

void KQalculate::display_function_hint(MathFunction *f, int arg_index) {
      if(!f) return;
      int iargs = f->maxargs();
      Argument *arg;
      Argument default_arg;
      QString str, str2, str3;
      const ExpressionName *ename = &f->preferredName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) statusLabel_l);
      bool last_is_vctr = f->getArgumentDefinition(iargs) && f->getArgumentDefinition(iargs)->type() == ARGUMENT_TYPE_VECTOR;
      if(arg_index > iargs && iargs >= 0 && !last_is_vctr) {
            statusLabel_l->setText(i18n("Too many arguments for %1().").arg(ename->name.c_str()), false, false, true);
            return;
      }
      str += ename->name.c_str();
      if(iargs < 0) {
            iargs = f->minargs() + 1;
            if(arg_index > iargs) arg_index = iargs;
      }
      if(arg_index > iargs && last_is_vctr) arg_index = iargs;
      
      str += "(";
      int i_reduced = 0;
      if(iargs != 0) {
            for(int i2 = 1; i2 <= iargs; i2++) {                  
                  if(i2 > f->minargs() && arg_index < i2) {
                        str += "[";
                  }
                  if(i2 > 1) {
                        str += CALCULATOR->getComma().c_str();
                        str += " ";
                  }
                  if(i2 == arg_index) str += "<b>";
                  arg = f->getArgumentDefinition(i2);
                  if(arg && !arg->name().empty()) {
                        str2 = arg->name().c_str();
                  } else {
                        str2 = i18n("argument");
                        str2 += " ";
                        str2 += QString::number(i2);
                  }
                  if(i2 == arg_index) {
                        if(arg) {
                              if(i_reduced == 2) str3 = arg->print().c_str();
                              else str3 = arg->printlong().c_str();
                        } else {
                              Argument arg_default;
                              if(i_reduced == 2) str3 = arg_default.print().c_str();
                              else str3 = arg_default.printlong().c_str();
                        }
                        if(!str3.isEmpty()) {
                              str2 += ": ";
                              str2 += str3;
                        }
                        str2.replace("&", "&amp;");
                        str2.replace(">", "&gt;");
                        str2.replace("<", "&lt;");
                        str += str2;
                        str += "</b>";
                        if(i_reduced < 2) {
                              QSimpleRichText qsrt(str, statusLabel_l->font());
                              qsrt.setWidth(statusLabel_l->contentsRect().width() + 100);
                              if(qsrt.widthUsed() > statusLabel_l->contentsRect().width() - 4) {
                                    str = ename->name.c_str();    
                                    str += "(";
                                    if(i2 != 1) {
                                          str += "...";
                                          i_reduced++;
                                    } else {
                                          i_reduced = 2;
                                    }
                                    i2--;
                              }
                        } else {
                              i_reduced = 0;
                        }
                  } else {
                        str2.replace("&", "&amp;");
                        str2.replace(">", "&gt;");
                        str2.replace("<", "&lt;");
                        str += str2;
                        if(i2 > f->minargs() && arg_index < i2) {
                              str += "]";
                        }
                  }
            }
            if(f->maxargs() < 0) {
                  str += CALCULATOR->getComma().c_str();
                  str += " ...";
            }
      }
      str += ")";
      statusLabel_l->setText(str, false, false, false);
}

void KQalculate::displayParseStatus() {
      if(!display_expression_status) return;
      if(expressionEdit->text().length() == 0) {
            statusLabel_l->setText("", true, false, false);
            parsed_expression = "";
            expression_has_changed2 = false;
            had_errors_before = false;
            had_warnings_before = false;
            return;
      }
      MathStructure mparse, mfunc;
      string str_e, str_u;
      int pos = expressionEdit->cursorPosition();
      bool full_parsed = false;
      bool had_errors = false, had_warnings = false;
      evalops.parse_options.preserve_format = true;
      if(pos > 0) {
            evalops.parse_options.unended_function = &mfunc;
            CALCULATOR->beginTemporaryStopMessages();
            if(pos < (int) expressionEdit->text().length()) {
                  QString str = expressionEdit->text();
                  str.truncate(pos);
                  str_e = CALCULATOR->unlocalizeExpression(str.ascii());
                  if(!CALCULATOR->separateToExpression(str_e, str_u, evalops)) {
                        CALCULATOR->parse(&mparse, str_e, evalops.parse_options);
                  }
            } else {
                  str_e = CALCULATOR->unlocalizeExpression(expressionEdit->text().ascii());
                  CALCULATOR->separateToExpression(str_e, str_u, evalops);
                  CALCULATOR->parse(&mparse, str_e, evalops.parse_options);
                  full_parsed = true;
            }
            int warnings_count;
            had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0;
            had_warnings = warnings_count > 0;
            evalops.parse_options.unended_function = NULL;
      }
      if(mfunc.isFunction()) {
            if(mfunc.countChilds() == 0) {
                  display_function_hint(mfunc.function(), 1);
            } else {
                  display_function_hint(mfunc.function(), mfunc.countChilds());
            }
      } else if(expression_has_changed2) {
            if(!full_parsed) {
                  CALCULATOR->beginTemporaryStopMessages();
                  str_e = CALCULATOR->unlocalizeExpression(expressionEdit->text().ascii());
                  CALCULATOR->separateToExpression(str_e, str_u, evalops);
                  CALCULATOR->parse(&mparse, str_e, evalops.parse_options);
                  int warnings_count;
                  had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0;
                  had_warnings = warnings_count > 0;
            }
            PrintOptions po;
            po.preserve_format = true;
            po.show_ending_zeroes = true;
            po.lower_case_e = printops.lower_case_e;
            po.lower_case_numbers = printops.lower_case_numbers;
            po.abbreviate_names = false;
            po.hide_underscore_spaces = true;
            po.use_unicode_signs = printops.use_unicode_signs;
            po.multiplication_sign = printops.multiplication_sign;
            po.division_sign = printops.division_sign;
            po.short_multiplication = false;
            po.excessive_parenthesis = true;
            po.improve_division_multipliers = false;
            po.can_display_unicode_string_function = &can_display_unicode_string_function;
            po.can_display_unicode_string_arg = (void*) statusLabel_l;
            po.spell_out_logical_operators = printops.spell_out_logical_operators;
            mparse.format(po);
            parsed_expression = mparse.print(po).c_str();
            if(!str_u.empty()) {
                  parsed_expression += CALCULATOR->localToString().c_str();
                  CALCULATOR->beginTemporaryStopMessages();
                  CompositeUnit cu("", "temporary_composite_parse", "", str_u);
                  int warnings_count;
                  had_errors = CALCULATOR->endTemporaryStopMessages(NULL, &warnings_count) > 0 || had_errors;
                  had_warnings = had_warnings || warnings_count > 0;
                  mparse = cu.generateMathStructure(!printops.negative_exponents);
                  mparse.format(po);
                  parsed_expression += mparse.print(po).c_str();
            }
            parsed_expression.replace("&", "&amp;");
            parsed_expression.replace(">", "&gt;");
            parsed_expression.replace("<", "&lt;");
            statusLabel_l->setText(parsed_expression, true, had_errors, had_warnings);
            expression_has_changed2 = false;
            had_errors_before = had_errors;
            had_warnings_before = had_warnings;
      } else {    
            statusLabel_l->setText(parsed_expression, true, had_errors_before, had_warnings_before);
      }
      evalops.parse_options.preserve_format = false;
}


QalculateHistoryBrowser::QalculateHistoryBrowser(QWidget *parent, const char *name) : KTextBrowser(parent, name) {}
QalculateHistoryBrowser::~QalculateHistoryBrowser() {}

QPopupMenu *QalculateHistoryBrowser::createPopupMenu(const QPoint &pos) {

      QPopupMenu *menu = KTextBrowser::createPopupMenu(pos);
      menu->insertSeparator();
      mainWin->ActionClearHistory->plug(menu);
      return menu;

}


QalculateParseLabel::QalculateParseLabel(QWidget *parent, const char *name) : QLabel(parent, name) {
      QLabel::setText("<b>A</b>");
      bb = false;
      ec = false;
      wc = false;
}
QalculateParseLabel::~QalculateParseLabel() {}
void QalculateParseLabel::setText(QString text, bool break_begin, bool error_color, bool warning_color) {
      bb = break_begin;
      ec = error_color;
      wc = warning_color;
      parsetext = "<nobr>";
      parsetext += text;
      parsetext += "</nobr>";
      update();
}
void QalculateParseLabel::drawContents(QPainter *p) {
      QColorGroup cg = colorGroup();
      if(ec) {
            cg.setColor(QColorGroup::Text, status_error_color);
      } else if(wc) {
            cg.setColor(QColorGroup::Text, status_warning_color);
      } else if(backgroundMode() != PaletteBase && isEnabled()) {
            cg.setColor(QColorGroup::Text, paletteForegroundColor());
      }

      QRect cr = contentsRect();
      cr.setX(cr.x() + 4);
      cr.setWidth(cr.width() - 4);
      QSimpleRichText qsrt(parsetext, font());
      qsrt.setWidth(p, cr.width() + 100);
      if(qsrt.widthUsed() > cr.width()) {
            if(bb) {
                  QSimpleRichText qsrt_dots("...", font());
                  qsrt_dots.draw(p, cr.x(), cr.y(), cr, cg, 0);
                  cr.setX(cr.x() + qsrt_dots.widthUsed());
                  cr.setWidth(cr.width() - qsrt_dots.widthUsed());
                  qsrt.draw(p, cr.x() + cr.width() - qsrt.widthUsed(), cr.y(), cr, cg, 0);
            } else {
                  QSimpleRichText qsrt_dots("...", font());
                  qsrt_dots.draw(p, cr.x() + cr.width() - qsrt_dots.widthUsed(), cr.y(), cr, cg, 0);
                  cr.setWidth(cr.width() - qsrt_dots.widthUsed());
                  qsrt.draw(p, cr.x(), cr.y(), cr, cg, 0);
            }
      } else {
            qsrt.draw(p, cr.x(), cr.y(), cr, cg, 0);
      }
}

QalculateButton::QalculateButton(QWidget *parent, const char *name) : QPushButton(parent, name) {
      setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
      umtcw = true;
#if KDE_VERSION_MAJOR > 3 || KDE_VERSION_MINOR >= 4   
      KAcceleratorManager::setNoAccel(this);
#endif

}
QalculateButton::QalculateButton(const QString &text, QWidget *parent, const char *name) : QPushButton(text, parent, name) {
      setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
      umtcw = true;
#if KDE_VERSION_MAJOR > 3 || KDE_VERSION_MINOR >= 4   
      KAcceleratorManager::setNoAccel(this);
#endif      
}
QalculateButton::QalculateButton(const QIconSet &icon, const QString &text, QWidget *parent, const char *name) : QPushButton(icon, text, parent, name) {
      setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
      umtcw = true;
#if KDE_VERSION_MAJOR > 3 || KDE_VERSION_MINOR >= 4   
      KAcceleratorManager::setNoAccel(this);
#endif      
}
QalculateButton::~QalculateButton() {}

void QalculateButton::setUseMinThreeCharWidth(bool b) {
      umtcw = b;
}
void QalculateButton::setMarkup(const QString &str) {
      QColorGroup cg(colorGroup());
      cg.setColor(QColorGroup::Text, paletteForegroundColor());
      QSimpleRichText rtext(str, font());
      QPicture picture;
      QPainter p(&picture);
      rtext.draw(&p, 0, 0, QRect(), cg);
      p.flush();
      p.end();
      QRect r = picture.boundingRect();
      QPixmap pixmap(r.width(), rtext.height());
      pixmap.fill(cg.background());
      QPainter p2(&pixmap);
      p2.drawPicture(-r.x(), 0, picture);
      p2.flush();
      p2.end();
      pixmap.setMask(pixmap.createHeuristicMask());   
      setPixmap(pixmap);      
}

QSize QalculateButton::sizeHint() const {

      constPolish();

      int w = 0, h = 0;
    

#ifndef QT_NO_ICONSET
      if(iconSet() && !iconSet()->isNull()) {
            w = iconSet()->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 10;
            h = iconSet()->pixmap( QIconSet::Small, QIconSet::Normal ).height() + 10;
            return QSize(w, h).expandedTo(QApplication::globalStrut());
      }
#endif

      QSize sz;

      if(pixmap()) {
            QPixmap *pm = (QPixmap *)pixmap();
            w = pm->width();
            h = pm->height();
            if(umtcw) {
                  QFontMetrics fm = fontMetrics();
                  sz = fm.size(ShowPrefix, QString::fromLatin1("XXX"));
                  if(w < sz.width()) w = sz.width();
                  if(w < sz.height()) w = sz.height();
            }
            sz.setWidth(w);
            sz.setHeight(h);
            w += 12;
            h += 10;
      } else {
            QFontMetrics fm = fontMetrics();
            if(umtcw && (text().isEmpty() || text().length() < 3)) {
                  sz = fm.size(ShowPrefix, QString::fromLatin1("XXX"));
            } else {
                  sz = fm.size(ShowPrefix, text());
            }
            w = sz.width() + 12;
            h = sz.height() + 10;
      }

      return QSize(w, h).boundedTo(style().sizeFromContents(QStyle::CT_PushButton, this, sz)).expandedTo(QApplication::globalStrut());

}

QalculateStyleSheet::QalculateStyleSheet(QObject *parent, const char *name) : QStyleSheet(parent, name) {}
QalculateStyleSheet::~QalculateStyleSheet() {}
      
void QalculateStyleSheet::scaleFont(QFont &font, int logicalSize) const {

      if(logicalSize <= 1) {
            font.setPixelSize(1);
      } else if(logicalSize == 2) {
            logicalSize = 1;
      } else if(logicalSize > 7) {
            logicalSize = 7;
      }
      
      int baseSize = font.pointSize();
      
      bool pixel = FALSE;
      if(baseSize == -1){
            baseSize = font.pixelSize();
            pixel = TRUE;
      }

      float factor = baseSize;
      int i;
      int scale_level = logicalSize - 3;

      if(scale_level > 0) {
            i = 0;
            while (i < scale_level) {
                  factor *= 1.2;
                  ++i;
            }
      } else if(scale_level < 0) {
            i = scale_level;
            while (i < 0) {
                  factor /= 1.2;
                  ++i;
            }
      }
      
      if(pixel) font.setPixelSize((int) roundf(factor));
      else font.setPointSizeFloat(factor);
      
}

#include "kqalculate.moc"

Generated by  Doxygen 1.6.0   Back to index