maindlg.cpp 26.8 KB
Newer Older
1
2
3
/*
* KmPlot - a math. function plotter for the KDE-Desktop
*
Christoph Feck's avatar
Christoph Feck committed
4
* Copyright (C) 1998, 1999, 2000, 2002  Klaus-Dieter Möller <kd.moeller@t-online.de>
David Saxton's avatar
David Saxton committed
5
*                                 2006  David Saxton <david@bluehaze.org>
6
*
7
8
9
10
11
12
13
* This file is part of the KDE Project.
* KmPlot is part of the KDE-EDU Project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
14
*
15
16
17
18
* 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.
19
*
20
21
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
Dirk Mueller's avatar
Dirk Mueller committed
22
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23
24
25
*
*/

Peter Hedlund's avatar
Peter Hedlund committed
26
27
#include "maindlg.h"

28
// Qt includes
29
#include <QClipboard>
30
#include <QDebug>
31
#include <QFileDialog>
32
#include <QIcon>
33
#include <QImageWriter>
34
#include <QMainWindow>
35
#include <QMimeDatabase>
36
#include <QMimeType>
Laurent Montel's avatar
Laurent Montel committed
37
#include <QPixmap>
38
#include <QPrintDialog>
Yuri Chornoivan's avatar
Yuri Chornoivan committed
39
40
#include <QPrintPreviewDialog>
#include <QPrintPreviewWidget>
41
#include <QSvgGenerator>
42
#include <QTemporaryFile>
David Saxton's avatar
David Saxton committed
43
#include <QTimer>
44
45

// KDE includes
46
47
48
49
#include <KActionCollection>
#include <KConfigDialog>
#include <KConfigDialogManager>
#include <KHelpClient>
50
#include <KIO/StatJob>
51
52
53
54
55
56
#include <KIO/StoredTransferJob>
#include <KLineEdit>
#include <KMessageBox>
#include <KStandardAction>
#include <KToolBar>
#include <KToolInvocation>
57

58
// local includes
59
#include "calculator.h"
60
#include "functiontools.h"
61
#include "functioneditor.h"
62
#include "kconstanteditor.h"
63
#include "xparser.h"
64

65
#include "settings.h"
66
67
#include "ui_settingspagecolor.h"
#include "ui_settingspagefonts.h"
68
#include "ui_settingspagegeneral.h"
David Saxton's avatar
David Saxton committed
69
#include "ui_settingspagediagram.h"
70
#include "ksliderwindow.h"
71
#include "maindlgadaptor.h"
72

73
74
#include <assert.h>

75
76
class XParser;
class KmPlotIO;
77

78
79
80
81
82
83

class SettingsPageColor : public QWidget, public Ui::SettingsPageColor
{
    public:
        SettingsPageColor( QWidget * parent = 0 )
    : QWidget( parent )
84
85
        {
			setupUi(this);
Laurent Montel's avatar
Laurent Montel committed
86
			layout()->setContentsMargins(0, 0, 0, 0);
87
		}
88
89
90
91
92
93
};

class SettingsPageFonts : public QWidget, public Ui::SettingsPageFonts
{
    public:
        SettingsPageFonts( QWidget * parent = 0 )
94
95
96
	: QWidget( parent )
		{
			setupUi(this);
Laurent Montel's avatar
Laurent Montel committed
97
			layout()->setContentsMargins(0, 0, 0, 0);
98
		}
99
100
101
102
103
104
};

class SettingsPageGeneral : public QWidget, public Ui::SettingsPageGeneral
{
    public:
        SettingsPageGeneral( QWidget * parent = 0 )
105
106
107
	: QWidget( parent )
		{
			setupUi(this);
Laurent Montel's avatar
Laurent Montel committed
108
                        layout()->setContentsMargins(0, 0, 0, 0);
109
		}
110
111
};

David Saxton's avatar
David Saxton committed
112
113
114
115
116
class SettingsPageDiagram : public QWidget, public Ui::SettingsPageDiagram
{
	public:
		SettingsPageDiagram( QWidget * parent = 0 )
	: QWidget( parent )
117
118
		{
			setupUi(this);
Laurent Montel's avatar
Laurent Montel committed
119
			layout()->setContentsMargins(0, 0, 0, 0);
120
		}
David Saxton's avatar
David Saxton committed
121
122
};

123
bool MainDlg::oldfileversion;
124
125
MainDlg * MainDlg::m_self = 0;

126
K_PLUGIN_CLASS_WITH_JSON(MainDlg, "kmplot_part.json")
127

128
//BEGIN class MainDlg
129
MainDlg::MainDlg(QWidget *parentWidget, QObject *parent, const QVariantList& ) :
130
		KParts::ReadWritePart( parent ),
131
132
		m_recentFiles( 0 ),
		m_modified(false),
133
134
		m_parent(parentWidget),
		m_rootValue( 0 )
