diff --git a/src/cantor.cpp b/src/cantor.cpp index 97727d65..b3cafa05 100644 --- a/src/cantor.cpp +++ b/src/cantor.cpp @@ -1,648 +1,669 @@ /* 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. --- Copyright (C) 2009 Alexander Rieder */ #include "cantor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lib/backend.h" #include "lib/panelpluginhandler.h" #include "lib/panelplugin.h" #include "lib/worksheetaccess.h" #include "settings.h" #include "ui_settings.h" #include "backendchoosedialog.h" CantorShell::CantorShell() : KParts::MainWindow(), m_part(nullptr) { // set the shell's ui resource file setXMLFile(QLatin1String("cantor_shell.rc")); // then, setup our actions setupActions(); createGUI(nullptr); m_tabWidget=new QTabWidget(this); m_tabWidget->setTabsClosable(true); m_tabWidget->setMovable(true); m_tabWidget->setDocumentMode(true); setCentralWidget(m_tabWidget); connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(activateWorksheet(int))); connect(m_tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); // apply the saved mainwindow settings, if any, and ask the mainwindow // to automatically save settings if changed: window size, toolbar // position, icon size, etc. setAutoSaveSettings(); setDockOptions(QMainWindow::AnimatedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::VerticalTabs); updateNewSubmenu(); } void CantorShell::load(const QUrl &url) { if (!m_part||!m_part->url().isEmpty() || m_part->isModified() ) { addWorksheet(QLatin1String("null")); m_tabWidget->setCurrentIndex(m_parts.size()-1); } if (!m_part->openUrl( url )) closeTab(m_tabWidget->currentIndex()); } bool CantorShell::hasAvailableBackend() { bool hasBackend=false; foreach(Cantor::Backend* b, Cantor::Backend::availableBackends()) { if(b->isEnabled()) hasBackend=true; } return hasBackend; } void CantorShell::setupActions() { QAction* openNew = KStandardAction::openNew(this, SLOT(fileNew()), actionCollection()); openNew->setPriority(QAction::LowPriority); QAction* open = KStandardAction::open(this, SLOT(fileOpen()), actionCollection()); open->setPriority(QAction::LowPriority); KStandardAction::close (this, SLOT(closeTab()), actionCollection()); KStandardAction::quit(qApp, SLOT(closeAllWindows()), actionCollection()); createStandardStatusBarAction(); //setStandardToolBarMenuEnabled(true); KStandardAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection()); KStandardAction::configureToolbars(this, SLOT(configureToolbars()), actionCollection()); KStandardAction::preferences(this, SLOT(showSettings()), actionCollection()); QAction * downloadExamples = new QAction(i18n("Download Example Worksheets"), actionCollection()); downloadExamples->setIcon(QIcon::fromTheme(QLatin1String("get-hot-new-stuff"))); actionCollection()->addAction(QLatin1String("file_example_download"), downloadExamples); connect(downloadExamples, SIGNAL(triggered()), this, SLOT(downloadExamples())); QAction * openExample =new QAction(i18n("&Open Example"), actionCollection()); openExample->setIcon(QIcon::fromTheme(QLatin1String("document-open"))); actionCollection()->addAction(QLatin1String("file_example_open"), openExample); connect(openExample, SIGNAL(triggered()), this, SLOT(openExample())); QAction* toPreviousTab = new QAction(i18n("Go to previous worksheet"), actionCollection()); actionCollection()->addAction(QLatin1String("go_to_previous_tab"), toPreviousTab); actionCollection()->setDefaultShortcut(toPreviousTab, Qt::CTRL+Qt::Key_PageDown); connect(toPreviousTab, &QAction::triggered, toPreviousTab, [this](){ const int index = m_tabWidget->currentIndex()-1; if (index >= 0) m_tabWidget->setCurrentIndex(index); else m_tabWidget->setCurrentIndex(m_tabWidget->count()-1); }); addAction(toPreviousTab); QAction* toNextTab = new QAction(i18n("Go to next worksheet"), actionCollection()); actionCollection()->addAction(QLatin1String("go_to_next_tab"), toNextTab); actionCollection()->setDefaultShortcut(toNextTab, Qt::CTRL+Qt::Key_PageUp); connect(toNextTab, &QAction::triggered, toNextTab, [this](){ const int index = m_tabWidget->currentIndex()+1; if (index < m_tabWidget->count()) m_tabWidget->setCurrentIndex(index); else m_tabWidget->setCurrentIndex(0); }); addAction(toNextTab); } void CantorShell::saveProperties(KConfigGroup & /*config*/) { // the 'config' object points to the session managed // config file. anything you write here will be available // later when this app is restored } void CantorShell::readProperties(const KConfigGroup & /*config*/) { // the 'config' object points to the session managed // config file. this function is automatically called whenever // the app is being restored. read in here whatever you wrote // in 'saveProperties' } void CantorShell::fileNew() { if (sender()->inherits("QAction")) { QAction * a = qobject_cast(sender()); QString backendName = a->data().toString(); if (!backendName.isEmpty()) { addWorksheet(backendName); return; } } addWorksheet(); } void CantorShell::optionsConfigureKeys() { KShortcutsDialog dlg( KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsDisallowed, this ); dlg.addCollection( actionCollection(), i18n("Cantor") ); if (m_part) dlg.addCollection( m_part->actionCollection(), i18n("Cantor") ); dlg.configure( true ); } void CantorShell::fileOpen() { // this slot is called whenever the File->Open menu is selected, // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar // button is clicked QUrl url = QFileDialog::getOpenFileUrl(this, i18n("Open file"), QUrl(), i18n("Cantor Worksheet (*.cws)") + QLatin1String(";;") + i18n("Jupyter Notebook (*.ipynb)")); if (url.isEmpty() == false) { // About this function, the style guide ( // http://developer.kde.org/documentation/standards/kde/style/basics/index.html ) // says that it should open a new window if the document is _not_ // in its initial state. This is what we do here.. /*if ( m_part->url().isEmpty() && ! m_part->isModified() ) { // we open the file in this window... load( url ); } else { // we open the file in a new window... CantorShell* newWin = new CantorShell; newWin->load( url ); newWin->show(); }*/ load( url ); } } void CantorShell::addWorksheet() { if(hasAvailableBackend()) //There is no point in asking for the backend, if no one is available { QString backend = Settings::self()->defaultBackend(); if (backend.isEmpty()) { QPointer dlg=new BackendChooseDialog(this); if(dlg->exec()) { backend = dlg->backendName(); addWorksheet(backend); } delete dlg; } else { addWorksheet(backend); } }else { QTextBrowser *browser=new QTextBrowser(this); QString backendList=QLatin1String("
    "); int backendListSize = 0; foreach(Cantor::Backend* b, Cantor::Backend::availableBackends()) { if(!b->requirementsFullfilled()) //It's disabled because of misssing dependencies, not because of some other reason(like eg. nullbackend) { backendList+=QString::fromLatin1("
  • %1: %2
  • ").arg(b->name(), b->url()); ++backendListSize; } } browser->setHtml(i18np("

    No Backend Found

    \n" \ "
    You could try:\n" \ "
      " \ "
    • Changing the settings in the config dialog;
    • " \ "
    • Installing packages for the following program:
    • " \ " %2 " \ "
    " \ "
    " , "

    No Backend Found

    \n" \ "
    You could try:\n" \ "
      " \ "
    • Changing the settings in the config dialog;
    • " \ "
    • Installing packages for one of the following programs:
    • " \ " %2 " \ "
    " \ "
    " , backendListSize, backendList )); browser->setObjectName(QLatin1String("ErrorMessage")); m_tabWidget->addTab(browser, i18n("Error")); } } void CantorShell::addWorksheet(const QString& backendName) { static int sessionCount=1; // this routine will find and load our Part. it finds the Part by // name which is a bad idea usually.. but it's alright in this // case since our Part is made for this Shell KPluginFactory* factory = KPluginLoader(QLatin1String("cantorpart")).factory(); if (factory) { Cantor::Backend* backend = Cantor::Backend::getBackend(backendName); if (backend) { if (backend->isEnabled() || backendName == QLatin1String("null")) { // now that the Part is loaded, we cast it to a Part to get our hands on it KParts::ReadWritePart* part = factory->create(m_tabWidget, QVariantList()<addTab(part->widget(), QIcon::fromTheme(backend->icon()), i18n("Session %1", sessionCount++)); m_tabWidget->setCurrentIndex(tab); // Setting focus on worksheet view, because Qt clear focus of added widget inside addTab // This fix https://bugs.kde.org/show_bug.cgi?id=395976 part->widget()->findChild()->setFocus(); } else { qDebug()<<"error creating part "; } } else { KMessageBox::error(this, i18n("%1 backend installed, but inactive. Please check installation and Cantor settings", backendName), i18n("Cantor")); } } else KMessageBox::error(this, i18n("Backend %1 is not installed", backendName), i18n("Cantor")); } else { // if we couldn't find our Part, we exit since the Shell by // itself can't do anything useful KMessageBox::error(this, i18n("Could not find the Cantor Part.")); qApp->quit(); // we return here, cause qApp->quit() only means "exit the // next time we enter the event loop... return; } } void CantorShell::activateWorksheet(int index) { QObject* pluginHandler=m_part->findChild(QLatin1String("PanelPluginHandler")); if (pluginHandler) disconnect(pluginHandler,SIGNAL(pluginsChanged()), this, SLOT(updatePanel())); // Save part state before change worksheet if (m_part) { QStringList visiblePanelNames; foreach (QDockWidget* doc, m_panels) { if (doc->widget() && doc->widget()->isVisible()) visiblePanelNames << doc->objectName(); } m_pluginsVisibility[m_part] = visiblePanelNames; } m_part=findPart(m_tabWidget->widget(index)); if(m_part) { createGUI(m_part); QObject* pluginHandler=m_part->findChild(QLatin1String("PanelPluginHandler")); connect(pluginHandler, SIGNAL(pluginsChanged()), this, SLOT(updatePanel())); updatePanel(); } else qDebug()<<"selected part doesn't exist"; m_tabWidget->setCurrentIndex(index); } void CantorShell::setTabCaption(const QString& caption, const QIcon& icon) { if (caption.isEmpty()) return; KParts::ReadWritePart* part=dynamic_cast(sender()); m_tabWidget->setTabText(m_tabWidget->indexOf(part->widget()), caption); m_tabWidget->setTabIcon(m_tabWidget->indexOf(part->widget()), icon); } void CantorShell::closeTab(int index) { if (!reallyClose(false)) { return; } QWidget* widget = nullptr; if (index >= 0) { widget = m_tabWidget->widget(index); } else if (m_part) { widget = m_part->widget(); } if (!widget) { qWarning() << "Could not find widget by tab index" << index; return; } m_tabWidget->removeTab(index); if(widget->objectName()==QLatin1String("ErrorMessage")) { widget->deleteLater(); }else { KParts::ReadWritePart* part= findPart(widget); if(part) { m_parts.removeAll(part); m_pluginsVisibility.remove(part); delete part; } } updatePanel(); } bool CantorShell::reallyClose(bool checkAllParts) { if(checkAllParts && m_parts.count() > 1) { bool modified = false; foreach( KParts::ReadWritePart* const part, m_parts) { if(part->isModified()) { modified = true; break; } } if(!modified) return true; int want_save = KMessageBox::warningYesNo( this, i18n("Multiple unsaved Worksheets are opened. Do you want to close them?"), i18n("Close Cantor")); switch (want_save) { case KMessageBox::Yes: return true; case KMessageBox::No: return false; } } if (m_part && m_part->isModified() ) { int want_save = KMessageBox::warningYesNoCancel( this, i18n("The current project has been modified. Do you want to save it?"), i18n("Save Project")); switch (want_save) { case KMessageBox::Yes: m_part->save(); if(m_part->waitSaveComplete()) { return true; } else { m_part->setModified(true); return false; } case KMessageBox::Cancel: return false; case KMessageBox::No: return true; } } return true; } void CantorShell::closeEvent(QCloseEvent* event) { if(!reallyClose()) { event->ignore(); } else { KParts::MainWindow::closeEvent(event); } } void CantorShell::showSettings() { KConfigDialog *dialog = new KConfigDialog(this, QLatin1String("settings"), Settings::self()); QWidget *generalSettings = new QWidget; Ui::SettingsBase base; base.setupUi(generalSettings); base.kcfg_DefaultBackend->addItems(Cantor::Backend::listAvailableBackends()); dialog->addPage(generalSettings, i18n("General"), QLatin1String("preferences-other")); foreach(Cantor::Backend* backend, Cantor::Backend::availableBackends()) { if (backend->config()) //It has something to configure, so add it to the dialog dialog->addPage(backend->settingsWidget(dialog), backend->config(), backend->name(), backend->icon()); } dialog->show(); } void CantorShell::downloadExamples() { KNS3::DownloadDialog dialog; dialog.exec(); foreach (const KNS3::Entry& e, dialog.changedEntries()) { qDebug() << "Changed Entry: " << e.name(); } } void CantorShell::openExample() { QString dir = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/examples"); if (dir.isEmpty()) return; QDir().mkpath(dir); QStringList files=QDir(dir).entryList(QDir::Files); QPointer dlg=new QDialog(this); QListWidget* list=new QListWidget(dlg); foreach(const QString& file, files) { QString name=file; name.remove(QRegExp(QLatin1String("-.*\\.hotstuff-access$"))); list->addItem(name); } QVBoxLayout *mainLayout = new QVBoxLayout; dlg->setLayout(mainLayout); mainLayout->addWidget(list); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); mainLayout->addWidget(buttonBox); buttonBox->button(QDialogButtonBox::Ok)->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogOkButton)); buttonBox->button(QDialogButtonBox::Cancel)->setIcon(QApplication::style()->standardIcon(QStyle::SP_DialogCancelButton)); connect(buttonBox, SIGNAL(accepted()), dlg, SLOT(accept()) ); connect(buttonBox, SIGNAL(rejected()), dlg, SLOT(reject()) ); if (dlg->exec()==QDialog::Accepted&&list->currentRow()>=0) { const QString& selectedFile=files[list->currentRow()]; QUrl url = QUrl::fromLocalFile(QDir(dir).absoluteFilePath(selectedFile)); qDebug()<<"loading file "<widget()==widget) return part; } return nullptr; } void CantorShell::updatePanel() { unplugActionList(QLatin1String("view_show_panel_list")); //remove all of the previous panels (but do not delete the widgets) foreach(QDockWidget* dock, m_panels) { QWidget* widget=dock->widget(); if(widget!=nullptr) { widget->setParent(this); widget->hide(); } dock->deleteLater(); } m_panels.clear(); QList panelActions; Cantor::PanelPluginHandler* handler=m_part->findChild(QLatin1String("PanelPluginHandler")); if(!handler) { qDebug()<<"no PanelPluginHandle found for this part"; return; } QDockWidget* last=nullptr; QList plugins=handler->plugins(); const bool isNewWorksheet = !m_pluginsVisibility.contains(m_part); foreach(Cantor::PanelPlugin* plugin, plugins) { if(plugin==nullptr) { qDebug()<<"somethings wrong"; continue; } qDebug()<<"adding panel for "<name(); plugin->setParentWidget(this); QDockWidget* docker=new QDockWidget(plugin->name(), this); docker->setObjectName(plugin->name()); docker->setWidget(plugin->widget()); addDockWidget ( Qt::RightDockWidgetArea, docker ); // Set visibility for dock from saved info - if (!isNewWorksheet) - if (m_pluginsVisibility[m_part].contains(plugin->name())) + if (isNewWorksheet) + { + if (plugin->showOnStartup()) docker->show(); else docker->hide(); + } else - docker->show(); + { + if (m_pluginsVisibility[m_part].contains(plugin->name())) + docker->show(); + else + docker->hide(); + } if(last!=nullptr) tabifyDockWidget(last, docker); last=docker; - connect(plugin, SIGNAL(visibilityRequested()), docker, SLOT(raise())); + connect(plugin, &Cantor::PanelPlugin::visibilityRequested, this, &CantorShell::pluginVisibilityRequested); m_panels.append(docker); //Create the action to show/hide this panel panelActions<toggleViewAction(); } plugActionList(QLatin1String("view_show_panel_list"), panelActions); updateNewSubmenu(); } void CantorShell::updateNewSubmenu() { unplugActionList(QLatin1String("new_worksheet_with_backend_list")); QList newBackendActions; foreach (Cantor::Backend* backend, Cantor::Backend::availableBackends()) { if (!backend->isEnabled()) continue; QAction * action = new QAction(QIcon::fromTheme(backend->icon()), backend->name(), nullptr); action->setData(backend->name()); connect(action, SIGNAL(triggered()), this, SLOT(fileNew())); newBackendActions << action; } plugActionList(QLatin1String("new_worksheet_with_backend_list"), newBackendActions); } Cantor::WorksheetAccessInterface* CantorShell::currentWorksheetAccessInterface() { Cantor::WorksheetAccessInterface* wa=m_part->findChild(Cantor::WorksheetAccessInterface::Name); if (!wa) qDebug()<<"failed to access worksheet access interface for current part"; return wa; } + +void CantorShell::pluginVisibilityRequested() +{ + Cantor::PanelPlugin* plugin = static_cast(sender()); + for (QDockWidget* docker: m_panels) + { + if (plugin->name() == docker->windowTitle()) + { + if (docker->isHidden()) + docker->show(); + docker->raise(); + } + } +} diff --git a/src/cantor.h b/src/cantor.h index 1e8743e6..0b8a67a9 100644 --- a/src/cantor.h +++ b/src/cantor.h @@ -1,118 +1,120 @@ /* Copyright (C) 2009 Alexander Rieder 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 CANTOR_H #define CANTOR_H #include #include #include class QTabWidget; class KTextEdit; namespace Cantor{ class WorksheetAccessInterface; } namespace KParts{ class ReadWritePart; } /** * This is the application "Shell". It has a menubar, toolbar, and * statusbar but relies on the "Part" to do all the real work. */ class CantorShell : public KParts::MainWindow { Q_OBJECT public: /** * Default Constructor */ CantorShell(); /** * Default Destructor */ ~CantorShell() override = default; /** * Use this method to load whatever file/URL you have */ void load(const QUrl& url); /** * checks if at least one usable Backend is installed */ bool hasAvailableBackend(); Cantor::WorksheetAccessInterface* currentWorksheetAccessInterface(); protected: /** * This method is called when it is time for the app to save its * properties for session management purposes. */ void saveProperties(KConfigGroup &) override; /** * This method is called when this app is restored. The KConfig * object points to the session management config file that was saved * with @ref saveProperties */ void readProperties(const KConfigGroup &) override; public Q_SLOTS: void addWorksheet(); void addWorksheet(const QString& backendName); private Q_SLOTS: void fileNew(); void fileOpen(); void optionsConfigureKeys(); void activateWorksheet(int index); void setTabCaption(const QString& tab, const QIcon& icon); void closeTab(int index = -1); void showSettings(); void downloadExamples(); void openExample(); void updatePanel(); void updateNewSubmenu(); + + void pluginVisibilityRequested(); private: void setupActions(); void closeEvent(QCloseEvent*) override; bool reallyClose(bool checkAllParts = true); KParts::ReadWritePart* findPart(QWidget* widget); private: QMap m_pluginsVisibility; QList m_parts; KParts::ReadWritePart* m_part; QTabWidget* m_tabWidget; QList m_panels; QDockWidget* m_helpDocker; }; #endif // CANTOR_H diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 10279916..385b354c 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,99 +1,99 @@ set( cantor_LIB_SRCS session.cpp expression.cpp backend.cpp result.cpp textresult.cpp imageresult.cpp epsresult.cpp latexresult.cpp latexrenderer.cpp helpresult.cpp animationresult.cpp extension.cpp assistant.cpp completionobject.cpp syntaxhelpobject.cpp defaulthighlighter.cpp defaultvariablemodel.cpp panelplugin.cpp panelpluginhandler.cpp worksheetaccess.cpp directives/plotdirectives.cpp ) Set( cantor_LIB_HDRS cantor_macros.h #base classes backend.h session.h expression.h extension.h syntaxhelpobject.h completionobject.h #results animationresult.h epsresult.h helpresult.h imageresult.h latexresult.h result.h textresult.h #helper classes defaulthighlighter.h defaultvariablemodel.h worksheetaccess.h ) ki18n_wrap_ui(cantor_LIB_SRCS directives/axisrange.ui directives/plottitle.ui) kconfig_add_kcfg_files(cantor_LIB_SRCS settings.kcfgc) install(FILES cantor_libs.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR}) configure_file (config-cantorlib.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-cantorlib.h ) add_library( cantorlibs SHARED ${cantor_LIB_SRCS} ) generate_export_header(cantorlibs BASE_NAME cantor) kcoreaddons_desktop_to_json(cantorlibs cantor_assistant.desktop DEFAULT_SERVICE_TYPE) kcoreaddons_desktop_to_json(cantorlibs cantor_backend.desktop DEFAULT_SERVICE_TYPE) kcoreaddons_desktop_to_json(cantorlibs cantor_panelplugin.desktop DEFAULT_SERVICE_TYPE) target_link_libraries( cantorlibs KF5::Completion KF5::IconThemes KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets KF5::Archive KF5::ConfigCore KF5::ConfigGui KF5::I18n KF5::XmlGui ${QT5_LIBRARIES} Qt5::Xml ) -set (CANTORLIBS_SOVERSION 22) +set (CANTORLIBS_SOVERSION 23) set_target_properties( cantorlibs PROPERTIES VERSION ${KDE_APPLICATIONS_VERSION} SOVERSION ${CANTORLIBS_SOVERSION}) ecm_setup_version(${KDE_APPLICATIONS_VERSION} VARIABLE_PREFIX CANTOR SOVERSION ${CANTORLIBS_SOVERSION} VERSION_HEADER ${CMAKE_CURRENT_BINARY_DIR}/cantorlibs_version.h ) install( TARGETS cantorlibs EXPORT CantorTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} ) install( FILES ${cantor_LIB_HDRS} ${CMAKE_CURRENT_BINARY_DIR}/cantor_export.h ${CMAKE_CURRENT_BINARY_DIR}/cantorlibs_version.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/cantor COMPONENT Devel ) if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/src/lib/imageresult.cpp b/src/lib/imageresult.cpp index 77e593c5..f4ac9a2d 100644 --- a/src/lib/imageresult.cpp +++ b/src/lib/imageresult.cpp @@ -1,149 +1,164 @@ /* 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. --- Copyright (C) 2009 Alexander Rieder */ #include "imageresult.h" using namespace Cantor; #include #include #include #include #include +#include class Cantor::ImageResultPrivate { public: ImageResultPrivate() = default; QUrl url; QImage img; QString alt; }; ImageResult::ImageResult(const QUrl &url, const QString& alt) : d(new ImageResultPrivate) { d->url=url; d->alt=alt; } +Cantor::ImageResult::ImageResult(const QImage& image, const QString& alt) : d(new ImageResultPrivate) +{ + d->img=image; + d->alt=alt; + + QTemporaryFile imageFile; + imageFile.setAutoRemove(false); + if (imageFile.open()) + { + d->img.save(imageFile.fileName(), "PNG"); + d->url = QUrl::fromLocalFile(imageFile.fileName()); + } +} + ImageResult::~ImageResult() { delete d; } QString ImageResult::toHtml() { return QStringLiteral("\"%2\"/").arg(d->url.toLocalFile(), d->alt); } QString ImageResult::toLatex() { return QStringLiteral(" \\begin{center} \n \\includegraphics[width=12cm]{%1} \n \\end{center}").arg(d->url.fileName()); } QVariant ImageResult::data() { if(d->img.isNull()) d->img.load(d->url.toLocalFile()); return QVariant(d->img); } QUrl ImageResult::url() { return d->url; } int ImageResult::type() { return ImageResult::Type; } QString ImageResult::mimeType() { const QList formats=QImageWriter::supportedImageFormats(); QString mimetype; foreach(const QByteArray& format, formats) { mimetype+=QLatin1String("image/"+format.toLower()+' '); } qDebug()<<"type: "<url.fileName()); qDebug()<<"done"; return e; } QJsonValue Cantor::ImageResult::toJupyterJson() { QJsonObject root; root.insert(QLatin1String("output_type"), QLatin1String("display_data")); QJsonObject data; data.insert(QLatin1String("text/plain"), d->alt); QImage image; if (d->img.isNull()) image.load(d->url.toLocalFile()); else image = d->img; QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); image.save(&buffer, "PNG"); data.insert(QLatin1String("image/png"), QString::fromLatin1(ba.toBase64())); root.insert(QLatin1String("data"), data); QJsonObject metadata; QJsonObject size; size.insert(QLatin1String("width"), image.size().width()); size.insert(QLatin1String("height"), image.size().height()); metadata.insert(QLatin1String("image/png"), size); root.insert(QLatin1String("metadata"), metadata); return root; } void ImageResult::saveAdditionalData(KZip* archive) { archive->addLocalFile(d->url.toLocalFile(), d->url.fileName()); } void ImageResult::save(const QString& filename) { //load into memory and let Qt save it, instead of just copying d->url //to give possibility to convert file format QImage img=data().value(); img.save(filename); } diff --git a/src/lib/imageresult.h b/src/lib/imageresult.h index fe4fad5b..9cd347d7 100644 --- a/src/lib/imageresult.h +++ b/src/lib/imageresult.h @@ -1,58 +1,61 @@ /* 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. --- Copyright (C) 2009 Alexander Rieder */ #ifndef _IMAGERESULT_H #define _IMAGERESULT_H #include "result.h" #include +class QImage; + namespace Cantor { class ImageResultPrivate; class CANTOR_EXPORT ImageResult : public Result { public: enum{Type=2}; explicit ImageResult( const QUrl& url, const QString& alt=QString()); + explicit ImageResult( const QImage& image, const QString& alt=QString()); ~ImageResult() override; QString toHtml() override; QString toLatex() override; QVariant data() override; QUrl url() override; int type() override; QString mimeType() override; QDomElement toXml(QDomDocument& doc) override; QJsonValue toJupyterJson() override; void saveAdditionalData(KZip* archive) override; void save(const QString& filename) override; private: ImageResultPrivate* d; }; } #endif /* _IMAGERESULT_H */ diff --git a/src/lib/panelplugin.cpp b/src/lib/panelplugin.cpp index 1f2f3fac..b7d18263 100644 --- a/src/lib/panelplugin.cpp +++ b/src/lib/panelplugin.cpp @@ -1,92 +1,97 @@ /* 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. --- Copyright (C) 2010 Alexander Rieder */ #include "panelplugin.h" using namespace Cantor; #include class Cantor::PanelPluginPrivate { public: QString name; QStringList requiredExtensions; Session* session; QWidget* parentWidget; }; PanelPlugin::PanelPlugin( QObject* parent) : QObject(parent), /* KXMLGUIClient(dynamic_cast(parent)),*/ d(new PanelPluginPrivate) { d->parentWidget=nullptr; d->session=nullptr; } PanelPlugin::~PanelPlugin() { delete d; } void PanelPlugin::setParentWidget(QWidget* widget) { d->parentWidget=widget; } QWidget* PanelPlugin::parentWidget() { return d->parentWidget; } void PanelPlugin::setPluginInfo(const KPluginMetaData& info) { d->name=info.name(); d->requiredExtensions=info.value(QStringLiteral("RequiredExtensions")).split(QLatin1Char(',')); } QStringList PanelPlugin::requiredExtensions() { return d->requiredExtensions; } Backend::Capabilities PanelPlugin::requiredCapabilities() { return Backend::Nothing; } QString PanelPlugin::name() { return d->name; } Session* PanelPlugin::session() { return d->session; } void PanelPlugin::setSession(Session* session) { d->session=session; onSessionChanged(); } void PanelPlugin::onSessionChanged() { } + +bool Cantor::PanelPlugin::showOnStartup() +{ + return true; +} diff --git a/src/lib/panelplugin.h b/src/lib/panelplugin.h index 1d640a21..6bd4e06c 100644 --- a/src/lib/panelplugin.h +++ b/src/lib/panelplugin.h @@ -1,116 +1,122 @@ /* 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. --- Copyright (C) 2010 Alexander Rieder */ #ifndef _PANEL_PLUGIN_H #define _PANEL_PLUGIN_H #include class KPluginMetaData; #include "backend.h" #include "cantor_export.h" namespace Cantor { class Session; class PanelPluginPrivate; /** * A plugin provides some additional features for the worksheet */ class CANTOR_EXPORT PanelPlugin : public QObject { Q_OBJECT public: /** * Create a new PanelPlugin * @param parent the parent Object @see QObject **/ PanelPlugin( QObject* parent ); /** * Destructor */ ~PanelPlugin() override; /** * Sets the properties of this PanelPlugin * according to KPluginMetaData * @param info KPluginMetaData */ void setPluginInfo(const KPluginMetaData&); /** * Returns a list of all extensions, the current backend * must provide to make this PanelPlugin work. If it doesn't * this PanelPlugin won't be enabled * @return list of required extensions */ QStringList requiredExtensions(); /** * Returns the capabilities, the current backend * must provide to make this PanelPlugin work. If it doesn't * this PanelPlugin won't be enabled * @return the required capabilities */ virtual Backend::Capabilities requiredCapabilities(); /** * Returns the name of the plugin * @return name of the plugin */ QString name(); /** * returns the widget, provided by this plugin * @return the widget, provided by this plugin **/ virtual QWidget* widget() = 0; void setParentWidget(QWidget* widget); QWidget* parentWidget(); /** * sets the session this plugin operates on **/ void setSession(Session* session); /** * returns the session */ Session* session(); + /** + * Show on worksheet startup or not + * Default returns true + */ + virtual bool showOnStartup(); + Q_SIGNALS: void requestRunCommand(const QString& cmd); void visibilityRequested(); protected: virtual void onSessionChanged(); private: PanelPluginPrivate* d; }; } #endif /* _PANEL_PLUGIN_H */ diff --git a/src/panelplugins/helppanel/helppanelplugin.cpp b/src/panelplugins/helppanel/helppanelplugin.cpp index 831e268c..efb101e3 100644 --- a/src/panelplugins/helppanel/helppanelplugin.cpp +++ b/src/panelplugins/helppanel/helppanelplugin.cpp @@ -1,74 +1,79 @@ /* 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. --- Copyright (C) 2010 Alexander Rieder */ #include "helppanelplugin.h" #include #include #include "cantor_macros.h" HelpPanelPlugin::HelpPanelPlugin(QObject* parent, QList args) : Cantor::PanelPlugin(parent) { Q_UNUSED(args); m_edit=nullptr; } HelpPanelPlugin::~HelpPanelPlugin() { delete m_edit; } QWidget* HelpPanelPlugin::widget() { if(m_edit==nullptr) { m_edit=new KTextEdit(parentWidget()); setHelpHtml(i18n("

    Cantor

    The KDE way to do Mathematics")); m_edit->setTextInteractionFlags(Qt::TextBrowserInteraction); connect(parent()->parent(), SIGNAL(showHelp(QString)), this, SLOT(setHelpHtml(QString))); connect(parent()->parent(), SIGNAL(showHelp(QString)), this, SIGNAL(visibilityRequested())); } return m_edit; } void HelpPanelPlugin::setHelpHtml(const QString& help) { if(!m_edit) return; m_edit->setHtml(help); m_edit->selectAll(); m_edit->setFontFamily(QLatin1String("Monospace")); m_edit->moveCursor(QTextCursor::Start); } void HelpPanelPlugin::showHelp(const QString& help) { if(m_edit) m_edit->setHtml(help); } +bool HelpPanelPlugin::showOnStartup() +{ + return false; +} + K_PLUGIN_FACTORY_WITH_JSON(helppanelplugin, "helppanelplugin.json", registerPlugin();) #include "helppanelplugin.moc" diff --git a/src/panelplugins/helppanel/helppanelplugin.h b/src/panelplugins/helppanel/helppanelplugin.h index a7c6db92..8589542b 100644 --- a/src/panelplugins/helppanel/helppanelplugin.h +++ b/src/panelplugins/helppanel/helppanelplugin.h @@ -1,47 +1,49 @@ /* 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. --- Copyright (C) 2010 Alexander Rieder */ #ifndef _HELPPANELPLUGIN_H #define _HELPPANELPLUGIN_H #include "panelplugin.h" class KTextEdit; class HelpPanelPlugin : public Cantor::PanelPlugin { Q_OBJECT public: HelpPanelPlugin( QObject* parent, QList args); ~HelpPanelPlugin() override; QWidget* widget() override; + bool showOnStartup() override; + public Q_SLOTS: void setHelpHtml(const QString& help); void showHelp(const QString& help); private: QPointer m_edit; }; #endif /* _HELPPANELPLUGIN_H */