[gnome-logs] Add custom journal timestamp range submenu



commit 9eb24061bc6d2ed745ba2996e46e30e7b4ac3d18
Author: Pranav Ganorkar <pranavg189 gmail com>
Date:   Sun Aug 14 18:39:22 2016 +0530

    Add custom journal timestamp range submenu
    
    The custom timestamp range submenu is opened through the select
    timestamp range treeview.
    
    If the user doesn't specify any date, then today's date is taken as
    default. If the user doesn't specify any time, then 11:59:59 PM is
    taken as default start time and 12:00:00 AM is taken default end time.
    This is done so that if the user selects the same date in both the
    start and end date selection widgets, all the logs corresponding to
    that date will be shown in the window.
    
    The journal is filtered according to the entered start date-time and
    end date-time timestamp range and the logs are shown in window
    accordingly.
    
    Invalid values in time spinboxes are set to nearest correct values.
    Future dates fail silently.
    
    If the user selects any other filter, then the options
    in the custom timestamp range submenu are reset.
    
    Depending upon whether the user has selected start date-time
    or end date-time, we update the timestamp range button label
    accordingly.
    
    If time zone format is 24hr, we show only the hour-minute-second
    spinboxes in the custom timestamp range submenu.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=767996

 data/gl-searchpopover.ui | 1192 +++++++++++++++++++++++++++++++++++++---------
 src/gl-eventviewlist.c   |   14 +
 src/gl-searchpopover.c   |  987 ++++++++++++++++++++++++++++++++++++++-
 src/gl-searchpopover.h   |    5 +-
 4 files changed, 1959 insertions(+), 239 deletions(-)
---
diff --git a/data/gl-searchpopover.ui b/data/gl-searchpopover.ui
index 0d4a9a8..b3257b9 100644
--- a/data/gl-searchpopover.ui
+++ b/data/gl-searchpopover.ui
@@ -2,206 +2,301 @@
     <template class="GlSearchPopover" parent="GtkPopover">
         <signal name="closed" handler="search_popover_closed"/>
         <child>
-            <object class="GtkGrid" id="popover_grid">
+            <object class="GtkStack" id="menu_stack">
                 <property name="visible">True</property>
-                <property name="border_width">20</property>
-                <property name="row_spacing">8</property>
-                <property name="column_spacing">18</property>
+                <property name="vhomogeneous">False</property>
+                <property name="transition_duration">250</property>
+                <property name="transition_type">GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT</property>
                 <child>
-                    <object class="GtkStack" id="parameter_stack">
+                    <object class="GtkGrid" id="popover_grid">
                         <property name="visible">True</property>
-                        <property name="vhomogeneous">False</property>
-                        <property name="transition_type">crossfade</property>
+                        <property name="border_width">20</property>
+                        <property name="row_spacing">8</property>
+                        <property name="column_spacing">18</property>
                         <child>
-                            <object class="GtkButton" id="select_parameter_button">
+                            <object class="GtkStack" id="parameter_stack">
                                 <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">True</property>
-                                <property name="tooltip_text" translatable="yes">Select a Journal Field to 
filter the Logs according to it</property>
-                                <signal name="clicked" handler="select_parameter_button_clicked"/>
-                                    <child>
-                                        <object class="GtkBox" id="parameter_filter_box">
-                                            <property name="visible">True</property>
-                                            <child>
-                                                <object class="GtkLabel" id="parameter_button_label">
-                                                    <property name="visible">True</property>
-                                                    <property name="hexpand">True</property>
-                                                    <property name="label" translatable="yes">All Available 
Fields</property>
-                                                    <property name="width_chars">30</property>
-                                                    <property name="xalign">0</property>
-                                                </object>
-                                                <packing>
-                                                    <property name="expand">False</property>
-                                                    <property name="fill">True</property>
-                                                    <property name="position">0</property>
-                                                </packing>
-                                            </child>
+                                <property name="vhomogeneous">False</property>
+                                <property name="transition_type">crossfade</property>
+                                <child>
+                                    <object class="GtkButton" id="select_parameter_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 a Journal 
Field to filter the Logs according to it</property>
+                                        <signal name="clicked" handler="select_parameter_button_clicked"/>
                                             <child>
-                                                <object class="GtkImage" id="parameter_button_image">
+                                                <object class="GtkBox" id="parameter_filter_box">
                                                     <property name="visible">True</property>
-                                                    <property name="icon_name">pan-down-symbolic</property>
+                                                    <child>
+                                                        <object class="GtkLabel" id="parameter_button_label">
+                                                            <property name="visible">True</property>
+                                                            <property name="hexpand">True</property>
+                                                            <property name="label" translatable="yes">All 
Available Fields</property>
+                                                            <property name="width_chars">30</property>
+                                                            <property name="xalign">0</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="parameter_button_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="position">1</property>
+                                                        </packing>
+                                                    </child>
                                                 </object>
-                                                <packing>
-                                                    <property name="expand">False</property>
-                                                    <property name="fill">True</property>
-                                                    <property name="position">1</property>
-                                                </packing>
                                             </child>
-                                        </object>
-                                    </child>
-                            </object>
-                            <packing>
-                                <property name="name">parameter-button</property>
-                            </packing>
-                        </child>
-                        <child>
-                            <object class="GtkScrolledWindow" id="parameter_scrolled_window">
-                                <property name="height_request">150</property>
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="shadow_type">in</property>
+                                    </object>
+                                    <packing>
+                                        <property name="name">parameter-button</property>
+                                    </packing>
+                                </child>
                                 <child>
-                                    <object class="GtkTreeView" id="parameter_treeview">
+                                    <object class="GtkScrolledWindow" id="parameter_scrolled_window">
+                                        <property name="height_request">150</property>
                                         <property name="visible">True</property>
-                                        <property name="model">parameter_liststore</property>
-                                        <property name="headers-visible">False</property>
-                                        <property name="activate-on-single-click">True</property>
-                                        <signal name="row-activated" 
handler="on_parameter_treeview_row_activated"/>
+                                        <property name="can_focus">True</property>
+                                        <property name="shadow_type">in</property>
                                         <child>
-                                            <object class="GtkTreeViewColumn" id="parameter-column">
-                                                <property name="title">Parameters</property>
+                                            <object class="GtkTreeView" id="parameter_treeview">
                                                 <property name="visible">True</property>
+                                                <property name="model">parameter_liststore</property>
+                                                <property name="headers-visible">False</property>
+                                                <property name="activate-on-single-click">True</property>
+                                                <signal name="row-activated" 
handler="on_parameter_treeview_row_activated"/>
                                                 <child>
-                                                    <object class="GtkCellRendererText" id="test-renderer"/>
-                                                    <attributes>
-                                                        <attribute name="text">0</attribute>
-                                                    </attributes>
+                                                    <object class="GtkTreeViewColumn" id="parameter-column">
+                                                        <property name="title">Parameters</property>
+                                                        <property name="visible">True</property>
+                                                        <child>
+                                                            <object class="GtkCellRendererText" 
id="test-renderer"/>
+                                                            <attributes>
+                                                                <attribute name="text">0</attribute>
+                                                            </attributes>
+                                                        </child>
+                                                    </object>
+                                                </child>
+                                                <child internal-child="selection">
+                                                    <object class="GtkTreeSelection" id="selection">
+                                                    <property name="mode">GTK_SELECTION_BROWSE</property>
+                                                    </object>
                                                 </child>
-                                            </object>
-                                        </child>
-                                        <child internal-child="selection">
-                                            <object class="GtkTreeSelection" id="selection">
-                                            <property name="mode">GTK_SELECTION_BROWSE</property>
                                             </object>
                                         </child>
                                     </object>
+                                    <packing>
+                                        <property name="name">parameter-list</property>
+                                        <property name="position">1</property>
+                                    </packing>
                                 </child>
                             </object>
                             <packing>
-                                <property name="name">parameter-list</property>
-                                <property name="position">1</property>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">1</property>
+                                <property name="width">2</property>
                             </packing>
                         </child>
-                    </object>
-                    <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">1</property>
-                        <property name="width">2</property>
-                    </packing>
-                </child>
-                <child>
-                    <object class="GtkStack" id="parameter_label_stack">
-                        <property name="visible">True</property>
                         <child>
-                            <object class="GtkLabel" id="what_dim_label">
+                            <object class="GtkStack" id="parameter_label_stack">
                                 <property name="visible">True</property>