Matthias Messmer's avatar
Matthias Messmer committed
135
{
136
137
	assert( !m_self ); // this class should only be constructed once
	m_self = this;
Stephan Kulow's avatar
Stephan Kulow committed
138

139
	qDebug() << "parentWidget->objectName():" << parentWidget->objectName();
Fredrik Edemar's avatar
Fredrik Edemar committed
140
	if ( QString(parentWidget->objectName()).startsWith("KmPlot") )
141
142
143
144
145
146
147
148
149
150
	{
		setXMLFile("kmplot_part.rc");
		m_readonly = false;
	}
	else
	{
		setXMLFile("kmplot_part_readonly.rc");
		m_readonly = true;
		new BrowserExtension(this); // better integration with Konqueror
	}
Stephan Kulow's avatar
Stephan Kulow committed
151

152
	m_coordsDialog = 0;
153
	m_constantEditor = 0;
Inge Wallin's avatar
Inge Wallin committed
154
155
	m_popupmenu = new QMenu( parentWidget );
	m_newPlotMenu = new QMenu( parentWidget );
156
	(void) new View( m_readonly, m_popupmenu, parentWidget );
157
	connect( View::self(), &View::setStatusBarText, this, &MainDlg::setReadOnlyStatusBarText );
Stephan Kulow's avatar
Stephan Kulow committed
158

159
	m_functionEditor = 0;
160
161
	if ( !m_readonly )
	{
162
		m_functionEditor = new FunctionEditor( m_newPlotMenu, parentWidget );
163
164
		static_cast<QMainWindow*>(parentWidget)->addDockWidget( Qt::LeftDockWidgetArea, m_functionEditor );
	}
Stephan Kulow's avatar
Stephan Kulow committed
165

166
167
	setWidget( View::self() );
	View::self()->setFocusPolicy(Qt::ClickFocus);
168
	m_functionTools = new FunctionTools(m_parent);
169
	m_calculator = new Calculator( m_parent );
170
	setupActions();
171
	XParser::self()->constants()->load();
172
	kmplotio = new KmPlotIO();
Laurent Montel's avatar
Laurent Montel committed
173
	m_config = KSharedConfig::openConfig();
Stephan Kulow's avatar
ported    
Stephan Kulow committed
174
	m_recentFiles->loadEntries( m_config->group( QString() ) );
Stephan Kulow's avatar
Stephan Kulow committed
175
176


David Saxton's avatar
David Saxton committed
177
178
179
180
	//BEGIN undo/redo stuff
	m_currentState = kmplotio->currentState();
	m_saveCurrentStateTimer = new QTimer( this );
	m_saveCurrentStateTimer->setSingleShot( true );
181
	connect( m_saveCurrentStateTimer, &QTimer::timeout, this, &MainDlg::saveCurrentState );
David Saxton's avatar
David Saxton committed
182
	//END undo/redo stuff
Stephan Kulow's avatar
Stephan Kulow committed
183

Yuri Chornoivan's avatar
Yuri Chornoivan committed
184
	// Let's create a Configure Dialog
185
	m_settingsDialog = new KConfigDialog( parentWidget, "settings", Settings::self() );
186

Yuri Chornoivan's avatar
Yuri Chornoivan committed
187
	QMetaObject::invokeMethod(m_settingsDialog, "setHelp", Qt::DirectConnection, Q_ARG(QString, QString::fromLatin1("configuration")), Q_ARG(QString, QString::fromLatin1("kmplot")));
188

189
	// create and add the page(s)
190
191
192
	m_generalSettings = new SettingsPageGeneral( View::self() );
	m_colorSettings = new SettingsPageColor( View::self() );
	m_fontsSettings = new SettingsPageFonts( View::self() );
David Saxton's avatar
David Saxton committed
193
	m_diagramSettings = new SettingsPageDiagram( View::self() );
194

195
	// Make sure the dialog is at a good default size (hmm QDialog should do this automatically?)
196
197
198
	QSize minSize = m_generalSettings->layout()->minimumSize()
			.expandedTo( m_colorSettings->layout()->minimumSize() )
			.expandedTo( m_fontsSettings->layout()->minimumSize() )
199
			.expandedTo( m_diagramSettings->layout()->minimumSize() );
200
	m_generalSettings->setMinimumSize( minSize );
Stephan Kulow's avatar
Stephan Kulow committed
201

Pino Toscano's avatar
Pino Toscano committed
202
	m_settingsDialog->addPage( m_generalSettings, i18n("General"), "kmplot", i18n("General Settings") );
David Saxton's avatar
David Saxton committed
203
	m_settingsDialog->addPage( m_diagramSettings, i18n("Diagram"), "coords", i18n("Diagram Appearance") );
Pino Toscano's avatar
Pino Toscano committed
204
205
	m_settingsDialog->addPage( m_colorSettings, i18n("Colors"), "preferences-desktop-color", i18n("Colors") );
	m_settingsDialog->addPage( m_fontsSettings, i18n("Fonts"), "preferences-desktop-font", i18n("Fonts") );
206
207
	// User edited the configuration - update your local copies of the
	// configuration data
208
	connect( m_settingsDialog, &KConfigDialog::settingsChanged, View::self(), QOverload<>::of(&View::drawPlot) );
209
210
211


    new MainDlgAdaptor(this);
212
    QDBusConnection::sessionBus().registerObject("/maindlg", this);
213

214
215
216
217
}

MainDlg::~MainDlg()
{
Stephan Kulow's avatar
ported    
Stephan Kulow committed
218
        m_recentFiles->saveEntries( m_config->group( QString() ) );
219
	XParser::self()->constants()->save();
220
	delete kmplotio;
221
222
223
}

