Index: logview/logview-prefs.h
===================================================================
--- logview/logview-prefs.h	(Revision 8464)
+++ logview/logview-prefs.h	(Arbeitskopie)
@@ -21,6 +21,8 @@
 #ifndef __LOGVIEW_PREFS_H__
 #define __LOGVIEW_PREFS_H__
 
+#include "logview-filter.h"
+
 #define LOGVIEW_TYPE_PREFS logview_prefs_get_type()
 #define LOGVIEW_PREFS(obj) \
   (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_PREFS, LogviewPrefs))
@@ -50,29 +52,38 @@
                                  const char *font_name);
   void (* have_tearoff_changed) (LogviewPrefs *prefs,
                                  gboolean have_tearoff);
+  void (* filters_changed)      (LogviewPrefs *prefs);
 };
 
 GType          logview_prefs_get_type (void);
 
 /* public methods */
 
-LogviewPrefs * logview_prefs_get (void);
-void           logview_prefs_store_window_size       (LogviewPrefs *prefs,
-                                                      int width, int height);
-void           logview_prefs_get_stored_window_size  (LogviewPrefs *prefs,
-                                                      int *width, int *height);
-char *         logview_prefs_get_monospace_font_name (LogviewPrefs *prefs);
-gboolean       logview_prefs_get_have_tearoff        (LogviewPrefs *prefs);
-void           logview_prefs_store_log               (LogviewPrefs *prefs,
-                                                      GFile *file);
-void           logview_prefs_remove_stored_log       (LogviewPrefs *prefs,
-                                                      GFile *target);
-GSList *       logview_prefs_get_stored_logfiles     (LogviewPrefs *prefs);
-void           logview_prefs_store_fontsize          (LogviewPrefs *prefs,
-                                                      int fontsize);
-int            logview_prefs_get_stored_fontsize     (LogviewPrefs *prefs);
-void           logview_prefs_store_active_logfile    (LogviewPrefs *prefs,
-                                                      const char *filename);
-char *         logview_prefs_get_active_logfile      (LogviewPrefs *prefs);
+LogviewPrefs *  logview_prefs_get (void);
+void            logview_prefs_store_window_size       (LogviewPrefs *prefs,
+                                                       int width, int height);
+void            logview_prefs_get_stored_window_size  (LogviewPrefs *prefs,
+                                                       int *width, int *height);
+char *          logview_prefs_get_monospace_font_name (LogviewPrefs *prefs);
+gboolean        logview_prefs_get_have_tearoff        (LogviewPrefs *prefs);
+void            logview_prefs_store_log               (LogviewPrefs *prefs,
+                                                       GFile *file);
+void            logview_prefs_remove_stored_log       (LogviewPrefs *prefs,
+                                                       GFile *target);
+GSList *        logview_prefs_get_stored_logfiles     (LogviewPrefs *prefs);
+void            logview_prefs_store_fontsize          (LogviewPrefs *prefs,
+                                                       int fontsize);
+int             logview_prefs_get_stored_fontsize     (LogviewPrefs *prefs);
+void            logview_prefs_store_active_logfile    (LogviewPrefs *prefs,
+                                                       const char *filename);
+char *          logview_prefs_get_active_logfile      (LogviewPrefs *prefs);
 