-                                <property name="margin_top">10</property>
-                                <!-- Translators: What [journal fields to search in] -->
-                                <property name="label" translatable="yes">What</property>
-                                <property name="xalign">0</property>
-                                <style>
-                                  <class name="dim-label"/>
-                                </style>
-                            </object>
-                            <packing>
-                                <property name="name">what-label</property>
-                                <property name="title">page0</property>
-                            </packing>
-                        </child>
-                        <child>
-                            <object class="GtkLabel" id="select_parameter_dim_label">
-                                <property name="visible">True</property>
-                                <property name="margin_top">10</property>
-                                <property name="label" translatable="yes">Select Journal Field…</property>
-                                <property name="xalign">0</property>
-                                <style>
-                                  <class name="dim-label"/>
-                                </style>
+                                <child>
+                                    <object class="GtkLabel" id="what_dim_label">
+                                        <property name="visible">True</property>
+                                        <property name="margin_top">10</property>
+                                        <!-- Translators: What [journal fields to search in] -->
+                                        <property name="label" translatable="yes">What</property>
+                                        <property name="xalign">0</property>
+                                        <style>
+                                          <class name="dim-label"/>
+                                        </style>
+                                    </object>
+                                    <packing>
+                                        <property name="name">what-label</property>
+                                        <property name="title">page0</property>
+                                    </packing>
+                                </child>
+                                <child>
+                                    <object class="GtkLabel" id="select_parameter_dim_label">
+                                        <property name="visible">True</property>
+                                        <property name="margin_top">10</property>
+                                        <property name="label" translatable="yes">Select Journal 
Field…</property>
+                                        <property name="xalign">0</property>
+                                        <style>
+                                          <class name="dim-label"/>
+                                        </style>
+                                    </object>
+                                    <packing>
+                                        <property name="name">select-parameter-label</property>
+                                        <property name="title">page1</property>
+                                        <property name="position">1</property>
+                                    </packing>
+                                </child>
                             </object>
                             <packing>
-                                <property name="name">select-parameter-label</property>
-                                <property name="title">page1</property>
-                                <property name="position">1</property>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">0</property>
+                                <property name="width">2</property>
                             </packing>
                         </child>
-                    </object>
-                    <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                        <property name="width">2</property>
-                    </packing>
-                </child>
-                <child>
-                    <object class="GtkStack" id="range_label_stack">
-                        <property name="visible">True</property>
                         <child>
-                            <object class="GtkLabel" id="when_dim_label">
+                            <object class="GtkStack" id="range_label_stack">
                                 <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>
+                                <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="name">when-label</property>
-                                <property name="title">page0</property>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">2</property>
+                                <property name="width">2</property>
                             </packing>
                         </child>
                         <child>
-                            <object class="GtkLabel" id="show_logs_from_dim_label">
+                            <object class="GtkStack" id="range_stack">
                                 <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>
+                                <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">176</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="name">show-log-from-label</property>
-                                <property name="title">page1</property>
-                                <property name="position">1</property>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">3</property>
+                                <property name="width">2</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"/>
+                            <object class="GtkRevealer" id="search_type_revealer">
                                 <child>
                                     <object class="GtkBox">
                                         <property name="visible">True</property>
+                                        <property name="orientation">vertical</property>
+                                        <property name="spacing">8</property>
                                         <child>
-                                            <object class="GtkLabel" id="range_button_label">
+                                            <object class="GtkLabel" id="search_type_dim_label">
                                                 <property name="visible">True</property>
-                                                <property name="label" translatable="yes">Current 
Boot</property>
+                                                <property name="margin_top">10</property>
+                                                <property name="label" translatable="yes">Search 
Type</property>
+                                                <property name="xalign">0</property>
+                                                <style>
+                                                <class name="dim-label"/>
+                                                </style>
                                             </object>
                                             <packing>
                                                 <property name="expand">False</property>
@@ -210,14 +305,52 @@
                                             </packing>
                                         </child>
                                         <child>
-                                            <object class="GtkImage" id="range_button_drop_down_image">
+                                            <object class="GtkBox">
                                                 <property name="visible">True</property>
-                                                <property name="icon_name">pan-down-symbolic</property>
+                                                <child>
+                                                    <object class="GtkRadioButton" 
id="radiobutton_substring">
+                                                        <property name="label" 
translatable="yes">Substring</property>
+                                                        <property name="visible">True</property>
+                                                        <property name="can_focus">True</property>
+                                                        <property name="receives_default">False</property>
+                                                        <property name="tooltip_text" 
translatable="yes">Match in any part of the string</property>
+                                                        <property name="hexpand">True</property>
+                                                        <property name="xalign">0</property>
+                                                        <property name="active">True</property>
+                                                        <property name="draw_indicator">False</property>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="expand">False</property>
+                                                        <property name="fill">True</property>
+                                                        <property name="position">0</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkRadioButton" id="radiobutton_exact">
+                                                        <property name="label" 
translatable="yes">Exact</property>
+                                                        <property name="visible">True</property>
+                                                        <property name="can_focus">True</property>
+                                                        <property name="receives_default">False</property>
+                                                        <property name="tooltip_text" 
translatable="yes">Match complete string only</property>
+                                                        <property name="hexpand">True</property>
+                                                        <property name="xalign">0</property>
+                                                        <property name="draw_indicator">False</property>
+                                                        <property 
name="group">radiobutton_substring</property>
+                                                        <signal name="toggled" 
handler="search_type_changed"/>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="expand">False</property>
+                                                        <property name="fill">True</property>
+                                                        <property name="position">1</property>
+                                                    </packing>
+                                                </child>
+                                                <style>
+                                                    <class name="linked"/>
+                                                </style>
                                             </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>
@@ -225,136 +358,662 @@
                                 </child>
                             </object>
                             <packing>
-                                <property name="name">range-button</property>
+                                <property name="left_attach">0</property>
+                                <property name="top_attach">4</property>
+                                <property name="width">2</property>
                             </packing>
                         </child>
+                    </object>
+                    <packing>
+                        <property name="name">main</property>
+                    </packing>
+                </child>
+                <child>
+                    <object class="GtkBox" id="set_custom_range_vbox">
+                        <property name="orientation">vertical</property>
+                        <property name="visible">True</property>
                         <child>
-                            <object class="GtkScrolledWindow" id="range_scrolled_window">
-                                <property name="height_request">150</property>
+                            <object class="GtkModelButton" id="submenu_back_button">
                                 <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="hexpand">True</property>
-                                <property name="shadow_type">in</property>
+                                <property name="centered">True</property>
+                                <property name="inverted">True</property>
+                                <property name="menu-name">main</property>
+                                <property name="text" translatable="yes">Back</property>
+                                <signal name="clicked" handler="custom_range_submenu_back_button_clicked"/>
+                            </object>
+                            <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                            </packing>
+                        </child>
+                        <child>
+                            <object class="GtkGrid" id="start_end_date_time_grid">
+                                <property name="visible">True</property>
+                                <property name="border_width">20</property>
+                                <property name="row_spacing">8</property>
+                                <property name="column_spacing">18</property>
+                                <child>
+                                    <object class="GtkLabel" id="start_date_dim_label">
+                                        <property name="visible">True</property>
+                                        <property name="label" translatable="yes">Show Logs Starting 
From…</property>
+                                        <property name="xalign">0</property>
+                                        <style>
+                                          <class name="dim-label"/>
+                                        </style>
+                                    </object>
+                                    <packing>
+                                        <property name="left_attach">0</property>
+                                        <property name="top_attach">0</property>
+                                        <property name="width">2</property>
+                                    </packing>
+                                </child>
+                                <child>
+                                    <object class="GtkStack" id="start_date_stack">
+                                        <property name="visible">True</property>
+                                        <property name="transition_duration">250</property>
+                                        <property name="transition_type">crossfade</property>
+                                        <child>
+                                            <object class="GtkButton" id="start_date_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 a 
start date</property>
+                                                <property name="hexpand">True</property>
+                                                <signal name="clicked" handler="start_date_button_clicked"/>
+                                                <child>
+                                                    <object class="GtkBox" id="start_date_button_label_hbox">
+                                                        <property name="visible">True</property>
+                                                        <child>
+                                                            <object class="GtkLabel" 
id="start_date_button_label">
+                                                                <property name="visible">True</property>
+                                                                <property name="label" 
translatable="yes">Select Start Date…</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="start_date_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">start-date-button</property>
+                                            </packing>
+                                        </child>
+                                        <child>
+                                            <object class="GtkEntry" id="start_date_entry">
+                                                <property name="visible">True</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="placeholder-text">22 January 2016 or 
1/22/2016</property>
+                                                <signal name="activate" handler="start_date_entry_activate"/>
+                                            </object>
+                                            <packing>
+                                                <property name="name">start-date-entry</property>
+                                                <property name="position">1</property>
+                                            </packing>
+                                        </child>
+                                    </object>
+                                    <packing>
+                                        <property name="left_attach">0</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="width">2</property>
+                                    </packing>
+                                </child>
                                 <child>
-                                    <object class="GtkTreeView" id="range_treeview">
+                                    <object class="GtkRevealer" id="start_date_calendar_revealer">
+                                        <child>
+                                            <object class="GtkCalendar" id="start_date_calendar">
+                                                <property name="visible">True</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="valign">start</property>
+                                                <property name="show_week_numbers">True</property>
+                                                <signal name="day-selected" 
handler="start_date_calendar_day_selected"/>
+                                            </object>
+                                        </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="start_time_stack">
                                         <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"/>