void MainDlg::setupActions()
Matthias Messmer's avatar
Matthias Messmer committed
224
{
225
	// standard actions
226
        m_recentFiles = KStandardAction::openRecent( this, SLOT(slotOpenRecent(QUrl)), this );
Christoph Feck's avatar
Christoph Feck committed
227
        actionCollection()->addAction( "file_open_recent", m_recentFiles );
228
	actionCollection()->addAction( KStandardAction::Print, "file_print", this, SLOT(slotPrint()) );
Yuri Chornoivan's avatar
Yuri Chornoivan committed
229
	actionCollection()->addAction( KStandardAction::PrintPreview, "file_print_preview", this, SLOT(slotPrintPreview()) );
230
231
	KStandardAction::save( this, SLOT(slotSave()), actionCollection() );
	KStandardAction::saveAs( this, SLOT(slotSaveas()), actionCollection() );
232

233
	QAction *prefs  = KStandardAction::preferences( this, SLOT(slotSettings()), actionCollection());
234
	prefs->setText( i18n( "Configure KmPlot..." ) );
235

236
	// KmPlot specific actions
Stephan Kulow's avatar
Stephan Kulow committed
237

238
	//BEGIN file menu
239
240
	QAction * exportAction = actionCollection()->addAction( "export" );
        exportAction->setText( i18n( "E&xport..." ) );
Christoph Feck's avatar
Christoph Feck committed
241
        exportAction->setIcon( QIcon::fromTheme( "document-export" ) );
242
	connect( exportAction, &QAction::triggered, this, &MainDlg::slotExport );
243
244
	//END file menu

Stephan Kulow's avatar
Stephan Kulow committed
245

David Saxton's avatar
David Saxton committed
246
	//BEGIN edit menu
Aaron J. Seigo's avatar
Aaron J. Seigo committed
247
	m_undoAction = KStandardAction::undo( this, SLOT(undo()), actionCollection() );
David Saxton's avatar
David Saxton committed
248
	m_undoAction->setEnabled( false );
Stephan Kulow's avatar
Stephan Kulow committed
249

Aaron J. Seigo's avatar
Aaron J. Seigo committed
250
	m_redoAction = KStandardAction::redo( this, SLOT(redo()), actionCollection() );
David Saxton's avatar
David Saxton committed
251
	m_redoAction->setEnabled( false );
Stephan Kulow's avatar
Stephan Kulow committed
252

253
254
	QAction * editAxes = actionCollection()->addAction( "editaxes" );
        editAxes->setText( i18n( "&Coordinate System..." ) );
Christoph Feck's avatar
Christoph Feck committed
255
	editAxes->setIcon( QIcon::fromTheme("coords.png") );
256
	connect( editAxes, &QAction::triggered, this, &MainDlg::editAxes );
257

258
259
	QAction * editConstants = actionCollection()->addAction( "editconstants" );
        editConstants->setText( i18n( "&Constants..." ) );
Christoph Feck's avatar
Christoph Feck committed
260
	editConstants->setIcon( QIcon::fromTheme("editconstants.png") );
261
	connect( editConstants, &QAction::triggered, this, &MainDlg::editConstants );
David Saxton's avatar
David Saxton committed
262
	//END edit menu
Stephan Kulow's avatar
Stephan Kulow committed
263
264


265
	//BEGIN view menu
David Saxton's avatar
David Saxton committed
266
	/// \todo check that new shortcuts work
Stephan Kulow's avatar
Stephan Kulow committed
267

Christoph Feck's avatar
Christoph Feck committed
268
	QAction * zoomIn = actionCollection()->addAction( "zoom_in" );
269
        zoomIn->setText( i18n("Zoom &In") );
Christoph Feck's avatar
Christoph Feck committed
270
	actionCollection()->setDefaultShortcut( zoomIn, QKeySequence(Qt::ControlModifier | Qt::Key_1) );
Christoph Feck's avatar
Christoph Feck committed
271
	zoomIn->setIcon( QIcon::fromTheme("zoom-in") );
272
	connect( zoomIn, &QAction::triggered, View::self(), QOverload<>::of(&View::zoomIn) );
Stephan Kulow's avatar
Stephan Kulow committed
273

Christoph Feck's avatar
Christoph Feck committed
274
	QAction * zoomOut = actionCollection()->addAction( "zoom_out" );
275
        zoomOut->setText(i18n("Zoom &Out"));
Christoph Feck's avatar
Christoph Feck committed
276
	actionCollection()->setDefaultShortcut( zoomOut, QKeySequence(Qt::ControlModifier | Qt::Key_2) );
Christoph Feck's avatar
Christoph Feck committed
277
	zoomOut->setIcon( QIcon::fromTheme("zoom-out") );
278
	connect( zoomOut, &QAction::triggered, View::self(), QOverload<>::of(&View::zoomOut) );
Stephan Kulow's avatar
Stephan Kulow committed
279

280
281
	QAction * zoomTrig = actionCollection()->addAction( "zoom_trig" );
        zoomTrig->setText( i18n("&Fit Widget to Trigonometric Functions") );
282
	connect( zoomTrig, &QAction::triggered, View::self(), &View::zoomToTrigonometric );
Stephan Kulow's avatar
Stephan Kulow committed
283

284
285
	QAction * resetView = actionCollection()->addAction( "reset_view" );
	resetView->setText( i18n( "Reset View" ) );
Christoph Feck's avatar
Christoph Feck committed
286
	resetView->setIcon( QIcon::fromTheme("resetview") );
287
288
289
290
	connect( resetView, &QAction::triggered, this, &MainDlg::slotResetView );

	View::self()->m_menuSliderAction = actionCollection()->add<KToggleAction>( "options_configure_show_sliders" );
	View::self()->m_menuSliderAction->setText( i18n( "Show Sliders" ) );
291
	connect( View::self()->m_menuSliderAction, &QAction::toggled, this, &MainDlg::toggleShowSliders );
292
	//END view menu
Stephan Kulow's avatar
Stephan Kulow committed
293
294


295
	//BEGIN tools menu
296
297
	QAction *mnuCalculator = actionCollection()->addAction( "calculator" );
	mnuCalculator->setText( i18n( "Calculator") );
Christoph Feck's avatar
Christoph Feck committed
298
	mnuCalculator->setIcon( QIcon::fromTheme("system-run") );
299
	connect( mnuCalculator, &QAction::triggered, this, &MainDlg::calculator );
Stephan Kulow's avatar
Stephan Kulow committed
300

301
302
	QAction *mnuArea = actionCollection()->addAction( "grapharea" );
        mnuArea->setText( i18n( "Plot &Area..." ) );
303
	connect( mnuArea, &QAction::triggered, this, &MainDlg::graphArea );
Stephan Kulow's avatar
Stephan Kulow committed
304

305
306
	QAction *mnuMaxValue = actionCollection()->addAction( "maximumvalue" );
        mnuMaxValue->setText( i18n( "Find Ma&ximum..." ) );
Christoph Feck's avatar
Christoph Feck committed
307
	mnuMaxValue->setIcon( QIcon::fromTheme("maximum") );
308
	connect( mnuMaxValue, &QAction::triggered, this, &MainDlg::findMaximumValue );
Stephan Kulow's avatar
Stephan Kulow committed
309

310
311
	QAction *mnuMinValue = actionCollection()->addAction( "minimumvalue" );
        mnuMinValue->setText( i18n( "Find Mi&nimum..." ) );
Christoph Feck's avatar
Christoph Feck committed
312
	mnuMinValue->setIcon( QIcon::fromTheme("minimum") );
313
	connect( mnuMinValue, &QAction::triggered, this, &MainDlg::findMinimumValue );
314
	//END tools menu
315

Stephan Kulow's avatar
Stephan Kulow committed
316

317
	//BEGIN help menu
318
	QAction * namesAction = actionCollection()->addAction( "names" );
Antoni Bella Pérez's avatar
Antoni Bella Pérez committed
319
        namesAction->setText( i18nc("@action:inmenu Help", "Predefined &Math Functions") );
Christoph Feck's avatar
Christoph Feck committed
320
	namesAction->setIcon( QIcon::fromTheme("functionhelp") );
321
	connect( namesAction, &QAction::triggered, this, &MainDlg::slotNames );
322
	//END help menu
Stephan Kulow's avatar
Stephan Kulow committed
323
324


325
	//BEGIN new plots menu
326
327
	QAction * newFunction = actionCollection()->addAction( "newcartesian" );
        newFunction->setText( i18n( "Cartesian Plot" ) );
Christoph Feck's avatar
Christoph Feck committed
328
	newFunction->setIcon( QIcon::fromTheme("newfunction") );
329
	connect( newFunction, &QAction::triggered, m_functionEditor, &FunctionEditor::createCartesian );
330
	m_newPlotMenu->addAction( newFunction );
Stephan Kulow's avatar
Stephan Kulow committed
331

332
333
	QAction * newParametric = actionCollection()->addAction( "newparametric" );
        newParametric->setText( i18n( "Parametric Plot" ) );
Christoph Feck's avatar
Christoph Feck committed
334
	newParametric->setIcon( QIcon::fromTheme("newparametric") );
335
	connect( newParametric, &QAction::triggered, m_functionEditor, &FunctionEditor::createParametric );
336
	m_newPlotMenu->addAction( newParametric );
Stephan Kulow's avatar
Stephan Kulow committed
337

338
339
	QAction * newPolar = actionCollection()->addAction( "newpolar" );
        newPolar->setText( i18n( "Polar Plot" ) );
Christoph Feck's avatar
Christoph Feck committed
340
	newPolar->setIcon( QIcon::fromTheme("newpolar") );
341
	connect( newPolar, &QAction::triggered, m_functionEditor, &FunctionEditor::createPolar );
342
	m_newPlotMenu->addAction( newPolar );
Stephan Kulow's avatar
Stephan Kulow committed
343

344
345
	QAction * newImplicit = actionCollection()->addAction( "newimplicit" );
        newImplicit->setText( i18n( "Implicit Plot" ) );
Christoph Feck's avatar
Christoph Feck committed
346
	newImplicit->setIcon( QIcon::fromTheme("newimplicit") );
347
	connect( newImplicit, &QAction::triggered, m_functionEditor, &FunctionEditor::createImplicit );
348
	m_newPlotMenu->addAction( newImplicit );
Stephan Kulow's avatar
Stephan Kulow committed
349

350
351
	QAction * newDifferential = actionCollection()->addAction( "newdifferential" );
        newDifferential->setText( i18n( "Differential Plot" ) );
Christoph Feck's avatar
Christoph Feck committed
352
	newDifferential->setIcon( QIcon::fromTheme("newdifferential") );
353
	connect( newDifferential, &QAction::triggered, m_functionEditor, &FunctionEditor::createDifferential );
354
	m_newPlotMenu->addAction( newDifferential );
355
	//END new plots menu
Stephan Kulow's avatar
Stephan Kulow committed
356
357


358
	//BEGIN function popup menu
359
360
	QAction *mnuEdit = actionCollection()->addAction( "mnuedit"  );
        mnuEdit->setText(i18n("&Edit"));
361
	m_firstFunctionAction = mnuEdit;
Christoph Feck's avatar
Christoph Feck committed
362
	mnuEdit->setIcon( QIcon::fromTheme("editplots") );
363
	connect(mnuEdit, &QAction::triggered, View::self(), &View::editCurrentPlot );
364
	m_popupmenu->addAction( mnuEdit );
365
366
367

	QAction *mnuHide = actionCollection()->addAction( "mnuhide" );
        mnuHide->setText( i18n("&Hide") );
368
	connect( mnuHide, &QAction::triggered, View::self(), &View::hideCurrentFunction );
369
	m_popupmenu->addAction( mnuHide );
Stephan Kulow's avatar
Stephan Kulow committed
370

371
372
	QAction *mnuRemove = actionCollection()->addAction( "mnuremove"  );
        mnuRemove->setText(i18n("&Remove"));
Christoph Feck's avatar
Christoph Feck committed
373
	mnuRemove->setIcon( QIcon::fromTheme("edit-delete") );
374
	connect( mnuRemove, &QAction::triggered, View::self(), &View::removeCurrentPlot );
375
	m_popupmenu->addAction( mnuRemove );
Stephan Kulow's avatar
Stephan Kulow committed
376

David Saxton's avatar
David Saxton committed
377
	m_popupmenu->addSeparator();
Stephan Kulow's avatar
Stephan Kulow committed
378

379
380
	QAction * animateFunction = actionCollection()->addAction( "animateFunction" );
        animateFunction->setText(i18n("Animate Plot..."));
381
	connect( animateFunction, &QAction::triggered, View::self(), &View::animateFunction );
382
	m_popupmenu->addAction( animateFunction );
383
	m_popupmenu->addSeparator();
Stephan Kulow's avatar
Stephan Kulow committed
384

385
	m_popupmenu->addAction( mnuCalculator );
386
387
388
	m_popupmenu->addAction( mnuMinValue );
	m_popupmenu->addAction( mnuMaxValue );
	m_popupmenu->addAction( mnuArea );
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410

	QAction * copyXY = actionCollection()->addAction( "copyXY" );
	copyXY->setText(i18n("Copy (x, y)"));
	connect( copyXY, &QAction::triggered, []{
		QClipboard * cb = QApplication::clipboard();
		QPointF currentXY = View::self()->getCrosshairPosition();
		cb->setText( i18nc("Copied pair of coordinates (x, y)", "(%1, %2)", QLocale().toString( currentXY.x(), 'f', 5 ), QLocale().toString( currentXY.y(), 'f', 5 )), QClipboard::Clipboard );
	} );
	m_popupmenu->addAction( copyXY );

	QAction * copyRootValue = actionCollection()->addAction( "copyRootValue" );
	copyRootValue->setText(i18n("Copy Root Value"));
	connect( View::self(), &View::updateRootValue, [this, copyRootValue]( bool haveRoot, double rootValue ){
		copyRootValue->setVisible(haveRoot);
		m_rootValue = rootValue;
	} );
	connect( copyRootValue, &QAction::triggered, [this]{
		QClipboard * cb = QApplication::clipboard();
		cb->setText( QLocale().toString( m_rootValue, 'f', 5 ), QClipboard::Clipboard );
	} );
	m_popupmenu->addAction( copyRootValue );

411
	//END function popup menu
412
}
413
414


