File indexing completed on 2024-04-21 03:42:07

0001 /*
0002     KmPlot - a math. function plotter for the KDE-Desktop
0003 
0004     SPDX-FileCopyrightText: 2004 Fredrik Edemar <f_edemar@linux.se>
0005 
0006     This file is part of the KDE Project.
0007     KmPlot is part of the KDE-EDU Project.
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 
0011 */
0012 
0013 #include "kmplot.h"
0014 
0015 #include <QFileDialog>
0016 #include <QLabel>
0017 #include <QStatusBar>
0018 #include <QUrl>
0019 
0020 #include <KActionCollection>
0021 #include <KConfig>
0022 #include <KConfigGroup>
0023 #include <KDialogJobUiDelegate>
0024 #include <KIO/CommandLauncherJob>
0025 #include <KLocalizedString>
0026 #include <KMessageBox>
0027 #include <KPluginFactory>
0028 #include <KShortcutsDialog>
0029 #include <KStandardAction>
0030 #include <KToggleFullScreenAction>
0031 
0032 #include "kmplotadaptor.h"
0033 #include "maindlg.h"
0034 #include "view.h"
0035 #include <kmplotprogress.h>
0036 
0037 static QUrl urlFromArg(const QString &arg)
0038 {
0039     return QUrl::fromUserInput(arg, QDir::currentPath(), QUrl::AssumeLocalFile);
0040 }
0041 
0042 KmPlot::KmPlot(const QCommandLineParser &parser)
0043     : KParts::MainWindow()
0044 {
0045     setObjectName(QStringLiteral("KmPlot"));
0046 
0047     // set the shell's ui resource file
0048     setXMLFile(QStringLiteral("kmplot_shell.rc"));
0049     // then, setup our actions
0050     setupActions();
0051 
0052     // setup the status bar
0053     setupStatusBar();
0054 
0055     // this routine will find and load our Part.  it finds the Part by
0056     // name which is a bad idea usually.. but it's alright in this
0057     // case since our Part is made for this Shell
0058     const auto result =
0059         KPluginFactory::instantiatePlugin<KParts::ReadWritePart>(KPluginMetaData(QStringLiteral("kf" QT_STRINGIFY(QT_VERSION_MAJOR) "/parts/kmplotpart")),
0060                                                                  this);
0061     if (result) {
0062         m_part = result.plugin;
0063         // tell the KParts::MainWindow that this is indeed the main widget
0064         setCentralWidget(m_part->widget());
0065         // m_part->widget()->setFocus();
0066         //  and integrate the part's GUI with the shell's
0067         setupGUI(Keys | ToolBar | Save);
0068         createGUI(m_part);
0069     } else {
0070         // if we couldn't find our Part, we exit since the Shell by
0071         // itself can't do anything useful
0072         KMessageBox::error(this, i18n("Could not find KmPlot's part."));
0073         qApp->quit();
0074         // we return here, cause qApp->quit() only means "exit the
0075         // next time we enter the event loop...
0076         return;
0077     }
0078 
0079     // apply the saved mainwindow settings, if any, and ask the mainwindow
0080     // to automatically save settings if changed: window size, toolbar
0081     // position, icon size, etc.
0082     setAutoSaveSettings();
0083     {
0084         bool exit = false;
0085         bool first = true;
0086         const auto arguments = parser.positionalArguments();
0087         for (const QString &arg : arguments) {
0088             QUrl url = urlFromArg(arg);
0089             if (first) {
0090                 exit = !load(url);
0091             } else
0092                 openFileInNewWindow(url);
0093         }
0094         if (exit)
0095             deleteLater(); // couldn't open the file, and therefore exit
0096         first = false;
0097     }
0098 
0099     show();
0100 
0101     new KmPlotAdaptor(this);
0102     QDBusConnection::sessionBus().registerObject(QStringLiteral("/kmplot"), this);
0103 
0104     if (parser.isSet(QStringLiteral("function"))) {
0105         QString f = parser.value(QStringLiteral("function"));
0106         QDBusReply<bool> reply = QDBusInterface(QDBusConnection::sessionBus().baseService(), QStringLiteral("/parser"), QStringLiteral("org.kde.kmplot.Parser"))
0107                                      .call(QDBus::BlockWithGui, QStringLiteral("addFunction"), f, "");
0108     }
0109 }
0110 
0111 KmPlot::~KmPlot()
0112 {
0113 }
0114 
0115 void KmPlot::slotUpdateFullScreen(bool checked)
0116 {
0117     if (checked) {
0118         KToggleFullScreenAction::setFullScreen(this, true);
0119         // m_fullScreen->plug( toolBar( "mainToolBar" ) ); deprecated annma 2006-03-01
0120     } else {
0121         KToggleFullScreenAction::setFullScreen(this, false);
0122         // m_fullScreen->unplug( toolBar( "mainToolBar" ) ); deprecated annma 2006-03-01
0123     }
0124 }
0125 
0126 bool KmPlot::load(const QUrl &url)
0127 {
0128     m_part->openUrl(url);
0129     if (m_part->url().isEmpty())
0130         return false;
0131     setWindowTitle(url.toDisplayString());
0132     return true;
0133 }
0134 
0135 void KmPlot::setupActions()
0136 {
0137     KStandardAction::openNew(this, SLOT(fileNew()), actionCollection());
0138     KStandardAction::open(this, SLOT(fileOpen()), actionCollection());
0139     KStandardAction::quit(this, SLOT(close()), actionCollection());
0140 
0141     createStandardStatusBarAction();
0142     setStandardToolBarMenuEnabled(true);
0143 
0144     m_fullScreen = KStandardAction::fullScreen(nullptr, nullptr, this, actionCollection());
0145     actionCollection()->addAction(QStringLiteral("fullscreen"), m_fullScreen);
0146     connect(m_fullScreen, &KToggleFullScreenAction::toggled, this, &KmPlot::slotUpdateFullScreen);
0147 }
0148 
0149 void KmPlot::fileNew()
0150 {
0151     // About this function, the style guide
0152     // says that it should open a new window if the document is _not_
0153     // in its initial state.  This is what we do here...
0154     if (!m_part->url().isEmpty() || isModified()) {
0155         KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(QStringLiteral("kmplot"), this);
0156         job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0157         job->start();
0158     }
0159 }
0160 
0161 void KmPlot::applyNewToolbarConfig()
0162 {
0163     applyMainWindowSettings(KSharedConfig::openConfig()->group(QString()));
0164 }
0165 
0166 void KmPlot::fileOpen()
0167 {
0168     // this slot is called whenever the File->Open menu is selected,
0169     // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
0170     // button is clicked
0171     QUrl const url = QFileDialog::getOpenFileUrl(this, i18n("Open"), QUrl::fromLocalFile(QDir::currentPath()), i18n("KmPlot Files (*.fkt);;All Files (*)"));
0172 
0173     if (!url.isEmpty()) {
0174         // About this function, the style guide
0175         // says that it should open a new window if the document is _not_
0176         // in its initial state.  This is what we do here..
0177         if (m_part->url().isEmpty() && !isModified())
0178             load(url); // we open the file in this window...
0179         else
0180             openFileInNewWindow(url); // we open the file in a new window...
0181     }
0182 }
0183 
0184 void KmPlot::fileOpen(const QUrl &url)
0185 {
0186     if (!url.isEmpty()) {
0187         // About this function, the style guide
0188         // says that it should open a new window if the document is _not_
0189         // in its initial state.  This is what we do here..
0190         if (m_part->url().isEmpty() && !isModified())
0191             load(url); // we open the file in this window...
0192         else
0193             openFileInNewWindow(url); // we open the file in a new window...
0194     }
0195 }
0196 
0197 void KmPlot::openFileInNewWindow(const QUrl &url)
0198 {
0199     KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(QStringLiteral("kmplot"), {url.url()}, this);
0200     job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, this));
0201     job->start();
0202 }
0203 
0204 bool KmPlot::isModified()
0205 {
0206     QDBusReply<bool> reply = QDBusInterface(QDBusConnection::sessionBus().baseService(), QStringLiteral("/maindlg"), QStringLiteral("org.kde.kmplot.MainDlg"))
0207                                  .call(QDBus::BlockWithGui, QStringLiteral("isModified"));
0208     return reply.value();
0209 }
0210 
0211 bool KmPlot::queryClose()
0212 {
0213     return m_part->queryClose();
0214 }
0215 
0216 void KmPlot::setStatusBarText(const QString &text, int id)
0217 {
0218     static_cast<QLabel *>(statusBarLabels.at(id))->setText(text);
0219 }
0220 
0221 void KmPlot::setupStatusBar()
0222 {
0223     QStatusBar *statusBar = new QStatusBar(this);
0224     setStatusBar(statusBar);
0225 
0226     for (int i = 0; i < View::SectionCount; ++i) {
0227         QLabel *label = new QLabel(statusBar);
0228         label->setFixedHeight(label->fontMetrics().height() + 2);
0229         /// Labels for coordinates should be of fixed width 16 chars to be the same as for good old KmPlot
0230         if (i < 2) {
0231             label->setFixedWidth(label->fontMetrics().boundingRect(QLatin1Char('8')).width() * 16);
0232             label->setAlignment(Qt::AlignCenter);
0233         } else {
0234             label->setAlignment(Qt::AlignLeft);
0235         }
0236 
0237         statusBar->addWidget(label);
0238         statusBarLabels.append(label);
0239     }
0240 
0241     m_progressBar = new KmPlotProgress(statusBar);
0242     m_progressBar->setMaximumHeight(statusBar->height() - 10);
0243     connect(m_progressBar, &KmPlotProgress::cancelDraw, this, &KmPlot::cancelDraw);
0244     statusBar->addWidget(m_progressBar);
0245 }
0246 
0247 void KmPlot::setDrawProgress(double progress)
0248 {
0249     m_progressBar->setProgress(progress);
0250 }
0251 
0252 void KmPlot::cancelDraw()
0253 {
0254     QDBusInterface(QDBusConnection::sessionBus().baseService(), QStringLiteral("/kmplot"), QStringLiteral("org.kde.kmplot.KmPlot"))
0255         .call(QDBus::NoBlock, QStringLiteral("stopDrawing"));
0256 }
0257 
0258 #include "moc_kmplot.cpp"