-#endif /* __LOG_PREFS_H__ */
\ No newline at end of file
+GList *         logview_prefs_get_filters             (LogviewPrefs *prefs);
+void            logview_prefs_remove_filter           (LogviewPrefs *prefs,
+                                                       const gchar* name);
+void            logview_prefs_add_filter              (LogviewPrefs *prefs,
+                                                       LogviewFilter *filter);
+LogviewFilter * logview_prefs_get_filter              (LogviewPrefs *prefs,
+                                                       const gchar *name);
+
+#endif /* __LOG_PREFS_H__ */
Index: logview/logview-filter.c
===================================================================
--- logview/logview-filter.c	(Revision 0)
+++ logview/logview-filter.c	(Revision 0)
@@ -0,0 +1,191 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/*
+ * gnome-utils
+ * Copyright (C) Johannes Schmid 2009 <jhs@gnome.org>
+ * 
+ * gnome-utils 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.
+ * 
+ * gnome-utils 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "logview-filter.h"
+
+enum
+{
+  PROP_0,
+  PROP_REGEX,
+  PROP_NAME,
+  PROP_TEXTTAG
+};
+
+G_DEFINE_TYPE (LogviewFilter, logview_filter, G_TYPE_OBJECT);
+
+struct _LogviewFilterPrivate
+{
+  GRegex* regex;
+  gchar* name;
+  GtkTextTag* tag;
+};
+
+#define LOGVIEW_FILTER_GET_PRIVATE(o)  \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_FILTER, LogviewFilterPrivate))
+
+static void
+logview_filter_init (LogviewFilter *object)
+{
+  object->priv = LOGVIEW_FILTER_GET_PRIVATE(object);
+  object->priv->tag = NULL;
+}
+
+static void
+logview_filter_finalize (GObject *object)
+{
+  LogviewFilterPrivate *priv = LOGVIEW_FILTER (object)->priv;
+  if (priv->tag)
+    g_object_unref (priv->tag);
+  g_regex_unref (priv->regex);
+
+  G_OBJECT_CLASS (logview_filter_parent_class)->finalize (object);
+}
+
+static void
+logview_filter_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+  g_return_if_fail (LOGVIEW_IS_FILTER (object));
+  LogviewFilterPrivate* priv = LOGVIEW_FILTER(object)->priv;
+
+  switch (prop_id)
+  {
+    case PROP_NAME:
+      priv->name = g_value_dup_string (value);
+      break;
+    case PROP_REGEX:
+    {
+      GError* err = NULL;
+      const gchar* regex = g_value_get_string (value);
+      priv->regex = g_regex_new (regex, 0, 0, &err);
+
+      if (err)
+      {
+        g_regex_unref (priv->regex);
+        priv->regex = NULL;
+      }
+      break;
+    }
+    case PROP_TEXTTAG:
+    {
+      if (priv->tag)
+        g_object_unref (priv->tag);
+      priv->tag = g_value_dup_object (value);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+logview_filter_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+  g_return_if_fail (LOGVIEW_IS_FILTER (object));
+  LogviewFilterPrivate* priv = LOGVIEW_FILTER(object)->priv;
+  switch (prop_id)
+  {
+    case PROP_REGEX:
+      g_value_set_string (value, g_regex_get_pattern(priv->regex));
+      break;
+    case PROP_NAME:
+      g_value_set_string (value, priv->name);
+      break;
+    case PROP_TEXTTAG:
+      g_value_set_object (value, priv->tag);
+      break;
+  }
+}
+
+static void
+logview_filter_class_init (LogviewFilterClass *klass)
+{
+  GObjectClass* object_class = G_OBJECT_CLASS (klass);
+  GObjectClass* parent_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = logview_filter_finalize;
+  object_class->set_property = logview_filter_set_property;
+  object_class->get_property = logview_filter_get_property;
+
+  g_object_class_install_property (object_class,
+                                   PROP_REGEX,
+                                   g_param_spec_string ("regex",
+                                                        "regular expression",
+                                                        "regular expression",
+                                                        "NULL",
+                                                        G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
+                                   PROP_NAME,
+                                   g_param_spec_string ("name",
+                                                        "name",
+                                                        "name",
+                                                        "NULL",
+                                                        G_PARAM_WRITABLE | G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY));
+
+  g_object_class_install_property (object_class,
+                                   PROP_TEXTTAG,
+                                   g_param_spec_object ("texttag",
+                                                        "texttag",
+                                                        "The text tag to be set on matching lines",
+                                                        GTK_TYPE_TEXT_TAG,
+                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+
+  g_type_class_add_private (klass, sizeof (LogviewFilterPrivate));
+}
+
+
+LogviewFilter*
+logview_filter_new (const gchar *name, const gchar *regex)
+{
+  return LOGVIEW_FILTER (g_object_new (LOGVIEW_TYPE_FILTER,
+                                       "name", name,
+                                       "regex", regex,
+                                       NULL));
+}
+
+gboolean
+logview_filter_filter (LogviewFilter *filter, const gchar *line)
+{
+  g_return_val_if_fail (LOGVIEW_IS_FILTER (filter), FALSE);
+  g_return_val_if_fail (line != NULL, FALSE);
+
+  GMatchInfo* match_info;
+  LogviewFilterPrivate* priv;
+  gboolean retval;
+  
+  priv = filter->priv;
+
+  g_regex_match (priv->regex, line, 0, &match_info);
+
+  retval = g_match_info_matches (match_info);
+
+  g_match_info_free (match_info);
+
+  return retval;
+}
+
+GtkTextTag *
+logview_filter_get_tag (LogviewFilter *filter)
+{
+  g_return_val_if_fail (LOGVIEW_IS_FILTER (filter), NULL);
+  
+  return filter->priv->tag;
+}
Index: logview/logview-filter.h
===================================================================
--- logview/logview-filter.h	(Revision 0)
+++ logview/logview-filter.h	(Revision 0)
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/*
+ * gnome-utils
+ * Copyright (C) Johannes Schmid 2009 <jhs@gnome.org>
+ * 
+ * gnome-utils 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.
+ * 
+ * gnome-utils 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LOGVIEW_FILTER_H_
+#define _LOGVIEW_FILTER_H_
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define LOGVIEW_TYPE_FILTER             (logview_filter_get_type ())
+#define LOGVIEW_FILTER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_FILTER, LogviewFilter))
+#define LOGVIEW_FILTER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_FILTER, LogviewFilterClass))
+#define LOGVIEW_IS_FILTER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_FILTER))
+#define LOGVIEW_IS_FILTER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_FILTER))
+#define LOGVIEW_FILTER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_FILTER, LogviewFilterClass))
+
+typedef struct _LogviewFilterClass LogviewFilterClass;
+typedef struct _LogviewFilter LogviewFilter;
+typedef struct _LogviewFilterPrivate LogviewFilterPrivate;
+
+struct _LogviewFilterClass
+{
+  GObjectClass parent_class;
+};
+
+struct _LogviewFilter
+{
+  GObject parent_instance;
+
+  LogviewFilterPrivate *priv;
+};
+
+GType           logview_filter_get_type (void) G_GNUC_CONST;
+LogviewFilter * logview_filter_new (const gchar *name, 
+                                    const gchar *regex);
+gboolean        logview_filter_filter (LogviewFilter *filter, 
+                                       const gchar *line);
+GtkTextTag *    logview_filter_get_tag (LogviewFilter *filter);
+
+G_END_DECLS
+
+#endif /* _LOGVIEW_FILTER_H_ */
Index: logview/logview-filter-manager.c
===================================================================
--- logview/logview-filter-manager.c	(Revision 0)
+++ logview/logview-filter-manager.c	(Revision 0)
@@ -0,0 +1,558 @@
+/*-*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/*
+ * gnome-utils
+ * Copyright (C) Johannes Schmid 2009 <jhs@gnome.org>
+ *
+ * gnome-utils 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.
+ *
+ * gnome-utils 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "logview-filter-manager.h"
+#include "logview-prefs.h"
+#include <gtk/gtk.h>
+#include <string.h>
+#include <glib/gi18n.h>
+
+#define UI_FILE LOGVIEW_DATADIR "/logview-filter.ui"
+
+struct _LogviewFilterManagerPrivate
+{
+  GtkWidget *tree;
+
+  GtkWidget *add_button;
+  GtkWidget *remove_button;
+  GtkWidget *edit_button;
+
+  GtkTreeModel *model;
+  GtkBuilder* builder;
+};
+
+enum
+{
+  COLUMN_NAME = 0,
+  COLUMN_FILTER,
+  N_COLUMNS
+};
+
+#define LOGVIEW_FILTER_MANAGER_GET_PRIVATE(o)  \
+(G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_FILTER_MANAGER, LogviewFilterManagerPrivate))
+
+G_DEFINE_TYPE (LogviewFilterManager, logview_filter_manager, GTK_TYPE_DIALOG);
+
+static void
+logview_filter_manager_update_model (LogviewFilterManager *manager)
+{
+  GList *filters;
+  GList *filter;
+
+  gtk_list_store_clear (GTK_LIST_STORE (manager->priv->model));
+
+  filters = logview_prefs_get_filters (logview_prefs_get());  
+  for (filter = filters; filter != NULL; filter = g_list_next (filter))
+  {
+    gchar *name;
+    GtkTreeIter iter;
+
+    g_object_get (filter->data, "name", &name, NULL);
+
+    gtk_list_store_append (GTK_LIST_STORE(manager->priv->model),
+                           &iter);
+    gtk_list_store_set (GTK_LIST_STORE (manager->priv->model),
+                        &iter,
+                        COLUMN_NAME, name,
+                        COLUMN_FILTER, filter->data,
+                        -1);
+    g_free(name);
+  }
+  g_list_free (filters);  
+}
+
+static gboolean
+check_name (LogviewFilterManager *manager, const gchar *name)
+{
+  if (!strlen (name))
+  {
+    GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (manager),
+                                                GTK_DIALOG_MODAL,
+                                                GTK_MESSAGE_ERROR,
+                                                GTK_BUTTONS_CLOSE,
+                                                "%s", _("Filter name is empty!"));
+    gtk_dialog_run (GTK_DIALOG (dialog));
+    gtk_widget_destroy (dialog);
+    return FALSE;
+  }
+  else if (strstr (name, ":") != NULL)
+  {
+    GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(manager),
+                                                GTK_DIALOG_MODAL,
+                                                GTK_MESSAGE_ERROR,
+                                                GTK_BUTTONS_CLOSE,
+                                                "%s", _("Filter name may not contain the ':' character"));
+    gtk_dialog_run (GTK_DIALOG (dialog));
+    gtk_widget_destroy (dialog);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+static gboolean
+check_regex (LogviewFilterManager *manager, const gchar *regex)
+{
+  if (!strlen (regex))
+  {
+    GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW(manager),
+                                                GTK_DIALOG_MODAL,
+                                                GTK_MESSAGE_ERROR,
+                                                GTK_BUTTONS_CLOSE,
+                                                "%s", _("Regular expression is empty!"));
+    gtk_dialog_run (GTK_DIALOG (dialog));
+    gtk_widget_destroy (dialog);
+    return FALSE;
+  }
+  else
+  {
+    GError *error = NULL;
+    GRegex *reg = g_regex_new (regex,
+                               0, 0, &error);
+    if (error)
+    {
+      GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (manager),
+                                                  GTK_DIALOG_MODAL,
+                                                  GTK_MESSAGE_ERROR,
+                                                  GTK_BUTTONS_CLOSE,
+                                                  _("Regular expression is invalid: %s"),
+                                                  error->message);
+      gtk_dialog_run (GTK_DIALOG (dialog));
+      gtk_widget_destroy (dialog);
+      g_error_free (error);
+      return FALSE;
+    }
+    g_regex_unref (reg);
+  }
+  return TRUE;
+}
+
+static void
+on_check_toggled (GtkToggleButton *button, GtkWidget *widget)
+{
+  gboolean status = gtk_toggle_button_get_active (button);
+  gtk_widget_set_sensitive (widget, status);
+}
+
+static void
+on_dialog_add_edit_reponse (GtkWidget *dialog, int response_id,
+                            LogviewFilterManager *manager)
+{
+  GtkWidget *entry_name;
+  GtkWidget *entry_regex;
+
+  GtkWidget *radio_color;
+  GtkWidget *radio_visible;
+
+  GtkWidget *check_foreground;
+  GtkWidget *check_background;
+  GtkWidget *color_foreground;
+  GtkWidget *color_background;
+  
+  gchar *old_name = g_object_get_data (G_OBJECT (manager), "old_name");
+
+  GtkBuilder *builder = manager->priv->builder;
+
+  entry_name = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                   "entry_name"));
+  entry_regex = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                    "entry_regex"));
+  radio_color = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                    "radio_color"));
+  radio_visible = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                      "radio_visible"));
+  check_foreground = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                         "check_foreground"));
+  check_background = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                         "check_background"));
+  color_foreground = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                         "color_foreground"));
+  color_background = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                         "color_background"));
+
+  if (response_id == GTK_RESPONSE_APPLY)
+  {
+    const gchar *name;
+    const gchar *regex;
+
+    name = gtk_entry_get_text (GTK_ENTRY (entry_name));
+    regex = gtk_entry_get_text (GTK_ENTRY (entry_regex));
+
+    if (!check_name(manager, name) || !check_regex(manager, regex))
+    {
+      return;
+    }
+    else
+    {
+      LogviewFilter *filter;
+      GtkTextTag *tag;
+
+      filter = logview_filter_new (name, regex);
+      tag = gtk_text_tag_new (name);
+
+      if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_color)))
+      {
+        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_foreground)))
+        {
+          GdkColor foreground_color;
+          gtk_color_button_get_color (GTK_COLOR_BUTTON (color_foreground),
+                                      &foreground_color);
+          g_object_set (G_OBJECT (tag), 
+                        "foreground-gdk", &foreground_color,
+                        "foreground-set", TRUE, NULL);
+        }
+        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_background)))
+        {
+          GdkColor background_color;
+          gtk_color_button_get_color (GTK_COLOR_BUTTON (color_background),
+                                      &background_color);
+          g_object_set (tag, 
+                        "paragraph-background-gdk", &background_color,
+                        "paragraph-background-set", TRUE, NULL);
+        }
+        if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_foreground))
+            && !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check_background)))
+        {
+          GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (manager),
+                                                      GTK_DIALOG_MODAL,
+                                                      GTK_MESSAGE_ERROR,
+                                                      GTK_BUTTONS_CLOSE,
+                                                      "%s",
+                                                      _("Please specify either foreground or background color!"));
+          gtk_dialog_run (GTK_DIALOG (dialog));
+          gtk_widget_destroy (dialog);
+          g_object_unref (tag);
+          g_object_unref (filter);
+          return;
+        }
+      }
+      else
+      {
+        g_object_set (tag, "invisible", TRUE, NULL);
+      }
+      if (old_name && !g_str_equal (old_name, name))
+      {
+        logview_prefs_remove_filter (logview_prefs_get(), old_name);
+      }
+      g_object_set (G_OBJECT (filter), "texttag", tag, NULL);
+      g_object_unref (tag);
+      logview_prefs_add_filter (logview_prefs_get(), filter);
+      g_object_unref (filter);
+      logview_filter_manager_update_model (manager);
+    }
+  }
+  
+  g_free (old_name);
+  gtk_widget_destroy (dialog);
+}
+
+static void
+run_add_edit_dialog (LogviewFilterManager *manager, LogviewFilter *filter)
+{
+  int response;
+
+  GError *error = NULL;
+  gchar *name = NULL;
+
+  GtkWidget *dialog;
+
+  GtkWidget *entry_name;
+  GtkWidget *entry_regex;
+
+  GtkWidget *radio_color;
+  GtkWidget *radio_visible;
+
+  GtkWidget *check_foreground;
+  GtkWidget *check_background;
+  GtkWidget *color_foreground;
+  GtkWidget *color_background;
+
+  GtkWidget *vbox_color;
+  const gchar *title;
+  
+  GtkBuilder* builder = manager->priv->builder;
+  gtk_builder_add_from_file (manager->priv->builder, UI_FILE, NULL);
+  if (error)
+  {
+    g_warning ("Could not load filter ui: %s", error->message);
+    return;
+  }
+
+
+  title = (filter != NULL ? _("Edit filter") : _("Add new filter"));
+
+  dialog = GTK_WIDGET (gtk_builder_get_object (builder,
+                                               "dialog_filter"));
+
+  entry_name = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                   "entry_name"));
+  entry_regex = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                    "entry_regex"));
+  radio_color = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                    "radio_color"));
+  radio_visible = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                      "radio_visible"));
+
+  gtk_radio_button_set_group (GTK_RADIO_BUTTON (radio_color),
+                              gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio_visible)));
+
+  check_foreground = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                         "check_foreground"));
+  check_background = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                         "check_background"));
+  color_foreground = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                         "color_foreground"));
+  color_background = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                         "color_background"));
+  g_signal_connect (check_foreground, "toggled", G_CALLBACK(on_check_toggled),
+                    color_foreground);
+  g_signal_connect (check_background, "toggled", G_CALLBACK(on_check_toggled),
+                    color_background);
+
+  on_check_toggled (GTK_TOGGLE_BUTTON (check_foreground),
+                    color_foreground);
+  on_check_toggled (GTK_TOGGLE_BUTTON (check_background),
+                    color_background);
+
+  vbox_color = GTK_WIDGET (gtk_builder_get_object (builder, "vbox_color"));
+  g_signal_connect (radio_color, "toggled", G_CALLBACK(on_check_toggled),
+                    vbox_color);
+  on_check_toggled (GTK_TOGGLE_BUTTON (radio_color),
+                    vbox_color);
+
+  if (filter)
+  {
+    gchar *regex;
+    GdkColor *foreground;
+    GdkColor *background;
+    gboolean foreground_set;
+    gboolean background_set;
+    gboolean invisible;
+    GtkTextTag *tag;
+
+    g_object_get (filter,
+                  "name", &name,
+                  "regex", &regex,
+                  "texttag", &tag,
+                  NULL);
+    g_object_get (tag,
+                  "foreground-gdk", &foreground,
+                  "foreground-set", &foreground_set,
+                  "paragraph-background-gdk", &background,
+                  "paragraph-background-set", &background_set,
+                  "invisible", &invisible, NULL);
+    gtk_entry_set_text (GTK_ENTRY(entry_name), name);
+    gtk_entry_set_text (GTK_ENTRY(entry_regex), regex);
+    if (foreground_set)
+    {
+      gtk_color_button_set_color (GTK_COLOR_BUTTON (color_foreground),
+                                  foreground);
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_foreground),
+                                    TRUE);
+      gdk_color_free (foreground);
+    }
+    if (background_set)
+    {
+
+      gtk_color_button_set_color (GTK_COLOR_BUTTON (color_background),
+                                  background);
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_background),
+                                    TRUE);
+      gdk_color_free (background);
+    }
+    if (background_set || foreground_set)
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_color), TRUE);
+    else if (invisible)
+      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio_visible), TRUE);
+    g_free(regex);
+    g_object_unref (tag);
+  }
+
+  g_object_set_data (G_OBJECT(manager), "old_name", name);
+
+  g_signal_connect (G_OBJECT (dialog), "response",
+                    G_CALLBACK (on_dialog_add_edit_reponse), manager);
+  gtk_window_set_transient_for (GTK_WINDOW (dialog),
+                                GTK_WINDOW (manager));
+  gtk_dialog_run (GTK_DIALOG (dialog));
+}
+
+static void
+on_add_clicked (GtkWidget *button, LogviewFilterManager *manager)
+{                                                   
+  run_add_edit_dialog (manager, NULL);
+}
+
+static void
+on_edit_clicked (GtkWidget *button, LogviewFilterManager *manager)
+{
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  LogviewFilter *filter;
+  GtkTreeSelection *selection;
+
+  selection = 
+    gtk_tree_view_get_selection (GTK_TREE_VIEW (manager->priv->tree));
+
+  gtk_tree_selection_get_selected (selection, &model, &iter);
+  gtk_tree_model_get (model, &iter, COLUMN_FILTER, &filter, -1);
+
+  run_add_edit_dialog (manager, filter);
+  g_object_unref (filter);
+}
+
+static void
+on_remove_clicked (GtkWidget *button, LogviewFilterManager *manager)
+{
+  GtkTreeSelection *selection;
+  GtkTreeIter iter;
+  GtkTreeModel *model;
+  gchar *name;
+
+  selection  = 
+    gtk_tree_view_get_selection (GTK_TREE_VIEW (manager->priv->tree));
+
+
+  gtk_tree_selection_get_selected (selection, &model, &iter);
+  gtk_tree_model_get (model, &iter, COLUMN_NAME, &name, -1);
+
+  logview_prefs_remove_filter (logview_prefs_get(), name);
+  logview_filter_manager_update_model (manager);
+  g_free(name);
+}
+
+static void
+on_tree_selection_changed (GtkTreeSelection *selection, LogviewFilterManager *manager)
+{
+  gboolean status;
+
+  status = gtk_tree_selection_get_selected (selection, NULL, NULL);
+  gtk_widget_set_sensitive (manager->priv->edit_button, status);
+  gtk_widget_set_sensitive (manager->priv->remove_button, status);	
+}
+
+static void
+logview_filter_manager_init (LogviewFilterManager *manager)
+{
+  GtkWidget *table;
+  GtkWidget *scrolled_window;
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *text_renderer;
+  LogviewFilterManagerPrivate *priv;
+
+  manager->priv = LOGVIEW_FILTER_MANAGER_GET_PRIVATE(manager);
+  priv = manager->priv;
+  
+  priv->builder = gtk_builder_new ();
+  
+  gtk_dialog_add_button (GTK_DIALOG(manager),
+                         GTK_STOCK_CLOSE,
+                         GTK_RESPONSE_CLOSE);
+  priv->model = GTK_TREE_MODEL(gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_OBJECT));
+  logview_filter_manager_update_model(manager);
+
+  table = gtk_table_new (3, 2, FALSE);
+  scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
+                                       GTK_SHADOW_ETCHED_IN);
+  priv->tree = gtk_tree_view_new_with_model (priv->model);
+  gtk_widget_set_size_request (priv->tree, 150, 200);
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->tree), FALSE);
+  gtk_container_add (GTK_CONTAINER (scrolled_window), priv->tree);
+
+  text_renderer = gtk_cell_renderer_text_new ();
+
+  column = gtk_tree_view_column_new();
+  gtk_tree_view_column_pack_start (column, text_renderer, TRUE);
+  gtk_tree_view_column_set_attributes (column,
+                                       text_renderer,
+                                       "text", COLUMN_NAME,
+                                       NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (priv->tree),
+                               column);
+
+  priv->add_button = gtk_button_new_from_stock (GTK_STOCK_ADD);
+  priv->edit_button = gtk_button_new_from_stock (GTK_STOCK_PROPERTIES);
+  priv->remove_button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+
+  gtk_window_set_title (GTK_WINDOW (manager),
+                        _("Filters"));
+
+  g_signal_connect (priv->add_button, "clicked", 
+                    G_CALLBACK (on_add_clicked), manager);
+  g_signal_connect (priv->edit_button, "clicked", 
+                    G_CALLBACK (on_edit_clicked), manager);
+  g_signal_connect (priv->remove_button, "clicked", 
+                    G_CALLBACK (on_remove_clicked), manager);
+
+  gtk_widget_set_sensitive (priv->edit_button, FALSE);
+  gtk_widget_set_sensitive (priv->remove_button, FALSE);
+
+  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW(priv->tree)),
+                    "changed",
+                    G_CALLBACK (on_tree_selection_changed),
+                    manager);
+
+  gtk_table_attach_defaults (GTK_TABLE (table),
+                             scrolled_window,
+                             0, 1, 0, 3);
+  gtk_table_attach (GTK_TABLE(table),
+                    priv->add_button,
+                    1, 2, 0, 1, GTK_FILL, 0, 5, 5);
+  gtk_table_attach (GTK_TABLE(table),
+                    priv->edit_button,
+                    1, 2, 1, 2, GTK_FILL, 0, 5, 5);
+  gtk_table_attach (GTK_TABLE(table),
+                    priv->remove_button,
+                    1, 2, 2, 3, GTK_FILL, 0, 5, 5);
+  gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG(manager))),
+                      table, TRUE, TRUE, 5);
+  gtk_widget_show_all (GTK_WIDGET (manager));  
+}
+
+static void
+logview_filter_manager_dispose (GObject *object)
+{
+  LogviewFilterManager* manager;
+
+  manager = LOGVIEW_FILTER_MANAGER (object);
+  
+  g_object_unref (manager->priv->builder);
+  
+  G_OBJECT_CLASS (logview_filter_manager_parent_class)->dispose (object);
+}
+
+static void
+logview_filter_manager_class_init (LogviewFilterManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkDialogClass *parent_class = GTK_DIALOG_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (LogviewFilterManagerPrivate));
+
+  object_class->dispose = logview_filter_manager_dispose;
+}
+
+
+GtkWidget *
+logview_filter_manager_new (void)
+{
+  return GTK_WIDGET(g_object_new (LOGVIEW_TYPE_FILTER_MANAGER, NULL));
+}
Index: logview/logview-filter-manager.h
===================================================================
--- logview/logview-filter-manager.h	(Revision 0)
+++ logview/logview-filter-manager.h	(Revision 0)
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
+/*
+ * gnome-utils
+ * Copyright (C) Johannes Schmid 2009 <jhs@gnome.org>
+ * 
+ * gnome-utils 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.
+ * 
+ * gnome-utils 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LOGVIEW_FILTER_MANAGER_H_
+#define _LOGVIEW_FILTER_MANAGER_H_
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define LOGVIEW_TYPE_FILTER_MANAGER             (logview_filter_manager_get_type ())
+#define LOGVIEW_FILTER_MANAGER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_FILTER_MANAGER, LogviewFilterManager))
+#define LOGVIEW_FILTER_MANAGER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_FILTER_MANAGER, LogviewFilterManagerClass))
+#define LOGVIEW_IS_FILTER_MANAGER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_FILTER_MANAGER))
+#define LOGVIEW_IS_FILTER_MANAGER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_FILTER_MANAGER))
+#define LOGVIEW_FILTER_MANAGER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_FILTER_MANAGER, LogviewFilterManagerClass))
+
+typedef struct _LogviewFilterManagerClass LogviewFilterManagerClass;
+typedef struct _LogviewFilterManager LogviewFilterManager;
+typedef struct _LogviewFilterManagerPrivate LogviewFilterManagerPrivate;
+
+struct _LogviewFilterManagerClass
+{
+	GtkDialogClass parent_class;
+};
+
+struct _LogviewFilterManager
+{
+	GtkDialog parent_instance;
+
+	LogviewFilterManagerPrivate* priv;
+};
+
+GType       logview_filter_manager_get_type (void) G_GNUC_CONST;
+GtkWidget * logview_filter_manager_new (void);
+
+G_END_DECLS
+
+#endif /* _LOGVIEW_FILTER_MANAGER_H_ */
Index: logview/data/Makefile.am
===================================================================
--- logview/data/Makefile.am	(Revision 8464)
+++ logview/data/Makefile.am	(Arbeitskopie)
@@ -1,5 +1,5 @@
 xmldir = $(pkgdatadir)