+                                        <property name="transition_duration">250</property>
+                                        <property name="transition_type">crossfade</property>
+                                        <property name="vhomogeneous">False</property>
+                                        <property 
name="transition_type">GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN</property>
                                         <child>
-                                            <object class="GtkTreeViewColumn" id="range-column">
-                                                <property name="title">Parameters</property>
+                                            <object class="GtkButton" id="start_time_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 
start time</property>
+                                                <property name="hexpand">True</property>
+                                                <signal name="clicked" handler="start_time_button_clicked"/>
                                                 <child>
-                                                    <object class="GtkCellRendererText" 
id="range-text-renderer"/>
-                                                    <attributes>
-                                                        <attribute name="text">0</attribute>
-                                                    </attributes>
+                                                    <object class="GtkBox" id="start_time_button_label_hbox">
+                                                        <property name="visible">True</property>
+                                                        <child>
+                                                            <object class="GtkLabel" 
id="start_time_button_label">
+                                                                <property name="visible">True</property>
+                                                                <property name="label" 
translatable="yes">Select Start Time…</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="start_time_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">start-time-select-button</property>
+                                            </packing>
                                         </child>
-                                        <child internal-child="selection">
-                                            <object class="GtkTreeSelection" id="range-selection">
-                                            <property name="mode">GTK_SELECTION_BROWSE</property>
+                                        <child>
+                                            <object class="GtkGrid" id="start-time-spinbox-grid">
+                                                <property name="visible">True</property>
+                                                <property name="border_width">10</property>
+                                                <property name="row_spacing">15</property>
+                                                <property name="column_spacing">10</property>
+                                                <property name="column-homogeneous">True</property>
+                                                <child>
+                                                    <object class="GtkLabel" id="start_time_hour_label">
+                                                        <property name="visible">True</property>
+                                                        <property name="label" 
translatable="yes">Hr</property>
+                                                        <style>
+                                                            <class name="dim-label"/>
+                                                        </style>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">0</property>
+                                                        <property name="top_attach">0</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkSpinButton" id="start_time_hour_spin">
+                                                        <property name="visible">1</property>
+                                                        <property name="orientation">vertical</property>
+                                                        <property name="width_chars">2</property>
+                                                        <property 
name="adjustment">start_time_hour_adjustment</property>
+                                                        <property name="wrap">1</property>
+                                                        <property name="max-length">2</property>
+                                                        <property name="numeric">True</property>
+                                                        <property name="halign">GTK_ALIGN_CENTER</property>
+                                                        <property name="hexpand">True</property>
+                                                        <signal name="output" 
handler="spinbox_entry_format_two_digits"/>
+                                                        <signal name="input" 
handler="spinbox_entry_validate_hour_min_sec"/>
+                                                        <signal name="value-changed" 
handler="start_time_spinbox_value_changed"/>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">0</property>
+                                                        <property name="top_attach">1</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkLabel" id="start_time_minute_label">
+                                                        <property name="visible">True</property>
+                                                        <property name="label" 
translatable="yes">Min</property>
+                                                        <style>
+                                                            <class name="dim-label"/>
+                                                        </style>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">1</property>
+                                                        <property name="top_attach">0</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkSpinButton" 
id="start_time_minute_spin">
+                                                        <property name="visible">1</property>
+                                                        <property name="orientation">vertical</property>
+                                                        <property name="width_chars">2</property>
+                                                        <property 
name="adjustment">start_time_minute_adjustment</property>
+                                                        <property name="wrap">1</property>
+                                                        <property name="max-length">2</property>
+                                                        <property name="numeric">True</property>
+                                                        <property name="hexpand">True</property>
+                                                        <property name="halign">GTK_ALIGN_CENTER</property>
+                                                        <signal name="output" 
handler="spinbox_entry_format_two_digits"/>
+                                                        <signal name="input" 
handler="spinbox_entry_validate_hour_min_sec"/>
+                                                        <signal name="value-changed" 
handler="start_time_spinbox_value_changed"/>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">1</property>
+                                                        <property name="top_attach">1</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkLabel" id="start_time_second_label">
+                                                        <property name="visible">True</property>
+                                                        <property name="label" 
translatable="yes">Sec</property>
+                                                        <style>
+                                                            <class name="dim-label"/>
+                                                        </style>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">2</property>
+                                                        <property name="top_attach">0</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkSpinButton" 
id="start_time_second_spin">
+                                                        <property name="visible">1</property>
+                                                        <property name="orientation">vertical</property>
+                                                        <property name="width_chars">2</property>
+                                                        <property 
name="adjustment">start_time_second_adjustment</property>
+                                                        <property name="wrap">1</property>
+                                                        <property name="max-length">2</property>
+                                                        <property name="numeric">True</property>
+                                                        <property name="hexpand">True</property>
+                                                        <property name="halign">GTK_ALIGN_CENTER</property>
+                                                        <signal name="output" 
handler="spinbox_entry_format_two_digits"/>
+                                                        <signal name="input" 
handler="spinbox_entry_validate_hour_min_sec"/>
+                                                        <signal name="value-changed" 
handler="start_time_spinbox_value_changed"/>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">2</property>
+                                                        <property name="top_attach">1</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkLabel" id="start_time_period_label">
+                                                        <property name="visible">True</property>
+                                                        <property name="label" 
translatable="yes">AM/PM</property>
+                                                        <style>
+                                                            <class name="dim-label"/>
+                                                        </style>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">3</property>
+                                                        <property name="top_attach">0</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkSpinButton" 
id="start_time_period_spin">
+                                                        <property name="visible">True</property>
+                                                        <property name="orientation">vertical</property>
+                                                        <property name="width_chars">2</property>
+                                                        <property name="editable">True</property>
+                                                        <property 
name="adjustment">start_time_period_adjustment</property>
+                                                        <property name="wrap">1</property>
+                                                        <property name="max-length">2</property>
+                                                        <property name="halign">GTK_ALIGN_CENTER</property>
+                                                        <signal name="input" 
handler="spinbox_format_time_period_to_int"/>
+                                                        <signal name="output" 
handler="spinbox_format_time_period_to_text"/>
+                                                        <signal name="value-changed" 
handler="start_time_spinbox_value_changed"/>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">3</property>
+                                                        <property name="top_attach">1</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
                                             </object>
+                                            <packing>
+                                                <property name="name">start-time-spinbutton</property>
+                                            </packing>
                                         </child>
                                     </object>
+                                    <packing>
+                                        <property name="left_attach">0</property>
+                                        <property name="top_attach">3</property>
+                                        <property name="width">2</property>
+                                    </packing>
                                 </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">
-                                <property name="visible">True</property>
-                                <property name="orientation">vertical</property>
-                                <property name="spacing">8</property>
                                 <child>
-                                    <object class="GtkLabel" id="search_type_dim_label">
+                                    <object class="GtkLabel" id="end_date_dim_label">
                                         <property name="visible">True</property>
-                                        <property name="margin_top">10</property>
-                                        <property name="label" translatable="yes">Search Type</property>
+                                        <property name="label" translatable="yes">Until…</property>
                                         <property name="xalign">0</property>
                                         <style>
-                                        <class name="dim-label"/>
+                                            <class name="dim-label"/>
                                         </style>
                                     </object>
                                     <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">True</property>
-                                        <property name="position">0</property>
+                                        <property name="left_attach">0</property>
+                                        <property name="top_attach">4</property>
+                                        <property name="width">2</property>
                                     </packing>
                                 </child>
                                 <child>
-                                    <object class="GtkBox">
+                                    <object class="GtkStack" id="end_date_stack">
                                         <property name="visible">True</property>
+                                        <property name="transition_duration">250</property>
+                                        <property name="transition_type">crossfade</property>
                                         <child>
-                                            <object class="GtkRadioButton" id="radiobutton_substring">
-                                                <property name="label" 
translatable="yes">Substring</property>
+                                            <object class="GtkButton" id="end_date_button">
                                                 <property name="visible">True</property>
                                                 <property name="can_focus">True</property>
-                                                <property name="receives_default">False</property>
-                                                <property name="tooltip_text" translatable="yes">Match in 
any part of the string</property>
+                                                <property name="receives_default">True</property>
+                                                <property name="tooltip_text" translatable="yes">Select an 
end date</property>
                                                 <property name="hexpand">True</property>
-                                                <property name="xalign">0</property>
-                                                <property name="active">True</property>
-                                                <property name="draw_indicator">False</property>
+                                                <signal name="clicked" handler="end_date_button_clicked"/>
+                                                <child>
+                                                    <object class="GtkBox" id="end_date_button_label_hbox">
+                                                        <property name="visible">True</property>
+                                                        <child>
+                                                            <object class="GtkLabel" 
id="end_date_button_label">
+                                                                <property name="visible">True</property>
+                                                                <property name="label" 
translatable="yes">Select End Date…</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="end_date_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="expand">False</property>
-                                                <property name="fill">True</property>
-                                                <property name="position">0</property>
+                                                <property name="name">end-date-button</property>
                                             </packing>
                                         </child>
                                         <child>
