[gnome-logs] Add journal timestamp range filters



commit ec6b654fea3466707efa421a0894ffc9834e3b19
Author: Pranav Ganorkar <pranavg189 gmail com>
Date:   Sun Jul 24 22:14:54 2016 +0530

    Add journal timestamp range filters
    
    The journal timestamp range filters in search popover can be
    used to set the timestamp range of journal model.The default
    journal timestamp range is the currently selected boot from
    the boot selection menu in toolbar.
    
    The query object was modified to include two
    new parameters for storing the start and end timestamps
    of the journal.
    
    The gl_journal_set_matches() function was modified to
    remove setting the boot match if no boot match is specified.
    
    The search popover range button label is made consistent when
    user selects boot through the toolbar boot selection menu.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=767996

 data/gl-searchpopover.ui |  183 +++++++++++++++++++++++++++++++++++++++++++++-
 src/gl-eventviewlist.c   |  150 ++++++++++++++++++++++++++++++++------
 src/gl-journal-model.c   |   39 ++++++++++-
 src/gl-journal-model.h   |    6 ++
 src/gl-journal.c         |   62 ++++++----------
 src/gl-journal.h         |    1 +
 src/gl-searchpopover.c   |  183 ++++++++++++++++++++++++++++++++++++++++++++++
 src/gl-searchpopover.h   |   12 +++
 8 files changed, 573 insertions(+), 63 deletions(-)
---
diff --git a/data/gl-searchpopover.ui b/data/gl-searchpopover.ui
index 7721383..0d4a9a8 100644
--- a/data/gl-searchpopover.ui
+++ b/data/gl-searchpopover.ui
@@ -142,6 +142,140 @@
                     </packing>
                 </child>
                 <child>
+                    <object class="GtkStack" id="range_label_stack">
+                        <property name="visible">True</property>
+                        <child>
+                            <object class="GtkLabel" id="when_dim_label">
+                                <property name="visible">True</property>
+                                <!-- Translators: When [log entries to be shown for a given timestamp range] 
-->
+                                <property name="label" translatable="yes">When</property>
+                                <property name="xalign">0</property>
+                                <style>
+                                    <class name="dim-label"/>
+                                </style>
+                            </object>
+                            <packing>
+                                <property name="name">when-label</property>
+                                <property name="title">page0</property>
+                            </packing>
+                        </child>
+                        <child>
+                            <object class="GtkLabel" id="show_logs_from_dim_label">
+                                <property name="visible">True</property>
+                                <property name="margin_top">10</property>
+                                <property name="label" translatable="yes">Show Logs from…</property>
+                                <property name="xalign">0</property>
+                                <style>
+                                    <class name="dim-label"/>
+                                </style>
+                            </object>
+                            <packing>
+                                <property name="name">show-log-from-label</property>
+                                <property name="title">page1</property>
+                                <property name="position">1</property>
+                            </packing>
+                        </child>
+                    </object>
+                    <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">2</property>
+                        <property name="width">2</property>
+                    </packing>
+                </child>
+                <child>
+                    <object class="GtkStack" id="range_stack">
+                        <property name="visible">True</property>
+                        <property name="vhomogeneous">False</property>
+                        <property name="transition_type">crossfade</property>
+                        <child>
+                            <object class="GtkButton" id="select_range_button">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="tooltip_text" translatable="yes">Select Timestamp Range of 
the Log Entries to be shown</property>
+                                <property name="hexpand">True</property>
+                                <signal name="clicked" handler="select_range_button_clicked"/>
+                                <child>
+                                    <object class="GtkBox">
+                                        <property name="visible">True</property>
+                                        <child>
+                                            <object class="GtkLabel" id="range_button_label">
+                                                <property name="visible">True</property>
+                                                <property name="label" translatable="yes">Current 
Boot</property>
+                                            </object>
+                                            <packing>
+                                                <property name="expand">False</property>
+                                                <property name="fill">True</property>
+                                                <property name="position">0</property>
+                                            </packing>
+                                        </child>
+                                        <child>
+                                            <object class="GtkImage" id="range_button_drop_down_image">
+                                                <property name="visible">True</property>
+                                                <property name="icon_name">pan-down-symbolic</property>
+                                            </object>
+                                            <packing>
+                                                <property name="expand">False</property>
+                                                <property name="fill">True</property>
+                                                <property name="pack_type">end</property>
+                                                <property name="position">1</property>
+                                            </packing>
+                                        </child>
+                                    </object>
+                                </child>
+                            </object>
+                            <packing>
+                                <property name="name">range-button</property>
+                            </packing>
+                        </child>
+                        <child>
+                            <object class="GtkScrolledWindow" id="range_scrolled_window">
+                                <property name="height_request">150</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="hexpand">True</property>
+                                <property name="shadow_type">in</property>
+                                <child>
+                                    <object class="GtkTreeView" id="range_treeview">
+                                        <property name="visible">True</property>
+                                        <property name="model">range_liststore</property>
+                                        <property name="headers-visible">False</property>
+                                        <property name="activate-on-single-click">True</property>
+                                        <signal name="row-activated" 
handler="on_range_treeview_row_activated"/>
+                                        <child>
+                                            <object class="GtkTreeViewColumn" id="range-column">
+                                                <property name="title">Parameters</property>
+                                                <property name="visible">True</property>
+                                                <child>
+                                                    <object class="GtkCellRendererText" 
id="range-text-renderer"/>
+                                                    <attributes>
+                                                        <attribute name="text">0</attribute>
+                                                    </attributes>
+                                                </child>
+                                            </object>
+                                        </child>
+                                        <child internal-child="selection">
+                                            <object class="GtkTreeSelection" id="range-selection">
+                                            <property name="mode">GTK_SELECTION_BROWSE</property>
+                                            </object>
+                                        </child>
+                                    </object>
+                                </child>
+                            </object>
+                            <packing>
+                                <property name="name">range-list</property>
+                                <property name="title">page0</property>
+                                <property name="position">1</property>
+                            </packing>
+                        </child>
+                    </object>
+                    <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">3</property>
+                        <property name="width">2</property>
+                    </packing>
+                </child>
+                <child>
                     <object class="GtkRevealer" id="search_type_revealer">
                         <child>
                             <object class="GtkBox">
