[gnome-logs] Output the shown logs in GtkListBox to file



commit a0b01ba05eaf1153a27a05a4eb7f926e34741bfe
Author: Jonathan Kang <jonathan121537 gmail com>
Date:   Mon Oct 12 17:03:14 2015 +0800

    Output the shown logs in GtkListBox to file
    
    https://bugzilla.gnome.org/show_bug.cgi?id=727173

 data/gl-eventtoolbar.ui |   21 +++++++++++
 src/gl-eventtoolbar.c   |    5 +++
 src/gl-eventview.c      |   12 ++++++
 src/gl-eventview.h      |    1 +
 src/gl-eventviewlist.c  |   53 +++++++++++++++++++++++++++
 src/gl-eventviewlist.h  |    1 +
 src/gl-eventviewrow.c   |   30 +++++++++++++++
 src/gl-eventviewrow.h   |    3 ++
 src/gl-window.c         |   90 +++++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 216 insertions(+), 0 deletions(-)
---
diff --git a/data/gl-eventtoolbar.ui b/data/gl-eventtoolbar.ui
index c42af57..8e3fc8d 100644
--- a/data/gl-eventtoolbar.ui
+++ b/data/gl-eventtoolbar.ui
@@ -20,6 +20,27 @@
                 </child>
             </object>
         </child>
+        <child>
+            <object class="GtkButton" id="output_button">
+                <property name="action-name">win.export</property>
+                <property name="tooltip-text" translatable="yes">Export logs to a file</property>
+                <property name="valign">center</property>
+                <property name="visible">True</property>
+                <style>
+                    <class name="image-button" />
+                </style>
+                <child>
+                    <object class="GtkImage" id="output_icon">
+                        <property name="icon-name">send-to-symbolic</property>
+                        <property name="icon-size">1</property>
+                        <property name="visible">True</property>
+                    </object>
+                </child>
+            </object>
+            <packing>
+                <property name="pack-type">end</property>
+            </packing>
+        </child>
         <child type="title">
             <object class="GtkMenuButton" id="menu_button">
                 <property name="direction">none</property>