-                                            <object class="GtkRadioButton" id="radiobutton_exact">
-                                                <property name="label" translatable="yes">Exact</property>
+                                            <object class="GtkEntry" id="end_date_entry">
                                                 <property name="visible">True</property>
                                                 <property name="can_focus">True</property>
-                                                <property name="receives_default">False</property>
-                                                <property name="tooltip_text" translatable="yes">Match 
complete string only</property>
-                                                <property name="hexpand">True</property>
-                                                <property name="xalign">0</property>
-                                                <property name="draw_indicator">False</property>
-                                                <property name="group">radiobutton_substring</property>
-                                                <signal name="toggled" handler="search_type_changed"/>
+                                                <property name="placeholder-text">22 January 2016 or 
1/22/2016</property>
+                                                <signal name="activate" handler="end_date_entry_activate"/>
                                             </object>
                                             <packing>
-                                                <property name="expand">False</property>
-                                                <property name="fill">True</property>
+                                                <property name="name">end-date-entry</property>
                                                 <property name="position">1</property>
                                             </packing>
                                         </child>
-                                        <style>
-                                            <class name="linked"/>
-                                        </style>
                                     </object>
                                     <packing>
-                                        <property name="expand">False</property>
-                                        <property name="fill">True</property>
-                                        <property name="position">1</property>
+                                        <property name="left_attach">0</property>
+                                        <property name="top_attach">5</property>
+                                        <property name="width">2</property>
+                                    </packing>
+                                </child>
+                                <child>
+                                    <object class="GtkRevealer" id="end_date_calendar_revealer">
+                                        <child>
+                                            <object class="GtkCalendar" id="end_date_calendar">
+                                                <property name="visible">True</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="valign">start</property>
+                                                <property name="year">2016</property>
+                                                <property name="month">5</property>
+                                                <property name="day">1</property>
+                                                <property name="show_week_numbers">True</property>
+                                                <signal name="day-selected" 
handler="end_date_calendar_day_selected"/>
+                                            </object>
+                                        </child>
+                                    </object>
+                                    <packing>
+                                        <property name="left_attach">0</property>
+                                        <property name="top_attach">6</property>
+                                        <property name="width">2</property>
+                                    </packing>
+                                </child>
+                                <child>
+                                    <object class="GtkStack" id="end_time_stack">
+                                        <property name="visible">True</property>
+                                        <property name="transition_duration">250</property>
+                                        <property name="transition_type">crossfade</property>
+                                        <property name="vhomogeneous">False</property>
+                                        <property 
name="transition_type">GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN</property>
+                                        <child>
+                                            <object class="GtkButton" id="end_time_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 end 
time</property>
+                                                <property name="hexpand">True</property>
+                                                <signal name="clicked" handler="end_time_button_clicked"/>
+                                                <child>
+                                                    <object class="GtkBox" id="end_time_button_label_hbox">
+                                                        <property name="visible">True</property>
+                                                        <child>
+                                                            <object class="GtkLabel" 
id="end_time_button_label">
+                                                                <property name="visible">True</property>
+                                                                <property name="label" 
translatable="yes">Select End Time…</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="end_time_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">end-time-select-button</property>
+                                            </packing>
+                                        </child>
+                                        <child>
+                                            <object class="GtkGrid" id="end-time-spinbox-grid">
+                                                <property name="visible">True</property>
+                                                <property name="border_width">10</property>
+                                                <property name="row_spacing">15</property>
+                                                <property name="column_spacing">10</property>
+                                                <property name="column-homogeneous">True</property>
+                                                <child>
+                                                    <object class="GtkLabel" id="end_time_hour_label">
+                                                        <property name="visible">True</property>
+                                                        <property name="label" 
translatable="yes">Hr</property>
+                                                        <style>
+                                                            <class name="dim-label"/>
+                                                        </style>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">0</property>
+                                                        <property name="top_attach">0</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkSpinButton" id="end_time_hour_spin">
+                                                        <property name="visible">1</property>
+                                                        <property name="orientation">vertical</property>
+                                                        <property name="width_chars">2</property>
+                                                        <property 
name="adjustment">end_time_hour_adjustment</property>
+                                                        <property name="wrap">1</property>
+                                                        <property name="max-length">2</property>
+                                                        <property name="numeric">True</property>
+                                                        <property name="halign">GTK_ALIGN_CENTER</property>
+                                                        <property name="hexpand">True</property>
+                                                        <signal name="output" 
handler="spinbox_entry_format_two_digits"/>
+                                                        <signal name="input" 
handler="spinbox_entry_validate_hour_min_sec"/>
+                                                        <signal name="value-changed" 
handler="end_time_spinbox_value_changed"/>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">0</property>
+                                                        <property name="top_attach">1</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkLabel" id="end_time_minute_label">
+                                                        <property name="visible">True</property>
+                                                        <property name="label" 
translatable="yes">Min</property>
+                                                        <style>
+                                                            <class name="dim-label"/>
+                                                        </style>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">1</property>
+                                                        <property name="top_attach">0</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkSpinButton" id="end_time_minute_spin">
+                                                        <property name="visible">1</property>
+                                                        <property name="orientation">vertical</property>
+                                                        <property name="width_chars">2</property>
+                                                        <property 
name="adjustment">end_time_minute_adjustment</property>
+                                                        <property name="wrap">1</property>
+                                                        <property name="max-length">2</property>
+                                                        <property name="numeric">True</property>
+                                                        <property name="hexpand">True</property>
+                                                        <property name="halign">GTK_ALIGN_CENTER</property>
+                                                        <signal name="output" 
handler="spinbox_entry_format_two_digits"/>
+                                                        <signal name="input" 
handler="spinbox_entry_validate_hour_min_sec"/>
+                                                        <signal name="value-changed" 
handler="end_time_spinbox_value_changed"/>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">1</property>
+                                                        <property name="top_attach">1</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkLabel" id="end_time_second_label">
+                                                        <property name="visible">True</property>
+                                                        <property name="label" 
translatable="yes">Sec</property>
+                                                        <style>
+                                                            <class name="dim-label"/>
+                                                        </style>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">2</property>
+                                                        <property name="top_attach">0</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkSpinButton" id="end_time_second_spin">
+                                                        <property name="visible">1</property>
+                                                        <property name="orientation">vertical</property>
+                                                        <property name="width_chars">2</property>
+                                                        <property 
name="adjustment">end_time_second_adjustment</property>
+                                                        <property name="wrap">1</property>
+                                                        <property name="max-length">2</property>
+                                                        <property name="numeric">True</property>
+                                                        <property name="hexpand">True</property>
+                                                        <property name="halign">GTK_ALIGN_CENTER</property>
+                                                        <signal name="output" 
handler="spinbox_entry_format_two_digits"/>
+                                                        <signal name="input" 
handler="spinbox_entry_validate_hour_min_sec"/>
+                                                        <signal name="value-changed" 
handler="end_time_spinbox_value_changed"/>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">2</property>
+                                                        <property name="top_attach">1</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkLabel" id="end_time_period_label">
+                                                        <property name="visible">True</property>
+                                                        <property name="label" 
translatable="yes">AM/PM</property>
+                                                        <style>
+                                                            <class name="dim-label"/>
+                                                        </style>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">3</property>
+                                                        <property name="top_attach">0</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                                <child>
+                                                    <object class="GtkSpinButton" id="end_time_period_spin">
+                                                        <property name="visible">True</property>
+                                                        <property name="orientation">vertical</property>
+                                                        <property name="width_chars">2</property>
+                                                        <property name="editable">True</property>
+                                                        <property 
name="adjustment">end_time_period_adjustment</property>
+                                                        <property name="wrap">1</property>
+                                                        <property name="max-length">2</property>
+                                                        <property name="halign">GTK_ALIGN_CENTER</property>
+                                                        <signal name="input" 
handler="spinbox_format_time_period_to_int"/>
+                                                        <signal name="output" 
handler="spinbox_format_time_period_to_text"/>
+                                                        <signal name="value-changed" 
handler="end_time_spinbox_value_changed"/>
+                                                    </object>
+                                                    <packing>
+                                                        <property name="left_attach">3</property>
+                                                        <property name="top_attach">1</property>
+                                                        <property name="width">1</property>
+                                                    </packing>
+                                                </child>
+                                            </object>
+                                            <packing>
+                                                <property name="name">end-time-spinbutton</property>
+                                            </packing>
+                                        </child>
+                                    </object>
+                                    <packing>
+                                        <property name="left_attach">0</property>
+                                        <property name="top_attach">7</property>
+                                        <property name="width">2</property>
                                     </packing>
                                 </child>
                             </object>
+                            <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                            </packing>
                         </child>
                     </object>
                     <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">4</property>
-                        <property name="width">2</property>
+                        <property name="name">custom-range-submenu</property>
                     </packing>
                 </child>
             </object>