-xml_DATA = logview-toolbar.xml
+xml_DATA = logview-toolbar.xml logview-filter.ui
 
 desktopdir = $(datadir)/applications
 desktop_in_files = gnome-system-log.desktop.in
Index: logview/data/logview-toolbar.xml
===================================================================
--- logview/data/logview-toolbar.xml	(Revision 8464)
+++ logview/data/logview-toolbar.xml	(Arbeitskopie)
@@ -19,6 +19,12 @@
       <menuitem action="ViewZoomOut"/>
       <menuitem action="ViewZoom100"/>
     </menu>
+    <menu action="FilterMenu">
+      <placeholder name="PlaceholderFilters"/>
+      <separator />
+      <menuitem action="FilterMatchOnly" />
+      <menuitem action="FilterManage" />
+    </menu>
     <menu action="HelpMenu">
       <menuitem action="HelpContents"/>
       <menuitem action="AboutAction"/>
Index: logview/data/logview-filter.ui
===================================================================
--- logview/data/logview-filter.ui	(Revision 0)
+++ logview/data/logview-filter.ui	(Revision 0)
@@ -0,0 +1,238 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.14"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="dialog_filter">
+    <property name="border_width">5</property>
+    <property name="modal">True</property>
+    <property name="type_hint">normal</property>
+    <property name="has_separator">False</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox2">
+        <property name="visible">True</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkTable" id="table1">
+            <property name="visible">True</property>
+            <property name="n_rows">3</property>
+            <property name="n_columns">2</property>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Name:</property>
+              </object>
+              <packing>
+                <property name="x_options"></property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label2">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Regular Expression:</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options"></property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry_name">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry_regex">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="label_xalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment1">
+                    <property name="visible">True</property>
+                    <property name="left_padding">12</property>
+                    <child>
+                      <object class="GtkTable" id="table2">
+                        <property name="visible">True</property>
+                        <property name="n_rows">2</property>
+                        <property name="n_columns">2</property>
+                        <child>
+                          <object class="GtkRadioButton" id="radio_color">
+                            <property name="label" translatable="yes">Highlight</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkRadioButton" id="radio_visible">
+                            <property name="label" translatable="yes">Hide</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                          <packing>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkVBox" id="vbox_color">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkHBox" id="hbox1">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkCheckButton" id="check_foreground">
+                                    <property name="label" translatable="yes">Foreground:</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkColorButton" id="color_foreground">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="hbox2">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkCheckButton" id="check_background">
+                                    <property name="label" translatable="yes">Background:</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkColorButton" id="color_background">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Effect:&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area2">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label" translatable="yes">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button2">
+                <property name="label" translatable="yes">gtk-apply</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-6">button1</action-widget>
+      <action-widget response="-10">button2</action-widget>
+    </action-widgets>
+  </object>
+</interface>
Index: logview/logview-marshal.c
===================================================================
--- logview/logview-marshal.c	(Revision 0)
+++ logview/logview-marshal.c	(Revision 0)
@@ -0,0 +1,87 @@
+#include "logview-marshal.h"
+
+#include	<glib-object.h>
+
+
+#ifdef G_ENABLE_DEBUG
+#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
+#define g_marshal_value_peek_char(v)     g_value_get_char (v)
+#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
+#define g_marshal_value_peek_int(v)      g_value_get_int (v)
+#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
+#define g_marshal_value_peek_long(v)     g_value_get_long (v)
+#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
+#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
+#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
+#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
+#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
+#define g_marshal_value_peek_float(v)    g_value_get_float (v)
+#define g_marshal_value_peek_double(v)   g_value_get_double (v)
+#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
+#define g_marshal_value_peek_param(v)    g_value_get_param (v)
+#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
+#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
+#define g_marshal_value_peek_object(v)   g_value_get_object (v)
+#else /* !G_ENABLE_DEBUG */
+/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
+ *          Do not access GValues directly in your code. Instead, use the
+ *          g_value_get_*() functions
+ */
+#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
+#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
+#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
+#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
+#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
+#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
+#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
+#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
+#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
+#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
+#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
+#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
+#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
+#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
+#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
+#endif /* !G_ENABLE_DEBUG */
+
+
+/* VOID:OBJECT,OBJECT (logview-marshal.list:1) */
+void
+logview_marshal_VOID__OBJECT_OBJECT (GClosure     *closure,
+                                     GValue       *return_value G_GNUC_UNUSED,
+                                     guint         n_param_values,
+                                     const GValue *param_values,
+                                     gpointer      invocation_hint G_GNUC_UNUSED,
+                                     gpointer      marshal_data)
+{
+  typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer     data1,
+                                                    gpointer     arg_1,
+                                                    gpointer     arg_2,
+                                                    gpointer     data2);
+  register GMarshalFunc_VOID__OBJECT_OBJECT callback;
+  register GCClosure *cc = (GCClosure*) closure;
+  register gpointer data1, data2;
+
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    {
+      data1 = closure->data;
+      data2 = g_value_peek_pointer (param_values + 0);
+    }
+  else
+    {
+      data1 = g_value_peek_pointer (param_values + 0);
+      data2 = closure->data;
+    }
+  callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback);
+
+  callback (data1,
+            g_marshal_value_peek_object (param_values + 1),
+            g_marshal_value_peek_object (param_values + 2),
+            data2);
+}
+
Index: logview/logview-marshal.h
===================================================================
--- logview/logview-marshal.h	(Revision 0)
+++ logview/logview-marshal.h	(Revision 0)
@@ -0,0 +1,20 @@
+
+#ifndef __logview_marshal_MARSHAL_H__
+#define __logview_marshal_MARSHAL_H__
+
+#include	<glib-object.h>
+
+G_BEGIN_DECLS
+
+/* VOID:OBJECT,OBJECT (logview-marshal.list:1) */
+extern void logview_marshal_VOID__OBJECT_OBJECT (GClosure     *closure,
+                                                 GValue       *return_value,
+                                                 guint         n_param_values,
+                                                 const GValue *param_values,
+                                                 gpointer      invocation_hint,
+                                                 gpointer      marshal_data);
+
+G_END_DECLS
+
+#endif /* __logview_marshal_MARSHAL_H__ */
+
Index: logview/logview-window.c
===================================================================
--- logview/logview-window.c	(Revision 8464)
+++ logview/logview-window.c	(Arbeitskopie)
@@ -33,6 +33,7 @@
 #include "logview-about.h"
 #include "logview-prefs.h"
 #include "logview-manager.h"