@@ -219,7 +353,7 @@
                     </object>
                     <packing>
                         <property name="left_attach">0</property>
-                        <property name="top_attach">2</property>
+                        <property name="top_attach">4</property>
                         <property name="width">2</property>
                     </packing>
                 </child>
@@ -289,4 +423,51 @@
             </row>
         </data>
     </object>
+    <object class="GtkListStore" id="range_liststore">
+        <columns>
+            <column type="gchararray"/>
+            <column type="gboolean"/>
+            <column type="GlSearchPopoverJournalTimestampRange"/>
+        </columns>
+        <data>
+            <row>
+                <col id="0" translatable="yes">Current Boot</col>
+                <col id="1">False</col>
+                <col id="2">GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CURRENT_BOOT</col>
+            </row>
+            <row>
+                <col id="0" translatable="yes">Previous Boot</col>
+                <col id="1">False</col>
+                <col id="2">GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_PREVIOUS_BOOT</col>
+            </row>
+            <row>
+                <col id="0">Separator</col>
+                <col id="1">True</col>
+            </row>
+            <row>
+                <col id="0" translatable="yes">Today</col>
+                <col id="1">False</col>
+                <col id="2">GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_TODAY</col>
+            </row>
+            <row>
+                <col id="0" translatable="yes">Yesterday</col>
+                <col id="1">False</col>
+                <col id="2">GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_YESTERDAY</col>
+            </row>
+            <row>
+                <col id="0" translatable="yes">Last 3 days</col>
+                <col id="1">False</col>
+                <col id="2">GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_LAST_3_DAYS</col>
+            </row>
+            <row>
+                <col id="0">Separator</col>
+                <col id="1">True</col>
+            </row>
+            <row>
+                <col id="0" translatable="yes">Entire Journal</col>
+                <col id="1">False</col>
+                <col id="2">GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_ENTIRE_JOURNAL</col>
+            </row>
+        </data>
+    </object>
 </interface>
diff --git a/src/gl-eventviewlist.c b/src/gl-eventviewlist.c
index 22fcc83..6ed73a5 100644
--- a/src/gl-eventviewlist.c
+++ b/src/gl-eventviewlist.c
@@ -52,8 +52,10 @@ typedef struct
     GtkWidget *event_scrolled;
     GtkWidget *search_entry;
     GtkWidget *search_dropdown_button;
+    GtkWidget *search_popover;
     GlSearchPopoverJournalFieldFilter journal_search_field;
     GlQuerySearchType search_type;
+    GlSearchPopoverJournalTimestampRange journal_timestamp_range;
     gchar *search_text;
     const gchar *boot_match;
 } GlEventViewListPrivate;
