Commit 49313857 authored by Julian Wolff's avatar Julian Wolff Committed by Albert Astals Cid
Browse files

add markdown support

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/D7382
parent 37de97a0
# - 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)
......@@ -89,6 +89,13 @@ set_package_properties("libqmobipocket" PROPERTIES
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
if(Poppler_Qt5_FOUND)
......@@ -140,3 +147,7 @@ add_subdirectory(txt)
if(QMobipocket_FOUND)
add_subdirectory(mobipocket)
endif()
if(discount_FOUND)
add_subdirectory(markdown)
endif()
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} )
#!/bin/sh
$XGETTEXT $(find . -name "*.cpp" -o -name "*.h") -o $podir/okular_markdown.pot
/***************************************************************************
* 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 );
}
}
}
}
/***************************************************************************
* 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
/***************************************************************************
* 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
/***************************************************************************
* 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"
/***************************************************************************
* 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
{
"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
}
[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
[Desktop Entry]
Icon=okular
Name=Okular
X-KDE-ServiceTypes=KParts/ReadOnlyPart
X-KDE-Library=okularpart
Type=Service
MimeType=text/markdown;
[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
<?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>
......@@ -5,6 +5,7 @@ org.kde.okular.generators.ooo Okular (Generator OOo)
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)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment