33#include <glib/gi18n.h>
34#include <glib/gstdio.h>
50#include "gnc-html-history.h"
53static QofLogModule log_module = GNC_MOD_HTML;
56static GHashTable * gnc_html_type_to_proto_hash =
nullptr;
57GHashTable * gnc_html_proto_to_type_hash =
nullptr;
60GHashTable* gnc_html_object_handlers =
nullptr;
63GHashTable* gnc_html_stream_handlers =
nullptr;
66GHashTable* gnc_html_url_handlers =
nullptr;
69extern GHashTable* gnc_html_object_handlers;
71G_DEFINE_ABSTRACT_TYPE(GncHtml, gnc_html, GTK_TYPE_BIN)
73static void gnc_html_dispose( GObject* obj );
74static void gnc_html_finalize( GObject* obj );
79#define GNC_HTML_GET_PRIVATE(o) (GNC_HTML(o)->priv)
81#include "gnc-html-p.h"
84gnc_html_class_init( GncHtmlClass* klass )
86 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
88 gobject_class->dispose = gnc_html_dispose;
89 gobject_class->finalize = gnc_html_finalize;
91 klass->show_url =
nullptr;
92 klass->show_data =
nullptr;
93 klass->reload =
nullptr;
94 klass->copy_to_clipboard =
nullptr;
95 klass->export_to_file =
nullptr;
96 klass->print =
nullptr;
97 klass->cancel =
nullptr;
98 klass->parse_url =
nullptr;
99 klass->set_parent =
nullptr;
103gnc_html_init( GncHtml* self )
105 GncHtmlPrivate *priv = self->priv = g_new0( GncHtmlPrivate, 1 );
107 priv->container = gtk_scrolled_window_new(
nullptr,
nullptr );
108 gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(priv->container),
109 GTK_POLICY_AUTOMATIC,
110 GTK_POLICY_AUTOMATIC );
112 priv->request_info = g_hash_table_new( g_str_hash, g_str_equal );
113 priv->history = gnc_html_history_new();
117gnc_html_dispose( GObject* obj )
119 GncHtml* self = GNC_HTML(obj);
120 GncHtmlPrivate* priv = GNC_HTML_GET_PRIVATE(self);
122 if ( priv->container !=
nullptr )
124 gtk_widget_destroy( GTK_WIDGET(priv->container) );
125 g_object_unref( G_OBJECT(priv->container) );
126 priv->container =
nullptr;
128 if ( priv->request_info !=
nullptr )
130 g_hash_table_destroy( priv->request_info );
131 priv->request_info =
nullptr;
133 if ( priv->history !=
nullptr )
135 gnc_html_history_destroy( priv->history );
136 priv->history =
nullptr;
139 G_OBJECT_CLASS(gnc_html_parent_class)->dispose( obj );
143gnc_html_finalize( GObject* obj )
145 GncHtml* self = GNC_HTML(obj);
147 if ( self->priv !=
nullptr )
149 g_free( self->priv );
150 self->priv =
nullptr;
153 G_OBJECT_CLASS(gnc_html_parent_class)->finalize( obj );
159extract_machine_name(
const gchar* path )
161 constexpr gchar machine_rexp[] =
"^(//[^/]*)/*(.*)?$";
163 constexpr size_t MATCH_LEN = 4;
164 regmatch_t match[MATCH_LEN];
165 gchar* machine =
nullptr;
167 if ( path ==
nullptr )
return nullptr;
169 regcomp( &compiled_m, machine_rexp, REG_EXTENDED );
173 if ( !regexec( &compiled_m, path, MATCH_LEN, match, 0 ) )
176 if ( match[1].rm_so != -1 )
178 machine = g_strndup( path + match[1].rm_so, match[1].rm_eo - match[1].rm_so );
181 regfree(&compiled_m);
192gnc_html_parse_url( GncHtml* self,
const gchar* url,
193 gchar** url_location, gchar** url_label )
noexcept
195 constexpr gchar uri_rexp[] =
"^(([^:][^:]+):)?([^#]+)?(#(.*))?$";
197 constexpr size_t MATCH_LEN = 6;
198 regmatch_t match[MATCH_LEN];
199 gchar* protocol =
nullptr;
200 gchar* path =
nullptr;
201 gchar* label =
nullptr;
202 bool found_protocol =
false;
203 bool found_path =
false;
204 bool found_label =
false;
206 GncHtmlPrivate* priv = GNC_HTML_GET_PRIVATE(self);
208 g_return_val_if_fail( self !=
nullptr,
nullptr );
209 g_return_val_if_fail( GNC_IS_HTML(self),
nullptr );
211 DEBUG(
"parsing %s, base_location %s",
212 url ? url :
"(null)",
213 self ? (priv->base_location ? priv->base_location
214 :
"(null base_location)")
217 regcomp( &compiled, uri_rexp, REG_EXTENDED );
219 if ( !regexec( &compiled, url, MATCH_LEN, match, 0 ) )
221 if ( match[2].rm_so != -1 )
223 protocol = g_new0( gchar, match[2].rm_eo - match[2].rm_so + 1 );
224 strncpy( protocol, url + match[2].rm_so, match[2].rm_eo - match[2].rm_so );
225 protocol[match[2].rm_eo - match[2].rm_so] = 0;
226 found_protocol =
true;
228 if ( match[3].rm_so != -1 )
230 path = g_new0( gchar, match[3].rm_eo - match[3].rm_so + 1 );
231 strncpy( path, url + match[3].rm_so, match[3].rm_eo - match[3].rm_so );
232 path[match[3].rm_eo - match[3].rm_so] = 0;
235 if ( match[5].rm_so != -1 )
237 label = g_new0( gchar, match[5].rm_eo - match[5].rm_so + 1 );
238 strncpy( label, url + match[5].rm_so, match[5].rm_eo - match[5].rm_so );
239 label[match[5].rm_eo - match[5].rm_so] = 0;
244 regfree( &compiled );
246 if ( found_protocol )
248 const gpointer p = g_hash_table_lookup( gnc_html_proto_to_type_hash, protocol );
249 retval =
static_cast<const char *
>(p);
250 if ( retval ==
nullptr )
252 PWARN(
"unhandled URL type for '%s'", url ? url :
"(null)" );
253 retval = URL_TYPE_OTHER;
256 else if ( found_label && !found_path )
258 retval = URL_TYPE_JUMP;
264 retval = priv->base_type;
268 retval = URL_TYPE_FILE;
274 if ( !g_strcmp0( retval, URL_TYPE_FILE ) )
276 if ( !found_protocol && path && self && priv->base_location )
278 if ( g_path_is_absolute( path ) )
280 *url_location = g_strdup( path );
284 *url_location = g_build_filename( priv->base_location, path,
nullptr );
290 *url_location = g_strdup( path );
295 else if ( !g_strcmp0( retval, URL_TYPE_JUMP ) )
297 *url_location =
nullptr;
305 if ( !found_protocol && path && self && priv->base_location )
307 if ( g_path_is_absolute( path ) )
309 *url_location = g_build_filename( extract_machine_name( priv->base_location ),
314 *url_location = g_build_filename( priv->base_location, path,
nullptr );
320 *url_location = g_strdup( path );
336gnc_html_show_data( GncHtml* self,
const gchar* data,
int datalen )
noexcept
338 g_return_if_fail( self !=
nullptr );
339 g_return_if_fail( GNC_IS_HTML(self) );
341 if ( GNC_HTML_GET_CLASS(self)->show_data !=
nullptr )
343 GNC_HTML_GET_CLASS(self)->show_data( self, data, datalen );
347 DEBUG(
"'show_data' not implemented" );
361gnc_html_show_url( GncHtml* self, URLType type,
362 const gchar* location,
const gchar* label,
363 gboolean new_window_hint )
noexcept
365 g_return_if_fail( self !=
nullptr );
366 g_return_if_fail( GNC_IS_HTML(self) );
368 char* lc_type = g_ascii_strdown (type, -1);
370 if ( GNC_HTML_GET_CLASS(self)->show_url !=
nullptr )
372 GNC_HTML_GET_CLASS(self)->show_url( self, lc_type, location, label, new_window_hint );
376 DEBUG(
"'show_url' not implemented" );
391gnc_html_reload( GncHtml* self, gboolean force_rebuild )
noexcept
393 g_return_if_fail( self !=
nullptr );
394 g_return_if_fail( GNC_IS_HTML(self) );
396 if ( GNC_HTML_GET_CLASS(self)->reload !=
nullptr )
398 GNC_HTML_GET_CLASS(self)->reload( self, force_rebuild );
402 DEBUG(
"'reload' not implemented" );
412gnc_html_cancel( GncHtml* self )
noexcept
414 g_return_if_fail( self !=
nullptr );
415 g_return_if_fail( GNC_IS_HTML(self) );
417 if ( GNC_HTML_GET_CLASS(self)->cancel !=
nullptr )
419 GNC_HTML_GET_CLASS(self)->cancel( self );
423 DEBUG(
"'cancel' not implemented" );
434gnc_html_destroy( GncHtml* self )
noexcept
436 g_return_if_fail( self !=
nullptr );
437 g_return_if_fail( GNC_IS_HTML(self) );
439 if ( g_object_is_floating( G_OBJECT(self) ) )
441 (void)g_object_ref_sink( G_OBJECT(self) );
444 g_object_unref( G_OBJECT(self) );
448gnc_html_set_urltype_cb( GncHtml* self, GncHTMLUrltypeCB urltype_cb )
noexcept
450 g_return_if_fail( self !=
nullptr );
451 g_return_if_fail( GNC_IS_HTML(self) );
453 auto priv = GNC_HTML_GET_PRIVATE(self);
454 priv->urltype_cb = urltype_cb;
458gnc_html_set_load_cb( GncHtml* self, GncHTMLLoadCB load_cb, gpointer data )
noexcept
460 g_return_if_fail( self !=
nullptr );
461 g_return_if_fail( GNC_IS_HTML(self) );
463 auto priv = GNC_HTML_GET_PRIVATE(self);
464 priv->load_cb = load_cb;
465 priv->load_cb_data = data;
469gnc_html_set_flyover_cb( GncHtml* self, GncHTMLFlyoverCB flyover_cb, gpointer data )
noexcept
471 g_return_if_fail( self !=
nullptr );
472 g_return_if_fail( GNC_IS_HTML(self) );
474 auto priv = GNC_HTML_GET_PRIVATE(self);
475 priv->flyover_cb = flyover_cb;
476 priv->flyover_cb_data = data;
480gnc_html_set_button_cb( GncHtml* self, GncHTMLButtonCB button_cb, gpointer data )
noexcept
482 g_return_if_fail( self !=
nullptr );
483 g_return_if_fail( GNC_IS_HTML(self) );
485 auto priv = GNC_HTML_GET_PRIVATE(self);
486 priv->button_cb = button_cb;
487 priv->button_cb_data = data;
491gnc_html_copy_to_clipboard( GncHtml* self )
noexcept
493 g_return_if_fail( self !=
nullptr );
494 g_return_if_fail( GNC_IS_HTML(self) );
496 if ( GNC_HTML_GET_CLASS(self)->copy_to_clipboard !=
nullptr )
498 GNC_HTML_GET_CLASS(self)->copy_to_clipboard( self );
502 DEBUG(
"'copy_to_clipboard' not implemented" );
511gnc_html_export_to_file( GncHtml* self,
const gchar* filepath )
noexcept
513 g_return_val_if_fail( self !=
nullptr, FALSE );
514 g_return_val_if_fail( GNC_IS_HTML(self), FALSE );
516 if ( GNC_HTML_GET_CLASS(self)->export_to_file !=
nullptr )
518 return GNC_HTML_GET_CLASS(self)->export_to_file( self, filepath );
522 DEBUG(
"'export_to_file' not implemented" );
528gnc_html_print (GncHtml* self,
const char *jobname, gboolean export_pdf)
noexcept
531gnc_html_print (GncHtml* self,
const char *jobname)
noexcept
534 g_return_if_fail( self !=
nullptr );
535 g_return_if_fail( jobname !=
nullptr );
536 g_return_if_fail( GNC_IS_HTML(self) );
538 if ( GNC_HTML_GET_CLASS(self)->print !=
nullptr )
541 GNC_HTML_GET_CLASS(self)->print (self, jobname, export_pdf);
543 GNC_HTML_GET_CLASS(self)->print (self, jobname);
548 DEBUG(
"'print' not implemented" );
553gnc_html_get_history( GncHtml* self )
noexcept
555 g_return_val_if_fail( self !=
nullptr,
nullptr );
556 g_return_val_if_fail( GNC_IS_HTML(self),
nullptr );
558 return GNC_HTML_GET_PRIVATE(self)->history;
563gnc_html_get_widget( GncHtml* self )
noexcept
565 g_return_val_if_fail( self !=
nullptr,
nullptr );
566 g_return_val_if_fail( GNC_IS_HTML(self),
nullptr );
568 return GNC_HTML_GET_PRIVATE(self)->container;
573gnc_html_get_webview( GncHtml* self )
noexcept
575 g_return_val_if_fail (self !=
nullptr,
nullptr);
576 g_return_val_if_fail (GNC_IS_HTML(self),
nullptr);
578 auto priv = GNC_HTML_GET_PRIVATE(self);
579 GList *sw_list = gtk_container_get_children (GTK_CONTAINER(priv->container));
580 GtkWidget *webview =
nullptr;
585 webview =
static_cast<GtkWidget *
>(sw_list->data);
587 GList *vp_list = gtk_container_get_children (GTK_CONTAINER(sw_list->data));
591 webview =
static_cast<GtkWidget *
>(vp_list->data);
592 g_list_free (vp_list);
596 g_list_free (sw_list);
602gnc_html_set_parent( GncHtml* self, GtkWindow* parent )
noexcept
604 g_return_if_fail( self !=
nullptr );
605 g_return_if_fail( GNC_IS_HTML(self) );
607 if ( GNC_HTML_GET_CLASS(self)->set_parent !=
nullptr )
609 GNC_HTML_GET_CLASS(self)->set_parent( self, parent );
613 DEBUG(
"'set_parent' not implemented" );
621gnc_html_register_urltype( URLType type,
const char *protocol )
noexcept
623 if (!protocol)
return FALSE;
625 if (!gnc_html_type_to_proto_hash)
627 gnc_html_type_to_proto_hash = g_hash_table_new (g_str_hash, g_str_equal);
628 gnc_html_proto_to_type_hash = g_hash_table_new (g_str_hash, g_str_equal);
631 char *lc_type = g_ascii_strdown (type, -1);
632 if (g_hash_table_lookup (gnc_html_type_to_proto_hash, lc_type))
638 char *lc_proto = g_ascii_strdown (protocol, -1);
639 g_hash_table_insert (gnc_html_type_to_proto_hash, lc_type,
static_cast<gpointer
>(lc_proto));
641 g_hash_table_insert (gnc_html_proto_to_type_hash,
static_cast<gpointer
>(lc_proto), lc_type);
647gnc_html_initialize(
void )
noexcept
652 const char *protocol;
655 { URL_TYPE_FILE,
"file" },
656 { URL_TYPE_JUMP,
"" },
657 { URL_TYPE_HTTP,
"http" },
658 { URL_TYPE_FTP,
"ftp" },
659 { URL_TYPE_SECURE,
"https" },
660 { URL_TYPE_REGISTER,
"gnc-register" },
661 { URL_TYPE_ACCTTREE,
"gnc-acct-tree" },
662 { URL_TYPE_REPORT,
"gnc-report" },
663 { URL_TYPE_OPTIONS,
"gnc-options" },
664 { URL_TYPE_SCHEME,
"gnc-scm" },
665 { URL_TYPE_HELP,
"gnc-help" },
666 { URL_TYPE_XMLDATA,
"gnc-xml" },
667 { URL_TYPE_PRICE,
"gnc-price" },
668 { URL_TYPE_BUDGET,
"gnc-budget" },
669 { URL_TYPE_OTHER,
"" }
672 for (
const auto& elem : types)
674 (void) gnc_html_register_urltype (elem.type, elem.protocol);
687gnc_build_url( URLType type,
const gchar* location,
const gchar* label )
noexcept
690 char *lc_type = g_ascii_strdown (type, -1);
691 const gpointer p = g_hash_table_lookup (gnc_html_type_to_proto_hash, lc_type);
692 const char *type_name =
static_cast<const char *
>(p);
693 g_free (
static_cast<gpointer
>(lc_type));
699 return g_strdup_printf(
"%s%s%s#%s", type_name, (*type_name ?
":" :
""),
700 (location ? location :
""),
705 return g_strdup_printf(
"%s%s%s", type_name, (*type_name ?
":" :
""),
706 (location ? location :
""));
711gnc_html_register_object_handler(
const char * classid,
712 GncHTMLObjectCB hand )
noexcept
714 g_return_if_fail( classid !=
nullptr );
716 if ( gnc_html_object_handlers ==
nullptr )
718 gnc_html_object_handlers = g_hash_table_new( g_str_hash, g_str_equal );
721 gnc_html_unregister_object_handler( classid );
722 if ( hand !=
nullptr )
724 gchar *lc_id = g_ascii_strdown (classid, -1);
725 g_hash_table_insert( gnc_html_object_handlers, lc_id,
726 reinterpret_cast<gpointer
>(hand) );
731gnc_html_unregister_object_handler(
const gchar* classid )
noexcept
733 gchar* keyptr =
nullptr;
734 gchar* valptr =
nullptr;
735 gchar* lc_id = g_ascii_strdown (classid, -1);
737 if ( g_hash_table_lookup_extended( gnc_html_object_handlers,
739 reinterpret_cast<gpointer *
>(&keyptr),
740 reinterpret_cast<gpointer *
>(&valptr) ) )
742 g_hash_table_remove( gnc_html_object_handlers, lc_id );
749gnc_html_register_stream_handler( URLType url_type, GncHTMLStreamCB hand )
noexcept
751 g_return_if_fail( url_type !=
nullptr && *url_type !=
'\0' );
753 if ( gnc_html_stream_handlers ==
nullptr )
755 gnc_html_stream_handlers = g_hash_table_new( g_str_hash, g_str_equal );
758 gnc_html_unregister_stream_handler( url_type );
759 if ( hand !=
nullptr )
761 char* lc_type = g_ascii_strdown (url_type, -1);
762 g_hash_table_insert( gnc_html_stream_handlers, lc_type,
763 reinterpret_cast<gpointer
>(hand) );
768gnc_html_unregister_stream_handler( URLType url_type )
noexcept
770 char* lc_type = g_ascii_strdown (url_type, -1);
771 g_hash_table_remove( gnc_html_stream_handlers, lc_type );
776gnc_html_register_url_handler( URLType url_type, GncHTMLUrlCB hand )
noexcept
778 g_return_if_fail( url_type !=
nullptr && *url_type !=
'\0' );
780 if ( gnc_html_url_handlers ==
nullptr )
782 gnc_html_url_handlers = g_hash_table_new( g_str_hash, g_str_equal );
785 gnc_html_unregister_url_handler( url_type );
786 if ( hand !=
nullptr )
788 char* lc_type = g_ascii_strdown (url_type, -1);
789 g_hash_table_insert( gnc_html_url_handlers, lc_type,
790 reinterpret_cast<gpointer
>(hand) );
795gnc_html_unregister_url_handler( URLType url_type )
noexcept
797 char* lc_type = g_ascii_strdown (url_type, -1);
798 g_hash_table_remove( gnc_html_url_handlers, lc_type );
Account handling public routines.
All type declarations for the whole Gnucash engine.
#define DEBUG(format, args...)
Print a debugging message.
#define PWARN(format, args...)
Log a warning.