David Saxton's avatar
David Saxton committed
415
416
void MainDlg::undo()
{
417
	qDebug() ;
Stephan Kulow's avatar
Stephan Kulow committed
418

David Saxton's avatar
David Saxton committed
419
420
	if ( m_undoStack.isEmpty() )
		return;
Stephan Kulow's avatar
Stephan Kulow committed
421

David Saxton's avatar
David Saxton committed
422
423
	m_redoStack.push( m_currentState );
	m_currentState = m_undoStack.pop();
Stephan Kulow's avatar
Stephan Kulow committed
424

David Saxton's avatar
David Saxton committed
425
	kmplotio->restore( m_currentState );
426
	View::self()->drawPlot();
Stephan Kulow's avatar
Stephan Kulow committed
427

David Saxton's avatar
David Saxton committed
428
429
430
431
432
433
434
	m_undoAction->setEnabled( !m_undoStack.isEmpty() );
	m_redoAction->setEnabled( true );
}


void MainDlg::redo()
{
435
	qDebug() ;
Stephan Kulow's avatar
Stephan Kulow committed
436

David Saxton's avatar
David Saxton committed
437
438
	if ( m_redoStack.isEmpty() )
		return;
Stephan Kulow's avatar
Stephan Kulow committed
439

David Saxton's avatar
David Saxton committed
440
441
	m_undoStack.push( m_currentState );
	m_currentState = m_redoStack.pop();
Stephan Kulow's avatar
Stephan Kulow committed
442

David Saxton's avatar
David Saxton committed
443
	kmplotio->restore( m_currentState );
444
	View::self()->drawPlot();
Stephan Kulow's avatar
Stephan Kulow committed
445

David Saxton's avatar
David Saxton committed
446
447
448
449
450
451
452
453
454
455
456
457
458
459
	m_undoAction->setEnabled( true );
	m_redoAction->setEnabled( !m_redoStack.isEmpty() );
}