@@ -377,18 +379,10 @@ get_current_boot_id (const gchar *boot_match)
 
 static void
 query_add_category_matches (GlQuery *query,
-                            GlCategoryList *list,
-                            const gchar *boot_match)
+                            GlCategoryList *list)
 {
-    gchar *boot_id;
     GlCategoryListFilter filter;
 
-    /* Get current boot id */
-    boot_id = get_current_boot_id (boot_match);
-
-    /* Add boot match for all the categories */
-    gl_query_add_match (query, "_BOOT_ID", boot_id, GL_QUERY_SEARCH_TYPE_EXACT);
-
     /* Add exact matches according to selected category */
     filter = gl_category_list_get_category (list);
 
@@ -449,8 +443,6 @@ query_add_category_matches (GlQuery *query,
         default:
             g_assert_not_reached ();
     }
-
-    g_free (boot_id);
 }
 
 static void
@@ -502,6 +494,99 @@ query_add_search_matches (GlQuery *query,
     }
 }
 
+static void
+query_set_day_timestamps (GlQuery *query,
+                          gint start_day_offset,
+                          gint end_day_offset)
+{
+    GDateTime *now;
+    GDateTime *today_start;
+    GDateTime *today_end;
+    guint64 start_timestamp;
+    guint64 end_timestamp;
+
+    now = g_date_time_new_now_local();
+
+    today_start = g_date_time_new_local (g_date_time_get_year (now),
+                                         g_date_time_get_month (now),
+                                         g_date_time_get_day_of_month (now) - start_day_offset,
+                                         23,
+                                         59,
+                                         59.0);
+
+    start_timestamp = g_date_time_to_unix (today_start) * G_USEC_PER_SEC;
+
+    today_end = g_date_time_new_local (g_date_time_get_year (now),
+                                       g_date_time_get_month (now),
+                                       g_date_time_get_day_of_month (now) - end_day_offset,
+                                       0,
+                                       0,
+                                       0.0);
+
+    end_timestamp = g_date_time_to_unix (today_end) * G_USEC_PER_SEC;
+
+    gl_query_set_journal_timestamp_range (query, start_timestamp, end_timestamp);
+
+    g_date_time_unref (now);
+    g_date_time_unref (today_start);
+    g_date_time_unref (today_end);
+}
+
+static void
+query_add_journal_range_filter (GlQuery *query,
+                                GlEventViewList *view)
+{
+    GlEventViewListPrivate *priv;
+
+    priv = gl_event_view_list_get_instance_private (view);
+    /* Add range filters */
+    switch (priv->journal_timestamp_range)
+    {
+        case GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CURRENT_BOOT:
+        {
+            /* Get current boot id */
+            gchar *boot_match;
+
+            boot_match = get_current_boot_id (priv->boot_match);
+            gl_query_add_match (query, "_BOOT_ID", boot_match, GL_QUERY_SEARCH_TYPE_EXACT);
+
+            g_free (boot_match);
+        }
+            break;
+        case GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_PREVIOUS_BOOT:
+        {
+            GArray *boot_ids;
+            GlJournalBootID *boot_id;
+
+            boot_ids = gl_event_view_list_get_boot_ids (view);
+
+            boot_id = &g_array_index (boot_ids, GlJournalBootID, boot_ids->len - 2);
+
+            gl_query_set_journal_timestamp_range (query, boot_id->realtime_last, boot_id->realtime_first);
+        }
+            break;
+        case GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_TODAY:
+
+            query_set_day_timestamps (query, 0, 0);
+
+            break;
+        case GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_YESTERDAY:
+
+            query_set_day_timestamps (query, 1, 1);
+
+            break;
+        case GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_LAST_3_DAYS:
+
+            query_set_day_timestamps (query, 0, 2);
+
+            break;
+        default:
+
+            /* By default, search the entire journal */
+            break;
+    }
+}
+
 /* Create query object according to selected category */
 static GlQuery *
 create_query_object (GlEventViewList *view)
@@ -516,7 +601,10 @@ create_query_object (GlEventViewList *view)
     /* Create new query object */
     query = gl_query_new ();
 
-    query_add_category_matches (query, list, priv->boot_match);
+    /* Set journal timestamp range */
+    query_add_journal_range_filter (query, view);
+
+    query_add_category_matches (query, list);
 
     query_add_search_matches (query, priv->search_text, priv->journal_search_field, priv->search_type);
 