+#include "logview-filter-manager.h"
 
 #include "gtkmessagearea.h"
 
@@ -43,6 +44,7 @@
 struct _LogviewWindowPrivate {
   GtkUIManager *ui_manager;
   GtkActionGroup *action_group;
+  GtkActionGroup *filter_action_group;
 
   GtkWidget *find_bar;
   GtkWidget *loglist;
@@ -66,6 +68,10 @@
 
   gulong monitor_id;
   guint search_timeout_id;
+
+  guint filter_merge_id;
+  GList *active_filters;
+  gboolean matches_only;
 };
 
 #define GET_PRIVATE(o) \
@@ -123,7 +129,7 @@
 populate_tag_table (GtkTextTagTable *tag_table)
 {
   GtkTextTag *tag;
-
+  
   tag = gtk_text_tag_new ("bold");
   g_object_set (tag, "weight", PANGO_WEIGHT_BOLD,
                 "weight-set", TRUE, NULL);
@@ -132,9 +138,12 @@
 
   tag = gtk_text_tag_new ("invisible");
   g_object_set (tag, "invisible", TRUE, "invisible-set", TRUE, NULL);
-
   gtk_text_tag_table_add (tag_table, tag);
 
+  
+  tag = gtk_text_tag_new ("invisible-filter");
+  g_object_set (tag, "invisible", TRUE, "invisible-set", TRUE, NULL);
+  gtk_text_tag_table_add (tag_table, tag); 
 }
 
 