@@ -468,6 +1127,69 @@
                 <col id="1">False</col>
                 <col id="2">GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_ENTIRE_JOURNAL</col>
             </row>
+            <row>
+                <col id="0">Separator</col>
+                <col id="1">True</col>
+            </row>
+            <row>
+                <col id="0" translatable="yes">Set Custom Range…</col>
+                <col id="1">False</col>
+                <col id="2">GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CUSTOM</col>
+            </row>
         </data>
     </object>
+    <object class="GtkAdjustment" id="start_time_hour_adjustment">
+        <property name="lower">1</property>
+        <property name="upper">12</property>
+        <property name="value">11</property>
+        <property name="step_increment">3</property>
+        <property name="page_increment">3</property>
+    </object>
+    <object class="GtkAdjustment" id="start_time_minute_adjustment">
+        <property name="lower">0</property>
+        <property name="upper">59</property>
+        <property name="value">59</property>
+        <property name="step_increment">10</property>
+        <property name="page_increment">3</property>
+    </object>
+    <object class="GtkAdjustment" id="start_time_second_adjustment">
+        <property name="lower">0</property>
+        <property name="upper">59</property>
+        <property name="value">59</property>
+        <property name="step_increment">10</property>
+        <property name="page_increment">3</property>
+    </object>
+    <object class="GtkAdjustment" id="start_time_period_adjustment">
+        <property name="lower">0</property>
+        <property name="upper">1</property>
+        <property name="value">1</property>
+        <property name="step_increment">1</property>
+        <property name="page_increment">1</property>
+    </object>
+    <object class="GtkAdjustment" id="end_time_hour_adjustment">
+        <property name="lower">1</property>
+        <property name="upper">12</property>
+        <property name="value">12</property>
+        <property name="step_increment">3</property>
+        <property name="page_increment">3</property>
+    </object>
+    <object class="GtkAdjustment" id="end_time_minute_adjustment">
+        <property name="lower">0</property>
+        <property name="upper">59</property>
+        <property name="step_increment">10</property>
+        <property name="page_increment">3</property>
+    </object>
+    <object class="GtkAdjustment" id="end_time_second_adjustment">
+        <property name="lower">0</property>
+        <property name="upper">59</property>
+        <property name="step_increment">10</property>
+        <property name="page_increment">3</property>
+    </object>
+    <object class="GtkAdjustment" id="end_time_period_adjustment">
+        <property name="lower">0</property>
+        <property name="upper">1</property>
+        <property name="value">0</property>
+        <property name="step_increment">1</property>
+        <property name="page_increment">1</property>
+    </object>
 </interface>
diff --git a/src/gl-eventviewlist.c b/src/gl-eventviewlist.c
index 6ed73a5..c54ffd6 100644
--- a/src/gl-eventviewlist.c
+++ b/src/gl-eventviewlist.c
@@ -580,6 +580,20 @@ query_add_journal_range_filter (GlQuery *query,
             query_set_day_timestamps (query, 0, 2);
 
             break;
+        case GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CUSTOM:
+        {
+            GlSearchPopover *popover;
+            guint64 custom_start_timestamp;
+            guint64 custom_end_timestamp;
+
+            popover = GL_SEARCH_POPOVER (priv->search_popover);
+
+            custom_start_timestamp = gl_search_popover_get_custom_start_timestamp (popover);
+            custom_end_timestamp = gl_search_popover_get_custom_end_timestamp (popover);
+
+            gl_query_set_journal_timestamp_range (query, custom_start_timestamp, custom_end_timestamp);
+            break;
+        }
         default:
 
             /* By default, search the entire journal */
diff --git a/src/gl-searchpopover.c b/src/gl-searchpopover.c
index bcf6b7c..264dd93 100644
--- a/src/gl-searchpopover.c
+++ b/src/gl-searchpopover.c
@@ -18,8 +18,10 @@
 
 #include "gl-searchpopover.h"
 #include "gl-enums.h"
+#include "gl-util.h"
 
 #include <glib/gi18n.h>
+#include <stdlib.h>
 
 struct _GlSearchPopover
 {
@@ -43,10 +45,42 @@ typedef struct
     GtkWidget *clear_range_button;
     GtkWidget *range_button_drop_down_image;
     GtkListStore *range_liststore;
+    GtkWidget *menu_stack;
+
+    GtkWidget *start_date_stack;
+    GtkWidget *start_date_calendar_revealer;
+    GtkWidget *start_date_entry;
+    GtkWidget *start_date_button_label;
+
+    GtkWidget *start_time_stack;
+    GtkWidget *start_time_hour_spin;
+    GtkWidget *start_time_minute_spin;
+    GtkWidget *start_time_second_spin;
+    GtkWidget *start_time_period_spin;
+    GtkWidget *start_time_button_label;
+    GtkWidget *start_time_period_label;
+
+    GtkWidget *end_date_stack;
+    GtkWidget *end_date_calendar_revealer;
+    GtkWidget *end_date_entry;
+    GtkWidget *end_date_button_label;
+
+    GtkWidget *end_time_stack;
+    GtkWidget *end_time_hour_spin;
+    GtkWidget *end_time_minute_spin;
+    GtkWidget *end_time_second_spin;
+    GtkWidget *end_time_period_spin;
+    GtkWidget *end_time_button_label;
+    GtkWidget *end_time_period_label;
 
     GlSearchPopoverJournalFieldFilter journal_search_field;
     GlQuerySearchType search_type;
     GlSearchPopoverJournalTimestampRange journal_timestamp_range;
+
+    guint64 custom_start_timestamp;
+    guint64 custom_end_timestamp;
+
+    GlUtilClockFormat clock_format;
 } GlSearchPopoverPrivate;
 
 enum
@@ -74,8 +108,17 @@ enum
     JOURNAL_TIMESTAMP_RANGE_N_COLUMNS
 };
 
+enum
+{
+    AM,
+    PM
+};
+
 static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
 
+static const gchar DESKTOP_SCHEMA[] = "org.gnome.desktop.interface";
+static const gchar CLOCK_FORMAT[] = "clock-format";
+
 G_DEFINE_TYPE_WITH_PRIVATE (GlSearchPopover, gl_search_popover, GTK_TYPE_POPOVER)
 
 /* Event handlers for search popover elements */
@@ -377,6 +420,109 @@ range_treeview_row_seperator (GtkTreeModel *model,
 }
 
 static void
