30#include <glib/gi18n.h>
31#include <glib/gstdio.h>
41#include <webkit/webkit.h>
45#include "gnc-gui-query.h"
48#include "gnc-html-webkit.hpp"
49#include "gnc-html-history.h"
54static void gnc_html_webkit_dispose( GObject* obj );
55static void gnc_html_webkit_finalize( GObject* obj );
57#define GNC_HTML_WEBKIT_GET_PRIVATE(o) (GNC_HTML_WEBKIT(o)->priv)
59#include "gnc-html-webkit-p.hpp"
62static QofLogModule log_module = GNC_MOD_HTML;
65extern GHashTable* gnc_html_object_handlers;
68extern GHashTable* gnc_html_stream_handlers;
71extern GHashTable* gnc_html_url_handlers;
73static char error_404_format[] =
"<html><body><h3>%s</h3><p>%s</body></html>";
74static char error_404_title[] = N_(
"Not found");
75static char error_404_body[] = N_(
"The specified URL could not be loaded.");
77#define BASE_URI_NAME "base-uri"
78#define GNC_PREF_RPT_DFLT_ZOOM "default-zoom"
80static WebKitNavigationResponse webkit_navigation_requested_cb(
81 WebKitWebView* web_view,
82 WebKitWebFrame* frame,
83 WebKitNetworkRequest* request,
85static gboolean webkit_on_load_error (WebKitWebView *web_view,
86 WebKitWebFrame *web_frame, gchar *uri,
87 GError *error, gpointer data);
88static void webkit_resource_load_error (WebKitWebView *web_view,
89 WebKitWebFrame *web_frame,
90 WebKitWebResource *resource,
91 GError *error, gpointer data);
92static void webkit_on_url_cb( WebKitWebView* web_view, gchar* title, gchar* url,
94static gchar* handle_embedded_object(
GncHtmlWebkit* self, gchar* html_str );
96static void gnc_html_set_base_cb( GtkHTML* gtkhtml,
const gchar* base, gpointer data );
97static void gnc_html_link_clicked_cb( GtkHTML* html,
const gchar* url, gpointer data );
98static gboolean gnc_html_object_requested_cb( GtkHTML* html, GtkHTMLEmbedded* eb,
102static int gnc_html_button_press_cb( GtkWidget* widg, GdkEventButton* event,
103 gpointer user_data );
105static void impl_webkit_show_url( GncHtml* self, URLType type,
106 const gchar* location,
const gchar* label,
107 gboolean new_window_hint );
108static void impl_webkit_show_data( GncHtml* self,
const gchar* data,
int datalen );
109static void impl_webkit_reload( GncHtml* self, gboolean force_rebuild );
110static void impl_webkit_copy_to_clipboard( GncHtml* self );
111static gboolean impl_webkit_export_to_file( GncHtml* self,
const gchar* filepath );
112static void impl_webkit_print( GncHtml* self,
const gchar* jobname, gboolean export_pdf );
113static void impl_webkit_cancel( GncHtml* self );
114static void impl_webkit_set_parent( GncHtml* self, GtkWindow* parent );
115static void impl_webkit_default_zoom_changed(gpointer prefs, gchar *pref, gpointer user_data);
120 PangoFontDescription *font_desc =
nullptr;
125 auto priv = self->priv = new_priv;
126 GNC_HTML(self)->priv =
reinterpret_cast<GncHtmlPrivate*
>(priv);
128 priv->html_string =
nullptr;
129 priv->web_view = WEBKIT_WEB_VIEW(webkit_web_view_new());
132 auto stylecontext = gtk_widget_get_style_context (GTK_WIDGET(priv->web_view));
133 gtk_style_context_get (stylecontext, gtk_widget_get_state_flags (GTK_WIDGET(priv->web_view)),
134 "font", &font_desc,
nullptr);
136 const char *default_font_family = pango_font_description_get_family (font_desc);
137 pango_font_description_free (font_desc);
140 auto webkit_settings = webkit_web_view_get_settings (priv->web_view);
141 g_object_set (G_OBJECT(webkit_settings),
"default-encoding",
"utf-8",
nullptr);
142 if (default_font_family ==
nullptr)
144 PWARN(
"webkit_settings: Cannot get default font family.");
148 g_object_set (G_OBJECT(webkit_settings),
149 "default-font-family", default_font_family,
151 PINFO(
"webkit_settings: Set default font to [%s]", default_font_family);
154 gdouble zoom =
gnc_prefs_get_float (GNC_PREFS_GROUP_GENERAL_REPORT, GNC_PREF_RPT_DFLT_ZOOM);
155 webkit_web_view_set_full_content_zoom (priv->web_view, TRUE);
156 webkit_web_view_set_zoom_level (priv->web_view, zoom);
159 gtk_container_add( GTK_CONTAINER(priv->base.container),
160 GTK_WIDGET(priv->web_view) );
162 g_object_ref_sink( priv->base.container );
165 g_signal_connect( priv->web_view,
"navigation-requested",
166 G_CALLBACK(webkit_navigation_requested_cb),
169 g_signal_connect( priv->web_view,
"hovering-over-link",
170 G_CALLBACK(webkit_on_url_cb),
174 g_signal_connect( priv->html,
"set_base",
175 G_CALLBACK(gnc_html_set_base_cb),
178 g_signal_connect(priv->html,
"link_clicked",
179 G_CALLBACK(gnc_html_link_clicked_cb),
182 g_signal_connect (priv->html,
"object_requested",
183 G_CALLBACK (gnc_html_object_requested_cb),
186 g_signal_connect (priv->html,
"button_press_event",
187 G_CALLBACK (gnc_html_button_press_cb),
190 g_signal_connect (priv->html,
"submit",
191 G_CALLBACK(gnc_html_submit_cb),
194 g_signal_connect (priv->web_view,
"load-error",
195 G_CALLBACK (webkit_on_load_error),
198 g_signal_connect (priv->web_view,
"resource-load-failed",
199 G_CALLBACK (webkit_resource_load_error),
203 GNC_PREF_RPT_DFLT_ZOOM,
204 reinterpret_cast<gpointer
>(impl_webkit_default_zoom_changed),
207 LEAVE(
"retval %p", self);
213 GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
214 GncHtmlClass* html_class = GNC_HTML_CLASS(klass);
216 gobject_class->dispose = gnc_html_webkit_dispose;
217 gobject_class->finalize = gnc_html_webkit_finalize;
219 html_class->show_url = impl_webkit_show_url;
220 html_class->show_data = impl_webkit_show_data;
221 html_class->reload = impl_webkit_reload;
222 html_class->copy_to_clipboard = impl_webkit_copy_to_clipboard;
223 html_class->export_to_file = impl_webkit_export_to_file;
224 html_class->print = impl_webkit_print;
225 html_class->cancel = impl_webkit_cancel;
226 html_class->set_parent = impl_webkit_set_parent;
230gnc_html_webkit_dispose( GObject* obj )
235 if ( priv->web_view !=
nullptr )
237 gtk_container_remove( GTK_CONTAINER(priv->base.container),
238 GTK_WIDGET(priv->web_view) );
239 priv->web_view =
nullptr;
242 if ( priv->html_string !=
nullptr )
244 g_free( priv->html_string );
245 priv->html_string =
nullptr;
249 GNC_PREF_RPT_DFLT_ZOOM,
250 reinterpret_cast<gpointer
>(
251 impl_webkit_default_zoom_changed
255 G_OBJECT_CLASS(gnc_html_webkit_parent_class)->dispose( obj );
259gnc_html_webkit_finalize( GObject* obj )
263 self->priv =
nullptr;
265 G_OBJECT_CLASS(gnc_html_webkit_parent_class)->finalize( obj );
271extract_base_name(URLType type,
const gchar* path)
273 constexpr gchar machine_rexp[] =
"^(//[^/]*)/*(/.*)?$";
274 constexpr gchar path_rexp[] =
"^/*(.*)/+([^/]*)$";
275 regex_t compiled_m, compiled_p;
276 constexpr size_t MATCH_LEN = 4;
277 regmatch_t match[MATCH_LEN];
278 gchar * machine =
nullptr, * location =
nullptr, * base =
nullptr;
279 gchar * basename =
nullptr;
282 if (!path)
return nullptr;
284 regcomp(&compiled_m, machine_rexp, REG_EXTENDED);
285 regcomp(&compiled_p, path_rexp, REG_EXTENDED);
287 if (!g_strcmp0 (type, URL_TYPE_HTTP) ||
288 !g_strcmp0 (type, URL_TYPE_SECURE) ||
289 !g_strcmp0 (type, URL_TYPE_FTP))
294 if (!regexec(&compiled_m, path, MATCH_LEN, match, 0))
297 if (match[1].rm_so != -1)
299 machine = g_strndup(path + match[1].rm_so,
300 match[1].rm_eo - match[1].rm_so);
303 if (match[2].rm_so != -1)
305 location = g_strndup(path + match[2].rm_so,
306 match[2].rm_eo - match[2].rm_so);
313 location = g_strdup(path);
318 if (!regexec(&compiled_p, location, 4, match, 0))
320 if (match[1].rm_so != -1)
322 base = g_strndup(location + match[1].rm_so,
323 match[1].rm_eo - match[1].rm_so);
332 regfree(&compiled_m);
333 regfree(&compiled_p);
337 if (base && (strlen(base) > 0))
339 basename = g_strconcat(machine,
"/", base,
"/",
nullptr);
343 basename = g_strconcat(machine,
"/",
nullptr);
348 if (base && (strlen(base) > 0))
350 basename = g_strdup(base);
377handle_embedded_object(
GncHtmlWebkit* self, gchar* html_str )
382 gchar* remainder_str = html_str;
384 gchar* end_object_tag;
385 gchar* object_contents;
386 gchar* html_str_start =
nullptr;
387 gchar* html_str_middle;
388 gchar* html_str_result =
nullptr;
389 gchar* classid_start;
395 object_tag = g_strstr_len( remainder_str, -1,
"<object classid=" );
399 classid_start = object_tag + strlen(
"<object classid=" ) + 1;
400 classid_end = g_strstr_len( classid_start, -1,
"\"" );
401 classid_str = g_strndup( classid_start, (classid_end - classid_start) );
403 end_object_tag = g_strstr_len( object_tag, -1,
"</object>" );
404 if ( end_object_tag ==
nullptr )
408 g_free (classid_str);
409 g_free (html_str_result);
410 return g_strdup (html_str);
412 end_object_tag += strlen(
"</object>" );
413 object_contents = g_strndup( object_tag, (end_object_tag - object_tag) );
415 const gpointer p = g_hash_table_lookup( gnc_html_object_handlers, classid_str );
416 h =
reinterpret_cast<GncHTMLObjectCB
>(p);
419 (void)h( GNC_HTML(self), object_contents, &html_str_middle );
423 html_str_middle = g_strdup_printf(
"No handler found for classid \"%s\"", classid_str );
426 html_str_start = html_str_result;
427 new_chunk = g_strndup (remainder_str, (object_tag - remainder_str));
429 html_str_result = g_strconcat (new_chunk, html_str_middle,
nullptr);
431 html_str_result = g_strconcat (html_str_start, new_chunk, html_str_middle,
nullptr);
433 g_free( html_str_start );
435 g_free( html_str_middle );
437 remainder_str = end_object_tag;
438 object_tag = g_strstr_len( remainder_str, -1,
"<object classid=" );
443 html_str_start = html_str_result;
444 html_str_result = g_strconcat (html_str_start, remainder_str,
nullptr);
445 g_free (html_str_start);
448 html_str_result = g_strdup (remainder_str);
450 return html_str_result;
461 const gchar* location,
const gchar* label )
463 gchar* fdata =
nullptr;
467 DEBUG(
"type %s, location %s, label %s", type ? type :
"(null)",
468 location ? location :
"(null)", label ? label :
"(null)");
470 g_return_val_if_fail( self !=
nullptr, FALSE );
472 if ( gnc_html_stream_handlers !=
nullptr )
474 const gpointer p = g_hash_table_lookup( gnc_html_stream_handlers, type );
475 GncHTMLStreamCB stream_handler =
reinterpret_cast<GncHTMLStreamCB
>(p);
476 if ( stream_handler )
478 GncHtml *weak_html = GNC_HTML(self);
480 g_object_add_weak_pointer(G_OBJECT(self), (gpointer *)(&weak_html));
482 bool ok = stream_handler(location, &fdata, &fdata_len);
491 g_object_remove_weak_pointer(G_OBJECT(self),
492 (gpointer*)(&weak_html));
497 fdata = fdata ? fdata : g_strdup(
"");
502 if (g_strstr_len(fdata, -1,
"<object classid=") !=
nullptr)
505 new_fdata = handle_embedded_object(self, fdata);
511 if (priv->html_string !=
nullptr)
513 g_free(priv->html_string);
515 priv->html_string = g_strdup(fdata);
516 impl_webkit_show_data(GNC_HTML(self), fdata, strlen(fdata));
520 fdata = fdata ? fdata :
521 g_strdup_printf( error_404_format,
522 _(error_404_title),
_(error_404_body) );
523 webkit_web_view_load_html_string( priv->web_view, fdata, BASE_URI_NAME );
530 while ( gtk_events_pending() )
532 gtk_main_iteration();
543 if ( !g_strcmp0( type, URL_TYPE_SECURE ) ||
544 !g_strcmp0( type, URL_TYPE_HTTP ) )
547 if ( !g_strcmp0( type, URL_TYPE_SECURE ) )
549 if ( !https_allowed() )
551 gnc_error_dialog (GTK_WINDOW (priv->base.parent),
"%s",
552 _(
"Secure HTTP access is disabled. "
553 "You can enable it in the Network section of "
554 "the Preferences dialog."));
559 if ( !http_allowed() )
561 gnc_error_dialog (GTK_WINDOW (priv->base.parent),
"%s",
562 _(
"Network HTTP access is disabled. "
563 "You can enable it in the Network section of "
564 "the Preferences dialog."));
568 gnc_build_url( type, location, label );
574 PWARN(
"load_to_stream for inappropriate type\n"
576 location ? location :
"(null)",
577 label ? label :
"(null)" );
578 fdata = g_strdup_printf( error_404_format,
579 _(error_404_title),
_(error_404_body) );
580 webkit_web_view_load_html_string( priv->web_view, fdata, BASE_URI_NAME );
596gnc_html_link_clicked_cb( GtkHTML* html,
const gchar* url, gpointer data )
599 gchar* location =
nullptr;
600 gchar* label =
nullptr;
603 DEBUG(
"Clicked %s", url);
604 type = gnc_html_parse_url( GNC_HTML(self), url, &location, &label );
605 gnc_html_show_url( GNC_HTML(self), type, location, label, 0 );
616static WebKitNavigationResponse
617webkit_navigation_requested_cb( WebKitWebView* web_view, WebKitWebFrame* frame,
618 WebKitNetworkRequest* request,
621 gchar* location =
nullptr;
622 gchar* label =
nullptr;
624 const gchar* url = webkit_network_request_get_uri( request );
626 ENTER(
"requesting %s", url );
627 if ( strcmp( url, BASE_URI_NAME ) == 0 )
629 LEAVE(
"URI is %s", BASE_URI_NAME);
630 return WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
633 URLType type = gnc_html_parse_url( GNC_HTML(self), url, &location, &label );
634 if ( strcmp( type,
"file" ) == 0 )
636 LEAVE(
"URI type is 'file'");
637 return WEBKIT_NAVIGATION_RESPONSE_ACCEPT;
639 gnc_html_show_url( GNC_HTML(self), type, location, label, 0 );
645 return WEBKIT_NAVIGATION_RESPONSE_IGNORE;
649webkit_on_load_error (WebKitWebView *web_view, WebKitWebFrame *web_frame,
650 gchar *uri, GError *error, gpointer data)
652 PERR (
"WebKit load of %s failed due to %s\n", uri, error->message);
657webkit_resource_load_error (WebKitWebView *web_view, WebKitWebFrame *web_frame,
658 WebKitWebResource *resource, GError *error,
661 const gchar *uri = webkit_web_resource_get_uri (resource);
662 const gchar *type = webkit_web_resource_get_mime_type (resource);
663 PERR (
"WebKit load of resource %s, type %s, failed due to %s\n",
664 uri, type, error->message);
674gnc_html_object_requested_cb( GtkHTML* html, GtkHTMLEmbedded* eb,
680 if ( !eb || !(eb->classid) || !gnc_html_object_handlers )
return FALSE;
682 auto h = g_hash_table_lookup( gnc_html_object_handlers, eb->classid );
685 return h( GNC_HTML(self), eb, data );
699webkit_on_url_cb( WebKitWebView* web_view, gchar* title, gchar* url, gpointer data )
704 DEBUG(
"Rollover %s", url ? url :
"(null)" );
705 g_free( priv->base.current_link );
706 priv->base.current_link = g_strdup( url );
707 if ( priv->base.flyover_cb )
709 (priv->base.flyover_cb)( GNC_HTML(self), url, priv->base.flyover_cb_data );
719gnc_html_set_base_cb( GtkHTML* gtkhtml,
const gchar* base,
724 gchar* location =
nullptr;
725 gchar* label =
nullptr;
727 DEBUG(
"Setting base location to %s", base );
728 URLType type = gnc_html_parse_url( GNC_HTML(self), base, &location, &label );
730 g_free( priv->base.base_location );
733 priv->base.base_type = type;
734 priv->base.base_location = location;
745gnc_html_button_press_cb( GtkWidget* widg, GdkEventButton* event,
751 DEBUG(
"Button Press" );
752 if ( priv->base.button_cb !=
nullptr )
754 (priv->base.button_cb)( GNC_HTML(self), event, priv->base.button_cb_data );
770gnc_html_open_scm(
GncHtmlWebkit* self,
const gchar * location,
771 const gchar * label,
int newwin )
773 PINFO(
"location='%s'", location ? location :
"(null)");
784impl_webkit_show_data( GncHtml* self,
const gchar* data,
int datalen )
786#define TEMPLATE_REPORT_FILE_NAME "gnc-report-XXXXXX.html"
787 g_return_if_fail( self !=
nullptr );
788 g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
790 ENTER(
"datalen %d, data %20.20s", datalen, data );
792 auto priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
799 gchar *filename = g_build_filename(g_get_tmp_dir(), TEMPLATE_REPORT_FILE_NAME, (gchar *)
nullptr);
800 int fd = g_mkstemp( filename );
801 impl_webkit_export_to_file( self, filename );
804 gchar *uri = g_strdup_printf(
"file:///%s", filename );
806 gchar *uri = g_strdup_printf(
"file://%s", filename );
809 DEBUG(
"Loading uri '%s'", uri);
810 webkit_web_view_load_uri( priv->web_view, uri );
825impl_webkit_show_url( GncHtml* self, URLType type,
826 const gchar* location,
const gchar* label,
827 gboolean new_window_hint )
829 GncHTMLUrlCB url_handler =
nullptr;
830 bool new_window =
false;
831 bool stream_loaded =
false;
833 g_return_if_fail( self !=
nullptr );
834 g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
835 g_return_if_fail( location !=
nullptr );
837 auto priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
840 if ( new_window_hint == 0 )
842 if ( priv->base.urltype_cb )
844 new_window = !((priv->base.urltype_cb)( type ));
854 gnc_html_cancel( GNC_HTML(self) );
857 if ( gnc_html_url_handlers )
859 url_handler =
reinterpret_cast<GncHTMLUrlCB
>(
860 g_hash_table_lookup( gnc_html_url_handlers, type )
868 result.load_to_stream = FALSE;
869 result.url_type = type;
870 result.location =
nullptr;
871 result.label =
nullptr;
872 result.base_type = URL_TYPE_FILE;
873 result.base_location =
nullptr;
874 result.error_message =
nullptr;
875 result.parent = GTK_WINDOW (priv->base.parent);
877 bool ok = url_handler( location, label, new_window, &result );
880 if ( result.error_message )
882 gnc_error_dialog (GTK_WINDOW (priv->base.parent),
"%s", result.error_message );
887 gnc_error_dialog (GTK_WINDOW (priv->base.parent),
_(
"There was an error accessing %s."), location );
890 if ( priv->base.load_cb )
892 priv->base.load_cb( GNC_HTML(self), result.url_type,
893 location, label, priv->base.load_cb_data );
896 else if ( result.load_to_stream )
898 gnc_html_history_node *hnode;
899 const char *new_location;
900 const char *new_label;
902 new_location = result.location ? result.location : location;
903 new_label = result.label ? result.label : label;
904 hnode = gnc_html_history_node_new( result.url_type, new_location, new_label );
906 gnc_html_history_append( priv->base.history, hnode );
908 g_free( priv->base.base_location );
909 priv->base.base_type = result.base_type;
910 priv->base.base_location =
911 g_strdup( extract_base_name( result.base_type, new_location ) );
912 DEBUG(
"resetting base location to %s",
913 priv->base.base_location ? priv->base.base_location :
"(null)" );
915 stream_loaded = load_to_stream( GNC_HTML_WEBKIT(self),
917 new_location, new_label );
919 if ( stream_loaded && priv->base.load_cb !=
nullptr )
921 priv->base.load_cb( GNC_HTML(self), result.url_type,
922 new_location, new_label, priv->base.load_cb_data );
926 g_free( result.location );
927 g_free( result.label );
928 g_free( result.base_location );
929 g_free( result.error_message );
934 if ( g_strcmp0( type, URL_TYPE_SCHEME ) == 0 )
936 gnc_html_open_scm( GNC_HTML_WEBKIT(self), location, label, new_window );
939 else if ( g_strcmp0( type, URL_TYPE_JUMP ) == 0 )
943 else if ( g_strcmp0( type, URL_TYPE_SECURE ) == 0 ||
944 g_strcmp0( type, URL_TYPE_HTTP ) == 0 ||
945 g_strcmp0( type, URL_TYPE_FILE ) == 0 )
950 if ( g_strcmp0( type, URL_TYPE_SECURE ) == 0 )
952 if ( !https_allowed() )
954 gnc_error_dialog (GTK_WINDOW (priv->base.parent),
"%s",
955 _(
"Secure HTTP access is disabled. "
956 "You can enable it in the Network section of "
957 "the Preferences dialog.") );
962 if ( g_strcmp0( type, URL_TYPE_HTTP ) == 0 )
964 if ( !http_allowed() )
966 gnc_error_dialog (GTK_WINDOW (priv->base.parent),
"%s",
967 _(
"Network HTTP access is disabled. "
968 "You can enable it in the Network section of "
969 "the Preferences dialog.") );
974 priv->base.base_type = type;
976 if ( priv->base.base_location !=
nullptr ) g_free( priv->base.base_location );
977 priv->base.base_location = extract_base_name( type, location );
980 gnc_html_history_append( priv->base.history,
981 gnc_html_history_node_new( type, location, label ) );
982 stream_loaded = load_to_stream( GNC_HTML_WEBKIT(self), type,
991 PERR(
"URLType %s not supported.", type );
994 if ( stream_loaded && priv->base.load_cb !=
nullptr )
996 (priv->base.load_cb)( GNC_HTML(self), type, location, label, priv->base.load_cb_data );
1009impl_webkit_reload( GncHtml* self, gboolean force_rebuild )
1013 g_return_if_fail( self !=
nullptr );
1014 g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
1016 priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
1018 if ( force_rebuild )
1020 gnc_html_history_node *n = gnc_html_history_get_current( priv->base.history );
1022 gnc_html_show_url( self, n->type, n->location, n->label, 0 );
1025 webkit_web_view_reload( priv->web_view );
1035gnc_html_webkit_new(
void )
1038 g_object_new( GNC_TYPE_HTML_WEBKIT,
nullptr )
1040 return GNC_HTML(self);
1049webkit_cancel_helper(gpointer key, gpointer value, gpointer user_data)
1052 g_list_free((GList *)value);
1057impl_webkit_cancel( GncHtml* self )
1061 g_return_if_fail( self !=
nullptr );
1062 g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
1064 priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
1066 g_hash_table_foreach_remove( priv->base.request_info, webkit_cancel_helper,
nullptr );
1070impl_webkit_copy_to_clipboard( GncHtml* self )
1074 g_return_if_fail( self !=
nullptr );
1075 g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
1077 priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
1078 if ( webkit_web_view_can_copy_clipboard( priv->web_view ) )
1080 webkit_web_view_copy_clipboard( priv->web_view );
1092impl_webkit_export_to_file( GncHtml* self,
const char *filepath )
1097 g_return_val_if_fail( self !=
nullptr, FALSE );
1098 g_return_val_if_fail( GNC_IS_HTML_WEBKIT(self), FALSE );
1099 g_return_val_if_fail( filepath !=
nullptr, FALSE );
1101 priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
1102 if ( priv->html_string ==
nullptr )
1106 fh = g_fopen( filepath,
"w" );
1107 if ( fh !=
nullptr )
1110 gint len = strlen( priv->html_string );
1112 written = fwrite( priv->html_string, 1, len, fh );
1115 if ( written != len )
1141impl_webkit_print( GncHtml* self,
const gchar* jobname, gboolean export_pdf )
1143 gchar *export_filename =
nullptr;
1145 WebKitWebFrame* frame;
1146 GtkPrintOperation* op = gtk_print_operation_new();
1147 GError* error =
nullptr;
1148 GtkPrintSettings *print_settings;
1150 priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
1151 frame = webkit_web_view_get_main_frame( priv->web_view );
1154 print_settings = gtk_print_operation_get_print_settings (op);
1155 if (!print_settings)
1157 print_settings = gtk_print_settings_new();
1158 gtk_print_operation_set_print_settings(op, print_settings);
1161 gtk_print_operation_set_unit( op, GTK_UNIT_POINTS );
1165 if (g_str_has_suffix(jobname,
".pdf"))
1167 export_filename = g_strdup(jobname);
1171 export_filename = g_strconcat(jobname,
".pdf",
nullptr);
1180 gchar *export_dirname =
nullptr;
1186 dialog = gtk_file_chooser_dialog_new (
_(
"Export to PDF File"),
1188 GTK_FILE_CHOOSER_ACTION_SAVE,
1189 _(
"_Cancel"), GTK_RESPONSE_CANCEL,
1190 _(
"_Save"), GTK_RESPONSE_ACCEPT,
1192 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
1195 basename = g_path_get_basename(jobname);
1196 if (strcmp(basename, jobname) != 0)
1198 gchar *tmp_basename;
1199 gchar *tmp_dirname = g_path_get_dirname(jobname);
1201 if (g_file_test(tmp_dirname,
1202 static_cast<GFileTest
>(
1203 G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR
1208 export_dirname = tmp_dirname;
1209 tmp_dirname =
nullptr;
1213 tmp_basename = g_path_get_basename(export_filename);
1214 g_free(export_filename);
1215 export_filename = tmp_basename;
1217 g_free(tmp_dirname);
1222 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(dialog), export_filename);
1227 const char* tmp_dirname = gtk_print_settings_get(print_settings,
1230 if (g_file_test(tmp_dirname,
1231 static_cast<GFileTest
>(
1232 G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR
1235 export_dirname = g_strdup(tmp_dirname);
1242 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), export_dirname);
1244 g_free(export_dirname);
1246 result = gtk_dialog_run (GTK_DIALOG (dialog));
1252 if (result == GTK_RESPONSE_ACCEPT)
1256 char *tmp = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1257 g_free(export_filename);
1258 export_filename = tmp;
1261 dirname = g_path_get_dirname(export_filename);
1262 if (g_file_test(dirname,
1263 static_cast<GFileTest
>(
1264 G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR
1271 gtk_widget_destroy (dialog);
1273 if (result != GTK_RESPONSE_ACCEPT)
1276 g_free(export_filename);
1277 g_object_unref( op );
1282 gtk_print_operation_set_export_filename(op, export_filename);
1285 webkit_web_frame_print_full( frame, op, GTK_PRINT_OPERATION_ACTION_EXPORT, &error );
1291 if (gtk_print_settings_has_key(print_settings, GTK_PRINT_SETTINGS_OUTPUT_URI))
1295 const gchar *olduri = gtk_print_settings_get(print_settings, GTK_PRINT_SETTINGS_OUTPUT_URI);
1296 gchar *dirname = g_path_get_dirname(olduri);
1297 gchar *newuri = (g_strcmp0(dirname,
".") == 0)
1298 ? g_strdup(export_filename)
1299 : g_build_filename(dirname, export_filename,
nullptr);
1303 gtk_print_settings_set(print_settings, GTK_PRINT_SETTINGS_OUTPUT_URI, newuri);
1311 gtk_print_settings_set(print_settings, GTK_PRINT_SETTINGS_OUTPUT_URI, export_filename);
1315 webkit_web_frame_print_full( frame, op, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, &error );
1318 if ( error !=
nullptr )
1320 GtkWidget* window = gtk_widget_get_toplevel( GTK_WIDGET(priv->web_view) );
1321 GtkWidget* dialog = gtk_message_dialog_new( gtk_widget_is_toplevel(window) ? GTK_WINDOW(window) : nullptr,
1322 GTK_DIALOG_DESTROY_WITH_PARENT,
1325 "%s", error->message );
1326 g_error_free( error );
1328 g_signal_connect( dialog,
"response", G_CALLBACK(gtk_widget_destroy),
nullptr);
1329 gtk_widget_show( dialog );
1334 g_object_unref( op );
1335 g_free(export_filename);
1339impl_webkit_set_parent( GncHtml* self, GtkWindow* parent )
1343 g_return_if_fail( self !=
nullptr );
1344 g_return_if_fail( GNC_IS_HTML_WEBKIT(self) );
1346 priv = GNC_HTML_WEBKIT_GET_PRIVATE(self);
1347 priv->base.parent = GTK_WIDGET(parent);
1351impl_webkit_default_zoom_changed(gpointer prefs, gchar *pref, gpointer user_data)
1357 g_return_if_fail(user_data !=
nullptr);
1360 webkit_web_view_set_zoom_level (priv->web_view, zoom);
Account handling public routines.
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.
#define GNC_GTK_PRINT_SETTINGS_EXPORT_DIR
Key for saving the PDF-export directory in the print settings.
void gnc_print_operation_init(GtkPrintOperation *op, const gchar *jobname)
If print settings have been saved by gnc_print_operation_save_print_settings(), then set them on the ...
void gnc_print_operation_save_print_settings(GtkPrintOperation *op)
Retrieve the print settings from the GtkPrintOperation op and save them in a static variable.
#define PINFO(format, args...)
Print an informational note.
#define DEBUG(format, args...)
Print a debugging message.
#define LEAVE(format, args...)
Print a function exit debugging message.
#define PERR(format, args...)
Log a serious error.
#define PWARN(format, args...)
Log a warning.
#define ENTER(format, args...)
Print a function entry debugging message.
void gnc_prefs_remove_cb_by_func(const gchar *group, const gchar *pref_name, gpointer func, gpointer user_data)
Remove a function that was registered for a callback when the given preference changed.
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)
Get an float value from the preferences backend.
gulong gnc_prefs_register_cb(const char *group, const gchar *pref_name, gpointer func, gpointer user_data)
Register a callback that gets triggered when the given preference changes.