Summary: Adds support for Markdown documents BUG: 360603 Test Plan: Open a Markdown (.md) document in Okular Reviewers: #okular, aacid Reviewed By: #okular, aacid Subscribers: michaelweghorn, aacid Tags: #okular Differential Revision: https://phabricator.kde.org/D7382remotes/origin/Applications/17.12
parent
37de97a030
commit
4931385777
15 changed files with 452 additions and 0 deletions
@ -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, <wolff@julianwolff.de> |
||||||
|
# |
||||||
|
# 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) |
||||||
|
|
||||||
@ -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} ) |
||||||
|
|
||||||
@ -0,0 +1,2 @@ |
|||||||
|
#!/bin/sh |
||||||
|
$XGETTEXT $(find . -name "*.cpp" -o -name "*.h") -o $podir/okular_markdown.pot |
||||||
@ -0,0 +1,177 @@ |
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2017 by Julian Wolff <wolff@julianwolff.de> * |
||||||
|
* * |
||||||
|
* 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 <KLocalizedString> |
||||||
|
|
||||||
|
#include <QTemporaryFile> |
||||||
|
#include <QTextDocument> |
||||||
|
#include <QTextStream> |
||||||
|
#include <QTextFrame> |
||||||
|
#include <QTextCursor> |
||||||
|
|
||||||
|
#include <core/action.h> |
||||||
|
|
||||||
|
#include "debug_md.h" |
||||||
|
|
||||||
|
extern "C" { |
||||||
|
#include <mkdio.h> |
||||||
|
} |
||||||
|
|
||||||
|
// 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 ); |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,47 @@ |
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2017 by Julian Wolff <wolff@julianwolff.de> * |
||||||
|
* * |
||||||
|
* 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 <QDir> |
||||||
|
|
||||||
|
#include <core/textdocumentgenerator.h> |
||||||
|
|
||||||
|
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 |
||||||
@ -0,0 +1,19 @@ |
|||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2006 by Luigi Toscano <luigi.toscano@tiscali.it> * |
||||||
|
* Copyright (C) 2014 by Frederik Gladhorn <gladhorn@kde.org> * |
||||||
|
* * |
||||||
|
* 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 <QtCore/qloggingcategory.h> |
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(OkularMdDebug) |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,37 @@ |
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2017 by Julian Wolff <wolff@julianwolff.de> * |
||||||
|
* * |
||||||
|
* 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 <KAboutData> |
||||||
|
#include <KLocalizedString> |
||||||
|
#include <kconfigdialog.h> |
||||||
|
|
||||||
|
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" |
||||||
|
|
||||||
@ -0,0 +1,27 @@ |
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2017 by Julian Wolff <wolff@julianwolff.de> * |
||||||
|
* * |
||||||
|
* 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 <core/textdocumentgenerator.h> |
||||||
|
|
||||||
|
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 |
||||||
@ -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 |
||||||
|
} |
||||||
@ -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 |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
[Desktop Entry] |
||||||
|
Icon=okular |
||||||
|
Name=Okular |
||||||
|
X-KDE-ServiceTypes=KParts/ReadOnlyPart |
||||||
|
X-KDE-Library=okularpart |
||||||
|
Type=Service |
||||||
|
MimeType=text/markdown; |
||||||
@ -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 |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<component type="addon"> |
||||||
|
<id>org.kde.okular-md</id> |
||||||
|
<extends>org.kde.okular.desktop</extends> |
||||||
|
<metadata_license>CC0-1.0</metadata_license> |
||||||
|
<project_license>GPL-2.0+ and GFDL-1.3</project_license> |
||||||
|
<name>Markdown</name> |
||||||
|
<summary>Adds support for reading Markdown documents</summary> |
||||||
|
<mimetypes> |
||||||
|
<mimetype>text/markdown</mimetype> |
||||||
|
</mimetypes> |
||||||
|
<url type="homepage">https://okular.kde.org</url> |
||||||
|
</component> |
||||||
Loading…
Reference in new issue