+show_start_date_widgets (GlSearchPopover *popover, gboolean visible)
+{
+    GlSearchPopoverPrivate *priv;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->start_date_stack),
+                                      visible ? "start-date-entry" : "start-date-button");
+
+    gtk_widget_set_visible (priv->start_date_calendar_revealer, visible);
+    gtk_revealer_set_reveal_child (GTK_REVEALER (priv->start_date_calendar_revealer), visible);
+}
+
+static void
+show_start_time_widgets (GlSearchPopover *popover, gboolean visible)
+{
+    GlSearchPopoverPrivate *priv;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->start_time_stack),
+                                      visible ? "start-time-spinbutton" : "start-time-select-button");
+}
+
+static void
+show_end_date_widgets (GlSearchPopover *popover, gboolean visible)
+{
+    GlSearchPopoverPrivate *priv;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->end_date_stack),
+                                      visible ? "end-date-entry" : "end-date-button");
+
+    gtk_widget_set_visible (priv->end_date_calendar_revealer, visible);
+    gtk_revealer_set_reveal_child (GTK_REVEALER (priv->end_date_calendar_revealer), visible);
+}
+
+static void
+show_end_time_widgets (GlSearchPopover *popover, gboolean visible)
+{
+    GlSearchPopoverPrivate *priv;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    gtk_stack_set_visible_child_name (GTK_STACK (priv->end_time_stack),
+                                      visible ? "end-time-spinbutton" : "end-time-select-button");
+}
+
+static void
+reset_custom_range_widgets (GlSearchPopover *popover)
+{
+    GlSearchPopoverPrivate *priv;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    priv->custom_start_timestamp = 0;
+    priv->custom_end_timestamp = 0;
+
+    /* Close any previously opened widgets in the submenu */
+    show_start_date_widgets (popover, FALSE);
+    show_start_time_widgets (popover, FALSE);
+    show_end_date_widgets (popover, FALSE);
+    show_end_time_widgets (popover, FALSE);
+
+    /* Reset start range elements */
+    gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->start_time_minute_spin), 59.0);
+    gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->start_time_second_spin), 59.0);
+
+    if (priv->clock_format == GL_UTIL_CLOCK_FORMAT_12HR)
+    {
+        gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->start_time_hour_spin), 11.0);
+        gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->start_time_period_spin), PM);
+    }
+    else
+    {
+        gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->start_time_hour_spin), 23.0);
+    }
+
+    gtk_entry_set_text (GTK_ENTRY (priv->start_date_entry), "");
+    gtk_label_set_label (GTK_LABEL (priv->start_date_button_label), _("Select Start Date..."));
+    gtk_label_set_label (GTK_LABEL (priv->start_time_button_label), _("Select Start Time..."));
+
+    /*Reset end range elements */
+    gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->end_time_minute_spin), 0.0);
+    gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->end_time_second_spin), 0.0);
+
+    if (priv->clock_format == GL_UTIL_CLOCK_FORMAT_12HR)
+    {
+        gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->end_time_hour_spin), 12.0);
+        gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->end_time_period_spin), AM);
+    }
+    else
+    {
+        gtk_spin_button_set_value (GTK_SPIN_BUTTON (priv->end_time_hour_spin), 0.0);
+    }
+
+    gtk_entry_set_text (GTK_ENTRY (priv->end_date_entry), "");
+    gtk_label_set_label (GTK_LABEL (priv->end_date_button_label), _("Select End Date..."));
+    gtk_label_set_label (GTK_LABEL (priv->end_time_button_label), _("Select End Time..."));
+}
+
+static void
 on_range_treeview_row_activated (GtkTreeView *tree_view,
                                  GtkTreePath *path,
                                  GtkTreeViewColumn *column,
@@ -401,16 +547,741 @@ on_range_treeview_row_activated (GtkTreeView *tree_view,
 
     priv->journal_timestamp_range = journal_range_enum_value;
 
-    gtk_label_set_label (GTK_LABEL (priv->range_button_label),
-                         _(range_label));
+    if (priv->journal_timestamp_range == GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CUSTOM)
+    {
+        gtk_stack_set_visible_child_name (GTK_STACK (priv->menu_stack), "custom-range-submenu");
+    }
+    else
+    {
+        /* Reset the Custom Range elements if set as only one filter can be applied at time */
+        reset_custom_range_widgets (popover);
+
+        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);
+}
+
+static void
+start_date_button_clicked (GtkButton *button,
+                           gpointer user_data)
+{
+    GlSearchPopover *popover = GL_SEARCH_POPOVER (user_data);
+
+    show_start_date_widgets (popover, TRUE);
+    show_start_time_widgets (popover, FALSE);
+    show_end_date_widgets (popover, FALSE);
+    show_end_time_widgets (popover, FALSE);
+}
+
+/* Utility function for converting hours from 12 hour format to 24 hour format */
+static void
+convert_hour (gint *hour, gint time_period)
+{
+    if (*hour == 12 && time_period == AM)
+    {
+        *hour = 0;
+    }
+    else if (*hour != 12 && time_period == PM)
+    {
+        *hour = *hour + 12;
+    }
+}
+
+static GDateTime *
+get_start_date_time (GlSearchPopover *popover)
+{
+    GlSearchPopoverPrivate *priv;
+    const gchar *entry_date;
+    GDateTime *now;
+    GDateTime *start_date_time;
+    GDate *start_date;
+    gint hour;
+    gint minute;
+    gint second;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    entry_date = gtk_entry_get_text (GTK_ENTRY (priv->start_date_entry));
+
+    hour = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->start_time_hour_spin));
+    minute = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->start_time_minute_spin));
+    second = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->start_time_second_spin));
+
+    /* Convert to 24 Hour format */
+    if (priv->clock_format == GL_UTIL_CLOCK_FORMAT_12HR)
+    {
+        gint time_period;
+
+        time_period = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->start_time_period_spin));
+
+        convert_hour (&hour, time_period);
+    }
+
+    /* Parse the date entered into the Text Entry */
+    start_date = g_date_new ();
+    g_date_set_parse (start_date, entry_date);
+
+    now = g_date_time_new_now_local ();
+
+    /* If Invalid date, then take today's date as default */
+    if (!g_date_valid (start_date))
+    {
+        start_date_time = 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),
+                                                 hour,
+                                                 minute,
+                                                 second);
+    }
+    else
+    {
+        start_date_time = g_date_time_new_local (g_date_get_year (start_date),
+                                                 g_date_get_month (start_date),
+                                                 g_date_get_day (start_date),
+                                                 hour,
+                                                 minute,
+                                                 second);
+    }
+
+    g_date_time_unref (now);
+    g_date_free (start_date);
+
+    return start_date_time;
+}
+
+static void
+update_range_button (GlSearchPopover *popover)
+{
+    GlSearchPopoverPrivate *priv;
+    gchar *range_button_label;
+    gchar *display_time;
+    GDateTime *now;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    now = g_date_time_new_now_local ();
+
+    /* Update range button label according to timestamps set in the custom range submenu */
+    if (priv->custom_end_timestamp && priv->custom_start_timestamp)
+    {
+        range_button_label = gl_util_boot_time_to_display (priv->custom_start_timestamp,
+                                                           priv->custom_end_timestamp);
+    }
+    else if (priv->custom_start_timestamp && !priv->custom_end_timestamp)
+    {
+        display_time = gl_util_timestamp_to_display (priv->custom_start_timestamp,
+                                                     now, priv->clock_format, FALSE);
+
+        /* Translators: if only custom start timestamp is set, then we update
+         * the timestamp range button label in popover to show that
+         * logs are shown in the window starting from this timestamp
+         * until the ending timestamp of journal. */
+        range_button_label = g_strdup_printf (_("From %s"), display_time);
+
+        g_free (display_time);
+    }
+    else
+    {
+        display_time = gl_util_timestamp_to_display (priv->custom_end_timestamp,
+                                                     now, priv->clock_format, FALSE);
+
+        /* Translators: if only custom end timestamp is set, then we update
+         * the timestamp range button label in popover to show that
+         * logs are shown in the window upto this timestamp
+         * with the starting timestamp being the current time. */
+        range_button_label = g_strdup_printf (_("Until %s"), display_time);
+
+        g_free (display_time);
+    }
+
+    gtk_label_set_label (GTK_LABEL (priv->range_button_label), range_button_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");
+
+    g_date_time_unref (now);
+    g_free (range_button_label);
+}
+
+static void
+start_date_calendar_day_selected (GtkCalendar *calendar,
+                                  gpointer user_data)
+{
+    GDateTime *date;
+    GDateTime *now;
+    guint year, month, day;
+    gchar *date_label;
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    gtk_calendar_get_date (calendar, &year, &month, &day);
+
+    date = g_date_time_new_local (year, month + 1, day, 0, 0, 0);
+
+    /* Translators: date format for the start date entry
+     * and start date button label in the custom range submenu,
+     * showing the day of month in decimal number, full month
+     * name as string, the year as a decimal number including the century. */
+    date_label = g_date_time_format (date, _("%e %B %Y"));
+
+    now = g_date_time_new_now_local ();
+
+    /* If a future date, fail silently */
+    if (g_date_time_compare (date, now) != 1)
+    {
+        GDateTime *start_date_time;
+
+        gtk_entry_set_text (GTK_ENTRY (priv->start_date_entry), date_label);
+
+        gtk_label_set_label (GTK_LABEL (priv->start_date_button_label), date_label);
+
+        start_date_time = get_start_date_time (popover);
+
+        priv->custom_start_timestamp = g_date_time_to_unix (start_date_time) * G_USEC_PER_SEC;
+
+        update_range_button (popover);
+
+        g_object_notify_by_pspec (G_OBJECT (popover),
+                                  obj_properties[PROP_JOURNAL_TIMESTAMP_RANGE]);
+
+        g_date_time_unref (start_date_time);
+    }
+
+    g_date_time_unref (date);
+}
+
+static void
+start_date_entry_activate (GtkEntry *entry,
+                           gpointer user_data)
+{
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    if (gtk_entry_get_text_length (entry) > 0)
+    {
+        GDateTime *now;
+        GDateTime *date_time;
+        GDate *date;
+
+        date = g_date_new ();
+        g_date_set_parse (date, gtk_entry_get_text (entry));
+
+        /* Invalid date silently does nothing */
+        if (!g_date_valid (date))
+        {
+            g_date_free (date);
+            return;
+        }
+
+        now = g_date_time_new_now_local ();
+        date_time = g_date_time_new_local (g_date_get_year (date),
+                                           g_date_get_month (date),
+                                           g_date_get_day (date),
+                                           0,
+                                           0,
+                                           0);
+
+        /* Future dates silently fail */
+        if (g_date_time_compare (date_time, now) != 1)
+        {
+            GDateTime *start_date_time;
+
+            gtk_label_set_label (GTK_LABEL (priv->start_date_button_label), gtk_entry_get_text(entry));
+
+            show_start_date_widgets (popover, FALSE);
+
+            start_date_time = get_start_date_time (popover);
+
+            priv->custom_start_timestamp = g_date_time_to_unix (start_date_time) * G_USEC_PER_SEC;
+
+            update_range_button (popover);
+
+            g_object_notify_by_pspec (G_OBJECT (popover),
+                                      obj_properties[PROP_JOURNAL_TIMESTAMP_RANGE]);
+
+            g_date_time_unref (start_date_time);
+        }
+
+        g_date_time_unref (now);
+        g_date_time_unref (date_time);
+        g_date_free (date);
+    }
+}
+
+static void
+start_time_button_clicked (GtkButton *button,
+                           gpointer user_data)
+{
+    GlSearchPopover *popover = GL_SEARCH_POPOVER (user_data);
+
+    show_start_time_widgets (popover, TRUE);
+    show_start_date_widgets (popover, FALSE);
+    show_end_time_widgets (popover, FALSE);
+    show_end_date_widgets (popover, FALSE);
+}
+
+static void
+roundoff_invalid_time_value (GtkSpinButton *spin_button,
+                             gdouble *new_val,
+                             gint lower_limit,
+                             gint upper_limit)
+{
+    gint time;
+
+    time = atoi (gtk_entry_get_text (GTK_ENTRY (spin_button)));
+
+    /* Roundoff to the nearest limit if out of limits*/
+    if (time < lower_limit)
+    {
+        *new_val = lower_limit;
+    }
+    else if (time > upper_limit)
+    {
+        *new_val = upper_limit;
+    }
+    else
+    {
+        *new_val = time;
+    }
+}
+
+static gboolean
+spinbox_format_time_period_to_text (GtkSpinButton *spin_button,
+                                    gpointer user_data)
+{
+    gchar *time_period_string;
+    gint time_period;
+
+    time_period = gtk_spin_button_get_value_as_int (spin_button);
+
+    if (time_period == AM)
+    {
+        time_period_string = g_strdup_printf (_("AM"));
+    }
+    else
+    {
+        time_period_string = g_strdup_printf (_("PM"));
+    }
+
+    gtk_entry_set_text (GTK_ENTRY (spin_button), time_period_string);
+
+    g_free (time_period_string);
+
+    return TRUE;
+}
+
+static gint
+spinbox_format_time_period_to_int (GtkSpinButton *spin_button,
+                                   gdouble *time_period,
+                                   gpointer user_data)
+{
+    const gchar *time_period_string;
+
+    time_period_string = gtk_entry_get_text (GTK_ENTRY (spin_button));
+
+    if ( g_strcmp0 ("PM", time_period_string) == 0)
+    {
+        *time_period = PM;
+    }
+    else
+    {
+        /* Reset invalid values to "AM" */
+        *time_period = AM;
+    }
+
+    return TRUE;
+}
+
+/* Common event handler for validating spinbutton entry values */
+static gint
+spinbox_entry_validate_hour_min_sec (GtkSpinButton *spin_button,
+                                     gdouble *new_val,
+                                     gpointer user_data)
+{
+    const gchar *spinbutton_id;
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    spinbutton_id = gtk_buildable_get_name (GTK_BUILDABLE (spin_button));
+
+    /* Check if called from hour spinboxes */
+    if (g_strcmp0 (spinbutton_id, "end_time_hour_spin") == 0
+        || g_strcmp0 (spinbutton_id, "start_time_hour_spin") == 0)
+    {
+        if (priv->clock_format == GL_UTIL_CLOCK_FORMAT_24HR)
+        {
+            roundoff_invalid_time_value (spin_button, new_val, 0, 23);
+        }
+        else
+        {
+            roundoff_invalid_time_value (spin_button, new_val, 1, 12);
+        }
+    }
+    else
+    {
+        roundoff_invalid_time_value (spin_button, new_val, 0, 59);
+    }
+
+    return TRUE;
+}
+
+static gboolean
+spinbox_entry_format_two_digits (GtkSpinButton *spin_button,
+                                 gpointer user_data)
+{
+    gchar *time_string;
+    gint value;
+
+    value = gtk_spin_button_get_value_as_int (spin_button);
+
+    time_string = g_strdup_printf ("%02d", value);
+
+    gtk_entry_set_text (GTK_ENTRY (spin_button), time_string);
+
+    g_free (time_string);
+
+    return TRUE;
+}
+
+/* Common event handler for setting query when any one of start time spinbutton changes */
+static void
+start_time_spinbox_value_changed (GtkSpinButton *spin_button,
+                                  gpointer user_data)
+{
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+    GDateTime *start_date_time;
+    gchar *button_label;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    start_date_time = get_start_date_time (popover);
+
+    if (priv->clock_format == GL_UTIL_CLOCK_FORMAT_12HR)
+    {
+        /* Translators: timestamp format for the custom start time button
+         * label in the custom range submenu, showing the time with seconds
+         * in 12-hour format. */
+        button_label = g_date_time_format (start_date_time, _("%I:%M:%S %p"));
+    }
+    else
+    {
+        /* Translators: timestamp format for the custom start time button
+         * label in the custom range submenu, showing the time with seconds
+         * in 24-hour format. */
+        button_label = g_date_time_format (start_date_time, _("%T"));
+    }
+
+    gtk_label_set_label (GTK_LABEL (priv->start_time_button_label), button_label);
+
+    priv->custom_start_timestamp = g_date_time_to_unix (start_date_time) * G_USEC_PER_SEC;
+
+    update_range_button (popover);
 
     g_object_notify_by_pspec (G_OBJECT (popover),
                               obj_properties[PROP_JOURNAL_TIMESTAMP_RANGE]);
+}
+
+static void
+end_date_button_clicked (GtkButton *button,
+                         gpointer user_data)
+{
+    GlSearchPopover *popover = GL_SEARCH_POPOVER (user_data);
+
+    show_end_date_widgets (popover, TRUE);
+    show_end_time_widgets (popover, FALSE);
+    show_start_date_widgets (popover, FALSE);
+    show_start_time_widgets (popover, FALSE);
+}
+
+static GDateTime *
+get_end_date_time (GlSearchPopover *popover)
+{
+    GlSearchPopoverPrivate *priv;
+    const gchar *entry_date;
+    GDateTime *now;
+    GDateTime *end_date_time;
+    GDate *end_date;
+    gint hour;
+    gint minute;
+    gint second;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    entry_date = gtk_entry_get_text (GTK_ENTRY (priv->end_date_entry));
+
+    hour = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->end_time_hour_spin));
+    minute = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->end_time_minute_spin));
+    second = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->end_time_second_spin));
+
+    /* Convert to 24 Hour format */
+    if (priv->clock_format == GL_UTIL_CLOCK_FORMAT_12HR)
+    {
+        gint time_period;
+
+        time_period = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (priv->end_time_period_spin));
+
+        convert_hour (&hour, time_period);
+    }
+
+    /* Parse the date entered into the Text Entry */
+    end_date = g_date_new ();
+    g_date_set_parse (end_date, entry_date);
+
+    now = g_date_time_new_now_local ();
+
+    /* If Invalid date, then take today's date as default */
+    if (!g_date_valid (end_date))
+    {
+        end_date_time = 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),
+                                               hour,
+                                               minute,
+                                               second);
+    }
+    else
+    {
+        end_date_time = g_date_time_new_local (g_date_get_year (end_date),
+                                               g_date_get_month (end_date),
+                                               g_date_get_day (end_date),
+                                               hour,
+                                               minute,
+                                               second);
+    }
+
+    g_date_time_unref (now);
+    g_date_free (end_date);
+
+    return end_date_time;
+}
+
+static void
+end_date_calendar_day_selected (GtkCalendar *calendar,
+                                gpointer user_data)
+{
+    GDateTime *date;
+    GDateTime *now;
+    guint year, month, day;
+    gchar *date_label;
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    gtk_calendar_get_date (calendar, &year, &month, &day);
+
+    date = g_date_time_new_local (year, month + 1, day, 0, 0, 0);
+
+    /* Translators: date format for the end date entry
+     * and end date button label in the custom range submenu,
+     * showing the day of month in decimal number, full month
+     * name as string, the year as a decimal number including the century. */
+    date_label = g_date_time_format (date, _("%e %B %Y"));
+
+    now = g_date_time_new_now_local ();
+
+    /* If a future date, fail silently */
+    if (g_date_time_compare (date, now) != 1)
+    {
+        GDateTime *end_date_time;
+
+        gtk_entry_set_text (GTK_ENTRY (priv->end_date_entry), date_label);
+
+        gtk_label_set_label (GTK_LABEL (priv->end_date_button_label), date_label);
+
+        end_date_time = get_end_date_time (popover);
+
+        priv->custom_end_timestamp = g_date_time_to_unix (end_date_time) * G_USEC_PER_SEC;
+
+        update_range_button (popover);
+
+        g_object_notify_by_pspec (G_OBJECT (popover),
+                                  obj_properties[PROP_JOURNAL_TIMESTAMP_RANGE]);
+
+        g_date_time_unref (end_date_time);
+    }
+
+    g_date_time_unref (date);
+}
+
+static void
+end_date_entry_activate (GtkEntry *entry,
+                         gpointer user_data)
+{
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    if (gtk_entry_get_text_length (entry) > 0)
+    {
+        GDateTime *now;
+        GDateTime *date_time;
+        GDate *date;
+
+        date = g_date_new ();
+        g_date_set_parse (date, gtk_entry_get_text (entry));
+
+        /* Invalid date silently does nothing */
+        if (!g_date_valid (date))
+        {
+            g_date_free (date);
+            return;
+        }
+
+        now = g_date_time_new_now_local ();
+        date_time = g_date_time_new_local (g_date_get_year (date),
+                                           g_date_get_month (date),
+                                           g_date_get_day (date),
+                                           0,
+                                           0,
+                                           0);
+
+        /* Future dates silently fails */
+        if (g_date_time_compare (date_time, now) != 1)
+        {
+            GDateTime *end_date_time;
+
+            gtk_label_set_label (GTK_LABEL (priv->end_date_button_label), gtk_entry_get_text(entry));
+
+            show_end_date_widgets (popover, FALSE);
+
+            end_date_time = get_end_date_time (popover);
+
+            priv->custom_end_timestamp = g_date_time_to_unix (end_date_time) * G_USEC_PER_SEC;
+
+            update_range_button (popover);
+
+            g_object_notify_by_pspec (G_OBJECT (popover),
+                                      obj_properties[PROP_JOURNAL_TIMESTAMP_RANGE]);
+
+            g_date_time_unref (end_date_time);
+        }
+
+        g_date_time_unref (now);
+        g_date_time_unref (date_time);
+        g_date_free (date);
+    }
+}
+
+static void
+end_time_button_clicked (GtkButton *button,
+                         gpointer user_data)
+{
+    GlSearchPopover *popover = GL_SEARCH_POPOVER (user_data);
+
+    show_end_time_widgets (popover, TRUE);
+    show_end_date_widgets (popover, FALSE);
+    show_start_time_widgets (popover, FALSE);
+    show_start_date_widgets (popover, FALSE);
+}
+
+static void
+end_time_spinbox_value_changed (GtkSpinButton *spin_button,
+                                gpointer user_data)
+{
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+    GDateTime *end_date_time;
+    gchar *button_label;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    end_date_time = get_end_date_time (popover);
+
+    if (priv->clock_format == GL_UTIL_CLOCK_FORMAT_12HR)
+    {
+        /* Translators: timestamp format for the custom end time button
+         * label in the custom range submenu, showing the time with seconds
+         * in 12-hour format. */
+        button_label = g_date_time_format (end_date_time, _("%I:%M:%S %p"));
+    }
+    else
+    {
+        /* Translators: timestamp format for the custom end time button
+         * label in the custom range submenu, showing the time with seconds
+         * in 24-hour format. */
+        button_label = g_date_time_format (end_date_time, _("%T"));
+    }
+
+    gtk_label_set_label (GTK_LABEL (priv->end_time_button_label), button_label);
+
+    priv->custom_end_timestamp = g_date_time_to_unix (end_date_time) * G_USEC_PER_SEC;
+
+    update_range_button (popover);
+
+    g_object_notify_by_pspec (G_OBJECT (popover),
+                              obj_properties[PROP_JOURNAL_TIMESTAMP_RANGE]);
+}
+
+static void
+custom_range_submenu_back_button_clicked (GtkButton *button,
+                                          gpointer user_data)
+{
+    GlSearchPopover *popover;
+    GlSearchPopoverPrivate *priv;
+
+    popover = GL_SEARCH_POPOVER (user_data);
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    /* Default to Current boot if none of the timestamp was set */
+    if (!priv->custom_start_timestamp && !priv->custom_end_timestamp)
+    {
+        gl_search_popover_set_journal_timestamp_range_current_boot (popover);
+    }
 
     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);