@@ -555,15 +643,17 @@ void
 gl_event_view_list_view_boot (GlEventViewList *view, const gchar *match)
 {
     GlEventViewListPrivate *priv;
-    GlCategoryList *categories;
+    GlSearchPopover *popover;
 
     g_return_if_fail (GL_EVENT_VIEW_LIST (view));
 
     priv = gl_event_view_list_get_instance_private (view);
-    categories = GL_CATEGORY_LIST (priv->categories);
+    popover = GL_SEARCH_POPOVER (priv->search_popover);
     priv->boot_match = match;
 
-    on_notify_category (categories, NULL, view);
+    /* Make search popover journal timestamp range label consistent with
+       event-toolbar boot selection menu */
+    gl_search_popover_set_journal_timestamp_range_current_boot (popover);
 }
 
 static gint
@@ -744,30 +834,46 @@ search_popover_search_type_changed (GlSearchPopover *popover,
     gl_journal_model_take_query (priv->journal_model, query);
 }
 
+static void
+search_popover_journal_timestamp_range_changed (GlSearchPopover *popover,
+                                                GParamSpec *psec,
+                                                GlEventViewList *view)
+{
+    GlEventViewListPrivate *priv = gl_event_view_list_get_instance_private (view);
+    GlQuery *query;
+
+    priv->journal_timestamp_range = gl_search_popover_get_journal_timestamp_range (popover);
+
+    query = create_query_object (view);
+
+    gl_journal_model_take_query (priv->journal_model, query);
+}
+
 /* Get the view elements from ui file and link it with the drop down button */
 static void
 set_up_search_popover (GlEventViewList *view)
 {
 
     GlEventViewListPrivate *priv;
-    GtkWidget *search_popover;
 
     priv = gl_event_view_list_get_instance_private (view);
 
-    search_popover = gl_search_popover_new ();
+    priv->search_popover = gl_search_popover_new ();
 
     /* Grab/Remove keyboard focus from popover menu when it is opened or closed */
-    g_signal_connect (search_popover, "show", (GCallback) gtk_widget_grab_focus, NULL);
-    g_signal_connect_swapped (search_popover, "closed", (GCallback) gtk_widget_grab_focus, view);
+    g_signal_connect (priv->search_popover, "show", (GCallback) gtk_widget_grab_focus, NULL);
+    g_signal_connect_swapped (priv->search_popover, "closed", (GCallback) gtk_widget_grab_focus, view);
 
-    g_signal_connect (search_popover, "notify::journal-search-field",
+    g_signal_connect (priv->search_popover, "notify::journal-search-field",
                       G_CALLBACK (search_popover_journal_search_field_changed), view);
-    g_signal_connect (search_popover, "notify::search-type",
+    g_signal_connect (priv->search_popover, "notify::search-type",
                       G_CALLBACK (search_popover_search_type_changed), view);
+    g_signal_connect (priv->search_popover, "notify::journal-timestamp-range",
+                      G_CALLBACK (search_popover_journal_timestamp_range_changed), view);
 
     /* Link the drop down button with search popover */
     gtk_menu_button_set_popover (GTK_MENU_BUTTON (priv->search_dropdown_button),
-                                 search_popover);
+                                 priv->search_popover);
 }
 
 static void
diff --git a/src/gl-journal-model.c b/src/gl-journal-model.c
index 73d9f3a..7b6f1b2 100644
--- a/src/gl-journal-model.c
+++ b/src/gl-journal-model.c
@@ -45,6 +45,7 @@ struct _GlJournalModel
 
 static void gl_journal_model_interface_init (GListModelInterface *iface);
 static gboolean search_in_entry (GlJournalEntry *entry, GlQuery *query);
+static gboolean gl_query_check_journal_end (GlQuery *query, GlJournalEntry *entry);
 
 G_DEFINE_TYPE_WITH_CODE (GlJournalModel, gl_journal_model, G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gl_journal_model_interface_init))
@@ -76,7 +77,7 @@ gl_journal_model_fetch_idle (gpointer user_data)
     g_assert (model->n_entries_to_fetch > 0);
 
     last = model->entries->len;
