diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,8 @@ set(WITH_EPS Off) endif(NOT WIN32) +find_package(Discount) + add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) if (CMAKE_BUILD_TYPE STREQUAL "RELEASE") add_definitions(-DQT_NO_DEBUG_OUTPUT) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -62,6 +62,7 @@ worksheetimageitem.cpp commandentry.cpp textentry.cpp + markdownentry.cpp pagebreakentry.cpp imageentry.cpp latexentry.cpp @@ -98,11 +99,14 @@ target_link_libraries(cantorpart KF5::Parts KF5::NewStuff KF5::TextEditor ${Qt5XmlPatterns_LIBRARIES} - KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets - Qt5::PrintSupport cantorlibs cantor_config ) + KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets + Qt5::PrintSupport cantorlibs cantor_config) if(LIBSPECTRE_FOUND) - target_link_libraries(cantorpart ${LIBSPECTRE_LIBRARY}) + target_link_libraries(cantorpart ${LIBSPECTRE_LIBRARY}) endif(LIBSPECTRE_FOUND) +if(discount_FOUND) + target_link_libraries(cantorpart ${discount_LIBRARIES}) +endif(discount_FOUND) install( FILES cantor_part.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/cantor ) install( FILES cantor_scripteditor.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/cantor ) diff --git a/src/cantor_part.cpp b/src/cantor_part.cpp --- a/src/cantor_part.cpp +++ b/src/cantor_part.cpp @@ -286,6 +286,10 @@ actionCollection()->addAction(QLatin1String("insert_text_entry"), insertTextEntry); connect(insertTextEntry, SIGNAL(triggered()), m_worksheet, SLOT(insertTextEntry())); + QAction * insertMarkdownEntry=new QAction(i18n("Insert Markdown Entry"), actionCollection()); + actionCollection()->addAction(QLatin1String("insert_markdown_entry"), insertMarkdownEntry); + connect(insertMarkdownEntry, SIGNAL(triggered()), m_worksheet, SLOT(insertMarkdownEntry())); + QAction * insertLatexEntry=new QAction(i18n("Insert Latex Entry"), actionCollection()); actionCollection()->addAction(QLatin1String("insert_latex_entry"), insertLatexEntry); connect(insertLatexEntry, SIGNAL(triggered()), m_worksheet, SLOT(insertLatexEntry())); diff --git a/src/cantor_part.rc b/src/cantor_part.rc --- a/src/cantor_part.rc +++ b/src/cantor_part.rc @@ -34,6 +34,7 @@ + diff --git a/src/config-cantor.h.cmake b/src/config-cantor.h.cmake --- a/src/config-cantor.h.cmake +++ b/src/config-cantor.h.cmake @@ -4,4 +4,6 @@ #cmakedefine LIBSPECTRE_FOUND 1 +#cmakedefine discount_FOUND 1 + #define PATH_TO_CANTOR_PLUGINS "${PATH_TO_CANTOR_BACKENDS}" diff --git a/src/markdownentry.h b/src/markdownentry.h new file mode 100644 --- /dev/null +++ b/src/markdownentry.h @@ -0,0 +1,56 @@ +/* + 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) 2018 Yifei Wu + */ + +#ifndef MARKDOWNENTRY_H +#define MARKDOWNENTRY_H + +#include "textentry.h" +#include "worksheettextitem.h" + +#include + +class MarkdownEntry : public TextEntry +{ + Q_OBJECT + public: + MarkdownEntry(Worksheet* worksheet); + ~MarkdownEntry() override; + + enum {Type = UserType + 6}; + + void setContent(const QString& content) Q_DECL_OVERRIDE; + void setContent(const QDomElement& content, const KZip& file) Q_DECL_OVERRIDE; + + QDomElement toXml(QDomDocument& doc, KZip* archive) Q_DECL_OVERRIDE; + + public Q_SLOTS: + bool evaluate(WorksheetEntry::EvaluationOption evalOp = FocusNext) Q_DECL_OVERRIDE; + + protected: + bool eventFilter(QObject* object, QEvent* event) Q_DECL_OVERRIDE; + + protected: + QString plain; + QString html; + bool dirty; + bool evalJustNow; +}; + +#endif //MARKDOWNENTRY_H diff --git a/src/markdownentry.cpp b/src/markdownentry.cpp new file mode 100644 --- /dev/null +++ b/src/markdownentry.cpp @@ -0,0 +1,138 @@ +/* + 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) 2018 Yifei Wu + */ + +#include "markdownentry.h" + +#include "config-cantor.h" + +#ifdef discount_FOUND +extern "C" { +#include +} +#endif + +#include + +MarkdownEntry::MarkdownEntry(Worksheet* worksheet) : TextEntry(worksheet), dirty(false), evalJustNow(false) +{ + m_textItem->installEventFilter(this); +} + +MarkdownEntry::~MarkdownEntry() +{ +} + +void MarkdownEntry::setContent(const QString& content) +{ + dirty = true; + plain = content; + TextEntry::setContent(content); +} + +void MarkdownEntry::setContent(const QDomElement& content, const KZip& file) +{ + Q_UNUSED(file); + + dirty = true; + plain = content.text(); + m_textItem->setPlainText(plain); + qDebug() << plain; +} + +QDomElement MarkdownEntry::toXml(QDomDocument& doc, KZip* archive) +{ + Q_UNUSED(archive); + + qDebug() << plain; + QDomElement el = doc.createElement(QLatin1String("Markdown")); + QDomText text=doc.createTextNode(plain); + el.appendChild(text); + return el; +} + +bool MarkdownEntry::evaluate(EvaluationOption evalOp) +{ +#ifdef discount_FOUND + if(m_textItem->hasFocus()) // text in the entry may be edited + plain = m_textItem->toPlainText(); + + /* + QString tempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation); + QTemporaryFile* markdownQFile = new QTemporaryFile(tempDir + QLatin1String("/cantor_md-XXXXXX.md")); + markdownQFile->open(QIODevice::ReadOnly); + FILE* mdFile = fdopen(markdownQFile->handle(), "rb"); + if(!mdFile) + { + qDebug()<<"Failed to open the markdown temporary file"; + return TextEntry::evaluate(evalOp); + } + */ + + // convert markdown to html + QByteArray mdCharArray = plain.toUtf8(); + MMIOT* mdHandle = mkd_string(mdCharArray.data(), mdCharArray.size()+1, 0); // get the size of the string in byte + if(!mkd_compile(mdHandle, MKD_NOSUPERSCRIPT | MKD_FENCEDCODE | MKD_GITHUBTAGS)) + { + qDebug()<<"Failed to compile the markdown document"; + return TextEntry::evaluate(evalOp); + } + char *htmlDocument; + int htmlSize = mkd_document(mdHandle, &htmlDocument); + html = QString::fromUtf8(htmlDocument, htmlSize); + + m_textItem->setHtml(html); + dirty = false; + evalJustNow = true; +#endif + return TextEntry::evaluate(evalOp); +} + +bool MarkdownEntry::eventFilter(QObject* object, QEvent* event) +{ + if(object == m_textItem) + { + if(event->type() == QEvent::FocusIn) + { + QString plainHtml = QLatin1String("