+guint64
+gl_search_popover_get_custom_start_timestamp (GlSearchPopover *popover)
+{
+    GlSearchPopoverPrivate *priv;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    return priv->custom_start_timestamp;
+}
+
+guint64
+gl_search_popover_get_custom_end_timestamp (GlSearchPopover *popover)
+{
+    GlSearchPopoverPrivate *priv;
+
+    priv = gl_search_popover_get_instance_private (popover);
+
+    return priv->custom_end_timestamp;
 }
 
 void
@@ -420,6 +1291,9 @@ gl_search_popover_set_journal_timestamp_range_current_boot (GlSearchPopover *pop
 
     priv = gl_search_popover_get_instance_private (popover);
 
+    /* Reset the Custom Range elements if set as only one filter can be applied at time */
+    reset_custom_range_widgets (popover);
+
     priv->journal_timestamp_range = GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CURRENT_BOOT;
 
     g_object_notify_by_pspec (G_OBJECT (popover),
@@ -488,6 +1362,52 @@ gl_search_popover_class_init (GlSearchPopoverClass *klass)
                                                   range_button_drop_down_image);
     gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
                                                   range_liststore);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  menu_stack);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_date_stack);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_date_calendar_revealer);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_date_entry);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_date_button_label);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_time_stack);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_time_hour_spin);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_time_minute_spin);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_time_second_spin);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_time_period_spin);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_time_button_label);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_date_stack);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_date_calendar_revealer);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_date_entry);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_date_button_label);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_time_stack);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_time_hour_spin);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_time_minute_spin);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_time_second_spin);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_time_period_spin);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_time_button_label);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  start_time_period_label);