@@ -584,6 +593,187 @@
 }
 
 static void
+filter_buffer (LogviewWindow *logview, gint start_line)
+{
+  GtkTextBuffer* buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
+  int lines = gtk_text_buffer_get_line_count (buffer);
+  int i;
+  GdkRectangle visible_rect;
+  for (i = start_line; i < lines; i++)
+  {
+    GtkTextIter start, end;
+    gchar* text;
+    GList* cur_filter;
+    gboolean matched = FALSE;
+    
+    gtk_text_buffer_get_iter_at_line (buffer, &start, i);
+    gtk_text_buffer_get_iter_at_line (buffer, &end, i + 1);
+
+    gtk_text_iter_forward_to_line_end (&end);
+    text = gtk_text_buffer_get_text (buffer,
+                                     &start,
+                                     &end,
+                                     TRUE);
+    for (cur_filter = logview->priv->active_filters; cur_filter != NULL;
+         cur_filter = g_list_next (cur_filter))
+    {
+      if (logview_filter_filter (LOGVIEW_FILTER (cur_filter->data),
+                                               text))
+      {
+        gtk_text_buffer_apply_tag (buffer, 
+                                   logview_filter_get_tag (LOGVIEW_FILTER (cur_filter->data)),
+                                   &start, &end);
+        matched = TRUE;
+      }
+    }
+    if (!matched && logview->priv->matches_only)
+    {
+      gtk_text_buffer_apply_tag_by_name (buffer, 
+                                         "invisible-filter",
+                                         &start, &end);
+    }
+    else
+    {
+      gtk_text_buffer_remove_tag_by_name (buffer,
+                                          "invisible-filter",
+                                          &start, &end);
+    }
+  }
+}
+
+static void
+filter_remove (LogviewWindow *logview, LogviewFilter *filter)
+{
+  GtkTextIter start, end;
+  GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
+  gtk_text_buffer_get_bounds (buffer, &start, &end);
+  gtk_text_buffer_remove_tag (buffer,
+                              logview_filter_get_tag (filter),
+                              &start,
+                              &end);
+}
+
+static void
+on_filter_toggled (GtkToggleAction *action, LogviewWindow *logview)
+{
+  LogviewWindowPrivate *priv = GET_PRIVATE (logview);
+  const gchar* name = gtk_action_get_name (GTK_ACTION (action));
+  
+  if (gtk_toggle_action_get_active (action))
+  {
+    priv->active_filters = g_list_append (priv->active_filters,
+                                          logview_prefs_get_filter (logview_prefs_get (),
+                                                                    name));
+    filter_buffer(logview, 0);
+  }
+  else
+  {
+    LogviewFilter* filter = logview_prefs_get_filter (logview_prefs_get (),
+                                                      name);
+    priv->active_filters = g_list_remove (priv->active_filters,
+                                          filter);
+    filter_remove (logview, filter);
+  }
+}
+
+#define FILTER_PLACEHOLDER "/LogviewMenu/FilterMenu/PlaceholderFilters"
+static void
+update_filter_menu (LogviewWindow *window)
+{
+  LogviewWindowPrivate *priv;
+  GtkUIManager* ui;
+  GList *actions, *l;
+  gint n, i;
+  guint id;
+  GList *filters;
+  GtkTextBuffer *buffer;
+  GtkTextTagTable *table;
+
+  priv = GET_PRIVATE (window);
+  ui = priv->ui_manager;
+
+    g_return_if_fail (priv->filter_action_group != NULL);
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
+  table = priv->tag_table;
+
+  if (priv->filter_merge_id != 0)
+    gtk_ui_manager_remove_ui (ui,
+                              priv->filter_merge_id);
+
+  actions = gtk_action_group_list_actions (priv->filter_action_group);
+  for (l = actions; l != NULL; l = g_list_next (l))
+  {
+    GtkTextTag *tag = gtk_text_tag_table_lookup (table, 
+                                                 gtk_action_get_name (GTK_ACTION (l->data)));
+    gtk_text_tag_table_remove (table, tag);
+    g_signal_handlers_disconnect_by_func (GTK_ACTION (l->data),
+                                          G_CALLBACK (on_filter_toggled),
+                                          window);
+    gtk_action_group_remove_action (priv->filter_action_group,
+                                    GTK_ACTION (l->data));
+  }
+  g_list_free (actions);
+  
+  filters = logview_prefs_get_filters (logview_prefs_get ());
+
+  id = (g_list_length (filters) > 0) ? gtk_ui_manager_new_merge_id (ui) : 0;
+
+  for (l = filters; l != NULL; l = g_list_next (l))
+  {
+    GtkToggleAction *action;
+    gchar* name;
+
+    g_object_get (l->data, "name", &name, NULL);
+
+    action = gtk_toggle_action_new (name,
+                                    name,
+                                    NULL,
+                                    NULL);
+
+    gtk_action_group_add_action (priv->filter_action_group,
+                                 GTK_ACTION (action));
+
+    g_signal_connect (action,
+                      "toggled",
+                      G_CALLBACK (on_filter_toggled),
+                      window);
+
+    gtk_ui_manager_add_ui (ui,
+                           id,
+                           FILTER_PLACEHOLDER,
+                           name, name,
+                           GTK_UI_MANAGER_MENUITEM,
+                           FALSE);
+
+    gtk_text_tag_table_add (table, 
+                            logview_filter_get_tag (LOGVIEW_FILTER (l->data)));
+
+    g_object_unref (action);
+    g_free(name);
+  }
+  priv->filter_merge_id = id;
+}
+
+static void
+logview_manage_filters (GtkAction *action, LogviewWindow *logview)
+{
+  GtkWidget *manager;
+
+  manager = logview_filter_manager_new ();
+  
+  gtk_window_set_transient_for (GTK_WINDOW (manager),
+                                GTK_WINDOW (logview));
+  gtk_dialog_run (GTK_DIALOG(manager)); 
+  gtk_widget_destroy (GTK_WIDGET(manager));
+
+  g_list_free (logview->priv->active_filters);
+  logview->priv->active_filters = NULL;
+  
+  update_filter_menu (logview);
+}
+
+static void
 logview_about (GtkWidget *widget, GtkWidget *window)
 {
   g_return_if_fail (GTK_IS_WINDOW (window));
@@ -629,6 +819,13 @@
     gtk_widget_show (logview->priv->sidebar);
 }
 
