You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
qalculate-tde/src/qalculateplotdialog.cpp

790 lines
31 KiB

/***************************************************************************
* 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. *
***************************************************************************/
#include "qalculateplotdialog.h"
#include "qalculateexpressionedit.h"
#include <klineedit.h>
#include <kpushbutton.h>
#include <kcombobox.h>
#include <tqlabel.h>
#include <tdelocale.h>
#include <tqcheckbox.h>
#include <tqradiobutton.h>
#include <tqbuttongroup.h>
#include <tqspinbox.h>
#include <tdemessagebox.h>
#include <tqlayout.h>
#include <ktextedit.h>
#include <tdelistview.h>
#include <tdeversion.h>
#if TDE_VERSION_MAJOR < 4 && TDE_VERSION_MINOR < 2
#include <tqtabwidget.h>
#else
#include <ktabwidget.h>
#endif
#include <tdefiledialog.h>
#include <tdeapplication.h>
#include <kstdguiitem.h>
extern PlotLegendPlacement default_plot_legend_placement;
extern bool default_plot_display_grid;
extern bool default_plot_full_border;
extern TQString default_plot_min;
extern TQString default_plot_max;
extern TQString default_plot_step;
extern int default_plot_sampling_rate;
extern bool default_plot_use_sampling_rate;
extern bool default_plot_rows;
extern int default_plot_type;
extern PlotStyle default_plot_style;
extern PlotSmoothing default_plot_smoothing;
extern TQString default_plot_variable;
extern bool default_plot_color;
extern bool enable_plot_expression_completion;
extern EvaluationOptions evalops;
QalculatePlotDialog::QalculatePlotDialog(TQWidget *parent, const char *name) : KDialogBase(parent, name, false, i18n("Plot"), User1 | Close | Help, Close, false, KStdGuiItem::save()) {
actionButton(Close)->setAutoDefault(false);
actionButton(Close)->setDefault(false);
actionButton(User1)->setAutoDefault(false);
actionButton(User1)->setDefault(false);
actionButton(User1)->setEnabled(false);
#if TDE_VERSION_MAJOR < 4 && TDE_VERSION_MINOR < 2
tabs = new TQTabWidget(this);
#else
tabs = new KTabWidget(this);
#endif
setMainWidget(tabs);
TQWidget *page1 = new TQWidget(this);
TQWidget *page2 = new TQWidget(this);
TQWidget *page3 = new TQWidget(this);
tabs->addTab(page1, i18n("Data"));
tabs->addTab(page2, i18n("Function Range"));
tabs->addTab(page3, i18n("Appearance"));
TQGridLayout *grid = new TQGridLayout(page1, 1, 1, spacingHint());
grid->addWidget(new TQLabel(i18n("Title:"), page1), 0, 0);
seriesTitleEdit = new KLineEdit(page1);
grid->addWidget(seriesTitleEdit, 0, 1);
grid->addWidget(new TQLabel(i18n("Expression:"), page1), 1, 0);
expressionEdit = new QalculateExpressionEdit(false, page1);
if(!enable_plot_expression_completion) expressionEdit->disableCompletion();
expressionEdit->updateCompletion();
grid->addWidget(expressionEdit, 1, 1);
TQHBoxLayout *hbox = new TQHBoxLayout(0, 0, spacingHint());
grid->addMultiCellLayout(hbox, 2, 2, 0, 1);
hbox->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Expanding, TQSizePolicy::Minimum));
typeGroup = new TQButtonGroup();
functionButton = new TQRadioButton(i18n("Function"), page1);
typeGroup->insert(functionButton, 0);
hbox->addWidget(functionButton);
vectorMatrixButton = new TQRadioButton(i18n("Vector/matrix"), page1);
typeGroup->insert(vectorMatrixButton, 1);
hbox->addWidget(vectorMatrixButton);
pairedMatrixButton = new TQRadioButton(i18n("Paired matrix"), page1);
typeGroup->insert(pairedMatrixButton, 2);
hbox->addWidget(pairedMatrixButton);
rowsButton = new TQCheckBox(i18n("Rows"), page1);
hbox->addWidget(rowsButton);
xVariableLabel = new TQLabel(i18n("X variable:"), page1);
grid->addWidget(xVariableLabel, 3, 0);
xVariableEdit = new KLineEdit(page1);
grid->addWidget(xVariableEdit, 3, 1);
grid->addWidget(new TQLabel(i18n("Style:"), page1), 4, 0);
styleCombo = new KComboBox(page1);
styleCombo->insertItem(i18n("Line"));
styleCombo->insertItem(i18n("Points"));
styleCombo->insertItem(i18n("Line with points"));
styleCombo->insertItem(i18n("Boxes/bars"));
styleCombo->insertItem(i18n("Histogram"));
styleCombo->insertItem(i18n("Steps"));
styleCombo->insertItem(i18n("Candlesticks"));
styleCombo->insertItem(i18n("Dots"));
grid->addWidget(styleCombo, 4, 1);
grid->addWidget(new TQLabel(i18n("Smoothing:"), page1), 5, 0);
smoothingCombo = new KComboBox(page1);
smoothingCombo->insertItem(i18n("None"));
smoothingCombo->insertItem(i18n("Monotonic"));
smoothingCombo->insertItem(i18n("Natural cubic splines"));
smoothingCombo->insertItem(i18n("Bezier"));
smoothingCombo->insertItem(i18n("Bezier (monotonic)"));
grid->addWidget(smoothingCombo, 5, 1);
grid->addWidget(new TQLabel(i18n("Y-axis:"), page1), 6, 0);
hbox = new TQHBoxLayout(0, 0, spacingHint());
grid->addLayout(hbox, 6, 1);
TQButtonGroup *group = new TQButtonGroup();
primaryButton = new TQRadioButton(i18n("Primary"), page1);
group->insert(primaryButton, 0);
hbox->addWidget(primaryButton);
secondaryButton = new TQRadioButton(i18n("Secondary"), page1);
group->insert(secondaryButton, 1);
hbox->addWidget(secondaryButton);
hbox->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Expanding, TQSizePolicy::Minimum));
hbox = new TQHBoxLayout(0, 0, spacingHint());
grid->addMultiCellLayout(hbox, 7, 7, 0, 1);
hbox->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Expanding, TQSizePolicy::Minimum));
addButton = new TQPushButton(i18n("Add"), page1);
hbox->addWidget(addButton);
modifyButton = new TQPushButton(i18n("Modify"), page1);
hbox->addWidget(modifyButton);
removeButton = new TQPushButton(i18n("Remove"), page1);
hbox->addWidget(removeButton);
seriesView = new TDEListView(page1);
seriesView->addColumn(i18n("Title"));
seriesView->addColumn(i18n("Expression"));
seriesView->setRootIsDecorated(false);
seriesView->setItemsRenameable(true);
seriesView->setRenameable(0, true);
seriesView->setRenameable(1, true);
seriesView->setItemsMovable(true);
seriesView->setSorting(-1);
grid->addMultiCellWidget(seriesView, 8, 8, 0, 1);
grid = new TQGridLayout(page2, 1, 1, spacingHint());
grid->addWidget(new TQLabel(i18n("Min:"), page2), 0, 0);
minEdit = new KLineEdit(page2);
grid->addWidget(minEdit, 0, 1);
grid->addWidget(new TQLabel(i18n("Max:"), page2), 1, 0);
maxEdit = new KLineEdit(page2);
grid->addWidget(maxEdit, 1, 1);
rangeGroup = new TQButtonGroup();
samplingRateButton = new TQRadioButton(i18n("Sampling rate:"), page2);
rangeGroup->insert(samplingRateButton, 0);
grid->addWidget(samplingRateButton, 2, 0);
samplingRateBox = new TQSpinBox(1, 10000, 10, page2);
grid->addWidget(samplingRateBox, 2, 1);
stepSizeButton = new TQRadioButton(i18n("Step size:"), page2);
rangeGroup->insert(stepSizeButton, 1);
grid->addWidget(stepSizeButton, 3, 0);
stepSizeEdit = new KLineEdit(page2);
grid->addWidget(stepSizeEdit, 3, 1);
hbox = new TQHBoxLayout(0, 0, spacingHint());
grid->addMultiCellLayout(hbox, 4, 4, 0, 1);
hbox->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Expanding, TQSizePolicy::Minimum));
applyRangeButton = new KPushButton(KStdGuiItem::apply(), page2);
hbox->addWidget(applyRangeButton);
grid->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Minimum, TQSizePolicy::Expanding), 5, 0);
grid = new TQGridLayout(page3, 1, 1, spacingHint());
grid->addWidget(new TQLabel(i18n("Title:"), page3), 0, 0);
titleEdit = new KLineEdit(page3);
grid->addWidget(titleEdit, 0, 1);
hbox = new TQHBoxLayout(0, 0, spacingHint());
grid->addMultiCellLayout(hbox, 1, 1, 0, 1);
gridButton = new TQCheckBox(i18n("Display grid"), page3);
hbox->addWidget(gridButton);
fullBorderButton = new TQCheckBox(i18n("Display full border"), page3);
hbox->addWidget(fullBorderButton);
hbox->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Expanding, TQSizePolicy::Minimum));
logXButton = new TQCheckBox(i18n("Logarithmic x scale:"), page3);
grid->addWidget(logXButton, 2, 0);
logXBox = new TQSpinBox(2, 100, 1, page3);
grid->addWidget(logXBox, 2, 1);
logYButton = new TQCheckBox(i18n("Logarithmic y scale:"), page3);
grid->addWidget(logYButton, 3, 0);
logYBox = new TQSpinBox(2, 100, 1, page3);
grid->addWidget(logYBox, 3, 1);
grid->addWidget(new TQLabel(i18n("X-axis label:"), page3), 4, 0);
xLabelEdit = new KLineEdit(page3);
grid->addWidget(xLabelEdit, 4, 1);
grid->addWidget(new TQLabel(i18n("Y-axis label:"), page3), 5, 0);
yLabelEdit = new KLineEdit(page3);
grid->addWidget(yLabelEdit, 5, 1);
grid->addWidget(new TQLabel(i18n("Color display:"), page3), 6, 0);
hbox = new TQHBoxLayout(0, 0, spacingHint());
grid->addLayout(hbox, 6, 1);
group = new TQButtonGroup();
colorButton = new TQRadioButton(i18n("Color"), page3);
group->insert(colorButton, 0);
hbox->addWidget(colorButton);
monochromeButton = new TQRadioButton(i18n("Monochrome"), page3);
group->insert(monochromeButton, 1);
hbox->addWidget(monochromeButton);
hbox->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Expanding, TQSizePolicy::Minimum));
grid->addWidget(new TQLabel(i18n("Legend placement:"), page3), 7, 0);
legendPlacementCombo = new KComboBox(page3);
legendPlacementCombo->insertItem(i18n("Hide"));
legendPlacementCombo->insertItem(i18n("Top-left"));
legendPlacementCombo->insertItem(i18n("Top-right"));
legendPlacementCombo->insertItem(i18n("Bottom-left"));
legendPlacementCombo->insertItem(i18n("Bottom-right"));
legendPlacementCombo->insertItem(i18n("Below"));
legendPlacementCombo->insertItem(i18n("Outside"));
grid->addWidget(legendPlacementCombo, 7, 1);
hbox = new TQHBoxLayout(0, 0, spacingHint());
grid->addMultiCellLayout(hbox, 8, 8, 0, 1);
hbox->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Expanding, TQSizePolicy::Minimum));
applyAppearanceButton = new KPushButton(KStdGuiItem::apply(), page3);
hbox->addWidget(applyAppearanceButton);
grid->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Minimum, TQSizePolicy::Expanding), 9, 0);
primaryButton->setChecked(true);
modifyButton->setEnabled(false);
removeButton->setEnabled(false);
gridButton->setChecked(default_plot_display_grid);
fullBorderButton->setChecked(default_plot_full_border);
rowsButton->setChecked(default_plot_rows);
colorButton->setChecked(default_plot_color);
monochromeButton->setChecked(!default_plot_color);
minEdit->setText(default_plot_min);
maxEdit->setText(default_plot_max);
stepSizeEdit->setText(default_plot_step);
xVariableEdit->setText(default_plot_variable);
samplingRateButton->setChecked(default_plot_use_sampling_rate);
samplingRateBox->setEnabled(default_plot_use_sampling_rate);
stepSizeButton->setChecked(!default_plot_use_sampling_rate);
stepSizeEdit->setEnabled(!default_plot_use_sampling_rate);
logXBox->setEnabled(false);
logYBox->setEnabled(false);
switch(default_plot_type) {
case 1: {vectorMatrixButton->setChecked(true); break;}
case 2: {pairedMatrixButton->setChecked(true); break;}
default: {functionButton->setChecked(true);}
}
rowsButton->setEnabled(default_plot_type == 1 || default_plot_type == 2);
xVariableEdit->setEnabled(default_plot_type != 1 && default_plot_type != 2);
xVariableLabel->setEnabled(default_plot_type != 1 && default_plot_type != 2);
switch(default_plot_legend_placement) {
case PLOT_LEGEND_NONE: {legendPlacementCombo->setCurrentItem(0); break;}
case PLOT_LEGEND_TOP_LEFT: {legendPlacementCombo->setCurrentItem(1); break;}
case PLOT_LEGEND_TOP_RIGHT: {legendPlacementCombo->setCurrentItem(2); break;}
case PLOT_LEGEND_BOTTOM_LEFT: {legendPlacementCombo->setCurrentItem(3); break;}
case PLOT_LEGEND_BOTTOM_RIGHT: {legendPlacementCombo->setCurrentItem(4); break;}
case PLOT_LEGEND_BELOW: {legendPlacementCombo->setCurrentItem(5); break;}
case PLOT_LEGEND_OUTSIDE: {legendPlacementCombo->setCurrentItem(6); break;}
}
switch(default_plot_smoothing) {
case PLOT_SMOOTHING_NONE: {smoothingCombo->setCurrentItem(0); break;}
case PLOT_SMOOTHING_UNIQUE: {smoothingCombo->setCurrentItem(1); break;}
case PLOT_SMOOTHING_CSPLINES: {smoothingCombo->setCurrentItem(2); break;}
case PLOT_SMOOTHING_BEZIER: {smoothingCombo->setCurrentItem(3); break;}
case PLOT_SMOOTHING_SBEZIER: {smoothingCombo->setCurrentItem(4); break;}
}
switch(default_plot_style) {
case PLOT_STYLE_LINES: {styleCombo->setCurrentItem(0); break;}
case PLOT_STYLE_POINTS: {styleCombo->setCurrentItem(1); break;}
case PLOT_STYLE_POINTS_LINES: {styleCombo->setCurrentItem(2); break;}
case PLOT_STYLE_BOXES: {styleCombo->setCurrentItem(3); break;}
case PLOT_STYLE_HISTOGRAM: {styleCombo->setCurrentItem(4); break;}
case PLOT_STYLE_STEPS: {styleCombo->setCurrentItem(5); break;}
case PLOT_STYLE_CANDLESTICKS: {styleCombo->setCurrentItem(6); break;}
case PLOT_STYLE_DOTS: {styleCombo->setCurrentItem(7); break;}
}
samplingRateBox->setValue(default_plot_sampling_rate);
seriesTitleEdit->setFocus();
connect(seriesTitleEdit, SIGNAL(returnPressed()), expressionEdit, SLOT(setFocus()));
connect(expressionEdit, SIGNAL(returnPressed()), this, SLOT(expressionActivated()));
connect(typeGroup, SIGNAL(clicked(int)), this, SLOT(typeChanged(int)));
connect(rangeGroup, SIGNAL(clicked(int)), this, SLOT(rangeTypeChanged(int)));
connect(logXButton, SIGNAL(toggled(bool)), logXBox, SLOT(setEnabled(bool)));
connect(logYButton, SIGNAL(toggled(bool)), logYBox, SLOT(setEnabled(bool)));
connect(applyRangeButton, SIGNAL(clicked()), this, SLOT(applyRange()));
connect(applyAppearanceButton, SIGNAL(clicked()), this, SLOT(applyAppearance()));
connect(seriesView, SIGNAL(selectionChanged()), this, SLOT(seriesSelected()));
connect(seriesView, SIGNAL(itemRenamed(TQListViewItem*, const TQString&, int)), this, SLOT(seriesItemRenamed(TQListViewItem*, const TQString&, int)));
connect(addButton, SIGNAL(clicked()), this, SLOT(addSeries()));
connect(modifyButton, SIGNAL(clicked()), this, SLOT(modifySeries()));
connect(removeButton, SIGNAL(clicked()), this, SLOT(removeSeries()));
connect(this, SIGNAL(user1Clicked()), this, SLOT(savePlot()));
connect(this, SIGNAL(finished()), this, SLOT(onClosing()));
}
QalculatePlotDialog::~QalculatePlotDialog() {}
void QalculatePlotDialog::slotHelp() {
TDEApplication::kApplication()->invokeHelp("qalculate-plotting");
}
void QalculatePlotDialog::saveMode() {
enable_plot_expression_completion = expressionEdit->completionEnabled();
default_plot_display_grid = gridButton->isChecked();
default_plot_full_border = fullBorderButton->isChecked();
default_plot_rows = rowsButton->isChecked();
default_plot_color = colorButton->isChecked();
default_plot_min = minEdit->text().ascii();
default_plot_max = maxEdit->text().ascii();
default_plot_step = stepSizeEdit->text().ascii();
default_plot_variable = xVariableEdit->text().ascii();
default_plot_use_sampling_rate = samplingRateButton->isChecked();
if(vectorMatrixButton->isChecked()) {
default_plot_type = 1;
} else if(pairedMatrixButton->isChecked()) {
default_plot_type = 2;
} else {
default_plot_type = 0;
}
switch(legendPlacementCombo->currentItem()) {
case 0: {default_plot_legend_placement = PLOT_LEGEND_NONE; break;}
case 1: {default_plot_legend_placement = PLOT_LEGEND_TOP_LEFT; break;}
case 2: {default_plot_legend_placement = PLOT_LEGEND_TOP_RIGHT; break;}
case 3: {default_plot_legend_placement = PLOT_LEGEND_BOTTOM_LEFT; break;}
case 4: {default_plot_legend_placement = PLOT_LEGEND_BOTTOM_RIGHT; break;}
case 5: {default_plot_legend_placement = PLOT_LEGEND_BELOW; break;}
case 6: {default_plot_legend_placement = PLOT_LEGEND_OUTSIDE; break;}
}
switch(smoothingCombo->currentItem()) {
case 0: {default_plot_smoothing = PLOT_SMOOTHING_NONE; break;}
case 1: {default_plot_smoothing = PLOT_SMOOTHING_UNIQUE; break;}
case 2: {default_plot_smoothing = PLOT_SMOOTHING_CSPLINES; break;}
case 3: {default_plot_smoothing = PLOT_SMOOTHING_BEZIER; break;}
case 4: {default_plot_smoothing = PLOT_SMOOTHING_SBEZIER; break;}
}
switch(styleCombo->currentItem()) {
case 0: {default_plot_style = PLOT_STYLE_LINES; break;}
case 1: {default_plot_style = PLOT_STYLE_POINTS; break;}
case 2: {default_plot_style = PLOT_STYLE_POINTS_LINES; break;}
case 3: {default_plot_style = PLOT_STYLE_BOXES; break;}
case 4: {default_plot_style = PLOT_STYLE_HISTOGRAM; break;}
case 5: {default_plot_style = PLOT_STYLE_STEPS; break;}
case 6: {default_plot_style = PLOT_STYLE_CANDLESTICKS; break;}
case 7: {default_plot_style = PLOT_STYLE_DOTS; break;}
}
default_plot_sampling_rate = samplingRateBox->value();
}
void QalculatePlotDialog::onClosing() {
tabs->setCurrentPage(0);
modifyButton->setEnabled(false);
removeButton->setEnabled(false);
actionButton(User1)->setEnabled(false);
TQListViewItemIterator it(seriesView);
while(it.current()) {
MathStructure *y_vector = itemYVector[it.current()], *x_vector = itemXVector[it.current()];
if(y_vector) delete y_vector;
if(x_vector) delete x_vector;
++it;
}
itemStyle.clear();
itemType.clear();
itemAxis.clear();
itemSmoothing.clear();
itemRows.clear();
itemXVector.clear();
itemYVector.clear();
itemXVariable.clear();
seriesView->clear();
expressionEdit->clear();
seriesTitleEdit->clear();
CALCULATOR->closeGnuplot();
}
void QalculatePlotDialog::seriesItemRenamed(TQListViewItem *i, const TQString &str, int col) {
if(!i) return;
if(col == 0) {
updatePlot();
} else if(col == 1) {
if(str.isEmpty()) {
KMessageBox::error(this, i18n("Empty expression."));
}
MathStructure *x_vector = itemXVector[i], *y_vector = itemYVector[i];
if(x_vector) delete x_vector;
if(y_vector) delete y_vector;
x_vector = NULL;
y_vector = NULL;
generatePlotSeries(&x_vector, &y_vector, itemType[i], str.ascii(), itemXVariable[i].ascii());
itemXVector[i] = x_vector;
itemYVector[i] = y_vector;
updatePlot();
}
seriesSelected();
}
void QalculatePlotDialog::seriesSelected() {
TQListViewItem *i = seriesView->selectedItem();
if(i) {
modifyButton->setEnabled(true);
removeButton->setEnabled(true);
expressionEdit->setText(i->text(1));
seriesTitleEdit->setText(i->text(0));
xVariableEdit->setText(itemXVariable[i]);
styleCombo->setCurrentItem(itemStyle[i]);
smoothingCombo->setCurrentItem(itemSmoothing[i]);
typeGroup->setButton(itemType[i]);
secondaryButton->setChecked(itemAxis[i] == 2);
primaryButton->setChecked(itemAxis[i] != 2);
rowsButton->setChecked(itemRows[i]);
} else {
modifyButton->setEnabled(false);
removeButton->setEnabled(false);
}
}
void QalculatePlotDialog::rangeTypeChanged(int i) {
stepSizeEdit->setEnabled(i == 1);
samplingRateBox->setEnabled(i == 0);
}
void QalculatePlotDialog::typeChanged(int i) {
rowsButton->setEnabled(i == 1 || i == 2);
xVariableEdit->setEnabled(i != 1 && i != 2);
xVariableLabel->setEnabled(i != 1 && i != 2);
}
void QalculatePlotDialog::expressionActivated() {
TQListViewItem *i = seriesView->selectedItem();
if(i) {
modifySeries();
} else {
addSeries();
}
}
void QalculatePlotDialog::addSeries() {
TQString expression = expressionEdit->text();
if(expression.stripWhiteSpace().isEmpty()) {
expressionEdit->setFocus();
KMessageBox::error(this, i18n("Empty expression."));
return;
}
int type = 0, axis = 1;
bool rows = false;
TQString title = seriesTitleEdit->text();
if(vectorMatrixButton->isChecked()) {
type = 1;
} else if(pairedMatrixButton->isChecked()) {
type = 2;
}
TQString str_x = xVariableEdit->text().stripWhiteSpace();
if(str_x.isEmpty() && type == 0) {
xVariableEdit->setFocus();
KMessageBox::error(this, i18n("Empty x variable."));
return;
}
expressionEdit->addToHistory(expression);
if(secondaryButton->isChecked()) {
axis = 2;
}
if((type == 1 || type == 2) && title.isEmpty()) {
Variable *v = CALCULATOR->getActiveVariable(expression.ascii());
if(v) {
title = v->title(false).c_str();
}
}
MathStructure *x_vector, *y_vector;
generatePlotSeries(&x_vector, &y_vector, type, expression.ascii(), str_x.ascii());
rows = rowsButton->isChecked();
TQListViewItem *i = new TDEListViewItem(seriesView, seriesView->lastChild(), title, expression);
itemStyle[i] = styleCombo->currentItem();
itemSmoothing[i] = smoothingCombo->currentItem();
itemType[i] = type;
itemAxis[i] = axis;
itemRows[i] = rows;
itemXVector[i] = x_vector;
itemYVector[i] = y_vector;
itemXVariable[i] = str_x;
seriesView->setSelected(i, true);
updatePlot();
}
void QalculatePlotDialog::modifySeries() {
TQListViewItem *i = seriesView->selectedItem();
if(i) {
TQString expression = expressionEdit->text();
if(expression.stripWhiteSpace().isEmpty()) {
expressionEdit->setFocus();
KMessageBox::error(this, i18n("Empty expression."));
return;
}
int type = 0, axis = 1;
TQString title = seriesTitleEdit->text();
if(vectorMatrixButton->isChecked()) {
type = 1;
} else if(pairedMatrixButton->isChecked()) {
type = 2;
}
TQString str_x = xVariableEdit->text().stripWhiteSpace();
if(str_x.isEmpty() && type == 0) {
xVariableEdit->setFocus();
KMessageBox::error(this, i18n("Empty x variable."));
return;
}
expressionEdit->addToHistory(expression);
if(secondaryButton->isChecked()) {
axis = 2;
}
if((type == 1 || type == 2) && title.isEmpty()) {
Variable *v = CALCULATOR->getActiveVariable(expression.ascii());
if(v) {
title = v->title(false).c_str();
}
}
MathStructure *x_vector = itemXVector[i], *y_vector = itemYVector[i];
if(x_vector) delete x_vector;
if(y_vector) delete y_vector;
x_vector = NULL;
y_vector = NULL;
generatePlotSeries(&x_vector, &y_vector, type, expression.ascii(), str_x.ascii());
i->setText(0, title);
i->setText(1, expression);
itemStyle[i] = styleCombo->currentItem();
itemSmoothing[i] = smoothingCombo->currentItem();
itemType[i] = type;
itemAxis[i] = axis;
itemRows[i] = rowsButton->isChecked();
itemXVector[i] = x_vector;
itemYVector[i] = y_vector;
itemXVariable[i] = str_x;
updatePlot();
}
}
void QalculatePlotDialog::removeSeries() {
TQListViewItem *i = seriesView->selectedItem();
if(i) {
MathStructure *x_vector = itemXVector[i], *y_vector = itemYVector[i];
if(x_vector) delete x_vector;
if(y_vector) delete y_vector;
itemStyle.erase(i);
itemSmoothing.erase(i);
itemType.erase(i);
itemAxis.erase(i);
itemRows.erase(i);
itemXVector.erase(i);
itemYVector.erase(i);
itemXVariable.erase(i);
delete i;
expressionEdit->clear();
seriesTitleEdit->clear();
updatePlot();
}
}
void QalculatePlotDialog::applyRange() {
TQListViewItemIterator it(seriesView);
while(it.current()) {
MathStructure *x_vector = itemXVector[it.current()], *y_vector = itemYVector[it.current()];
if(y_vector) delete y_vector;
if(x_vector) delete x_vector;
x_vector = NULL;
y_vector = NULL;
generatePlotSeries(&x_vector, &y_vector, itemType[it.current()], it.current()->text(1).ascii(), itemXVariable[it.current()].ascii());
itemXVector[it.current()] = x_vector;
itemYVector[it.current()] = y_vector;
++it;
}
updatePlot();
}
void QalculatePlotDialog::applyAppearance() {
updatePlot();
}
bool QalculatePlotDialog::generatePlot(PlotParameters &pp, vector<MathStructure> &y_vectors, vector<MathStructure> &x_vectors, vector<PlotDataParameters*> &pdps) {
TQListViewItemIterator it(seriesView);
if(!it.current()) {
return false;
}
while(it.current()) {
int count = 1;
TQString title = it.current()->text(0), expression = it.current()->text(1);
int style = itemStyle[it.current()];
int smoothing = itemSmoothing[it.current()];
int type = itemType[it.current()];
int axis = itemAxis[it.current()];
bool rows = itemRows[it.current()];
MathStructure *x_vector = itemXVector[it.current()];
MathStructure *y_vector = itemYVector[it.current()];
if(type == 1) {
if(y_vector->isMatrix()) {
count = 0;
if(rows) {
for(size_t i = 1; i <= y_vector->rows(); i++) {
y_vectors.push_back(m_undefined);
y_vector->rowToVector(i, y_vectors[y_vectors.size() - 1]);
x_vectors.push_back(m_undefined);
count++;
}
} else {
for(size_t i = 1; i <= y_vector->columns(); i++) {
y_vectors.push_back(m_undefined);
y_vector->columnToVector(i, y_vectors[y_vectors.size() - 1]);
x_vectors.push_back(m_undefined);
count++;
}
}
} else if(y_vector->isVector()) {
y_vectors.push_back(*y_vector);
x_vectors.push_back(m_undefined);
} else {
y_vectors.push_back(*y_vector);
y_vectors[y_vectors.size() - 1].transform(STRUCT_VECTOR);
x_vectors.push_back(m_undefined);
}
} else if(type == 2) {
if(y_vector->isMatrix()) {
count = 0;
if(rows) {
for(size_t i = 1; i <= y_vector->rows(); i += 2) {
y_vectors.push_back(m_undefined);
y_vector->rowToVector(i, y_vectors[y_vectors.size() - 1]);
x_vectors.push_back(m_undefined);
y_vector->rowToVector(i + 1, x_vectors[x_vectors.size() - 1]);
count++;
}
} else {
for(size_t i = 1; i <= y_vector->columns(); i += 2) {
y_vectors.push_back(m_undefined);
y_vector->columnToVector(i, y_vectors[y_vectors.size() - 1]);
x_vectors.push_back(m_undefined);
y_vector->columnToVector(i + 1, x_vectors[x_vectors.size() - 1]);
count++;
}
}
} else if(y_vector->isVector()) {
y_vectors.push_back(*y_vector);
x_vectors.push_back(m_undefined);
} else {
y_vectors.push_back(*y_vector);
y_vectors[y_vectors.size() - 1].transform(STRUCT_VECTOR);
x_vectors.push_back(m_undefined);
}
} else {
y_vectors.push_back(*y_vector);
x_vectors.push_back(*x_vector);
}
for(int i = 0; i < count; i++) {
PlotDataParameters *pdp = new PlotDataParameters();
pdp->title = title.ascii();
if(count > 1) {
pdp->title += " :";
pdp->title += i2s(i + 1);
}
remove_blank_ends(pdp->title);
if(pdp->title.empty()) {
pdp->title = expression.ascii();
}
switch(smoothing) {
case 0: {pdp->smoothing = PLOT_SMOOTHING_NONE; break;}
case 1: {pdp->smoothing = PLOT_SMOOTHING_UNIQUE; break;}
case 2: {pdp->smoothing = PLOT_SMOOTHING_CSPLINES; break;}
case 3: {pdp->smoothing = PLOT_SMOOTHING_BEZIER; break;}
case 4: {pdp->smoothing = PLOT_SMOOTHING_SBEZIER; break;}
}
switch(style) {
case 0: {pdp->style = PLOT_STYLE_LINES; break;}
case 1: {pdp->style = PLOT_STYLE_POINTS; break;}
case 2: {pdp->style = PLOT_STYLE_POINTS_LINES; break;}
case 3: {pdp->style = PLOT_STYLE_DOTS; break;}
case 4: {pdp->style = PLOT_STYLE_BOXES; break;}
case 5: {pdp->style = PLOT_STYLE_HISTOGRAM; break;}
case 6:{pdp->style = PLOT_STYLE_STEPS; break;}
case 7: {pdp->style = PLOT_STYLE_CANDLESTICKS; break;}
}
pdp->yaxis2 = (axis == 2);
pdps.push_back(pdp);
}
++it;
}
switch(legendPlacementCombo->currentItem()) {
case 0: {pp.legend_placement = PLOT_LEGEND_NONE; break;}
case 1: {pp.legend_placement = PLOT_LEGEND_TOP_LEFT; break;}
case 2: {pp.legend_placement = PLOT_LEGEND_TOP_RIGHT; break;}
case 3: {pp.legend_placement = PLOT_LEGEND_BOTTOM_LEFT; break;}
case 4: {pp.legend_placement = PLOT_LEGEND_BOTTOM_RIGHT; break;}
case 5: {pp.legend_placement = PLOT_LEGEND_BELOW; break;}
case 6: {pp.legend_placement = PLOT_LEGEND_OUTSIDE; break;}
}
pp.title = titleEdit->text().ascii();
pp.x_label = xLabelEdit->text().ascii();
pp.y_label = yLabelEdit->text().ascii();
pp.grid = gridButton->isChecked();
pp.x_log = logXButton->isChecked();
pp.y_log = logYButton->isChecked();
pp.x_log_base = logXBox->value();
pp.y_log_base = logYBox->value();
pp.color = colorButton->isChecked();
pp.show_all_borders = fullBorderButton->isChecked();
return true;
}
void QalculatePlotDialog::savePlot() {
TQString title = titleEdit->text().ascii();
if(title.isEmpty()) {
title = "plot.png";
} else {
title += ".png";
}
TQString filename;
while(true) {
filename = KFileDialog::getSaveFileName(title, "image/png image/svg application/postscript image/x-eps /text/x-tex image/x-xfig", this, i18n("Save Image"));
if(filename.isEmpty()) {
return;
} else {
if(TQFile::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;
}
}
}
vector<MathStructure> y_vectors;
vector<MathStructure> x_vectors;
vector<PlotDataParameters*> pdps;
PlotParameters pp;
if(generatePlot(pp, y_vectors, x_vectors, pdps)) {
pp.filename = filename.ascii();
pp.filetype = PLOT_FILETYPE_AUTO;
CALCULATOR->plotVectors(&pp, y_vectors, x_vectors, pdps);
for(size_t i = 0; i < pdps.size(); i++) {
if(pdps[i]) delete pdps[i];
}
}
}
void QalculatePlotDialog::updatePlot() {
vector<MathStructure> y_vectors;
vector<MathStructure> x_vectors;
vector<PlotDataParameters*> pdps;
PlotParameters pp;
if(!generatePlot(pp, y_vectors, x_vectors, pdps)) {
CALCULATOR->closeGnuplot();
actionButton(User1)->setEnabled(false);
return;
}
CALCULATOR->plotVectors(&pp, y_vectors, x_vectors, pdps);
actionButton(User1)->setEnabled(true);
for(size_t i = 0; i < pdps.size(); i++) {
if(pdps[i]) delete pdps[i];
}
}
void QalculatePlotDialog::generatePlotSeries(MathStructure **x_vector, MathStructure **y_vector, int type, string str, string str_x) {
EvaluationOptions eo;
eo.approximation = APPROXIMATION_APPROXIMATE;
eo.parse_options = evalops.parse_options;
eo.parse_options.read_precision = DONT_READ_PRECISION;
if(type == 1 || type == 2) {
*y_vector = new MathStructure(CALCULATOR->calculate(CALCULATOR->unlocalizeExpression(str, evalops.parse_options), eo));
*x_vector = NULL;
} else {
MathStructure min(CALCULATOR->calculate(CALCULATOR->unlocalizeExpression(minEdit->text().ascii(), evalops.parse_options), eo));
MathStructure max(CALCULATOR->calculate(CALCULATOR->unlocalizeExpression(maxEdit->text().ascii(), evalops.parse_options), eo));
*x_vector = new MathStructure();
(*x_vector)->clearVector();
if(stepSizeButton->isChecked()) {
*y_vector = new MathStructure(CALCULATOR->expressionToPlotVector(str, min, max, CALCULATOR->calculate(CALCULATOR->unlocalizeExpression(stepSizeEdit->text().ascii(), evalops.parse_options), eo), *x_vector, str_x, evalops.parse_options));
} else {
*y_vector = new MathStructure(CALCULATOR->expressionToPlotVector(str, min, max, samplingRateBox->value(), *x_vector, str_x, evalops.parse_options));
}
}
}
#include "qalculateplotdialog.moc"