diff --git a/src/gl-eventtoolbar.c b/src/gl-eventtoolbar.c
index 951b320..072e838 100644
--- a/src/gl-eventtoolbar.c
+++ b/src/gl-eventtoolbar.c
@@ -42,6 +42,7 @@ typedef struct
 {
     GtkWidget *current_boot;
     GtkWidget *back_button;
+    GtkWidget *output_button;
     GtkWidget *menu_button;
     GtkWidget *search_button;
     GlEventToolbarMode mode;
@@ -164,11 +165,13 @@ on_notify_mode (GlEventToolbar *toolbar,
     {
         case GL_EVENT_TOOLBAR_MODE_LIST:
             gtk_widget_hide (priv->back_button);
+            gtk_widget_show (priv->output_button);
             gtk_widget_show (priv->menu_button);
             gtk_widget_show (priv->search_button);
             break;
         case GL_EVENT_TOOLBAR_MODE_DETAIL:
             gtk_widget_show (priv->back_button);
+            gtk_widget_hide (priv->output_button);
             gtk_widget_hide (priv->menu_button);
             gtk_widget_hide (priv->search_button);
             break;
@@ -263,6 +266,8 @@ gl_event_toolbar_class_init (GlEventToolbarClass *klass)
     gtk_widget_class_set_template_from_resource (widget_class,
                                                  "/org/gnome/Logs/gl-eventtoolbar.ui");
     gtk_widget_class_bind_template_child_private (widget_class, GlEventToolbar,
+                                                  output_button);
+    gtk_widget_class_bind_template_child_private (widget_class, GlEventToolbar,
                                                   back_button);
     gtk_widget_class_bind_template_child_private (widget_class, GlEventToolbar,
                                                   menu_button);
diff --git a/src/gl-eventview.c b/src/gl-eventview.c
index 41c8a9e..df6c83d 100644
--- a/src/gl-eventview.c
+++ b/src/gl-eventview.c
@@ -59,6 +59,18 @@ static const gchar DESKTOP_SCHEMA[] = "org.gnome.desktop.interface";
 static const gchar CLOCK_FORMAT[] = "clock-format";
 
 gchar *
+gl_event_view_get_output_logs (GlEventView *view)
+{
+    GlEventViewPrivate *priv;
+    GlEventViewList *events;
+
+    priv = gl_event_view_get_instance_private (view);
+    events = GL_EVENT_VIEW_LIST (priv->events);
+
+    return gl_event_view_list_get_output_logs (events);
+}
+
+gchar *
 gl_event_view_get_current_boot_time (GlEventView *view,
                                      const gchar *boot_match)
 {
diff --git a/src/gl-eventview.h b/src/gl-eventview.h
index eb02ad4..3e34c87 100644
--- a/src/gl-eventview.h
+++ b/src/gl-eventview.h
@@ -51,6 +51,7 @@ void gl_event_view_set_search_mode (GlEventView *view, gboolean state);
 void gl_event_view_set_sort_order (GlEventView *view, GlSortOrder sort_order);
 GArray * gl_event_view_get_boot_ids (GlEventView *view);
 void gl_event_view_view_boot (GlEventView *view, const gchar *match);
+gchar * gl_event_view_get_output_logs (GlEventView *view);
 gchar * gl_event_view_get_current_boot_time (GlEventView *view,
                                              const gchar *boot_match);
 
diff --git a/src/gl-eventviewlist.c b/src/gl-eventviewlist.c
index 46f55e8..05dc4fe 100644
--- a/src/gl-eventviewlist.c
+++ b/src/gl-eventviewlist.c
@@ -69,6 +69,59 @@ static const gchar SETTINGS_SCHEMA[] = "org.gnome.Logs";
 static const gchar CLOCK_FORMAT[] = "clock-format";
 static const gchar SORT_ORDER[] = "sort-order";
 
+gchar *
+gl_event_view_list_get_output_logs (GlEventViewList *view)
+{
+    gchar *output_buf = NULL;
+    gint index = 0;
+    GOutputStream *stream;
+    GlEventViewListPrivate *priv;
+
+    priv = gl_event_view_list_get_instance_private (view);
+
+    stream = g_memory_output_stream_new_resizable ();
+
+    while (gtk_list_box_get_row_at_index (GTK_LIST_BOX (priv->entries_box),
+                                          index) != NULL)
+    {
+        const gchar *comm;
+        const gchar *message;
+        gchar *output_text;
+        gchar *time;
+        GDateTime *now;
+        guint64 timestamp;
+        GtkListBoxRow *row;
+
+        row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (priv->entries_box),
+                                             index);
+
+        comm = gl_event_view_row_get_command_line (GL_EVENT_VIEW_ROW (row));
+        message = gl_event_view_row_get_message (GL_EVENT_VIEW_ROW (row));
+        timestamp = gl_event_view_row_get_timestamp (GL_EVENT_VIEW_ROW (row));
+        now = g_date_time_new_now_local ();
+        time = gl_util_timestamp_to_display (timestamp, now,
+                                             priv->clock_format);
+
+        output_text = g_strconcat (time, " ",
+                                   comm ? comm : "kernel", ": ",
+                                   message, "\n", NULL);
+        index++;
+
+        g_output_stream_write (stream, output_text, strlen (output_text),
+                               NULL, NULL);
+
+        g_date_time_unref (now);
+        g_free (time);
+        g_free (output_text);
+    }
+
+    output_buf = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (stream));
+
+    g_output_stream_close (stream, NULL, NULL);
+
+    return output_buf;
+}
+
 static gboolean
 gl_event_view_search_is_case_sensitive (GlEventViewList *view)
 {
diff --git a/src/gl-eventviewlist.h b/src/gl-eventviewlist.h
index 3ba1083..df2cbd6 100644
--- a/src/gl-eventviewlist.h
+++ b/src/gl-eventviewlist.h
@@ -39,6 +39,7 @@ void gl_event_view_list_set_search_mode (GlEventViewList *view, gboolean state);
 void gl_event_view_list_set_sort_order (GlEventViewList *view, GlSortOrder  sort_order);
 void gl_event_view_list_view_boot (GlEventViewList *view, const gchar *match);
 GArray * gl_event_view_list_get_boot_ids (GlEventViewList *view);
+gchar * gl_event_view_list_get_output_logs (GlEventViewList *view);
 gchar * gl_event_view_list_get_current_boot_time (GlEventViewList *view,
                                                   const gchar *boot_match);
 
diff --git a/src/gl-eventviewrow.c b/src/gl-eventviewrow.c
index 41de277..5765e5f 100644
--- a/src/gl-eventviewrow.c
+++ b/src/gl-eventviewrow.c
@@ -53,6 +53,36 @@ G_DEFINE_TYPE_WITH_PRIVATE (GlEventViewRow, gl_event_view_row, GTK_TYPE_LIST_BOX
 
 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
 
+const gchar *
+gl_event_view_row_get_command_line (GlEventViewRow *row)
+{
+    GlEventViewRowPrivate *priv;
+
+    priv = gl_event_view_row_get_instance_private (row);
+
+    return gl_journal_entry_get_command_line (priv->entry);
+}
+
+guint64
+gl_event_view_row_get_timestamp (GlEventViewRow *row)
+{
+    GlEventViewRowPrivate *priv;
+
+    priv = gl_event_view_row_get_instance_private (row);
+
+    return gl_journal_entry_get_timestamp (priv->entry);
+}
+
+const gchar *
+gl_event_view_row_get_message (GlEventViewRow *row)
+{
+    GlEventViewRowPrivate *priv;
+
+    priv = gl_event_view_row_get_instance_private (row);
+
+    return gl_journal_entry_get_message (priv->entry);
+}
+
 GtkWidget *
 gl_event_view_row_get_category_label (GlEventViewRow *row)
 {
diff --git a/src/gl-eventviewrow.h b/src/gl-eventviewrow.h
index 4fbba00..63ffcd4 100644
--- a/src/gl-eventviewrow.h
+++ b/src/gl-eventviewrow.h
@@ -45,6 +45,9 @@ G_DECLARE_FINAL_TYPE (GlEventViewRow, gl_event_view_row, GL, EVENT_VIEW_ROW, Gtk
 
 GtkWidget * gl_event_view_row_new (GlJournalEntry *entry, GlUtilClockFormat clock_format, 
GlEventViewRowCategory category);
 GlJournalEntry * gl_event_view_row_get_entry (GlEventViewRow *row);
+const gchar * gl_event_view_row_get_command_line (GlEventViewRow *row);
+const gchar * gl_event_view_row_get_message (GlEventViewRow *row);
+guint64 gl_event_view_row_get_timestamp (GlEventViewRow *row);
 GtkWidget * gl_event_view_row_get_category_label (GlEventViewRow *row);
 GtkWidget * gl_event_view_row_get_message_label (GlEventViewRow *row);
 GtkWidget * gl_event_view_row_get_time_label (GlEventViewRow *row);
diff --git a/src/gl-window.c b/src/gl-window.c
index 8dfccad..0a06050 100644
--- a/src/gl-window.c
+++ b/src/gl-window.c
@@ -169,6 +169,95 @@ on_search (GSimpleAction *action,
 }
 
 static void
+on_export (GSimpleAction *action,
+           GVariant *variant,
+           gpointer user_data)
+{
+    GlWindowPrivate *priv;
+    GlEventView *event;
+    GtkFileChooser *file_chooser;
+    GtkWidget *dialog;
+    gint res;
+
+    priv = gl_window_get_instance_private (GL_WINDOW (user_data));
+    event = GL_EVENT_VIEW (priv->event);
+
+    dialog = gtk_file_chooser_dialog_new (_("Save logs"),
+                                          GTK_WINDOW (user_data),
+                                          GTK_FILE_CHOOSER_ACTION_SAVE,
+                                          _("_Cancel"), GTK_RESPONSE_CANCEL,
+                                          _("_Save"), GTK_RESPONSE_ACCEPT,
+                                          NULL);
+
+    file_chooser = GTK_FILE_CHOOSER (dialog);
+    gtk_file_chooser_set_do_overwrite_confirmation (file_chooser, TRUE);
+    gtk_file_chooser_set_current_name (file_chooser, _("log messages"));
+
+    res = gtk_dialog_run (GTK_DIALOG (dialog));
+    if (res == GTK_RESPONSE_ACCEPT)
+    {
+        gboolean have_error = FALSE;
+        gchar *file_content;
+        GFile *output_file;
+        GFileOutputStream *file_ostream;
+        GError *error = NULL;
+        GtkWidget *error_dialog;
+
+        file_content = gl_event_view_get_output_logs (event);
+        output_file = gtk_file_chooser_get_file (file_chooser);
+        file_ostream = g_file_replace (output_file, NULL, TRUE,
+                                       G_FILE_CREATE_NONE, NULL, &error);
+        if (error != NULL)
+        {
+            have_error = TRUE;
+
+            g_warning ("Error while replacing exported log messages file: %s",
+                       error->message);
+            g_clear_error (&error);
+        }
+
+        g_output_stream_write (G_OUTPUT_STREAM (file_ostream), file_content,
+                               strlen (file_content), NULL, &error);
+        if (error != NULL)
+        {
+            have_error = TRUE;
+
+            g_warning ("Error while replacing exported log messages file: %s",
+                       error->message);
+            g_clear_error (&error);
+        }
+
+        g_output_stream_close (G_OUTPUT_STREAM (file_ostream), NULL, &error);
+        if (error != NULL)
+        {
+            have_error = TRUE;
+
+            g_warning ("Error while replacing exported log messages file: %s",
+                       error->message);
+            g_clear_error (&error);
+        }
+
+        if (have_error == TRUE)
+        {
+            error_dialog = gtk_message_dialog_new (GTK_WINDOW (user_data),
+                                                   GTK_DIALOG_MODAL,
+                                                   GTK_MESSAGE_ERROR,
+                                                   GTK_BUTTONS_CLOSE,
+                                                   "%s",
+                                                   _("Unable to export log messages to a file"));
+            gtk_dialog_run (GTK_DIALOG (error_dialog));
+            gtk_widget_destroy (error_dialog);
+        }
+
+        g_free (file_content);
+        g_object_unref (file_ostream);
+        g_object_unref (output_file);
+    }
+
+    gtk_widget_destroy (dialog);
+}
+
+static void
 on_view_boot (GSimpleAction *action,
               GVariant *variant,
               gpointer user_data)
@@ -275,6 +364,7 @@ static GActionEntry actions[] = {
     { "toolbar-mode", on_action_radio, "s", "'list'", on_toolbar_mode },
     { "search", on_action_toggle, NULL, "false", on_search },
     { "view-boot", on_action_radio, "s", "''", on_view_boot },
+    { "export", on_export },
     { "close", on_close }
 };
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]