GNOME Bugzilla – Bug 548594
Support for line wrapping.
Last modified: 2020-09-26 09:40:48 UTC
the bug has been described on https://bugs.launchpad.net/ubuntu/+source/gnome-utils/+bug/258788 "Would be nice to have a word wrap option to read those long system log lines."
Created attachment 117393 [details] [review] Patch: text wrapping and tooltips for logs. Updated version.
Comment on attachment 117393 [details] [review] Patch: text wrapping and tooltips for logs. Updated version. Index: logview/logview.c =================================================================== --- logview/logview.c (revision 8031) +++ logview/logview.c (working copy) @@ -70,6 +70,7 @@ static void logview_close_log (GtkAction static void logview_bigger_text (GtkAction *action, LogviewWindow *logview); static void logview_smaller_text (GtkAction *action, LogviewWindow *logview); static void logview_normal_text (GtkAction *action, LogviewWindow *logview); +static void logview_toggle_wordwrap (GtkAction *action, LogviewWindow *logview); static void logview_calendar_set_state (LogviewWindow *logview); static void logview_search (GtkAction *action, LogviewWindow *logview); static void logview_help (GtkAction *action, GtkWidget *parent_window); @@ -125,6 +126,8 @@ static GtkToggleActionEntry toggle_entri G_CALLBACK (logview_toggle_sidebar), TRUE }, { "MonitorLogs", NULL, N_("_Monitor"), "<control>M", N_("Monitor Current Log"), G_CALLBACK (logview_toggle_monitor), TRUE }, + { "TextWrap", NULL, N_("_Text Wrap"), "<control>T", N_("Enable Text Wrapping"), + G_CALLBACK (logview_toggle_wordwrap), TRUE }, {"ShowCalendar", NULL, N_("Ca_lendar"), "<control>L", N_("Show Calendar Log"), G_CALLBACK (logview_toggle_calendar), TRUE }, }; @@ -150,6 +153,7 @@ static const char *ui_description = " <separator/>" " <menuitem action='Search'/>" " <menuitem action='CollapseAll'/>" + " <menuitem action='TextWrap'/>" " <separator/>" " <menuitem action='ViewZoomIn'/>" " <menuitem action='ViewZoomOut'/>" @@ -207,13 +211,11 @@ logview_select_log (LogviewWindow *logvi g_return_if_fail (LOGVIEW_IS_WINDOW (logview)); logview_store_visible_range (logview); - logview->curlog = log; logview_menus_set_state (logview); logview_calendar_set_state (logview); logview_repaint (logview); logview_update_findbar_visibility (logview); - logview_update_version_bar (logview); logview_save_prefs (logview); gtk_widget_grab_focus (logview->view); @@ -281,6 +283,7 @@ logview_menus_set_state (LogviewWindow * logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/Search", (log != NULL)); logview_menu_item_set_state (logview, "/LogviewMenu/EditMenu/Copy", (log != NULL)); logview_menu_item_set_state (logview, "/LogviewMenu/EditMenu/SelectAll", (log != NULL)); + logview_menu_item_toggle_set_active (logview, "/LogviewMenu/ViewMenu/TextWrap", prefs_get_wordwrap()); } void @@ -367,6 +370,7 @@ logview_save_prefs (LogviewWindow *logvi prefs_store_active_log (logview->curlog->name); } prefs_store_fontsize (logview->fontsize); + prefs_store_wordwrap (logview->wordwrap); prefs_save (); } } @@ -613,7 +617,7 @@ logview_toggle_monitor (GtkAction *actio void logview_set_font (LogviewWindow *logview, - const gchar *fontname) + const gchar *fontname) { PangoFontDescription *font_desc; @@ -635,7 +639,7 @@ logview_set_fontsize (LogviewWindow *log PangoFontDescription *fontdesc; PangoContext *context; - g_assert (LOGVIEW_IS_WINDOW (logview)); + g_assert (LOGVIEW_IS_WINDOW (logview)); context = gtk_widget_get_pango_context (logview->view); fontdesc = pango_context_get_font_description (context); @@ -670,6 +674,67 @@ logview_normal_text (GtkAction *action, logview->fontsize = logview->original_fontsize; logview_set_fontsize (logview); } + +static gboolean +logview_grid_changed (GtkTreeModel *tm, GtkTreePath *path, + GtkTreeIter *iter, gpointer data) +{ + gtk_tree_model_row_changed (tm, path, iter); + return FALSE; +} + +static void +logview_update_grid_width (LogviewWindow *logview, gint w) +{ + GtkTreeView *tv; + GtkTreeViewColumn *col; + GList *cell_list; + gint taken_width = 0; + + tv = GTK_TREE_VIEW (logview->view); + col = gtk_tree_view_get_column (tv, 0); + if (! col) return; + + cell_list = gtk_tree_view_column_get_cell_renderers (col); + if (cell_list == NULL || cell_list->data == NULL) + return; + if (logview->wordwrap) { + gtk_widget_style_get (GTK_WIDGET (tv), "expander-size", &taken_width, NULL); + taken_width = taken_width * 2; // indented rows are indented twice... + taken_width += gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW + (logview->scrolled))->allocation.width; + taken_width += 5; // prettier + if (w == -1) w = GTK_WIDGET (logview->scrolled)->allocation.width; + if (w > taken_width) w = w - taken_width; + g_object_set (G_OBJECT (cell_list->data), "wrap-width", w, + "wrap-mode", PANGO_WRAP_WORD_CHAR, NULL); + } + else { + g_object_set (G_OBJECT(cell_list->data), "wrap-width", -1, NULL); + } + + GtkTreeModel *tm = GTK_TREE_MODEL (gtk_tree_view_get_model(tv)); + if (tm) gtk_tree_model_foreach (tm, logview_grid_changed, NULL); +} + +static void +logview_scrollwindow_cb (GtkScrolledWindow *sw, + GtkAllocation *allocation, + LogviewWindow *logview) +{ + logview_update_grid_width (logview, allocation->width); +} + +static void +logview_toggle_wordwrap (GtkAction *action, LogviewWindow *logview) +{ + g_assert (LOGVIEW_IS_WINDOW (logview)); + + logview->wordwrap = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)); + logview_update_grid_width (logview, -1); + logview_save_prefs (logview); + // free everything +} static void logview_search (GtkAction *action, LogviewWindow *logview) @@ -786,6 +851,29 @@ window_size_changed_cb (GtkWidget *widge return FALSE; } +static gboolean +query_tooltip_cb (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, +GtkTooltip *tooltip, gpointer data) +{ + GtkTreeIter iter; + GtkTreeView *tree_view = GTK_TREE_VIEW (widget); + GtkTreeModel *model = gtk_tree_view_get_model (tree_view); + GtkTreePath *path = NULL; + gchar *wholeline; + gchar *pathstring; + + if (!gtk_tree_view_get_tooltip_context (tree_view, &x, &y, keyboard_mode, + &model, &path, &iter)) + return FALSE; + gtk_tree_model_get (model, &iter, 0, &wholeline, -1); + gtk_tooltip_set_text (tooltip, wholeline); + gtk_tree_view_set_tooltip_row (tree_view, tooltip, path); + gtk_tree_path_free (path); + g_free (wholeline); + + return TRUE; +} + static void logview_window_finalize (GObject *object) { @@ -811,7 +899,7 @@ logview_init (LogviewWindow *logview) GtkWidget *hpaned; GtkWidget *label; GtkWidget *main_view; - GtkWidget *loglist_scrolled, *scrolled; + GtkWidget *loglist_scrolled; PangoContext *context; PangoFontDescription *fontdesc; gchar *monospace_font_name; @@ -870,23 +958,27 @@ logview_init (LogviewWindow *logview) gtk_paned_pack2 (GTK_PANED (hpaned), GTK_WIDGET (main_view), TRUE, TRUE); /* Scrolled window for the main view */ - scrolled = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), + logview->scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (logview->scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_box_pack_start (GTK_BOX(main_view), scrolled, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX(main_view), logview->scrolled, TRUE, TRUE, 0); /* Main Tree View */ logview->view = gtk_tree_view_new (); gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (logview->view), FALSE); gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (logview->view), FALSE); + g_object_set(G_OBJECT(logview->view), "has-tooltip", TRUE, NULL); /* Use the desktop monospace font */ monospace_font_name = prefs_get_monospace (); logview_set_font (logview, monospace_font_name); g_free (monospace_font_name); + logview->wordwrap = prefs_get_wordwrap (); renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT (renderer), "wrap-width", -1, "wrap-mode", + PANGO_WRAP_WORD_CHAR, NULL); column = gtk_tree_view_column_new (); gtk_tree_view_column_pack_start (column, renderer, TRUE); gtk_tree_view_column_set_attributes (column, renderer, @@ -905,9 +997,9 @@ logview_init (LogviewWindow *logview) G_CALLBACK (logview_version_selector_changed), logview); label = gtk_label_new (_("Version: ")); - gtk_box_pack_end (GTK_BOX(logview->version_bar), logview->version_selector, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX(logview->version_bar), label, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX(main_view), logview->version_bar, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (logview->version_bar), logview->version_selector, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (logview->version_bar), label, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (main_view), logview->version_bar, FALSE, FALSE, 0); logview->find_bar = logview_findbar_new (); gtk_box_pack_end (GTK_BOX (main_view), logview->find_bar, FALSE, FALSE, 0); @@ -919,21 +1011,25 @@ logview_init (LogviewWindow *logview) logview->original_fontsize = pango_font_description_get_size (fontdesc) / PANGO_SCALE; logview->fontsize = logview->original_fontsize; - gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (logview->view)); - gtk_widget_show_all (scrolled); + gtk_container_add (GTK_CONTAINER (logview->scrolled), GTK_WIDGET (logview->view)); + gtk_widget_show_all (logview->scrolled); selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (logview->view)); gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); /* Add signal handlers */ - g_signal_connect (G_OBJECT (selection), "changed", + g_signal_connect (selection, "changed", G_CALLBACK (selection_changed_cb), logview); - g_signal_connect (G_OBJECT (logview->view), "row-expanded", + g_signal_connect (logview->view, "row-expanded", G_CALLBACK (row_toggled_cb), logview); - g_signal_connect (G_OBJECT (logview->view), "row-collapsed", + g_signal_connect (logview->view, "row-collapsed", G_CALLBACK (row_toggled_cb), logview); - g_signal_connect (G_OBJECT (logview), "configure_event", + g_signal_connect (logview->view, "query-tooltip", + G_CALLBACK(query_tooltip_cb), NULL); + g_signal_connect (logview, "configure_event", G_CALLBACK (window_size_changed_cb), logview); + g_signal_connect (logview->scrolled, "size-allocate", + G_CALLBACK (logview_scrollwindow_cb), logview); /* Status area at bottom */ logview->statusbar = gtk_statusbar_new (); Index: logview/userprefs.c =================================================================== --- logview/userprefs.c (revision 8031) +++ logview/userprefs.c (working copy) @@ -33,6 +33,7 @@ #define LOGVIEW_DEFAULT_HEIGHT 400 #define LOGVIEW_DEFAULT_WIDTH 600 +#define LOGVIEW_DEFAULT_WORDWRAP FALSE /* logview settings */ #define GCONF_DIR "/apps/gnome-system-log" @@ -41,6 +42,7 @@ #define GCONF_LOGFILE GCONF_DIR "/logfile" #define GCONF_LOGFILES GCONF_DIR "/logfiles" #define GCONF_FONTSIZE_KEY GCONF_DIR "/fontsize" +#define GCONF_WORDWRAP_KEY GCONF_DIR "/wordwrap" /* desktop-wide settings */ #define GCONF_MONOSPACE_FONT_NAME "/desktop/gnome/interface/monospace_font_name" @@ -145,6 +147,7 @@ prefs_load (void) { gchar *logfile; int width, height, fontsize; + gboolean wordwrap; UserPrefs *p; GError *err; @@ -180,10 +183,12 @@ prefs_load (void) width = gconf_client_get_int (gconf_client, GCONF_WIDTH_KEY, NULL); height = gconf_client_get_int (gconf_client, GCONF_HEIGHT_KEY, NULL); fontsize = gconf_client_get_int (gconf_client, GCONF_FONTSIZE_KEY, NULL); + wordwrap = gconf_client_get_bool(gconf_client, GCONF_WORDWRAP_KEY, NULL); p->width = (width == 0 ? LOGVIEW_DEFAULT_WIDTH : width); p->height = (height == 0 ? LOGVIEW_DEFAULT_HEIGHT : height); p->fontsize = fontsize; + p->wordwrap = wordwrap; return p; } @@ -257,6 +262,12 @@ prefs_get_height (void) return prefs->height; } +gboolean +prefs_get_wordwrap (void) +{ + return prefs->wordwrap; +} + void prefs_free_loglist () { @@ -285,6 +296,12 @@ prefs_store_fontsize (int fontsize) } void +prefs_store_wordwrap (gboolean wordwrap) +{ + prefs->wordwrap = wordwrap; +} + +void prefs_save (void) { GSList *logs; @@ -327,6 +344,12 @@ prefs_save (void) prefs->fontsize, NULL); } + + if (gconf_client_key_is_writable (gconf_client, GCONF_WORDWRAP_KEY, NULL)) + gconf_client_set_bool(gconf_client, + GCONF_WORDWRAP_KEY, + prefs->wordwrap, + NULL); } void Index: logview/logview.h =================================================================== --- logview/logview.h (revision 8031) +++ logview/logview.h (working copy) @@ -39,6 +39,7 @@ typedef struct _LogviewWindowClass Logvi struct _LogviewWindow { GtkWindow parent_instance; + GtkWidget *scrolled; GtkWidget *view; GtkWidget *statusbar; GtkUIManager *ui_manager; @@ -49,12 +50,13 @@ struct _LogviewWindow { GtkWidget *sidebar; GtkWidget *version_bar; GtkWidget *version_selector; - GtkWidget *hpaned; + GtkWidget *hpaned; - GSList *logs; + GSList *logs; Log *curlog; int original_fontsize, fontsize; + gboolean wordwrap; }; struct _LogviewWindowClass { Index: logview/userprefs.h =================================================================== --- logview/userprefs.h (revision 8031) +++ logview/userprefs.h (working copy) @@ -25,6 +25,7 @@ typedef struct gchar *logfile; GSList *logs; int width, height, fontsize; + gboolean wordwrap; } UserPrefs; gboolean prefs_get_have_tearoff (void); @@ -33,6 +34,7 @@ gchar *prefs_get_active_log (void); GSList *prefs_get_logs (void); int prefs_get_width (void); int prefs_get_height (void); +gboolean prefs_get_wordwrap (void); void prefs_store_log (gchar *name); void prefs_store_active_log (gchar *name); void prefs_store_fontsize (int fontsize); Index: logview/logview.schemas.in =================================================================== --- logview/logview.schemas.in (revision 8031) +++ logview/logview.schemas.in (working copy) @@ -75,6 +75,20 @@ </locale> </schema> + <schema> + <key>/schemas/apps/gnome-system-log/wordwrap</key> + <applyto>/apps/gnome-system-log/wordwrap</applyto> + <owner>logview</owner> + <type>bool</type> + <default>false</default> + <locale name="C"> + <short>Wrap lines in log files</short> + <long>Specifies whether or not lines should be wrapped when + viewing text files. + </long> + </locale> + </schema> + </schemalist> </gconfschemafile> Index: logview/main.c =================================================================== --- logview/main.c (revision 8031) +++ logview/main.c (working copy) @@ -158,7 +158,7 @@ main (int argc, char *argv[]) } gtk_window_set_default_icon_name ("logviewer"); - + prefs_connect (logview); logview_menus_set_state (logview);
Created attachment 118207 [details] [review] Updated version
Hi David, and thanks for the patch. Logview has been unmaintained for much time, but now it has been rewritten almost from scratch. If you look at the new Logview in trunk, you will see that the log is now displayed within a GtkTextView instead of a GtkTreeView. I think we want to support, as an option, text wrapping but it's not in trunk yet. Ideally it should be much easier: you have the gtk_text_view_set_wrap_mode () function that does it for you, but you should pay attention to indent the text under the gray timestamp like Dec 23 09:43:21 This is a very long line, and this is how it should look like Dec 23 09:44:12 Next line
gnome-system-log is not under active development anymore and had its last code changes more than four years ago. Its codebase has been archived at https://gitlab.gnome.org/Archive/gnome-system-log/ Closing this report as WONTFIX as part of Bugzilla Housekeeping to reflect reality. Please feel free to reopen this ticket (or rather transfer the project to GNOME Gitlab, as GNOME Bugzilla is being shut down) if anyone takes the responsibility for active development again.