apostrophe/uberwriter/UberwriterExportDialog.py

382 lines
12 KiB
Python

# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# Copyright (C) 2012, Wolf Vollprecht <w.vollprecht@gmail.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
### END LICENSE
"""Manages all the export operations and dialogs
"""
import os
import subprocess
import logging
# import gettext
from gettext import gettext as _
import gi
from uberwriter.Theme import Theme
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from uberwriter import helpers
from uberwriter.helpers import get_builder
LOGGER = logging.getLogger('uberwriter')
class Export:
"""
Manages all the export operations and dialogs
"""
__gtype_name__ = "UberwriterExportDialog"
def __init__(self, filename):
"""Set up the about dialog"""
self.builder = get_builder('Export')
self.dialog = self.builder.get_object("Export")
self.stack = self.builder.get_object("export_stack")
self.stack_switcher = self.builder.get_object("format_switcher")
stack_pdf_disabled = self.builder.get_object("pdf_disabled")
filename = filename or _("Untitled document.md")
self.filechoosers = {export_format:self.stack.get_child_by_name(export_format)\
for export_format in ["pdf", "html", "odt", "advanced"]}
for export_format, filechooser in self.filechoosers.items():
filechooser.set_do_overwrite_confirmation(True)
filechooser.set_current_folder(os.path.dirname(filename))
if export_format == "advanced":
self.adv_export_name = self.builder.get_object("advanced_export_name")
self.adv_export_name.set_text(os.path.basename(filename)[:-3])
else:
filechooser.set_current_name(os.path.basename(filename)[:-2] + export_format)
# Disable pdf if Texlive not installed
texlive_installed = helpers.exist_executable("pdftex")
if not texlive_installed:
self.filechoosers["pdf"].set_visible(False)
stack_pdf_disabled.set_visible(True)
stack_pdf_disabled.set_text(disabled_text())
stack_pdf_disabled.set_justify(Gtk.Justification.CENTER)
self.stack.connect('notify', self.allow_export, 'visible_child_name')
self.builder.get_object("highlight_style").set_active(0)
format_store = Gtk.ListStore(int, str)
for fmt_id in self.formats_dict:
format_store.append([fmt_id, self.formats_dict[fmt_id]["name"]])
self.format_field = self.builder.get_object('choose_format')
self.format_field.set_model(format_store)
format_renderer = Gtk.CellRendererText()
self.format_field.pack_start(format_renderer, True)
self.format_field.add_attribute(format_renderer, "text", 1)
self.format_field.set_active(0)
formats_dict = {
1: {
"name": "LaTeX Source",
"ext": "tex",
"to": "latex"
},
2: {
"name": "LaTeX PDF",
"ext": "pdf",
"to": "pdf"
},
3: {
"name": "LaTeX beamer slide show Source .tex",
"ext": "tex",
"to": "beamer"
},
4: {
"name": "LaTeX beamer slide show PDF",
"ext": "pdf",
"to": "beamer"
},
5: {
"name": "HTML",
"ext": "html",
"to": "html"
},
6: {
"name": "Textile",
"ext": "txt",
"to": "textile"
},
7: {
"name": "OpenOffice text document",
"ext": "odt",
"to": "odt"
},
8: {
"name": "Word docx",
"ext": "docx",
"to": "docx"
},
9: {
"name": "reStructuredText txt",
"ext": "txt",
"to": "rst"
},
10: {
"name": "ConTeXt tex",
"ext": "tex",
"to": "context"
},
11: {
"name": "groff man",
"ext": "man",
"to": "man"
},
12: {
"name": "MediaWiki markup",
"ext": "txt",
"to": "mediawiki"
},
13: {
"name": "OpenDocument XML",
"ext": "xml",
"to": "opendocument"
},
14: {
"name": "OpenDocument XML",
"ext": "texi",
"to": "texinfo"
},
15: {
"name": "Slidy HTML and javascript slide show",
"ext": "html",
"to": "slidy"
},
16: {
"name": "Slideous HTML and javascript slide show",
"ext": "html",
"to": "slideous"
},
17: {
"name": "HTML5 + javascript slide show",
"ext": "html",
"to": "dzslides"
},
18: {
"name": "S5 HTML and javascript slide show",
"ext": "html",
"to": "s5"
},
19: {
"name": "EPub electronic publication",
"ext": "epub",
"to": "epub"
},
20: {
"name": "RTF Rich Text Format",
"ext": "rtf",
"to": "rtf"
}
}
def export(self, text=""):
"""Export to pdf, html or odt the given text
Keyword Arguments:
text {str} -- Text to export (default: {""})
"""
export_format = self.stack.get_visible_child_name()
if export_format == "advanced":
self.advanced_export(text)
else:
filename = self.filechoosers[export_format].get_filename()
if filename.endswith("." + export_format):
filename = filename[:-len(export_format)-1]
output_dir = os.path.abspath(os.path.join(filename, os.path.pardir))
basename = os.path.basename(filename)
args = ['pandoc', '--from=markdown', '-s']
if export_format == "pdf":
args.append("-o%s.pdf" % basename)
elif export_format == "odt":
args.append("-o%s.odt" % basename)
elif export_format == "html":
css = Theme.ADWAITA.get_gtk_css_file()
relativize = helpers.get_script_path('relative_to_absolute.lua')
task_list = helpers.get_script_path('task-list.lua')
args.append("-c%s" % css)
args.append("-o%s.html" % basename)
args.append("--mathjax")
args.append("--lua-filter=" + relativize)
args.append("--lua-filter=" + task_list)
proc = subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, cwd=output_dir)
_ = proc.communicate(text)[0]
def advanced_export(self, text=""):
"""Export the given text to special formats with the enabled flags
Keyword Arguments:
text {str} -- The text to export (default: {""})
"""
filename = self.adv_export_name.get_text()
output_dir = os.path.abspath(self.filechoosers["advanced"].get_current_folder())
basename = os.path.basename(filename)
args = self.set_arguments(basename)
LOGGER.info(args)
proc = subprocess.Popen(args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, cwd=output_dir)
_ = proc.communicate(text)[0]
def set_arguments(self, basename):
"""Retrieve a list of the selected arguments
For most of the advanced option checkboxes, returns a list
of the related pandoc flags
Arguments:
basename {str} -- the name of the file
Returns:
list of {str} -- related pandoc flags
"""
highlight_style = self.builder.get_object("highlight_style").get_active_text()
conditions_dict = {
1: {
"condition": self.builder.get_object("toc").get_active(),
"yes": "--toc",
"no": None
},
2: {
"condition": self.builder.get_object("highlight").get_active(),
"yes": "--highlight-style=%s" % highlight_style,
"no": "--no-highlight"
},
3: {
"condition": self.builder.get_object("standalone").get_active(),
"yes": "--standalone",
"no": None
},
4: {
"condition": self.builder.get_object("number_sections").get_active(),
"yes": "--number-sections",
"no": None
},
5: {
"condition": self.builder.get_object("strict").get_active(),
"yes": "--strict",
"no": None
},
6: {
"condition": self.builder.get_object("incremental").get_active(),
"yes": "--incremental",
"no": None
},
7: {
"condition": self.builder.get_object("self_contained").get_active(),
"yes": "--self-contained",
"no": None
}
}
tree_iter = self.format_field.get_active_iter()
if tree_iter is not None:
model = self.format_field.get_model()
row_id, _ = model[tree_iter][:2]
fmt = self.formats_dict[row_id]
args = ['pandoc', '--from=markdown']
extension = "--to=%s" % fmt["to"]
if basename.endswith("." + fmt["ext"]):
output_file = "--output=%s" % basename
else:
output_file = "--output=%s.%s" % (basename, fmt["ext"])
args.extend([conditions_dict[c_id]["yes"]\
if conditions_dict[c_id]["condition"]\
else conditions_dict[c_id]["no"]\
for c_id in conditions_dict])
args = list(filter(None, args))
if self.builder.get_object("html5").get_active():
if fmt["to"] == "html":
extension = "--to=%s" % "html5"
if self.builder.get_object("smart").get_active():
extension += '+smart'
else:
extension += '-smart'
if fmt["to"] != "pdf":
args.append(extension)
css_uri = self.builder.get_object("css_filechooser").get_uri()
if css_uri:
if css_uri.startswith("file://"):
css_uri = css_uri[7:]
args.append("--css=%s" % css_uri)
bib_uri = self.builder.get_object("bib_filechooser").get_uri()
if bib_uri:
if bib_uri.startswith("file://"):
bib_uri = bib_uri[7:]
args.append("--bibliography=%s" % bib_uri)
args.append(output_file)
return args
def allow_export(self, widget, data, signal):
"""Disable export button if the visible child is "pdf_disabled"
"""
del widget, data, signal
export_btn = self.builder.get_object("export_btn")
if self.stack.get_visible_child_name() == "pdf_disabled":
export_btn.set_sensitive(False)
else:
export_btn.set_sensitive(True)
def disabled_text():
"""Return the TexLive installation instructions
Returns:
{str} -- [TexLive installation instructions]
"""
if os.path.isfile("/.flatpak-info"):
text = _("Please, install the TexLive extension from Gnome Software or running\n")\
+ ("flatpak install flathub de.wolfvollprecht.UberWriter.Plugin.TexLive")
else:
text = _("Please, install TexLive from your distribuiton repositories")
return text