Fri, 24 May 2019 03:21:48 -0400
Convert log viewer to Glade.
Currently, the search is hooked up, but Talkatu does not support it, so
the trigger to show the search box is _not_ connected yet. I don't know
if it works entirely yet.
--- a/pidgin/pidginlog.c Wed Jun 05 02:25:52 2019 -0400 +++ b/pidgin/pidginlog.c Fri May 24 03:21:48 2019 -0400 @@ -21,6 +21,8 @@ #include "internal.h" #include "pidgin.h" +#include <talkatu.h> + #include "account.h" #include "debug.h" #include "log.h" @@ -31,7 +33,6 @@ #include "pidginstock.h" #include "gtkblist.h" #include "gtkutils.h" -#include "gtkwebview.h" #include "pidginlog.h" #include "gtk3compat.h" @@ -39,13 +40,17 @@ #define PIDGIN_TYPE_LOG_VIEWER pidgin_log_viewer_get_type() /** * PidginLogViewer: - * @logs: The list of logs viewed in this viewer - * @treestore: The treestore containing said logs - * @treeview: The treeview representing said treestore - * @log_view: The webkit web view to display said logs - * @entry: The search entry, in which search terms are entered - * @search: The string currently being searched for - * @label: The label at the top of the log viewer + * @logs: The list of logs viewed in this viewer + * @browse_button: The button for opening a log folder externally + * @treestore: The treestore containing said logs + * @treeview: The treeview representing said treestore + * @log_view: The talkatu view to display said logs + * @log_buffer: The talkatu buffer to hold said logs + * @title_box: The box containing the title (and optional icon) + * @label: The label at the top of the log viewer + * @size_label: The label to show the size of the logs + * @entry: The search entry, in which search terms are entered + * @search: The string currently being searched for * * A Pidgin Log Viewer. You can look at logs with it. */ @@ -56,13 +61,20 @@ GList *logs; + GtkWidget *browse_button; + GtkTreeStore *treestore; GtkWidget *treeview; GtkWidget *log_view; - GtkWidget *entry; + TalkatuHtmlBuffer *log_buffer; + + GtkWidget *title_box; + GtkLabel *label; - char *search; - GtkLabel *label; + GtkWidget *size_label; + + GtkWidget *entry; + char *search; }; G_DEFINE_TYPE(PidginLogViewer, pidgin_log_viewer, GTK_TYPE_DIALOG) @@ -149,26 +161,31 @@ return ret; } -static void search_cb(GtkWidget *button, PidginLogViewer *lv) +static void +entry_stop_search_cb(GtkWidget *entry, PidginLogViewer *lv) +{ + /* reset the tree */ + gtk_tree_store_clear(lv->treestore); + populate_log_tree(lv); + g_clear_pointer(&lv->search, g_free); +#if 0 + webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(lv->log_view)); +#endif + select_first_log(lv); +} + +static void +entry_search_changed_cb(GtkWidget *button, PidginLogViewer *lv) { const char *search_term = gtk_entry_get_text(GTK_ENTRY(lv->entry)); GList *logs; - if (!(*search_term)) { - /* reset the tree */ - gtk_tree_store_clear(lv->treestore); - populate_log_tree(lv); - g_free(lv->search); - lv->search = NULL; - webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(lv->log_view)); - select_first_log(lv); - return; - } - if (lv->search != NULL && purple_strequal(lv->search, search_term)) { +#if 0 /* Searching for the same term acts as "Find Next" */ webkit_web_view_search_text(WEBKIT_WEB_VIEW(lv->log_view), lv->search, FALSE, TRUE, TRUE); +#endif return; } @@ -178,7 +195,7 @@ lv->search = g_strdup(search_term); gtk_tree_store_clear(lv->treestore); - webkit_web_view_open(WEBKIT_WEB_VIEW(lv->log_view), "about:blank"); /* clear the view */ + talkatu_buffer_clear(TALKATU_BUFFER(lv->log_buffer)); for (logs = lv->logs; logs != NULL; logs = logs->next) { char *read = purple_log_read((PurpleLog*)logs->data, NULL); @@ -444,6 +461,7 @@ } } +#if 0 /* FIXME: Add support in Talkatu for highlighting search terms. */ static gboolean search_find_cb(gpointer data) { PidginLogViewer *viewer = data; @@ -452,6 +470,7 @@ webkit_web_view_search_text(WEBKIT_WEB_VIEW(viewer->log_view), viewer->search, FALSE, TRUE, TRUE); return FALSE; } +#endif static void log_select_cb(GtkTreeSelection *sel, PidginLogViewer *viewer) { GtkTreeIter iter; @@ -476,13 +495,14 @@ if (log->type != PURPLE_LOG_SYSTEM) { gchar *log_date = log_get_date(log); - char *title; - if (log->type == PURPLE_LOG_CHAT) - title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation in %s on %s</span>"), - log->name, log_date); - else - title = g_strdup_printf(_("<span size='larger' weight='bold'>Conversation with %s on %s</span>"), - log->name, log_date); + gchar *title; + if (log->type == PURPLE_LOG_CHAT) { + title = g_strdup_printf(_("Conversation in %s on %s"), + log->name, log_date); + } else { + title = g_strdup_printf(_("Conversation with %s on %s"), + log->name, log_date); + } gtk_label_set_markup(viewer->label, title); g_free(log_date); @@ -491,7 +511,7 @@ read = purple_log_read(log, &flags); - webkit_web_view_open(WEBKIT_WEB_VIEW(viewer->log_view), "about:blank"); + talkatu_buffer_clear(TALKATU_BUFFER(viewer->log_buffer)); purple_signal_emit(pidgin_log_get_handle(), "log-displaying", viewer, log); @@ -503,12 +523,14 @@ read = newRead; } - webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(viewer->log_view), read, ""); + talkatu_markup_set_html(TALKATU_BUFFER(viewer->log_buffer), read, -1); g_free(read); if (viewer->search != NULL) { +#if 0 /* FIXME: Add support in Talkatu for highlighting search terms. */ webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(viewer->log_view)); g_idle_add(search_find_cb, viewer); +#endif } pidgin_clear_cursor(GTK_WIDGET(viewer)); @@ -564,17 +586,6 @@ const char *title, GtkWidget *icon, int log_size) { PidginLogViewer *lv; - GtkWidget *title_box; - char *text; - GtkWidget *pane; - GtkCellRenderer *rend; - GtkTreeViewColumn *col; - GtkTreeSelection *sel; - GtkWidget *vbox; - GtkWidget *frame; - GtkWidget *hbox; - GtkWidget *find_button; - GtkWidget *size_label; if (logs == NULL) { @@ -606,115 +617,45 @@ /* Window ***********/ lv = g_object_new(PIDGIN_TYPE_LOG_VIEWER, NULL); gtk_window_set_title(GTK_WINDOW(lv), title); - gtk_dialog_add_buttons(GTK_DIALOG(lv), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); lv->logs = logs; if (ht != NULL) g_hash_table_insert(log_viewers, ht, lv); -#ifdef _WIN32 - /* Steal the "HELP" response and use it to trigger browsing to the logs folder */ - gtk_dialog_add_button(GTK_DIALOG(lv), _("_Browse logs folder"), GTK_RESPONSE_HELP); +#ifndef _WIN32 + gtk_widget_hide(lv->browse_button); #endif - gtk_container_set_border_width(GTK_CONTAINER(lv), PIDGIN_HIG_BOX_SPACE); - gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv))), 0); - g_signal_connect(G_OBJECT(lv), "response", - G_CALLBACK(destroy_cb), ht); - gtk_window_set_role(GTK_WINDOW(lv), "log_viewer"); + + g_signal_connect(G_OBJECT(lv), "response", G_CALLBACK(destroy_cb), ht); /* Icon *************/ if (icon != NULL) { - title_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PIDGIN_HIG_BOX_SPACE); - gtk_container_set_border_width(GTK_CONTAINER(title_box), PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv))), - title_box, FALSE, FALSE, 0); - - gtk_box_pack_start(GTK_BOX(title_box), icon, FALSE, FALSE, 0); - } else - title_box = gtk_dialog_get_content_area(GTK_DIALOG(lv)); + gtk_box_pack_start(GTK_BOX(lv->title_box), icon, FALSE, FALSE, + 0); + } /* Label ************/ - lv->label = GTK_LABEL(gtk_label_new(NULL)); - - text = g_strdup_printf("<span size='larger' weight='bold'>%s</span>", title); - - gtk_label_set_markup(lv->label, text); - gtk_label_set_xalign(GTK_LABEL(lv->label), 0); - gtk_label_set_yalign(GTK_LABEL(lv->label), 0); - gtk_box_pack_start(GTK_BOX(title_box), GTK_WIDGET(lv->label), FALSE, FALSE, 0); - g_free(text); - - /* Pane *************/ - pane = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); - gtk_container_set_border_width(GTK_CONTAINER(pane), PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv))), - pane, TRUE, TRUE, 0); + gtk_label_set_markup(lv->label, title); /* List *************/ - lv->treestore = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); - lv->treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (lv->treestore)); - g_object_unref(G_OBJECT(lv->treestore)); - rend = gtk_cell_renderer_text_new(); - col = gtk_tree_view_column_new_with_attributes ("time", rend, "markup", 0, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW(lv->treeview), col); - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (lv->treeview), FALSE); - gtk_paned_add1(GTK_PANED(pane), - pidgin_make_scrollable(lv->treeview, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1)); - populate_log_tree(lv); - sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (lv->treeview)); - g_signal_connect (G_OBJECT (sel), "changed", - G_CALLBACK (log_select_cb), - lv); - g_signal_connect (G_OBJECT(lv->treeview), "row-activated", - G_CALLBACK(log_row_activated_cb), - lv); - pidgin_set_accessible_label(lv->treeview, lv->label); - - g_signal_connect(lv->treeview, "button-press-event", G_CALLBACK(log_button_press_cb), lv); - g_signal_connect(lv->treeview, "popup-menu", G_CALLBACK(log_popup_menu_cb), lv); - /* Log size ************/ if(log_size) { char *sz_txt = purple_str_size_to_units(log_size); - text = g_strdup_printf("<span weight='bold'>%s</span> %s", _("Total log size:"), sz_txt); - size_label = gtk_label_new(NULL); - gtk_label_set_markup(GTK_LABEL(size_label), text); - /* gtk_paned_add1(GTK_PANED(pane), size_label); */ - gtk_label_set_xalign(GTK_LABEL(size_label), 0); - gtk_label_set_yalign(GTK_LABEL(size_label), 0); - gtk_box_pack_end(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(lv))), - size_label, FALSE, FALSE, 0); + char *text = g_strdup_printf("<span weight='bold'>%s</span> %s", + _("Total log size:"), sz_txt); + gtk_label_set_markup(GTK_LABEL(lv->size_label), text); g_free(sz_txt); g_free(text); + } else { + gtk_widget_hide(lv->size_label); } - /* A fancy little box ************/ - vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PIDGIN_HIG_BOX_SPACE); - gtk_paned_add2(GTK_PANED(pane), vbox); - - /* Viewer ************/ - frame = pidgin_create_webview(FALSE, &lv->log_view, NULL); - gtk_widget_set_name(lv->log_view, "pidgin_log_log_view"); - gtk_widget_set_size_request(lv->log_view, 320, 200); - gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); - gtk_widget_show(frame); - - /* Search box **********/ - hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, PIDGIN_HIG_BOX_SPACE); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - lv->entry = gtk_entry_new(); - gtk_box_pack_start(GTK_BOX(hbox), lv->entry, TRUE, TRUE, 0); - find_button = gtk_button_new_from_stock(GTK_STOCK_FIND); - gtk_box_pack_start(GTK_BOX(hbox), find_button, FALSE, FALSE, 0); - g_signal_connect(GTK_ENTRY(lv->entry), "activate", G_CALLBACK(search_cb), lv); - g_signal_connect(GTK_BUTTON(find_button), "clicked", G_CALLBACK(search_cb), lv); - select_first_log(lv); - gtk_widget_show_all(GTK_WIDGET(lv)); + gtk_widget_show(GTK_WIDGET(lv)); return lv; } @@ -725,11 +666,51 @@ static void pidgin_log_viewer_class_init(PidginLogViewerClass *klass) { + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + + gtk_widget_class_set_template_from_resource( + widget_class, "/im/pidgin/Pidgin/Log/log-viewer.ui"); + + gtk_widget_class_bind_template_child_internal( + widget_class, PidginLogViewer, browse_button); + + gtk_widget_class_bind_template_child_internal( + widget_class, PidginLogViewer, title_box); + gtk_widget_class_bind_template_child_internal(widget_class, + PidginLogViewer, label); + + gtk_widget_class_bind_template_child_internal( + widget_class, PidginLogViewer, treeview); + gtk_widget_class_bind_template_child_internal( + widget_class, PidginLogViewer, treestore); + gtk_widget_class_bind_template_callback(widget_class, log_select_cb); + gtk_widget_class_bind_template_callback(widget_class, + log_row_activated_cb); + gtk_widget_class_bind_template_callback(widget_class, + log_button_press_cb); + gtk_widget_class_bind_template_callback(widget_class, + log_popup_menu_cb); + + gtk_widget_class_bind_template_child_internal(widget_class, + PidginLogViewer, entry); + gtk_widget_class_bind_template_callback(widget_class, + entry_search_changed_cb); + gtk_widget_class_bind_template_callback(widget_class, + entry_stop_search_cb); + + gtk_widget_class_bind_template_child_internal( + widget_class, PidginLogViewer, log_view); + gtk_widget_class_bind_template_child_internal( + widget_class, PidginLogViewer, log_buffer); + + gtk_widget_class_bind_template_child_internal( + widget_class, PidginLogViewer, size_label); } static void pidgin_log_viewer_init(PidginLogViewer *self) { + gtk_widget_init_template(GTK_WIDGET(self)); } /****************************************************************************
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pidgin/resources/Log/log-viewer.ui Fri May 24 03:21:48 2019 -0400 @@ -0,0 +1,242 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface> + <requires lib="Talkatu" version="0.0"/> + <requires lib="gtk+" version="3.10"/> + <object class="TalkatuHtmlBuffer" id="log_buffer"/> + <object class="GtkTreeStore" id="treestore"> + <columns> + <!-- column-name markup --> + <column type="gchararray"/> + <!-- column-name log --> + <column type="gpointer"/> + </columns> + </object> + <template class="PidginLogViewer" parent="GtkDialog"> + <property name="can_focus">False</property> + <property name="role">log_viewer</property> + <property name="type_hint">dialog</property> + <child> + <placeholder/> + </child> + <child internal-child="vbox"> + <object class="GtkBox"> + <property name="can_focus">False</property> + <property name="margin_top">6</property> + <property name="margin_bottom">6</property> + <property name="orientation">vertical</property> + <property name="spacing">2</property> + <child internal-child="action_area"> + <object class="GtkButtonBox"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="browse_button"> + <property name="label" translatable="yes">_Browse logs folder</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="close_button"> + <property name="label" translatable="yes">_Close</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkBox" id="title_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">6</property> + <child> + <placeholder/> + </child> + <child> + <object class="GtkLabel" id="label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Conversations with buddy</property> + <property name="track_visited_links">False</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <attributes> + <attribute name="weight" value="bold"/> + <attribute name="scale" value="1.2"/> + </attributes> + <accessibility> + <relation type="label-for" target="PidginLogViewer"/> + </accessibility> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkPaned"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="border_width">0</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">never</property> + <property name="vscrollbar_policy">always</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">treestore</property> + <property name="headers_visible">False</property> + <signal name="button-press-event" handler="log_button_press_cb" object="PidginLogViewer" swapped="no"/> + <signal name="popup-menu" handler="log_popup_menu_cb" object="PidginLogViewer" swapped="no"/> + <signal name="row-activated" handler="log_row_activated_cb" object="PidginLogViewer" swapped="no"/> + <child internal-child="selection"> + <object class="GtkTreeSelection"> + <signal name="changed" handler="log_select_cb" object="PidginLogViewer" swapped="no"/> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="time"> + <child> + <object class="GtkCellRendererText"/> + <attributes> + <attribute name="markup">0</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="resize">False</property> + <property name="shrink">True</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkSearchBar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkSearchEntry" id="entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="primary_icon_name">edit-find-symbolic</property> + <property name="primary_icon_activatable">False</property> + <property name="primary_icon_sensitive">False</property> + <signal name="search-changed" handler="entry_search_changed_cb" object="PidginLogViewer" swapped="no"/> + <signal name="stop-search" handler="entry_stop_search_cb" object="PidginLogViewer" swapped="no"/> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="width_request">320</property> + <property name="height_request">200</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <child> + <object class="TalkatuView" id="log_view"> + <property name="name">pidgin_log_view</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="hexpand_set">True</property> + <property name="vexpand_set">True</property> + <property name="editable">False</property> + <property name="wrap_mode">word</property> + <property name="buffer">log_buffer</property> + <property name="send_binding"/> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="resize">True</property> + <property name="shrink">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="size_label"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes"><b>Total log size:</b> 123 KiB</property> + <property name="use_markup">True</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-11">browse_button</action-widget> + <action-widget response="-7">close_button</action-widget> + </action-widgets> + <accessibility> + <relation type="labelled-by" target="label"/> + </accessibility> + </template> +</interface>
--- a/pidgin/resources/pidgin.gresource.xml Wed Jun 05 02:25:52 2019 -0400 +++ b/pidgin/resources/pidgin.gresource.xml Fri May 24 03:21:48 2019 -0400 @@ -9,6 +9,7 @@ <file compressed="true">Debug/debug.ui</file> <file compressed="true">Debug/filter-popover.ui</file> <file compressed="true">Debug/plugininfo.ui</file> + <file compressed="true">Log/log-viewer.ui</file> <file compressed="true">Prefs/prefs.ui</file> </gresource> </gresources>