+    gtk_widget_class_bind_template_child_private (widget_class, GlSearchPopover,
+                                                  end_time_period_label);
 
 
     gtk_widget_class_bind_template_callback (widget_class,
@@ -502,12 +1422,43 @@ gl_search_popover_class_init (GlSearchPopoverClass *klass)
                                              select_range_button_clicked);
     gtk_widget_class_bind_template_callback (widget_class,
                                              on_range_treeview_row_activated);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             custom_range_submenu_back_button_clicked);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             end_time_spinbox_value_changed);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             end_time_button_clicked);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             end_date_entry_activate);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             end_date_calendar_day_selected);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             end_date_button_clicked);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             start_time_spinbox_value_changed);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             spinbox_entry_format_two_digits);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             spinbox_entry_validate_hour_min_sec);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             spinbox_format_time_period_to_int);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             spinbox_format_time_period_to_text);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             start_time_button_clicked);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             start_date_entry_activate);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             start_date_calendar_day_selected);
+    gtk_widget_class_bind_template_callback (widget_class,
+                                             start_date_button_clicked);
 }
 
 static void
 gl_search_popover_init (GlSearchPopover *popover)
 {
     GlSearchPopoverPrivate *priv;
+    GSettings *settings;
 
     gtk_widget_init_template (GTK_WIDGET (popover));
 
@@ -522,6 +1473,36 @@ gl_search_popover_init (GlSearchPopover *popover)
                                           (GtkTreeViewRowSeparatorFunc) range_treeview_row_seperator,
                                           popover,
                                           NULL);
+
+    settings = g_settings_new (DESKTOP_SCHEMA);
+    priv->clock_format = g_settings_get_enum (settings, CLOCK_FORMAT);
+
+    /* Show only hour-minute-second spinboxes when time format is 24hr */
+    if (priv->clock_format == GL_UTIL_CLOCK_FORMAT_24HR)
+    {
+        GtkAdjustment *start_hour_adjustment;
+        GtkAdjustment *end_hour_adjustment;
+
+        /* Hide the AM/PM time period spinbuttons */
+        gtk_widget_hide (priv->start_time_period_spin);
+        gtk_widget_hide (priv->start_time_period_label);
+        gtk_widget_hide (priv->end_time_period_spin);
+        gtk_widget_hide (priv->end_time_period_label);
+
+        /* Set 0-23 as range for hour spinbutton */
+        start_hour_adjustment = gtk_adjustment_new (23.0, 0.0, 23.0, 5.0, 0.0, 0.0);
+        end_hour_adjustment = gtk_adjustment_new (0.0, 0.0, 23.0, 5.0, 0.0, 0.0);
+
+        gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (priv->start_time_hour_spin),
+                                        start_hour_adjustment);
+        gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (priv->end_time_hour_spin),
+                                        end_hour_adjustment);
+    }
+
+    priv->custom_start_timestamp = 0;
+    priv->custom_end_timestamp = 0;
+
+    g_object_unref (settings);
 }
 
 GtkWidget *
diff --git a/src/gl-searchpopover.h b/src/gl-searchpopover.h
index cd44cb4..a4d97e6 100644
--- a/src/gl-searchpopover.h
+++ b/src/gl-searchpopover.h
@@ -46,7 +46,8 @@ typedef enum
     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
+    GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_ENTIRE_JOURNAL,
+    GL_SEARCH_POPOVER_JOURNAL_TIMESTAMP_RANGE_CUSTOM
 } GlSearchPopoverJournalTimestampRange;
 
 #define GL_TYPE_SEARCH_POPOVER (gl_search_popover_get_type ())
@@ -57,6 +58,8 @@ GlSearchPopoverJournalFieldFilter gl_search_popover_get_journal_search_field (Gl
 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);
+guint64 gl_search_popover_get_custom_start_timestamp (GlSearchPopover *popover);
+guint64 gl_search_popover_get_custom_end_timestamp (GlSearchPopover *popover);
 
 G_END_DECLS
 



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