-    if ((entry = gl_journal_previous (model->journal)))
+    if ((entry = gl_journal_previous (model->journal)) && gl_query_check_journal_end (model->query, entry))
     {
         if (search_in_entry (entry, model->query))
         {
@@ -246,6 +247,8 @@ gl_query_new (void)
 
     query->queryitems = g_ptr_array_new_with_free_func ((GDestroyNotify) gl_query_item_free);
     query->search_type = GL_QUERY_SEARCH_TYPE_SUBSTRING;
+    query->start_timestamp = 0;
+    query->end_timestamp = 0;
 
     return query;
 }
@@ -364,6 +367,8 @@ gl_journal_model_process_query (GlJournalModel *model)
 
     gl_journal_set_matches (model->journal, category_matches);
 
+    gl_journal_set_start_position (model->journal, model->query->start_timestamp);
+
     /* Start re-population of the journal */
     gl_journal_model_fetch_more_entries (model, FALSE);
 
@@ -425,6 +430,38 @@ gl_query_add_match (GlQuery *query,
     g_ptr_array_add (query->queryitems, queryitem);
 }
 
+/* Check if current entry timestamp is less than the end timestamp */
+static gboolean
+gl_journal_entry_check_journal_end (GlJournalEntry *entry,
+                                    guint64 end_timestamp)
+{
+    guint64 entry_timestamp = gl_journal_entry_get_timestamp (entry);
+
+    if (end_timestamp)
+    {
+        /* Check if we have reached the end of given journal range */
+        if (end_timestamp >= entry_timestamp)
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+static gboolean
+gl_query_check_journal_end (GlQuery *query, GlJournalEntry *entry)
+{
+    return gl_journal_entry_check_journal_end (entry, query->end_timestamp);
+}
+
+void
+gl_query_set_journal_timestamp_range (GlQuery *query,
+                                      guint64 start_timestamp,
+                                      guint64 end_timestamp)
+{
+    query->start_timestamp = start_timestamp;
+    query->end_timestamp = end_timestamp;
+}
+
 static gboolean
 is_string_case_sensitive (const gchar *user_text)
 {
diff --git a/src/gl-journal-model.h b/src/gl-journal-model.h
index 7b42de6..110c150 100644
--- a/src/gl-journal-model.h
+++ b/src/gl-journal-model.h
@@ -32,6 +32,8 @@ typedef struct GlQuery
 {
     GPtrArray *queryitems;   /* array of GlQueryItem structs */
     GlQuerySearchType search_type;    /* indicates if search field is passed as exact match */
+    guint64 start_timestamp;
+    guint64 end_timestamp;
 } GlQuery;
 
 #define GL_TYPE_JOURNAL_MODEL gl_journal_model_get_type()
@@ -49,6 +51,10 @@ void                    gl_query_add_match                              (GlQuery
                                                                          const gchar *field_value,
                                                                          GlQuerySearchType search_type);
 
+void                    gl_query_set_journal_timestamp_range            (GlQuery *query,
+                                                                         guint64 start_timestamp,
+                                                                         guint64 end_timestamp);
+
 void                    gl_journal_model_set_matches                    (GlJournalModel      *model,
                                                                          const gchar * const *matches);
 
diff --git a/src/gl-journal.c b/src/gl-journal.c
index 05aeaff..a8cddaa 100644
--- a/src/gl-journal.c
+++ b/src/gl-journal.c
@@ -569,24 +569,6 @@ gl_journal_query_match (sd_journal          *journal,
   return TRUE;
 }
 
-static gchar *
-create_boot_id_match_string (void)
-{
-    sd_id128_t boot_id;
-    gchar boot_string[33];
-    int r;
-
-    r = sd_id128_get_boot (&boot_id);
-    if (r < 0)
-    {
-        g_warning ("Error getting boot ID of running kernel: %s", g_strerror (-r));
-        return NULL;
-    }
-
-    sd_id128_to_string (boot_id, boot_string);
-    return g_strconcat ("_BOOT_ID=", boot_string, NULL);
-}
-
 /**
  * gl_journal_set_matches:
  * @journal: a #GlJournal
@@ -603,7 +585,6 @@ gl_journal_set_matches (GlJournal *journal,
     GPtrArray *mandatory_fields;
     int r;
     gint i;
-    gboolean has_boot_id = FALSE;
 
     g_return_if_fail (matches != NULL);
 
@@ -629,9 +610,6 @@ gl_journal_set_matches (GlJournal *journal,
             continue;
         }
 
-        if (g_str_has_prefix (match, "_BOOT_ID="))
-          has_boot_id = TRUE;
-
         r = sd_journal_add_match (priv->journal, match, 0);
         if (r < 0)
         {
@@ -643,27 +621,33 @@ gl_journal_set_matches (GlJournal *journal,
     /* add sentinel */
     g_ptr_array_add (mandatory_fields, NULL);
 
-    /* take events from this boot only, unless _BOOT_ID was in @matches */
-    if (!has_boot_id)
-    {
-        gchar *boot_match;
+    priv->mandatory_fields = (gchar **) g_ptr_array_free (mandatory_fields, FALSE);
+}
 
-        boot_match = create_boot_id_match_string ();
-        if (boot_match)
-        {
-            r = sd_journal_add_match (priv->journal, boot_match, 0);
-            if (r < 0)
-                g_warning ("Failed to add match '%s': %s", boot_match, g_strerror (-r));
+/* Sets the starting position of journal from which to start reading the entries */
+void
+gl_journal_set_start_position (GlJournal *journal,
+                               guint64 start_timestamp)
+{
+    GlJournalPrivate *priv = gl_journal_get_instance_private (journal);
+    gint r;
 
-            g_free (boot_match);
+    if (start_timestamp)
+    {
+        r = sd_journal_seek_realtime_usec (priv->journal, start_timestamp);
+        if (r < 0)
+        {
+            g_warning ("Error seeking to given timestamp %" G_GUINT64_FORMAT ": %s", start_timestamp, 
g_strerror (-r));
+        }
+    }
+    else
+    {
+        r = sd_journal_seek_tail (priv->journal);
+        if (r < 0)
+        {
+            g_warning ("Error seeking to start of systemd journal: %s", g_strerror (-r));
         }
     }
-
-    priv->mandatory_fields = (gchar **) g_ptr_array_free (mandatory_fields, FALSE);
-
-    r = sd_journal_seek_tail (priv->journal);
-    if (r < 0)
-        g_warning ("Error seeking to start of systemd journal: %s", g_strerror (-r));
 }
 
 GlJournalEntry *
diff --git a/src/gl-journal.h b/src/gl-journal.h
index c140703..648ecb0 100644
--- a/src/gl-journal.h
+++ b/src/gl-journal.h
@@ -72,6 +72,7 @@ typedef struct
 GType gl_journal_result_get_type (void);
 GType gl_journal_get_type (void);
 void gl_journal_set_matches (GlJournal *journal, GPtrArray *matches);
+void gl_journal_set_start_position (GlJournal *journal, guint64 until_timestamp);
 GArray * gl_journal_get_boot_ids (GlJournal *journal);
 GlJournalEntry * gl_journal_previous (GlJournal *journal);
 GlJournal * gl_journal_new (void);
diff --git a/src/gl-searchpopover.c b/src/gl-searchpopover.c
index d153260..bcf6b7c 100644
--- a/src/gl-searchpopover.c
+++ b/src/gl-searchpopover.c
@@ -36,9 +36,17 @@ typedef struct
     GtkWidget *parameter_treeview;
     GtkListStore *parameter_liststore;
     GtkWidget *search_type_revealer;
+    GtkWidget *range_stack;
+    GtkWidget *range_label_stack;
+    GtkWidget *range_treeview;
+    GtkWidget *range_button_label;
+    GtkWidget *clear_range_button;
+    GtkWidget *range_button_drop_down_image;
+    GtkListStore *range_liststore;
 
     GlSearchPopoverJournalFieldFilter journal_search_field;
     GlQuerySearchType search_type;
+    GlSearchPopoverJournalTimestampRange journal_timestamp_range;
 } GlSearchPopoverPrivate;
 
 enum
@@ -46,6 +54,7 @@ enum
     PROP_0,
     PROP_JOURNAL_SEARCH_FIELD,
     PROP_SEARCH_TYPE,
+    PROP_JOURNAL_TIMESTAMP_RANGE,
     N_PROPERTIES
 };
 
@@ -57,6 +66,14 @@ enum
     JOURNAL_FIELD_N_COLUMNS
 };
 
+enum
+{
+    COLUMN_JOURNAL_TIMESTAMP_RANGE_LABEL,
+    COLUMN_JOURNAL_TIMESTAMP_RANGE_SHOW_SEPARATOR,
+    COLUMN_JOURNAL_TIMESTAMP_RANGE_ENUM_VALUE,
+    JOURNAL_TIMESTAMP_RANGE_N_COLUMNS
+};
+
 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
 
 G_DEFINE_TYPE_WITH_PRIVATE (GlSearchPopover, gl_search_popover, GTK_TYPE_POPOVER)
@@ -72,6 +89,9 @@ search_popover_closed (GtkPopover *popover,
 
     gtk_stack_set_visible_child_name (GTK_STACK (priv->parameter_stack), "parameter-button");
     gtk_stack_set_visible_child_name (GTK_STACK (priv->parameter_label_stack), "what-label");
+
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->range_stack), "range-button");
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->range_label_stack), "when-label");
 }
 
 static void