+static void
+logview_toggle_match_filters (GtkToggleAction *action, LogviewWindow *logview)
+{
+  logview->priv->matches_only = gtk_toggle_action_get_active (action);
+  filter_buffer (logview, 0);
+}
+
 /* GObject functions */
 
 /* Menus */
@@ -637,6 +834,7 @@
     { "FileMenu", NULL, N_("_File"), NULL, NULL, NULL },
     { "EditMenu", NULL, N_("_Edit"), NULL, NULL, NULL },
     { "ViewMenu", NULL, N_("_View"), NULL, NULL, NULL },
+    { "FilterMenu", NULL, N_("_Filters"), NULL, NULL, NULL },  
     { "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
 
     { "OpenLog", GTK_STOCK_OPEN, N_("_Open..."), "<control>O", N_("Open a log from file"), 
@@ -660,6 +858,9 @@
     { "ViewZoom100", GTK_STOCK_ZOOM_100, NULL, "<control>0", N_("Normal text size"),
       G_CALLBACK (logview_normal_text)},
 
+    { "FilterManage", NULL, N_("Manage Filters"), NULL, N_("Manage filters"),
+      G_CALLBACK (logview_manage_filters)},
+  
     { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", N_("Open the help contents for the log viewer"), 
       G_CALLBACK (logview_help) },
     { "AboutAction", GTK_STOCK_ABOUT, N_("_About"), NULL, N_("Show the about dialog for the log viewer"), 
@@ -671,6 +872,8 @@
       G_CALLBACK (logview_toggle_statusbar), TRUE },
     { "ShowSidebar", NULL, N_("Side _Pane"), "F9", N_("Show Side Pane"), 
       G_CALLBACK (logview_toggle_sidebar), TRUE }, 
+    { "FilterMatchOnly", NULL, N_("Show matches only"), NULL, N_("Only show lines that match one of the given filters"),
+      G_CALLBACK (logview_toggle_match_filters), FALSE}
 };
 
 static gboolean 
@@ -1241,6 +1444,13 @@
   gtk_box_pack_start (GTK_BOX (vbox), priv->statusbar, FALSE, FALSE, 0);
   gtk_widget_show (priv->statusbar);
 
+  /* Filter menu */
+  priv->filter_action_group = gtk_action_group_new ("ActionGroupFilter");
+  gtk_ui_manager_insert_action_group (priv->ui_manager, priv->filter_action_group,
+                                      1);
+  priv->active_filters = NULL;
+  update_filter_menu (logview);
+  
   gtk_widget_show (vbox);
   gtk_widget_show (main_view);
 }
