1 /*
2 KmPlot - a math. function plotter for the KDE-Desktop
3
4 SPDX-FileCopyrightText: 1998, 1999, 2000, 2002 Klaus-Dieter Möller <kd.moeller@t-online.de>
5 SPDX-FileCopyrightText: 2006 David Saxton <david@bluehaze.org>
6
7 This file is part of the KDE Project.
8 KmPlot is part of the KDE-EDU Project.
9
10 SPDX-License-Identifier: GPL-2.0-or-later
11
12 */
13
14 #include "maindlg.h"
15
16 // Qt includes
17 #include <QClipboard>
18 #include <QDebug>
19 #include <QFileDialog>
20 #include <QIcon>
21 #include <QImageWriter>
22 #include <QMainWindow>
23 #include <QMimeDatabase>
24 #include <QMimeType>
25 #include <QPixmap>
26 #include <QPrintDialog>
27 #include <QPrintPreviewDialog>
28 #include <QPrintPreviewWidget>
29 #include <QSvgGenerator>
30 #include <QTemporaryFile>
31 #include <QTimer>
32
33 // KDE includes
34 #include <KActionCollection>
35 #include <KConfigDialog>
36 #include <KConfigDialogManager>
37 #include <KHelpClient>
38 #include <KIO/StatJob>
39 #include <KIO/StoredTransferJob>
40 #include <KLineEdit>
41 #include <KMessageBox>
42 #include <KStandardAction>
43 #include <KToolBar>
44 #include <KToolInvocation>
45
46 // local includes
47 #include "calculator.h"
48 #include "functiontools.h"
49 #include "functioneditor.h"
50 #include "kconstanteditor.h"
51 #include "xparser.h"
52
53 #include "settings.h"
54 #include "ui_settingspagecolor.h"
55 #include "ui_settingspagefonts.h"
56 #include "ui_settingspagegeneral.h"
57 #include "ui_settingspagediagram.h"
58 #include "ksliderwindow.h"
59 #include "maindlgadaptor.h"
60
61 #include <assert.h>
62
63 class XParser;
64 class KmPlotIO;
65
66
67 class SettingsPageColor : public QWidget, public Ui::SettingsPageColor
68 {
69 public:
SettingsPageColor(QWidget * parent=0)70 SettingsPageColor( QWidget * parent = 0 )
71 : QWidget( parent )
72 {
73 setupUi(this);
74 layout()->setContentsMargins(0, 0, 0, 0);
75 }
76 };
77
78 class SettingsPageFonts : public QWidget, public Ui::SettingsPageFonts
79 {
80 public:
SettingsPageFonts(QWidget * parent=0)81 SettingsPageFonts( QWidget * parent = 0 )
82 : QWidget( parent )
83 {
84 setupUi(this);
85 layout()->setContentsMargins(0, 0, 0, 0);
86 }
87 };
88
89 class SettingsPageGeneral : public QWidget, public Ui::SettingsPageGeneral
90 {
91 public:
SettingsPageGeneral(QWidget * parent=0)92 SettingsPageGeneral( QWidget * parent = 0 )
93 : QWidget( parent )
94 {
95 setupUi(this);
96 layout()->setContentsMargins(0, 0, 0, 0);
97 }
98 };
99
100 class SettingsPageDiagram : public QWidget, public Ui::SettingsPageDiagram
101 {
102 public:
SettingsPageDiagram(QWidget * parent=0)103 SettingsPageDiagram( QWidget * parent = 0 )
104 : QWidget( parent )
105 {
106 setupUi(this);
107 layout()->setContentsMargins(0, 0, 0, 0);
108 }
109 };
110
111 bool MainDlg::oldfileversion;
112 MainDlg * MainDlg::m_self = 0;
113
114 K_PLUGIN_CLASS_WITH_JSON(MainDlg, "kmplot_part.json")
115
116 //BEGIN class MainDlg
MainDlg(QWidget * parentWidget,QObject * parent,const QVariantList &)117 MainDlg::MainDlg(QWidget *parentWidget, QObject *parent, const QVariantList& ) :
118 KParts::ReadWritePart( parent ),
119 m_recentFiles( 0 ),
120 m_modified(false),
121 m_parent(parentWidget),
122 m_rootValue( 0 )
123 {
124 assert( !m_self ); // this class should only be constructed once
125 m_self = this;
126
127 qDebug() << "parentWidget->objectName():" << parentWidget->objectName();
128 if ( QString(parentWidget->objectName()).startsWith("KmPlot") )
129 {
130 setXMLFile("kmplot_part.rc");
131 m_readonly = false;
132 }
133 else
134 {
135 setXMLFile("kmplot_part_readonly.rc");
136 m_readonly = true;
137 new BrowserExtension(this); // better integration with Konqueror
138 }
139
140 m_coordsDialog = 0;
141 m_constantEditor = 0;
142 m_popupmenu = new QMenu( parentWidget );
143 m_newPlotMenu = new QMenu( parentWidget );
144 (void) new View( m_readonly, m_popupmenu, parentWidget );
145 connect( View::self(), &View::setStatusBarText, this, &MainDlg::setReadOnlyStatusBarText );
146
147 m_functionEditor = 0;
148 if ( !m_readonly )
149 {
150 m_functionEditor = new FunctionEditor( m_newPlotMenu, parentWidget );
151 static_cast<QMainWindow*>(parentWidget)->addDockWidget( Qt::LeftDockWidgetArea, m_functionEditor );
152 }
153
154 setWidget( View::self() );
155 View::self()->setFocusPolicy(Qt::ClickFocus);
156 m_functionTools = new FunctionTools(m_parent);
157 m_calculator = new Calculator( m_parent );
158 setupActions();
159 XParser::self()->constants()->load();
160 kmplotio = new KmPlotIO();
161 m_config = KSharedConfig::openConfig();
162 m_recentFiles->loadEntries( m_config->group( QString() ) );
163
164
165 //BEGIN undo/redo stuff
166 m_currentState = kmplotio->currentState();
167 m_saveCurrentStateTimer = new QTimer( this );
168 m_saveCurrentStateTimer->setSingleShot( true );
169 connect( m_saveCurrentStateTimer, &QTimer::timeout, this, &MainDlg::saveCurrentState );
170 //END undo/redo stuff
171
172 // Let's create a Configure Dialog
173 m_settingsDialog = new KConfigDialog( parentWidget, "settings", Settings::self() );
174
175 QMetaObject::invokeMethod(m_settingsDialog, "setHelp", Qt::DirectConnection, Q_ARG(QString, QString::fromLatin1("configuration")), Q_ARG(QString, QString::fromLatin1("kmplot")));
176
177 // create and add the page(s)
178 m_generalSettings = new SettingsPageGeneral( View::self() );
179 m_colorSettings = new SettingsPageColor( View::self() );
180 m_fontsSettings = new SettingsPageFonts( View::self() );
181 m_diagramSettings = new SettingsPageDiagram( View::self() );
182
183 // Make sure the dialog is at a good default size (hmm QDialog should do this automatically?)
184 QSize minSize = m_generalSettings->layout()->minimumSize()
185 .expandedTo( m_colorSettings->layout()->minimumSize() )
186 .expandedTo( m_fontsSettings->layout()->minimumSize() )
187 .expandedTo( m_diagramSettings->layout()->minimumSize() );
188 m_generalSettings->setMinimumSize( minSize );
189
190 m_settingsDialog->addPage( m_generalSettings, i18n("General"), "kmplot", i18n("General Settings") );
191 m_settingsDialog->addPage( m_diagramSettings, i18n("Diagram"), "coords", i18n("Diagram Appearance") );
192 m_settingsDialog->addPage( m_colorSettings, i18n("Colors"), "preferences-desktop-color", i18n("Colors") );
193 m_settingsDialog->addPage( m_fontsSettings, i18n("Fonts"), "preferences-desktop-font", i18n("Fonts") );
194 // User edited the configuration - update your local copies of the
195 // configuration data
196 connect( m_settingsDialog, &KConfigDialog::settingsChanged, View::self(), QOverload<>::of(&View::drawPlot) );
197
198
199 new MainDlgAdaptor(this);
200 QDBusConnection::sessionBus().registerObject("/maindlg", this);
201
202 }
203
~MainDlg()204 MainDlg::~MainDlg()
205 {
206 m_recentFiles->saveEntries( m_config->group( QString() ) );
207 XParser::self()->constants()->save();
208 delete kmplotio;
209 }
210
setupActions()211 void MainDlg::setupActions()
212 {
213 // standard actions
214 m_recentFiles = KStandardAction::openRecent( this, SLOT(slotOpenRecent(QUrl)), this );
215 actionCollection()->addAction( "file_open_recent", m_recentFiles );
216 actionCollection()->addAction( KStandardAction::Print, "file_print", this, SLOT(slotPrint()) );
217 actionCollection()->addAction( KStandardAction::PrintPreview, "file_print_preview", this, SLOT(slotPrintPreview()) );
218 KStandardAction::save( this, SLOT(slotSave()), actionCollection() );
219 KStandardAction::saveAs( this, SLOT(slotSaveas()), actionCollection() );
220
221 QAction *prefs = KStandardAction::preferences( this, SLOT(slotSettings()), actionCollection());
222 prefs->setText( i18n( "Configure KmPlot..." ) );
223
224 // KmPlot specific actions
225
226 //BEGIN file menu
227 QAction * exportAction = actionCollection()->addAction( "export" );
228 exportAction->setText( i18n( "E&xport..." ) );
229 exportAction->setIcon( QIcon::fromTheme( "document-export" ) );
230 connect( exportAction, &QAction::triggered, this, &MainDlg::slotExport );
231 //END file menu
232
233
234 //BEGIN edit menu
235 m_undoAction = KStandardAction::undo( this, SLOT(undo()), actionCollection() );
236 m_undoAction->setEnabled( false );
237
238 m_redoAction = KStandardAction::redo( this, SLOT(redo()), actionCollection() );
239 m_redoAction->setEnabled( false );
240
241 QAction * editAxes = actionCollection()->addAction( "editaxes" );
242 editAxes->setText( i18n( "&Coordinate System..." ) );
243 editAxes->setIcon( QIcon::fromTheme("coords.png") );
244 connect( editAxes, &QAction::triggered, this, &MainDlg::editAxes );
245
246 QAction * editConstants = actionCollection()->addAction( "editconstants" );
247 editConstants->setText( i18n( "&Constants..." ) );
248 editConstants->setIcon( QIcon::fromTheme("editconstants.png") );
249 connect( editConstants, &QAction::triggered, this, &MainDlg::editConstants );
250 //END edit menu
251
252
253 //BEGIN view menu
254 /// \todo check that new shortcuts work
255
256 QAction * zoomIn = actionCollection()->addAction( "zoom_in" );
257 zoomIn->setText( i18n("Zoom &In") );
258 actionCollection()->setDefaultShortcut( zoomIn, QKeySequence(Qt::ControlModifier | Qt::Key_1) );
259 zoomIn->setIcon( QIcon::fromTheme("zoom-in") );
260 connect( zoomIn, &QAction::triggered, View::self(), QOverload<>::of(&View::zoomIn) );
261
262 QAction * zoomOut = actionCollection()->addAction( "zoom_out" );
263 zoomOut->setText(i18n("Zoom &Out"));
264 actionCollection()->setDefaultShortcut( zoomOut, QKeySequence(Qt::ControlModifier | Qt::Key_2) );
265 zoomOut->setIcon( QIcon::fromTheme("zoom-out") );
266 connect( zoomOut, &QAction::triggered, View::self(), QOverload<>::of(&View::zoomOut) );
267
268 QAction * zoomTrig = actionCollection()->addAction( "zoom_trig" );
269 zoomTrig->setText( i18n("&Fit Widget to Trigonometric Functions") );
270 connect( zoomTrig, &QAction::triggered, View::self(), &View::zoomToTrigonometric );
271
272 QAction * resetView = actionCollection()->addAction( "reset_view" );
273 resetView->setText( i18n( "Reset View" ) );
274 resetView->setIcon( QIcon::fromTheme("resetview") );
275 connect( resetView, &QAction::triggered, this, &MainDlg::slotResetView );
276
277 View::self()->m_menuSliderAction = actionCollection()->add<KToggleAction>( "options_configure_show_sliders" );
278 View::self()->m_menuSliderAction->setText( i18n( "Show Sliders" ) );
279 connect( View::self()->m_menuSliderAction, &QAction::toggled, this, &MainDlg::toggleShowSliders );
280 //END view menu
281
282
283 //BEGIN tools menu
284 QAction *mnuCalculator = actionCollection()->addAction( "calculator" );
285 mnuCalculator->setText( i18n( "Calculator") );
286 mnuCalculator->setIcon( QIcon::fromTheme("system-run") );
287 connect( mnuCalculator, &QAction::triggered, this, &MainDlg::calculator );
288
289 QAction *mnuArea = actionCollection()->addAction( "grapharea" );
290 mnuArea->setText( i18n( "Plot &Area..." ) );
291 connect( mnuArea, &QAction::triggered, this, &MainDlg::graphArea );
292
293 QAction *mnuMaxValue = actionCollection()->addAction( "maximumvalue" );
294 mnuMaxValue->setText( i18n( "Find Ma&ximum..." ) );
295 mnuMaxValue->setIcon( QIcon::fromTheme("maximum") );
296 connect( mnuMaxValue, &QAction::triggered, this, &MainDlg::findMaximumValue );
297
298 QAction *mnuMinValue = actionCollection()->addAction( "minimumvalue" );
299 mnuMinValue->setText( i18n( "Find Mi&nimum..." ) );
300 mnuMinValue->setIcon( QIcon::fromTheme("minimum") );
301 connect( mnuMinValue, &QAction::triggered, this, &MainDlg::findMinimumValue );
302 //END tools menu
303
304
305 //BEGIN help menu
306 QAction * namesAction = actionCollection()->addAction( "names" );
307 namesAction->setText( i18nc("@action:inmenu Help", "Predefined &Math Functions") );
308 namesAction->setIcon( QIcon::fromTheme("functionhelp") );
309 connect( namesAction, &QAction::triggered, this, &MainDlg::slotNames );
310 //END help menu
311
312
313 //BEGIN new plots menu
314 QAction * newFunction = actionCollection()->addAction( "newcartesian" );
315 newFunction->setText( i18n( "Cartesian Plot" ) );
316 newFunction->setIcon( QIcon::fromTheme("newfunction") );
317 connect( newFunction, &QAction::triggered, m_functionEditor, &FunctionEditor::createCartesian );
318 m_newPlotMenu->addAction( newFunction );
319
320 QAction * newParametric = actionCollection()->addAction( "newparametric" );
321 newParametric->setText( i18n( "Parametric Plot" ) );
322 newParametric->setIcon( QIcon::fromTheme("newparametric") );
323 connect( newParametric, &QAction::triggered, m_functionEditor, &FunctionEditor::createParametric );
324 m_newPlotMenu->addAction( newParametric );
325
326 QAction * newPolar = actionCollection()->addAction( "newpolar" );
327 newPolar->setText( i18n( "Polar Plot" ) );
328 newPolar->setIcon( QIcon::fromTheme("newpolar") );
329 connect( newPolar, &QAction::triggered, m_functionEditor, &FunctionEditor::createPolar );
330 m_newPlotMenu->addAction( newPolar );
331
332 QAction * newImplicit = actionCollection()->addAction( "newimplicit" );
333 newImplicit->setText( i18n( "Implicit Plot" ) );
334 newImplicit->setIcon( QIcon::fromTheme("newimplicit") );
335 connect( newImplicit, &QAction::triggered, m_functionEditor, &FunctionEditor::createImplicit );
336 m_newPlotMenu->addAction( newImplicit );
337
338 QAction * newDifferential = actionCollection()->addAction( "newdifferential" );
339 newDifferential->setText( i18n( "Differential Plot" ) );
340 newDifferential->setIcon( QIcon::fromTheme("newdifferential") );
341 connect( newDifferential, &QAction::triggered, m_functionEditor, &FunctionEditor::createDifferential );
342 m_newPlotMenu->addAction( newDifferential );
343 //END new plots menu
344
345
346 //BEGIN function popup menu
347 QAction *mnuEdit = actionCollection()->addAction( "mnuedit" );
348 mnuEdit->setText(i18n("&Edit"));
349 m_firstFunctionAction = mnuEdit;
350 mnuEdit->setIcon( QIcon::fromTheme("editplots") );
351 connect(mnuEdit, &QAction::triggered, View::self(), &View::editCurrentPlot );
352 m_popupmenu->addAction( mnuEdit );
353
354 QAction *mnuHide = actionCollection()->addAction( "mnuhide" );
355 mnuHide->setText( i18n("&Hide") );
356 connect( mnuHide, &QAction::triggered, View::self(), &View::hideCurrentFunction );
357 m_popupmenu->addAction( mnuHide );
358
359 QAction *mnuRemove = actionCollection()->addAction( "mnuremove" );
360 mnuRemove->setText(i18n("&Remove"));
361 mnuRemove->setIcon( QIcon::fromTheme("edit-delete") );
362 connect( mnuRemove, &QAction::triggered, View::self(), &View::removeCurrentPlot );
363 m_popupmenu->addAction( mnuRemove );
364
365 m_popupmenu->addSeparator();
366
367 QAction * animateFunction = actionCollection()->addAction( "animateFunction" );
368 animateFunction->setText(i18n("Animate Plot..."));
369 connect( animateFunction, &QAction::triggered, View::self(), &View::animateFunction );
370 m_popupmenu->addAction( animateFunction );
371 m_popupmenu->addSeparator();
372
373 m_popupmenu->addAction( mnuCalculator );
374 m_popupmenu->addAction( mnuMinValue );
375 m_popupmenu->addAction( mnuMaxValue );
376 m_popupmenu->addAction( mnuArea );
377
378 QAction * copyXY = actionCollection()->addAction( "copyXY" );
379 copyXY->setText(i18n("Copy (x, y)"));
380 connect( copyXY, &QAction::triggered, []{
381 QClipboard * cb = QApplication::clipboard();
382 QPointF currentXY = View::self()->getCrosshairPosition();
383 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 );
384 } );
385 m_popupmenu->addAction( copyXY );
386
387 QAction * copyRootValue = actionCollection()->addAction( "copyRootValue" );
388 copyRootValue->setText(i18n("Copy Root Value"));
389 connect( View::self(), &View::updateRootValue, [this, copyRootValue]( bool haveRoot, double rootValue ){
390 copyRootValue->setVisible(haveRoot);
391 m_rootValue = rootValue;
392 } );
393 connect( copyRootValue, &QAction::triggered, [this]{
394 QClipboard * cb = QApplication::clipboard();
395 cb->setText( QLocale().toString( m_rootValue, 'f', 5 ), QClipboard::Clipboard );
396 } );
397 m_popupmenu->addAction( copyRootValue );
398
399 //END function popup menu
400 }
401
402
undo()403 void MainDlg::undo()
404 {
405 qDebug() ;
406
407 if ( m_undoStack.isEmpty() )
408 return;
409
410 m_redoStack.push( m_currentState );
411 m_currentState = m_undoStack.pop();
412
413 kmplotio->restore( m_currentState );
414 View::self()->drawPlot();
415
416 m_undoAction->setEnabled( !m_undoStack.isEmpty() );
417 m_redoAction->setEnabled( true );
418 }
419
420
redo()421 void MainDlg::redo()
422 {
423 qDebug() ;
424
425 if ( m_redoStack.isEmpty() )
426 return;
427
428 m_undoStack.push( m_currentState );
429 m_currentState = m_redoStack.pop();
430
431 kmplotio->restore( m_currentState );
432 View::self()->drawPlot();
433
434 m_undoAction->setEnabled( true );
435 m_redoAction->setEnabled( !m_redoStack.isEmpty() );
436 }
437
438
requestSaveCurrentState()439 void MainDlg::requestSaveCurrentState()
440 {
441 m_saveCurrentStateTimer->start( 0 );
442 }
saveCurrentState()443 void MainDlg::saveCurrentState( )
444 {
445 m_redoStack.clear();
446 m_undoStack.push( m_currentState );
447 m_currentState = kmplotio->currentState();
448
449 // limit stack size to 100 items
450 while ( m_undoStack.count() > 100 )
451 m_undoStack.pop_front();
452
453 m_undoAction->setEnabled( true );
454 m_redoAction->setEnabled( false );
455
456 m_modified = true;
457 }
458
459
resetUndoRedo()460 void MainDlg::resetUndoRedo()
461 {
462 m_redoStack.clear();
463 m_undoStack.clear();
464 m_currentState = kmplotio->currentState();
465 m_undoAction->setEnabled( false );
466 m_redoAction->setEnabled( false );
467 }
468
469
checkModified()470 bool MainDlg::checkModified()
471 {
472 if( m_modified )
473 {
474 int saveit = KMessageBox::warningYesNoCancel( m_parent, i18n( "The plot has been modified.\n"
475 "Do you want to save it?" ), QString(), KStandardGuiItem::save(), KStandardGuiItem::discard() );
476 switch( saveit )
477 {
478 case KMessageBox::Yes:
479 slotSave();
480 if ( m_modified) // the user didn't saved the file
481 return false;
482 break;
483 case KMessageBox::Cancel:
484 return false;
485 }
486 }
487 return true;
488 }
489
490
slotSave()491 void MainDlg::slotSave()
492 {
493 if ( !m_modified || m_readonly) //don't save if no changes are made or readonly is enabled
494 return;
495 if ( url().isEmpty() ) // if there is no file name set yet
496 slotSaveas();
497 else
498 {
499 if ( !m_modified) //don't save if no changes are made
500 return;
501
502 if ( oldfileversion)
503 {
504 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)
505 return;
506 }
507 kmplotio->save( this->url() );
508 qDebug() << "saved";
509 m_modified = false;
510 }
511
512 }
513
slotSaveas()514 void MainDlg::slotSaveas()
515 {
516 if (m_readonly)
517 return;
518 const QUrl url = QFileDialog::getSaveFileUrl(m_parent, i18n( "Save As" ), QUrl::fromLocalFile(QDir::currentPath()),
519 i18n( "KmPlot Files (*.fkt);;All Files (*)" )
520 );
521
522 if ( url.isEmpty() )
523 return;
524
525 if ( !kmplotio->save( url ) )
526 KMessageBox::error(m_parent, i18n("The file could not be saved") );
527 else
528 {
529 setUrl(url);
530 m_recentFiles->addUrl( url );
531 setWindowCaption( QUrl(this->url()).toString() );
532 m_modified = false;
533 }
534 }
535
slotExport()536 void MainDlg::slotExport()
537 {
538 QString filters;
539 QMimeDatabase mimeDatabase;
540 for (const QByteArray &mimeType : QImageWriter::supportedMimeTypes()) {
541 const QString filter = mimeDatabase.mimeTypeForName(QLatin1String(mimeType)).filterString();
542 if (!filter.isEmpty()) {
543 if (mimeType == QByteArrayLiteral("image/png")) {
544 if (!filters.isEmpty()) {
545 filters.prepend(QStringLiteral(";;"));
546 }
547 filters.prepend(filter);
548 } else {
549 if (!filters.isEmpty()) {
550 filters.append(QStringLiteral(";;"));
551 }
552 filters.append(filter);
553 }
554 }
555 }
556 if (!filters.isEmpty()) {
557 filters.append(QStringLiteral(";;"));
558 }
559 filters.append(i18n("Scalable Vector Graphics (*.svg)"));
560
561 QUrl url = QFileDialog::getSaveFileUrl(m_parent, i18nc("@title:window", "Export as Image"), QUrl::fromLocalFile(QDir::currentPath()), filters);
562
563 if ( !url.isValid() )
564 return;
565
566 QMimeType mimeType = mimeDatabase.mimeTypeForUrl( url );
567 qDebug() << "mimetype: " << mimeType.name();
568
569 bool isSvg = mimeType.name() == "image/svg+xml";
570
571 bool saveOk = true;
572
573 if ( isSvg )
574 {
575 QSvgGenerator img;
576 img.setViewBox( QRect( QPoint(0, 0), View::self()->size() ) );
577
578 QFile file;
579 QTemporaryFile tmp;
580
581 if ( url.isLocalFile() )
582 {
583 file.setFileName( url.toLocalFile() );
584 img.setOutputDevice( &file );
585 }
586 else
587 {
588 tmp.setFileTemplate(QDir::tempPath() + QLatin1String("/kmplot_XXXXXX") + QLatin1String(".svg"));
589 img.setOutputDevice( &tmp );
590 }
591
592 View::self()->draw( &img, View::SVG );
593
594 if ( !url.isLocalFile() )
595 {
596 Q_CONSTEXPR int permission = -1;
597 QFile file(tmp.fileName());
598 file.open(QIODevice::ReadOnly);
599 KIO::StoredTransferJob *putjob = KIO::storedPut(file.readAll(), url, permission, KIO::JobFlag::Overwrite);
600 saveOk &= putjob->exec();
601 file.close();
602 }
603 }
604 else
605 {
606 QPixmap img( View::self()->size() );
607 View::self()->draw( & img, View::Pixmap );
608
609 QStringList types = mimeType.suffixes();
610 if ( types.isEmpty() )
611 return; // TODO error dialog?
612
613 if ( url.isLocalFile() )
614 saveOk = img.save( url.toLocalFile(), types.at(0).toLatin1() );
615 else
616 {
617 QTemporaryFile tmp;
618 tmp.open();
619 img.save( tmp.fileName(), types.at(0).toLatin1() );
620 Q_CONSTEXPR int permission = -1;
621 QFile file(tmp.fileName());
622 file.open(QIODevice::ReadOnly);
623 KIO::StoredTransferJob *putjob = KIO::storedPut(file.readAll(), url, permission, KIO::JobFlag::Overwrite);
624 saveOk = putjob->exec();
625 file.close();
626 }
627 }
628
629 if ( !saveOk )
630 KMessageBox::error(m_parent,
631 i18n("Sorry, something went wrong while saving to image \"%1\"",
632 url.toString()));
633 }
634
635
openFile()636 bool MainDlg::openFile()
637 {
638 if (url()==m_currentfile || !kmplotio->load( url() ) )
639 {
640 m_recentFiles->removeUrl( url() ); //remove the file from the recent-opened-file-list
641 setUrl(QUrl());
642 return false;
643 }
644
645 m_currentfile = url();
646 m_recentFiles->addUrl( url() );
647 setWindowCaption( url().toDisplayString() );
648 resetUndoRedo();
649 View::self()->updateSliders();
650 View::self()->drawPlot();
651 return true;
652 }
653
saveFile()654 bool MainDlg::saveFile()
655 {
656 slotSave();
657 return !isModified();
658 }
659
slotOpenRecent(const QUrl & url)660 void MainDlg::slotOpenRecent( const QUrl &url )
661 {
662 if( isModified() || !this->url().isEmpty() ) // open the file in a new window
663 {
664 QDBusReply<void> reply = QDBusInterface( QDBusConnection::sessionBus().baseService(), "/kmplot", "org.kde.kmplot.KmPlot" ).call( QDBus::Block, "openFileInNewWindow", url.url() );
665 return;
666 }
667
668 if ( !kmplotio->load( url ) ) //if the loading fails
669 {
670 m_recentFiles->removeUrl(url ); //remove the file from the recent-opened-file-list
671 return;
672 }
673 m_currentfile = url;
674 setUrl(url);
675 m_recentFiles->setCurrentItem(-1); //don't select the item in the open-recent menu
676 setWindowCaption( QUrl(this->url()).toString() );
677 resetUndoRedo();
678 View::self()->updateSliders();
679 View::self()->drawPlot();
680 }
681
slotPrint()682 void MainDlg::slotPrint()
683 {
684 QPrinter prt( QPrinter::PrinterResolution );
685 prt.setResolution( 72 );
686 KPrinterDlg* printdlg = new KPrinterDlg( m_parent );
687 printdlg->setObjectName( "KmPlot page" );
688 QPointer<QPrintDialog> printDialog = new QPrintDialog( &prt, m_parent );
689 printDialog->setOptionTabs( QList<QWidget*>() << printdlg );
690 printDialog->setWindowTitle( i18nc("@title:window", "Print Plot") );
691
692 if (printDialog->exec())
693 {
694 setupPrinter(printdlg, &prt);
695 }
696 delete printDialog;
697 }
698
slotPrintPreview()699 void MainDlg::slotPrintPreview()
700 {
701 QPrinter prt( QPrinter::PrinterResolution );
702 QPointer<QPrintPreviewDialog> preview = new QPrintPreviewDialog( &prt );
703 QPointer<KPrinterDlg> printdlg = new KPrinterDlg( m_parent );
704 QList<QToolBar *> toolbarlist = preview->findChildren<QToolBar *>();
705 if(!toolbarlist.isEmpty())
706 {
707 QAction *printSettings = toolbarlist.first()->addAction( QIcon::fromTheme( "configure" ), i18n("Print Settings") );
708 QList<QPrintPreviewWidget*> previewWidgetsList = preview->findChildren<QPrintPreviewWidget*>();
709 QPrintPreviewWidget *previewWidget = previewWidgetsList.first();
710 connect( printSettings, &QAction::triggered, [preview, previewWidget, printdlg]{
711 QDialog *printSettingsDialog = new QDialog( preview, Qt::WindowFlags() );
712 printSettingsDialog->setWindowTitle( i18nc("@title:window", "Print Settings") );
713 QVBoxLayout *mainLayout = new QVBoxLayout;
714 printSettingsDialog->setLayout(mainLayout);
715 mainLayout->addWidget(printdlg);
716 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok|QDialogButtonBox::Cancel );
717 connect(buttonBox, &QDialogButtonBox::accepted, [previewWidget, printSettingsDialog]{
718 previewWidget->updatePreview();
719 printSettingsDialog->close();
720 } );
721 connect(buttonBox, &QDialogButtonBox::rejected, printSettingsDialog, &QDialog::reject);
722 mainLayout->addWidget(buttonBox);
723 printSettingsDialog->show();
724 });
725 }
726 connect(preview, &QPrintPreviewDialog::paintRequested, [this, &printdlg, &prt]{
727 setupPrinter(printdlg, &prt);
728 } );
729 preview->exec();
730 delete printdlg;
731 delete preview;
732 }
733
setupPrinter(KPrinterDlg * printDialog,QPrinter * printer)734 void MainDlg::setupPrinter(KPrinterDlg *printDialog, QPrinter *printer)
735 {
736 View::self()->setPrintHeaderTable( printDialog->printHeaderTable() );
737 View::self()->setPrintBackground( printDialog->printBackground() );
738 View::self()->setPrintWidth( printDialog->printWidth() );
739 View::self()->setPrintHeight( printDialog->printHeight() );
740 View::self()->draw(printer, View::Printer);
741 }
742
editAxes()743 void MainDlg::editAxes()
744 {
745 coordsDialog()->show();
746 }
747
748
editConstants()749 void MainDlg::editConstants()
750 {
751 if ( !m_constantEditor)
752 m_constantEditor = new KConstantEditor(m_parent);
753
754 m_constantEditor->show();
755 }
756
757
editConstantsModal(QWidget * parent)758 void MainDlg::editConstantsModal(QWidget *parent)
759 {
760 if (m_constantEditor) {
761 m_constantEditor->hide();
762 }
763 else {
764 m_constantEditor = new KConstantEditor(parent);
765 }
766
767 m_constantEditor->setModal(true);
768 m_constantEditor->show();
769 }
770
fileExists(const QUrl & url)771 bool MainDlg::fileExists(const QUrl &url)
772 {
773 bool fileExists = false;
774 if (url.isValid()) {
775 short int detailLevel = 0; // Lowest level: file/dir/symlink/none
776 KIO::StatJob* statjob = KIO::stat(url, KIO::StatJob::SourceSide, detailLevel);
777 bool noerror = statjob->exec();
778 if (noerror) {
779 // We want a file
780 fileExists = !statjob->statResult().isDir();
781 }
782 }
783 return fileExists;
784 }
785
slotNames()786 void MainDlg::slotNames()
787 {
788 KHelpClient::invokeHelp( "func-predefined", "kmplot" );
789 }
790
791
slotResetView()792 void MainDlg::slotResetView()
793 {
794 View::self()->animateZoom( QRectF( -8, -8, 16, 16 ) );
795 }
796
slotSettings()797 void MainDlg::slotSettings()
798 {
799 // An instance of your dialog has already been created and has been cached,
800 // so we want to display the cached dialog instead of creating
801 // another one
802 KConfigDialog::showDialog( "settings" );
803 }
804
805
calculator()806 void MainDlg::calculator()
807 {
808 m_calculator->show();
809 }
810
findMinimumValue()811 void MainDlg::findMinimumValue()
812 {
813 m_functionTools->init( FunctionTools::FindMinimum );
814 m_functionTools->show();
815 }
816
findMaximumValue()817 void MainDlg::findMaximumValue()
818 {
819 m_functionTools->init( FunctionTools::FindMaximum );
820 m_functionTools->show();
821 }
822
graphArea()823 void MainDlg::graphArea()
824 {
825 m_functionTools->init( FunctionTools::CalculateArea );
826 m_functionTools->show();
827 }
828
toggleShowSliders()829 void MainDlg::toggleShowSliders()
830 {
831 View::self()->updateSliders();
832 }
833
setReadOnlyStatusBarText(const QString & text)834 void MainDlg::setReadOnlyStatusBarText(const QString &text)
835 {
836 setStatusBarText(text);
837 }
838
queryClose()839 bool MainDlg::queryClose()
840 {
841 return checkModified();
842 }
843
coordsDialog()844 CoordsConfigDialog * MainDlg::coordsDialog( )
845 {
846 if ( !m_coordsDialog)
847 {
848 m_coordsDialog = new CoordsConfigDialog(m_parent);
849 connect( m_coordsDialog, &CoordsConfigDialog::settingsChanged, View::self(), QOverload<>::of(&View::drawPlot) );
850 }
851
852 return m_coordsDialog;
853 }
854 //END class MainDlg
855
856
857 /// BrowserExtension class
BrowserExtension(MainDlg * parent)858 BrowserExtension::BrowserExtension(MainDlg* parent)
859 : KParts::BrowserExtension( parent )
860 {
861 emit enableAction("print", true);
862 setURLDropHandlingEnabled(true);
863 }
864
print()865 void BrowserExtension::print()
866 {
867 static_cast<MainDlg*>(parent())->slotPrint();
868 }
869
870 #include "maindlg.moc"
871