void MainDlg::requestSaveCurrentState()
{
	m_saveCurrentStateTimer->start( 0 );
}
void MainDlg::saveCurrentState( )
{
	m_redoStack.clear();
	m_undoStack.push( m_currentState );
	m_currentState = kmplotio->currentState();
Stephan Kulow's avatar
Stephan Kulow committed
460

David Saxton's avatar
David Saxton committed
461
462
463
	// limit stack size to 100 items
	while ( m_undoStack.count() > 100 )
		m_undoStack.pop_front();
Stephan Kulow's avatar
Stephan Kulow committed
464

David Saxton's avatar
David Saxton committed
465
466
	m_undoAction->setEnabled( true );
	m_redoAction->setEnabled( false );
Stephan Kulow's avatar
Stephan Kulow committed
467

468
	m_modified = true;
David Saxton's avatar
David Saxton committed
469
470
471
}


472
473
474
475
476
477
478
479
480
481
void MainDlg::resetUndoRedo()
{
	m_redoStack.clear();
	m_undoStack.clear();
	m_currentState = kmplotio->currentState();
	m_undoAction->setEnabled( false );
	m_redoAction->setEnabled( false );
}


482
483
484
485
bool MainDlg::checkModified()
{
	if( m_modified )
	{
486
		int saveit = KMessageBox::warningYesNoCancel( m_parent, i18n( "The plot has been modified.\n"
487
		             "Do you want to save it?" ), QString(), KStandardGuiItem::save(), KStandardGuiItem::discard() );
488
489
		switch( saveit )
		{
490
491
492
493
494
495
			case KMessageBox::Yes:
				slotSave();
				if ( m_modified) // the user didn't saved the file
					return false;
				break;
			case KMessageBox::Cancel:
496
497
498
499
500
				return false;
		}
	}
	return true;
}
David Saxton's avatar
David Saxton committed
501
502


