diff --git a/cmake/modules/FindDiscount.cmake b/cmake/modules/FindDiscount.cmake new file mode 100644 --- /dev/null +++ b/cmake/modules/FindDiscount.cmake @@ -0,0 +1,36 @@ +# - 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, +# +# 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) + diff --git a/generators/CMakeLists.txt b/generators/CMakeLists.txt --- a/generators/CMakeLists.txt +++ b/generators/CMakeLists.txt @@ -88,6 +88,13 @@ URL "https://commits.kde.org/kdegraphics-mobipocket" TYPE RECOMMENDED PURPOSE "Support for Mobipocket documents in Okular.") + +find_package(Discount "2") +set_package_properties("discount" PROPERTIES + DESCRIPTION "A library that gives you formatting functions suitable for marking down entire documents or lines of text" + URL "http://www.pell.portland.or.us/~orc/Code/discount/" + TYPE RECOMMENDED + PURPOSE "Support for Markdown documents in Okular.") # let's enable the generators properly configured @@ -140,3 +147,7 @@ if(QMobipocket_FOUND) add_subdirectory(mobipocket) endif() + +if(discount_FOUND) + add_subdirectory(markdown) +endif() diff --git a/generators/markdown/CMakeLists.txt b/generators/markdown/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/generators/markdown/CMakeLists.txt @@ -0,0 +1,22 @@ +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/../.. +) + + +########### next target ############### + +set(okularGenerator_md_PART_SRCS + converter.cpp + generator_md.cpp +) + + +okular_add_generator(okularGenerator_md ${okularGenerator_md_PART_SRCS}) + +target_link_libraries(okularGenerator_md okularcore KF5::I18n KF5::KIOCore ${discount_LIBRARIES}) + +########### install files ############### +install( FILES okularMd.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) +install( PROGRAMS okularApplication_md.desktop org.kde.mobile.okular_md.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) +install( FILES org.kde.okular-md.metainfo.xml DESTINATION ${KDE_INSTALL_METAINFODIR} ) + diff --git a/generators/markdown/Messages.sh b/generators/markdown/Messages.sh new file mode 100644 --- /dev/null +++ b/generators/markdown/Messages.sh @@ -0,0 +1,2 @@ +#!/bin/sh +$XGETTEXT $(find . -name "*.cpp" -o -name "*.h") -o $podir/okular_markdown.pot diff --git a/generators/markdown/converter.h b/generators/markdown/converter.h new file mode 100644 --- /dev/null +++ b/generators/markdown/converter.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2017 by Julian Wolff * + * * + * 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. * + ***************************************************************************/ + +#ifndef MARKDOWN_CONVERTER_H +#define MARKDOWN_CONVERTER_H + +#include + +#include + +class QTextCursor; +class QTextFrame; + +namespace Markdown { + +class Converter : public Okular::TextDocumentConverter +{ + Q_OBJECT + + public: + Converter(); + ~Converter(); + + QTextDocument *convert( const QString &fileName ) override; + + private: + void convertLinks(); + void convertImages(); + + void convertLinks(QTextFrame *parent); + void convertLinks(QTextBlock& parent); + void convertImages(QTextFrame *parent); + void convertImages(QTextBlock& parent); + + QTextDocument *mTextDocument; + QDir mDir; +}; + +} + +#endif diff --git a/generators/markdown/converter.cpp b/generators/markdown/converter.cpp new file mode 100644 --- /dev/null +++ b/generators/markdown/converter.cpp @@ -0,0 +1,177 @@ +/*************************************************************************** + * Copyright (C) 2017 by Julian Wolff * + * * + * 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. * + ***************************************************************************/ + +#include "converter.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include "debug_md.h" + +extern "C" { +#include +} + +// older versions of discount might not have these flags. +// defining them to 0 allows us to convert without them +#ifndef MKD_FENCEDCODE +#define MKD_FENCEDCODE 0 +#endif + +#ifndef MKD_GITHUBTAGS +#define MKD_GITHUBTAGS 0 +#endif + +#ifndef MKD_AUTOLINK +#define MKD_AUTOLINK 0 +#endif + +using namespace Markdown; + +Converter::Converter() +: mTextDocument(nullptr) +{ +} + +Converter::~Converter() +{ +} + +QTextDocument* Converter::convert( const QString &fileName ) +{ + FILE *markdownFile = fopen( fileName.toLocal8Bit(), "rb" ); + mDir = QDir( fileName.left( fileName.lastIndexOf( '/' ) ) ); + + MMIOT *markdownHandle = mkd_in( markdownFile, 0 ); + + if ( !mkd_compile( markdownHandle, MKD_FENCEDCODE | MKD_GITHUBTAGS | MKD_AUTOLINK ) ) { + emit error( i18n( "Failed to compile markdown document!" ), -1 ); + return 0; + } + + char *htmlDocument; + int size = mkd_document( markdownHandle, &htmlDocument ); + + QString html = QString::fromUtf8( htmlDocument, size ); + + mTextDocument = new QTextDocument; + mTextDocument->setPageSize( QSizeF( 980, 1307 ) ); + mTextDocument->setHtml( html ); + + mkd_cleanup( markdownHandle ); + + QTextFrameFormat frameFormat; + frameFormat.setMargin( 45 ); + + QTextFrame *rootFrame = mTextDocument->rootFrame(); + rootFrame->setFrameFormat( frameFormat ); + + convertLinks(); + convertImages(); + + return mTextDocument; +} + +void Converter::convertLinks() +{ + convertLinks( mTextDocument->rootFrame() ); +} + + +void Converter::convertLinks(QTextFrame * parent) +{ + for ( QTextFrame::iterator it = parent->begin(); !it.atEnd(); ++it ) { + QTextFrame *textFrame = it.currentFrame(); + QTextBlock textBlock = it.currentBlock(); + + if ( textFrame ) { + convertLinks(textFrame); + } + else if ( textBlock.isValid() ) { + convertLinks(textBlock); + } + } +} + +void Converter::convertLinks(QTextBlock & parent) +{ + for ( QTextBlock::iterator it = parent.begin(); !it.atEnd(); ++it ) { + QTextFragment textFragment = it.fragment(); + if ( textFragment.isValid() ) { + QTextCharFormat textCharFormat = textFragment.charFormat(); + if ( textCharFormat.isAnchor() ) { + Okular::BrowseAction *action = new Okular::BrowseAction( QUrl( textCharFormat.anchorHref() ) ); + emit addAction( action, textFragment.position(), textFragment.position()+textFragment.length() ); + + } + } + } +} + +void Converter::convertImages() +{ + convertImages( mTextDocument->rootFrame() ); +} + +void Converter::convertImages(QTextFrame * parent) +{ + for ( QTextFrame::iterator it = parent->begin(); !it.atEnd(); ++it ) { + QTextFrame *textFrame = it.currentFrame(); + QTextBlock textBlock = it.currentBlock(); + + if ( textFrame ) { + convertImages(textFrame); + } + else if ( textBlock.isValid() ) { + convertImages(textBlock); + } + } +} + +void Converter::convertImages(QTextBlock & parent) +{ + for ( QTextBlock::iterator it = parent.begin(); !it.atEnd(); ++it ) { + QTextFragment textFragment = it.fragment(); + if ( textFragment.isValid() ) { + QTextCharFormat textCharFormat = textFragment.charFormat(); + if( textCharFormat.isImageFormat() ) { + + //TODO: Show images from http URIs + + QTextImageFormat format; + + format.setName( QDir::cleanPath( mDir.absoluteFilePath( textCharFormat.toImageFormat().name() ) ) ); + const QImage img = QImage( format.name() ); + + if ( img.width() > 890 ) { + format.setWidth( 890 ); + format.setHeight( img.height() * 890. / img.width() ); + } + else { + format.setWidth( img.width() ); + format.setHeight( img.height() ); + } + + QTextCursor cursor( mTextDocument ); + cursor.setPosition( textFragment.position(), QTextCursor::MoveAnchor ); + cursor.setPosition( textFragment.position() + textFragment.length(), QTextCursor::KeepAnchor ); + cursor.removeSelectedText(); + cursor.insertImage( format ); + + } + } + } +} diff --git a/generators/markdown/debug_md.h b/generators/markdown/debug_md.h new file mode 100644 --- /dev/null +++ b/generators/markdown/debug_md.h @@ -0,0 +1,19 @@ + +/*************************************************************************** + * Copyright (C) 2006 by Luigi Toscano * + * Copyright (C) 2014 by Frederik Gladhorn * + * * + * 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. * + ***************************************************************************/ + +#ifndef OKULAR_MD_DEBUG_P_H +#define OKULAR_MD_DEBUG_P_H + +#include + +Q_DECLARE_LOGGING_CATEGORY(OkularMdDebug) + +#endif diff --git a/generators/markdown/generator_md.h b/generators/markdown/generator_md.h new file mode 100644 --- /dev/null +++ b/generators/markdown/generator_md.h @@ -0,0 +1,27 @@ +/*************************************************************************** + * Copyright (C) 2017 by Julian Wolff * + * * + * 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. * + ***************************************************************************/ + +#ifndef _OKULAR_GENERATOR_MD_H_ +#define _OKULAR_GENERATOR_MD_H_ + +#include + +class MarkdownGenerator : public Okular::TextDocumentGenerator +{ + Q_OBJECT + Q_INTERFACES( Okular::Generator ) + + public: + MarkdownGenerator( QObject *parent, const QVariantList &args ); + + // [INHERITED] reparse configuration + void addPages( KConfigDialog* dlg ) override; +}; + +#endif diff --git a/generators/markdown/generator_md.cpp b/generators/markdown/generator_md.cpp new file mode 100644 --- /dev/null +++ b/generators/markdown/generator_md.cpp @@ -0,0 +1,37 @@ +/*************************************************************************** + * Copyright (C) 2017 by Julian Wolff * + * * + * 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. * + ***************************************************************************/ + +#include "generator_md.h" + +#include "converter.h" +#include "debug_md.h" + +#include +#include +#include + +OKULAR_EXPORT_PLUGIN(MarkdownGenerator, "libokularGenerator_md.json") + +MarkdownGenerator::MarkdownGenerator( QObject *parent, const QVariantList &args ) + : Okular::TextDocumentGenerator( new Markdown::Converter, QStringLiteral("okular_markdown_generator_settings"), parent, args ) +{ +} + +void MarkdownGenerator::addPages( KConfigDialog* dlg ) +{ + Okular::TextDocumentSettingsWidget *widget = new Okular::TextDocumentSettingsWidget(); + + dlg->addPage( widget, generalSettings(), i18n("Markdown"), QStringLiteral("text-markdown"), i18n("Markdown Backend Configuration") ); +} + + +Q_LOGGING_CATEGORY(OkularMdDebug, "org.kde.okular.generators.md", QtWarningMsg) + +#include "generator_md.moc" + diff --git a/generators/markdown/libokularGenerator_md.json b/generators/markdown/libokularGenerator_md.json new file mode 100644 --- /dev/null +++ b/generators/markdown/libokularGenerator_md.json @@ -0,0 +1,26 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "wolff@julianwolff.de", + "Name": "Julian Wolff", + "Name[x-test]": "xxJulian Wolffxx" + } + ], + "Copyright": "© 2017 Julian Wolff", + "Id": "okular_markdown", + "License": "GPL", + "MimeTypes": [ + "text/markdown", + "text/x-markdown" + ], + "Name": "Markdown Backend", + "ServiceTypes": [ + "okular/Generator" + ], + "Version": "0.1.0" + }, + "X-KDE-Priority": 1, + "X-KDE-okularAPIVersion": 1, + "X-KDE-okularHasInternalSettings": true +} diff --git a/generators/markdown/okularApplication_md.desktop b/generators/markdown/okularApplication_md.desktop new file mode 100644 --- /dev/null +++ b/generators/markdown/okularApplication_md.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +MimeType=text/markdown; +Terminal=false +Name=Okular +GenericName=Document Viewer +Comment=Universal document viewer +Exec=okular %U +Icon=okular +Type=Application +InitialPreference=7 +Categories=Qt;KDE;Graphics;Viewer; +NoDisplay=true +X-KDE-Keywords=Markdown diff --git a/generators/markdown/okularMd.desktop b/generators/markdown/okularMd.desktop new file mode 100644 --- /dev/null +++ b/generators/markdown/okularMd.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Icon=okular +Name=Okular +X-KDE-ServiceTypes=KParts/ReadOnlyPart +X-KDE-Library=okularpart +Type=Service +MimeType=text/markdown; diff --git a/generators/markdown/org.kde.mobile.okular_md.desktop b/generators/markdown/org.kde.mobile.okular_md.desktop new file mode 100644 --- /dev/null +++ b/generators/markdown/org.kde.mobile.okular_md.desktop @@ -0,0 +1,14 @@ +[Desktop Entry] +MimeType=text/markdown; +Name=Reader +GenericName=Document viewer +Comment=Viewer for various types of documents +TryExec=kpackagelauncherqml -a org.kde.mobile.okular +Exec=kpackagelauncherqml -a org.kde.mobile.okular %u +Terminal=false +Icon=okular +Type=Application +Categories=Qt;KDE;Graphics;Office;Viewer; +InitialPreference=2 +NoDisplay=true +X-KDE-Keywords=Markdown diff --git a/generators/markdown/org.kde.okular-md.metainfo.xml b/generators/markdown/org.kde.okular-md.metainfo.xml new file mode 100644 --- /dev/null +++ b/generators/markdown/org.kde.okular-md.metainfo.xml @@ -0,0 +1,13 @@ + + + org.kde.okular-md + org.kde.okular.desktop + CC0-1.0 + GPL-2.0+ and GFDL-1.3 + Markdown + Adds support for reading Markdown documents + + text/markdown + + https://okular.kde.org + diff --git a/okular.categories b/okular.categories --- a/okular.categories +++ b/okular.categories @@ -5,6 +5,7 @@ org.kde.okular.generators.dvi.core Okular (Generator DVI/Core) org.kde.okular.generators.dvi.shell Okular (Generator DVI/Shell) org.kde.okular.generators.txt Okular (Generator TXT) +org.kde.okular.generators.md Okular (Generator Markdown) org.kde.kio.msits kioslave (kio_msits) org.kde.okular.generators.fax Okular (Generator Fax) org.kde.okular.generators.pdf Okular (Generator PDF)