1 /*
2 * gnote
3 *
4 * Copyright (C) 2010-2013,2016-2017,2019-2021 Aurimas Cernius
5 * Copyright (C) 2009 Hubert Figuiere
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21
22 #include <libxml/xmlmemory.h>
23 #include <libxml/xpathInternals.h>
24 #include <libxslt/extensions.h>
25
26 #include <glibmm/i18n.h>
27
28 #include "config.h"
29 #include "sharp/exception.hpp"
30 #include "sharp/files.hpp"
31 #include "sharp/streamwriter.hpp"
32 #include "sharp/string.hpp"
33 #include "sharp/uri.hpp"
34 #include "sharp/xsltargumentlist.hpp"
35 #include "debug.hpp"
36 #include "iactionmanager.hpp"
37 #include "ignote.hpp"
38 #include "preferences.hpp"
39 #include "notewindow.hpp"
40 #include "utils.hpp"
41
42 #include "exporttohtmlnoteaddin.hpp"
43 #include "exporttohtmldialog.hpp"
44 #include "notenameresolver.hpp"
45
46 #define STYLESHEET_NAME "exporttohtml.xsl"
47
48
49 using gnote::Preferences;
50
51 namespace exporttohtml {
52
53
ExportToHtmlModule()54 ExportToHtmlModule::ExportToHtmlModule()
55 {
56 ADD_INTERFACE_IMPL(ExportToHtmlNoteAddin);
57 }
58
59 sharp::XslTransform *ExportToHtmlNoteAddin::s_xsl = NULL;
60
61
initialize()62 void ExportToHtmlNoteAddin::initialize()
63 {
64
65 }
66
67
shutdown()68 void ExportToHtmlNoteAddin::shutdown()
69 {
70 }
71
72
on_note_opened()73 void ExportToHtmlNoteAddin::on_note_opened()
74 {
75 register_main_window_action_callback("exporttohtml-export",
76 sigc::mem_fun(*this, &ExportToHtmlNoteAddin::export_button_clicked));
77 }
78
79
get_actions_popover_widgets() const80 std::vector<gnote::PopoverWidget> ExportToHtmlNoteAddin::get_actions_popover_widgets() const
81 {
82 auto widgets = NoteAddin::get_actions_popover_widgets();
83 auto button = gnote::utils::create_popover_button("win.exporttohtml-export", _("Export to HTML…"));
84 widgets.push_back(gnote::PopoverWidget::create_for_note(gnote::EXPORT_TO_HTML_ORDER, button));
85 return widgets;
86 }
87
88
export_button_clicked(const Glib::VariantBase &)89 void ExportToHtmlNoteAddin::export_button_clicked(const Glib::VariantBase&)
90 {
91 ExportToHtmlDialog dialog(ignote(), get_note()->get_title() + ".html");
92 int response = dialog.run();
93 Glib::ustring output_path = dialog.get_filename();
94
95 if (response != Gtk::RESPONSE_OK) {
96 return;
97 }
98
99 DBG_OUT("Exporting Note '%s' to '%s'...", get_note()->get_title().c_str(),
100 output_path.c_str());
101
102 sharp::StreamWriter writer;
103 Glib::ustring error_message;
104
105 try {
106 // FIXME: Warn about file existing. Allow overwrite.
107 sharp::file_delete(output_path);
108
109 writer.init(output_path);
110 write_html_for_note (writer, get_note(), dialog.get_export_linked(),
111 dialog.get_export_linked_all());
112
113 // Save the dialog preferences now that the note has
114 // successfully been exported
115 dialog.save_preferences ();
116
117 try {
118 sharp::Uri output_uri(output_path);
119 gnote::utils::open_url(*get_host_window(), "file://" + output_uri.get_absolute_uri());
120 }
121 catch (const Glib::Exception & ex) {
122 ERR_OUT(_("Could not open exported note in a web browser: %s"),
123 ex.what().c_str());
124
125 Glib::ustring detail = Glib::ustring::compose(
126 // TRANSLATORS: %1%: boost format placeholder for the path
127 _("Your note was exported to \"%1\"."),
128 output_path);
129
130 // Let the user know the note was saved successfully
131 // even though showing the note in a web browser failed.
132 gnote::utils::HIGMessageDialog msg_dialog(
133 get_host_window(),
134 GTK_DIALOG_DESTROY_WITH_PARENT,
135 Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK,
136 _("Note exported successfully"),
137 detail);
138 msg_dialog.run();
139 }
140 }
141 #if 0
142 catch (UnauthorizedAccessException) {
143 error_message = Catalog.GetString ("Access denied.");
144 }
145 catch (DirectoryNotFoundException) {
146 error_message = Catalog.GetString ("Folder does not exist.");
147 }
148 #endif
149 catch (const sharp::Exception & e) {
150 ERR_OUT(_("Could not export: %s"), e.what());
151
152 error_message = e.what();
153 }
154 writer.close ();
155
156 if (!error_message.empty())
157 {
158 ERR_OUT(_("Could not export: %s"), error_message.c_str());
159
160 Glib::ustring msg = Glib::ustring::compose(
161 _("Could not save the file \"%1\""),
162 output_path.c_str());
163
164 gnote::utils::HIGMessageDialog msg_dialog(&dialog,
165 GTK_DIALOG_DESTROY_WITH_PARENT,
166 Gtk::MESSAGE_ERROR,
167 Gtk::BUTTONS_OK,
168 msg, error_message);
169 msg_dialog.run();
170 }
171 }
172
173
174
to_lower(xmlXPathParserContextPtr ctxt,int)175 static void to_lower(xmlXPathParserContextPtr ctxt,
176 int)
177 {
178 const xmlChar *input = xmlXPathPopString(ctxt);
179 gchar * lower = g_utf8_strdown((const gchar*)input, -1);
180 xmlXPathReturnString(ctxt, xmlStrdup((const xmlChar*)lower));
181 g_free(lower);
182 }
183
184
get_note_xsl()185 sharp::XslTransform & ExportToHtmlNoteAddin::get_note_xsl()
186 {
187 if(s_xsl == NULL) {
188 int result = xsltRegisterExtModuleFunction((const xmlChar *)"ToLower",
189 (const xmlChar *)"http://beatniksoftware.com/tomboy",
190 &to_lower);
191 DBG_OUT("xsltRegisterExtModule %d", result);
192 if(result == -1) {
193 DBG_OUT("xsltRegisterExtModule failed");
194 }
195
196 s_xsl = new sharp::XslTransform;
197 Glib::ustring stylesheet_file = DATADIR "/gnote/" STYLESHEET_NAME;
198
199 if (sharp::file_exists (stylesheet_file)) {
200 DBG_OUT("ExportToHTML: Using user-custom %s file.", STYLESHEET_NAME);
201 s_xsl->load(stylesheet_file);
202 }
203 #if 0
204 else {
205 Stream resource = asm.GetManifestResourceStream (stylesheet_name);
206 if (resource != null) {
207 XmlTextReader reader = new XmlTextReader (resource);
208 s_xsl->load (reader, null, null);
209 resource.Close ();
210 }
211 else {
212 DBG_OUT("Unable to find HTML export template '%s'.", STYLESHEET_NAME);
213 }
214 }
215 #endif
216
217 }
218 return *s_xsl;
219 }
220
221
222
223
write_html_for_note(sharp::StreamWriter & writer,const gnote::Note::Ptr & note,bool export_linked,bool export_linked_all)224 void ExportToHtmlNoteAddin::write_html_for_note (sharp::StreamWriter & writer,
225 const gnote::Note::Ptr & note,
226 bool export_linked,
227 bool export_linked_all)
228 {
229 Glib::ustring s_writer;
230 s_writer = note->manager().note_archiver().write_string(note->data());
231 xmlDocPtr doc = xmlParseMemory(s_writer.c_str(), s_writer.bytes());
232
233 sharp::XsltArgumentList args;
234 args.add_param ("export-linked", "", export_linked);
235 args.add_param ("export-linked-all", "", export_linked_all);
236 args.add_param ("root-note", "", gnote::utils::XmlEncoder::encode(note->get_title()));
237
238 if(ignote().preferences().enable_custom_font()) {
239 Glib::ustring font_face = ignote().preferences().custom_font_face();
240 Pango::FontDescription font_desc (font_face);
241 Glib::ustring font = Glib::ustring::compose("font-family:'%1';", font_desc.get_family());
242
243 args.add_param ("font", "", font);
244 }
245
246 NoteNameResolver resolver(note->manager(), note);
247 get_note_xsl().transform(doc, args, writer, resolver);
248
249 xmlFreeDoc(doc);
250 }
251
252
253 }
254
255