@@ -89,6 +109,9 @@ select_parameter_button_clicked (GtkButton *button,
     gtk_stack_set_visible_child_name (GTK_STACK (priv->parameter_stack), "parameter-list");
     gtk_stack_set_visible_child_name (GTK_STACK (priv->parameter_label_stack), "select-parameter-label");
 
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->range_stack), "range-button");
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->range_label_stack), "when-label");
+
     model = GTK_TREE_MODEL (priv->parameter_liststore);
 
     valid = gtk_tree_model_get_iter_first (model, &iter);
@@ -228,6 +251,16 @@ gl_search_popover_get_query_search_type (GlSearchPopover *popover)
     return priv->search_type;
 }
 
+GlSearchPopoverJournalTimestampRange
+gl_search_popover_get_journal_timestamp_range (GlSearchPopover *popover)
+{
+    GlSearchPopoverPrivate *priv;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    return priv->journal_timestamp_range;
+}
+
 static void
 gl_search_popover_get_property (GObject *object,
                                 guint prop_id,
@@ -245,6 +278,9 @@ gl_search_popover_get_property (GObject *object,
         case PROP_SEARCH_TYPE:
             g_value_set_enum (value, priv->search_type);
             break;
+        case PROP_JOURNAL_TIMESTAMP_RANGE:
+            g_value_set_enum (value, priv->journal_timestamp_range);
+            break;
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
             break;
@@ -268,6 +304,9 @@ gl_search_popover_set_property (GObject *object,
         case PROP_SEARCH_TYPE:
             priv->search_type = g_value_get_enum (value);
             break;
+        case PROP_JOURNAL_TIMESTAMP_RANGE:
+            priv->journal_timestamp_range = g_value_get_enum (value);
+            break;
         default:
             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
             break;
@@ -275,6 +314,122 @@ gl_search_popover_set_property (GObject *object,
 }
 
 static void
+select_range_button_clicked (GtkButton *button,
+                             gpointer user_data)
+{
+    GlSearchPopoverPrivate *priv;
+    GtkTreeSelection *selection;
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    gboolean valid;
+
+    priv = gl_search_popover_get_instance_private (GL_SEARCH_POPOVER (user_data));
+
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->range_stack), "range-list");
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->range_label_stack), "show-log-from-label");
+
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->parameter_stack), "parameter-button");
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->parameter_label_stack), "what-label");
+
+    model = GTK_TREE_MODEL (priv->range_liststore);
+
+    valid = gtk_tree_model_get_iter_first (model, &iter);
+
+    while (valid)
+    {
+        GlSearchPopoverJournalTimestampRange journal_range_enum_value;
+
+        gtk_tree_model_get (GTK_TREE_MODEL (priv->range_liststore), &iter,
+                            COLUMN_JOURNAL_TIMESTAMP_RANGE_ENUM_VALUE, &journal_range_enum_value,
+                            -1);
+
+        if (priv->journal_timestamp_range == journal_range_enum_value)
+        {
+            break;
+        }
+
+        valid = gtk_tree_model_iter_next (model, &iter);
+    }
+
+    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->range_treeview));
+
+    gtk_tree_selection_select_iter (selection, &iter);
+}
+
+static gboolean
+range_treeview_row_seperator (GtkTreeModel *model,
+                              GtkTreeIter *iter,
+                              gpointer user_data)
+{
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+    gboolean show_seperator;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    gtk_tree_model_get (GTK_TREE_MODEL (priv->range_liststore), iter,
+                        COLUMN_JOURNAL_TIMESTAMP_RANGE_SHOW_SEPARATOR, &show_seperator,
+                        -1);
+
+    return show_seperator;
+}
+
+static void
+on_range_treeview_row_activated (GtkTreeView *tree_view,
+                                 GtkTreePath *path,
+                                 GtkTreeViewColumn *column,
+                                 gpointer user_data)
+{
+    GtkTreeIter iter;
+    gchar *range_label;
+    GlSearchPopoverJournalTimestampRange journal_range_enum_value;
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->range_liststore), &iter, path);
+
+    gtk_tree_model_get (GTK_TREE_MODEL (priv->range_liststore), &iter,
+                        COLUMN_JOURNAL_TIMESTAMP_RANGE_LABEL, &range_label,
+                        COLUMN_JOURNAL_TIMESTAMP_RANGE_ENUM_VALUE, &journal_range_enum_value,
+                        -1);
+
+    priv->journal_timestamp_range = journal_range_enum_value;
+
+    gtk_label_set_label (GTK_LABEL (priv->range_button_label),
+                         _(range_label));
+
+    g_object_notify_by_pspec (G_OBJECT (popover),
+                              obj_properties[PROP_JOURNAL_TIMESTAMP_RANGE]);
+
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->range_stack), "range-button");
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->range_label_stack), "when-label");
+
+    g_free (range_label);
+}
+
+void
+gl_search_popover_set_journal_timestamp_range_current_boot (GlSearchPopover *popover)
+{
+    GlSearchPopoverPrivate *priv;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    priv->journal_timestamp_range = GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CURRENT_BOOT;
+
+    g_object_notify_by_pspec (G_OBJECT (popover),
+                              obj_properties[PROP_JOURNAL_TIMESTAMP_RANGE]);
+
+    gtk_label_set_label (GTK_LABEL (priv->range_button_label),
+                         _("Current Boot"));
+}
+
+static void
 gl_search_popover_class_init (GlSearchPopoverClass *klass)
 {
     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
@@ -297,6 +452,13 @@ gl_search_popover_class_init (GlSearchPopoverClass *klass)
                                                           G_PARAM_READWRITE |
                                                           G_PARAM_STATIC_STRINGS);
 