503
void MainDlg::slotSave()
Matthias Messmer's avatar
Matthias Messmer committed
504
{
505
	if ( !m_modified || m_readonly) //don't save if no changes are made or readonly is enabled
506
		return;
507
	if ( url().isEmpty() )            // if there is no file name set yet
508
		slotSaveas();
509
	else
510
	{
511
512
		if ( !m_modified) //don't save if no changes are made
			return;
513

514
515
		if ( oldfileversion)
		{
516
			if ( KMessageBox::warningContinueCancel( m_parent, i18n( "This file is saved with an old file format; if you save it, you cannot open the file with older versions of KmPlot. Are you sure you want to continue?" ), QString(), KGuiItem(i18n("Save New Format")) ) == KMessageBox::Cancel)
517
518
				return;
		}
519
		kmplotio->save( this->url() );
520
		qDebug() << "saved";
521
522
		m_modified = false;
	}
Matthias Messmer's avatar
Matthias Messmer committed
523

Matthias Messmer's avatar
Matthias Messmer committed
524
}
525

526
void MainDlg::slotSaveas()
Matthias Messmer's avatar
Matthias Messmer committed
527
{
528
529
	if (m_readonly)
		return;
530
531
532
	const QUrl url = QFileDialog::getSaveFileUrl(m_parent, i18n( "Save As" ), QUrl::fromLocalFile(QDir::currentPath()),
			    i18n( "KmPlot Files (*.fkt);;All Files (*)" )
			      );
533

534
535
	if ( url.isEmpty() )
		return;
536

537
538
539
540
	if ( !kmplotio->save( url ) )
		KMessageBox::error(m_parent, i18n("The file could not be saved") );
	else
	{
541
		setUrl(url);
542
		m_recentFiles->addUrl( url );
Inge Wallin's avatar
Inge Wallin committed
543
		setWindowCaption( QUrl(this->url()).toString() );
544
		m_modified = false;
545
	}
Matthias Messmer's avatar
Matthias Messmer committed
546
}
547