Index: logview/Makefile.am
===================================================================
--- logview/Makefile.am	(Revision 8464)
+++ logview/Makefile.am	(Arbeitskopie)
@@ -38,6 +38,10 @@
 	logview-findbar.c	\
 	logview-prefs.c		\
 	logview-prefs.h		\
+	logview-filter.h       \
+	logview-filter.c       \
+	logview-filter-manager.h       \
+	logview-filter-manager.c  \
 	$(BUILT_SOURCES)
 
 gnome_system_log_LDADD =	\
Index: logview/logview-prefs.c
===================================================================
--- logview/logview-prefs.c	(Revision 8464)
+++ logview/logview-prefs.c	(Arbeitskopie)
@@ -42,6 +42,7 @@
 #define GCONF_LOGFILE 		GCONF_DIR "/logfile"
 #define GCONF_LOGFILES 		GCONF_DIR "/logfiles"
 #define GCONF_FONTSIZE_KEY 	GCONF_DIR "/fontsize"
+#define GCONF_FILTERS     GCONF_DIR "/filters"
 
 /* desktop-wide settings */
 #define GCONF_MONOSPACE_FONT_NAME "/desktop/gnome/interface/monospace_font_name"
@@ -55,6 +56,15 @@
   LAST_SIGNAL
 };
 
