diff --git a/src/cantor_part.h b/src/cantor_part.h --- a/src/cantor_part.h +++ b/src/cantor_part.h @@ -22,6 +22,7 @@ #define CANTORPART_H #include +#include #include #include @@ -103,6 +104,8 @@ void loadAssistants(); void adjustGuiToSession(); + void setReadOnly(); + protected Q_SLOTS: void fileSaveAs(); void fileSavePlain(); @@ -171,6 +174,7 @@ KToggleAction* m_exprNumbering; KToggleAction* m_animateWorksheet; QAction * m_showBackendHelp; + QVector m_editActions; QString m_cachedStatusMessage; bool m_statusBarBlocked; diff --git a/src/cantor_part.cpp b/src/cantor_part.cpp --- a/src/cantor_part.cpp +++ b/src/cantor_part.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -142,6 +143,15 @@ return; } + if (b && !b->isEnabled() && backendName != QLatin1String("null")) + { + KMessageBox::information(parentWidget, i18n("There are some problems with the %1 backend,\n"\ + "please check your configuration or install the needed packages.\n" + "You will only be able to view this worksheet.", backendName), i18n("Cantor")); + setWidget(new QWidget(parentWidget)); + return; + } + qDebug()<<"Backend "<name()<<" offers extensions: "<extensions(); @@ -179,28 +189,33 @@ QAction* undo = KStandardAction::undo(m_worksheet, SIGNAL(undo()), collection); undo->setPriority(QAction::LowPriority); connect(m_worksheet, SIGNAL(undoAvailable(bool)), undo, SLOT(setEnabled(bool))); + m_editActions.push_back(undo); QAction* redo = KStandardAction::redo(m_worksheet, SIGNAL(redo()), collection); redo->setPriority(QAction::LowPriority); connect(m_worksheet, SIGNAL(redoAvailable(bool)), redo, SLOT(setEnabled(bool))); + m_editActions.push_back(redo); QAction* cut = KStandardAction::cut(m_worksheet, SIGNAL(cut()), collection); cut->setPriority(QAction::LowPriority); connect(m_worksheet, SIGNAL(cutAvailable(bool)), cut, SLOT(setEnabled(bool))); + m_editActions.push_back(cut); 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); + QAction* paste = KStandardAction::paste(m_worksheet, SIGNAL(paste()), collection); paste->setPriority(QAction::LowPriority); connect(m_worksheet, SIGNAL(pasteAvailable(bool)), paste, SLOT(setEnabled(bool))); + m_editActions.push_back(paste); 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_editActions.push_back(replace); m_findNext = KStandardAction::findNext(this, SLOT(findNext()), collection); m_findNext->setEnabled(false); @@ -228,6 +243,7 @@ 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_editActions.push_back(m_evaluate); m_typeset = new KToggleAction(i18n("Typeset using LaTeX"), collection); m_typeset->setChecked(Settings::self()->typesetDefault()); @@ -260,45 +276,54 @@ collection->addAction(QLatin1String("restart_backend"), restart); restart->setIcon(QIcon::fromTheme(QLatin1String("system-reboot"))); connect(restart, SIGNAL(triggered()), this, SLOT(restartBackend())); + m_editActions.push_back(restart); 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())); + m_editActions.push_back(evaluateCurrent); 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())); + m_editActions.push_back(insertCommandEntry); 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())); + m_editActions.push_back(insertTextEntry); #ifdef Discount_FOUND 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())); + m_editActions.push_back(insertMarkdownEntry); #endif #ifdef WITH_EPS 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())); + m_editActions.push_back(insertLatexEntry); #endif 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())); + m_editActions.push_back(insertPageBreakEntry); 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())); + m_editActions.push_back(insertImageEntry); 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_editActions.push_back(removeCurrent); m_showBackendHelp = new QAction(i18n("Show %1 Help", b->name()) , collection); m_showBackendHelp->setIcon(QIcon::fromTheme(QLatin1String("help-contents"))); @@ -327,6 +352,7 @@ showCompletionShortcuts << Qt::Key_Tab << Qt::CTRL + Qt::Key_Space; collection->setDefaultShortcuts(showCompletion, showCompletionShortcuts); connect(showCompletion, SIGNAL(triggered()), m_worksheet, SLOT(showCompletion())); + m_editActions.push_back(showCompletion); // set our XML-UI resource file setXMLFile(QLatin1String("cantor_part.rc")); @@ -359,6 +385,18 @@ ReadWritePart::setReadWrite(rw); } +void CantorPart::setReadOnly() +{ + for (QAction* action : m_editActions) + action->setEnabled(false); + + if (m_showBackendHelp) + { + m_showBackendHelp->setEnabled(false); + m_showBackendHelp->setVisible(false); + } +} + void CantorPart::setModified(bool modified) { // get a handle on our Save action and make sure it is valid @@ -436,12 +474,15 @@ 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"))) + if (!m_worksheet->isReadOnly()) { - Cantor::ScriptExtension* e=dynamic_cast(backend->extension(QLatin1String("ScriptExtension"))); - filter+=QLatin1String(";;")+e->scriptFileFilter(); + //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; @@ -578,17 +619,35 @@ void CantorPart::initialized() { - connect(m_worksheet->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))); + if (!m_worksheet->isReadOnly()) + { + connect(m_worksheet->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(); + loadAssistants(); + m_panelHandler->setSession(m_worksheet->session()); + adjustGuiToSession(); - if (m_worksheet->isEmpty()) - m_worksheet->appendCommandEntry(); + if (m_worksheet->isEmpty()) + m_worksheet->appendCommandEntry(); + } + else + { + setReadOnly(); + // Clear assistants + for (KXMLGUIClient* client: childClients()) + { + Cantor::Assistant* assistant = dynamic_cast(client); + if (assistant) + { + factory()->removeClient(client); + removeChildClient(client); + assistant->deleteLater(); + } + } + } m_worksheetview->setEnabled(true); m_worksheetview->setFocus(); @@ -638,7 +697,10 @@ if (filename.isEmpty()) filename=i18n("Unnamed"); - emit setCaption(filename, QIcon::fromTheme(m_worksheet->session()->backend()->icon())); + if (!m_worksheet->isReadOnly()) + emit setCaption(filename, QIcon::fromTheme(m_worksheet->session()->backend()->icon())); + else + emit setCaption(filename+QLatin1Char(' ')+i18n("[read-only]"), QIcon()); } void CantorPart::pluginsChanged() diff --git a/src/lib/expression.cpp b/src/lib/expression.cpp --- a/src/lib/expression.cpp +++ b/src/lib/expression.cpp @@ -76,7 +76,7 @@ { d->session=session; d->internal = internal; - if (!internal) + if (!internal && session) d->id=session->nextExpressionId(); else d->id = -1; @@ -131,7 +131,8 @@ qDebug()<<"setting result to a type "<type()<<" result"; #ifdef WITH_EPS //If it's text, and latex typesetting is enabled, render it - if ( session()->isTypesettingEnabled()&& + if ( session() && + session()->isTypesettingEnabled()&& result->type()==TextResult::Type && dynamic_cast(result)->format()==TextResult::LatexFormat && !result->toHtml().trimmed().isEmpty() && diff --git a/src/worksheet.h b/src/worksheet.h --- a/src/worksheet.h +++ b/src/worksheet.h @@ -63,6 +63,7 @@ Cantor::Session* session(); bool isRunning(); + bool isReadOnly(); bool showExpressionIds(); bool animationsEnabled(); @@ -292,6 +293,9 @@ bool m_loginDone; bool m_isPrinting; bool m_isLoadingFromFile; + bool m_readOnly; + + QString m_backendName; }; #endif // WORKSHEET_H diff --git a/src/worksheet.cpp b/src/worksheet.cpp --- a/src/worksheet.cpp +++ b/src/worksheet.cpp @@ -88,6 +88,7 @@ m_isPrinting = false; m_loginDone = false; + m_readOnly = false; m_isLoadingFromFile = false; enableHighlighting(Settings::self()->highlightDefault()); @@ -425,6 +426,9 @@ void Worksheet::startDrag(WorksheetEntry* entry, QDrag* drag) { + if (m_readOnly) + return; + resetEntryCursor(); m_dragEntry = entry; WorksheetEntry* prev = entry->previous(); @@ -478,7 +482,7 @@ void Worksheet::evaluate() { qDebug()<<"evaluate worksheet"; - if (!m_loginDone) + if (!m_loginDone && !m_readOnly) loginToSession(); firstEntry()->evaluate(WorksheetEntry::EvaluateNext); @@ -488,7 +492,7 @@ void Worksheet::evaluateCurrentEntry() { - if (!m_loginDone) + if (!m_loginDone && !m_readOnly) loginToSession(); WorksheetEntry* entry = currentEntry(); @@ -523,7 +527,10 @@ setLastEntry(entry); updateLayout(); makeVisible(entry); - focusEntry(entry); + if (m_readOnly) + entry->setAcceptHoverEvents(false); + else + focusEntry(entry); } return entry; } @@ -803,7 +810,11 @@ if(m_highlighter) m_highlighter->deleteLater(); - m_highlighter=session()->syntaxHighlighter(this); + if (!m_readOnly) + m_highlighter=session()->syntaxHighlighter(this); + else + m_highlighter=nullptr; + if(!m_highlighter) m_highlighter=new Cantor::DefaultHighlighter(this); @@ -831,7 +842,12 @@ bool Worksheet::isRunning() { - return m_session->status()==Cantor::Session::Running; + return m_session && m_session->status()==Cantor::Session::Running; +} + +bool Worksheet::isReadOnly() +{ + return m_readOnly; } bool Worksheet::showExpressionIds() @@ -859,7 +875,7 @@ { QDomDocument doc( QLatin1String("CantorWorksheet") ); QDomElement root=doc.createElement( QLatin1String("Worksheet") ); - root.setAttribute(QLatin1String("backend"), m_session->backend()->name()); + root.setAttribute(QLatin1String("backend"), (m_session ? m_session->backend()->name(): m_backendName)); doc.appendChild(root); for( WorksheetEntry* entry = firstEntry(); entry; entry = entry->next()) @@ -927,14 +943,19 @@ QString commentStartingSeq = QLatin1String(""); QString commentEndingSeq = QLatin1String(""); - Cantor::Backend * const backend=session()->backend(); - if (backend->extensions().contains(QLatin1String("ScriptExtension"))) + if (!m_readOnly) { - Cantor::ScriptExtension* e=dynamic_cast(backend->extension(QLatin1String(("ScriptExtension")))); - cmdSep=e->commandSeparator(); - commentStartingSeq = e->commentStartingSequence(); - commentEndingSeq = e->commentEndingSequence(); + Cantor::Backend * const backend=session()->backend(); + if (backend->extensions().contains(QLatin1String("ScriptExtension"))) + { + Cantor::ScriptExtension* e=dynamic_cast(backend->extension(QLatin1String(("ScriptExtension")))); + cmdSep=e->commandSeparator(); + commentStartingSeq = e->commentStartingSequence(); + commentEndingSeq = e->commentEndingSequence(); + } } + else + KMessageBox::information(worksheetView(), i18n("In read-only mode Cantor couldn't guarantee, that the export will be valid for %1", m_backendName), i18n("Cantor")); QTextStream stream(&file); @@ -990,7 +1011,7 @@ } bool rc = load(&file); - if (rc) + if (rc && !m_readOnly) m_session->setWorksheetPath(filename); return rc; @@ -1031,22 +1052,31 @@ QDomElement root=doc.documentElement(); // qDebug()<isEnabled()) + if(!m_readOnly && !b->isEnabled()) { QApplication::restoreOverrideCursor(); KMessageBox::information(worksheetView(), i18n("There are some problems with the %1 backend,\n"\ "please check your configuration or install the needed packages.\n" - "You will only be able to view this worksheet.", backendName), i18n("Cantor")); + "You will only be able to view this worksheet.", m_backendName), i18n("Cantor")); + m_readOnly = true; + } + if (m_readOnly) + { + // TODO: Handle this here? + for (QAction* action : m_richTextActionList) + action->setEnabled(false); } m_isLoadingFromFile = true; @@ -1065,7 +1095,8 @@ resetEntryCursor(); - m_session=b->createSession(); + if (!m_readOnly) + m_session=b->createSession(); qDebug()<<"loading entries"; QDomElement expressionChild = root.firstChildElement(); @@ -1230,6 +1261,9 @@ void Worksheet::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { + if (m_readOnly) + return; + // forward the event to the items QGraphicsScene::contextMenuEvent(event); @@ -1250,12 +1284,15 @@ event->scenePos().y() > lastEntry()->y() + lastEntry()->size().height()) lastEntry()->focusEntry(WorksheetTextItem::BottomRight); */ - - updateEntryCursor(event); + if (!m_readOnly) + updateEntryCursor(event); } void Worksheet::keyPressEvent(QKeyEvent *keyEvent) { + if (m_readOnly) + return; + // If we choose entry by entry cursor and press text button (not modifiers, for example, like Control) if ((m_choosenCursorEntry || m_isCursorEntryAfterLastEntry) && !keyEvent->text().isEmpty()) addEntryFromEntryCursor(); @@ -1457,6 +1494,27 @@ void Worksheet::updateFocusedTextItem(WorksheetTextItem* newItem) { + // No need update and emit signals about editing actions in readonly + // So support only copy action and reset selection + if (m_readOnly) + { + if (m_lastFocusedTextItem && m_lastFocusedTextItem != newItem) + { + disconnect(this, SIGNAL(copy()), m_lastFocusedTextItem, SLOT(copy())); + emit copyAvailable(newItem->isCopyAvailable()); + m_lastFocusedTextItem->clearSelection(); + } + + if (newItem && m_lastFocusedTextItem != newItem) + { + connect(this, SIGNAL(copy()), newItem, SLOT(copy())); + emit copyAvailable(newItem->isCopyAvailable()); + } + + m_lastFocusedTextItem = newItem; + return; + } + if (m_lastFocusedTextItem && m_lastFocusedTextItem != newItem) { disconnect(m_lastFocusedTextItem, SIGNAL(undoAvailable(bool)), this, SIGNAL(undoAvailable(bool))); @@ -1542,8 +1600,9 @@ void Worksheet::setAcceptRichText(bool b) { - for (auto* action : m_richTextActionList) - action->setEnabled(b); + if (!m_readOnly) + for(QAction * action : m_richTextActionList) + action->setEnabled(b); } WorksheetTextItem* Worksheet::currentTextItem()