548
void MainDlg::slotExport()
549
{
550
551
	QString filters;
	QMimeDatabase mimeDatabase;
552
	for (const QByteArray &mimeType : QImageWriter::supportedMimeTypes()) {
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
		const QString filter = mimeDatabase.mimeTypeForName(QLatin1String(mimeType)).filterString();
		if (!filter.isEmpty()) {
			if (mimeType == QByteArrayLiteral("image/png")) {
				if (!filters.isEmpty()) {
					filters.prepend(QStringLiteral(";;"));
				}
				filters.prepend(filter);
			} else {
				if (!filters.isEmpty()) {
					filters.append(QStringLiteral(";;"));
                                }
				filters.append(filter);
			}
		}
	}
	if (!filters.isEmpty()) {
		filters.append(QStringLiteral(";;"));
	}
	filters.append(i18n("Scalable Vector Graphics (*.svg)"));
572

573
	QUrl url = QFileDialog::getSaveFileUrl(m_parent, i18nc("@title:window", "Export as Image"), QUrl::fromLocalFile(QDir::currentPath()), filters);
574

575
	if ( !url.isValid() )
576
577
		return;

578
	QMimeType mimeType = mimeDatabase.mimeTypeForUrl( url );
579
	qDebug() << "mimetype: " << mimeType.name();
580

581
	bool isSvg = mimeType.name() == "image/svg+xml";
582

583
	bool saveOk = true;
584

585
	if ( isSvg )
586
	{
587
		QSvgGenerator img;
588
		img.setViewBox( QRect( QPoint(0, 0), View::self()->size() ) );
589

590
		QFile file;
591
		QTemporaryFile tmp;
592

593
		if ( url.isLocalFile() )
594
		{
595
			file.setFileName( url.toLocalFile() );
596
597
			img.setOutputDevice( &file );
		}
598
599
		else
		{
600
 			tmp.setFileTemplate(QDir::tempPath() + QLatin1String("/kmplot_XXXXXX") + QLatin1String(".svg")); 
601
			img.setOutputDevice( &tmp );
602
		}
603

604
		View::self()->draw( &img, View::SVG );
605

606
		if ( !url.isLocalFile() )
607
608
609
610
611
612
613
614
		{
		    Q_CONSTEXPR int permission = -1;
		    QFile file(tmp.fileName());
		    file.open(QIODevice::ReadOnly);
		    KIO::StoredTransferJob *putjob = KIO::storedPut(file.readAll(), url, permission, KIO::JobFlag::Overwrite);
		    saveOk &= putjob->exec();
		    file.close();
		}
615
	}
616
	else
617
	{
618
619
		QPixmap img( View::self()->size() );
		View::self()->draw( & img, View::Pixmap );
620

621
		QStringList types = mimeType.suffixes();
622
623
		if ( types.isEmpty() )
			return; // TODO error dialog?
624

625
		if ( url.isLocalFile() )
626
			saveOk = img.save( url.toLocalFile(), types.at(0).toLatin1() );
627
		else
628
		{
629
			QTemporaryFile tmp;
Jaison Lee's avatar
Jaison Lee committed
630
631
			tmp.open();
			img.save( tmp.fileName(), types.at(0).toLatin1() );
632
633
634
635
636
637
			Q_CONSTEXPR int permission = -1;
			QFile file(tmp.fileName());
			file.open(QIODevice::ReadOnly);
			KIO::StoredTransferJob *putjob = KIO::storedPut(file.readAll(), url, permission, KIO::JobFlag::Overwrite);
			saveOk = putjob->exec();
			file.close();
638
639
		}
	}
640

641
	if ( !saveOk )
Inge Wallin's avatar
Inge Wallin committed
642
643
644
	    KMessageBox::error(m_parent,
			       i18n("Sorry, something went wrong while saving to image \"%1\"",
				    url.toString()));
645
}
646
647


648
bool MainDlg::openFile()
Matthias Messmer's avatar
Matthias Messmer committed
649
{
650
	if (url()==m_currentfile || !kmplotio->load( url() ) )
651
	{
652
		m_recentFiles->removeUrl( url() ); //remove the file from the recent-opened-file-list
Inge Wallin's avatar
Inge Wallin committed
653
		setUrl(QUrl());
654
655
		return false;
	}
656

657
	m_currentfile = url();
658
659
	m_recentFiles->addUrl( url() );
	setWindowCaption( url().toDisplayString() );
660
	resetUndoRedo();
661
662
	View::self()->updateSliders();
	View::self()->drawPlot();
663
	return true;
Matthias Messmer's avatar
Matthias Messmer committed
664
665
}

666
667
668
669
670
671
bool MainDlg::saveFile()
{
    slotSave();
    return !isModified();
}

Inge Wallin's avatar
Inge Wallin committed
672
void MainDlg::slotOpenRecent( const QUrl &url )
Matthias Messmer's avatar
Matthias Messmer committed
673
{
674
 	if( isModified() || !this->url().isEmpty() ) // open the file in a new window
675
 	{
676
		QDBusReply<void> reply = QDBusInterface( QDBusConnection::sessionBus().baseService(), "/kmplot", "org.kde.kmplot.KmPlot" ).call( QDBus::Block, "openFileInNewWindow", url.url() );
677
678
679
680
681
682
683
684
		return;
	}

	if ( !kmplotio->load( url ) ) //if the loading fails
	{
		m_recentFiles->removeUrl(url ); //remove the file from the recent-opened-file-list
		return;
	}
685
686
    m_currentfile = url;
    setUrl(url);
687
    m_recentFiles->setCurrentItem(-1); //don't select the item in the open-recent menu
Inge Wallin's avatar
Inge Wallin committed
688
    setWindowCaption( QUrl(this->url()).toString() );
689
	resetUndoRedo();
690
691
    View::self()->updateSliders();
    View::self()->drawPlot();
692
}
693

694
void MainDlg::slotPrint()
695
{
696
	QPrinter prt( QPrinter::PrinterResolution );
697
	prt.setResolution( 72 );
698
699
	KPrinterDlg* printdlg = new KPrinterDlg( m_parent );
	printdlg->setObjectName( "KmPlot page" );
Yuri Chornoivan's avatar
Yuri Chornoivan committed
700
	QPointer<QPrintDialog> printDialog = new QPrintDialog( &prt, m_parent );
701
	printDialog->setOptionTabs( QList<QWidget*>() << printdlg );
Antoni Bella Pérez's avatar
Antoni Bella Pérez committed
702
	printDialog->setWindowTitle( i18nc("@title:window", "Print Plot") );
703
704
705

	if (printDialog->exec())
	{
Yuri Chornoivan's avatar
Yuri Chornoivan committed
706
		setupPrinter(printdlg, &prt);
707
	}
Laurent Montel's avatar
Laurent Montel committed
708
        delete printDialog;
709
710
}

