diff --git a/CMakeLists.txt b/CMakeLists.txt index d29a023..7b14042 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,40 +1,41 @@ project(kmplot) cmake_minimum_required (VERSION 3.5 FATAL_ERROR) -set (QT_MIN_VERSION "5.3.0") +set (QT_MIN_VERSION "5.6.0") +set (KF5_MIN_VERSION "5.32.0") find_package (ECM 1.3.0 REQUIRED NO_MODULE) set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(CheckIncludeFiles) include(KDEInstallDirs) include(ECMAddAppIcon) include(ECMInstallIcons) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Svg Widgets PrintSupport) -find_package (KF5 REQUIRED +find_package (KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Crash GuiAddons I18n Parts WidgetsAddons DocTools DBusAddons ) include_directories (${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}) add_definitions (-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050d00) check_include_files(ieeefp.h HAVE_IEEEFP_H) configure_file(config-kmplot.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kmplot/config-kmplot.h) add_subdirectory( doc ) add_subdirectory( kmplot ) add_subdirectory( icons ) install(FILES org.kde.kmplot.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/kmplot/equationedit.h b/kmplot/equationedit.h index 66f0711..fe01b56 100644 --- a/kmplot/equationedit.h +++ b/kmplot/equationedit.h @@ -1,160 +1,160 @@ /* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 2006 David Saxton * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef EQUATIONEDIT_H #define EQUATIONEDIT_H #include "function.h" #include #include class Equation; class EquationEdit; class EquationEditWidget; class EquationEditor; class EquationEditorWidget; class EquationHighlighter; class QPushButton; typedef QMap CharMap; /** * A line edit for equations that also does syntax highlighting, error checking, * etc, and provides a button for invoking an advanced equation editor. * \author David Saxton */ class EquationEdit : public QWidget { Q_OBJECT - Q_PROPERTY( QString text READ text WRITE setText USER true ) + Q_PROPERTY( QString text READ text WRITE setText NOTIFY textEdited USER true ) public: enum InputType { Function, Expression }; explicit EquationEdit( QWidget * parent ); /** * Set the current error message and position of the error. This is * used to inform the user if his equation is Ok or not. */ void setError( const QString & message, int position ); /** * Check the validity of the current text. Called from * EquationHighlighter when it needs to highlight text. */ void checkTextValidity(); /** * Sets whether the equation edit should be storing a function (i.e. of * the form f(x)=[expression]), or just an expression (i.e. without the * f(x)= part). By default, this assumes that an expression is being * stored. */ void setInputType( InputType type ); /** * Prepends \p prefix to the start of the text when validating it. */ void setValidatePrefix( const QString & prefix ); /** * Hide/show the edit button. */ void showEditButton( bool show ); /** * Changes the equation type. */ void setEquationType( Equation::Type type ); /** * \return a pointer that the equation that this equation edit uses for * validation, etc. */ Equation * equation() const { return m_equation; } /** * For inserting the currently selected text into a function. For * example, if "2+x" is selected, \p before is "sin(" and \p after is * ")", then the text will become "sin(2+x)". */ void wrapSelected( const QString & before, const QString & after ); QString text() const; void clear(); void selectAll(); void insertText( const QString & text ); /** * Attempts to evaluate the text and return it. * \a ok Will be set to whether the text could be evaluated as a number. */ double value( bool * ok = 0 ); /** * @internal workaround for QTBUG-10907 */ void setTabChain( QWidget *next ); signals: void editingFinished(); void textEdited( const QString & text ); void textChanged( const QString & text ); void returnPressed(); void upPressed(); void downPressed(); public Q_SLOTS: void setText( const QString & text ); /** * Launches a dialog for editing the equation. */ void invokeEquationEditor(); void reHighlight(); protected Q_SLOTS: void slotTextChanged(); protected: EquationHighlighter * m_highlighter; Equation * m_equation; InputType m_inputType; bool m_settingText:1; bool m_cleaningText:1; bool m_forcingRehighlight:1; QString m_validatePrefix; EquationEditWidget * m_equationEditWidget; QPushButton * m_editButton; static CharMap m_replaceMap; friend class EquationEditor; friend class EquationEditorWidget; friend class EquationEditWidget; friend class EquationHighlighter; }; #endif diff --git a/kmplot/maindlg.cpp b/kmplot/maindlg.cpp index 7d8c370..129c9ff 100644 --- a/kmplot/maindlg.cpp +++ b/kmplot/maindlg.cpp @@ -1,888 +1,884 @@ /* * KmPlot - a math. function plotter for the KDE-Desktop * * Copyright (C) 1998, 1999, 2000, 2002 Klaus-Dieter Möller * 2006 David Saxton * * This file is part of the KDE Project. * KmPlot is part of the KDE-EDU Project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "maindlg.h" // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include #include #include #include #include #include #include #include #include // local includes #include "calculator.h" #include "functiontools.h" #include "functioneditor.h" #include "kconstanteditor.h" #include "xparser.h" #include "settings.h" #include "ui_settingspagecolor.h" #include "ui_settingspagefonts.h" #include "ui_settingspagegeneral.h" #include "ui_settingspagediagram.h" #include "ksliderwindow.h" #include "maindlgadaptor.h" #include class XParser; class KmPlotIO; class SettingsPageColor : public QWidget, public Ui::SettingsPageColor { public: SettingsPageColor( QWidget * parent = 0 ) : QWidget( parent ) { setupUi(this); layout()->setContentsMargins(0, 0, 0, 0); } }; class SettingsPageFonts : public QWidget, public Ui::SettingsPageFonts { public: SettingsPageFonts( QWidget * parent = 0 ) : QWidget( parent ) { setupUi(this); layout()->setContentsMargins(0, 0, 0, 0); } }; class SettingsPageGeneral : public QWidget, public Ui::SettingsPageGeneral { public: SettingsPageGeneral( QWidget * parent = 0 ) : QWidget( parent ) { setupUi(this); layout()->setContentsMargins(0, 0, 0, 0); } }; class SettingsPageDiagram : public QWidget, public Ui::SettingsPageDiagram { public: SettingsPageDiagram( QWidget * parent = 0 ) : QWidget( parent ) { setupUi(this); layout()->setContentsMargins(0, 0, 0, 0); } }; bool MainDlg::oldfileversion; MainDlg * MainDlg::m_self = 0; K_PLUGIN_FACTORY( KmPlotPartFactory, registerPlugin(); ) //BEGIN class MainDlg MainDlg::MainDlg(QWidget *parentWidget, QObject *parent, const QVariantList& ) : KParts::ReadWritePart( parent ), m_recentFiles( 0 ), m_modified(false), m_parent(parentWidget), m_rootValue( 0 ) { assert( !m_self ); // this class should only be constructed once m_self = this; qDebug() << "parentWidget->objectName():" << parentWidget->objectName(); if ( QString(parentWidget->objectName()).startsWith("KmPlot") ) { setXMLFile("kmplot_part.rc"); m_readonly = false; } else { setXMLFile("kmplot_part_readonly.rc"); m_readonly = true; new BrowserExtension(this); // better integration with Konqueror } m_coordsDialog = 0; m_constantEditor = 0; m_popupmenu = new QMenu( parentWidget ); m_newPlotMenu = new QMenu( parentWidget ); (void) new View( m_readonly, m_popupmenu, parentWidget ); connect( View::self(), &View::setStatusBarText, this, &MainDlg::setReadOnlyStatusBarText ); m_functionEditor = 0; if ( !m_readonly ) { m_functionEditor = new FunctionEditor( m_newPlotMenu, parentWidget ); static_cast(parentWidget)->addDockWidget( Qt::LeftDockWidgetArea, m_functionEditor ); } setWidget( View::self() ); View::self()->setFocusPolicy(Qt::ClickFocus); m_functionTools = new FunctionTools(m_parent); m_calculator = new Calculator( m_parent ); setupActions(); XParser::self()->constants()->load(); kmplotio = new KmPlotIO(); m_config = KSharedConfig::openConfig(); m_recentFiles->loadEntries( m_config->group( QString() ) ); //BEGIN undo/redo stuff m_currentState = kmplotio->currentState(); m_saveCurrentStateTimer = new QTimer( this ); m_saveCurrentStateTimer->setSingleShot( true ); connect( m_saveCurrentStateTimer, &QTimer::timeout, this, &MainDlg::saveCurrentState ); //END undo/redo stuff - - - // Allow config manager to read from equation edits - KConfigDialogManager::changedMap()->insert( "EquationEdit", SIGNAL(textEdited(QString)) ); // Let's create a Configure Dialog m_settingsDialog = new KConfigDialog( parentWidget, "settings", Settings::self() ); QMetaObject::invokeMethod(m_settingsDialog, "setHelp", Qt::DirectConnection, Q_ARG(QString, "configuration"), Q_ARG(QString, "kmplot")); // create and add the page(s) m_generalSettings = new SettingsPageGeneral( View::self() ); m_colorSettings = new SettingsPageColor( View::self() ); m_fontsSettings = new SettingsPageFonts( View::self() ); m_diagramSettings = new SettingsPageDiagram( View::self() ); // Make sure the dialog is at a good default size (hmm QDialog should do this automatically?) QSize minSize = m_generalSettings->layout()->minimumSize() .expandedTo( m_colorSettings->layout()->minimumSize() ) .expandedTo( m_fontsSettings->layout()->minimumSize() ) .expandedTo( m_diagramSettings->layout()->minimumSize() ); m_generalSettings->setMinimumSize( minSize ); m_settingsDialog->addPage( m_generalSettings, i18n("General"), "kmplot", i18n("General Settings") ); m_settingsDialog->addPage( m_diagramSettings, i18n("Diagram"), "coords", i18n("Diagram Appearance") ); m_settingsDialog->addPage( m_colorSettings, i18n("Colors"), "preferences-desktop-color", i18n("Colors") ); m_settingsDialog->addPage( m_fontsSettings, i18n("Fonts"), "preferences-desktop-font", i18n("Fonts") ); // User edited the configuration - update your local copies of the // configuration data connect( m_settingsDialog, &KConfigDialog::settingsChanged, View::self(), QOverload<>::of(&View::drawPlot) ); new MainDlgAdaptor(this); QDBusConnection::sessionBus().registerObject("/maindlg", this); } MainDlg::~MainDlg() { m_recentFiles->saveEntries( m_config->group( QString() ) ); XParser::self()->constants()->save(); delete kmplotio; } void MainDlg::setupActions() { // standard actions m_recentFiles = KStandardAction::openRecent( this, SLOT(slotOpenRecent(QUrl)), this ); actionCollection()->addAction( "file_open_recent", m_recentFiles ); actionCollection()->addAction( KStandardAction::Print, "file_print", this, SLOT(slotPrint()) ); actionCollection()->addAction( KStandardAction::PrintPreview, "file_print_preview", this, SLOT(slotPrintPreview()) ); KStandardAction::save( this, SLOT(slotSave()), actionCollection() ); KStandardAction::saveAs( this, SLOT(slotSaveas()), actionCollection() ); QAction *prefs = KStandardAction::preferences( this, SLOT(slotSettings()), actionCollection()); prefs->setText( i18n( "Configure KmPlot..." ) ); // KmPlot specific actions //BEGIN file menu QAction * exportAction = actionCollection()->addAction( "export" ); exportAction->setText( i18n( "E&xport..." ) ); exportAction->setIcon( QIcon::fromTheme( "document-export" ) ); connect( exportAction, &QAction::triggered, this, &MainDlg::slotExport ); //END file menu //BEGIN edit menu m_undoAction = KStandardAction::undo( this, SLOT(undo()), actionCollection() ); m_undoAction->setEnabled( false ); m_redoAction = KStandardAction::redo( this, SLOT(redo()), actionCollection() ); m_redoAction->setEnabled( false ); QAction * editAxes = actionCollection()->addAction( "editaxes" ); editAxes->setText( i18n( "&Coordinate System..." ) ); editAxes->setIcon( QIcon::fromTheme("coords.png") ); connect( editAxes, &QAction::triggered, this, &MainDlg::editAxes ); QAction * editConstants = actionCollection()->addAction( "editconstants" ); editConstants->setText( i18n( "&Constants..." ) ); editConstants->setIcon( QIcon::fromTheme("editconstants.png") ); connect( editConstants, &QAction::triggered, this, &MainDlg::editConstants ); //END edit menu //BEGIN view menu /// \todo check that new shortcuts work QAction * zoomIn = actionCollection()->addAction( "zoom_in" ); zoomIn->setText( i18n("Zoom &In") ); actionCollection()->setDefaultShortcut( zoomIn, QKeySequence(Qt::ControlModifier | Qt::Key_1) ); zoomIn->setIcon( QIcon::fromTheme("zoom-in") ); connect( zoomIn, &QAction::triggered, View::self(), QOverload<>::of(&View::zoomIn) ); QAction * zoomOut = actionCollection()->addAction( "zoom_out" ); zoomOut->setText(i18n("Zoom &Out")); actionCollection()->setDefaultShortcut( zoomOut, QKeySequence(Qt::ControlModifier | Qt::Key_2) ); zoomOut->setIcon( QIcon::fromTheme("zoom-out") ); connect( zoomOut, &QAction::triggered, View::self(), QOverload<>::of(&View::zoomOut) ); QAction * zoomTrig = actionCollection()->addAction( "zoom_trig" ); zoomTrig->setText( i18n("&Fit Widget to Trigonometric Functions") ); connect( zoomTrig, &QAction::triggered, View::self(), &View::zoomToTrigonometric ); QAction * resetView = actionCollection()->addAction( "reset_view" ); resetView->setText( i18n( "Reset View" ) ); resetView->setIcon( QIcon::fromTheme("resetview") ); connect( resetView, &QAction::triggered, this, &MainDlg::slotResetView ); View::self()->m_menuSliderAction = actionCollection()->add( "options_configure_show_sliders" ); View::self()->m_menuSliderAction->setText( i18n( "Show Sliders" ) ); connect( View::self()->m_menuSliderAction, &QAction::toggled, this, &MainDlg::toggleShowSliders ); //END view menu //BEGIN tools menu QAction *mnuCalculator = actionCollection()->addAction( "calculator" ); mnuCalculator->setText( i18n( "Calculator") ); mnuCalculator->setIcon( QIcon::fromTheme("system-run") ); connect( mnuCalculator, &QAction::triggered, this, &MainDlg::calculator ); QAction *mnuArea = actionCollection()->addAction( "grapharea" ); mnuArea->setText( i18n( "Plot &Area..." ) ); connect( mnuArea, &QAction::triggered, this, &MainDlg::graphArea ); QAction *mnuMaxValue = actionCollection()->addAction( "maximumvalue" ); mnuMaxValue->setText( i18n( "Find Ma&ximum..." ) ); mnuMaxValue->setIcon( QIcon::fromTheme("maximum") ); connect( mnuMaxValue, &QAction::triggered, this, &MainDlg::findMaximumValue ); QAction *mnuMinValue = actionCollection()->addAction( "minimumvalue" ); mnuMinValue->setText( i18n( "Find Mi&nimum..." ) ); mnuMinValue->setIcon( QIcon::fromTheme("minimum") ); connect( mnuMinValue, &QAction::triggered, this, &MainDlg::findMinimumValue ); //END tools menu //BEGIN help menu QAction * namesAction = actionCollection()->addAction( "names" ); namesAction->setText( i18n( "Predefined &Math Functions" ) ); namesAction->setIcon( QIcon::fromTheme("functionhelp") ); connect( namesAction, &QAction::triggered, this, &MainDlg::slotNames ); //END help menu //BEGIN new plots menu QAction * newFunction = actionCollection()->addAction( "newcartesian" ); newFunction->setText( i18n( "Cartesian Plot" ) ); newFunction->setIcon( QIcon::fromTheme("newfunction") ); connect( newFunction, &QAction::triggered, m_functionEditor, &FunctionEditor::createCartesian ); m_newPlotMenu->addAction( newFunction ); QAction * newParametric = actionCollection()->addAction( "newparametric" ); newParametric->setText( i18n( "Parametric Plot" ) ); newParametric->setIcon( QIcon::fromTheme("newparametric") ); connect( newParametric, &QAction::triggered, m_functionEditor, &FunctionEditor::createParametric ); m_newPlotMenu->addAction( newParametric ); QAction * newPolar = actionCollection()->addAction( "newpolar" ); newPolar->setText( i18n( "Polar Plot" ) ); newPolar->setIcon( QIcon::fromTheme("newpolar") ); connect( newPolar, &QAction::triggered, m_functionEditor, &FunctionEditor::createPolar ); m_newPlotMenu->addAction( newPolar ); QAction * newImplicit = actionCollection()->addAction( "newimplicit" ); newImplicit->setText( i18n( "Implicit Plot" ) ); newImplicit->setIcon( QIcon::fromTheme("newimplicit") ); connect( newImplicit, &QAction::triggered, m_functionEditor, &FunctionEditor::createImplicit ); m_newPlotMenu->addAction( newImplicit ); QAction * newDifferential = actionCollection()->addAction( "newdifferential" ); newDifferential->setText( i18n( "Differential Plot" ) ); newDifferential->setIcon( QIcon::fromTheme("newdifferential") ); connect( newDifferential, &QAction::triggered, m_functionEditor, &FunctionEditor::createDifferential ); m_newPlotMenu->addAction( newDifferential ); //END new plots menu //BEGIN function popup menu QAction *mnuEdit = actionCollection()->addAction( "mnuedit" ); mnuEdit->setText(i18n("&Edit")); m_firstFunctionAction = mnuEdit; mnuEdit->setIcon( QIcon::fromTheme("editplots") ); connect(mnuEdit, &QAction::triggered, View::self(), &View::editCurrentPlot ); m_popupmenu->addAction( mnuEdit ); QAction *mnuHide = actionCollection()->addAction( "mnuhide" ); mnuHide->setText( i18n("&Hide") ); connect( mnuHide, &QAction::triggered, View::self(), &View::hideCurrentFunction ); m_popupmenu->addAction( mnuHide ); QAction *mnuRemove = actionCollection()->addAction( "mnuremove" ); mnuRemove->setText(i18n("&Remove")); mnuRemove->setIcon( QIcon::fromTheme("edit-delete") ); connect( mnuRemove, &QAction::triggered, View::self(), &View::removeCurrentPlot ); m_popupmenu->addAction( mnuRemove ); m_popupmenu->addSeparator(); QAction * animateFunction = actionCollection()->addAction( "animateFunction" ); animateFunction->setText(i18n("Animate Plot...")); connect( animateFunction, &QAction::triggered, View::self(), &View::animateFunction ); m_popupmenu->addAction( animateFunction ); m_popupmenu->addSeparator(); m_popupmenu->addAction( mnuCalculator ); m_popupmenu->addAction( mnuMinValue ); m_popupmenu->addAction( mnuMaxValue ); m_popupmenu->addAction( mnuArea ); 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 ); //END function popup menu } void MainDlg::undo() { qDebug() ; if ( m_undoStack.isEmpty() ) return; m_redoStack.push( m_currentState ); m_currentState = m_undoStack.pop(); kmplotio->restore( m_currentState ); View::self()->drawPlot(); m_undoAction->setEnabled( !m_undoStack.isEmpty() ); m_redoAction->setEnabled( true ); } void MainDlg::redo() { qDebug() ; if ( m_redoStack.isEmpty() ) return; m_undoStack.push( m_currentState ); m_currentState = m_redoStack.pop(); kmplotio->restore( m_currentState ); View::self()->drawPlot(); 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(); // limit stack size to 100 items while ( m_undoStack.count() > 100 ) m_undoStack.pop_front(); m_undoAction->setEnabled( true ); m_redoAction->setEnabled( false ); m_modified = true; } void MainDlg::resetUndoRedo() { m_redoStack.clear(); m_undoStack.clear(); m_currentState = kmplotio->currentState(); m_undoAction->setEnabled( false ); m_redoAction->setEnabled( false ); } bool MainDlg::checkModified() { if( m_modified ) { int saveit = KMessageBox::warningYesNoCancel( m_parent, i18n( "The plot has been modified.\n" "Do you want to save it?" ), QString(), KStandardGuiItem::save(), KStandardGuiItem::discard() ); switch( saveit ) { case KMessageBox::Yes: slotSave(); if ( m_modified) // the user didn't saved the file return false; break; case KMessageBox::Cancel: return false; } } return true; } void MainDlg::slotSave() { if ( !m_modified || m_readonly) //don't save if no changes are made or readonly is enabled return; if ( url().isEmpty() ) // if there is no file name set yet slotSaveas(); else { if ( !m_modified) //don't save if no changes are made return; if ( oldfileversion) { 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) return; } kmplotio->save( this->url() ); qDebug() << "saved"; m_modified = false; } } void MainDlg::slotSaveas() { if (m_readonly) return; const QUrl url = QFileDialog::getSaveFileUrl(m_parent, i18n( "Save As" ), QUrl::fromLocalFile(QDir::currentPath()), i18n( "KmPlot Files (*.fkt);;All Files (*)" ) ); if ( url.isEmpty() ) return; if ( !kmplotio->save( url ) ) KMessageBox::error(m_parent, i18n("The file could not be saved") ); else { setUrl(url); m_recentFiles->addUrl( url ); setWindowCaption( QUrl(this->url()).toString() ); m_modified = false; } } void MainDlg::slotExport() { QString filters; QMimeDatabase mimeDatabase; for (const QByteArray &mimeType : QImageWriter::supportedMimeTypes()) { 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)")); QUrl url = QFileDialog::getSaveFileUrl(m_parent, i18nc("@title:window", "Export as Image"), QUrl::fromLocalFile(QDir::currentPath()), filters); if ( !url.isValid() ) return; QMimeType mimeType = mimeDatabase.mimeTypeForUrl( url ); qDebug() << "mimetype: " << mimeType.name(); bool isSvg = mimeType.name() == "image/svg+xml"; bool saveOk = true; if ( isSvg ) { QSvgGenerator img; img.setViewBox( QRect( QPoint(0, 0), View::self()->size() ) ); QFile file; QTemporaryFile tmp; if ( url.isLocalFile() ) { file.setFileName( url.toLocalFile() ); img.setOutputDevice( &file ); } else { tmp.setFileTemplate(QDir::tempPath() + QLatin1String("/kmplot_XXXXXX") + QLatin1String(".svg")); img.setOutputDevice( &tmp ); } View::self()->draw( &img, View::SVG ); if ( !url.isLocalFile() ) { 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(); } } else { QPixmap img( View::self()->size() ); View::self()->draw( & img, View::Pixmap ); QStringList types = mimeType.suffixes(); if ( types.isEmpty() ) return; // TODO error dialog? if ( url.isLocalFile() ) saveOk = img.save( url.toLocalFile(), types.at(0).toLatin1() ); else { QTemporaryFile tmp; tmp.open(); img.save( tmp.fileName(), types.at(0).toLatin1() ); 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(); } } if ( !saveOk ) KMessageBox::error(m_parent, i18n("Sorry, something went wrong while saving to image \"%1\"", url.toString())); } bool MainDlg::openFile() { if (url()==m_currentfile || !kmplotio->load( url() ) ) { m_recentFiles->removeUrl( url() ); //remove the file from the recent-opened-file-list setUrl(QUrl()); return false; } m_currentfile = url(); m_recentFiles->addUrl( url() ); setWindowCaption( url().toDisplayString() ); resetUndoRedo(); View::self()->updateSliders(); View::self()->drawPlot(); return true; } bool MainDlg::saveFile() { slotSave(); return !isModified(); } void MainDlg::slotOpenRecent( const QUrl &url ) { if( isModified() || !this->url().isEmpty() ) // open the file in a new window { QDBusReply reply = QDBusInterface( QDBusConnection::sessionBus().baseService(), "/kmplot", "org.kde.kmplot.KmPlot" ).call( QDBus::Block, "openFileInNewWindow", url.url() ); return; } if ( !kmplotio->load( url ) ) //if the loading fails { m_recentFiles->removeUrl(url ); //remove the file from the recent-opened-file-list return; } m_currentfile = url; setUrl(url); m_recentFiles->setCurrentItem(-1); //don't select the item in the open-recent menu setWindowCaption( QUrl(this->url()).toString() ); resetUndoRedo(); View::self()->updateSliders(); View::self()->drawPlot(); } void MainDlg::slotPrint() { QPrinter prt( QPrinter::PrinterResolution ); prt.setResolution( 72 ); KPrinterDlg* printdlg = new KPrinterDlg( m_parent ); printdlg->setObjectName( "KmPlot page" ); QPointer printDialog = new QPrintDialog( &prt, m_parent ); printDialog->setOptionTabs( QList() << printdlg ); printDialog->setWindowTitle( i18n("Print Plot") ); if (printDialog->exec()) { setupPrinter(printdlg, &prt); } delete printDialog; } void MainDlg::slotPrintPreview() { QPrinter prt( QPrinter::PrinterResolution ); QPointer preview = new QPrintPreviewDialog( &prt ); QPointer printdlg = new KPrinterDlg( m_parent ); QList toolbarlist = preview->findChildren(); if(!toolbarlist.isEmpty()) { QAction *printSettings = toolbarlist.first()->addAction( QIcon::fromTheme( "configure" ), i18n("Print Settings") ); QList previewWidgetsList = preview->findChildren(); QPrintPreviewWidget *previewWidget = previewWidgetsList.first(); connect( printSettings, &QAction::triggered, [preview, previewWidget, printdlg]{ QDialog *printSettingsDialog = new QDialog( preview, Qt::WindowFlags() ); printSettingsDialog->setWindowTitle( i18n("Print Settings") ); 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); } void MainDlg::editAxes() { coordsDialog()->show(); } void MainDlg::editConstants() { if ( !m_constantEditor) m_constantEditor = new KConstantEditor(m_parent); m_constantEditor->show(); } void MainDlg::editConstantsModal(QWidget *parent) { if (m_constantEditor) { m_constantEditor->hide(); } else { m_constantEditor = new KConstantEditor(parent); } m_constantEditor->setModal(true); m_constantEditor->show(); } 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; } void MainDlg::slotNames() { KHelpClient::invokeHelp( "func-predefined", "kmplot" ); } void MainDlg::slotResetView() { View::self()->animateZoom( QRectF( -8, -8, 16, 16 ) ); } void MainDlg::slotSettings() { // 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 KConfigDialog::showDialog( "settings" ); } void MainDlg::calculator() { m_calculator->show(); } void MainDlg::findMinimumValue() { m_functionTools->init( FunctionTools::FindMinimum ); m_functionTools->show(); } void MainDlg::findMaximumValue() { m_functionTools->init( FunctionTools::FindMaximum ); m_functionTools->show(); } void MainDlg::graphArea() { m_functionTools->init( FunctionTools::CalculateArea ); m_functionTools->show(); } void MainDlg::toggleShowSliders() { View::self()->updateSliders(); } void MainDlg::setReadOnlyStatusBarText(const QString &text) { setStatusBarText(text); } bool MainDlg::queryClose() { return checkModified(); } CoordsConfigDialog * MainDlg::coordsDialog( ) { if ( !m_coordsDialog) { m_coordsDialog = new CoordsConfigDialog(m_parent); connect( m_coordsDialog, &CoordsConfigDialog::settingsChanged, View::self(), QOverload<>::of(&View::drawPlot) ); } return m_coordsDialog; } //END class MainDlg /// BrowserExtension class BrowserExtension::BrowserExtension(MainDlg* parent) : KParts::BrowserExtension( parent ) { emit enableAction("print", true); setURLDropHandlingEnabled(true); } void BrowserExtension::print() { static_cast(parent())->slotPrint(); } #include "maindlg.moc"