diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,12 @@ set(WITH_EPS Off) endif(NOT WIN32) +find_package(Discount) +set_package_properties(Discount PROPERTIES DESCRIPTION "A C implementation of the Markdown markup language" + URL "https://www.pell.portland.or.us/~orc/Code/discount/" + TYPE OPTIONAL + PURPOSE "Used for Markdown entries in Cantor") + 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/cmake/FindDiscount.cmake b/cmake/FindDiscount.cmake new file mode 100644 --- /dev/null +++ b/cmake/FindDiscount.cmake @@ -0,0 +1,41 @@ +# - Find Discount +# Find the Discount markdown library. +# +# This module defines +# Discount_FOUND - whether the Discount library was found +# Discount_LIBRARIES - the Discount library +# Discount_INCLUDE_DIR - the include path of the Discount library + +# Copyright (c) 2017, Julian Wolff, +# Copyright (c) 2018, Sune Vuorela, +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +if (Discount_INCLUDE_DIR AND Discount_LIBRARIES) + + # Already in cache + set (Discount_FOUND TRUE) + +else (Discount_INCLUDE_DIR AND Discount_LIBRARIES) + + find_library (Discount_LIBRARIES + NAMES markdown libmarkdown + ) + + find_path (Discount_INCLUDE_DIR + NAMES mkdio.h + ) + + include (FindPackageHandleStandardArgs) + find_package_handle_standard_args (Discount DEFAULT_MSG Discount_LIBRARIES Discount_INCLUDE_DIR) + +endif (Discount_INCLUDE_DIR AND Discount_LIBRARIES) + +mark_as_advanced(Discount_INCLUDE_DIR Discount_LIBRARIES) + +if (Discount_FOUND) + add_library(Discount::Lib UNKNOWN IMPORTED) + set_target_properties(Discount::Lib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${Discount_INCLUDE_DIR} IMPORTED_LOCATION ${Discount_LIBRARIES}) +endif() 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,126 @@ +/* + 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(); + + // 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(EvaluationOption::DoNothing); + } + 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);