Yuri Chornoivan's avatar
Yuri Chornoivan committed
711
712
713
714
715
716
717
718
719
720
721
void MainDlg::slotPrintPreview()
{
	QPrinter prt( QPrinter::PrinterResolution );
	QPointer<QPrintPreviewDialog> preview = new QPrintPreviewDialog( &prt );
	QPointer<KPrinterDlg> printdlg = new KPrinterDlg( m_parent );
	QList<QToolBar *> toolbarlist = preview->findChildren<QToolBar *>();
	if(!toolbarlist.isEmpty())
	{
		QAction *printSettings = toolbarlist.first()->addAction( QIcon::fromTheme( "configure" ), i18n("Print Settings") );
		QList<QPrintPreviewWidget*> previewWidgetsList = preview->findChildren<QPrintPreviewWidget*>();
		QPrintPreviewWidget *previewWidget = previewWidgetsList.first();
Laurent Montel's avatar
Laurent Montel committed
722
		connect( printSettings, &QAction::triggered, [preview, previewWidget, printdlg]{
Yuri Chornoivan's avatar
Yuri Chornoivan committed
723
			QDialog *printSettingsDialog = new QDialog( preview, Qt::WindowFlags() );
Antoni Bella Pérez's avatar
Antoni Bella Pérez committed
724
			printSettingsDialog->setWindowTitle( i18nc("@title:window", "Print Settings") );
Yuri Chornoivan's avatar
Yuri Chornoivan committed
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
			QVBoxLayout *mainLayout = new QVBoxLayout;
			printSettingsDialog->setLayout(mainLayout);
			mainLayout->addWidget(printdlg);
			QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok|QDialogButtonBox::Cancel );
			connect(buttonBox, &QDialogButtonBox::accepted, [previewWidget, printSettingsDialog]{
				previewWidget->updatePreview();
				printSettingsDialog->close();
			} );
			connect(buttonBox, &QDialogButtonBox::rejected, printSettingsDialog, &QDialog::reject);
			mainLayout->addWidget(buttonBox);
			printSettingsDialog->show();
		});
	}
	connect(preview, &QPrintPreviewDialog::paintRequested, [this, &printdlg, &prt]{
		setupPrinter(printdlg, &prt);
	} );
	preview->exec();
	delete printdlg;
	delete preview;
}

void MainDlg::setupPrinter(KPrinterDlg *printDialog, QPrinter *printer)
{
		View::self()->setPrintHeaderTable( printDialog->printHeaderTable() );
		View::self()->setPrintBackground( printDialog->printBackground() );
		View::self()->setPrintWidth( printDialog->printWidth() );
		View::self()->setPrintHeight( printDialog->printHeight() );
		View::self()->draw(printer, View::Printer);
}
754

755
756
void MainDlg::editAxes()
{
757
	coordsDialog()->show();
758
759
760
}


761
762
763
764
void MainDlg::editConstants()
{
	if ( !m_constantEditor)
		m_constantEditor = new KConstantEditor(m_parent);
765

766
767
768
769
	m_constantEditor->show();
}


770
771
void MainDlg::editConstantsModal(QWidget *parent)
{
Yuri Chornoivan's avatar
Yuri Chornoivan committed
772
773
774
775
776
777
	if (m_constantEditor) {
		m_constantEditor->hide();
	}
	else {
		m_constantEditor = new KConstantEditor(parent);
	}
778
779
780
781
782

	m_constantEditor->setModal(true);
	m_constantEditor->show();
}

783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
bool MainDlg::fileExists(const QUrl &url)
{
	bool fileExists = false;
	if (url.isValid()) {
		short int detailLevel = 0; // Lowest level: file/dir/symlink/none
		KIO::StatJob* statjob = KIO::stat(url, KIO::StatJob::SourceSide, detailLevel);
		bool noerror = statjob->exec();
		if (noerror) {
			// We want a file
			fileExists = !statjob->statResult().isDir();
		}
	}
	return fileExists;
}

798
void MainDlg::slotNames()
Matthias Messmer's avatar
Matthias Messmer committed
799
{
Christoph Feck's avatar
Christoph Feck committed
800
	KHelpClient::invokeHelp( "func-predefined", "kmplot" );
801
802
803
}


804
void MainDlg::slotResetView()
Matthias Messmer's avatar
Matthias Messmer committed
805
{
806
	View::self()->animateZoom( QRectF( -8, -8, 16, 16 ) );
807
808
}

809
810
void MainDlg::slotSettings()
{
811
812
813
	// An instance of your dialog has already been created and has been cached,
	// so we want to display the cached dialog instead of creating
	// another one
814
815
816
	KConfigDialog::showDialog( "settings" );
}

817

818
void MainDlg::calculator()
819
{
820
	m_calculator->show();
821
822
823
824
}

void MainDlg::findMinimumValue()
{
825
826
	m_functionTools->init( FunctionTools::FindMinimum );
	m_functionTools->show();
827
828
829
830
}

void MainDlg::findMaximumValue()
{
831
832
	m_functionTools->init( FunctionTools::FindMaximum );
	m_functionTools->show();
833
834
835
836
}

void MainDlg::graphArea()
{