+    obj_properties[PROP_JOURNAL_TIMESTAMP_RANGE] = g_param_spec_enum ("journal-timestamp-range", "Journal 
Timestamp Range",
+                                                                      "The Timestamp range of the logs to be 
shown",
+                                                                      
GL_TYPE_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE,
+                                                                      
GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CURRENT_BOOT,
+                                                                      G_PARAM_READWRITE |
+                                                                      G_PARAM_STATIC_STRINGS);
+
     g_object_class_install_properties (gobject_class, N_PROPERTIES,
                                        obj_properties);
 
@@ -314,6 +476,18 @@ gl_search_popover_class_init (GlSearchPopoverClass *klass)
                                                   parameter_liststore);
     gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
                                                   search_type_revealer);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  range_stack);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  range_label_stack);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  range_treeview);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  range_button_label);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  range_button_drop_down_image);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  range_liststore);
 
 
     gtk_widget_class_bind_template_callback (widget_class,
@@ -324,6 +498,10 @@ gl_search_popover_class_init (GlSearchPopoverClass *klass)
                                              on_parameter_treeview_row_activated);
     gtk_widget_class_bind_template_callback (widget_class,
                                              search_type_changed);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             select_range_button_clicked);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             on_range_treeview_row_activated);
 }
 
 static void