") + plain + QLatin1String("

"); // clear the style, such as font + plainHtml.replace(QLatin1String("\n"), QLatin1String("
")); + m_textItem->setHtml(plainHtml); + } + else if(event->type() == QEvent::FocusOut) + { + if(evalJustNow) + { + evalJustNow = false; + return false; + } + + if(!dirty && plain.compare(m_textItem->toPlainText()) == 0) + { + m_textItem->setHtml(html); + TextEntry::evaluate(); + } + else + { + dirty = true; + plain = m_textItem->toPlainText(); + } + } + } + return false; +} diff --git a/src/textentry.h b/src/textentry.h --- a/src/textentry.h +++ b/src/textentry.h @@ -78,12 +78,10 @@ protected: bool wantToEvaluate() Q_DECL_OVERRIDE; - - private: QTextCursor findLatexCode(const QTextCursor& cursor = QTextCursor()) const; QString showLatexCode(QTextCursor& cursor); - private: + protected: WorksheetTextItem* m_textItem; }; diff --git a/src/worksheet.h b/src/worksheet.h --- a/src/worksheet.h +++ b/src/worksheet.h @@ -116,17 +116,20 @@ WorksheetEntry* appendCommandEntry(); void appendCommandEntry(const QString& text); WorksheetEntry* appendTextEntry(); + WorksheetEntry* appendMarkdownEntry(); WorksheetEntry* appendImageEntry(); WorksheetEntry* appendPageBreakEntry(); WorksheetEntry* appendLatexEntry(); WorksheetEntry* insertCommandEntry(WorksheetEntry* current = nullptr); void insertCommandEntry(const QString& text); WorksheetEntry* insertTextEntry(WorksheetEntry* current = nullptr); + WorksheetEntry* insertMarkdownEntry(WorksheetEntry* current = nullptr); WorksheetEntry* insertImageEntry(WorksheetEntry* current = nullptr); WorksheetEntry* insertPageBreakEntry(WorksheetEntry* current = nullptr); WorksheetEntry* insertLatexEntry(WorksheetEntry* current = nullptr); WorksheetEntry* insertCommandEntryBefore(WorksheetEntry* current = nullptr); WorksheetEntry* insertTextEntryBefore(WorksheetEntry* current = nullptr); + WorksheetEntry* insertMarkdownEntryBefore(WorksheetEntry* current = nullptr); WorksheetEntry* insertImageEntryBefore(WorksheetEntry* current = nullptr); WorksheetEntry* insertPageBreakEntryBefore(WorksheetEntry* current = nullptr); WorksheetEntry* insertLatexEntryBefore(WorksheetEntry* current = nullptr); diff --git a/src/worksheet.cpp b/src/worksheet.cpp --- a/src/worksheet.cpp +++ b/src/worksheet.cpp @@ -37,6 +37,7 @@ #include "settings.h" #include "commandentry.h" #include "textentry.h" +#include "markdownentry.h" #include "latexentry.h" #include "imageentry.h" #include "pagebreakentry.h" @@ -544,6 +545,10 @@ return appendEntry(TextEntry::Type); } +WorksheetEntry* Worksheet::appendMarkdownEntry() +{ + return appendEntry(MarkdownEntry::Type); +} WorksheetEntry* Worksheet::appendPageBreakEntry() { @@ -612,6 +617,11 @@ return insertEntry(TextEntry::Type, current); } +WorksheetEntry* Worksheet::insertMarkdownEntry(WorksheetEntry* current) +{ + return insertEntry(MarkdownEntry::Type, current); +} + WorksheetEntry* Worksheet::insertCommandEntry(WorksheetEntry* current) { return insertEntry(CommandEntry::Type, current); @@ -675,6 +685,11 @@ return insertEntryBefore(TextEntry::Type, current); } +WorksheetEntry* Worksheet::insertMarkdownEntryBefore(WorksheetEntry* current) +{ + return insertEntryBefore(MarkdownEntry::Type, current); +} + WorksheetEntry* Worksheet::insertCommandEntryBefore(WorksheetEntry* current) { return insertEntryBefore(CommandEntry::Type, current); @@ -1073,6 +1088,10 @@ { entry = appendTextEntry(); entry->setContent(expressionChild, file); + } else if (tag == QLatin1String("Markdown")) + { + entry = appendMarkdownEntry(); + entry->setContent(expressionChild, file); } else if (tag == QLatin1String("Latex")) { entry = appendLatexEntry(); @@ -1170,12 +1189,14 @@ insert->addAction(i18n("Command Entry"), entry, SLOT(insertCommandEntry())); insert->addAction(i18n("Text Entry"), entry, SLOT(insertTextEntry())); + insert->addAction(i18n("Markdown Entry"), entry, SLOT(insertMarkdownEntry())); insert->addAction(i18n("LaTeX Entry"), entry, SLOT(insertLatexEntry())); insert->addAction(i18n("Image"), entry, SLOT(insertImageEntry())); insert->addAction(i18n("Page Break"), entry, SLOT(insertPageBreakEntry())); insertBefore->addAction(i18n("Command Entry"), entry, SLOT(insertCommandEntryBefore())); insertBefore->addAction(i18n("Text Entry"), entry, SLOT(insertTextEntryBefore())); + insertBefore->addAction(i18n("Markdown Entry"), entry, SLOT(insertMarkdownEntryBefore())); insertBefore->addAction(i18n("LaTeX Entry"), entry, SLOT(insertLatexEntryBefore())); insertBefore->addAction(i18n("Image"), entry, SLOT(insertImageEntryBefore())); insertBefore->addAction(i18n("Page Break"), entry, SLOT(insertPageBreakEntryBefore())); @@ -1187,6 +1208,7 @@ } else { menu->addAction(i18n("Insert Command Entry"), this, SLOT(appendCommandEntry())); menu->addAction(i18n("Insert Text Entry"), this, SLOT(appendTextEntry())); + menu->addAction(i18n("Insert Markdown Entry"), this, SLOT(appendMarkdownEntry())); menu->addAction(i18n("Insert LaTeX Entry"), this, SLOT(appendLatexEntry())); menu->addAction(i18n("Insert Image"), this, SLOT(appendImageEntry())); menu->addAction(i18n("Insert Page Break"), this, SLOT(appendPageBreakEntry())); diff --git a/src/worksheetentry.h b/src/worksheetentry.h --- a/src/worksheetentry.h +++ b/src/worksheetentry.h @@ -29,6 +29,7 @@ #include "worksheetcursor.h" class TextEntry; +class MarkdownEntry; class CommandEntry; class ImageEntry; class PageBreakEntry; @@ -112,11 +113,13 @@ void insertCommandEntry(); void insertTextEntry(); + void insertMarkdownEntry(); void insertLatexEntry(); void insertImageEntry(); void insertPageBreakEntry(); void insertCommandEntryBefore(); void insertTextEntryBefore(); + void insertMarkdownEntryBefore(); void insertLatexEntryBefore(); void insertImageEntryBefore(); void insertPageBreakEntryBefore(); diff --git a/src/worksheetentry.cpp b/src/worksheetentry.cpp --- a/src/worksheetentry.cpp +++ b/src/worksheetentry.cpp @@ -21,6 +21,7 @@ #include "worksheetentry.h" #include "commandentry.h" #include "textentry.h" +#include "markdownentry.h" #include "latexentry.h" #include "imageentry.h" #include "pagebreakentry.h" @@ -88,6 +89,8 @@ { case TextEntry::Type: return new TextEntry(worksheet); + case MarkdownEntry::Type: + return new MarkdownEntry(worksheet); case CommandEntry::Type: return new CommandEntry(worksheet); case ImageEntry::Type: @@ -111,6 +114,11 @@ worksheet()->insertTextEntry(this); } +void WorksheetEntry::insertMarkdownEntry() +{ + worksheet()->insertMarkdownEntry(this); +} + void WorksheetEntry::insertLatexEntry() { worksheet()->insertLatexEntry(this); @@ -136,6 +144,11 @@ worksheet()->insertTextEntryBefore(this); } +void WorksheetEntry::insertMarkdownEntryBefore() +{ + worksheet()->insertMarkdownEntryBefore(this); +} + void WorksheetEntry::insertLatexEntryBefore() { worksheet()->insertLatexEntryBefore(this);