diff --git a/src/cantor_part.cpp b/src/cantor_part.cpp index afb248b4..6fa20ffd 100644 --- a/src/cantor_part.cpp +++ b/src/cantor_part.cpp @@ -1,882 +1,861 @@ /* 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_part.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "worksheet.h" #include "worksheetview.h" #include "searchbar.h" #include "scripteditor/scripteditorwidget.h" #include "lib/backend.h" #include "lib/extension.h" #include "lib/assistant.h" #include "lib/panelpluginhandler.h" #include "lib/panelplugin.h" #include "lib/worksheetaccess.h" #include "settings.h" //A concrete implementation of the WorksheetAccesssInterface class WorksheetAccessInterfaceImpl : public Cantor::WorksheetAccessInterface { public: WorksheetAccessInterfaceImpl(QObject* parent, Worksheet* worksheet) : WorksheetAccessInterface(parent), m_worksheet(worksheet) { qDebug()<<"new worksheetaccess interface"; connect(worksheet, SIGNAL(modified()), this, SIGNAL(modified())); } ~WorksheetAccessInterfaceImpl() override = default; QByteArray saveWorksheetToByteArray() override { return m_worksheet->saveToByteArray(); } void loadWorksheetFromByteArray(QByteArray* data) override { m_worksheet->load(data); } Cantor::Session* session() override { return m_worksheet->session(); } void evaluate() override { m_worksheet->evaluate(); } void interrupt() override { m_worksheet->interrupt(); } private: Worksheet* m_worksheet; }; CantorPart::CantorPart( QWidget *parentWidget, QObject *parent, const QVariantList & args ): KParts::ReadWritePart(parent), m_searchBar(nullptr), m_initProgressDlg(nullptr), m_showProgressDlg(true), m_showBackendHelp(nullptr), m_statusBarBlocked(false), m_sessionStatusCounter(0) { m_panelHandler=new Cantor::PanelPluginHandler(this); connect(m_panelHandler, SIGNAL(pluginsChanged()), this, SLOT(pluginsChanged())); QString backendName; if(args.isEmpty()) backendName=QLatin1String("null"); else backendName=args.first().toString(); for (const QVariant& arg : args) { if (arg.toString() == QLatin1String("--noprogress") ) { qWarning()<<"not showing the progress bar by request"; m_showProgressDlg=false; } } Cantor::Backend* b=Cantor::Backend::createBackend(backendName); if(!b) { KMessageBox::error(parentWidget, i18n("Backend %1 is not installed", backendName), i18n("Error - Cantor")); setWidget(new QWidget(parentWidget)); //fake being modified so the shell won't try to reuse this part ReadWritePart::setModified(true); return; } qDebug()<<"Backend "<name()<<" offers extensions: "<extensions(); auto* collection = actionCollection(); //central widget QWidget* widget = new QWidget(parentWidget); QVBoxLayout* layout = new QVBoxLayout(widget); m_worksheet=new Worksheet(b, widget); m_worksheetview=new WorksheetView(m_worksheet, widget); m_worksheetview->setEnabled(false); //disable input until the session has successfully logged in and emits the ready signal connect(m_worksheet, SIGNAL(modified()), this, SLOT(setModified())); connect(m_worksheet, SIGNAL(showHelp(QString)), this, SIGNAL(showHelp(QString))); connect(m_worksheet, SIGNAL(loaded()), this, SLOT(initialized())); connect(collection, SIGNAL(inserted(QAction*)), m_worksheet, SLOT(registerShortcut(QAction*))); layout->addWidget(m_worksheetview); setWidget(widget); //create WorksheetAccessInterface, used at the moment by LabPlot only to access Worksheet's API Cantor::WorksheetAccessInterface* iface = new WorksheetAccessInterfaceImpl(this, m_worksheet); Q_UNUSED(iface); //initialize actions m_worksheet->createActions(collection); KStandardAction::saveAs(this, SLOT(fileSaveAs()), collection); m_save = KStandardAction::save(this, SLOT(save()), collection); m_save->setPriority(QAction::LowPriority); QAction* savePlain = new QAction(i18n("Save Plain Text"), collection); collection->addAction(QLatin1String("file_save_plain"), savePlain); savePlain->setIcon(QIcon::fromTheme(QLatin1String("document-save"))); connect(savePlain, SIGNAL(triggered()), this, SLOT(fileSavePlain())); QAction* undo = KStandardAction::undo(m_worksheet, SIGNAL(undo()), collection); undo->setPriority(QAction::LowPriority); connect(m_worksheet, SIGNAL(undoAvailable(bool)), undo, SLOT(setEnabled(bool))); QAction* redo = KStandardAction::redo(m_worksheet, SIGNAL(redo()), collection); redo->setPriority(QAction::LowPriority); connect(m_worksheet, SIGNAL(redoAvailable(bool)), redo, SLOT(setEnabled(bool))); QAction* cut = KStandardAction::cut(m_worksheet, SIGNAL(cut()), collection); cut->setPriority(QAction::LowPriority); connect(m_worksheet, SIGNAL(cutAvailable(bool)), cut, SLOT(setEnabled(bool))); QAction* copy = KStandardAction::copy(m_worksheet, SIGNAL(copy()), collection); copy->setPriority(QAction::LowPriority); connect(m_worksheet, SIGNAL(copyAvailable(bool)), copy, SLOT(setEnabled(bool))); QAction* paste = KStandardAction::paste(m_worksheet, SLOT(paste()), collection); paste->setPriority(QAction::LowPriority); connect(m_worksheet, SIGNAL(pasteAvailable(bool)), paste, SLOT(setEnabled(bool))); QAction* find = KStandardAction::find(this, SLOT(showSearchBar()), collection); find->setPriority(QAction::LowPriority); QAction* replace = KStandardAction::replace(this, SLOT(showExtendedSearchBar()), collection); replace->setPriority(QAction::LowPriority); m_findNext = KStandardAction::findNext(this, SLOT(findNext()), collection); m_findNext->setEnabled(false); m_findPrev = KStandardAction::findPrev(this, SLOT(findPrev()), collection); m_findPrev->setEnabled(false); QAction* latexExport = new QAction(i18n("Export to LaTeX"), collection); collection->addAction(QLatin1String("file_export_latex"), latexExport); latexExport->setIcon(QIcon::fromTheme(QLatin1String("document-export"))); connect(latexExport, SIGNAL(triggered()), this, SLOT(exportToLatex())); QAction* print = KStandardAction::print(this, SLOT(print()), collection); print->setPriority(QAction::LowPriority); QAction* printPreview = KStandardAction::printPreview(this, SLOT(printPreview()), collection); printPreview->setPriority(QAction::LowPriority); KStandardAction::zoomIn(m_worksheetview, SLOT(zoomIn()), collection); KStandardAction::zoomOut(m_worksheetview, SLOT(zoomOut()), collection); m_evaluate = new QAction(i18n("Evaluate Worksheet"), collection); collection->addAction(QLatin1String("evaluate_worksheet"), m_evaluate); m_evaluate->setIcon(QIcon::fromTheme(QLatin1String("system-run"))); collection->setDefaultShortcut(m_evaluate, Qt::CTRL+Qt::Key_E); connect(m_evaluate, SIGNAL(triggered()), this, SLOT(evaluateOrInterrupt())); m_typeset = new KToggleAction(i18n("Typeset using LaTeX"), collection); m_typeset->setChecked(Settings::self()->typesetDefault()); collection->addAction(QLatin1String("enable_typesetting"), m_typeset); connect(m_typeset, SIGNAL(toggled(bool)), this, SLOT(enableTypesetting(bool))); m_highlight = new KToggleAction(i18n("Syntax Highlighting"), collection); m_highlight->setChecked(Settings::self()->highlightDefault()); collection->addAction(QLatin1String("enable_highlighting"), m_highlight); connect(m_highlight, SIGNAL(toggled(bool)), m_worksheet, SLOT(enableHighlighting(bool))); m_completion = new KToggleAction(i18n("Completion"), collection); m_completion->setChecked(Settings::self()->completionDefault()); collection->addAction(QLatin1String("enable_completion"), m_completion); connect(m_completion, SIGNAL(toggled(bool)), m_worksheet, SLOT(enableCompletion(bool))); m_exprNumbering = new KToggleAction(i18n("Line Numbers"), collection); m_exprNumbering->setChecked(Settings::self()->expressionNumberingDefault()); collection->addAction(QLatin1String("enable_expression_numbers"), m_exprNumbering); connect(m_exprNumbering, SIGNAL(toggled(bool)), m_worksheet, SLOT(enableExpressionNumbering(bool))); m_animateWorksheet = new KToggleAction(i18n("Animate Worksheet"), collection); m_animateWorksheet->setChecked(Settings::self()->animationDefault()); collection->addAction(QLatin1String("enable_animations"), m_animateWorksheet); connect(m_animateWorksheet, SIGNAL(toggled(bool)), m_worksheet, SLOT(enableAnimations(bool))); QAction* restart = new QAction(i18n("Restart Backend"), collection); collection->addAction(QLatin1String("restart_backend"), restart); restart->setIcon(QIcon::fromTheme(QLatin1String("system-reboot"))); connect(restart, SIGNAL(triggered()), this, SLOT(restartBackend())); - QAction* evaluateCurrent = new QAction(i18n("Evaluate Entry"), collection); + QAction* evaluateCurrent = new QAction(QIcon::fromTheme(QLatin1String("media-playback-start")), i18n("Evaluate Entry"), collection); collection->addAction(QLatin1String("evaluate_current"), evaluateCurrent); collection->setDefaultShortcut(evaluateCurrent, Qt::SHIFT + Qt::Key_Return); connect(evaluateCurrent, SIGNAL(triggered()), m_worksheet, SLOT(evaluateCurrentEntry())); - QAction* insertCommandEntry = new QAction(i18n("Insert Command Entry"), collection); + QAction* insertCommandEntry = new QAction(QIcon::fromTheme(QLatin1String("run-build")), i18n("Insert Command Entry"), collection); collection->addAction(QLatin1String("insert_command_entry"), insertCommandEntry); collection->setDefaultShortcut(insertCommandEntry, Qt::CTRL + Qt::Key_Return); connect(insertCommandEntry, SIGNAL(triggered()), m_worksheet, SLOT(insertCommandEntry())); - QAction* insertTextEntry = new QAction(i18n("Insert Text Entry"), collection); + QAction* insertTextEntry = new QAction(QIcon::fromTheme(QLatin1String("draw-text")), i18n("Insert Text Entry"), collection); collection->addAction(QLatin1String("insert_text_entry"), insertTextEntry); connect(insertTextEntry, SIGNAL(triggered()), m_worksheet, SLOT(insertTextEntry())); #ifdef Discount_FOUND - QAction* insertMarkdownEntry = new QAction(i18n("Insert Markdown Entry"), collection); + QAction* insertMarkdownEntry = new QAction(QIcon::fromTheme(QLatin1String("text-x-markdown")), i18n("Insert Markdown Entry"), collection); collection->addAction(QLatin1String("insert_markdown_entry"), insertMarkdownEntry); connect(insertMarkdownEntry, SIGNAL(triggered()), m_worksheet, SLOT(insertMarkdownEntry())); #endif - QAction* insertLatexEntry = new QAction(i18n("Insert Latex Entry"), collection); + QAction* insertLatexEntry = new QAction(QIcon::fromTheme(QLatin1String("text-x-tex")), i18n("Insert Latex Entry"), collection); collection->addAction(QLatin1String("insert_latex_entry"), insertLatexEntry); connect(insertLatexEntry, SIGNAL(triggered()), m_worksheet, SLOT(insertLatexEntry())); - QAction* insertPageBreakEntry = new QAction(i18n("Insert Page Break"), collection); + QAction* insertPageBreakEntry = new QAction(QIcon::fromTheme(QLatin1String("go-next-view-page")), i18n("Insert Page Break"), collection); collection->addAction(QLatin1String("insert_page_break_entry"), insertPageBreakEntry); connect(insertPageBreakEntry, SIGNAL(triggered()), m_worksheet, SLOT(insertPageBreakEntry())); - QAction* insertImageEntry = new QAction(i18n("Insert Image"), collection); + QAction* insertImageEntry = new QAction(QIcon::fromTheme(QLatin1String("image-x-generic")), i18n("Insert Image"), collection); collection->addAction(QLatin1String("insert_image_entry"), insertImageEntry); connect(insertImageEntry, SIGNAL(triggered()), m_worksheet, SLOT(insertImageEntry())); - /* - QAction * insertCommandEntryBefore=new QAction(i18n("Insert Command Entry Before"), collection); - //insertCommandEntryBefore->setShortcut(Qt::CTRL + Qt::Key_Return); - collection->addAction("insert_command_entry_before", insertCommandEntryBefore); - connect(insertCommandEntryBefore, SIGNAL(triggered()), m_worksheet, SLOT(insertCommandEntryBefore())); - - QAction * insertTextEntryBefore=new QAction(i18n("Insert Text Entry Before"), collection); - //insertTextEntryBefore->setShortcut(Qt::CTRL + Qt::Key_Return); - collection->addAction("insert_text_entry_before", insertTextEntryBefore); - connect(insertTextEntryBefore, SIGNAL(triggered()), m_worksheet, SLOT(insertTextEntryBefore())); - - QAction * insertPageBreakEntryBefore=new QAction(i18n("Insert Page Break Before"), collection); - collection->addAction("insert_page_break_entry_before", insertPageBreakEntryBefore); - connect(insertPageBreakEntryBefore, SIGNAL(triggered()), m_worksheet, SLOT(insertPageBreakEntryBefore())); - - QAction * insertImageEntryBefore=new QAction(i18n("Insert Image Entry Before"), collection); - //insertTextEntryBefore->setShortcut(Qt::CTRL + Qt::Key_Return); - collection->addAction("insert_image_entry_before", insertImageEntryBefore); - connect(insertImageEntryBefore, SIGNAL(triggered()), m_worksheet, SLOT(insertImageEntryBefore())); - */ - - QAction* removeCurrent = new QAction(i18n("Remove current Entry"), collection); + QAction* removeCurrent = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Remove current Entry"), collection); collection->addAction(QLatin1String("remove_current"), removeCurrent); collection->setDefaultShortcut(removeCurrent, Qt::ShiftModifier + Qt::Key_Delete); connect(removeCurrent, SIGNAL(triggered()), m_worksheet, SLOT(removeCurrentEntry())); m_showBackendHelp = new QAction(i18n("Show %1 Help", b->name()) , collection); m_showBackendHelp->setIcon(QIcon::fromTheme(QLatin1String("help-contents"))); collection->addAction(QLatin1String("backend_help"), m_showBackendHelp); connect(m_showBackendHelp, SIGNAL(triggered()), this, SLOT(showBackendHelp())); QAction* publishWorksheet = new QAction(i18n("Publish Worksheet"), collection); publishWorksheet->setIcon(QIcon::fromTheme(QLatin1String("get-hot-new-stuff"))); collection->addAction(QLatin1String("file_publish_worksheet"), publishWorksheet); connect(publishWorksheet, SIGNAL(triggered()), this, SLOT(publishWorksheet())); KToggleAction* showEditor = new KToggleAction(i18n("Show Script Editor"), collection); showEditor->setChecked(false); collection->addAction(QLatin1String("show_editor"), showEditor); connect(showEditor, SIGNAL(toggled(bool)), this, SLOT(showScriptEditor(bool))); showEditor->setEnabled(b->extensions().contains(QLatin1String("ScriptExtension"))); QAction* showCompletion = new QAction(i18n("Show Completion"), collection); collection->addAction(QLatin1String("show_completion"), showCompletion); QList showCompletionShortcuts; showCompletionShortcuts << Qt::Key_Tab << Qt::CTRL + Qt::Key_Space; collection->setDefaultShortcuts(showCompletion, showCompletionShortcuts); connect(showCompletion, SIGNAL(triggered()), m_worksheet, SLOT(showCompletion())); // set our XML-UI resource file setXMLFile(QLatin1String("cantor_part.rc")); // we are read-write by default setReadWrite(true); // we are not modified since we haven't done anything yet setModified(false); initialized(); } CantorPart::~CantorPart() { if (m_scriptEditor) { disconnect(m_scriptEditor, SIGNAL(destroyed()), this, SLOT(scriptEditorClosed())); delete m_scriptEditor; } if (m_searchBar) delete m_searchBar; } void CantorPart::setReadWrite(bool rw) { // notify your internal widget of the read-write state m_worksheetview->setInteractive(rw); ReadWritePart::setReadWrite(rw); } void CantorPart::setModified(bool modified) { // get a handle on our Save action and make sure it is valid if (!m_save) return; // if so, we either enable or disable it based on the current state m_save->setEnabled(modified); // in any event, we want our parent to do it's thing ReadWritePart::setModified(modified); } KAboutData& CantorPart::createAboutData() { // the non-i18n name here must be the same as the directory in // which the part's rc file is installed ('partrcdir' in the Makefile) static KAboutData about(QLatin1String("cantorpart"), QLatin1String("Cantor"), QLatin1String(CANTOR_VERSION), i18n("CantorPart"), KAboutLicense::GPL, i18n("(C) 2009-2015 Alexander Rieder"), QString(), QLatin1String("http://edu.kde.org/cantor")); about.addAuthor( i18n("Alexander Rieder"), QString(), QLatin1String("alexanderrieder@gmail.com") ); return about; } bool CantorPart::openFile() { //don't crash if for some reason the worksheet is invalid if(m_worksheet==nullptr) { qWarning()<<"trying to open in an invalid cantor part"; return false; } QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); QElapsedTimer timer; timer.start(); const bool rc = m_worksheet->load(localFilePath()); QApplication::restoreOverrideCursor(); if (rc) { qDebug()<< "Worksheet successfully loaded in " << (float)timer.elapsed()/1000 << " seconds)."; updateCaption(); } return rc; } bool CantorPart::saveFile() { // if we aren't read-write, return immediately if (isReadWrite() == false) return false; qDebug()<<"saving to: "<save( localFilePath() ); setModified(false); return true; } void CantorPart::fileSaveAs() { // this slot is called whenever the File->Save As menu is selected QString worksheetFilter = i18n("Cantor Worksheet (*.cws)"); QString filter = worksheetFilter; //if the backend supports scripts, also append their scriptFile endings to the filter Cantor::Backend * const backend=m_worksheet->session()->backend(); if (backend->extensions().contains(QLatin1String("ScriptExtension"))) { Cantor::ScriptExtension* e=dynamic_cast(backend->extension(QLatin1String("ScriptExtension"))); filter+=QLatin1String(";;")+e->scriptFileFilter(); } QString selectedFilter; QString file_name = QFileDialog::getSaveFileName(widget(), i18n("Save as"), QString(), filter, &selectedFilter); if (file_name.isEmpty()) return; //depending on user's selection, save as a worksheet or as a plain script file if (selectedFilter == worksheetFilter) { if (!file_name.endsWith(QLatin1String(".cws"))) file_name += QLatin1String(".cws"); saveAs(QUrl::fromLocalFile(file_name)); } else m_worksheet->savePlain(file_name); updateCaption(); } void CantorPart::fileSavePlain() { QString file_name = QFileDialog::getSaveFileName(widget(), i18n("Save"), QString(), QString()); if (!file_name.isEmpty()) m_worksheet->savePlain(file_name); } void CantorPart::exportToLatex() { QString file_name = QFileDialog::getSaveFileName(widget(), i18n("Export to LaTeX"), QString(), QString()); if (file_name.isEmpty() == false) { if (!file_name.endsWith(QLatin1String(".tex"))) file_name += QLatin1String(".tex"); m_worksheet->saveLatex(file_name); } } void CantorPart::guiActivateEvent( KParts::GUIActivateEvent * event ) { KParts::ReadWritePart::guiActivateEvent(event); if(event->activated()) { if(m_scriptEditor) m_scriptEditor->show(); }else { if(m_scriptEditor) m_scriptEditor->hide(); } } void CantorPart::evaluateOrInterrupt() { qDebug()<<"evalorinterrupt"; if(m_worksheet->isRunning()) m_worksheet->interrupt(); else m_worksheet->evaluate(); } void CantorPart::restartBackend() { m_worksheet->session()->logout(); m_worksheet->session()->login(); } void CantorPart::worksheetStatusChanged(Cantor::Session::Status status) { qDebug()<<"wsStatusChange"<session()->status() == Cantor::Session::Running && m_sessionStatusCounter == count) { m_evaluate->setText(i18n("Interrupt")); m_evaluate->setShortcut(Qt::CTRL+Qt::Key_I); m_evaluate->setIcon(QIcon::fromTheme(QLatin1String("dialog-close"))); setStatusMessage(i18n("Calculating...")); } }); }else if (status==Cantor::Session::Done) { m_evaluate->setText(i18n("Evaluate Worksheet")); m_evaluate->setShortcut(Qt::CTRL+Qt::Key_E); m_evaluate->setIcon(QIcon::fromTheme(QLatin1String("system-run"))); setStatusMessage(i18n("Ready")); } } void CantorPart::showSessionError(const QString& message) { qDebug()<<"Error: "<session(), SIGNAL(statusChanged(Cantor::Session::Status)), this, SLOT(worksheetStatusChanged(Cantor::Session::Status))); connect(m_worksheet->session(), SIGNAL(loginStarted()),this, SLOT(worksheetSessionLoginStarted())); connect(m_worksheet->session(), SIGNAL(loginDone()),this, SLOT(worksheetSessionLoginDone())); connect(m_worksheet->session(), SIGNAL(error(QString)), this, SLOT(showSessionError(QString))); loadAssistants(); m_panelHandler->setSession(m_worksheet->session()); adjustGuiToSession(); if (m_worksheet->isEmpty()) m_worksheet->appendCommandEntry(); m_worksheetview->setEnabled(true); m_worksheetview->setFocus(); setStatusMessage(i18n("Initialization complete")); updateCaption(); } void CantorPart::worksheetSessionLoginStarted() { setStatusMessage(i18n("Initializing...")); QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } void CantorPart::worksheetSessionLoginDone() { setStatusMessage(i18n("Ready")); QApplication::restoreOverrideCursor(); } void CantorPart::enableTypesetting(bool enable) { m_worksheet->session()->setTypesettingEnabled(enable); } void CantorPart::showBackendHelp() { qDebug()<<"showing backends help"; Cantor::Backend* backend=m_worksheet->session()->backend(); QUrl url = backend->helpUrl(); qDebug()<<"launching url "<session()->backend()->icon())); } void CantorPart::pluginsChanged() { for (auto* plugin : m_panelHandler->plugins()) connect(plugin, SIGNAL(requestRunCommand(QString)), this, SLOT(runCommand(QString))); } void CantorPart::loadAssistants() { qDebug()<<"loading assistants..."; QStringList assistantDirs; for (const QString& dir : QCoreApplication::libraryPaths()) assistantDirs << dir + QDir::separator() + QLatin1String("cantor/assistants"); QPluginLoader loader; for (const QString& dir : assistantDirs) { qDebug() << "dir: " << dir; QStringList assistants; QDir assistantDir = QDir(dir); assistants = assistantDir.entryList(); for (const QString& assistant : assistants) { if (assistant==QLatin1String(".") || assistant==QLatin1String("..")) continue; loader.setFileName(dir + QDir::separator() + assistant); if (!loader.load()){ qDebug() << "Error while loading assistant: " << assistant; continue; } KPluginFactory* factory = KPluginLoader(loader.fileName()).factory(); Cantor::Assistant* plugin = factory->create(this); Cantor::Backend* backend=worksheet()->session()->backend(); KPluginMetaData info(loader); plugin->setPluginInfo(info); plugin->setBackend(backend); bool supported=true; for (const QString& req : plugin->requiredExtensions()) supported=supported && backend->extensions().contains(req); if(supported) { qDebug() << "plugin " << info.name() << " is supported by " << backend->name() << ", requires extensions " << plugin->requiredExtensions(); plugin->initActions(); connect(plugin, SIGNAL(requested()), this, SLOT(runAssistant())); }else { qDebug() << "plugin " << info.name() << " is not supported by "<name(); removeChildClient(plugin); plugin->deleteLater(); } } } } void CantorPart::runAssistant() { Cantor::Assistant* a=qobject_cast(sender()); QStringList cmds=a->run(widget()); qDebug()<appendCommandEntry(cmd); } void CantorPart::showSearchBar() { if (!m_searchBar) { m_searchBar = new SearchBar(widget(), m_worksheet); widget()->layout()->addWidget(m_searchBar); connect(m_searchBar, SIGNAL(destroyed(QObject*)), this, SLOT(searchBarDeleted())); } m_findNext->setEnabled(true); m_findPrev->setEnabled(true); m_searchBar->showStandard(); m_searchBar->setFocus(); } void CantorPart::showExtendedSearchBar() { if (!m_searchBar) { m_searchBar = new SearchBar(widget(), m_worksheet); widget()->layout()->addWidget(m_searchBar); connect(m_searchBar, SIGNAL(destroyed(QObject*)), this, SLOT(searchBarDeleted())); } m_findNext->setEnabled(true); m_findPrev->setEnabled(true); m_searchBar->showExtended(); m_searchBar->setFocus(); } void CantorPart::findNext() { if (m_searchBar) m_searchBar->next(); } void CantorPart::findPrev() { if (m_searchBar) m_searchBar->prev(); } void CantorPart::searchBarDeleted() { m_searchBar = nullptr; m_findNext->setEnabled(false); m_findPrev->setEnabled(false); } void CantorPart::adjustGuiToSession() { Cantor::Backend::Capabilities capabilities = m_worksheet->session()->backend()->capabilities(); #ifdef WITH_EPS m_typeset->setVisible(capabilities.testFlag(Cantor::Backend::LaTexOutput)); #else m_typeset->setVisible(false); #endif m_completion->setVisible(capabilities.testFlag(Cantor::Backend::Completion)); //this is 0 on the first call if(m_showBackendHelp) m_showBackendHelp->setText(i18n("Show %1 Help", m_worksheet->session()->backend()->name())); } void CantorPart::publishWorksheet() { int ret = KMessageBox::questionYesNo(widget(), i18n("Do you want to upload current Worksheet to public web server?"), i18n("Question - Cantor")); if (ret != KMessageBox::Yes) return; if (isModified()||url().isEmpty()) { ret = KMessageBox::warningContinueCancel(widget(), i18n("The Worksheet is not saved. You should save it before uploading."), i18n("Warning - Cantor"), KStandardGuiItem::save(), KStandardGuiItem::cancel()); if (ret != KMessageBox::Continue) return; if (!saveFile()) return; } qDebug()<<"uploading file "<session()->backend()->id().toLower()), widget()); dialog.setUploadFile(url()); dialog.exec(); } void CantorPart::print() { QPrinter printer; QPointer dialog = new QPrintDialog(&printer, widget()); // TODO: Re-enable print selection //if (m_worksheet->textCursor().hasSelection()) // dialog->addEnabledOption(QAbstractPrintDialog::PrintSelection); if (dialog->exec() == QDialog::Accepted) m_worksheet->print(&printer); delete dialog; } void CantorPart::printPreview() { QPrintPreviewDialog *dialog = new QPrintPreviewDialog(widget()); connect(dialog, SIGNAL(paintRequested(QPrinter*)), m_worksheet, SLOT(print(QPrinter*))); dialog->exec(); } void CantorPart::showScriptEditor(bool show) { if(show) { if (m_scriptEditor) { return; } Cantor::ScriptExtension* scriptE=dynamic_cast(m_worksheet->session()->backend()->extension(QLatin1String("ScriptExtension"))); if (!scriptE) { return; } m_scriptEditor=new ScriptEditorWidget(scriptE->scriptFileFilter(), scriptE->highlightingMode(), widget()->window()); connect(m_scriptEditor, SIGNAL(runScript(QString)), this, SLOT(runScript(QString))); connect(m_scriptEditor, SIGNAL(destroyed()), this, SLOT(scriptEditorClosed())); m_scriptEditor->show(); }else { m_scriptEditor->deleteLater(); } } void CantorPart::scriptEditorClosed() { QAction* showEditor = actionCollection()->action(QLatin1String("show_editor")); if (showEditor) { showEditor->setChecked(false); } } void CantorPart::runScript(const QString& file) { Cantor::Backend* backend=m_worksheet->session()->backend(); if(!backend->extensions().contains(QLatin1String("ScriptExtension"))) { KMessageBox::error(widget(), i18n("This backend does not support scripts."), i18n("Error - Cantor")); return; } Cantor::ScriptExtension* scriptE=dynamic_cast(backend->extension(QLatin1String("ScriptExtension"))); m_worksheet->appendCommandEntry(scriptE->runExternalScript(file)); } void CantorPart::blockStatusBar() { m_statusBarBlocked=true; } void CantorPart::unblockStatusBar() { m_statusBarBlocked=false; if(!m_cachedStatusMessage.isNull()) setStatusMessage(m_cachedStatusMessage); m_cachedStatusMessage.clear(); } void CantorPart::setStatusMessage(const QString& message) { if(!m_statusBarBlocked) emit setStatusBarText(message); else m_cachedStatusMessage=message; } void CantorPart::showImportantStatusMessage(const QString& message) { setStatusMessage(message); blockStatusBar(); QTimer::singleShot(3000, this, SLOT(unblockStatusBar())); } K_PLUGIN_FACTORY_WITH_JSON(CantorPartFactory, "cantor_part.json", registerPlugin();) #include "cantor_part.moc" diff --git a/src/worksheetentry.cpp b/src/worksheetentry.cpp index 38b50528..aad5071b 100644 --- a/src/worksheetentry.cpp +++ b/src/worksheetentry.cpp @@ -1,803 +1,803 @@ /* 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) 2012 Martin Kuettler */ #include "worksheetentry.h" #include "commandentry.h" #include "textentry.h" #include "markdownentry.h" #include "latexentry.h" #include "imageentry.h" #include "pagebreakentry.h" #include "settings.h" #include "actionbar.h" #include "worksheettoolbutton.h" #include #include #include #include #include #include #include #include #include #include struct AnimationData { QAnimationGroup* animation; QPropertyAnimation* sizeAnimation; QPropertyAnimation* opacAnimation; QPropertyAnimation* posAnimation; const char* slot; QGraphicsObject* item; }; const qreal WorksheetEntry::VerticalMargin = 4; WorksheetEntry::WorksheetEntry(Worksheet* worksheet) : QGraphicsObject() { m_next = nullptr; m_prev = nullptr; m_animation = nullptr; m_actionBar = nullptr; m_actionBarAnimation = nullptr; m_aboutToBeRemoved = false; setAcceptHoverEvents(true); worksheet->addItem(this); } WorksheetEntry::~WorksheetEntry() { emit aboutToBeDeleted(); if (next()) next()->setPrevious(previous()); if (previous()) previous()->setNext(next()); if (m_animation) { m_animation->animation->deleteLater(); delete m_animation; } } int WorksheetEntry::type() const { return Type; } WorksheetEntry* WorksheetEntry::create(int t, Worksheet* worksheet) { switch(t) { case TextEntry::Type: return new TextEntry(worksheet); case MarkdownEntry::Type: return new MarkdownEntry(worksheet); case CommandEntry::Type: return new CommandEntry(worksheet); case ImageEntry::Type: return new ImageEntry(worksheet); case PageBreakEntry::Type: return new PageBreakEntry(worksheet); case LatexEntry::Type: return new LatexEntry(worksheet); default: return nullptr; } } void WorksheetEntry::insertCommandEntry() { worksheet()->insertCommandEntry(this); } void WorksheetEntry::insertTextEntry() { worksheet()->insertTextEntry(this); } void WorksheetEntry::insertMarkdownEntry() { worksheet()->insertMarkdownEntry(this); } void WorksheetEntry::insertLatexEntry() { worksheet()->insertLatexEntry(this); } void WorksheetEntry::insertImageEntry() { worksheet()->insertImageEntry(this); } void WorksheetEntry::insertPageBreakEntry() { worksheet()->insertPageBreakEntry(this); } void WorksheetEntry::insertCommandEntryBefore() { worksheet()->insertCommandEntryBefore(this); } void WorksheetEntry::insertTextEntryBefore() { worksheet()->insertTextEntryBefore(this); } void WorksheetEntry::insertMarkdownEntryBefore() { worksheet()->insertMarkdownEntryBefore(this); } void WorksheetEntry::insertLatexEntryBefore() { worksheet()->insertLatexEntryBefore(this); } void WorksheetEntry::insertImageEntryBefore() { worksheet()->insertImageEntryBefore(this); } void WorksheetEntry::insertPageBreakEntryBefore() { worksheet()->insertPageBreakEntryBefore(this); } void WorksheetEntry::showCompletion() { } WorksheetEntry* WorksheetEntry::next() const { return m_next; } WorksheetEntry* WorksheetEntry::previous() const { return m_prev; } void WorksheetEntry::setNext(WorksheetEntry* n) { m_next = n; } void WorksheetEntry::setPrevious(WorksheetEntry* p) { m_prev = p; } void WorksheetEntry::startDrag(QPointF grabPos) { QDrag* drag = new QDrag(worksheetView()); qDebug() << size(); const qreal scale = worksheet()->epsRenderer()->scale(); QPixmap pixmap((size()*scale).toSize()); pixmap.fill(QColor(255, 255, 255, 0)); QPainter painter(&pixmap); const QRectF sceneRect = mapRectToScene(boundingRect()); worksheet()->render(&painter, pixmap.rect(), sceneRect); painter.end(); QBitmap mask = pixmap.createMaskFromColor(QColor(255, 255, 255), Qt::MaskInColor); pixmap.setMask(mask); drag->setPixmap(pixmap); if (grabPos.isNull()) { const QPointF scenePos = worksheetView()->sceneCursorPos(); drag->setHotSpot((mapFromScene(scenePos) * scale).toPoint()); } else { drag->setHotSpot((grabPos * scale).toPoint()); } drag->setMimeData(new QMimeData()); worksheet()->startDrag(this, drag); } QRectF WorksheetEntry::boundingRect() const { return QRectF(QPointF(0,0), m_size); } void WorksheetEntry::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { Q_UNUSED(painter); Q_UNUSED(option); Q_UNUSED(widget); } bool WorksheetEntry::focusEntry(int pos, qreal xCoord) { Q_UNUSED(pos); Q_UNUSED(xCoord); if (flags() & QGraphicsItem::ItemIsFocusable) { setFocus(); return true; } return false; } void WorksheetEntry::moveToPreviousEntry(int pos, qreal x) { WorksheetEntry* entry = previous(); while (entry && !(entry->wantFocus() && entry->focusEntry(pos, x))) entry = entry->previous(); } void WorksheetEntry::moveToNextEntry(int pos, qreal x) { WorksheetEntry* entry = next(); while (entry && !(entry->wantFocus() && entry->focusEntry(pos, x))) entry = entry->next(); } Worksheet* WorksheetEntry::worksheet() { return qobject_cast(scene()); } WorksheetView* WorksheetEntry::worksheetView() { return worksheet()->worksheetView(); } WorksheetCursor WorksheetEntry::search(const QString& pattern, unsigned flags, QTextDocument::FindFlags qt_flags, const WorksheetCursor& pos) { Q_UNUSED(pattern); Q_UNUSED(flags); Q_UNUSED(qt_flags); Q_UNUSED(pos); return WorksheetCursor(); } void WorksheetEntry::keyPressEvent(QKeyEvent* event) { // This event is used in Entries that set the ItemIsFocusable flag switch(event->key()) { case Qt::Key_Left: case Qt::Key_Up: if (event->modifiers() == Qt::NoModifier) moveToPreviousEntry(WorksheetTextItem::BottomRight, 0); break; case Qt::Key_Right: case Qt::Key_Down: if (event->modifiers() == Qt::NoModifier) moveToNextEntry(WorksheetTextItem::TopLeft, 0); break; /*case Qt::Key_Enter: case Qt::Key_Return: if (event->modifiers() == Qt::ShiftModifier) evaluate(); else if (event->modifiers() == Qt::ControlModifier) worksheet()->insertCommandEntry(); break; case Qt::Key_Delete: if (event->modifiers() == Qt::ShiftModifier) startRemoving(); break;*/ default: event->ignore(); } } void WorksheetEntry::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { QMenu *menu = worksheet()->createContextMenu(); populateMenu(menu, event->pos()); menu->popup(event->screenPos()); } void WorksheetEntry::populateMenu(QMenu* menu, QPointF pos) { if (!worksheet()->isRunning() && wantToEvaluate()) - menu->addAction(i18n("Evaluate Entry"), this, SLOT(evaluate()), 0); + menu->addAction(QIcon::fromTheme(QLatin1String("media-playback-start")), i18n("Evaluate Entry"), this, SLOT(evaluate()), 0); menu->addAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Remove Entry"), this, SLOT(startRemoving()), 0); worksheet()->populateMenu(menu, mapToScene(pos)); } bool WorksheetEntry::evaluateCurrentItem() { // A default implementation that works well for most entries, // because they have only one item. return evaluate(); } void WorksheetEntry::evaluateNext(EvaluationOption opt) { WorksheetEntry* entry = next(); while (entry && !entry->wantFocus()) entry = entry->next(); if (entry) { if (opt == EvaluateNext || Settings::self()->autoEval()) { entry->evaluate(EvaluateNext); } else if (opt == FocusNext) { worksheet()->setModified(); entry->focusEntry(WorksheetTextItem::BottomRight); } else { worksheet()->setModified(); } } else if (opt != DoNothing) { if (!worksheet()->isLoadingFromFile() && (!isEmpty() || type() != CommandEntry::Type)) worksheet()->appendCommandEntry(); else focusEntry(); worksheet()->setModified(); } } qreal WorksheetEntry::setGeometry(qreal x, qreal y, qreal w) { setPos(x, y); layOutForWidth(w); return size().height(); } void WorksheetEntry::recalculateSize() { qreal height = size().height(); layOutForWidth(size().width(), true); if (height != size().height()) worksheet()->updateEntrySize(this); } QPropertyAnimation* WorksheetEntry::sizeChangeAnimation(QSizeF s) { QSizeF oldSize; QSizeF newSize; if (s.isValid()) { oldSize = size(); newSize = s; } else { oldSize = size(); layOutForWidth(size().width(), true); newSize = size(); } QPropertyAnimation* sizeAn = new QPropertyAnimation(this, "size", this); sizeAn->setDuration(200); sizeAn->setStartValue(oldSize); sizeAn->setEndValue(newSize); sizeAn->setEasingCurve(QEasingCurve::InOutQuad); connect(sizeAn, &QPropertyAnimation::valueChanged, this, &WorksheetEntry::sizeAnimated); return sizeAn; } void WorksheetEntry::sizeAnimated() { worksheet()->updateEntrySize(this); } void WorksheetEntry::animateSizeChange() { if (!worksheet()->animationsEnabled()) { recalculateSize(); return; } if (m_animation) { layOutForWidth(size().width(), true); return; } QPropertyAnimation* sizeAn = sizeChangeAnimation(); m_animation = new AnimationData; m_animation->item = nullptr; m_animation->slot = nullptr; m_animation->opacAnimation = nullptr; m_animation->posAnimation = nullptr; m_animation->sizeAnimation = sizeAn; m_animation->sizeAnimation->setEasingCurve(QEasingCurve::OutCubic); m_animation->animation = new QParallelAnimationGroup(this); m_animation->animation->addAnimation(m_animation->sizeAnimation); connect(m_animation->animation, &QAnimationGroup::finished, this, &WorksheetEntry::endAnimation); m_animation->animation->start(); } void WorksheetEntry::fadeInItem(QGraphicsObject* item, const char* slot) { if (!worksheet()->animationsEnabled()) { recalculateSize(); if (slot) invokeSlotOnObject(slot, item); return; } if (m_animation) { // this calculates the new size and calls updateSizeAnimation layOutForWidth(size().width(), true); if (slot) invokeSlotOnObject(slot, item); return; } QPropertyAnimation* sizeAn = sizeChangeAnimation(); m_animation = new AnimationData; m_animation->sizeAnimation = sizeAn; m_animation->sizeAnimation->setEasingCurve(QEasingCurve::OutCubic); m_animation->opacAnimation = new QPropertyAnimation(item, "opacity", this); m_animation->opacAnimation->setDuration(200); m_animation->opacAnimation->setStartValue(0); m_animation->opacAnimation->setEndValue(1); m_animation->opacAnimation->setEasingCurve(QEasingCurve::OutCubic); m_animation->posAnimation = nullptr; m_animation->animation = new QParallelAnimationGroup(this); m_animation->item = item; m_animation->slot = slot; m_animation->animation->addAnimation(m_animation->sizeAnimation); m_animation->animation->addAnimation(m_animation->opacAnimation); connect(m_animation->animation, &QAnimationGroup::finished, this, &WorksheetEntry::endAnimation); m_animation->animation->start(); } void WorksheetEntry::fadeOutItem(QGraphicsObject* item, const char* slot) { // Note: The default value for slot is SLOT(deleteLater()), so item // will be deleted after the animation. if (!worksheet()->animationsEnabled()) { recalculateSize(); if (slot) invokeSlotOnObject(slot, item); return; } if (m_animation) { // this calculates the new size and calls updateSizeAnimation layOutForWidth(size().width(), true); if (slot) invokeSlotOnObject(slot, item); return; } QPropertyAnimation* sizeAn = sizeChangeAnimation(); m_animation = new AnimationData; m_animation->sizeAnimation = sizeAn; m_animation->opacAnimation = new QPropertyAnimation(item, "opacity", this); m_animation->opacAnimation->setDuration(200); m_animation->opacAnimation->setStartValue(1); m_animation->opacAnimation->setEndValue(0); m_animation->opacAnimation->setEasingCurve(QEasingCurve::OutCubic); m_animation->posAnimation = nullptr; m_animation->animation = new QParallelAnimationGroup(this); m_animation->item = item; m_animation->slot = slot; m_animation->animation->addAnimation(m_animation->sizeAnimation); m_animation->animation->addAnimation(m_animation->opacAnimation); connect(m_animation->animation, &QAnimationGroup::finished, this, &WorksheetEntry::endAnimation); m_animation->animation->start(); } void WorksheetEntry::endAnimation() { if (!m_animation) return; QAnimationGroup* anim = m_animation->animation; if (anim->state() == QAbstractAnimation::Running) { anim->stop(); if (m_animation->sizeAnimation) setSize(m_animation->sizeAnimation->endValue().toSizeF()); if (m_animation->opacAnimation) { qreal opac = m_animation->opacAnimation->endValue().value(); m_animation->item->setOpacity(opac); } if (m_animation->posAnimation) { const QPointF& pos = m_animation->posAnimation->endValue().toPointF(); m_animation->item->setPos(pos); } // If the animation was connected to a slot, call it if (m_animation->slot) invokeSlotOnObject(m_animation->slot, m_animation->item); } m_animation->animation->deleteLater(); delete m_animation; m_animation = nullptr; } bool WorksheetEntry::animationActive() { return m_animation; } void WorksheetEntry::updateSizeAnimation(QSizeF size) { // Update the current animation, so that the new ending will be size if (!m_animation) return; if (m_aboutToBeRemoved) // do not modify the remove-animation return; if (m_animation->sizeAnimation) { QPropertyAnimation* sizeAn = m_animation->sizeAnimation; qreal progress = static_cast(sizeAn->currentTime()) / sizeAn->totalDuration(); QEasingCurve curve = sizeAn->easingCurve(); qreal value = curve.valueForProgress(progress); sizeAn->setEndValue(size); QSizeF newStart = 1/(1-value)*(sizeAn->currentValue().toSizeF() - value*size); sizeAn->setStartValue(newStart); } else { m_animation->sizeAnimation = sizeChangeAnimation(size); int d = m_animation->animation->duration() - m_animation->animation->currentTime(); m_animation->sizeAnimation->setDuration(d); m_animation->animation->addAnimation(m_animation->sizeAnimation); } } void WorksheetEntry::invokeSlotOnObject(const char* slot, QObject* obj) { const QMetaObject* metaObj = obj->metaObject(); const QByteArray normSlot = QMetaObject::normalizedSignature(slot); const int slotIndex = metaObj->indexOfSlot(normSlot.constData()); if (slotIndex == -1) qDebug() << "Warning: Tried to invoke an invalid slot:" << slot; const QMetaMethod method = metaObj->method(slotIndex); method.invoke(obj, Qt::DirectConnection); } bool WorksheetEntry::aboutToBeRemoved() { return m_aboutToBeRemoved; } void WorksheetEntry::startRemoving() { if (!worksheet()->animationsEnabled()) { m_aboutToBeRemoved = true; remove(); return; } if (m_aboutToBeRemoved) return; if (focusItem()) { if (!next()) { if (previous() && previous()->isEmpty() && !previous()->aboutToBeRemoved()) { previous()->focusEntry(); } else { WorksheetEntry* next = worksheet()->appendCommandEntry(); setNext(next); next->focusEntry(); } } else { next()->focusEntry(); } } if (m_animation) { endAnimation(); } m_aboutToBeRemoved = true; m_animation = new AnimationData; m_animation->sizeAnimation = new QPropertyAnimation(this, "size", this); m_animation->sizeAnimation->setDuration(300); m_animation->sizeAnimation->setEndValue(QSizeF(size().width(), 0)); m_animation->sizeAnimation->setEasingCurve(QEasingCurve::InOutQuad); connect(m_animation->sizeAnimation, &QPropertyAnimation::valueChanged, this, &WorksheetEntry::sizeAnimated); connect(m_animation->sizeAnimation, &QPropertyAnimation::finished, this, &WorksheetEntry::remove); m_animation->opacAnimation = new QPropertyAnimation(this, "opacity", this); m_animation->opacAnimation->setDuration(300); m_animation->opacAnimation->setEndValue(0); m_animation->opacAnimation->setEasingCurve(QEasingCurve::OutCubic); m_animation->posAnimation = nullptr; m_animation->animation = new QParallelAnimationGroup(this); m_animation->animation->addAnimation(m_animation->sizeAnimation); m_animation->animation->addAnimation(m_animation->opacAnimation); m_animation->animation->start(); } bool WorksheetEntry::stopRemoving() { if (!m_aboutToBeRemoved) return true; if (m_animation->animation->state() == QAbstractAnimation::Stopped) // we are too late to stop the deletion return false; m_aboutToBeRemoved = false; m_animation->animation->stop(); m_animation->animation->deleteLater(); delete m_animation; m_animation = nullptr; return true; } void WorksheetEntry::remove() { if (!m_aboutToBeRemoved) return; if (previous() && previous()->next() == this) previous()->setNext(next()); else worksheet()->setFirstEntry(next()); if (next() && next()->previous() == this) next()->setPrevious(previous()); else worksheet()->setLastEntry(previous()); // make the entry invisible to QGraphicsScene's itemAt() function hide(); worksheet()->updateLayout(); deleteLater(); } void WorksheetEntry::setSize(QSizeF size) { prepareGeometryChange(); if (m_actionBar && size != m_size) m_actionBar->updatePosition(); m_size = size; } QSizeF WorksheetEntry::size() { return m_size; } bool WorksheetEntry::hasActionBar() { return m_actionBar; } void WorksheetEntry::showActionBar() { if (m_actionBar && !m_actionBarAnimation) return; if (m_actionBarAnimation) { if (m_actionBarAnimation->endValue().toReal() == 1) return; m_actionBarAnimation->stop(); delete m_actionBarAnimation; m_actionBarAnimation = nullptr; } if (!m_actionBar) { m_actionBar = new ActionBar(this); m_actionBar->addButton(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Remove Entry"), this, SLOT(startRemoving())); WorksheetToolButton* dragButton; dragButton = m_actionBar->addButton(QIcon::fromTheme(QLatin1String("transform-move")), i18n("Drag Entry")); connect(dragButton, SIGNAL(pressed()), this, SLOT(startDrag())); if (wantToEvaluate()) { QString toolTip = i18n("Evaluate Entry"); m_actionBar->addButton(QIcon::fromTheme(QLatin1String("media-playback-start")), toolTip, this, SLOT(evaluate())); } m_actionBar->addSpace(); addActionsToBar(m_actionBar); } if (worksheet()->animationsEnabled()) { m_actionBarAnimation = new QPropertyAnimation(m_actionBar, "opacity", this); m_actionBarAnimation->setStartValue(0); m_actionBarAnimation->setKeyValueAt(0.666, 0); m_actionBarAnimation->setEndValue(1); m_actionBarAnimation->setDuration(600); connect(m_actionBarAnimation, &QPropertyAnimation::finished, this, &WorksheetEntry::deleteActionBarAnimation); m_actionBarAnimation->start(); } } void WorksheetEntry::hideActionBar() { if (!m_actionBar) return; if (m_actionBarAnimation) { if (m_actionBarAnimation->endValue().toReal() == 0) return; m_actionBarAnimation->stop(); delete m_actionBarAnimation; m_actionBarAnimation = nullptr; } if (worksheet()->animationsEnabled()) { m_actionBarAnimation = new QPropertyAnimation(m_actionBar, "opacity", this); m_actionBarAnimation->setEndValue(0); m_actionBarAnimation->setEasingCurve(QEasingCurve::Linear); m_actionBarAnimation->setDuration(200); connect(m_actionBarAnimation, &QPropertyAnimation::finished, this, &WorksheetEntry::deleteActionBar); m_actionBarAnimation->start(); } else { deleteActionBar(); } } void WorksheetEntry::deleteActionBarAnimation() { if (m_actionBarAnimation) { delete m_actionBarAnimation; m_actionBarAnimation = nullptr; } } void WorksheetEntry::deleteActionBar() { if (m_actionBar) { delete m_actionBar; m_actionBar = nullptr; } deleteActionBarAnimation(); } void WorksheetEntry::addActionsToBar(ActionBar*) { } void WorksheetEntry::hoverEnterEvent(QGraphicsSceneHoverEvent* event) { Q_UNUSED(event); showActionBar(); } void WorksheetEntry::hoverLeaveEvent(QGraphicsSceneHoverEvent* event) { Q_UNUSED(event); hideActionBar(); } WorksheetTextItem* WorksheetEntry::highlightItem() { return nullptr; } bool WorksheetEntry::wantFocus() { return true; }