+enum {
+  FILTER_NAME,
+  FILTER_INVISIBLE,
+  FILTER_FOREGROUND,
+  FILTER_BACKGROUND,
+  FILTER_REGEX,
+  MAX_TOKENS
+};
+
 static guint signals[LAST_SIGNAL] = { 0 };
 
 #define GET_PRIVATE(o) \
@@ -64,6 +74,8 @@
   GConfClient *client;
 
   guint size_store_timeout;
+
+  GHashTable *filters;
 };
 
 typedef struct {
@@ -78,6 +90,8 @@
 {
   LogviewPrefs *prefs = LOGVIEW_PREFS (obj);
 
+  g_hash_table_destroy (prefs->priv->filters);
+
   g_object_unref (prefs->priv->client);
 
   G_OBJECT_CLASS (logview_prefs_parent_class)->finalize (obj);
@@ -170,7 +184,127 @@
   return FALSE;
 }
 
+#define DELIMITER ":"
+
 static void
+load_filters (LogviewPrefs *prefs)
+{
+  GSList *node; 
+  GSList *filters = gconf_client_get_list (prefs->priv->client,
+                                           GCONF_FILTERS,
+                                           GCONF_VALUE_STRING,
+                                           NULL);
+  prefs->priv->filters = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                (GDestroyNotify) g_free,
+                                                (GDestroyNotify) g_object_unref);
+  for (node = filters; node != NULL; node = g_slist_next (node))
+  {
+    gchar **tokens = g_strsplit (node->data, DELIMITER, MAX_TOKENS);
+    LogviewFilter *filter = logview_filter_new (tokens[FILTER_NAME], tokens[FILTER_REGEX]);
+    GtkTextTag *tag = gtk_text_tag_new (tokens[FILTER_NAME]);
+    g_object_set (tag, "invisible", g_str_equal (tokens[FILTER_INVISIBLE], "1"), NULL);
+    if (strlen (tokens[FILTER_FOREGROUND]))
+    {
+      GdkColor color;
+      gdk_color_parse (tokens[FILTER_FOREGROUND], &color);
+      g_object_set (tag, "foreground-gdk", &color, 
+                    "foreground-set", TRUE, NULL);
+    }
+    if (strlen (tokens[FILTER_BACKGROUND]))
+    {
+      GdkColor color;
+      gdk_color_parse (tokens[FILTER_BACKGROUND], &color);
+      g_object_set (tag, "background-gdk", &color, 
+                    "background-set", TRUE, NULL);
+    }
+    g_object_set (filter, "texttag", tag, NULL);
+    g_hash_table_insert (prefs->priv->filters, 
+                         g_strdup(tokens[FILTER_NAME]), 
+                         filter);
+    g_object_ref (filter);
+    g_object_unref (tag);
+    g_strfreev(tokens);
+  }
+  g_slist_foreach (filters, (GFunc) g_free, NULL);
+  g_slist_free (filters);
+}
+
+static void
+save_filter_foreach_func (gpointer key, gpointer value, gpointer user_data)
+{
+  GSList **filters = user_data;
+  const gchar *name = key;
+  LogviewFilter *filter = LOGVIEW_FILTER (value);
+
+  GdkColor *foreground;
+  gboolean foreground_set;
+  GdkColor *background;
+  gboolean background_set;
+  gchar *regex;
+  gboolean invisible;
+  GtkTextTag *tag;
+  GString *prefs_string = g_string_new(name);
+  g_string_append (prefs_string, DELIMITER);
+  
+  g_object_get (filter,
+                "regex", &regex,
+                "texttag", &tag,
+                NULL);
+  g_object_get (tag,
+                "foreground-gdk", &foreground,
+                "background-gdk", &background,
+                "foreground-set", &foreground_set,
+                "background-set", &background_set,
+                "invisible", &invisible, NULL);
+
+  if (invisible)
+  {
+    g_string_append(prefs_string, "1" DELIMITER);
+  }
+  else
+  {
+    g_string_append(prefs_string, "0" DELIMITER);
+  }
+  if (foreground_set)
+  {
+    gchar* color = gdk_color_to_string (foreground);
+    g_string_append(prefs_string, color);
+    g_free(color);
+    gdk_color_free(foreground);
+  }
+  g_string_append(prefs_string, DELIMITER);
+  if (background_set)
+  {
+    gchar* color = gdk_color_to_string (background);
+    g_string_append(prefs_string, color);
+    g_free(color);
+    gdk_color_free(background);
+  }
+  g_string_append(prefs_string, DELIMITER);
+  
+  g_string_append(prefs_string, regex);
+  g_free(regex);
+  g_object_unref (tag);
+  
+  *filters = g_slist_prepend (*filters, g_string_free (prefs_string, FALSE));
+} 
+
+static void
+save_filters (LogviewPrefs *prefs)
+{
+  GSList *filters = NULL;
+  g_hash_table_foreach (prefs->priv->filters,
+                        save_filter_foreach_func,
+                        &filters);
+  gconf_client_set_list (prefs->priv->client,
+                         GCONF_FILTERS,
+                         GCONF_VALUE_STRING,
+                         filters, NULL);
+  g_slist_foreach (filters, (GFunc) g_free, NULL);
+  g_slist_free (filters);
+}
+
+static void
 logview_prefs_init (LogviewPrefs *self)
 {
   gboolean stored_logs;
@@ -189,6 +323,8 @@
                            GCONF_MENUS_HAVE_TEAROFF,
                            (GConfClientNotifyFunc) have_tearoff_changed_cb,
                            self, NULL, NULL);
+
+  load_filters (self);
 }
 
 /* public methods */
@@ -410,3 +546,49 @@
 
   return filename;
 }
+
+static void
+get_filters_foreach (gpointer key, gpointer value, gpointer user_data)
+{
+  GList **list = user_data;
+  *list = g_list_append (*list, value);
+}
+
+GList *
+logview_prefs_get_filters (LogviewPrefs *prefs)
+{
+  GList *filters = NULL;
+  g_hash_table_foreach (prefs->priv->filters,
+                        get_filters_foreach,
+                        &filters);
+  return filters;
+}
+
+void
+logview_prefs_remove_filter (LogviewPrefs *prefs,
+                             const gchar *name)
+{
+  g_hash_table_remove (prefs->priv->filters,
+                       name);
+  save_filters (prefs);
+}
+
+void
+logview_prefs_add_filter (LogviewPrefs *prefs,
+                          LogviewFilter *filter)
+{
+  gchar* name;
+  g_object_get (filter, "name", &name, NULL);
+
+  g_hash_table_insert (prefs->priv->filters, name, g_object_ref(filter));
+  
+  save_filters (prefs);
+}
+
+LogviewFilter *
+logview_prefs_get_filter (LogviewPrefs *prefs,
+                          const gchar *name)
+{
+  return g_hash_table_lookup (prefs->priv->filters, name);
+}
+
