/* * GNOME Logs - View and search logs * Copyright (C) 2013 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "gl-eventviewdetail.h" #include "gl-eventviewrow.h" #include #include #include "gl-enums.h" enum { PROP_0, PROP_CLOCK_FORMAT, PROP_ENTRY, N_PROPERTIES }; struct _GlEventViewDetail { /*< private >*/ GtkPopover parent_instance; }; typedef struct { GlRowEntry *entry; GlUtilClockFormat clock_format; GtkWidget *grid; GtkWidget *comm_field_label; GtkWidget *comm_label; GtkWidget *time_label; GtkWidget *message_label; GtkWidget *audit_field_label; GtkWidget *audit_label; GtkWidget *device_field_label; GtkWidget *device_label; GtkWidget *priority_label; GtkWidget *subject_field_label; GtkWidget *subject_label; GtkWidget *definedby_field_label; GtkWidget *definedby_label; GtkWidget *support_field_label; GtkWidget *support_label; GtkWidget *documentation_field_label; GtkWidget *documentation_label; GtkWidget *detailed_message_label; } GlEventViewDetailPrivate; G_DEFINE_TYPE_WITH_PRIVATE (GlEventViewDetail, gl_event_view_detail, GTK_TYPE_POPOVER) static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; static void gl_event_view_detail_create_detail (GlEventViewDetail *detail) { GlEventViewDetailPrivate *priv; GlJournalEntry *entry; GlRowEntry *row_entry; gchar *str; gchar *str_field; gchar *str_message; gchar *str_copy; GDateTime *now; priv = gl_event_view_detail_get_instance_private (detail); row_entry = priv->entry; entry = gl_row_entry_get_journal_entry (row_entry); /* Force LTR direction also for RTL languages */ gtk_widget_set_direction (priv->grid, GTK_TEXT_DIR_LTR); gtk_widget_set_direction (priv->comm_label, GTK_TEXT_DIR_LTR); gtk_widget_set_direction (priv->message_label, GTK_TEXT_DIR_LTR); gtk_widget_set_direction (priv->audit_label, GTK_TEXT_DIR_LTR); gtk_widget_set_direction (priv->device_label, GTK_TEXT_DIR_LTR); gtk_widget_set_direction (priv->subject_label, GTK_TEXT_DIR_LTR); gtk_widget_set_direction (priv->definedby_label, GTK_TEXT_DIR_LTR); gtk_widget_set_direction (priv->support_label, GTK_TEXT_DIR_LTR); gtk_widget_set_direction (priv->documentation_label, GTK_TEXT_DIR_LTR); gtk_widget_set_direction (priv->detailed_message_label, GTK_TEXT_DIR_LTR); if (gl_journal_entry_get_command_line (entry)) { gtk_label_set_text (GTK_LABEL (priv->comm_label), gl_journal_entry_get_command_line (entry)); gtk_widget_show (priv->comm_field_label); gtk_widget_show (priv->comm_label); } now = g_date_time_new_now_local (); str = gl_util_timestamp_to_display (gl_journal_entry_get_timestamp (entry), now, priv->clock_format, TRUE); g_date_time_unref (now); gtk_label_set_text (GTK_LABEL (priv->time_label), str); g_free (str); gtk_label_set_text (GTK_LABEL (priv->message_label), gl_journal_entry_get_message (entry)); if (gl_journal_entry_get_audit_session (entry)) { gtk_label_set_text (GTK_LABEL (priv->audit_label), gl_journal_entry_get_audit_session (entry)); gtk_widget_show (priv->audit_field_label); gtk_widget_show (priv->audit_label); } if (gl_journal_entry_get_kernel_device (entry)) { gtk_label_set_text (GTK_LABEL (priv->device_label), gl_journal_entry_get_kernel_device (entry)); gtk_widget_show (priv->device_field_label); gtk_widget_show (priv->device_label); } /* TODO: Give a user-friendly representation of the priority. */ str = g_strdup_printf ("%d", gl_journal_entry_get_priority (entry)); gtk_label_set_text (GTK_LABEL (priv->priority_label), str); g_free (str); if (gl_journal_entry_get_catalog (entry) != NULL) { gint subject_count = 0; gint definedby_count = 0; gint support_count = 0; gint documentation_count = 0; str_copy = g_strdup (gl_journal_entry_get_catalog (entry)); do { const gchar *label; if (subject_count == 0 && definedby_count == 0 && support_count == 0 && documentation_count == 0) { str_field = strtok (str_copy, " "); } else { str_field = strtok (NULL, " "); } if (g_strcmp0 (str_field, "Subject:") == 0) { subject_count++; if (subject_count == 1) { str_message = strtok (NULL, "\n"); if (str_message && *str_message) { gtk_label_set_text (GTK_LABEL (priv->subject_label), str_message); gtk_widget_show (priv->subject_field_label); gtk_widget_show (priv->subject_label); } } else { str_field = strtok (NULL, "\n"); label = gtk_label_get_text (GTK_LABEL (priv->subject_label)); str = g_strconcat (label, "\n", str_field, NULL); if (str && *str) { gtk_label_set_text (GTK_LABEL (priv->subject_label), str); gtk_widget_show (priv->subject_field_label); gtk_widget_show (priv->subject_label); } g_free (str); } } else if (g_strcmp0 (str_field, "Defined-By:") == 0) { definedby_count++; if (subject_count == 1) { str_message = strtok (NULL, "\n"); if (str_message && *str_message) { gtk_label_set_text (GTK_LABEL (priv->definedby_label), str_message); gtk_widget_show (priv->definedby_field_label); gtk_widget_show (priv->definedby_label); } } else { str_field = strtok (NULL, "\n"); label = gtk_label_get_text (GTK_LABEL (priv->subject_label)); str = g_strconcat (label, "\n", str_field, NULL); if (str && *str) { gtk_label_set_text (GTK_LABEL (priv->definedby_label), str); gtk_widget_show (priv->definedby_field_label); gtk_widget_show (priv->definedby_label); } g_free (str); } } else if (g_strcmp0 (str_field, "Support:") == 0) { support_count++; if (support_count == 1) { str_message = strtok (NULL, "\n"); if (str_message && *str_message) { gchar *str_link; /* According to the spec, this should be a URI */ str_link = g_strdup_printf ("%s", str_message, str_message); gtk_label_set_markup (GTK_LABEL (priv->support_label), str_link); gtk_widget_show (priv->support_field_label); gtk_widget_show (priv->support_label); g_free (str_link); } } else { str_field = strtok (NULL, "\n"); label = gtk_label_get_text (GTK_LABEL (priv->subject_label)); str = g_strconcat (label, "\n", str_field, NULL); if (str && *str) { gchar *str_link; /* According to the spec, this should be a URI */ str_link = g_strdup_printf ("%s", str, str); gtk_label_set_markup (GTK_LABEL (priv->support_label), str_link); gtk_widget_show (priv->support_field_label); gtk_widget_show (priv->support_label); g_free (str_link); } g_free (str); } } else if (g_strcmp0 (str_field, "Documentation:") == 0) { documentation_count++; if (documentation_count == 1) { str_message = strtok (NULL, "\n"); if (str_message && *str_message) { gtk_label_set_text (GTK_LABEL (priv->documentation_label), str_message); gtk_widget_show (priv->documentation_field_label); gtk_widget_show (priv->documentation_label); } } else { str_field = strtok (NULL, "\n"); label = gtk_label_get_text (GTK_LABEL (priv->subject_label)); str = g_strconcat (label, "\n", str_field, NULL); if (str && *str) { gtk_label_set_text (GTK_LABEL (priv->documentation_label), str); gtk_widget_show (priv->documentation_field_label); gtk_widget_show (priv->documentation_label); } g_free (str); } } } while (g_strcmp0 (str_field, "Subject:") == 0 || g_strcmp0 (str_field, "Defined-By:") == 0 || g_strcmp0 (str_field, "Support:") == 0 || g_strcmp0 (str_field, "Documentation:") == 0); str = strtok (NULL, "\0"); str_field = g_strconcat (str_field, " ", str, NULL); if (str_field && *str_field) { gtk_label_set_text (GTK_LABEL (priv->detailed_message_label), str_field); gtk_widget_show (priv->detailed_message_label); } g_free (str_field); g_free (str_copy); } } static void gl_event_view_detail_popover_closed (GtkPopover *popover, gpointer user_data) { GtkWidget *row; GtkWidget *category_label; GtkWidget *time_label; GtkStyleContext *context; row = gtk_widget_get_parent (GTK_WIDGET (popover)); context = gtk_widget_get_style_context (row); gtk_style_context_remove_class (context, "popover-activated-row"); category_label = gl_event_view_row_get_category_label (GL_EVENT_VIEW_ROW (row)); if (category_label) { context = gtk_widget_get_style_context (category_label); gtk_style_context_add_class (context, "dim-label"); } time_label = gl_event_view_row_get_time_label (GL_EVENT_VIEW_ROW (row)); context = gtk_widget_get_style_context (time_label); gtk_style_context_add_class (context, "dim-label"); } static void gl_event_view_detail_finalize (GObject *object) { GlEventViewDetail *detail = GL_EVENT_VIEW_DETAIL (object); GlEventViewDetailPrivate *priv = gl_event_view_detail_get_instance_private (detail); g_clear_object (&priv->entry); G_OBJECT_CLASS (gl_event_view_detail_parent_class)->finalize (object); } static void gl_event_view_detail_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GlEventViewDetail *detail = GL_EVENT_VIEW_DETAIL (object); GlEventViewDetailPrivate *priv = gl_event_view_detail_get_instance_private (detail); switch (prop_id) { case PROP_CLOCK_FORMAT: g_value_set_enum (value, priv->clock_format); break; case PROP_ENTRY: g_value_set_object (value, priv->entry); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gl_event_view_detail_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GlEventViewDetail *detail = GL_EVENT_VIEW_DETAIL (object); GlEventViewDetailPrivate *priv = gl_event_view_detail_get_instance_private (detail); switch (prop_id) { case PROP_CLOCK_FORMAT: priv->clock_format = g_value_get_enum (value); break; case PROP_ENTRY: priv->entry = g_value_dup_object (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gl_event_view_detail_constructed (GObject *object) { GlEventViewDetail *detail = GL_EVENT_VIEW_DETAIL (object); /* contruct-only properties have already been set. */ gl_event_view_detail_create_detail (detail); G_OBJECT_CLASS (gl_event_view_detail_parent_class)->constructed (object); } static void gl_event_view_detail_class_init (GlEventViewDetailClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); gobject_class->constructed = gl_event_view_detail_constructed; gobject_class->finalize = gl_event_view_detail_finalize; gobject_class->get_property = gl_event_view_detail_get_property; gobject_class->set_property = gl_event_view_detail_set_property; obj_properties[PROP_CLOCK_FORMAT] = g_param_spec_enum ("clock-format", "Clock format", "Format of the clock in which to show timestamps", GL_TYPE_UTIL_CLOCK_FORMAT, GL_UTIL_CLOCK_FORMAT_24HR, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); obj_properties[PROP_ENTRY] = g_param_spec_object ("entry", "Entry", "Row entry for this detailed view", GL_TYPE_ROW_ENTRY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (gobject_class, N_PROPERTIES, obj_properties); gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Logs/gl-eventviewdetail.ui"); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, grid); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, comm_field_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, comm_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, time_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, message_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, audit_field_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, audit_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, device_field_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, device_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, priority_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, subject_field_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, subject_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, definedby_field_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, definedby_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, support_field_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, support_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, documentation_field_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, documentation_label); gtk_widget_class_bind_template_child_private (widget_class, GlEventViewDetail, detailed_message_label); gtk_widget_class_bind_template_callback (widget_class, gl_event_view_detail_popover_closed); } static void gl_event_view_detail_init (GlEventViewDetail *detail) { gtk_widget_init_template (GTK_WIDGET (detail)); } GtkWidget * gl_event_view_detail_new (GlRowEntry *entry, GlUtilClockFormat clock_format) { return g_object_new (GL_TYPE_EVENT_VIEW_DETAIL, "entry", entry, "clock-format", clock_format, NULL); }