@@ -339,6 +517,11 @@ gl_search_popover_init (GlSearchPopover *popover)
                                           (GtkTreeViewRowSeparatorFunc) parameter_treeview_row_seperator,
                                           popover,
                                           NULL);
+
+    gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (priv->range_treeview),
+                                          (GtkTreeViewRowSeparatorFunc) range_treeview_row_seperator,
+                                          popover,
+                                          NULL);
 }
 
 GtkWidget *
diff --git a/src/gl-searchpopover.h b/src/gl-searchpopover.h
index d4a9cab..cd44cb4 100644
--- a/src/gl-searchpopover.h
+++ b/src/gl-searchpopover.h
@@ -39,12 +39,24 @@ typedef enum
     GL_SEARCH_POPOVER_JOURNAL_FIELD_FILTER_EXECUTABLE_PATH
 } GlSearchPopoverJournalFieldFilter;
 
+typedef enum
+{
+    GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CURRENT_BOOT,
+    GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_PREVIOUS_BOOT,
+    GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_TODAY,
+    GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_YESTERDAY,
+    GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_LAST_3_DAYS,
+    GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_ENTIRE_JOURNAL
+} GlSearchPopoverJournalTimestampRange;
+
 #define GL_TYPE_SEARCH_POPOVER (gl_search_popover_get_type ())
 G_DECLARE_FINAL_TYPE (GlSearchPopover, gl_search_popover, GL, SEARCH_POPOVER, GtkPopover)
 
 GtkWidget * gl_search_popover_new (void);
 GlSearchPopoverJournalFieldFilter gl_search_popover_get_journal_search_field (GlSearchPopover *popover);
 GlQuerySearchType gl_search_popover_get_query_search_type (GlSearchPopover *popover);
+GlSearchPopoverJournalTimestampRange gl_search_popover_get_journal_timestamp_range (GlSearchPopover 
*popover);
+void gl_search_popover_set_journal_timestamp_range_current_boot (GlSearchPopover *popover);
 
 G_END_DECLS
 



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