From c9cadcd53d03e73475dd266aad223a1ebc9229b5 Mon Sep 17 00:00:00 2001 From: monsta Date: Wed, 9 Sep 2015 10:46:57 +0300 Subject: logview: move sources to src/ subdir --- configure.ac | 3 +- logview/Makefile.am | 73 +- logview/logview-about.h | 67 -- logview/logview-app.c | 420 --------- logview/logview-app.h | 71 -- logview/logview-filter-manager.c | 575 ------------- logview/logview-filter-manager.h | 54 -- logview/logview-filter.c | 200 ----- logview/logview-filter.h | 59 -- logview/logview-findbar.c | 352 -------- logview/logview-findbar.h | 72 -- logview/logview-log.c | 936 -------------------- logview/logview-log.h | 110 --- logview/logview-loglist.c | 500 ----------- logview/logview-loglist.h | 68 -- logview/logview-main.c | 120 --- logview/logview-manager.c | 432 ---------- logview/logview-manager.h | 90 -- logview/logview-marshal.list | 1 - logview/logview-prefs.c | 546 ------------ logview/logview-prefs.h | 89 -- logview/logview-utils.c | 282 ------- logview/logview-utils.h | 40 - logview/logview-window.c | 1548 ---------------------------------- logview/logview-window.h | 56 -- logview/src/Makefile.am | 73 ++ logview/src/logview-about.h | 67 ++ logview/src/logview-app.c | 420 +++++++++ logview/src/logview-app.h | 71 ++ logview/src/logview-filter-manager.c | 575 +++++++++++++ logview/src/logview-filter-manager.h | 54 ++ logview/src/logview-filter.c | 200 +++++ logview/src/logview-filter.h | 59 ++ logview/src/logview-findbar.c | 352 ++++++++ logview/src/logview-findbar.h | 72 ++ logview/src/logview-log.c | 936 ++++++++++++++++++++ logview/src/logview-log.h | 110 +++ logview/src/logview-loglist.c | 500 +++++++++++ logview/src/logview-loglist.h | 68 ++ logview/src/logview-main.c | 120 +++ logview/src/logview-manager.c | 432 ++++++++++ logview/src/logview-manager.h | 90 ++ logview/src/logview-marshal.list | 1 + logview/src/logview-prefs.c | 546 ++++++++++++ logview/src/logview-prefs.h | 89 ++ logview/src/logview-utils.c | 282 +++++++ logview/src/logview-utils.h | 40 + logview/src/logview-window.c | 1548 ++++++++++++++++++++++++++++++++++ logview/src/logview-window.h | 56 ++ logview/src/tests/Makefile.am | 9 + logview/src/tests/test-reader.c | 60 ++ logview/tests/Makefile.am | 9 - logview/tests/test-reader.c | 60 -- po/POTFILES.in | 16 +- 54 files changed, 6841 insertions(+), 6838 deletions(-) delete mode 100644 logview/logview-about.h delete mode 100644 logview/logview-app.c delete mode 100644 logview/logview-app.h delete mode 100644 logview/logview-filter-manager.c delete mode 100644 logview/logview-filter-manager.h delete mode 100644 logview/logview-filter.c delete mode 100644 logview/logview-filter.h delete mode 100644 logview/logview-findbar.c delete mode 100644 logview/logview-findbar.h delete mode 100644 logview/logview-log.c delete mode 100644 logview/logview-log.h delete mode 100644 logview/logview-loglist.c delete mode 100644 logview/logview-loglist.h delete mode 100644 logview/logview-main.c delete mode 100644 logview/logview-manager.c delete mode 100644 logview/logview-manager.h delete mode 100644 logview/logview-marshal.list delete mode 100644 logview/logview-prefs.c delete mode 100644 logview/logview-prefs.h delete mode 100644 logview/logview-utils.c delete mode 100644 logview/logview-utils.h delete mode 100644 logview/logview-window.c delete mode 100644 logview/logview-window.h create mode 100644 logview/src/Makefile.am create mode 100644 logview/src/logview-about.h create mode 100644 logview/src/logview-app.c create mode 100644 logview/src/logview-app.h create mode 100644 logview/src/logview-filter-manager.c create mode 100644 logview/src/logview-filter-manager.h create mode 100644 logview/src/logview-filter.c create mode 100644 logview/src/logview-filter.h create mode 100644 logview/src/logview-findbar.c create mode 100644 logview/src/logview-findbar.h create mode 100644 logview/src/logview-log.c create mode 100644 logview/src/logview-log.h create mode 100644 logview/src/logview-loglist.c create mode 100644 logview/src/logview-loglist.h create mode 100644 logview/src/logview-main.c create mode 100644 logview/src/logview-manager.c create mode 100644 logview/src/logview-manager.h create mode 100644 logview/src/logview-marshal.list create mode 100644 logview/src/logview-prefs.c create mode 100644 logview/src/logview-prefs.h create mode 100644 logview/src/logview-utils.c create mode 100644 logview/src/logview-utils.h create mode 100644 logview/src/logview-window.c create mode 100644 logview/src/logview-window.h create mode 100644 logview/src/tests/Makefile.am create mode 100644 logview/src/tests/test-reader.c delete mode 100644 logview/tests/Makefile.am delete mode 100644 logview/tests/test-reader.c diff --git a/configure.ac b/configure.ac index d5a98eb9..2c320365 100644 --- a/configure.ac +++ b/configure.ac @@ -394,8 +394,9 @@ logview/Makefile logview/data/Makefile logview/data/org.mate.system-log.gschema.xml logview/data/icons/Makefile -logview/tests/Makefile logview/help/Makefile +logview/src/Makefile +logview/src/tests/Makefile gsearchtool/Makefile gsearchtool/data/Makefile diff --git a/logview/Makefile.am b/logview/Makefile.am index 271947d3..d77eddc5 100644 --- a/logview/Makefile.am +++ b/logview/Makefile.am @@ -1,73 +1,2 @@ -SUBDIRS = data help tests - -AM_CPPFLAGS = \ - -DG_LOG_DOMAIN=\"mate-system-log\" \ - -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ - -DDATADIR=\""$(datadir)"\" \ - -DLOGVIEWINSTALLPREFIX=\""$(prefix)/\"" \ - -DLOGVIEW_DATADIR=\""$(pkgdatadir)"\" \ - $(SUN_OS) \ - $(DISABLE_DEPRECATED) \ - $(NULL) - -bin_PROGRAMS = mate-system-log - -BUILT_SOURCES = \ - logview-marshal.c \ - logview-marshal.h - -mate_system_log_SOURCES = \ - logview-app.c \ - logview-app.h \ - logview-main.c \ - logview-about.h \ - logview-manager.c \ - logview-manager.h \ - logview-utils.c \ - logview-utils.h \ - logview-loglist.c \ - logview-loglist.h \ - logview-window.c \ - logview-window.h \ - logview-log.h \ - logview-log.c \ - logview-findbar.h \ - 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) - -mate_system_log_CFLAGS = \ - $(GLIB_CFLAGS) \ - $(GTHREAD_CFLAGS) \ - $(GIO_CFLAGS) \ - $(GTK_CFLAGS) \ - $(NULL) - -mate_system_log_LDADD = \ - $(GLIB_LIBS) \ - $(GIO_LIBS) \ - $(GTHREAD_LIBS) \ - $(GTK_LIBS) \ - $(Z_LIBS) \ - -lm - -logview-marshal.h: logview-marshal.list $(GLIB_GENMARSHAL) - $(GLIB_GENMARSHAL) $< --header --prefix=logview_marshal >> $@ - -logview-marshal.c: logview-marshal.list $(GLIB_GENMARSHAL) - echo "#include \"logview-marshal.h\"" > $@ && \ - $(GLIB_GENMARSHAL) $< --body --prefix=logview_marshal >> $@ - -EXTRA_DIST = logview-marshal.list - -CLEANFILES = \ - $(BUILT_SOURCES) - -dist-hook: - cd $(distdir) ; rm -f $(CLEANFILES) +SUBDIRS = data help src diff --git a/logview/logview-about.h b/logview/logview-about.h deleted file mode 100644 index 9b4b0949..00000000 --- a/logview/logview-about.h +++ /dev/null @@ -1,67 +0,0 @@ -/* logview-about.h - authors and contributors information - * - * Copyright (C) 2004 Vincent Noel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef __LOGVIEW_ABOUT_H__ -#define __LOGVIEW_ABOUT_H__ - -static const char *logview_about_authors[] = { - "Cesar Miquel ", - "Glynn Foster ", - "Fernando Herrera ", - "Shakti Sen ", - "Julio M Merino Vidal ", - "Jason Leach ", - "Christian Neumair ", - "Jan Arne Petersen ", - "Jason Long ", - "Kjartan Maraas ", - "Vincent Noel ", - "Cosimo Cecchi ", - NULL -}; - -static const char *logview_about_documenters[] = { - "Sun GNOME Documentation Team ", - "Vincent Noel ", - "Judith Samson ", - NULL -}; - -static const char * logview_about_license[] = { - N_("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 2 of the License, or " - "(at your option) any later version."), - N_("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."), - N_("You should have received a copy of the GNU General Public License " - "along with this program; if not, write to the Free Software Foundation, Inc., " - "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA") -}; - -/* translator credits */ -static const char *logview_about_translator_credits = N_("translator-credits"); - - -#endif /* __LOGVIEW_ABOUT_H__ */ - diff --git a/logview/logview-app.c b/logview/logview-app.c deleted file mode 100644 index ffa37ec7..00000000 --- a/logview/logview-app.c +++ /dev/null @@ -1,420 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-app.c - logview application singleton - * - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/* logview-app.c */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "logview-app.h" - -#include "logview-manager.h" -#include "logview-window.h" -#include "logview-prefs.h" - -#include - -struct _LogviewAppPrivate { - LogviewPrefs *prefs; - LogviewManager *manager; - LogviewWindow *window; -}; - -enum { - APP_QUIT, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static LogviewApp *app_singleton = NULL; - -G_DEFINE_TYPE (LogviewApp, logview_app, G_TYPE_OBJECT); - -#define GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_APP, LogviewAppPrivate)) - -static gboolean -main_window_delete_cb (GtkWidget *widget, - GdkEvent *event, - gpointer user_data) -{ - LogviewApp *app = user_data; - - g_signal_emit (app, signals[APP_QUIT], 0, NULL); - - return FALSE; -} - -static gboolean -logview_app_set_window (LogviewApp *app) -{ - LogviewWindow *window; - gboolean retval = FALSE; - - window = LOGVIEW_WINDOW (logview_window_new ()); - - if (window) { - app->priv->window = window; - g_signal_connect (window, "delete-event", - G_CALLBACK (main_window_delete_cb), app); - retval = TRUE; - } - - gtk_window_set_default_icon_name ("mate-system-log"); - - return retval; -} - -typedef struct { - LogviewApp *app; - GSList *logs; -} EnumerateJob; - -/* TODO: ideally we should parse configuration files in /etc/logrotate.conf - * and all the files in /etc/logrotate.d/ and group all the logs referring - * to the same entry under a category. Right now, we just do some - * parsing instead, and fill with quasi-sensible defaults. - */ - -/* adapted from sysklogd sources */ -static GSList* -parse_syslog () -{ - char cbuf[BUFSIZ]; - char *cline, *p; - FILE *cf; - GSList *logfiles = NULL; - - if ((cf = fopen ("/etc/syslog.conf", "r")) == NULL) { - return NULL; - } - - cline = cbuf; - while (fgets (cline, sizeof (cbuf) - (cline - cbuf), cf) != NULL) { - gchar **list; - gint i; - - for (p = cline; g_ascii_isspace (*p); ++p); - if (*p == '\0' || *p == '#' || *p == '\n') - continue; - - list = g_strsplit_set (p, ", -\t()\n", 0); - - for (i = 0; list[i]; ++i) { - if (*list[i] == '/' && - g_slist_find_custom (logfiles, list[i], - (GCompareFunc) g_ascii_strcasecmp) == NULL) - { - logfiles = g_slist_insert (logfiles, - g_strdup (list[i]), 0); - } - } - - g_strfreev (list); - } - - fclose (cf); - - return logfiles; -} - -static void -enumerate_job_finish (EnumerateJob *job) -{ - GSList *files = job->logs; - LogviewApp *app = job->app; - - logview_manager_add_logs_from_name_list (app->priv->manager, files, files->data); - - g_slist_foreach (files, (GFunc) g_free, NULL); - g_slist_free (files); - - g_object_unref (job->app); - g_slice_free (EnumerateJob, job); -} - -static void -enumerate_next_files_async_cb (GObject *source, - GAsyncResult *res, - gpointer user_data) -{ - EnumerateJob *job = user_data; - GList *enumerated_files, *l; - GFileInfo *info; - GSList *logs; - const char *content_type, *name; - char *parse_string, *container_path; - GFileType type; - GFile *container; - - enumerated_files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source), - res, NULL); - if (!enumerated_files) { - enumerate_job_finish (job); - return; - } - - logs = job->logs; - container = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source)); - container_path = g_file_get_path (container); - - /* TODO: we don't support grouping rotated logs yet, skip gzipped files - * and those which name contains a formatted date. - */ - for (l = enumerated_files; l; l = l->next) { - info = l->data; - type = g_file_info_get_file_type (info); - content_type = g_file_info_get_content_type (info); - name = g_file_info_get_name (info); - - if (!g_file_info_get_attribute_boolean (info, "access::can-read")) { - g_object_unref (info); - continue; - } - - if (type != (G_FILE_TYPE_REGULAR || G_FILE_TYPE_SYMBOLIC_LINK) || - !g_content_type_is_a (content_type, "text/plain")) - { - g_object_unref (info); - continue; - } - - if (g_content_type_is_a (content_type, "application/x-gzip")) { - g_object_unref (info); - continue; - } - - if (g_regex_match_simple ("\\d{8}$", name, 0, 0)) { - g_object_unref (info); - continue; - } - - parse_string = g_build_filename (container_path, name, NULL); - - if (g_slist_find_custom (logs, parse_string, (GCompareFunc) g_ascii_strcasecmp) == NULL) { - logs = g_slist_append (logs, parse_string); - } else { - g_free (parse_string); - } - - g_object_unref (info); - parse_string = NULL; - } - - g_list_free (enumerated_files); - g_object_unref (container); - g_free (container_path); - - job->logs = logs; - - enumerate_job_finish (job); -} - -static void -enumerate_children_async_cb (GObject *source, - GAsyncResult *res, - gpointer user_data) -{ - EnumerateJob *job = user_data; - GFileEnumerator *enumerator; - - enumerator = g_file_enumerate_children_finish (G_FILE (source), - res, NULL); - if (!enumerator) { - enumerate_job_finish (job); - return; - } - - g_file_enumerator_next_files_async (enumerator, G_MAXINT, - G_PRIORITY_DEFAULT, - NULL, enumerate_next_files_async_cb, job); -} - -static void -logview_app_first_time_initialize (LogviewApp *app) -{ - GSList *logs; - GFile *log_dir; - EnumerateJob *job; - - /* let's add all accessible files in /var/log and those mentioned - * in /etc/syslog.conf. - */ - - logs = parse_syslog (); - - job = g_slice_new0 (EnumerateJob); - job->app = g_object_ref (app); - job->logs = logs; - - log_dir = g_file_new_for_path ("/var/log/"); - g_file_enumerate_children_async (log_dir, - "standard::*,access::can-read", 0, - G_PRIORITY_DEFAULT, NULL, - enumerate_children_async_cb, job); - - g_object_unref (log_dir); -} - -static void -do_finalize (GObject *obj) -{ - LogviewApp *app = LOGVIEW_APP (obj); - - g_object_unref (app->priv->manager); - g_object_unref (app->priv->prefs); - - G_OBJECT_CLASS (logview_app_parent_class)->finalize (obj); -} - -static void -logview_app_class_init (LogviewAppClass *klass) -{ - GObjectClass *oclass = G_OBJECT_CLASS (klass); - - oclass->finalize = do_finalize; - - signals[APP_QUIT] = - g_signal_new ("app-quit", - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewAppClass, app_quit), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_type_class_add_private (klass, sizeof (LogviewAppPrivate)); -} - -static void -logview_app_init (LogviewApp *self) -{ - LogviewAppPrivate *priv = self->priv = GET_PRIVATE (self); - - priv->prefs = logview_prefs_get (); - priv->manager = logview_manager_get (); -} - -LogviewApp* -logview_app_get (void) -{ - if (!app_singleton) { - app_singleton = g_object_new (LOGVIEW_TYPE_APP, NULL); - - if (!logview_app_set_window (app_singleton)) { - g_object_unref (app_singleton); - app_singleton = NULL; - } - } - - return app_singleton; -} - -void -logview_app_initialize (LogviewApp *app, char **log_files) -{ - LogviewAppPrivate *priv; - - g_assert (LOGVIEW_IS_APP (app)); - - priv = app->priv; - - /* open regular logs and add each log passed as a parameter */ - - if (log_files == NULL) { - char *active_log; - gchar **logs; - - active_log = logview_prefs_get_active_logfile (priv->prefs); - logs = logview_prefs_get_stored_logfiles (priv->prefs); - - if (!logs || !logs[0]) { - logview_app_first_time_initialize (app); - } else { - logview_manager_add_logs_from_names (priv->manager, - logs, active_log); - - g_free (active_log); - g_strfreev (logs); - } - } else { - logview_manager_add_logs_from_names (priv->manager, log_files, NULL); - } - - gtk_widget_show (GTK_WIDGET (priv->window)); -} - -void -logview_app_add_error (LogviewApp *app, - const char *file_path, - const char *secondary) -{ - LogviewWindow *window; - char *primary; - - g_assert (LOGVIEW_IS_APP (app)); - - window = app->priv->window; - primary = g_strdup_printf (_("Impossible to open the file %s"), file_path); - - logview_window_add_error (window, primary, secondary); - - g_free (primary); -} - -static void -check_error_prefs (gpointer data, - gpointer user_data) -{ - gchar **strings = data; - LogviewApp *app = user_data; - GFile *file = g_file_new_for_path (strings[0]); - - logview_prefs_remove_stored_log (app->priv->prefs, file); - g_object_unref (file); -} - -void -logview_app_add_errors (LogviewApp *app, - GPtrArray *errors) -{ - LogviewWindow *window; - - g_assert (LOGVIEW_IS_APP (app)); - - window = app->priv->window; - - if (errors->len == 0) { - return; - } - - g_ptr_array_foreach (errors, check_error_prefs, app); - - if (errors->len == 1) { - char **err; - - err = g_ptr_array_index (errors, 0); - logview_window_add_error (window, err[0], err[1]); - } else { - logview_window_add_errors (window, errors); - } -} diff --git a/logview/logview-app.h b/logview/logview-app.h deleted file mode 100644 index 3ce7c059..00000000 --- a/logview/logview-app.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-app.h - logview application singleton - * - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __LOGVIEW_APP_H__ -#define __LOGVIEW_APP_H__ - -#include - -G_BEGIN_DECLS - -#define LOGVIEW_TYPE_APP logview_app_get_type() -#define LOGVIEW_APP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_APP, LogviewApp)) -#define LOGVIEW_APP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_APP, LogviewAppClass)) -#define LOGVIEW_IS_APP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_APP)) -#define LOGVIEW_IS_APP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_APP)) -#define LOGVIEW_APP_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_APP, LogviewAppClass)) - -typedef struct _LogviewApp LogviewApp; -typedef struct _LogviewAppClass LogviewAppClass; -typedef struct _LogviewAppPrivate LogviewAppPrivate; - -struct _LogviewApp { - GObject parent; - - LogviewAppPrivate *priv; -}; - -struct _LogviewAppClass { - GObjectClass parent_class; - - void (* app_quit) (LogviewApp *app); -}; - - -GType logview_app_get_type (void); - -/* public methods */ -LogviewApp * logview_app_get (void); -void logview_app_initialize (LogviewApp *app, - char **log_files); -void logview_app_add_error (LogviewApp *app, - const char *file_path, - const char *secondary); -void logview_app_add_errors (LogviewApp *app, - GPtrArray *errors); - -G_END_DECLS - -#endif /* __LOGVIEW_APP_H__ */ diff --git a/logview/logview-filter-manager.c b/logview/logview-filter-manager.c deleted file mode 100644 index 0905306f..00000000 --- a/logview/logview-filter-manager.c +++ /dev/null @@ -1,575 +0,0 @@ -/*-*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* - * mate-utils - * Copyright (C) Johannes Schmid 2009 - * - * mate-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. - * - * mate-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 . - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "logview-filter-manager.h" -#include "logview-prefs.h" -#include -#include -#include - -#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; - - LogviewPrefs* prefs; -}; - -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; - gchar *name; - GtkTreeIter iter; - - gtk_list_store_clear (GTK_LIST_STORE (manager->priv->model)); - - filters = logview_prefs_get_filters (manager->priv->prefs); - - for (filter = filters; filter != NULL; filter = g_list_next (filter)) { - 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) -{ - GtkWidget *dialog; - - if (!strlen (name)) { - 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; - } - - if (strstr (name, ":") != NULL) { - 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) -{ - GtkWidget *dialog; - GError *error = NULL; - GRegex *reg; - - if (!strlen (regex)) { - 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; - } - - reg = g_regex_new (regex, - 0, 0, &error); - if (error) { - 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) -{ - gtk_widget_set_sensitive (widget, - gtk_toggle_button_get_active (button)); -} - -static void -on_dialog_add_edit_reponse (GtkWidget *dialog, int response_id, - LogviewFilterManager *manager) -{ - GtkWidget *entry_name, *entry_regex; - GtkWidget *radio_color, *radio_visible; - GtkWidget *check_foreground, *check_background; - GtkWidget *color_foreground, *color_background; - gchar *old_name; - const gchar *name; - const gchar *regex; - LogviewFilter *filter; - GtkTextTag *tag; - GtkBuilder *builder; - - old_name = g_object_get_data (G_OBJECT (manager), "old_name"); - 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) { - 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; - } - - 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 *error_dialog; - - error_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 (error_dialog)); - gtk_widget_destroy (error_dialog); - g_object_unref (tag); - g_object_unref (filter); - - return; - } - } else { /* !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_color)) */ - g_object_set (tag, "invisible", TRUE, NULL); - } - - if (old_name && !g_str_equal (old_name, name)) { - logview_prefs_remove_filter (manager->priv->prefs, old_name); - } - - g_object_set (G_OBJECT (filter), "texttag", tag, NULL); - g_object_unref (tag); - - logview_prefs_add_filter (manager->priv->prefs, filter); - g_object_unref (filter); - - logview_filter_manager_update_model (manager); - } - - gtk_widget_destroy (dialog); -} - -static void -run_add_edit_dialog (LogviewFilterManager *manager, LogviewFilter *filter) -{ - GError *error; - gchar *name, *regex; - const gchar *title; - GtkWidget *dialog, *entry_name, *entry_regex, *radio_color; - GtkWidget *radio_visible, *check_foreground, *check_background; - GtkWidget *color_foreground, *color_background, *vbox_color; - gboolean foreground_set, background_set, invisible; - GtkTextTag *tag; - GtkBuilder* builder; - - builder = manager->priv->builder; - - error = NULL; - name = NULL; - - gtk_builder_add_from_file (builder, UI_FILE, &error); - - if (error) { - g_warning ("Could not load filter ui: %s", error->message); - g_error_free (error); - return; - } - - title = (filter != NULL ? _("Edit filter") : _("Add new filter")); - - dialog = GTK_WIDGET (gtk_builder_get_object (builder, - "dialog_filter")); - - gtk_window_set_title (GTK_WINDOW (dialog), title); - - 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) { - g_object_get (filter, - "name", &name, - "regex", ®ex, - "texttag", &tag, - NULL); - g_object_get (tag, - "foreground-set", &foreground_set, - "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) { - GdkColor *foreground; - - g_object_get (tag, "foreground-gdk", &foreground, NULL); - 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) { - GdkColor *background; - - g_object_get (tag, "paragraph-background-gdk", &background, NULL); - 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_full (G_OBJECT (manager), "old_name", name, g_free); - - 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_window_set_modal (GTK_WINDOW (dialog), - TRUE); - - gtk_widget_show (GTK_WIDGET (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 (manager->priv->prefs, 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 (); - g_object_ref (priv->builder); - priv->prefs = logview_prefs_get (); - - gtk_dialog_add_button (GTK_DIALOG(manager), - GTK_STOCK_CLOSE, - GTK_RESPONSE_CLOSE); - gtk_window_set_modal (GTK_WINDOW (manager), - TRUE); - - 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_response (GtkDialog* dialog, gint response_id) -{ - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -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; - parent_class->response = logview_filter_manager_response; -} - -GtkWidget * -logview_filter_manager_new (void) -{ - return g_object_new (LOGVIEW_TYPE_FILTER_MANAGER, NULL); -} diff --git a/logview/logview-filter-manager.h b/logview/logview-filter-manager.h deleted file mode 100644 index c33ea1f7..00000000 --- a/logview/logview-filter-manager.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* - * mate-utils - * Copyright (C) Johannes Schmid 2009 - * - * mate-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. - * - * mate-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 . - */ - -#ifndef _LOGVIEW_FILTER_MANAGER_H_ -#define _LOGVIEW_FILTER_MANAGER_H_ - -#include -#include - -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_ */ diff --git a/logview/logview-filter.c b/logview/logview-filter.c deleted file mode 100644 index b5f9cfc6..00000000 --- a/logview/logview-filter.c +++ /dev/null @@ -1,200 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* - * mate-utils - * Copyright (C) Johannes Schmid 2009 - * - * mate-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. - * - * mate-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 . - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#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_free (priv->name); - - 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) -{ - 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; - const gchar* regex; - - err = NULL; - - 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; - g_warning ("Couldn't create GRegex object: %s", err->message); - g_error_free (err); - } - - 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) -{ - 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); - - 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)); -} - -/* public methods */ - -LogviewFilter* -logview_filter_new (const gchar *name, const gchar *regex) -{ - return g_object_new (LOGVIEW_TYPE_FILTER, - "name", name, - "regex", regex, - NULL); -} - -gboolean -logview_filter_filter (LogviewFilter *filter, const gchar *line) -{ - GMatchInfo* match_info; - LogviewFilterPrivate* priv; - gboolean retval; - - g_return_val_if_fail (LOGVIEW_IS_FILTER (filter), FALSE); - g_return_val_if_fail (line != NULL, FALSE); - - 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; -} diff --git a/logview/logview-filter.h b/logview/logview-filter.h deleted file mode 100644 index 6eb827b8..00000000 --- a/logview/logview-filter.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* - * mate-utils - * Copyright (C) Johannes Schmid 2009 - * - * mate-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. - * - * mate-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 . - */ - -#ifndef _LOGVIEW_FILTER_H_ -#define _LOGVIEW_FILTER_H_ - -#include -#include -#include - -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_ */ diff --git a/logview/logview-findbar.c b/logview/logview-findbar.c deleted file mode 100644 index 3cb53f1d..00000000 --- a/logview/logview-findbar.c +++ /dev/null @@ -1,352 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-findbar.c - find toolbar for logview - * - * Copyright (C) 2005 Vincent Noel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "logview-findbar.h" - -struct _LogviewFindbarPrivate { - GtkWidget *entry; - GtkWidget *message; - - GtkToolItem *clear_button; - GtkToolItem *back_button; - GtkToolItem *forward_button; - GtkToolItem *status_item; - GtkToolItem *separator; - - char *string; - - guint status_bold_id; -}; - -enum { - PREVIOUS, - NEXT, - CLOSE, - TEXT_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE (LogviewFindbar, logview_findbar, GTK_TYPE_TOOLBAR); - -#define GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_FINDBAR, LogviewFindbarPrivate)) - -static void -back_button_clicked_cb (GtkToolButton *button, - gpointer user_data) -{ - LogviewFindbar *findbar = user_data; - - g_signal_emit (findbar, signals[PREVIOUS], 0); -} - -static void -forward_button_clicked_cb (GtkToolButton *button, - gpointer user_data) -{ - LogviewFindbar *findbar = user_data; - - g_signal_emit (findbar, signals[NEXT], 0); -} - -static void -clear_button_clicked_cb (GtkToolButton *button, - gpointer user_data) -{ - LogviewFindbar *findbar = user_data; - - logview_findbar_set_message (findbar, NULL); - gtk_entry_set_text (GTK_ENTRY (findbar->priv->entry), ""); -} - -static void -entry_activate_cb (GtkWidget *entry, - gpointer user_data) -{ - LogviewFindbar *findbar = user_data; - - g_signal_emit (findbar, signals[NEXT], 0); -} - -static void -entry_changed_cb (GtkEditable *editable, - gpointer user_data) -{ - LogviewFindbar *findbar = user_data; - const char *text; - - text = gtk_entry_get_text (GTK_ENTRY (editable)); - - if (g_strcmp0 (text, "") == 0) { - return; - } - - if (g_strcmp0 (findbar->priv->string, text) != 0) { - g_free (findbar->priv->string); - findbar->priv->string = g_strdup (text); - - g_signal_emit (findbar, signals[TEXT_CHANGED], 0); - } -} - -static gboolean -entry_key_press_event_cb (GtkWidget *entry, - GdkEventKey *event, - gpointer user_data) -{ - LogviewFindbar *findbar = user_data; - - if (event->keyval == GDK_KEY_Escape) { - g_signal_emit (findbar, signals[CLOSE], 0); - return TRUE; - } - - return FALSE; -} - -static gboolean -unbold_timeout_cb (gpointer user_data) -{ - LogviewFindbar *findbar = user_data; - PangoFontDescription *desc; - - desc = pango_font_description_new (); - gtk_widget_modify_font (findbar->priv->message, desc); - pango_font_description_free (desc); - - findbar->priv->status_bold_id = 0; - - return FALSE; -} - -static void -logview_findbar_init (LogviewFindbar *findbar) -{ - GtkWidget *label, *w, *box; - GtkToolbar *gtoolbar; - GtkToolItem *item; - LogviewFindbarPrivate *priv; - - priv = findbar->priv = GET_PRIVATE (findbar); - - gtoolbar = GTK_TOOLBAR (findbar); - - gtk_toolbar_set_style (gtoolbar, GTK_TOOLBAR_BOTH_HORIZ); - - priv->status_bold_id = 0; - - /* Find: |_______| */ - w = gtk_alignment_new (0.0, 0.5, 1.0, 1.0); - gtk_alignment_set_padding (GTK_ALIGNMENT (w), 0, 0, 2, 2); - - box = gtk_hbox_new (FALSE, 12); - gtk_container_add (GTK_CONTAINER (w), box); - - label = gtk_label_new_with_mnemonic (_("_Find:")); - gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); - - priv->entry = gtk_entry_new (); - gtk_entry_set_width_chars (GTK_ENTRY (priv->entry), 32); - gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->entry); - gtk_box_pack_start (GTK_BOX (box), priv->entry, TRUE, TRUE, 0); - - item = gtk_tool_item_new (); - gtk_container_add (GTK_CONTAINER (item), w); - gtk_toolbar_insert (gtoolbar, item, -1); - gtk_widget_show_all (GTK_WIDGET (item)); - - /* "Previous" and "Next" buttons */ - w = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE); - priv->back_button = gtk_tool_button_new (w, _("Find Previous")); - gtk_tool_item_set_is_important (priv->back_button, TRUE); - gtk_tool_item_set_tooltip_text (priv->back_button, - _("Find previous occurrence of the search string")); - gtk_toolbar_insert (gtoolbar, priv->back_button, -1); - gtk_widget_show_all (GTK_WIDGET (priv->back_button)); - - w = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE); - priv->forward_button = gtk_tool_button_new (w, _("Find Next")); - gtk_tool_item_set_is_important (priv->forward_button, TRUE); - gtk_tool_item_set_tooltip_text (priv->forward_button, - _("Find next occurrence of the search string")); - gtk_toolbar_insert (gtoolbar, priv->forward_button, -1); - gtk_widget_show_all (GTK_WIDGET (priv->forward_button)); - - /* clear button */ - priv->clear_button = gtk_tool_button_new_from_stock (GTK_STOCK_CLEAR); - gtk_tool_item_set_tooltip_text (priv->clear_button, - _("Clear the search string")); - gtk_toolbar_insert (gtoolbar, priv->clear_button, -1); - gtk_widget_show_all (GTK_WIDGET (priv->clear_button)); - - /* separator */ - priv->separator = gtk_separator_tool_item_new (); - gtk_toolbar_insert (gtoolbar, priv->separator, -1); - - /* message */ - priv->status_item = gtk_tool_item_new (); - gtk_tool_item_set_expand (priv->status_item, TRUE); - priv->message = gtk_label_new (""); - gtk_label_set_use_markup (GTK_LABEL (priv->message), TRUE); - gtk_misc_set_alignment (GTK_MISC (priv->message), 0.0, 0.5); - gtk_container_add (GTK_CONTAINER (priv->status_item), priv->message); - gtk_widget_show (priv->message); - gtk_toolbar_insert (gtoolbar, priv->status_item, -1); - - priv->string = NULL; - - /* signal handlers */ - g_signal_connect (priv->back_button, "clicked", - G_CALLBACK (back_button_clicked_cb), findbar); - g_signal_connect (priv->forward_button, "clicked", - G_CALLBACK (forward_button_clicked_cb), findbar); - g_signal_connect (priv->clear_button, "clicked", - G_CALLBACK (clear_button_clicked_cb), findbar); - g_signal_connect (priv->entry, "activate", - G_CALLBACK (entry_activate_cb), findbar); - g_signal_connect (priv->entry, "changed", - G_CALLBACK (entry_changed_cb), findbar); - g_signal_connect (priv->entry, "key-press-event", - G_CALLBACK (entry_key_press_event_cb), findbar); -} - -static void -do_grab_focus (GtkWidget *widget) -{ - LogviewFindbar *findbar = LOGVIEW_FINDBAR (widget); - - gtk_widget_grab_focus (findbar->priv->entry); -} - -static void -do_finalize (GObject *obj) -{ - LogviewFindbar *findbar = LOGVIEW_FINDBAR (obj); - - g_free (findbar->priv->string); - - G_OBJECT_CLASS (logview_findbar_parent_class)->finalize (obj); -} - -static void -logview_findbar_class_init (LogviewFindbarClass *klass) -{ - GObjectClass *oclass = G_OBJECT_CLASS (klass); - GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); - - oclass->finalize = do_finalize; - - wclass->grab_focus = do_grab_focus; - - signals[PREVIOUS] = g_signal_new ("previous", - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewFindbarClass, previous), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[NEXT] = g_signal_new ("next", - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewFindbarClass, next), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[CLOSE] = g_signal_new ("close", - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewFindbarClass, close), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[TEXT_CHANGED] = g_signal_new ("text-changed", - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewFindbarClass, text_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_type_class_add_private (klass, sizeof (LogviewFindbarPrivate)); -} - -/* public methods */ - -GtkWidget * -logview_findbar_new (void) -{ - GtkWidget *widget; - widget = g_object_new (LOGVIEW_TYPE_FINDBAR, NULL); - return widget; -} - -void -logview_findbar_open (LogviewFindbar *findbar) -{ - g_assert (LOGVIEW_IS_FINDBAR (findbar)); - - gtk_widget_show (GTK_WIDGET (findbar)); - gtk_widget_grab_focus (GTK_WIDGET (findbar)); -} - -const char * -logview_findbar_get_text (LogviewFindbar *findbar) -{ - g_assert (LOGVIEW_IS_FINDBAR (findbar)); - - return findbar->priv->string; -} - -void -logview_findbar_set_message (LogviewFindbar *findbar, - const char *text) -{ - PangoFontDescription *desc; - - g_assert (LOGVIEW_IS_FINDBAR (findbar)); - - if (text) { - desc = pango_font_description_new (); - pango_font_description_set_weight (desc, PANGO_WEIGHT_BOLD); - gtk_widget_modify_font (findbar->priv->message, desc); - pango_font_description_free (desc); - - findbar->priv->status_bold_id = g_timeout_add (600, unbold_timeout_cb, findbar); - } - - gtk_label_set_text (GTK_LABEL (findbar->priv->message), - text != NULL ? text : ""); - g_object_set (findbar->priv->separator, "visible", text != NULL, NULL); - g_object_set (findbar->priv->status_item, "visible", text != NULL, NULL); -} diff --git a/logview/logview-findbar.h b/logview/logview-findbar.h deleted file mode 100644 index 89c65249..00000000 --- a/logview/logview-findbar.h +++ /dev/null @@ -1,72 +0,0 @@ -/* logview-findbar.h - find toolbar for logview - * - * Copyright (C) 2004 Vincent Noel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __LOGVIEW_FINDBAR_H__ -#define __LOGVIEW_FINDBAR_H__ - -#include -#include - -G_BEGIN_DECLS - -#define LOGVIEW_TYPE_FINDBAR \ - (logview_findbar_get_type ()) -#define LOGVIEW_FINDBAR(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_FINDBAR, LogviewFindbar)) -#define LOGVIEW_FINDBAR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_FINDBAR, LogviewFindbarClass)) -#define LOGVIEW_IS_FINDBAR(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_FINDBAR)) -#define LOGVIEW_IS_FINDBAR_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((obj), LOGVIEW_TYPE_FINDBAR)) -#define LOGVIEW_FINDBAR_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_FINDBAR, LogviewFindbarClass)) - -typedef struct _LogviewFindbar LogviewFindbar; -typedef struct _LogviewFindbarClass LogviewFindbarClass; -typedef struct _LogviewFindbarPrivate LogviewFindbarPrivate; - -struct _LogviewFindbar { - GtkToolbar parent_instance; - LogviewFindbarPrivate *priv; -}; - -struct _LogviewFindbarClass { - GtkToolbarClass parent_class; - - /* signals */ - void (* previous) (LogviewFindbar *findbar); - void (* next) (LogviewFindbar *findbar); - void (* close) (LogviewFindbar *findbar); - void (* text_changed) (LogviewFindbar *findbar); -}; - -GType logview_findbar_get_type (void); - -/* public methods */ -GtkWidget * logview_findbar_new (void); -void logview_findbar_open (LogviewFindbar *findbar); -const char * logview_findbar_get_text (LogviewFindbar *findbar); -void logview_findbar_set_message (LogviewFindbar *findbar, - const char *message); - -G_END_DECLS - -#endif /* __LOGVIEW_FINDBAR_H__ */ diff --git a/logview/logview-log.c b/logview/logview-log.c deleted file mode 100644 index 407f49c3..00000000 --- a/logview/logview-log.c +++ /dev/null @@ -1,936 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-log.c - object representation of a logfile - * - * Copyright (C) 1998 Cesar Miquel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include "config.h" - -#include -#include -#include - -#ifdef HAVE_ZLIB -#include -#endif - -#include "logview-log.h" -#include "logview-utils.h" - -G_DEFINE_TYPE (LogviewLog, logview_log, G_TYPE_OBJECT); - -#define GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_LOG, LogviewLogPrivate)) - -enum { - LOG_CHANGED, - LAST_SIGNAL -}; - -static guint signals [LAST_SIGNAL] = { 0 }; - -struct _LogviewLogPrivate { - /* file and monitor */ - GFile *file; - GFileMonitor *mon; - - /* stats about the file */ - time_t file_time; - goffset file_size; - char *display_name; - gboolean has_days; - - /* lines and relative days */ - GSList *days; - GPtrArray *lines; - guint lines_no; - - /* stream poiting to the log */ - GDataInputStream *stream; - gboolean has_new_lines; -}; - -typedef struct { - LogviewLog *log; - GError *err; - LogviewCreateCallback callback; - gpointer user_data; -} LoadJob; - -typedef struct { - LogviewLog *log; - GError *err; - const char **lines; - GSList *new_days; - GCancellable *cancellable; - LogviewNewLinesCallback callback; - gpointer user_data; -} NewLinesJob; - -typedef struct { - GInputStream *parent_str; - guchar * buffer; - GFile *file; - - gboolean last_str_result; - int last_z_result; - z_stream zstream; -} GZHandle; - -static void -do_finalize (GObject *obj) -{ - LogviewLog *log = LOGVIEW_LOG (obj); - char ** lines; - - if (log->priv->stream) { - g_object_unref (log->priv->stream); - log->priv->stream = NULL; - } - - if (log->priv->file) { - g_object_unref (log->priv->file); - log->priv->file = NULL; - } - - if (log->priv->mon) { - g_object_unref (log->priv->mon); - log->priv->mon = NULL; - } - - if (log->priv->days) { - g_slist_foreach (log->priv->days, - (GFunc) logview_utils_day_free, NULL); - g_slist_free (log->priv->days); - log->priv->days = NULL; - } - - if (log->priv->lines) { - lines = (char **) g_ptr_array_free (log->priv->lines, FALSE); - g_strfreev (lines); - log->priv->lines = NULL; - } - - G_OBJECT_CLASS (logview_log_parent_class)->finalize (obj); -} - -static void -logview_log_class_init (LogviewLogClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = do_finalize; - - signals[LOG_CHANGED] = g_signal_new ("log-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewLogClass, log_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_type_class_add_private (klass, sizeof (LogviewLogPrivate)); -} - -static void -logview_log_init (LogviewLog *self) -{ - self->priv = GET_PRIVATE (self); - - self->priv->lines = NULL; - self->priv->lines_no = 0; - self->priv->days = NULL; - self->priv->file = NULL; - self->priv->mon = NULL; - self->priv->has_new_lines = FALSE; - self->priv->has_days = FALSE; -} - -static void -monitor_changed_cb (GFileMonitor *monitor, - GFile *file, - GFile *unused, - GFileMonitorEvent event, - gpointer user_data) -{ - LogviewLog *log = user_data; - - if (event == G_FILE_MONITOR_EVENT_CHANGED) { - log->priv->has_new_lines = TRUE; - g_signal_emit (log, signals[LOG_CHANGED], 0, NULL); - } - /* TODO: handle the case where the log is deleted? */ -} - -static void -setup_file_monitor (LogviewLog *log) -{ - GError *err = NULL; - - log->priv->mon = g_file_monitor (log->priv->file, - 0, NULL, &err); - if (err) { - /* it'd be strange to get this error at this point but whatever */ - g_warning ("Impossible to monitor the log file: the changes won't be notified"); - g_error_free (err); - return; - } - - /* set the rate to 1sec, as I guess it's not unusual to have more than - * one line written consequently or in a short time, being a log file. - */ - g_file_monitor_set_rate_limit (log->priv->mon, 1000); - g_signal_connect (log->priv->mon, "changed", - G_CALLBACK (monitor_changed_cb), log); -} - -static GSList * -add_new_days_to_cache (LogviewLog *log, const char **new_lines, guint lines_offset) -{ - GSList *new_days, *l, *last_cached; - int res; - Day *day, *last; - - new_days = log_read_dates (new_lines, log->priv->file_time); - - /* the days are stored in chronological order, so we compare the last cached - * one with the new we got. - */ - last_cached = g_slist_last (log->priv->days); - - if (!last_cached) { - /* this means the day list is empty (i.e. we're on the first read */ - log->priv->days = logview_utils_day_list_copy (new_days); - return new_days; - } - - for (l = new_days; l; l = l->next) { - res = days_compare (l->data, last_cached->data); - day = l->data; - - if (res > 0) { - /* this day in the list is newer than the last one, append to - * the cache. - */ - day->first_line += lines_offset; - day->last_line += lines_offset; - log->priv->days = g_slist_append (log->priv->days, logview_utils_day_copy (day)); - } else if (res == 0) { - last = last_cached->data; - - /* update the lines number */ - last->last_line += day->last_line; - } - } - - return new_days; -} - -static gboolean -new_lines_job_done (gpointer data) -{ - NewLinesJob *job = data; - - if (job->err) { - job->callback (job->log, NULL, NULL, job->err, job->user_data); - g_error_free (job->err); - } else { - job->callback (job->log, job->lines, job->new_days, job->err, job->user_data); - } - - g_clear_object (&job->cancellable); - - g_slist_foreach (job->new_days, (GFunc) logview_utils_day_free, NULL); - g_slist_free (job->new_days); - - /* drop the reference we acquired before */ - g_object_unref (job->log); - - g_slice_free (NewLinesJob, job); - - return FALSE; -} - -static gboolean -do_read_new_lines (GIOSchedulerJob *io_job, - GCancellable *cancellable, - gpointer user_data) -{ - /* this runs in a separate thread */ - NewLinesJob *job = user_data; - LogviewLog *log = job->log; - char *line; - GError *err = NULL; - GPtrArray *lines; - - g_assert (LOGVIEW_IS_LOG (log)); - g_assert (log->priv->stream != NULL); - - if (!log->priv->lines) { - log->priv->lines = g_ptr_array_new (); - g_ptr_array_add (log->priv->lines, NULL); - } - - lines = log->priv->lines; - - /* remove the NULL-terminator */ - g_ptr_array_remove_index (lines, lines->len - 1); - - while ((line = g_data_input_stream_read_line (log->priv->stream, NULL, - job->cancellable, &err)) != NULL) - { - g_ptr_array_add (lines, (gpointer) line); - } - - /* NULL-terminate the array again */ - g_ptr_array_add (lines, NULL); - - if (err) { - job->err = err; - goto out; - } - - log->priv->has_new_lines = FALSE; - - /* we'll return only the new lines in the callback */ - line = g_ptr_array_index (lines, log->priv->lines_no); - job->lines = (const char **) lines->pdata + log->priv->lines_no; - - /* save the new number of days and lines */ - job->new_days = add_new_days_to_cache (log, job->lines, log->priv->lines_no); - log->priv->lines_no = (lines->len - 1); - -out: - g_io_scheduler_job_send_to_mainloop_async (io_job, - new_lines_job_done, - job, NULL); - return FALSE; -} - -static gboolean -log_load_done (gpointer user_data) -{ - LoadJob *job = user_data; - - if (job->err) { - /* the callback will have NULL as log, and the error set */ - g_object_unref (job->log); - job->callback (NULL, job->err, job->user_data); - g_error_free (job->err); - } else { - job->callback (job->log, NULL, job->user_data); - setup_file_monitor (job->log); - } - - g_slice_free (LoadJob, job); - - return FALSE; -} - -#ifdef HAVE_ZLIB - -/* GZip functions adapted for GIO from mate-vfs/gzip-method.c */ - -#define Z_BUFSIZE 16384 - -#define GZIP_HEADER_SIZE 10 -#define GZIP_MAGIC_1 0x1f -#define GZIP_MAGIC_2 0x8b -#define GZIP_FLAG_ASCII 0x01 /* bit 0 set: file probably ascii text */ -#define GZIP_FLAG_HEAD_CRC 0x02 /* bit 1 set: header CRC present */ -#define GZIP_FLAG_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ -#define GZIP_FLAG_ORIG_NAME 0x08 /* bit 3 set: original file name present */ -#define GZIP_FLAG_COMMENT 0x10 /* bit 4 set: file comment present */ -#define GZIP_FLAG_RESERVED 0xE0 /* bits 5..7: reserved */ - -static gboolean -skip_string (GInputStream *is) -{ - guchar c; - gssize bytes_read; - - do { - bytes_read = g_input_stream_read (is, &c, 1, NULL, NULL); - - if (bytes_read != 1) { - return FALSE; - } - } while (c != 0); - - return TRUE; -} - -static gboolean -read_gzip_header (GInputStream *is, - time_t *modification_time) -{ - gboolean res; - guchar buffer[GZIP_HEADER_SIZE]; - gssize bytes, to_skip; - guint mode; - guint flags; - - bytes = g_input_stream_read (is, buffer, GZIP_HEADER_SIZE, - NULL, NULL); - if (bytes == -1) { - return FALSE; - } - - if (bytes != GZIP_HEADER_SIZE) - return FALSE; - - if (buffer[0] != GZIP_MAGIC_1 || buffer[1] != GZIP_MAGIC_2) - return FALSE; - - mode = buffer[2]; - if (mode != 8) /* Mode: deflate */ - return FALSE; - - flags = buffer[3]; - - if (flags & GZIP_FLAG_RESERVED) - return FALSE; - - if (flags & GZIP_FLAG_EXTRA_FIELD) { - guchar tmp[2]; - - bytes = g_input_stream_read (is, tmp, 2, NULL, NULL); - - if (bytes != 2) { - return FALSE; - } - - to_skip = tmp[0] | (tmp[0] << 8); - bytes = g_input_stream_skip (is, to_skip, NULL, NULL); - if (bytes != to_skip) { - return FALSE; - } - } - - if (flags & GZIP_FLAG_ORIG_NAME) { - if (!skip_string (is)) { - return FALSE; - } - } - - if (flags & GZIP_FLAG_COMMENT) { - if (!skip_string (is)) { - return FALSE; - } - } - - if (flags & GZIP_FLAG_HEAD_CRC) { - bytes = g_input_stream_skip (is, 2, NULL, NULL); - if (bytes != 2) { - return FALSE; - } - } - - *modification_time = (buffer[4] | (buffer[5] << 8) - | (buffer[6] << 16) | (buffer[7] << 24)); - - return TRUE; -} - -static GZHandle * -gz_handle_new (GFile *file, - GInputStream *parent_stream) -{ - GZHandle *ret; - - ret = g_new (GZHandle, 1); - ret->parent_str = g_object_ref (parent_stream); - ret->file = g_object_ref (file); - ret->buffer = NULL; - - return ret; -} - -static gboolean -gz_handle_init (GZHandle *gz) -{ - gz->zstream.zalloc = NULL; - gz->zstream.zfree = NULL; - gz->zstream.opaque = NULL; - - g_free (gz->buffer); - gz->buffer = g_malloc (Z_BUFSIZE); - gz->zstream.next_in = gz->buffer; - gz->zstream.avail_in = 0; - - if (inflateInit2 (&gz->zstream, -MAX_WBITS) != Z_OK) { - return FALSE; - } - - gz->last_z_result = Z_OK; - gz->last_str_result = TRUE; - - return TRUE; -} - -static void -gz_handle_free (GZHandle *gz) -{ - g_object_unref (gz->parent_str); - g_object_unref (gz->file); - g_free (gz->buffer); - g_free (gz); -} - -static gboolean -fill_buffer (GZHandle *gz, - gsize num_bytes) -{ - gboolean res; - gsize count; - - z_stream * zstream = &gz->zstream; - - if (zstream->avail_in > 0) { - return TRUE; - } - - count = g_input_stream_read (gz->parent_str, - gz->buffer, - Z_BUFSIZE, - NULL, NULL); - if (count == -1) { - if (zstream->avail_out == num_bytes) { - return FALSE; - } - gz->last_str_result = FALSE; - } else { - zstream->next_in = gz->buffer; - zstream->avail_in = count; - } - - return TRUE; -} - -static gboolean -result_from_z_result (int z_result) -{ - switch (z_result) { - case Z_OK: - case Z_STREAM_END: - return TRUE; - case Z_DATA_ERROR: - return FALSE; - default: - return FALSE; - } -} - -static gboolean -gz_handle_read (GZHandle *gz, - guchar *buffer, - gsize num_bytes, - gsize * bytes_read) -{ - z_stream *zstream; - gboolean res; - int z_result; - - *bytes_read = 0; - zstream = &gz->zstream; - - if (gz->last_z_result != Z_OK) { - if (gz->last_z_result == Z_STREAM_END) { - *bytes_read = 0; - return TRUE; - } else { - return result_from_z_result (gz->last_z_result); - } - } else if (gz->last_str_result == FALSE) { - return FALSE; - } - - zstream->next_out = buffer; - zstream->avail_out = num_bytes; - - while (zstream->avail_out != 0) { - res = fill_buffer (gz, num_bytes); - - if (!res) { - return res; - } - - z_result = inflate (zstream, Z_NO_FLUSH); - if (z_result == Z_STREAM_END) { - gz->last_z_result = z_result; - break; - } else if (z_result != Z_OK) { - gz->last_z_result = z_result; - } - - if (gz->last_z_result != Z_OK && zstream->avail_out == num_bytes) { - return result_from_z_result (gz->last_z_result); - } - } - - *bytes_read = num_bytes - zstream->avail_out; - - return TRUE; -} - -static GError * -create_zlib_error (void) -{ - GError *err; - - err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_ZLIB, - _("Error while uncompressing the GZipped log. The file " - "might be corrupt.")); - return err; -} - -#endif /* HAVE_ZLIB */ - -static gboolean -log_load (GIOSchedulerJob *io_job, - GCancellable *cancellable, - gpointer user_data) -{ - /* this runs in a separate i/o thread */ - LoadJob *job = user_data; - LogviewLog *log = job->log; - GFile *f = log->priv->file; - GFileInfo *info; - GInputStream *is; - const char *peeked_buffer; - const char * parse_data[2]; - GSList *days; - const char *content_type; - GFileType type; - GError *err = NULL; - GTimeVal timeval; - gboolean is_archive, can_read; - - info = g_file_query_info (f, - G_FILE_ATTRIBUTE_ACCESS_CAN_READ "," - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," - G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," - G_FILE_ATTRIBUTE_STANDARD_TYPE "," - G_FILE_ATTRIBUTE_STANDARD_SIZE "," - G_FILE_ATTRIBUTE_TIME_MODIFIED ",", - 0, NULL, &err); - if (err) { - if (err->code == G_IO_ERROR_PERMISSION_DENIED) { - /* TODO: PolicyKit integration */ - } - goto out; - } - - can_read = g_file_info_get_attribute_boolean (info, - G_FILE_ATTRIBUTE_ACCESS_CAN_READ); - if (!can_read) { - /* TODO: PolicyKit integration */ - err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_PERMISSION_DENIED, - _("You don't have enough permissions to read the file.")); - g_object_unref (info); - - goto out; - } - - type = g_file_info_get_file_type (info); - content_type = g_file_info_get_content_type (info); - - is_archive = g_content_type_equals (content_type, "application/x-gzip"); - - if (type != (G_FILE_TYPE_REGULAR || G_FILE_TYPE_SYMBOLIC_LINK) || - (!g_content_type_is_a (content_type, "text/plain") && !is_archive)) - { - err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_NOT_A_LOG, - _("The file is not a regular file or is not a text file.")); - g_object_unref (info); - - goto out; - } - - log->priv->file_size = g_file_info_get_size (info); - g_file_info_get_modification_time (info, &timeval); - log->priv->file_time = timeval.tv_sec; - log->priv->display_name = g_strdup (g_file_info_get_display_name (info)); - - g_object_unref (info); - - /* initialize the stream */ - is = G_INPUT_STREAM (g_file_read (f, NULL, &err)); - - if (err) { - if (err->code == G_IO_ERROR_PERMISSION_DENIED) { - /* TODO: PolicyKit integration */ - } - - goto out; - } - - if (is_archive) { -#ifdef HAVE_ZLIB - GZHandle *gz; - gboolean res; - guchar * buffer; - gsize bytes_read; - GInputStream *real_is; - time_t mtime; /* seconds */ - - /* this also skips the header from |is| */ - res = read_gzip_header (is, &mtime); - - if (!res) { - g_object_unref (is); - - err = create_zlib_error (); - goto out; - } - - log->priv->file_time = mtime; - - gz = gz_handle_new (f, is); - res = gz_handle_init (gz); - - if (!res) { - g_object_unref (is); - gz_handle_free (gz); - - err = create_zlib_error (); - goto out; - } - - real_is = g_memory_input_stream_new (); - - do { - buffer = g_malloc (1024); - res = gz_handle_read (gz, buffer, 1024, &bytes_read); - g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (real_is), - buffer, bytes_read, g_free); - } while (res == TRUE && bytes_read > 0); - - if (!res) { - gz_handle_free (gz); - g_object_unref (real_is); - g_object_unref (is); - - err = create_zlib_error (); - goto out; - } - - g_object_unref (is); - is = real_is; - - gz_handle_free (gz); -#else /* HAVE_ZLIB */ - g_object_unref (is); - - err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_NOT_SUPPORTED, - _("This version of System Log does not support GZipped logs.")); - goto out; -#endif /* HAVE_ZLIB */ - } - - log->priv->stream = g_data_input_stream_new (is); - - /* sniff into the stream for a timestamped line */ - g_buffered_input_stream_fill (G_BUFFERED_INPUT_STREAM (log->priv->stream), - (gssize) g_buffered_input_stream_get_buffer_size (G_BUFFERED_INPUT_STREAM (log->priv->stream)), - NULL, &err); - if (err == NULL) { - peeked_buffer = g_buffered_input_stream_peek_buffer - (G_BUFFERED_INPUT_STREAM (log->priv->stream), NULL); - parse_data[0] = peeked_buffer; - parse_data[1] = NULL; - - if ((days = log_read_dates (parse_data, time (NULL))) != NULL) { - log->priv->has_days = TRUE; - g_slist_foreach (days, (GFunc) logview_utils_day_free, NULL); - g_slist_free (days); - } else { - log->priv->has_days = FALSE; - } - } else { - log->priv->has_days = FALSE; - g_clear_error (&err); - } - - g_object_unref (is); - -out: - if (err) { - job->err = err; - } - - g_io_scheduler_job_send_to_mainloop_async (io_job, - log_load_done, - job, NULL); - return FALSE; -} - -static void -log_setup_load (LogviewLog *log, LogviewCreateCallback callback, - gpointer user_data) -{ - LoadJob *job; - - job = g_slice_new0 (LoadJob); - job->callback = callback; - job->user_data = user_data; - job->log = log; - job->err = NULL; - - /* push the loading job into another thread */ - g_io_scheduler_push_job (log_load, - job, - NULL, 0, NULL); -} - -/* public methods */ - -void -logview_log_read_new_lines (LogviewLog *log, - GCancellable *cancellable, - LogviewNewLinesCallback callback, - gpointer user_data) -{ - NewLinesJob *job; - - /* initialize the job struct with sensible values */ - job = g_slice_new0 (NewLinesJob); - job->callback = callback; - job->user_data = user_data; - job->cancellable = (cancellable != NULL) ? g_object_ref (cancellable) : NULL; - job->log = g_object_ref (log); - job->err = NULL; - job->lines = NULL; - job->new_days = NULL; - - /* push the fetching job into another thread */ - g_io_scheduler_push_job (do_read_new_lines, - job, - NULL, 0, - job->cancellable); -} - -void -logview_log_create (const char *filename, LogviewCreateCallback callback, - gpointer user_data) -{ - LogviewLog *log = g_object_new (LOGVIEW_TYPE_LOG, NULL); - - log->priv->file = g_file_new_for_path (filename); - - log_setup_load (log, callback, user_data); -} - -void -logview_log_create_from_gfile (GFile *file, LogviewCreateCallback callback, - gpointer user_data) -{ - LogviewLog *log = g_object_new (LOGVIEW_TYPE_LOG, NULL); - - log->priv->file = g_object_ref (file); - - log_setup_load (log, callback, user_data); -} - -const char * -logview_log_get_display_name (LogviewLog *log) -{ - g_assert (LOGVIEW_IS_LOG (log)); - - return log->priv->display_name; -} - -time_t -logview_log_get_timestamp (LogviewLog *log) -{ - g_assert (LOGVIEW_IS_LOG (log)); - - return log->priv->file_time; -} - -goffset -logview_log_get_file_size (LogviewLog *log) -{ - g_assert (LOGVIEW_IS_LOG (log)); - - return log->priv->file_size; -} - -guint -logview_log_get_cached_lines_number (LogviewLog *log) -{ - g_assert (LOGVIEW_IS_LOG (log)); - - return log->priv->lines_no; -} - -const char ** -logview_log_get_cached_lines (LogviewLog *log) -{ - const char ** lines = NULL; - - g_assert (LOGVIEW_IS_LOG (log)); - - if (log->priv->lines) { - lines = (const char **) log->priv->lines->pdata; - } - - return lines; -} - -GSList * -logview_log_get_days_for_cached_lines (LogviewLog *log) -{ - g_assert (LOGVIEW_IS_LOG (log)); - - return log->priv->days; -} - -gboolean -logview_log_has_new_lines (LogviewLog *log) -{ - g_assert (LOGVIEW_IS_LOG (log)); - - return log->priv->has_new_lines; -} - -char * -logview_log_get_uri (LogviewLog *log) -{ - g_assert (LOGVIEW_IS_LOG (log)); - - return g_file_get_uri (log->priv->file); -} - -GFile * -logview_log_get_gfile (LogviewLog *log) -{ - g_assert (LOGVIEW_IS_LOG (log)); - - return g_object_ref (log->priv->file); -} - -gboolean -logview_log_get_has_days (LogviewLog *log) -{ - g_assert (LOGVIEW_IS_LOG (log)); - - return log->priv->has_days; -} - diff --git a/logview/logview-log.h b/logview/logview-log.h deleted file mode 100644 index 4f81af14..00000000 --- a/logview/logview-log.h +++ /dev/null @@ -1,110 +0,0 @@ -/* logview-log.h - object representation of a logfile - * - * Copyright (C) 1998 Cesar Miquel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* logview-log.h */ - -#ifndef __LOGVIEW_LOG_H__ -#define __LOGVIEW_LOG_H__ - -#include -#include - -G_BEGIN_DECLS - -#define LOGVIEW_TYPE_LOG logview_log_get_type() -#define LOGVIEW_LOG(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_LOG, LogviewLog)) -#define LOGVIEW_LOG_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_LOG, LogviewLogClass)) -#define LOGVIEW_IS_LOG(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_LOG)) -#define LOGVIEW_IS_LOG_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_LOG)) -#define LOGVIEW_LOG_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_LOG, LogviewLogClass)) - -typedef struct _LogviewLog LogviewLog; -typedef struct _LogviewLogClass LogviewLogClass; -typedef struct _LogviewLogPrivate LogviewLogPrivate; - -/* callback signatures for async I/O operations */ - -typedef void (* LogviewCreateCallback) (LogviewLog *log, - GError *error, - gpointer user_data); -typedef void (* LogviewNewLinesCallback) (LogviewLog *log, - const char **lines, - GSList *new_days, - GError *error, - gpointer user_data); - -#define LOGVIEW_ERROR_QUARK g_quark_from_static_string ("logview-error") - -typedef enum { - LOGVIEW_ERROR_FAILED, - LOGVIEW_ERROR_PERMISSION_DENIED, - LOGVIEW_ERROR_ZLIB, - LOGVIEW_ERROR_NOT_SUPPORTED, - LOGVIEW_ERROR_NOT_A_LOG -} LogviewErrorEnum; - -struct _LogviewLog { - GObject parent; - LogviewLogPrivate *priv; -}; - -struct _LogviewLogClass { - GObjectClass parent_class; - - /* signals */ - void (* log_changed) (LogviewLog *log); -}; - -GType logview_log_get_type (void); - -/* public methods */ - -/* these two do I/O, so they are wrapped async */ -void logview_log_create (const char *filename, - LogviewCreateCallback callback, - gpointer user_data); -void logview_log_create_from_gfile (GFile *file, - LogviewCreateCallback callback, - gpointer user_data); -void logview_log_read_new_lines (LogviewLog *log, - GCancellable *cancellable, - LogviewNewLinesCallback callback, - gpointer user_data); - -const char * logview_log_get_display_name (LogviewLog *log); -time_t logview_log_get_timestamp (LogviewLog *log); -goffset logview_log_get_file_size (LogviewLog *log); -const char ** logview_log_get_cached_lines (LogviewLog *log); -guint logview_log_get_cached_lines_number (LogviewLog *log); -GSList * logview_log_get_days_for_cached_lines (LogviewLog *log); -gboolean logview_log_has_new_lines (LogviewLog *log); -char * logview_log_get_uri (LogviewLog *log); -GFile * logview_log_get_gfile (LogviewLog *log); -gboolean logview_log_get_has_days (LogviewLog *log); - -G_END_DECLS - -#endif /* __LOGVIEW_LOG_H__ */ diff --git a/logview/logview-loglist.c b/logview/logview-loglist.c deleted file mode 100644 index 847626d9..00000000 --- a/logview/logview-loglist.c +++ /dev/null @@ -1,500 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-loglist.c - displays a list of the opened logs - * - * Copyright (C) 2005 Vincent Noel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "logview-manager.h" -#include "logview-log.h" -#include "logview-utils.h" - -#include "logview-loglist.h" - -struct _LogviewLoglistPrivate { - GtkTreeStore *model; - LogviewManager *manager; - GtkTreePath *selection; - gboolean has_day_selection; -}; - -G_DEFINE_TYPE (LogviewLoglist, logview_loglist, GTK_TYPE_TREE_VIEW); - -#define GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_LOGLIST, LogviewLoglistPrivate)) - -enum { - LOG_OBJECT = 0, - LOG_NAME, - LOG_WEIGHT, - LOG_WEIGHT_SET, - LOG_DAY -}; - -enum { - DAY_SELECTED, - DAY_CLEARED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static void -save_day_selection (LogviewLoglist *loglist, GtkTreeIter *iter) -{ - if (loglist->priv->selection) { - gtk_tree_path_free (loglist->priv->selection); - } - - loglist->priv->selection = gtk_tree_model_get_path - (GTK_TREE_MODEL (loglist->priv->model), iter); -} - -static void -update_days_and_lines_for_log (LogviewLoglist *loglist, - GtkTreeIter *log, GSList *days) -{ - gboolean res; - GtkTreeIter iter, dummy; - GSList *l; - int i; - char date[200]; - Day *day; - - /* if we have some days, we can't remove all the items immediately, otherwise, - * if the row is expanded, it will be collapsed because there are no items, - * so we create a dummy entry, remove all the others and then remove the - * dummy one. - */ - res = gtk_tree_model_iter_children (GTK_TREE_MODEL (loglist->priv->model), - &iter, log); - if (res) { - gtk_tree_store_insert_before (loglist->priv->model, &dummy, log, &iter); - gtk_tree_store_set (loglist->priv->model, &dummy, - LOG_NAME, "", -1); - do { - gtk_tree_store_remove (loglist->priv->model, &iter); - } while (gtk_tree_store_iter_is_valid (loglist->priv->model, &iter)); - } - - for (i = 1, l = days; l; l = l->next) { - /* now insert all the days */ - day = l->data; - - g_date_strftime (date, 200, "%A, %e %b", day->date); - - gtk_tree_store_insert (GTK_TREE_STORE (loglist->priv->model), - &iter, log, i); - gtk_tree_store_set (GTK_TREE_STORE (loglist->priv->model), - &iter, LOG_NAME, date, LOG_DAY, day, -1); - i++; - } - - if (res) { - gtk_tree_store_remove (loglist->priv->model, &dummy); - } -} - -static GtkTreeIter * -logview_loglist_find_log (LogviewLoglist *list, LogviewLog *log) -{ - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreeIter *retval = NULL; - LogviewLog *current; - - model = GTK_TREE_MODEL (list->priv->model); - - if (!gtk_tree_model_get_iter_first (model, &iter)) { - return NULL; - } - - do { - gtk_tree_model_get (model, &iter, LOG_OBJECT, ¤t, -1); - if (current == log) { - retval = gtk_tree_iter_copy (&iter); - } - if (current) - g_object_unref (current); - } while (gtk_tree_model_iter_next (model, &iter) != FALSE && retval == NULL); - - return retval; -} - -static void -log_changed_cb (LogviewLog *log, - gpointer user_data) -{ - LogviewLoglist *list = user_data; - LogviewLog *active; - GtkTreeIter *iter; - - active = logview_manager_get_active_log (list->priv->manager); - - if (log == active) { - g_object_unref (active); - return; - } - - iter = logview_loglist_find_log (list, log); - - if (!iter) { - return; - } - - /* make the log bold in the list */ - gtk_tree_store_set (list->priv->model, iter, - LOG_WEIGHT, PANGO_WEIGHT_BOLD, - LOG_WEIGHT_SET, TRUE, -1); - - gtk_tree_iter_free (iter); -} - - -static void -tree_selection_changed_cb (GtkTreeSelection *selection, - gpointer user_data) -{ - LogviewLoglist *list = user_data; - GtkTreeModel *model; - GtkTreeIter iter, parent; - LogviewLog *log; - gboolean is_bold, is_active; - Day *day; - - if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { - return; - } - - gtk_tree_model_get (model, &iter, LOG_OBJECT, &log, - LOG_WEIGHT_SET, &is_bold, - LOG_DAY, &day, -1); - if (log) { - is_active = logview_manager_log_is_active (list->priv->manager, log); - - if (is_active && list->priv->has_day_selection) { - list->priv->has_day_selection = FALSE; - g_signal_emit (list, signals[DAY_CLEARED], 0, NULL); - } else if (!is_active) { - logview_manager_set_active_log (list->priv->manager, log); - } - } else if (day) { - list->priv->has_day_selection = TRUE; - gtk_tree_model_iter_parent (model, &parent, &iter); - gtk_tree_model_get (model, &parent, LOG_OBJECT, &log, -1); - - if (!logview_manager_log_is_active (list->priv->manager, log)) { - save_day_selection (list, &iter); - logview_manager_set_active_log (list->priv->manager, log); - } else { - g_signal_emit (list, signals[DAY_SELECTED], 0, day, NULL); - } - } - - if (is_bold) { - gtk_tree_store_set (GTK_TREE_STORE (model), &iter, - LOG_WEIGHT_SET, FALSE, -1); - } - - if (log) { - g_object_unref (log); - } -} - -static void -manager_active_changed_cb (LogviewManager *manager, - LogviewLog *log, - LogviewLog *old_log, - gpointer user_data) -{ - LogviewLoglist *list = user_data; - GtkTreeIter * iter, sel_iter; - GtkTreeSelection * selection; - - if (list->priv->selection && - gtk_tree_model_get_iter (GTK_TREE_MODEL (list->priv->model), - &sel_iter, list->priv->selection)) - { - Day *day; - - iter = gtk_tree_iter_copy (&sel_iter); - - gtk_tree_model_get (GTK_TREE_MODEL (list->priv->model), iter, - LOG_DAY, &day, -1); - - if (day) { - g_signal_emit (list, signals[DAY_SELECTED], 0, day, NULL); - } - - gtk_tree_path_free (list->priv->selection); - list->priv->selection = NULL; - } else { - iter = logview_loglist_find_log (list, log); - } - - if (!iter) { - return; - } - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); - g_signal_handlers_block_by_func (selection, tree_selection_changed_cb, list); - - gtk_tree_selection_select_iter (selection, iter); - - g_signal_handlers_unblock_by_func (selection, tree_selection_changed_cb, list); - gtk_tree_iter_free (iter); -} - -static void -manager_log_closed_cb (LogviewManager *manager, - LogviewLog *log, - gpointer user_data) -{ - LogviewLoglist *list = user_data; - GtkTreeIter *iter; - gboolean res; - - iter = logview_loglist_find_log (list, log); - - if (!iter) { - return; - } - - g_signal_handlers_disconnect_by_func (log, log_changed_cb, list); - - res = gtk_tree_store_remove (list->priv->model, iter); - if (res) { - GtkTreeSelection *selection; - - /* iter now points to the next valid row */ - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); - gtk_tree_selection_select_iter (selection, iter); - } else { - /* FIXME: what shall we do here? */ - } - - gtk_tree_iter_free (iter); -} - -static void -manager_log_added_cb (LogviewManager *manager, - LogviewLog *log, - gpointer user_data) -{ - LogviewLoglist *list = user_data; - GtkTreeIter iter, child; - - gtk_tree_store_append (list->priv->model, &iter, NULL); - gtk_tree_store_set (list->priv->model, &iter, - LOG_OBJECT, g_object_ref (log), - LOG_NAME, logview_log_get_display_name (log), -1); - if (logview_log_get_has_days (log)) { - gtk_tree_store_insert (list->priv->model, - &child, &iter, 0); - gtk_tree_store_set (list->priv->model, &child, - LOG_NAME, _("Loading..."), -1); - } - - g_signal_connect (log, "log-changed", - G_CALLBACK (log_changed_cb), list); -} - -static void -row_expanded_cb (GtkTreeView *view, - GtkTreeIter *iter, - GtkTreePath *path, - gpointer user_data) -{ - LogviewLoglist *list = user_data; - LogviewLog *log; - - gtk_tree_model_get (GTK_TREE_MODEL (list->priv->model), iter, - LOG_OBJECT, &log, -1); - if (!logview_manager_log_is_active (list->priv->manager, log)) { - logview_manager_set_active_log (list->priv->manager, log); - } - - g_object_unref (log); -} - -static int -loglist_sort_func (GtkTreeModel *model, - GtkTreeIter *a, - GtkTreeIter *b, - gpointer user_data) -{ - char *name_a, *name_b; - Day *day_a, *day_b; - int retval = 0; - - switch (gtk_tree_store_iter_depth (GTK_TREE_STORE (model), a)) { - case 0: - gtk_tree_model_get (model, a, LOG_NAME, &name_a, -1); - gtk_tree_model_get (model, b, LOG_NAME, &name_b, -1); - retval = g_utf8_collate (name_a, name_b); - g_free (name_a); - g_free (name_b); - - break; - case 1: - gtk_tree_model_get (model, a, LOG_DAY, &day_a, -1); - gtk_tree_model_get (model, b, LOG_DAY, &day_b, -1); - if (day_a && day_b) { - retval = days_compare (day_a, day_b); - } else { - retval = 0; - } - - break; - default: - g_assert_not_reached (); - - break; - } - - return retval; -} - -static void -do_finalize (GObject *obj) -{ - LogviewLoglist *list = LOGVIEW_LOGLIST (obj); - - g_object_unref (list->priv->model); - list->priv->model = NULL; - - if (list->priv->selection) { - gtk_tree_path_free (list->priv->selection); - list->priv->selection = NULL; - } - - G_OBJECT_CLASS (logview_loglist_parent_class)->finalize (obj); -} - -static void -logview_loglist_init (LogviewLoglist *list) -{ - GtkTreeStore *model; - GtkTreeViewColumn *column; - GtkTreeSelection *selection; - GtkCellRenderer *cell; - - list->priv = GET_PRIVATE (list); - list->priv->has_day_selection = FALSE; - list->priv->selection = NULL; - - model = gtk_tree_store_new (5, LOGVIEW_TYPE_LOG, G_TYPE_STRING, G_TYPE_INT, - G_TYPE_BOOLEAN, G_TYPE_POINTER); - gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (model)); - list->priv->model = model; - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); - gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); - g_signal_connect (selection, "changed", - G_CALLBACK (tree_selection_changed_cb), list); - - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new (); - gtk_tree_view_column_pack_start (column, cell, TRUE); - gtk_tree_view_column_set_attributes (column, cell, - "text", LOG_NAME, - "weight-set", LOG_WEIGHT_SET, - "weight", LOG_WEIGHT, - NULL); - - gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list->priv->model), LOG_NAME, GTK_SORT_ASCENDING); - gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list->priv->model), - LOG_NAME, - (GtkTreeIterCompareFunc) loglist_sort_func, - list, NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (list), column); - gtk_tree_view_set_search_column (GTK_TREE_VIEW (list), -1); - - list->priv->manager = logview_manager_get (); - - g_signal_connect (list->priv->manager, "log-added", - G_CALLBACK (manager_log_added_cb), list); - g_signal_connect (list->priv->manager, "log-closed", - G_CALLBACK (manager_log_closed_cb), list); - g_signal_connect_after (list->priv->manager, "active-changed", - G_CALLBACK (manager_active_changed_cb), list); - g_signal_connect (list, "row-expanded", - G_CALLBACK (row_expanded_cb), list); -} - -static void -logview_loglist_class_init (LogviewLoglistClass *klass) -{ - GObjectClass *oclass = G_OBJECT_CLASS (klass); - oclass->finalize = do_finalize; - - signals[DAY_SELECTED] = g_signal_new ("day-selected", - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewLoglistClass, day_selected), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); - - signals[DAY_CLEARED] = g_signal_new ("day-cleared", - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewLoglistClass, day_cleared), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_type_class_add_private (klass, sizeof (LogviewLoglistPrivate)); -} - -/* public methods */ - -GtkWidget * -logview_loglist_new (void) -{ - GtkWidget *widget; - widget = g_object_new (LOGVIEW_TYPE_LOGLIST, NULL); - return widget; -} - -void -logview_loglist_update_lines (LogviewLoglist *loglist, LogviewLog *log) -{ - GSList *days; - GtkTreeIter *parent; - - g_assert (LOGVIEW_IS_LOGLIST (loglist)); - g_assert (LOGVIEW_IS_LOG (log)); - - parent = logview_loglist_find_log (loglist, log); - - if (parent) { - days = logview_log_get_days_for_cached_lines (log); - update_days_and_lines_for_log (loglist, parent, days); - gtk_tree_iter_free (parent); - } -} - diff --git a/logview/logview-loglist.h b/logview/logview-loglist.h deleted file mode 100644 index ebfbf04f..00000000 --- a/logview/logview-loglist.h +++ /dev/null @@ -1,68 +0,0 @@ -/* logview-loglist.h - displays a list of the opened logs - * - * Copyright (C) 2005 Vincent Noel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __LOGVIEW_LOGLIST_H__ -#define __LOGVIEW_LOGLIST_H__ - -#define LOGVIEW_TYPE_LOGLIST logview_loglist_get_type() -#define LOGVIEW_LOGLIST(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_LOGLIST, LogviewLoglist)) -#define LOGVIEW_LOGLIST_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_LOGLIST, LogviewLogListClass)) -#define LOGVIEW_IS_LOGLIST(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_LOGLIST)) -#define LOGVIEW_IS_LOGLIST_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_LOGLIST)) -#define LOGVIEW_LOGLIST_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_LOGLIST, LogviewLoglistClass)) - -#include -#include - -#include "logview-log.h" -#include "logview-utils.h" - -typedef struct _LogviewLoglist LogviewLoglist; -typedef struct _LogviewLoglistClass LogviewLoglistClass; -typedef struct _LogviewLoglistPrivate LogviewLoglistPrivate; - -struct _LogviewLoglist { - GtkTreeView parent_instance; - LogviewLoglistPrivate *priv; -}; - -struct _LogviewLoglistClass { - GtkTreeViewClass parent_class; - - void (* day_selected) (LogviewLoglist *loglist, - Day *day); - void (* day_cleared) (LogviewLoglist *loglist); -}; - -GType logview_loglist_get_type (void); - -/* public methods */ -GtkWidget * logview_loglist_new (void); -void logview_loglist_update_lines (LogviewLoglist *loglist, - LogviewLog *log); -GDate * logview_loglist_get_date_selection (LogviewLoglist *loglist); -void logview_loglist_clear_date (LogviewLoglist *loglist); - -#endif /* __LOGVIEW_LOGLIST_H__ */ diff --git a/logview/logview-main.c b/logview/logview-main.c deleted file mode 100644 index 74dcb44b..00000000 --- a/logview/logview-main.c +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-main.c - logview main - * - * Copyright (C) 2005 Vincent Noel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "config.h" - -#include - -#include -#include - -#include - -#include "logview-app.h" - -/* log files specified on the command line */ -static char **log_files = NULL; - -static void -app_quit_cb (LogviewApp *app, - gpointer user_data) -{ - gtk_main_quit (); -} - -static void -logview_show_version_and_quit (void) -{ - g_print ("%s - Version %s\n" - "Copyright (C) 2004-2008 Vincent Noel, Cosimo Cecchi and others.\n", - g_get_application_name (), - VERSION); - - exit (0); -} - -static GOptionContext * -create_option_context (void) -{ - GOptionContext *context; - - const GOptionEntry entries[] = { - { "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, - logview_show_version_and_quit, N_("Show the application's version"), NULL }, - { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &log_files, - NULL, N_("[LOGFILE...]") }, - { NULL }, - }; - - context = g_option_context_new (_(" - Browse and monitor logs")); - g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); - g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); - g_option_context_set_ignore_unknown_options (context, TRUE); - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - - return context; -} - -int -main (int argc, char *argv[]) -{ - GError *error = NULL; - GOptionContext *context; - LogviewApp *app; - - bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); - - context = create_option_context (); - - g_option_context_parse (context, &argc, &argv, &error); - - if (error) { - g_critical ("Unable to parse arguments: %s", error->message); - g_error_free (error); - g_option_context_free (context); - - exit (1); - } - - g_option_context_free (context); - g_set_application_name (_("Log Viewer")); - - app = logview_app_get (); - - if (!app) { - g_critical ("Unable to create the user interface."); - - exit (1); - } else { - g_signal_connect (app, "app-quit", - G_CALLBACK (app_quit_cb), NULL); - } - - logview_app_initialize (app, log_files); - - gtk_main (); - - g_object_unref (app); - - return EXIT_SUCCESS; -} diff --git a/logview/logview-manager.c b/logview/logview-manager.c deleted file mode 100644 index 54b5320b..00000000 --- a/logview/logview-manager.c +++ /dev/null @@ -1,432 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-manager.c - manager for the opened log objects - * - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* logview-manager.c */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "logview-manager.h" - -#include - -#include "logview-prefs.h" -#include "logview-marshal.h" -#include "logview-app.h" - -enum { - LOG_ADDED, - LOG_CLOSED, - ACTIVE_CHANGED, - LAST_SIGNAL -}; - -typedef struct { - LogviewManager *manager; - gboolean set_active; - gboolean is_multiple; - GFile *file; -} CreateCBData; - -typedef struct { - int total; - int current; - GPtrArray *errors; -} MultipleCreation; - -struct _LogviewManagerPrivate { - GHashTable *logs; - LogviewLog *active_log; -}; - -static LogviewManager *singleton = NULL; -static MultipleCreation *op = NULL; -static guint signals[LAST_SIGNAL] = { 0 }; - -G_DEFINE_TYPE (LogviewManager, logview_manager, G_TYPE_OBJECT); - -#define GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_MANAGER, LogviewManagerPrivate)) - -static void -logview_manager_finalize (GObject *object) -{ - LogviewManager *manager; - - manager = LOGVIEW_MANAGER (object); - - if (manager->priv->active_log) { - g_object_unref (manager->priv->active_log); - } - - g_hash_table_destroy (manager->priv->logs); - - G_OBJECT_CLASS (logview_manager_parent_class)->finalize (object); -} - -static void -logview_manager_class_init (LogviewManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = logview_manager_finalize; - - signals[LOG_ADDED] = g_signal_new ("log-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewManagerClass, log_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - LOGVIEW_TYPE_LOG); - - signals[LOG_CLOSED] = g_signal_new ("log-closed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewManagerClass, log_closed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - LOGVIEW_TYPE_LOG); - - signals[ACTIVE_CHANGED] = g_signal_new ("active-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewManagerClass, active_changed), - NULL, NULL, - logview_marshal_VOID__OBJECT_OBJECT, - G_TYPE_NONE, 2, - LOGVIEW_TYPE_LOG, - LOGVIEW_TYPE_LOG); - - g_type_class_add_private (klass, sizeof (LogviewManagerPrivate)); -} - -static void -logview_manager_init (LogviewManager *self) -{ - LogviewManagerPrivate *priv = self->priv = GET_PRIVATE (self); - - priv->active_log = NULL; - priv->logs = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); -} - -static MultipleCreation * -multiple_creation_op_new (int total) -{ - MultipleCreation *retval; - - retval = g_slice_new0 (MultipleCreation); - retval->total = total; - retval->current = 0; - retval->errors = g_ptr_array_new (); - - return retval; -} - -static void -multiple_creation_op_free (MultipleCreation *mc) -{ - g_ptr_array_foreach (mc->errors, (GFunc) g_strfreev, NULL); - g_ptr_array_free (mc->errors, TRUE); - - g_slice_free (MultipleCreation, mc); -} - -static void -create_log_cb (LogviewLog *log, - GError *error, - gpointer user_data) -{ - CreateCBData *data = user_data; - - if (log) { - char *log_uri; - LogviewPrefs *prefs; - GFile *file; - - log_uri = logview_log_get_uri (log); - - /* creation went well, store the log and notify */ - g_hash_table_insert (data->manager->priv->logs, - log_uri, log); - - prefs = logview_prefs_get (); - file = logview_log_get_gfile (log); - logview_prefs_store_log (prefs, file); - - g_object_unref (file); - - g_signal_emit (data->manager, signals[LOG_ADDED], 0, log, NULL); - - if (data->set_active) { - logview_manager_set_active_log (data->manager, log); - } - } else { - char *path; - - /* notify the error */ - path = g_file_get_path (data->file); - - if (!data->is_multiple) { - logview_app_add_error (logview_app_get (), - path, error->message); - } else { - char **error_arr = g_new0 (char *, 3); - - error_arr[0] = g_strdup (path); - error_arr[1] = g_strdup (error->message); - error_arr[2] = NULL; - - g_ptr_array_add (op->errors, error_arr); - } - - g_free (path); - } - - if (data->is_multiple) { - op->current++; - - if (op->total == op->current) { - logview_app_add_errors (logview_app_get (), op->errors); - multiple_creation_op_free (op); - op = NULL; - } - } - - g_object_unref (data->file); - g_slice_free (CreateCBData, data); -} - -static void -add_log_from_gfile_internal (LogviewManager *manager, - GFile *file, - gboolean set_active, - gboolean is_multiple) -{ - char *file_uri; - LogviewLog *log; - CreateCBData *data; - - file_uri = g_file_get_uri (file); - - if (set_active == FALSE) { - /* if it's the first log being added, set it as active anyway */ - set_active = (manager->priv->logs == NULL); - } - - if ((log = g_hash_table_lookup (manager->priv->logs, file_uri)) != NULL) { - /* log already exists, don't load it */ - if (set_active) { - logview_manager_set_active_log (manager, log); - } - } else { - data = g_slice_new0 (CreateCBData); - data->manager = manager; - data->set_active = set_active; - data->is_multiple = is_multiple; - data->file = g_object_ref (file); - - logview_log_create_from_gfile (file, create_log_cb, data); - } - - g_free (file_uri); -} - -static void -logview_manager_add_log_from_name (LogviewManager *manager, - const char *filename, gboolean set_active, - gboolean is_multiple) -{ - GFile *file; - - file = g_file_new_for_path (filename); - - add_log_from_gfile_internal (manager, file, set_active, is_multiple); - - g_object_unref (file); -} - -/* public methods */ - -LogviewManager* -logview_manager_get (void) -{ - if (!singleton) { - singleton = g_object_new (LOGVIEW_TYPE_MANAGER, NULL); - } - - return singleton; -} - -void -logview_manager_set_active_log (LogviewManager *manager, - LogviewLog *log) -{ - LogviewLog *old_log = NULL; - GFile *file; - char *path; - - g_assert (LOGVIEW_IS_MANAGER (manager)); - - if (manager->priv->active_log) { - old_log = manager->priv->active_log; - } - - manager->priv->active_log = g_object_ref (log); - - file = logview_log_get_gfile (log); - path = g_file_get_path (file); - logview_prefs_store_active_logfile (logview_prefs_get (), path); - g_free (path); - g_object_unref (file); - - g_signal_emit (manager, signals[ACTIVE_CHANGED], 0, log, old_log, NULL); - - if (old_log) { - g_object_unref (old_log); - } -} - -LogviewLog * -logview_manager_get_active_log (LogviewManager *manager) -{ - g_assert (LOGVIEW_IS_MANAGER (manager)); - - return (manager->priv->active_log != NULL) ? - g_object_ref (manager->priv->active_log) : - NULL; -} - -void -logview_manager_add_log_from_gfile (LogviewManager *manager, - GFile *file, - gboolean set_active) -{ - g_assert (LOGVIEW_IS_MANAGER (manager)); - - add_log_from_gfile_internal (manager, file, set_active, FALSE); -} - -void -logview_manager_add_logs_from_name_list (LogviewManager *manager, - GSList *names, - const char *active) -{ - GSList *l; - - g_assert (LOGVIEW_IS_MANAGER (manager)); - g_assert (op == NULL); - - op = multiple_creation_op_new (g_slist_length (names)); - - for (l = names; l; l = l->next) { - logview_manager_add_log_from_name (manager, l->data, - (g_ascii_strcasecmp (active, l->data) == 0), - TRUE); - } -} - -void -logview_manager_add_logs_from_names (LogviewManager *manager, - char ** names, - const gchar *active) -{ - int i; - gboolean set_active; - - g_assert (LOGVIEW_IS_MANAGER (manager)); - g_assert (op == NULL); - - op = multiple_creation_op_new (g_strv_length (names)); - - for (i = 0; names[i]; i++) { - set_active = (active != NULL) && (!g_ascii_strcasecmp (active, names[i])); - logview_manager_add_log_from_name (manager, names[i], set_active, - TRUE); - } -} - -int -logview_manager_get_log_count (LogviewManager *manager) -{ - g_assert (LOGVIEW_IS_MANAGER (manager)); - - return g_hash_table_size (manager->priv->logs); -} - -LogviewLog * -logview_manager_get_if_loaded (LogviewManager *manager, char *uri) -{ - LogviewLog *log; - - g_assert (LOGVIEW_IS_MANAGER (manager)); - - log = g_hash_table_lookup (manager->priv->logs, uri); - - if (log != NULL) { - return g_object_ref (log); - } - - return NULL; -} - -void -logview_manager_close_active_log (LogviewManager *manager) -{ - LogviewLog *active_log; - char *log_uri; - GFile *file; - - g_assert (LOGVIEW_IS_MANAGER (manager)); - - active_log = manager->priv->active_log; - if (active_log == NULL) { - return; - } - - log_uri = logview_log_get_uri (active_log); - file = logview_log_get_gfile (active_log); - - g_signal_emit (manager, signals[LOG_CLOSED], 0, active_log, NULL); - - logview_prefs_remove_stored_log (logview_prefs_get (), file); - - g_object_unref (file); - - /* drop the hash table ref */ - g_hash_table_remove (manager->priv->logs, log_uri); - - g_free (log_uri); - - /* someone else will take care of setting the next active log to us */ -} - -gboolean -logview_manager_log_is_active (LogviewManager *manager, - LogviewLog *log) -{ - g_assert (LOGVIEW_IS_MANAGER (manager)); - - return (manager->priv->active_log == log); -} diff --git a/logview/logview-manager.h b/logview/logview-manager.h deleted file mode 100644 index b9444323..00000000 --- a/logview/logview-manager.h +++ /dev/null @@ -1,90 +0,0 @@ -/* logview-manager.h - manager for the opened log objects - * - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* logview-manager.h */ - -#ifndef __LOGVIEW_MANAGER_H__ -#define __LOGVIEW_MANAGER_H__ - -#include - -#include "logview-log.h" - -G_BEGIN_DECLS - -#define LOGVIEW_TYPE_MANAGER logview_manager_get_type() -#define LOGVIEW_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_MANAGER, LogviewManager)) -#define LOGVIEW_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_MANAGER, LogviewManagerClass)) -#define LOGVIEW_IS_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_MANAGER)) -#define LOGVIEW_IS_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_MANAGER)) -#define LOGVIEW_MANAGER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_MANAGER, LogviewManagerClass)) - -typedef struct _LogviewManager LogviewManager; -typedef struct _LogviewManagerClass LogviewManagerClass; -typedef struct _LogviewManagerPrivate LogviewManagerPrivate; - -struct _LogviewManager { - GObject parent; - LogviewManagerPrivate *priv; -}; - -struct _LogviewManagerClass { - GObjectClass parent_class; - - void (* log_added) (LogviewManager *manager, - LogviewLog *log); - void (* log_closed) (LogviewManager *manager, - LogviewLog *log); - void (* active_changed) (LogviewManager *manager, - LogviewLog *log, - LogviewLog *old_log); -}; - -GType logview_manager_get_type (void); - -/* public methods */ -LogviewManager* logview_manager_get (void); -void logview_manager_add_logs_from_name_list (LogviewManager *manager, - GSList *names, - const char *active); -void logview_manager_add_log_from_gfile (LogviewManager *manager, - GFile *file, - gboolean set_active); -void logview_manager_add_logs_from_names (LogviewManager *manager, - char ** names, - const gchar *active); -void logview_manager_set_active_log (LogviewManager *manager, - LogviewLog *log); -LogviewLog * logview_manager_get_active_log (LogviewManager *manager); -int logview_manager_get_log_count (LogviewManager *manager); -LogviewLog * logview_manager_get_if_loaded (LogviewManager *manager, - char *filename); -gboolean logview_manager_log_is_active (LogviewManager *manager, - LogviewLog *log); -void logview_manager_close_active_log (LogviewManager *manager); - -G_END_DECLS - -#endif /* __LOGVIEW_MANAGER_H__ */ diff --git a/logview/logview-marshal.list b/logview/logview-marshal.list deleted file mode 100644 index 38076d6c..00000000 --- a/logview/logview-marshal.list +++ /dev/null @@ -1 +0,0 @@ -VOID:OBJECT,OBJECT diff --git a/logview/logview-prefs.c b/logview/logview-prefs.c deleted file mode 100644 index 0a2e0093..00000000 --- a/logview/logview-prefs.c +++ /dev/null @@ -1,546 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-prefs.c - logview user preferences handling - * - * Copyright (C) 1998 Cesar Miquel - * Copyright (C) 2004 Vincent Noel - * Copyright (C) 2006 Emmanuele Bassi - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include "logview-prefs.h" - -#define LOGVIEW_DEFAULT_HEIGHT 400 -#define LOGVIEW_DEFAULT_WIDTH 600 - -/* logview settings */ -#define LOGVIEW_SCHEMA "org.mate.system-log" -#define PREF_WIDTH "width" -#define PREF_HEIGHT "height" -#define PREF_LOGFILE "logfile" -#define PREF_LOGFILES "logfiles" -#define PREF_FONTSIZE "fontsize" -#define PREF_FILTERS "filters" - -/* desktop-wide settings */ -#define MATE_MONOSPACE_FONT_NAME "monospace-font-name" -#define MATE_MENUS_HAVE_TEAROFF "menus-have-tearoff" - -static LogviewPrefs *singleton = NULL; - -enum { - SYSTEM_FONT_CHANGED, - HAVE_TEAROFF_CHANGED, - 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) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_PREFS, LogviewPrefsPrivate)) - -struct _LogviewPrefsPrivate { - GSettings *logview_prefs; - GSettings *interface_prefs; - - GHashTable *filters; -}; - -G_DEFINE_TYPE (LogviewPrefs, logview_prefs, G_TYPE_OBJECT); - -static void -do_finalize (GObject *obj) -{ - LogviewPrefs *prefs = LOGVIEW_PREFS (obj); - - g_hash_table_destroy (prefs->priv->filters); - - g_object_unref (prefs->priv->logview_prefs); - g_object_unref (prefs->priv->interface_prefs); - - G_OBJECT_CLASS (logview_prefs_parent_class)->finalize (obj); -} - -static void -logview_prefs_class_init (LogviewPrefsClass *klass) -{ - GObjectClass *oclass = G_OBJECT_CLASS (klass); - - oclass->finalize = do_finalize; - - signals[SYSTEM_FONT_CHANGED] = g_signal_new ("system-font-changed", - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewPrefsClass, system_font_changed), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); - signals[HAVE_TEAROFF_CHANGED] = g_signal_new ("have-tearoff-changed", - G_OBJECT_CLASS_TYPE (oclass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (LogviewPrefsClass, have_tearoff_changed), - NULL, NULL, - g_cclosure_marshal_VOID__BOOLEAN, - G_TYPE_NONE, 1, - G_TYPE_BOOLEAN); - - g_type_class_add_private (klass, sizeof (LogviewPrefsPrivate)); -} - -static void -have_tearoff_changed_cb (GSettings *settings, - gchar *key, - gpointer data) -{ - LogviewPrefs *prefs = data; - gboolean add_tearoffs; - - add_tearoffs = g_settings_get_boolean (settings, key); - g_signal_emit (prefs, signals[HAVE_TEAROFF_CHANGED], 0, add_tearoffs, NULL); -} - -static void -monospace_font_changed_cb (GSettings *settings, - gchar *key, - gpointer data) -{ - LogviewPrefs *prefs = data; - gchar *monospace_font_name; - - monospace_font_name = g_settings_get_string (settings, key); - g_signal_emit (prefs, signals[SYSTEM_FONT_CHANGED], 0, monospace_font_name, NULL); - - g_free (monospace_font_name); -} - -#define DELIMITER ":" - -static void -load_filters (LogviewPrefs *prefs) -{ - gchar **filters; - gchar **tokens; - const gchar *str; - LogviewFilter *filter; - GtkTextTag *tag; - GdkColor color; - gint idx; - - filters = g_settings_get_strv (prefs->priv->logview_prefs, - PREF_FILTERS); - - prefs->priv->filters = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) g_object_unref); - - for (idx = 0; filters[idx] != NULL; idx++) { - str = filters[idx]; - tokens = g_strsplit (str, DELIMITER, MAX_TOKENS); - filter = logview_filter_new (tokens[FILTER_NAME], tokens[FILTER_REGEX]); - 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])) { - gdk_color_parse (tokens[FILTER_FOREGROUND], &color); - g_object_set (tag, "foreground-gdk", &color, - "foreground-set", TRUE, NULL); - } - - if (strlen (tokens[FILTER_BACKGROUND])) { - gdk_color_parse (tokens[FILTER_BACKGROUND], &color); - g_object_set (tag, "paragraph-background-gdk", &color, - "paragraph-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_strfreev (filters); -} - -static void -save_filter_foreach_func (gpointer key, gpointer value, gpointer user_data) -{ - GPtrArray *filters; - const gchar *name; - LogviewFilter *filter; - GdkColor *foreground; - gboolean foreground_set; - GdkColor *background; - gboolean background_set; - gchar *regex, *color; - gboolean invisible; - GtkTextTag *tag; - GString *prefs_string; - - filters = user_data; - filter = LOGVIEW_FILTER (value); - name = key; - color = NULL; - - prefs_string = g_string_new (name); - g_string_append (prefs_string, DELIMITER); - - g_object_get (filter, - "regex", ®ex, - "texttag", &tag, - NULL); - g_object_get (tag, - "foreground-gdk", &foreground, - "paragraph-background-gdk", &background, - "foreground-set", &foreground_set, - "paragraph-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) { - color = gdk_color_to_string (foreground); - g_string_append (prefs_string, color); - g_free (color); - } - - if (foreground) { - gdk_color_free (foreground); - } - - g_string_append (prefs_string, DELIMITER); - - if (background_set) { - color = gdk_color_to_string (background); - g_string_append (prefs_string, color); - g_free (color); - } - - if (background) { - gdk_color_free (background); - } - - g_string_append (prefs_string, DELIMITER); - g_string_append (prefs_string, regex); - - g_free (regex); - g_object_unref (tag); - - g_ptr_array_add (filters, g_string_free (prefs_string, FALSE)); -} - -static void -save_filters (LogviewPrefs *prefs) -{ - GPtrArray *filters; - gchar **filters_strv; - - filters = g_ptr_array_new (); - g_hash_table_foreach (prefs->priv->filters, - save_filter_foreach_func, - filters); - g_ptr_array_add (filters, NULL); - - filters_strv = (gchar **) g_ptr_array_free (filters, FALSE); - g_settings_set_strv (prefs->priv->logview_prefs, - PREF_FILTERS, - (const gchar **) filters_strv); - - g_strfreev (filters_strv); -} - -static void -get_filters_foreach (gpointer key, gpointer value, gpointer user_data) -{ - GList **list; - list = user_data; - *list = g_list_append (*list, value); -} - -static void -logview_prefs_init (LogviewPrefs *self) -{ - LogviewPrefsPrivate *priv; - - priv = self->priv = GET_PRIVATE (self); - - priv->logview_prefs = g_settings_new (LOGVIEW_SCHEMA); - priv->interface_prefs = g_settings_new ("org.mate.interface"); - - g_signal_connect (priv->interface_prefs, "changed::" MATE_MONOSPACE_FONT_NAME, - G_CALLBACK (monospace_font_changed_cb), self); - g_signal_connect (priv->interface_prefs, "changed::" MATE_MENUS_HAVE_TEAROFF, - G_CALLBACK (have_tearoff_changed_cb), self); - - load_filters (self); -} - -/* public methods */ - -LogviewPrefs * -logview_prefs_get () -{ - if (!singleton) - singleton = g_object_new (LOGVIEW_TYPE_PREFS, NULL); - - return singleton; -} - -void -logview_prefs_store_window_size (LogviewPrefs *prefs, - int width, int height) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - g_settings_set_int (prefs->priv->logview_prefs, - PREF_WIDTH, width); - g_settings_set_int (prefs->priv->logview_prefs, - PREF_HEIGHT, height); -} - -void -logview_prefs_get_stored_window_size (LogviewPrefs *prefs, - int *width, int *height) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - *width = g_settings_get_int (prefs->priv->logview_prefs, - PREF_WIDTH); - *height = g_settings_get_int (prefs->priv->logview_prefs, - PREF_HEIGHT); - - if ((*width == 0) ^ (*height == 0)) { - /* if one of the two failed, return default for both */ - *width = LOGVIEW_DEFAULT_WIDTH; - *height = LOGVIEW_DEFAULT_HEIGHT; - } -} - -char * -logview_prefs_get_monospace_font_name (LogviewPrefs *prefs) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - return (g_settings_get_string (prefs->priv->interface_prefs, MATE_MONOSPACE_FONT_NAME)); -} - -gboolean -logview_prefs_get_have_tearoff (LogviewPrefs *prefs) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - return (g_settings_get_boolean (prefs->priv->interface_prefs, MATE_MENUS_HAVE_TEAROFF)); -} - -/* the elements should be freed with g_free () */ - -gchar ** -logview_prefs_get_stored_logfiles (LogviewPrefs *prefs) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - return g_settings_get_strv (prefs->priv->logview_prefs, - PREF_LOGFILES); -} - -void -logview_prefs_store_log (LogviewPrefs *prefs, GFile *file) -{ - gchar **stored_logs; - GFile *stored; - gboolean found = FALSE; - gint idx, old_size; - - g_assert (LOGVIEW_IS_PREFS (prefs)); - g_assert (G_IS_FILE (file)); - - stored_logs = logview_prefs_get_stored_logfiles (prefs); - - for (idx = 0; stored_logs[idx] != NULL; idx++) { - stored = g_file_parse_name (stored_logs[idx]); - if (g_file_equal (file, stored)) { - found = TRUE; - } - - g_object_unref (stored); - - if (found) { - break; - } - } - - if (!found) { - old_size = g_strv_length (stored_logs); - stored_logs = g_realloc (stored_logs, (old_size + 2) * sizeof (gchar *)); - stored_logs[old_size] = g_file_get_parse_name (file); - stored_logs[old_size + 1] = NULL; - - g_settings_set_strv (prefs->priv->logview_prefs, - PREF_LOGFILES, - (const gchar **) stored_logs); - } - - g_strfreev (stored_logs); -} - -void -logview_prefs_remove_stored_log (LogviewPrefs *prefs, GFile *target) -{ - gchar **stored_logs; - GFile *stored; - GPtrArray *new_value; - gint idx; - gboolean removed = FALSE; - - g_assert (LOGVIEW_IS_PREFS (prefs)); - g_assert (G_IS_FILE (target)); - - stored_logs = logview_prefs_get_stored_logfiles (prefs); - new_value = g_ptr_array_new (); - - for (idx = 0; stored_logs[idx] != NULL; idx++) { - stored = g_file_parse_name (stored_logs[idx]); - if (!g_file_equal (stored, target)) { - g_ptr_array_add (new_value, g_strdup (stored_logs[idx])); - } - - g_object_unref (stored); - } - - g_ptr_array_add (new_value, NULL); - g_strfreev (stored_logs); - stored_logs = (gchar **) g_ptr_array_free (new_value, FALSE); - - g_settings_set_strv (prefs->priv->logview_prefs, - PREF_LOGFILES, - (const gchar **) stored_logs); - - g_strfreev (stored_logs); -} - -void -logview_prefs_store_fontsize (LogviewPrefs *prefs, int fontsize) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - g_assert (fontsize > 0); - - g_settings_set_int (prefs->priv->logview_prefs, PREF_FONTSIZE, fontsize); -} - -int -logview_prefs_get_stored_fontsize (LogviewPrefs *prefs) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - return g_settings_get_int (prefs->priv->logview_prefs, PREF_FONTSIZE); -} - -void -logview_prefs_store_active_logfile (LogviewPrefs *prefs, - const char *filename) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - g_settings_set_string (prefs->priv->logview_prefs, - PREF_LOGFILE, filename); -} - -char * -logview_prefs_get_active_logfile (LogviewPrefs *prefs) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - return g_settings_get_string (prefs->priv->logview_prefs, - PREF_LOGFILE); -} - -GList * -logview_prefs_get_filters (LogviewPrefs *prefs) -{ - GList *filters = NULL; - - g_assert (LOGVIEW_IS_PREFS (prefs)); - - g_hash_table_foreach (prefs->priv->filters, - get_filters_foreach, - &filters); - - return filters; -} - -void -logview_prefs_remove_filter (LogviewPrefs *prefs, - const gchar *name) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - g_hash_table_remove (prefs->priv->filters, - name); - - save_filters (prefs); -} - -void -logview_prefs_add_filter (LogviewPrefs *prefs, - LogviewFilter *filter) -{ - gchar* name; - - g_assert (LOGVIEW_IS_PREFS (prefs)); - g_assert (LOGVIEW_IS_FILTER (filter)); - - 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) -{ - g_assert (LOGVIEW_IS_PREFS (prefs)); - - return g_hash_table_lookup (prefs->priv->filters, name); -} - diff --git a/logview/logview-prefs.h b/logview/logview-prefs.h deleted file mode 100644 index bc9c6608..00000000 --- a/logview/logview-prefs.h +++ /dev/null @@ -1,89 +0,0 @@ -/* logview-prefs.h - logview user preferences handling - * - * Copyright (C) 2004 Vincent Noel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#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)) -#define LOGVIEW_PREFS_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_PREFS, LogviewPrefsClass)) -#define LOGVIEW_IS_PREFS(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_PREFS)) -#define LOGVIEW_IS_PREFS_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_PREFS)) -#define LOGVIEW_PREFS_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_PREFS, LogviewPrefsClass)) - -typedef struct _LogviewPrefs LogviewPrefs; -typedef struct _LogviewPrefsClass LogviewPrefsClass; -typedef struct _LogviewPrefsPrivate LogviewPrefsPrivate; - -struct _LogviewPrefs { - GObject parent; - LogviewPrefsPrivate *priv; -}; - -struct _LogviewPrefsClass { - GObjectClass parent_class; - - /* signals */ - void (* system_font_changed) (LogviewPrefs *prefs, - 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); -gchar ** 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); - -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__ */ diff --git a/logview/logview-utils.c b/logview/logview-utils.c deleted file mode 100644 index c8a61ed1..00000000 --- a/logview/logview-utils.c +++ /dev/null @@ -1,282 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-utils.c - misc logview utilities - * - * Copyright (C) 1998 Cesar Miquel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _XOPEN_SOURCE -#define _XOPEN_SOURCE_EXTENDED 1 /* strptime is XPG4v2 */ -#include -#include -#include -#include - -#include - -#include "logview-utils.h" - -void -logview_utils_day_free (Day *day) -{ - if (!day) { - return; - } - - g_date_free (day->date); - g_slice_free (Day, day); -} - -Day * -logview_utils_day_copy (Day *day) -{ - Day *retval; - - retval = g_slice_new0 (Day); - retval->date = g_date_new_julian (g_date_get_julian (day->date)); - retval->first_line = day->first_line; - retval->last_line = day->last_line; - retval->timestamp_len = day->timestamp_len; - - return retval; -} - -GSList * -logview_utils_day_list_copy (GSList *days) -{ - GSList *l, *retval = NULL; - - for (l = days; l; l = l->next) { - retval = g_slist_prepend (retval, logview_utils_day_copy (l->data)); - } - - return g_slist_reverse (retval); -} - -gint -days_compare (gconstpointer a, gconstpointer b) -{ - const Day *day1 = a, *day2 = b; - - return g_date_compare (day1->date, day2->date); -} - -static GDate * -string_get_date (const char *line, char **time_string, int *timestamp_len) -{ - GDate *date = NULL; - struct tm tp; - char *cp = NULL, *timestamp = NULL; - - /* it's safe to assume that if strptime returns NULL, it's - * because of an error (format unmatched). being a log file, it's very - * unlikely that there aren't any more characters after the date. - */ - - if (line == NULL || line[0] == '\0') { - return NULL; - } - - /* this parses the "MonthName DayNo" format */ - cp = strptime (line, "%b %d", &tp); - if (cp) { - goto out; - } - - /* this parses the YYYY-MM-DD format */ - cp = strptime (line, "%F", &tp); - if (cp) { - goto out; - } - -out: - if (cp) { - /* the year doesn't matter to us now */ - date = g_date_new_dmy (tp.tm_mday, tp.tm_mon + 1, 1); - *time_string = g_strndup (line, cp - line); - - timestamp = strptime (cp, "%X", &tp); - if (timestamp) { - *timestamp_len = timestamp - line; - } - } - - return date; -} - -/** - * log_read_dates: - * - * @buffer_lines: an array of text lines. - * @current: the mtime of the file being parsed. - * - * Reads all the dates inside the text buffer. - * All dates are given with respect to the 1/1/1970 - * and are then corrected to the correct year once we - * reach the end. - * - * Returns: a #GSList of #Day structures. - */ - -GSList * -log_read_dates (const char **buffer_lines, time_t current) -{ - int current_year, offsetyear, i, n, rangemin, rangemax, timestamp_len = 0; - GSList *days = NULL; - GDate *date = NULL; - struct tm *tmptm; - char *date_string = NULL; - Day *day; - gboolean done = FALSE; - - g_return_val_if_fail (buffer_lines != NULL, NULL); - - n = g_strv_length ((char **) buffer_lines); - - tmptm = localtime (¤t); - current_year = tmptm->tm_year + 1900; - offsetyear = 0; - - /* find the first line with a date we're able to parse */ - for (i = 0; buffer_lines[i]; i++) { - if ((date = string_get_date (buffer_lines[i], &date_string, ×tamp_len)) != NULL) - break; - } - - if (!date) { - /* no valid dates in the array, return NULL */ - return NULL; - } - - if (!g_date_valid (date)) { - g_date_free (date); - g_free (date_string); - return NULL; - } - - g_date_set_year (date, current_year); - - day = g_slice_new0 (Day); - days = g_slist_append (days, day); - - /* $i now contains the line number for the first good date */ - day->date = date; - day->first_line = i; - day->last_line = -1; - day->timestamp_len = timestamp_len; - - /* now scan the logfile to get the last line of the day */ - rangemin = i; - rangemax = n - 1; - - while (!done) { - /* find out the last line of the day we're currently building */ - - i = n - 1; - - while (day->last_line < 0) { - if (strstr (buffer_lines[i], date_string)) { - /* if we find the same string on the last line of the log, we're done */ - if (i == n - 1) { - done = TRUE; - day->last_line = i; - break; - } - - /* we're still in a section of lines with the same date; - * - if the next one changes, then we're on the last. - * - else we keep searching in the following. - */ - - if (!strstr (buffer_lines[i + 1], date_string)) { - day->last_line = i; - break; - } else { - rangemin = i; - i = floor (((float) i + (float) rangemax) / 2.); - } - } else { - /* we can't find the same date here; go back to a safer range. */ - rangemax = i; - i = floor (((float) rangemin + (float) i) / 2.); - } - } - - g_free (date_string); - date_string = NULL; - - if (!done) { - /* this means we finished the current day but we're not at the end - * of the buffer: reset the parameters for the next day. - */ - GDate *newdate = NULL; - - for (i = day->last_line + 1; buffer_lines[i]; i++) { - if ((newdate = string_get_date (buffer_lines[i], &date_string, ×tamp_len)) != NULL) - break; - } - - if (date_string == NULL && i == n - 1) { - done = TRUE; - } - - /* this will set the last line of the "old" log to either: - * - "n - 1" if we can't find another date - * - the line before the new date else. - */ - day->last_line = i - 1; - - if (newdate) { - /* append a new day to the list */ - - g_date_set_year (newdate, current_year + offsetyear); - - if (g_date_compare (newdate, date) < 1) { - /* this isn't possible, as we're reading the log forward. - * so it means that newdate is the next year. - */ - g_date_add_years (newdate, 1); - offsetyear++; - } - - date = newdate; - day = g_slice_new0 (Day); - days = g_slist_prepend (days, day); - - day->date = date; - day->first_line = i; - day->last_line = -1; - day->timestamp_len = timestamp_len; - rangemin = i; - rangemax = n - 1; - } - } - } - - if (date_string) { - g_free (date_string); - } - - /* sort the days in chronological order */ - days = g_slist_sort (days, days_compare); - - return days; -} diff --git a/logview/logview-utils.h b/logview/logview-utils.h deleted file mode 100644 index 27242917..00000000 --- a/logview/logview-utils.h +++ /dev/null @@ -1,40 +0,0 @@ -/* logview-utils.h - misc logview utilities - * - * Copyright (C) 1998 Cesar Miquel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - */ - -#ifndef __LOGVIEW_UTILS_H__ -#define __LOGVIEW_UTILS_H__ - -#include - -typedef struct { - GDate *date; - int first_line; - int last_line; - int timestamp_len; -} Day; - -GSList * log_read_dates (const char **buffer_lines, time_t current); -gint days_compare (gconstpointer a, gconstpointer b); -void logview_utils_day_free (Day *day); -Day * logview_utils_day_copy (Day *day); -GSList * logview_utils_day_list_copy (GSList *days); - - -#endif /* __LOGVIEW_UTILS_H__ */ \ No newline at end of file diff --git a/logview/logview-window.c b/logview/logview-window.c deleted file mode 100644 index d0728f92..00000000 --- a/logview/logview-window.c +++ /dev/null @@ -1,1548 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* logview-window.c - main window of logview - * - * Copyright (C) 1998 Cesar Miquel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include - -#include "logview-window.h" - -#include "logview-loglist.h" -#include "logview-findbar.h" -#include "logview-about.h" -#include "logview-prefs.h" -#include "logview-manager.h" -#include "logview-filter-manager.h" - -#define APP_NAME _("System Log Viewer") -#define SEARCH_START_MARK "lw-search-start-mark" -#define SEARCH_END_MARK "lw-search-end-mark" - -struct _LogviewWindowPrivate { - GtkUIManager *ui_manager; - GtkActionGroup *action_group; - GtkActionGroup *filter_action_group; - - GtkWidget *find_bar; - GtkWidget *loglist; - GtkWidget *sidebar; - GtkWidget *version_bar; - GtkWidget *version_selector; - GtkWidget *hpaned; - GtkWidget *text_view; - GtkWidget *statusbar; - - GtkWidget *message_area; - GtkWidget *message_primary; - GtkWidget *message_secondary; - - GtkTextTagTable *tag_table; - - int original_fontsize, fontsize; - - LogviewPrefs *prefs; - LogviewManager *manager; - - gulong monitor_id; - guint search_timeout_id; - - GCancellable *read_cancellable; - - guint filter_merge_id; - GList *active_filters; - gboolean matches_only; -}; - -#define GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_WINDOW, LogviewWindowPrivate)) - -G_DEFINE_TYPE (LogviewWindow, logview_window, GTK_TYPE_WINDOW); - -static void findbar_close_cb (LogviewFindbar *findbar, - gpointer user_data); -static void read_new_lines_cb (LogviewLog *log, - const char **lines, - GSList *new_days, - GError *error, - gpointer user_data); - -/* private functions */ - -static void -logview_version_selector_changed (GtkComboBox *version_selector, gpointer user_data) -{ - -} -#if 0 - LogviewWindow *logview = user_data; - Log *log = logview->curlog; - int selected; - - g_assert (LOGVIEW_IS_WINDOW (logview)); - - selected = gtk_combo_box_get_active (version_selector); - - if (selected == log->current_version) - return; - - /* select a new version */ - if (selected == 0) { - logview_select_log (logview, log->parent_log); - } else { - Log *new; - if (log->parent_log) { - new = log->parent_log->older_logs[selected]; - } else { - new = log->older_logs[selected]; - } - - logview_select_log (logview, new); - } -} - -#endif - -/* private helpers */ - -static void -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); - - gtk_text_tag_table_add (tag_table, tag); - - 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); -} - - -static void -populate_style_tag_table (GtkStyle *style, - GtkTextTagTable *tag_table) -{ - GtkTextTag *tag; - GdkColor color; - - tag = gtk_text_tag_table_lookup (tag_table, "gray"); - - if (tag) { - /* FIXME: do we need a way to update the buffer/view? */ - gtk_text_tag_table_remove (tag_table, tag); - } - - tag = gtk_text_tag_new ("gray"); - color = style->text[GTK_STATE_INSENSITIVE]; - g_object_set (tag, "foreground-gdk", &color, "foreground-set", TRUE, NULL); - - gtk_text_tag_table_add (tag_table, tag); -} - -static void -_gtk_text_buffer_apply_tag_to_rectangle (GtkTextBuffer *buffer, int line_start, int line_end, - int offset_start, int offset_end, char *tag_name) -{ - GtkTextIter start, end; - int line_cur; - - gtk_text_buffer_get_iter_at_line (buffer, &start, line_start); - gtk_text_buffer_get_iter_at_line (buffer, &end, line_start); - - for (line_cur = line_start; line_cur < line_end + 1; line_cur++) { - - if (offset_start > 0) { - gtk_text_iter_forward_chars (&start, offset_start); - } - - gtk_text_iter_forward_chars (&end, offset_end); - - gtk_text_buffer_apply_tag_by_name (buffer, tag_name, &start, &end); - - gtk_text_iter_forward_line (&start); - gtk_text_iter_forward_line (&end); - } -} - -static void -logview_update_statusbar (LogviewWindow *logview, LogviewLog *active) -{ - char *statusbar_text; - char *size, *modified, *timestring_utf8; - time_t timestamp; - char timestring[255]; - - if (active == NULL) { - gtk_statusbar_pop (GTK_STATUSBAR (logview->priv->statusbar), 0); - return; - } - - timestamp = logview_log_get_timestamp (active); - strftime (timestring, sizeof (timestring), "%a %b %e %T %Y", localtime (×tamp)); - timestring_utf8 = g_locale_to_utf8 (timestring, -1, NULL, NULL, NULL); - - modified = g_strdup_printf (_("last update: %s"), timestring_utf8); - - size = g_format_size (logview_log_get_file_size (active)); - - statusbar_text = g_strdup_printf (_("%d lines (%s) - %s"), - logview_log_get_cached_lines_number (active), - size, modified); - - gtk_statusbar_pop (GTK_STATUSBAR (logview->priv->statusbar), 0); - gtk_statusbar_push (GTK_STATUSBAR (logview->priv->statusbar), 0, statusbar_text); - - g_free (size); - g_free (timestring_utf8); - g_free (modified); - g_free (statusbar_text); -} - -#define DEFAULT_LOGVIEW_FONT "Monospace 10" - -static void -logview_set_font (LogviewWindow *logview, - const char *fontname) -{ - PangoFontDescription *font_desc; - - if (fontname == NULL) - fontname = DEFAULT_LOGVIEW_FONT; - - font_desc = pango_font_description_from_string (fontname); - if (font_desc) { - gtk_widget_modify_font (logview->priv->text_view, font_desc); - pango_font_description_free (font_desc); - } -} - -static void -logview_set_fontsize (LogviewWindow *logview, gboolean store) -{ - PangoFontDescription *fontdesc; - PangoContext *context; - LogviewWindowPrivate *priv = logview->priv; - - context = gtk_widget_get_pango_context (priv->text_view); - fontdesc = pango_context_get_font_description (context); - pango_font_description_set_size (fontdesc, (priv->fontsize) * PANGO_SCALE); - gtk_widget_modify_font (priv->text_view, fontdesc); - - if (store) { - logview_prefs_store_fontsize (logview->priv->prefs, priv->fontsize); - } -} - -static void -logview_set_window_title (LogviewWindow *logview, const char * log_name) -{ - char *window_title; - - if (log_name) { - window_title = g_strdup_printf ("%s - %s", log_name, APP_NAME); - } else { - window_title = g_strdup_printf (APP_NAME); - } - - gtk_window_set_title (GTK_WINDOW (logview), window_title); - - g_free (window_title); -} - -/* actions callbacks */ - -static void -open_file_selected_cb (GtkWidget *chooser, gint response, LogviewWindow *logview) -{ - GFile *f; - char *file_uri; - LogviewLog *log; - - gtk_widget_hide (GTK_WIDGET (chooser)); - if (response != GTK_RESPONSE_OK) { - return; - } - - f = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (chooser)); - file_uri = g_file_get_uri (f); - - log = logview_manager_get_if_loaded (logview->priv->manager, file_uri); - - g_free (file_uri); - - if (log) { - logview_manager_set_active_log (logview->priv->manager, log); - g_object_unref (log); - goto out; - } - - logview_manager_add_log_from_gfile (logview->priv->manager, f, TRUE); - -out: - g_object_unref (f); -} - -static void -logview_open_log (GtkAction *action, LogviewWindow *logview) -{ - static GtkWidget *chooser = NULL; - char *active; - - if (chooser == NULL) { - chooser = gtk_file_chooser_dialog_new (_("Open Log"), - GTK_WINDOW (logview), - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_OK, - NULL); - gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK); - gtk_window_set_modal (GTK_WINDOW (chooser), TRUE); - g_signal_connect (chooser, "response", - G_CALLBACK (open_file_selected_cb), logview); - g_signal_connect (chooser, "destroy", - G_CALLBACK (gtk_widget_destroyed), &chooser); - active = logview_prefs_get_active_logfile (logview->priv->prefs); - if (active != NULL) { - gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), active); - g_free (active); - } - } - - gtk_window_present (GTK_WINDOW (chooser)); -} - -static void -logview_close_log (GtkAction *action, LogviewWindow *logview) -{ - findbar_close_cb (LOGVIEW_FINDBAR (logview->priv->find_bar), logview); - logview_manager_close_active_log (logview->priv->manager); -} - -static void -logview_help (GtkAction *action, GtkWidget *parent_window) -{ - GError *error = NULL; - - gtk_show_uri (gtk_widget_get_screen (parent_window), - "help:mate-system-log", gtk_get_current_event_time (), - &error); - - if (error) { - g_warning (_("There was an error displaying help: %s"), error->message); - g_error_free (error); - } -} - -static void -logview_bigger_text (GtkAction *action, LogviewWindow *logview) -{ - logview->priv->fontsize = MIN (logview->priv->fontsize + 1, 24); - logview_set_fontsize (logview, TRUE); -} - -static void -logview_smaller_text (GtkAction *action, LogviewWindow *logview) -{ - logview->priv->fontsize = MAX (logview->priv->fontsize-1, 6); - logview_set_fontsize (logview, TRUE); -} - -static void -logview_normal_text (GtkAction *action, LogviewWindow *logview) -{ - logview->priv->fontsize = logview->priv->original_fontsize; - logview_set_fontsize (logview, TRUE); -} - -static void -logview_select_all (GtkAction *action, LogviewWindow *logview) -{ - GtkTextIter start, end; - GtkTextBuffer *buffer; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); - - gtk_text_buffer_get_bounds (buffer, &start, &end); - gtk_text_buffer_select_range (buffer, &start, &end); - - gtk_widget_grab_focus (GTK_WIDGET (logview->priv->text_view)); -} - -static void -logview_copy (GtkAction *action, LogviewWindow *logview) -{ - GtkTextBuffer *buffer; - GtkClipboard *clipboard; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - - gtk_text_buffer_copy_clipboard (buffer, clipboard); - - gtk_widget_grab_focus (GTK_WIDGET (logview->priv->text_view)); -} - -static void -findbar_close_cb (LogviewFindbar *findbar, - gpointer user_data) -{ - gtk_widget_hide (GTK_WIDGET (findbar)); - logview_findbar_set_message (findbar, NULL); -} - -static void -logview_search_text (LogviewWindow *logview, gboolean forward) -{ - GtkTextBuffer *buffer; - GtkTextMark *search_start, *search_end; - GtkTextIter search, start_m, end_m; - const char *text; - gboolean res, wrapped; - - wrapped = FALSE; - - text = logview_findbar_get_text (LOGVIEW_FINDBAR (logview->priv->find_bar)); - - if (!text || g_strcmp0 (text, "") == 0) { - return; - } - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); - search_start = gtk_text_buffer_get_mark (buffer, SEARCH_START_MARK); - search_end = gtk_text_buffer_get_mark (buffer, SEARCH_END_MARK); - - if (!search_start) { - /* this is our first search on the buffer, create a new search mark */ - gtk_text_buffer_get_start_iter (buffer, &search); - search_start = gtk_text_buffer_create_mark (buffer, SEARCH_START_MARK, - &search, TRUE); - search_end = gtk_text_buffer_create_mark (buffer, SEARCH_END_MARK, - &search, TRUE); - } else { - if (forward) { - gtk_text_buffer_get_iter_at_mark (buffer, &search, search_end); - } else { - gtk_text_buffer_get_iter_at_mark (buffer, &search, search_start); - } - } - -wrap: - - if (forward) { - res = gtk_text_iter_forward_search (&search, text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start_m, &end_m, NULL); - } else { - res = gtk_text_iter_backward_search (&search, text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start_m, &end_m, NULL); - } - - if (res) { - gtk_text_buffer_select_range (buffer, &start_m, &end_m); - gtk_text_buffer_move_mark (buffer, search_start, &start_m); - gtk_text_buffer_move_mark (buffer, search_end, &end_m); - - gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (logview->priv->text_view), search_end); - - if (wrapped) { - logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), _("Wrapped")); - } - } else { - if (wrapped) { - - GtkTextMark *mark; - GtkTextIter iter; - - if (gtk_text_buffer_get_has_selection (buffer)) { - /* unselect */ - mark = gtk_text_buffer_get_mark (buffer, "insert"); - gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark); - gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter); - } - - logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), _("Not found")); - } else { - if (forward) { - gtk_text_buffer_get_start_iter (buffer, &search); - } else { - gtk_text_buffer_get_end_iter (buffer, &search); - } - - wrapped = TRUE; - goto wrap; - } - } -} - -static void -findbar_previous_cb (LogviewFindbar *findbar, - gpointer user_data) -{ - LogviewWindow *logview = user_data; - - logview_search_text (logview, FALSE); -} - -static void -findbar_next_cb (LogviewFindbar *findbar, - gpointer user_data) -{ - LogviewWindow *logview = user_data; - - logview_search_text (logview, TRUE); -} - -static gboolean -text_changed_timeout_cb (gpointer user_data) -{ - LogviewWindow *logview = user_data; - GtkTextMark *search_start, *search_end; - GtkTextIter start; - GtkTextBuffer *buffer; - - logview->priv->search_timeout_id = 0; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); - search_start = gtk_text_buffer_get_mark (buffer, SEARCH_START_MARK); - search_end = gtk_text_buffer_get_mark (buffer, SEARCH_END_MARK); - - if (search_start) { - /* reset the search mark to the start */ - gtk_text_buffer_get_start_iter (buffer, &start); - gtk_text_buffer_move_mark (buffer, search_start, &start); - gtk_text_buffer_move_mark (buffer, search_end, &start); - } - - logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), NULL); - - logview_search_text (logview, TRUE); - - return FALSE; -} - -static void -findbar_text_changed_cb (LogviewFindbar *findbar, - gpointer user_data) -{ - LogviewWindow *logview = user_data; - - if (logview->priv->search_timeout_id != 0) { - g_source_remove (logview->priv->search_timeout_id); - } - - logview->priv->search_timeout_id = g_timeout_add (300, text_changed_timeout_cb, logview); -} - -static void -logview_search (GtkAction *action, LogviewWindow *logview) -{ - logview_findbar_open (LOGVIEW_FINDBAR (logview->priv->find_bar)); -} - -static void -filter_buffer (LogviewWindow *logview, gint start_line) -{ - GtkTextBuffer *buffer; - GtkTextIter start, *end; - gchar* text; - GList* cur_filter; - gboolean matched; - int lines, i; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); - lines = gtk_text_buffer_get_line_count (buffer); - - for (i = start_line; i < lines; i++) { - matched = FALSE; - - gtk_text_buffer_get_iter_at_line (buffer, &start, i); - end = gtk_text_iter_copy (&start); - gtk_text_iter_forward_line (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; - } - } - - g_free (text); - - 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); - } - - gtk_text_iter_free (end); - } -} - -static void -filter_remove (LogviewWindow *logview, LogviewFilter *filter) -{ - GtkTextIter start, end; - GtkTextBuffer *buffer; - - 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; - LogviewFilter *filter; - - 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 (priv->prefs, - name)); - filter_buffer(logview, 0); - } else { - filter = logview_prefs_get_filter (priv->prefs, 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; - guint id; - GList *filters; - GtkTextBuffer *buffer; - GtkTextTagTable *table; - GtkTextTag *tag; - GtkToggleAction *action; - gchar* name; - - 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)) { - 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)) { - 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); - } - - g_list_free (filters); - - priv->filter_merge_id = id; -} - -static void -on_logview_filter_manager_response (GtkDialog *dialog, - gint response, - LogviewWindow *logview) -{ - update_filter_menu (logview); - - g_list_free (logview->priv->active_filters); - logview->priv->active_filters = NULL; -} - -static void -logview_manage_filters (GtkAction *action, LogviewWindow *logview) -{ - GtkWidget *manager; - - manager = logview_filter_manager_new (); - - g_signal_connect (manager, "response", - G_CALLBACK (on_logview_filter_manager_response), - logview); - - gtk_window_set_transient_for (GTK_WINDOW (manager), - GTK_WINDOW (logview)); - gtk_widget_show (GTK_WIDGET (manager)); -} - -static void -logview_about (GtkWidget *widget, GtkWidget *window) -{ - g_return_if_fail (GTK_IS_WINDOW (window)); - - char *license_trans = g_strjoin ("\n\n", _(logview_about_license[0]), - _(logview_about_license[1]), - _(logview_about_license[2]), NULL); - - gtk_show_about_dialog (GTK_WINDOW (window), - "name", _("System Log Viewer"), - "version", VERSION, - "copyright", "Copyright \xc2\xa9 1998-2008 Free Software Foundation, Inc.", - "license", license_trans, - "wrap-license", TRUE, - "comments", _("A system log viewer for MATE."), - "authors", logview_about_authors, - "documenters", logview_about_documenters, - "translator_credits", strcmp (logview_about_translator_credits, - "translator-credits") != 0 ? - logview_about_translator_credits : NULL, - "logo_icon_name", "mate-system-log", - NULL); - g_free (license_trans); - - return; -} - -static void -logview_toggle_statusbar (GtkAction *action, LogviewWindow *logview) -{ - if (gtk_widget_get_visible (logview->priv->statusbar)) - gtk_widget_hide (logview->priv->statusbar); - else - gtk_widget_show (logview->priv->statusbar); -} - -static void -logview_toggle_sidebar (GtkAction *action, LogviewWindow *logview) -{ - if (gtk_widget_get_visible (logview->priv->sidebar)) - gtk_widget_hide (logview->priv->sidebar); - else - 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 */ - -static GtkActionEntry entries[] = { - { "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..."), "O", N_("Open a log from file"), - G_CALLBACK (logview_open_log) }, - { "CloseLog", GTK_STOCK_CLOSE, N_("_Close"), "W", N_("Close this log"), - G_CALLBACK (logview_close_log) }, - { "Quit", GTK_STOCK_QUIT, N_("_Quit"), "Q", N_("Quit the log viewer"), - G_CALLBACK (gtk_main_quit) }, - - { "Copy", GTK_STOCK_COPY, N_("_Copy"), "C", N_("Copy the selection"), - G_CALLBACK (logview_copy) }, - { "SelectAll", NULL, N_("Select _All"), "A", N_("Select the entire log"), - G_CALLBACK (logview_select_all) }, - { "Search", GTK_STOCK_FIND, N_("_Find..."), "F", N_("Find a word or phrase in the log"), - G_CALLBACK (logview_search) }, - - { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "plus", N_("Bigger text size"), - G_CALLBACK (logview_bigger_text)}, - { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "minus", N_("Smaller text size"), - G_CALLBACK (logview_smaller_text)}, - { "ViewZoom100", GTK_STOCK_ZOOM_100, NULL, "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"), - G_CALLBACK (logview_about) }, -}; - -static GtkToggleActionEntry toggle_entries[] = { - { "ShowStatusBar", NULL, N_("_Statusbar"), NULL, N_("Show Status Bar"), - 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 -window_size_changed_cb (GtkWidget *widget, GdkEventConfigure *event, - gpointer data) -{ - LogviewWindow *window = data; - - logview_prefs_store_window_size (window->priv->prefs, - event->width, event->height); - - return FALSE; -} - -static void -real_select_day (LogviewWindow *logview, - GDate *date, int first_line, int last_line) -{ - GtkTextBuffer *buffer; - GtkTextIter start_iter, end_iter, start_vis, end_vis; - GdkRectangle visible_rect; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); - - gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter); - gtk_text_buffer_get_iter_at_line (buffer, &start_vis, first_line); - gtk_text_buffer_get_iter_at_line (buffer, &end_vis, last_line + 1); - - /* clear all previous invisible tags */ - gtk_text_buffer_remove_tag_by_name (buffer, "invisible", - &start_iter, &end_iter); - - gtk_text_buffer_apply_tag_by_name (buffer, "invisible", - &start_iter, &start_vis); - gtk_text_buffer_apply_tag_by_name (buffer, "invisible", - &end_vis, &end_iter); - - /* FIXME: why is this needed to update the view when selecting a day back? */ - gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (logview->priv->text_view), - &visible_rect); - gdk_window_invalidate_rect (gtk_widget_get_window (logview->priv->text_view), - &visible_rect, TRUE); -} - -static void -loglist_day_selected_cb (LogviewLoglist *loglist, - Day *day, - gpointer user_data) -{ - LogviewWindow *logview = user_data; - - real_select_day (logview, day->date, day->first_line, day->last_line); -} - -static void -loglist_day_cleared_cb (LogviewLoglist *loglist, - gpointer user_data) -{ - LogviewWindow *logview = user_data; - GtkTextBuffer *buffer; - GtkTextIter start, end; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); - gtk_text_buffer_get_bounds (buffer, &start, &end); - - /* clear all previous invisible tags */ - gtk_text_buffer_remove_tag_by_name (buffer, "invisible", - &start, &end); -} - -static void -logview_window_schedule_log_read (LogviewWindow *window, - LogviewLog *log) -{ - if (window->priv->read_cancellable != NULL) { - g_cancellable_cancel (window->priv->read_cancellable); - g_clear_object (&window->priv->read_cancellable); - } - - window->priv->read_cancellable = g_cancellable_new (); - logview_log_read_new_lines (log, - window->priv->read_cancellable, - (LogviewNewLinesCallback) read_new_lines_cb, - window); -} - -static void -log_monitor_changed_cb (LogviewLog *log, - gpointer user_data) -{ - LogviewWindow *window = user_data; - - /* reschedule a read */ - logview_window_schedule_log_read (window, log); -} - -static void -paint_timestamps (GtkTextBuffer *buffer, int old_line_count, - GSList *days) -{ - GSList *l; - - for (l = days; l; l = l->next) { - Day *day = l->data; - - _gtk_text_buffer_apply_tag_to_rectangle (buffer, - old_line_count + day->first_line - 1, - old_line_count + day->last_line, - 0, day->timestamp_len, "gray"); - } -} - -static void -read_new_lines_cb (LogviewLog *log, - const char **lines, - GSList *new_days, - GError *error, - gpointer user_data) -{ - LogviewWindow *window = user_data; - GtkTextBuffer *buffer; - gboolean boldify = FALSE; - int i, old_line_count, filter_start_line; - GtkTextIter iter, start; - GtkTextMark *mark; - char *converted, *primary; - gsize len; - - if (error != NULL) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - primary = g_strdup_printf (_("Can't read from \"%s\""), - logview_log_get_display_name (log)); - logview_window_add_error (window, primary, error->message); - g_free (primary); - } - - return; - } - - if (lines == NULL) { - /* there's no error, but no lines have been read */ - return; - } - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->priv->text_view)); - old_line_count = gtk_text_buffer_get_line_count (buffer); - filter_start_line = old_line_count > 0 ? (old_line_count - 1) : 0; - - if (gtk_text_buffer_get_char_count (buffer) != 0) { - boldify = TRUE; - } - - gtk_text_buffer_get_end_iter (buffer, &iter); - - if (boldify) { - mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE); - } - - for (i = 0; lines[i]; i++) { - len = strlen (lines[i]); - - if (!g_utf8_validate (lines[i], len, NULL)) { - converted = g_locale_to_utf8 (lines[i], (gssize) len, NULL, &len, NULL); - gtk_text_buffer_insert (buffer, &iter, converted, len); - g_free (converted); - } else { - gtk_text_buffer_insert (buffer, &iter, lines[i], strlen (lines[i])); - } - - gtk_text_iter_forward_to_end (&iter); - gtk_text_buffer_insert (buffer, &iter, "\n", 1); - gtk_text_iter_forward_char (&iter); - } - - if (boldify) { - gtk_text_buffer_get_iter_at_mark (buffer, &start, mark); - gtk_text_buffer_apply_tag_by_name (buffer, "bold", &start, &iter); - gtk_text_buffer_delete_mark (buffer, mark); - } - filter_buffer (window, filter_start_line); - - gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (window->priv->text_view), - &iter, 0.0, FALSE, 0.0, 0.0); - - paint_timestamps (buffer, old_line_count, new_days); - - if (window->priv->monitor_id == 0) { - window->priv->monitor_id = g_signal_connect (log, "log-changed", - G_CALLBACK (log_monitor_changed_cb), window); - } - - logview_update_statusbar (window, log); - logview_loglist_update_lines (LOGVIEW_LOGLIST (window->priv->loglist), log); -} - -static void -active_log_changed_cb (LogviewManager *manager, - LogviewLog *log, - LogviewLog *old_log, - gpointer data) -{ - LogviewWindow *window = data; - const char **lines; - GtkTextBuffer *buffer; - - findbar_close_cb (LOGVIEW_FINDBAR (window->priv->find_bar), - window); - - logview_set_window_title (window, logview_log_get_display_name (log)); - - if (window->priv->monitor_id) { - g_signal_handler_disconnect (old_log, window->priv->monitor_id); - window->priv->monitor_id = 0; - } - - lines = logview_log_get_cached_lines (log); - buffer = gtk_text_buffer_new (window->priv->tag_table); - - if (lines != NULL) { - int i; - GtkTextIter iter; - - /* update the text view to show the current lines */ - gtk_text_buffer_get_end_iter (buffer, &iter); - - for (i = 0; lines[i]; i++) { - gtk_text_buffer_insert (buffer, &iter, lines[i], strlen (lines[i])); - gtk_text_iter_forward_to_end (&iter); - gtk_text_buffer_insert (buffer, &iter, "\n", 1); - gtk_text_iter_forward_char (&iter); - } - - paint_timestamps (buffer, 1, logview_log_get_days_for_cached_lines (log)); - } - - if (lines == NULL || logview_log_has_new_lines (log)) { - /* read the new lines */ - logview_window_schedule_log_read (window, log); - } else { - /* start now monitoring the log for changes */ - window->priv->monitor_id = g_signal_connect (log, "log-changed", - G_CALLBACK (log_monitor_changed_cb), window); - } - - /* we set the buffer to the view anyway; - * if there are no lines it will be empty for the duration of the thread - * and will help us to distinguish the two cases of the following if - * cause in the callback. - */ - gtk_text_view_set_buffer (GTK_TEXT_VIEW (window->priv->text_view), buffer); - g_object_unref (buffer); -} - -static void -font_changed_cb (LogviewPrefs *prefs, - const char *font_name, - gpointer user_data) -{ - LogviewWindow *window = user_data; - - logview_set_font (window, font_name); -} - -static void -tearoff_changed_cb (LogviewPrefs *prefs, - gboolean have_tearoffs, - gpointer user_data) -{ - LogviewWindow *window = user_data; - - gtk_ui_manager_set_add_tearoffs (window->priv->ui_manager, have_tearoffs); -} - -static void -style_set_cb (GtkWidget *widget, - GtkStyle *prev, - gpointer user_data) -{ - LogviewWindow *logview = user_data; - GtkStyle *style = gtk_widget_get_style (widget); - - populate_style_tag_table (style, logview->priv->tag_table); -} - -static const struct { - guint keyval; - GdkModifierType modifier; - const gchar *action; -} extra_keybindings [] = { - { GDK_KEY_KP_Add, GDK_CONTROL_MASK, "ViewZoomIn" }, - { GDK_KEY_KP_Subtract, GDK_CONTROL_MASK, "ViewZoomOut" }, - { GDK_KEY_KP_0, GDK_CONTROL_MASK, "ViewZoom100" } -}; - -static gboolean -key_press_event_cb (GtkWidget *widget, - GdkEventKey *event, - gpointer user_data) -{ - LogviewWindow *window = user_data; - guint modifier = event->state & gtk_accelerator_get_default_mod_mask (); - GtkAction *action; - int i; - - /* handle accelerators that we want bound, but aren't associated with - * an action */ - for (i = 0; i < G_N_ELEMENTS (extra_keybindings); i++) { - if (event->keyval == extra_keybindings[i].keyval && - modifier == extra_keybindings[i].modifier) { - - action = gtk_action_group_get_action (window->priv->action_group, - extra_keybindings[i].action); - gtk_action_activate (action); - return TRUE; - } - } - - return FALSE; -} - -/* adapted from GEdit */ - -static void -message_area_create_error_box (LogviewWindow *window, - GtkWidget *message_area) -{ - GtkWidget *hbox_content; - GtkWidget *image; - GtkWidget *vbox; - GtkWidget *primary_label; - GtkWidget *secondary_label; - - hbox_content = gtk_hbox_new (FALSE, 8); - gtk_widget_show (hbox_content); - - image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, - GTK_ICON_SIZE_DIALOG); - gtk_widget_show (image); - gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0); - gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0); - - vbox = gtk_vbox_new (FALSE, 6); - gtk_widget_show (vbox); - gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0); - - primary_label = gtk_label_new (NULL); - gtk_widget_show (primary_label); - gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0); - gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE); - gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE); - gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5); - gtk_widget_set_can_focus (primary_label, TRUE); - gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE); - - window->priv->message_primary = primary_label; - - secondary_label = gtk_label_new (NULL); - gtk_widget_show (secondary_label); - gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0); - gtk_widget_set_can_focus (secondary_label, TRUE); - gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE); - gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE); - gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE); - gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5); - - window->priv->message_secondary = secondary_label; - - gtk_container_add - (GTK_CONTAINER (gtk_info_bar_get_content_area - (GTK_INFO_BAR (message_area))), - hbox_content); -} - -static void -message_area_set_labels (LogviewWindow *window, - const char *primary, - const char *secondary) -{ - char *primary_markup, *secondary_markup; - - primary_markup = g_markup_printf_escaped ("%s", primary); - secondary_markup = g_markup_printf_escaped ("%s", - secondary); - - gtk_label_set_markup (GTK_LABEL (window->priv->message_primary), - primary_markup); - gtk_label_set_markup (GTK_LABEL (window->priv->message_secondary), - secondary_markup); - - g_free (primary_markup); - g_free (secondary_markup); -} - -static void -message_area_response_cb (GtkInfoBar *message_area, - int response_id, gpointer user_data) -{ - gtk_widget_hide (GTK_WIDGET (message_area)); - - g_signal_handlers_disconnect_by_func (message_area, - message_area_response_cb, - user_data); -} - -static void -logview_window_finalize (GObject *object) -{ - LogviewWindow *logview = LOGVIEW_WINDOW (object); - - if (logview->priv->read_cancellable != NULL) { - g_cancellable_cancel (logview->priv->read_cancellable); - g_clear_object (&logview->priv->read_cancellable); - } - - g_object_unref (logview->priv->ui_manager); - G_OBJECT_CLASS (logview_window_parent_class)->finalize (object); -} - -static void -logview_window_init (LogviewWindow *logview) -{ - GtkActionGroup *action_group; - GtkAccelGroup *accel_group; - GError *error = NULL; - GtkWidget *hpaned, *main_view, *vbox, *w; - PangoContext *context; - PangoFontDescription *fontdesc; - gchar *monospace_font_name; - LogviewWindowPrivate *priv; - int width, height; - gboolean res; - - priv = logview->priv = GET_PRIVATE (logview); - priv->prefs = logview_prefs_get (); - priv->manager = logview_manager_get (); - priv->monitor_id = 0; - - logview_prefs_get_stored_window_size (priv->prefs, &width, &height); - gtk_window_set_default_size (GTK_WINDOW (logview), width, height); - - vbox = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (logview), vbox); - - /* create menus */ - action_group = gtk_action_group_new ("LogviewMenuActions"); - gtk_action_group_set_translation_domain (action_group, NULL); - gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), logview); - gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), logview); - priv->action_group = action_group; - - priv->ui_manager = gtk_ui_manager_new (); - - gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, 0); - accel_group = gtk_ui_manager_get_accel_group (priv->ui_manager); - gtk_window_add_accel_group (GTK_WINDOW (logview), accel_group); - - res = gtk_ui_manager_add_ui_from_file (priv->ui_manager, - LOGVIEW_DATADIR "/logview-toolbar.xml", - &error); - - if (res == FALSE) { - priv->ui_manager = NULL; - g_critical ("Can't load the UI description: %s", error->message); - g_error_free (error); - return; - } - - gtk_ui_manager_set_add_tearoffs (priv->ui_manager, - logview_prefs_get_have_tearoff (priv->prefs)); - - w = gtk_ui_manager_get_widget (priv->ui_manager, "/LogviewMenu"); - gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); - gtk_widget_show (w); - - /* panes */ -#if GTK_CHECK_VERSION (3, 0, 0) - hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); -#else - hpaned = gtk_hpaned_new (); -#endif - gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0); - priv->hpaned = hpaned; - gtk_widget_show (hpaned); - - /* first pane : sidebar (list of logs) */ - priv->sidebar = gtk_vbox_new (FALSE, 0); - gtk_widget_show (priv->sidebar); - - /* first pane: log list */ - w = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), - GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), - GTK_SHADOW_ETCHED_IN); - - priv->loglist = logview_loglist_new (); - gtk_container_add (GTK_CONTAINER (w), priv->loglist); - gtk_box_pack_start (GTK_BOX (priv->sidebar), w, TRUE, TRUE, 0); - gtk_paned_pack1 (GTK_PANED (hpaned), priv->sidebar, FALSE, FALSE); - gtk_widget_show (w); - gtk_widget_show (priv->loglist); - - g_signal_connect (priv->loglist, "day_selected", - G_CALLBACK (loglist_day_selected_cb), logview); - g_signal_connect (priv->loglist, "day_cleared", - G_CALLBACK (loglist_day_cleared_cb), logview); - - /* second pane: log */ - main_view = gtk_vbox_new (FALSE, 0); - gtk_paned_pack2 (GTK_PANED (hpaned), main_view, TRUE, TRUE); - - /* second pane: error message area */ - priv->message_area = gtk_info_bar_new (); - message_area_create_error_box (logview, priv->message_area); - gtk_info_bar_add_button (GTK_INFO_BAR (priv->message_area), - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); - gtk_box_pack_start (GTK_BOX (main_view), priv->message_area, FALSE, FALSE, 0); - - /* second pane: text view */ - w = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_IN); - gtk_box_pack_start (GTK_BOX (main_view), w, TRUE, TRUE, 0); - gtk_widget_show (w); - - priv->tag_table = gtk_text_tag_table_new (); - populate_tag_table (priv->tag_table); - priv->text_view = gtk_text_view_new (); - g_object_set (priv->text_view, "editable", FALSE, NULL); - - gtk_container_add (GTK_CONTAINER (w), priv->text_view); - gtk_widget_show (priv->text_view); - - /* use the desktop monospace font */ - monospace_font_name = logview_prefs_get_monospace_font_name (priv->prefs); - logview_set_font (logview, monospace_font_name); - g_free (monospace_font_name); - - /* remember the original font size */ - context = gtk_widget_get_pango_context (priv->text_view); - fontdesc = pango_context_get_font_description (context); - priv->original_fontsize = pango_font_description_get_size (fontdesc) / PANGO_SCALE; - - /* restore saved zoom */ - priv->fontsize = logview_prefs_get_stored_fontsize (priv->prefs); - - if (priv->fontsize <= 0) { - /* restore the default */ - logview_normal_text (NULL, logview); - } else { - logview_set_fontsize (logview, FALSE); - } - - /* version selector */ - priv->version_bar = gtk_hbox_new (FALSE, 0); - gtk_container_set_border_width (GTK_CONTAINER (priv->version_bar), 3); - priv->version_selector = gtk_combo_box_text_new (); - g_signal_connect (priv->version_selector, "changed", - G_CALLBACK (logview_version_selector_changed), logview); - w = gtk_label_new (_("Version: ")); - - gtk_box_pack_end (GTK_BOX (priv->version_bar), priv->version_selector, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->version_bar), w, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (main_view), priv->version_bar, FALSE, FALSE, 0); - - priv->find_bar = logview_findbar_new (); - gtk_box_pack_end (GTK_BOX (main_view), priv->find_bar, FALSE, FALSE, 0); - - g_signal_connect (priv->find_bar, "previous", - G_CALLBACK (findbar_previous_cb), logview); - g_signal_connect (priv->find_bar, "next", - G_CALLBACK (findbar_next_cb), logview); - g_signal_connect (priv->find_bar, "text_changed", - G_CALLBACK (findbar_text_changed_cb), logview); - g_signal_connect (priv->find_bar, "close", - G_CALLBACK (findbar_close_cb), logview); - - /* signal handlers - * - first is used to remember/restore the window size on quit. - */ - g_signal_connect (logview, "configure_event", - G_CALLBACK (window_size_changed_cb), logview); - g_signal_connect (priv->prefs, "system-font-changed", - G_CALLBACK (font_changed_cb), logview); - g_signal_connect (priv->prefs, "have-tearoff-changed", - G_CALLBACK (tearoff_changed_cb), logview); - g_signal_connect (priv->manager, "active-changed", - G_CALLBACK (active_log_changed_cb), logview); - g_signal_connect (logview, "style-set", - G_CALLBACK (style_set_cb), logview); - g_signal_connect (logview, "key-press-event", - G_CALLBACK (key_press_event_cb), logview); - - /* status area at bottom */ - priv->statusbar = gtk_statusbar_new (); -#if GTK_CHECK_VERSION (3, 0, 0) - gtk_widget_set_margin_top (GTK_WIDGET (logview->priv->statusbar), 0); - gtk_widget_set_margin_bottom (GTK_WIDGET (logview->priv->statusbar), 0); -#endif - 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); -} - -static void -logview_window_class_init (LogviewWindowClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - - object_class->finalize = logview_window_finalize; - - g_type_class_add_private (klass, sizeof (LogviewWindowPrivate)); -} - -/* public methods */ - -GtkWidget * -logview_window_new () -{ - LogviewWindow *logview; - - logview = g_object_new (LOGVIEW_TYPE_WINDOW, NULL); - - if (logview->priv->ui_manager == NULL) { - return NULL; - } - - return GTK_WIDGET (logview); -} - -void -logview_window_add_error (LogviewWindow *window, - const char *primary, - const char *secondary) -{ - LogviewWindowPrivate *priv; - - g_assert (LOGVIEW_IS_WINDOW (window)); - priv = window->priv; - - message_area_set_labels (window, - primary, secondary); - - gtk_widget_show (priv->message_area); - - g_signal_connect (priv->message_area, "response", - G_CALLBACK (message_area_response_cb), window); -} - -void -logview_window_add_errors (LogviewWindow *window, - GPtrArray *errors) -{ - char *primary, *secondary; - GString *str; - char **err; - int i; - - g_assert (LOGVIEW_IS_WINDOW (window)); - g_assert (errors->len > 1); - - primary = g_strdup (_("Could not open the following files:")); - str = g_string_new (NULL); - - for (i = 0; i < errors->len; i++) { - err = (char **) g_ptr_array_index (errors, i); - g_string_append (str, err[0]); - g_string_append (str, ": "); - g_string_append (str, err[1]); - g_string_append (str, "\n"); - } - - secondary = g_string_free (str, FALSE); - - message_area_set_labels (window, primary, secondary); - - gtk_widget_show (window->priv->message_area); - - g_signal_connect (window->priv->message_area, "response", - G_CALLBACK (message_area_response_cb), window); - - g_free (primary); - g_free (secondary); -} - - diff --git a/logview/logview-window.h b/logview/logview-window.h deleted file mode 100644 index f9fd5303..00000000 --- a/logview/logview-window.h +++ /dev/null @@ -1,56 +0,0 @@ -/* logview-window.h - main window of logview - * - * Copyright (C) 1998 Cesar Miquel - * Copyright (C) 2008 Cosimo Cecchi - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __LOGVIEW_WINDOW_H__ -#define __LOGVIEW_WINDOW_H__ - -#include - -#define LOGVIEW_TYPE_WINDOW (logview_window_get_type ()) -#define LOGVIEW_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_WINDOW, LogviewWindow)) -#define LOGVIEW_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_WINDOW, LogviewWindowClass)) -#define LOGVIEW_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_WINDOW)) -#define LOGVIEW_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), LOGVIEW_TYPE_WINDOW)) -#define LOGVIEW_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_WINDOW, LogviewWindowClass)) - -typedef struct _LogviewWindow LogviewWindow; -typedef struct _LogviewWindowClass LogviewWindowClass; -typedef struct _LogviewWindowPrivate LogviewWindowPrivate; - -struct _LogviewWindow { - GtkWindow parent_instance; - LogviewWindowPrivate *priv; -}; - -struct _LogviewWindowClass { - GtkWindowClass parent_class; -}; - -GType logview_window_get_type (void); - -/* public methods */ -GtkWidget * logview_window_new (void); -void logview_window_add_error (LogviewWindow *window, - const char *primary, - const char *secondary); -void logview_window_add_errors (LogviewWindow *window, - GPtrArray *errors); - -#endif /* __LOGVIEW_WINDOW_H__ */ diff --git a/logview/src/Makefile.am b/logview/src/Makefile.am new file mode 100644 index 00000000..70cbee21 --- /dev/null +++ b/logview/src/Makefile.am @@ -0,0 +1,73 @@ +SUBDIRS = tests + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"mate-system-log\" \ + -DMATELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ + -DDATADIR=\""$(datadir)"\" \ + -DLOGVIEWINSTALLPREFIX=\""$(prefix)/\"" \ + -DLOGVIEW_DATADIR=\""$(pkgdatadir)"\" \ + $(SUN_OS) \ + $(DISABLE_DEPRECATED) \ + $(NULL) + +bin_PROGRAMS = mate-system-log + +BUILT_SOURCES = \ + logview-marshal.c \ + logview-marshal.h + +mate_system_log_SOURCES = \ + logview-app.c \ + logview-app.h \ + logview-main.c \ + logview-about.h \ + logview-manager.c \ + logview-manager.h \ + logview-utils.c \ + logview-utils.h \ + logview-loglist.c \ + logview-loglist.h \ + logview-window.c \ + logview-window.h \ + logview-log.h \ + logview-log.c \ + logview-findbar.h \ + 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) + +mate_system_log_CFLAGS = \ + $(GLIB_CFLAGS) \ + $(GTHREAD_CFLAGS) \ + $(GIO_CFLAGS) \ + $(GTK_CFLAGS) \ + $(NULL) + +mate_system_log_LDADD = \ + $(GLIB_LIBS) \ + $(GIO_LIBS) \ + $(GTHREAD_LIBS) \ + $(GTK_LIBS) \ + $(Z_LIBS) \ + -lm + +logview-marshal.h: logview-marshal.list $(GLIB_GENMARSHAL) + $(GLIB_GENMARSHAL) $< --header --prefix=logview_marshal >> $@ + +logview-marshal.c: logview-marshal.list $(GLIB_GENMARSHAL) + echo "#include \"logview-marshal.h\"" > $@ && \ + $(GLIB_GENMARSHAL) $< --body --prefix=logview_marshal >> $@ + +EXTRA_DIST = logview-marshal.list + +CLEANFILES = \ + $(BUILT_SOURCES) + +dist-hook: + cd $(distdir) ; rm -f $(CLEANFILES) + diff --git a/logview/src/logview-about.h b/logview/src/logview-about.h new file mode 100644 index 00000000..9b4b0949 --- /dev/null +++ b/logview/src/logview-about.h @@ -0,0 +1,67 @@ +/* logview-about.h - authors and contributors information + * + * Copyright (C) 2004 Vincent Noel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#ifndef __LOGVIEW_ABOUT_H__ +#define __LOGVIEW_ABOUT_H__ + +static const char *logview_about_authors[] = { + "Cesar Miquel ", + "Glynn Foster ", + "Fernando Herrera ", + "Shakti Sen ", + "Julio M Merino Vidal ", + "Jason Leach ", + "Christian Neumair ", + "Jan Arne Petersen ", + "Jason Long ", + "Kjartan Maraas ", + "Vincent Noel ", + "Cosimo Cecchi ", + NULL +}; + +static const char *logview_about_documenters[] = { + "Sun GNOME Documentation Team ", + "Vincent Noel ", + "Judith Samson ", + NULL +}; + +static const char * logview_about_license[] = { + N_("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 2 of the License, or " + "(at your option) any later version."), + N_("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."), + N_("You should have received a copy of the GNU General Public License " + "along with this program; if not, write to the Free Software Foundation, Inc., " + "51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA") +}; + +/* translator credits */ +static const char *logview_about_translator_credits = N_("translator-credits"); + + +#endif /* __LOGVIEW_ABOUT_H__ */ + diff --git a/logview/src/logview-app.c b/logview/src/logview-app.c new file mode 100644 index 00000000..ffa37ec7 --- /dev/null +++ b/logview/src/logview-app.c @@ -0,0 +1,420 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-app.c - logview application singleton + * + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* logview-app.c */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "logview-app.h" + +#include "logview-manager.h" +#include "logview-window.h" +#include "logview-prefs.h" + +#include + +struct _LogviewAppPrivate { + LogviewPrefs *prefs; + LogviewManager *manager; + LogviewWindow *window; +}; + +enum { + APP_QUIT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static LogviewApp *app_singleton = NULL; + +G_DEFINE_TYPE (LogviewApp, logview_app, G_TYPE_OBJECT); + +#define GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_APP, LogviewAppPrivate)) + +static gboolean +main_window_delete_cb (GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + LogviewApp *app = user_data; + + g_signal_emit (app, signals[APP_QUIT], 0, NULL); + + return FALSE; +} + +static gboolean +logview_app_set_window (LogviewApp *app) +{ + LogviewWindow *window; + gboolean retval = FALSE; + + window = LOGVIEW_WINDOW (logview_window_new ()); + + if (window) { + app->priv->window = window; + g_signal_connect (window, "delete-event", + G_CALLBACK (main_window_delete_cb), app); + retval = TRUE; + } + + gtk_window_set_default_icon_name ("mate-system-log"); + + return retval; +} + +typedef struct { + LogviewApp *app; + GSList *logs; +} EnumerateJob; + +/* TODO: ideally we should parse configuration files in /etc/logrotate.conf + * and all the files in /etc/logrotate.d/ and group all the logs referring + * to the same entry under a category. Right now, we just do some + * parsing instead, and fill with quasi-sensible defaults. + */ + +/* adapted from sysklogd sources */ +static GSList* +parse_syslog () +{ + char cbuf[BUFSIZ]; + char *cline, *p; + FILE *cf; + GSList *logfiles = NULL; + + if ((cf = fopen ("/etc/syslog.conf", "r")) == NULL) { + return NULL; + } + + cline = cbuf; + while (fgets (cline, sizeof (cbuf) - (cline - cbuf), cf) != NULL) { + gchar **list; + gint i; + + for (p = cline; g_ascii_isspace (*p); ++p); + if (*p == '\0' || *p == '#' || *p == '\n') + continue; + + list = g_strsplit_set (p, ", -\t()\n", 0); + + for (i = 0; list[i]; ++i) { + if (*list[i] == '/' && + g_slist_find_custom (logfiles, list[i], + (GCompareFunc) g_ascii_strcasecmp) == NULL) + { + logfiles = g_slist_insert (logfiles, + g_strdup (list[i]), 0); + } + } + + g_strfreev (list); + } + + fclose (cf); + + return logfiles; +} + +static void +enumerate_job_finish (EnumerateJob *job) +{ + GSList *files = job->logs; + LogviewApp *app = job->app; + + logview_manager_add_logs_from_name_list (app->priv->manager, files, files->data); + + g_slist_foreach (files, (GFunc) g_free, NULL); + g_slist_free (files); + + g_object_unref (job->app); + g_slice_free (EnumerateJob, job); +} + +static void +enumerate_next_files_async_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + EnumerateJob *job = user_data; + GList *enumerated_files, *l; + GFileInfo *info; + GSList *logs; + const char *content_type, *name; + char *parse_string, *container_path; + GFileType type; + GFile *container; + + enumerated_files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source), + res, NULL); + if (!enumerated_files) { + enumerate_job_finish (job); + return; + } + + logs = job->logs; + container = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source)); + container_path = g_file_get_path (container); + + /* TODO: we don't support grouping rotated logs yet, skip gzipped files + * and those which name contains a formatted date. + */ + for (l = enumerated_files; l; l = l->next) { + info = l->data; + type = g_file_info_get_file_type (info); + content_type = g_file_info_get_content_type (info); + name = g_file_info_get_name (info); + + if (!g_file_info_get_attribute_boolean (info, "access::can-read")) { + g_object_unref (info); + continue; + } + + if (type != (G_FILE_TYPE_REGULAR || G_FILE_TYPE_SYMBOLIC_LINK) || + !g_content_type_is_a (content_type, "text/plain")) + { + g_object_unref (info); + continue; + } + + if (g_content_type_is_a (content_type, "application/x-gzip")) { + g_object_unref (info); + continue; + } + + if (g_regex_match_simple ("\\d{8}$", name, 0, 0)) { + g_object_unref (info); + continue; + } + + parse_string = g_build_filename (container_path, name, NULL); + + if (g_slist_find_custom (logs, parse_string, (GCompareFunc) g_ascii_strcasecmp) == NULL) { + logs = g_slist_append (logs, parse_string); + } else { + g_free (parse_string); + } + + g_object_unref (info); + parse_string = NULL; + } + + g_list_free (enumerated_files); + g_object_unref (container); + g_free (container_path); + + job->logs = logs; + + enumerate_job_finish (job); +} + +static void +enumerate_children_async_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + EnumerateJob *job = user_data; + GFileEnumerator *enumerator; + + enumerator = g_file_enumerate_children_finish (G_FILE (source), + res, NULL); + if (!enumerator) { + enumerate_job_finish (job); + return; + } + + g_file_enumerator_next_files_async (enumerator, G_MAXINT, + G_PRIORITY_DEFAULT, + NULL, enumerate_next_files_async_cb, job); +} + +static void +logview_app_first_time_initialize (LogviewApp *app) +{ + GSList *logs; + GFile *log_dir; + EnumerateJob *job; + + /* let's add all accessible files in /var/log and those mentioned + * in /etc/syslog.conf. + */ + + logs = parse_syslog (); + + job = g_slice_new0 (EnumerateJob); + job->app = g_object_ref (app); + job->logs = logs; + + log_dir = g_file_new_for_path ("/var/log/"); + g_file_enumerate_children_async (log_dir, + "standard::*,access::can-read", 0, + G_PRIORITY_DEFAULT, NULL, + enumerate_children_async_cb, job); + + g_object_unref (log_dir); +} + +static void +do_finalize (GObject *obj) +{ + LogviewApp *app = LOGVIEW_APP (obj); + + g_object_unref (app->priv->manager); + g_object_unref (app->priv->prefs); + + G_OBJECT_CLASS (logview_app_parent_class)->finalize (obj); +} + +static void +logview_app_class_init (LogviewAppClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->finalize = do_finalize; + + signals[APP_QUIT] = + g_signal_new ("app-quit", + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewAppClass, app_quit), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private (klass, sizeof (LogviewAppPrivate)); +} + +static void +logview_app_init (LogviewApp *self) +{ + LogviewAppPrivate *priv = self->priv = GET_PRIVATE (self); + + priv->prefs = logview_prefs_get (); + priv->manager = logview_manager_get (); +} + +LogviewApp* +logview_app_get (void) +{ + if (!app_singleton) { + app_singleton = g_object_new (LOGVIEW_TYPE_APP, NULL); + + if (!logview_app_set_window (app_singleton)) { + g_object_unref (app_singleton); + app_singleton = NULL; + } + } + + return app_singleton; +} + +void +logview_app_initialize (LogviewApp *app, char **log_files) +{ + LogviewAppPrivate *priv; + + g_assert (LOGVIEW_IS_APP (app)); + + priv = app->priv; + + /* open regular logs and add each log passed as a parameter */ + + if (log_files == NULL) { + char *active_log; + gchar **logs; + + active_log = logview_prefs_get_active_logfile (priv->prefs); + logs = logview_prefs_get_stored_logfiles (priv->prefs); + + if (!logs || !logs[0]) { + logview_app_first_time_initialize (app); + } else { + logview_manager_add_logs_from_names (priv->manager, + logs, active_log); + + g_free (active_log); + g_strfreev (logs); + } + } else { + logview_manager_add_logs_from_names (priv->manager, log_files, NULL); + } + + gtk_widget_show (GTK_WIDGET (priv->window)); +} + +void +logview_app_add_error (LogviewApp *app, + const char *file_path, + const char *secondary) +{ + LogviewWindow *window; + char *primary; + + g_assert (LOGVIEW_IS_APP (app)); + + window = app->priv->window; + primary = g_strdup_printf (_("Impossible to open the file %s"), file_path); + + logview_window_add_error (window, primary, secondary); + + g_free (primary); +} + +static void +check_error_prefs (gpointer data, + gpointer user_data) +{ + gchar **strings = data; + LogviewApp *app = user_data; + GFile *file = g_file_new_for_path (strings[0]); + + logview_prefs_remove_stored_log (app->priv->prefs, file); + g_object_unref (file); +} + +void +logview_app_add_errors (LogviewApp *app, + GPtrArray *errors) +{ + LogviewWindow *window; + + g_assert (LOGVIEW_IS_APP (app)); + + window = app->priv->window; + + if (errors->len == 0) { + return; + } + + g_ptr_array_foreach (errors, check_error_prefs, app); + + if (errors->len == 1) { + char **err; + + err = g_ptr_array_index (errors, 0); + logview_window_add_error (window, err[0], err[1]); + } else { + logview_window_add_errors (window, errors); + } +} diff --git a/logview/src/logview-app.h b/logview/src/logview-app.h new file mode 100644 index 00000000..3ce7c059 --- /dev/null +++ b/logview/src/logview-app.h @@ -0,0 +1,71 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-app.h - logview application singleton + * + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __LOGVIEW_APP_H__ +#define __LOGVIEW_APP_H__ + +#include + +G_BEGIN_DECLS + +#define LOGVIEW_TYPE_APP logview_app_get_type() +#define LOGVIEW_APP(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_APP, LogviewApp)) +#define LOGVIEW_APP_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_APP, LogviewAppClass)) +#define LOGVIEW_IS_APP(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_APP)) +#define LOGVIEW_IS_APP_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_APP)) +#define LOGVIEW_APP_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_APP, LogviewAppClass)) + +typedef struct _LogviewApp LogviewApp; +typedef struct _LogviewAppClass LogviewAppClass; +typedef struct _LogviewAppPrivate LogviewAppPrivate; + +struct _LogviewApp { + GObject parent; + + LogviewAppPrivate *priv; +}; + +struct _LogviewAppClass { + GObjectClass parent_class; + + void (* app_quit) (LogviewApp *app); +}; + + +GType logview_app_get_type (void); + +/* public methods */ +LogviewApp * logview_app_get (void); +void logview_app_initialize (LogviewApp *app, + char **log_files); +void logview_app_add_error (LogviewApp *app, + const char *file_path, + const char *secondary); +void logview_app_add_errors (LogviewApp *app, + GPtrArray *errors); + +G_END_DECLS + +#endif /* __LOGVIEW_APP_H__ */ diff --git a/logview/src/logview-filter-manager.c b/logview/src/logview-filter-manager.c new file mode 100644 index 00000000..0905306f --- /dev/null +++ b/logview/src/logview-filter-manager.c @@ -0,0 +1,575 @@ +/*-*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* + * mate-utils + * Copyright (C) Johannes Schmid 2009 + * + * mate-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. + * + * mate-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 . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "logview-filter-manager.h" +#include "logview-prefs.h" +#include +#include +#include + +#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; + + LogviewPrefs* prefs; +}; + +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; + gchar *name; + GtkTreeIter iter; + + gtk_list_store_clear (GTK_LIST_STORE (manager->priv->model)); + + filters = logview_prefs_get_filters (manager->priv->prefs); + + for (filter = filters; filter != NULL; filter = g_list_next (filter)) { + 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) +{ + GtkWidget *dialog; + + if (!strlen (name)) { + 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; + } + + if (strstr (name, ":") != NULL) { + 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) +{ + GtkWidget *dialog; + GError *error = NULL; + GRegex *reg; + + if (!strlen (regex)) { + 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; + } + + reg = g_regex_new (regex, + 0, 0, &error); + if (error) { + 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) +{ + gtk_widget_set_sensitive (widget, + gtk_toggle_button_get_active (button)); +} + +static void +on_dialog_add_edit_reponse (GtkWidget *dialog, int response_id, + LogviewFilterManager *manager) +{ + GtkWidget *entry_name, *entry_regex; + GtkWidget *radio_color, *radio_visible; + GtkWidget *check_foreground, *check_background; + GtkWidget *color_foreground, *color_background; + gchar *old_name; + const gchar *name; + const gchar *regex; + LogviewFilter *filter; + GtkTextTag *tag; + GtkBuilder *builder; + + old_name = g_object_get_data (G_OBJECT (manager), "old_name"); + 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) { + 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; + } + + 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 *error_dialog; + + error_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 (error_dialog)); + gtk_widget_destroy (error_dialog); + g_object_unref (tag); + g_object_unref (filter); + + return; + } + } else { /* !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_color)) */ + g_object_set (tag, "invisible", TRUE, NULL); + } + + if (old_name && !g_str_equal (old_name, name)) { + logview_prefs_remove_filter (manager->priv->prefs, old_name); + } + + g_object_set (G_OBJECT (filter), "texttag", tag, NULL); + g_object_unref (tag); + + logview_prefs_add_filter (manager->priv->prefs, filter); + g_object_unref (filter); + + logview_filter_manager_update_model (manager); + } + + gtk_widget_destroy (dialog); +} + +static void +run_add_edit_dialog (LogviewFilterManager *manager, LogviewFilter *filter) +{ + GError *error; + gchar *name, *regex; + const gchar *title; + GtkWidget *dialog, *entry_name, *entry_regex, *radio_color; + GtkWidget *radio_visible, *check_foreground, *check_background; + GtkWidget *color_foreground, *color_background, *vbox_color; + gboolean foreground_set, background_set, invisible; + GtkTextTag *tag; + GtkBuilder* builder; + + builder = manager->priv->builder; + + error = NULL; + name = NULL; + + gtk_builder_add_from_file (builder, UI_FILE, &error); + + if (error) { + g_warning ("Could not load filter ui: %s", error->message); + g_error_free (error); + return; + } + + title = (filter != NULL ? _("Edit filter") : _("Add new filter")); + + dialog = GTK_WIDGET (gtk_builder_get_object (builder, + "dialog_filter")); + + gtk_window_set_title (GTK_WINDOW (dialog), title); + + 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) { + g_object_get (filter, + "name", &name, + "regex", ®ex, + "texttag", &tag, + NULL); + g_object_get (tag, + "foreground-set", &foreground_set, + "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) { + GdkColor *foreground; + + g_object_get (tag, "foreground-gdk", &foreground, NULL); + 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) { + GdkColor *background; + + g_object_get (tag, "paragraph-background-gdk", &background, NULL); + 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_full (G_OBJECT (manager), "old_name", name, g_free); + + 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_window_set_modal (GTK_WINDOW (dialog), + TRUE); + + gtk_widget_show (GTK_WIDGET (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 (manager->priv->prefs, 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 (); + g_object_ref (priv->builder); + priv->prefs = logview_prefs_get (); + + gtk_dialog_add_button (GTK_DIALOG(manager), + GTK_STOCK_CLOSE, + GTK_RESPONSE_CLOSE); + gtk_window_set_modal (GTK_WINDOW (manager), + TRUE); + + 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_response (GtkDialog* dialog, gint response_id) +{ + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +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; + parent_class->response = logview_filter_manager_response; +} + +GtkWidget * +logview_filter_manager_new (void) +{ + return g_object_new (LOGVIEW_TYPE_FILTER_MANAGER, NULL); +} diff --git a/logview/src/logview-filter-manager.h b/logview/src/logview-filter-manager.h new file mode 100644 index 00000000..c33ea1f7 --- /dev/null +++ b/logview/src/logview-filter-manager.h @@ -0,0 +1,54 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* + * mate-utils + * Copyright (C) Johannes Schmid 2009 + * + * mate-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. + * + * mate-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 . + */ + +#ifndef _LOGVIEW_FILTER_MANAGER_H_ +#define _LOGVIEW_FILTER_MANAGER_H_ + +#include +#include + +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_ */ diff --git a/logview/src/logview-filter.c b/logview/src/logview-filter.c new file mode 100644 index 00000000..b5f9cfc6 --- /dev/null +++ b/logview/src/logview-filter.c @@ -0,0 +1,200 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* + * mate-utils + * Copyright (C) Johannes Schmid 2009 + * + * mate-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. + * + * mate-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 . + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#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_free (priv->name); + + 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) +{ + 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; + const gchar* regex; + + err = NULL; + + 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; + g_warning ("Couldn't create GRegex object: %s", err->message); + g_error_free (err); + } + + 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) +{ + 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); + + 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)); +} + +/* public methods */ + +LogviewFilter* +logview_filter_new (const gchar *name, const gchar *regex) +{ + return g_object_new (LOGVIEW_TYPE_FILTER, + "name", name, + "regex", regex, + NULL); +} + +gboolean +logview_filter_filter (LogviewFilter *filter, const gchar *line) +{ + GMatchInfo* match_info; + LogviewFilterPrivate* priv; + gboolean retval; + + g_return_val_if_fail (LOGVIEW_IS_FILTER (filter), FALSE); + g_return_val_if_fail (line != NULL, FALSE); + + 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; +} diff --git a/logview/src/logview-filter.h b/logview/src/logview-filter.h new file mode 100644 index 00000000..6eb827b8 --- /dev/null +++ b/logview/src/logview-filter.h @@ -0,0 +1,59 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* + * mate-utils + * Copyright (C) Johannes Schmid 2009 + * + * mate-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. + * + * mate-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 . + */ + +#ifndef _LOGVIEW_FILTER_H_ +#define _LOGVIEW_FILTER_H_ + +#include +#include +#include + +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_ */ diff --git a/logview/src/logview-findbar.c b/logview/src/logview-findbar.c new file mode 100644 index 00000000..3cb53f1d --- /dev/null +++ b/logview/src/logview-findbar.c @@ -0,0 +1,352 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-findbar.c - find toolbar for logview + * + * Copyright (C) 2005 Vincent Noel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "logview-findbar.h" + +struct _LogviewFindbarPrivate { + GtkWidget *entry; + GtkWidget *message; + + GtkToolItem *clear_button; + GtkToolItem *back_button; + GtkToolItem *forward_button; + GtkToolItem *status_item; + GtkToolItem *separator; + + char *string; + + guint status_bold_id; +}; + +enum { + PREVIOUS, + NEXT, + CLOSE, + TEXT_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (LogviewFindbar, logview_findbar, GTK_TYPE_TOOLBAR); + +#define GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_FINDBAR, LogviewFindbarPrivate)) + +static void +back_button_clicked_cb (GtkToolButton *button, + gpointer user_data) +{ + LogviewFindbar *findbar = user_data; + + g_signal_emit (findbar, signals[PREVIOUS], 0); +} + +static void +forward_button_clicked_cb (GtkToolButton *button, + gpointer user_data) +{ + LogviewFindbar *findbar = user_data; + + g_signal_emit (findbar, signals[NEXT], 0); +} + +static void +clear_button_clicked_cb (GtkToolButton *button, + gpointer user_data) +{ + LogviewFindbar *findbar = user_data; + + logview_findbar_set_message (findbar, NULL); + gtk_entry_set_text (GTK_ENTRY (findbar->priv->entry), ""); +} + +static void +entry_activate_cb (GtkWidget *entry, + gpointer user_data) +{ + LogviewFindbar *findbar = user_data; + + g_signal_emit (findbar, signals[NEXT], 0); +} + +static void +entry_changed_cb (GtkEditable *editable, + gpointer user_data) +{ + LogviewFindbar *findbar = user_data; + const char *text; + + text = gtk_entry_get_text (GTK_ENTRY (editable)); + + if (g_strcmp0 (text, "") == 0) { + return; + } + + if (g_strcmp0 (findbar->priv->string, text) != 0) { + g_free (findbar->priv->string); + findbar->priv->string = g_strdup (text); + + g_signal_emit (findbar, signals[TEXT_CHANGED], 0); + } +} + +static gboolean +entry_key_press_event_cb (GtkWidget *entry, + GdkEventKey *event, + gpointer user_data) +{ + LogviewFindbar *findbar = user_data; + + if (event->keyval == GDK_KEY_Escape) { + g_signal_emit (findbar, signals[CLOSE], 0); + return TRUE; + } + + return FALSE; +} + +static gboolean +unbold_timeout_cb (gpointer user_data) +{ + LogviewFindbar *findbar = user_data; + PangoFontDescription *desc; + + desc = pango_font_description_new (); + gtk_widget_modify_font (findbar->priv->message, desc); + pango_font_description_free (desc); + + findbar->priv->status_bold_id = 0; + + return FALSE; +} + +static void +logview_findbar_init (LogviewFindbar *findbar) +{ + GtkWidget *label, *w, *box; + GtkToolbar *gtoolbar; + GtkToolItem *item; + LogviewFindbarPrivate *priv; + + priv = findbar->priv = GET_PRIVATE (findbar); + + gtoolbar = GTK_TOOLBAR (findbar); + + gtk_toolbar_set_style (gtoolbar, GTK_TOOLBAR_BOTH_HORIZ); + + priv->status_bold_id = 0; + + /* Find: |_______| */ + w = gtk_alignment_new (0.0, 0.5, 1.0, 1.0); + gtk_alignment_set_padding (GTK_ALIGNMENT (w), 0, 0, 2, 2); + + box = gtk_hbox_new (FALSE, 12); + gtk_container_add (GTK_CONTAINER (w), box); + + label = gtk_label_new_with_mnemonic (_("_Find:")); + gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0); + + priv->entry = gtk_entry_new (); + gtk_entry_set_width_chars (GTK_ENTRY (priv->entry), 32); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->entry); + gtk_box_pack_start (GTK_BOX (box), priv->entry, TRUE, TRUE, 0); + + item = gtk_tool_item_new (); + gtk_container_add (GTK_CONTAINER (item), w); + gtk_toolbar_insert (gtoolbar, item, -1); + gtk_widget_show_all (GTK_WIDGET (item)); + + /* "Previous" and "Next" buttons */ + w = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_NONE); + priv->back_button = gtk_tool_button_new (w, _("Find Previous")); + gtk_tool_item_set_is_important (priv->back_button, TRUE); + gtk_tool_item_set_tooltip_text (priv->back_button, + _("Find previous occurrence of the search string")); + gtk_toolbar_insert (gtoolbar, priv->back_button, -1); + gtk_widget_show_all (GTK_WIDGET (priv->back_button)); + + w = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE); + priv->forward_button = gtk_tool_button_new (w, _("Find Next")); + gtk_tool_item_set_is_important (priv->forward_button, TRUE); + gtk_tool_item_set_tooltip_text (priv->forward_button, + _("Find next occurrence of the search string")); + gtk_toolbar_insert (gtoolbar, priv->forward_button, -1); + gtk_widget_show_all (GTK_WIDGET (priv->forward_button)); + + /* clear button */ + priv->clear_button = gtk_tool_button_new_from_stock (GTK_STOCK_CLEAR); + gtk_tool_item_set_tooltip_text (priv->clear_button, + _("Clear the search string")); + gtk_toolbar_insert (gtoolbar, priv->clear_button, -1); + gtk_widget_show_all (GTK_WIDGET (priv->clear_button)); + + /* separator */ + priv->separator = gtk_separator_tool_item_new (); + gtk_toolbar_insert (gtoolbar, priv->separator, -1); + + /* message */ + priv->status_item = gtk_tool_item_new (); + gtk_tool_item_set_expand (priv->status_item, TRUE); + priv->message = gtk_label_new (""); + gtk_label_set_use_markup (GTK_LABEL (priv->message), TRUE); + gtk_misc_set_alignment (GTK_MISC (priv->message), 0.0, 0.5); + gtk_container_add (GTK_CONTAINER (priv->status_item), priv->message); + gtk_widget_show (priv->message); + gtk_toolbar_insert (gtoolbar, priv->status_item, -1); + + priv->string = NULL; + + /* signal handlers */ + g_signal_connect (priv->back_button, "clicked", + G_CALLBACK (back_button_clicked_cb), findbar); + g_signal_connect (priv->forward_button, "clicked", + G_CALLBACK (forward_button_clicked_cb), findbar); + g_signal_connect (priv->clear_button, "clicked", + G_CALLBACK (clear_button_clicked_cb), findbar); + g_signal_connect (priv->entry, "activate", + G_CALLBACK (entry_activate_cb), findbar); + g_signal_connect (priv->entry, "changed", + G_CALLBACK (entry_changed_cb), findbar); + g_signal_connect (priv->entry, "key-press-event", + G_CALLBACK (entry_key_press_event_cb), findbar); +} + +static void +do_grab_focus (GtkWidget *widget) +{ + LogviewFindbar *findbar = LOGVIEW_FINDBAR (widget); + + gtk_widget_grab_focus (findbar->priv->entry); +} + +static void +do_finalize (GObject *obj) +{ + LogviewFindbar *findbar = LOGVIEW_FINDBAR (obj); + + g_free (findbar->priv->string); + + G_OBJECT_CLASS (logview_findbar_parent_class)->finalize (obj); +} + +static void +logview_findbar_class_init (LogviewFindbarClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass); + + oclass->finalize = do_finalize; + + wclass->grab_focus = do_grab_focus; + + signals[PREVIOUS] = g_signal_new ("previous", + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewFindbarClass, previous), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[NEXT] = g_signal_new ("next", + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewFindbarClass, next), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[CLOSE] = g_signal_new ("close", + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewFindbarClass, close), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[TEXT_CHANGED] = g_signal_new ("text-changed", + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewFindbarClass, text_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private (klass, sizeof (LogviewFindbarPrivate)); +} + +/* public methods */ + +GtkWidget * +logview_findbar_new (void) +{ + GtkWidget *widget; + widget = g_object_new (LOGVIEW_TYPE_FINDBAR, NULL); + return widget; +} + +void +logview_findbar_open (LogviewFindbar *findbar) +{ + g_assert (LOGVIEW_IS_FINDBAR (findbar)); + + gtk_widget_show (GTK_WIDGET (findbar)); + gtk_widget_grab_focus (GTK_WIDGET (findbar)); +} + +const char * +logview_findbar_get_text (LogviewFindbar *findbar) +{ + g_assert (LOGVIEW_IS_FINDBAR (findbar)); + + return findbar->priv->string; +} + +void +logview_findbar_set_message (LogviewFindbar *findbar, + const char *text) +{ + PangoFontDescription *desc; + + g_assert (LOGVIEW_IS_FINDBAR (findbar)); + + if (text) { + desc = pango_font_description_new (); + pango_font_description_set_weight (desc, PANGO_WEIGHT_BOLD); + gtk_widget_modify_font (findbar->priv->message, desc); + pango_font_description_free (desc); + + findbar->priv->status_bold_id = g_timeout_add (600, unbold_timeout_cb, findbar); + } + + gtk_label_set_text (GTK_LABEL (findbar->priv->message), + text != NULL ? text : ""); + g_object_set (findbar->priv->separator, "visible", text != NULL, NULL); + g_object_set (findbar->priv->status_item, "visible", text != NULL, NULL); +} diff --git a/logview/src/logview-findbar.h b/logview/src/logview-findbar.h new file mode 100644 index 00000000..89c65249 --- /dev/null +++ b/logview/src/logview-findbar.h @@ -0,0 +1,72 @@ +/* logview-findbar.h - find toolbar for logview + * + * Copyright (C) 2004 Vincent Noel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __LOGVIEW_FINDBAR_H__ +#define __LOGVIEW_FINDBAR_H__ + +#include +#include + +G_BEGIN_DECLS + +#define LOGVIEW_TYPE_FINDBAR \ + (logview_findbar_get_type ()) +#define LOGVIEW_FINDBAR(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_FINDBAR, LogviewFindbar)) +#define LOGVIEW_FINDBAR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_FINDBAR, LogviewFindbarClass)) +#define LOGVIEW_IS_FINDBAR(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_FINDBAR)) +#define LOGVIEW_IS_FINDBAR_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((obj), LOGVIEW_TYPE_FINDBAR)) +#define LOGVIEW_FINDBAR_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_FINDBAR, LogviewFindbarClass)) + +typedef struct _LogviewFindbar LogviewFindbar; +typedef struct _LogviewFindbarClass LogviewFindbarClass; +typedef struct _LogviewFindbarPrivate LogviewFindbarPrivate; + +struct _LogviewFindbar { + GtkToolbar parent_instance; + LogviewFindbarPrivate *priv; +}; + +struct _LogviewFindbarClass { + GtkToolbarClass parent_class; + + /* signals */ + void (* previous) (LogviewFindbar *findbar); + void (* next) (LogviewFindbar *findbar); + void (* close) (LogviewFindbar *findbar); + void (* text_changed) (LogviewFindbar *findbar); +}; + +GType logview_findbar_get_type (void); + +/* public methods */ +GtkWidget * logview_findbar_new (void); +void logview_findbar_open (LogviewFindbar *findbar); +const char * logview_findbar_get_text (LogviewFindbar *findbar); +void logview_findbar_set_message (LogviewFindbar *findbar, + const char *message); + +G_END_DECLS + +#endif /* __LOGVIEW_FINDBAR_H__ */ diff --git a/logview/src/logview-log.c b/logview/src/logview-log.c new file mode 100644 index 00000000..407f49c3 --- /dev/null +++ b/logview/src/logview-log.c @@ -0,0 +1,936 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-log.c - object representation of a logfile + * + * Copyright (C) 1998 Cesar Miquel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +#include "config.h" + +#include +#include +#include + +#ifdef HAVE_ZLIB +#include +#endif + +#include "logview-log.h" +#include "logview-utils.h" + +G_DEFINE_TYPE (LogviewLog, logview_log, G_TYPE_OBJECT); + +#define GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_LOG, LogviewLogPrivate)) + +enum { + LOG_CHANGED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0 }; + +struct _LogviewLogPrivate { + /* file and monitor */ + GFile *file; + GFileMonitor *mon; + + /* stats about the file */ + time_t file_time; + goffset file_size; + char *display_name; + gboolean has_days; + + /* lines and relative days */ + GSList *days; + GPtrArray *lines; + guint lines_no; + + /* stream poiting to the log */ + GDataInputStream *stream; + gboolean has_new_lines; +}; + +typedef struct { + LogviewLog *log; + GError *err; + LogviewCreateCallback callback; + gpointer user_data; +} LoadJob; + +typedef struct { + LogviewLog *log; + GError *err; + const char **lines; + GSList *new_days; + GCancellable *cancellable; + LogviewNewLinesCallback callback; + gpointer user_data; +} NewLinesJob; + +typedef struct { + GInputStream *parent_str; + guchar * buffer; + GFile *file; + + gboolean last_str_result; + int last_z_result; + z_stream zstream; +} GZHandle; + +static void +do_finalize (GObject *obj) +{ + LogviewLog *log = LOGVIEW_LOG (obj); + char ** lines; + + if (log->priv->stream) { + g_object_unref (log->priv->stream); + log->priv->stream = NULL; + } + + if (log->priv->file) { + g_object_unref (log->priv->file); + log->priv->file = NULL; + } + + if (log->priv->mon) { + g_object_unref (log->priv->mon); + log->priv->mon = NULL; + } + + if (log->priv->days) { + g_slist_foreach (log->priv->days, + (GFunc) logview_utils_day_free, NULL); + g_slist_free (log->priv->days); + log->priv->days = NULL; + } + + if (log->priv->lines) { + lines = (char **) g_ptr_array_free (log->priv->lines, FALSE); + g_strfreev (lines); + log->priv->lines = NULL; + } + + G_OBJECT_CLASS (logview_log_parent_class)->finalize (obj); +} + +static void +logview_log_class_init (LogviewLogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = do_finalize; + + signals[LOG_CHANGED] = g_signal_new ("log-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewLogClass, log_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private (klass, sizeof (LogviewLogPrivate)); +} + +static void +logview_log_init (LogviewLog *self) +{ + self->priv = GET_PRIVATE (self); + + self->priv->lines = NULL; + self->priv->lines_no = 0; + self->priv->days = NULL; + self->priv->file = NULL; + self->priv->mon = NULL; + self->priv->has_new_lines = FALSE; + self->priv->has_days = FALSE; +} + +static void +monitor_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *unused, + GFileMonitorEvent event, + gpointer user_data) +{ + LogviewLog *log = user_data; + + if (event == G_FILE_MONITOR_EVENT_CHANGED) { + log->priv->has_new_lines = TRUE; + g_signal_emit (log, signals[LOG_CHANGED], 0, NULL); + } + /* TODO: handle the case where the log is deleted? */ +} + +static void +setup_file_monitor (LogviewLog *log) +{ + GError *err = NULL; + + log->priv->mon = g_file_monitor (log->priv->file, + 0, NULL, &err); + if (err) { + /* it'd be strange to get this error at this point but whatever */ + g_warning ("Impossible to monitor the log file: the changes won't be notified"); + g_error_free (err); + return; + } + + /* set the rate to 1sec, as I guess it's not unusual to have more than + * one line written consequently or in a short time, being a log file. + */ + g_file_monitor_set_rate_limit (log->priv->mon, 1000); + g_signal_connect (log->priv->mon, "changed", + G_CALLBACK (monitor_changed_cb), log); +} + +static GSList * +add_new_days_to_cache (LogviewLog *log, const char **new_lines, guint lines_offset) +{ + GSList *new_days, *l, *last_cached; + int res; + Day *day, *last; + + new_days = log_read_dates (new_lines, log->priv->file_time); + + /* the days are stored in chronological order, so we compare the last cached + * one with the new we got. + */ + last_cached = g_slist_last (log->priv->days); + + if (!last_cached) { + /* this means the day list is empty (i.e. we're on the first read */ + log->priv->days = logview_utils_day_list_copy (new_days); + return new_days; + } + + for (l = new_days; l; l = l->next) { + res = days_compare (l->data, last_cached->data); + day = l->data; + + if (res > 0) { + /* this day in the list is newer than the last one, append to + * the cache. + */ + day->first_line += lines_offset; + day->last_line += lines_offset; + log->priv->days = g_slist_append (log->priv->days, logview_utils_day_copy (day)); + } else if (res == 0) { + last = last_cached->data; + + /* update the lines number */ + last->last_line += day->last_line; + } + } + + return new_days; +} + +static gboolean +new_lines_job_done (gpointer data) +{ + NewLinesJob *job = data; + + if (job->err) { + job->callback (job->log, NULL, NULL, job->err, job->user_data); + g_error_free (job->err); + } else { + job->callback (job->log, job->lines, job->new_days, job->err, job->user_data); + } + + g_clear_object (&job->cancellable); + + g_slist_foreach (job->new_days, (GFunc) logview_utils_day_free, NULL); + g_slist_free (job->new_days); + + /* drop the reference we acquired before */ + g_object_unref (job->log); + + g_slice_free (NewLinesJob, job); + + return FALSE; +} + +static gboolean +do_read_new_lines (GIOSchedulerJob *io_job, + GCancellable *cancellable, + gpointer user_data) +{ + /* this runs in a separate thread */ + NewLinesJob *job = user_data; + LogviewLog *log = job->log; + char *line; + GError *err = NULL; + GPtrArray *lines; + + g_assert (LOGVIEW_IS_LOG (log)); + g_assert (log->priv->stream != NULL); + + if (!log->priv->lines) { + log->priv->lines = g_ptr_array_new (); + g_ptr_array_add (log->priv->lines, NULL); + } + + lines = log->priv->lines; + + /* remove the NULL-terminator */ + g_ptr_array_remove_index (lines, lines->len - 1); + + while ((line = g_data_input_stream_read_line (log->priv->stream, NULL, + job->cancellable, &err)) != NULL) + { + g_ptr_array_add (lines, (gpointer) line); + } + + /* NULL-terminate the array again */ + g_ptr_array_add (lines, NULL); + + if (err) { + job->err = err; + goto out; + } + + log->priv->has_new_lines = FALSE; + + /* we'll return only the new lines in the callback */ + line = g_ptr_array_index (lines, log->priv->lines_no); + job->lines = (const char **) lines->pdata + log->priv->lines_no; + + /* save the new number of days and lines */ + job->new_days = add_new_days_to_cache (log, job->lines, log->priv->lines_no); + log->priv->lines_no = (lines->len - 1); + +out: + g_io_scheduler_job_send_to_mainloop_async (io_job, + new_lines_job_done, + job, NULL); + return FALSE; +} + +static gboolean +log_load_done (gpointer user_data) +{ + LoadJob *job = user_data; + + if (job->err) { + /* the callback will have NULL as log, and the error set */ + g_object_unref (job->log); + job->callback (NULL, job->err, job->user_data); + g_error_free (job->err); + } else { + job->callback (job->log, NULL, job->user_data); + setup_file_monitor (job->log); + } + + g_slice_free (LoadJob, job); + + return FALSE; +} + +#ifdef HAVE_ZLIB + +/* GZip functions adapted for GIO from mate-vfs/gzip-method.c */ + +#define Z_BUFSIZE 16384 + +#define GZIP_HEADER_SIZE 10 +#define GZIP_MAGIC_1 0x1f +#define GZIP_MAGIC_2 0x8b +#define GZIP_FLAG_ASCII 0x01 /* bit 0 set: file probably ascii text */ +#define GZIP_FLAG_HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define GZIP_FLAG_EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define GZIP_FLAG_ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define GZIP_FLAG_COMMENT 0x10 /* bit 4 set: file comment present */ +#define GZIP_FLAG_RESERVED 0xE0 /* bits 5..7: reserved */ + +static gboolean +skip_string (GInputStream *is) +{ + guchar c; + gssize bytes_read; + + do { + bytes_read = g_input_stream_read (is, &c, 1, NULL, NULL); + + if (bytes_read != 1) { + return FALSE; + } + } while (c != 0); + + return TRUE; +} + +static gboolean +read_gzip_header (GInputStream *is, + time_t *modification_time) +{ + gboolean res; + guchar buffer[GZIP_HEADER_SIZE]; + gssize bytes, to_skip; + guint mode; + guint flags; + + bytes = g_input_stream_read (is, buffer, GZIP_HEADER_SIZE, + NULL, NULL); + if (bytes == -1) { + return FALSE; + } + + if (bytes != GZIP_HEADER_SIZE) + return FALSE; + + if (buffer[0] != GZIP_MAGIC_1 || buffer[1] != GZIP_MAGIC_2) + return FALSE; + + mode = buffer[2]; + if (mode != 8) /* Mode: deflate */ + return FALSE; + + flags = buffer[3]; + + if (flags & GZIP_FLAG_RESERVED) + return FALSE; + + if (flags & GZIP_FLAG_EXTRA_FIELD) { + guchar tmp[2]; + + bytes = g_input_stream_read (is, tmp, 2, NULL, NULL); + + if (bytes != 2) { + return FALSE; + } + + to_skip = tmp[0] | (tmp[0] << 8); + bytes = g_input_stream_skip (is, to_skip, NULL, NULL); + if (bytes != to_skip) { + return FALSE; + } + } + + if (flags & GZIP_FLAG_ORIG_NAME) { + if (!skip_string (is)) { + return FALSE; + } + } + + if (flags & GZIP_FLAG_COMMENT) { + if (!skip_string (is)) { + return FALSE; + } + } + + if (flags & GZIP_FLAG_HEAD_CRC) { + bytes = g_input_stream_skip (is, 2, NULL, NULL); + if (bytes != 2) { + return FALSE; + } + } + + *modification_time = (buffer[4] | (buffer[5] << 8) + | (buffer[6] << 16) | (buffer[7] << 24)); + + return TRUE; +} + +static GZHandle * +gz_handle_new (GFile *file, + GInputStream *parent_stream) +{ + GZHandle *ret; + + ret = g_new (GZHandle, 1); + ret->parent_str = g_object_ref (parent_stream); + ret->file = g_object_ref (file); + ret->buffer = NULL; + + return ret; +} + +static gboolean +gz_handle_init (GZHandle *gz) +{ + gz->zstream.zalloc = NULL; + gz->zstream.zfree = NULL; + gz->zstream.opaque = NULL; + + g_free (gz->buffer); + gz->buffer = g_malloc (Z_BUFSIZE); + gz->zstream.next_in = gz->buffer; + gz->zstream.avail_in = 0; + + if (inflateInit2 (&gz->zstream, -MAX_WBITS) != Z_OK) { + return FALSE; + } + + gz->last_z_result = Z_OK; + gz->last_str_result = TRUE; + + return TRUE; +} + +static void +gz_handle_free (GZHandle *gz) +{ + g_object_unref (gz->parent_str); + g_object_unref (gz->file); + g_free (gz->buffer); + g_free (gz); +} + +static gboolean +fill_buffer (GZHandle *gz, + gsize num_bytes) +{ + gboolean res; + gsize count; + + z_stream * zstream = &gz->zstream; + + if (zstream->avail_in > 0) { + return TRUE; + } + + count = g_input_stream_read (gz->parent_str, + gz->buffer, + Z_BUFSIZE, + NULL, NULL); + if (count == -1) { + if (zstream->avail_out == num_bytes) { + return FALSE; + } + gz->last_str_result = FALSE; + } else { + zstream->next_in = gz->buffer; + zstream->avail_in = count; + } + + return TRUE; +} + +static gboolean +result_from_z_result (int z_result) +{ + switch (z_result) { + case Z_OK: + case Z_STREAM_END: + return TRUE; + case Z_DATA_ERROR: + return FALSE; + default: + return FALSE; + } +} + +static gboolean +gz_handle_read (GZHandle *gz, + guchar *buffer, + gsize num_bytes, + gsize * bytes_read) +{ + z_stream *zstream; + gboolean res; + int z_result; + + *bytes_read = 0; + zstream = &gz->zstream; + + if (gz->last_z_result != Z_OK) { + if (gz->last_z_result == Z_STREAM_END) { + *bytes_read = 0; + return TRUE; + } else { + return result_from_z_result (gz->last_z_result); + } + } else if (gz->last_str_result == FALSE) { + return FALSE; + } + + zstream->next_out = buffer; + zstream->avail_out = num_bytes; + + while (zstream->avail_out != 0) { + res = fill_buffer (gz, num_bytes); + + if (!res) { + return res; + } + + z_result = inflate (zstream, Z_NO_FLUSH); + if (z_result == Z_STREAM_END) { + gz->last_z_result = z_result; + break; + } else if (z_result != Z_OK) { + gz->last_z_result = z_result; + } + + if (gz->last_z_result != Z_OK && zstream->avail_out == num_bytes) { + return result_from_z_result (gz->last_z_result); + } + } + + *bytes_read = num_bytes - zstream->avail_out; + + return TRUE; +} + +static GError * +create_zlib_error (void) +{ + GError *err; + + err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_ZLIB, + _("Error while uncompressing the GZipped log. The file " + "might be corrupt.")); + return err; +} + +#endif /* HAVE_ZLIB */ + +static gboolean +log_load (GIOSchedulerJob *io_job, + GCancellable *cancellable, + gpointer user_data) +{ + /* this runs in a separate i/o thread */ + LoadJob *job = user_data; + LogviewLog *log = job->log; + GFile *f = log->priv->file; + GFileInfo *info; + GInputStream *is; + const char *peeked_buffer; + const char * parse_data[2]; + GSList *days; + const char *content_type; + GFileType type; + GError *err = NULL; + GTimeVal timeval; + gboolean is_archive, can_read; + + info = g_file_query_info (f, + G_FILE_ATTRIBUTE_ACCESS_CAN_READ "," + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," + G_FILE_ATTRIBUTE_STANDARD_TYPE "," + G_FILE_ATTRIBUTE_STANDARD_SIZE "," + G_FILE_ATTRIBUTE_TIME_MODIFIED ",", + 0, NULL, &err); + if (err) { + if (err->code == G_IO_ERROR_PERMISSION_DENIED) { + /* TODO: PolicyKit integration */ + } + goto out; + } + + can_read = g_file_info_get_attribute_boolean (info, + G_FILE_ATTRIBUTE_ACCESS_CAN_READ); + if (!can_read) { + /* TODO: PolicyKit integration */ + err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_PERMISSION_DENIED, + _("You don't have enough permissions to read the file.")); + g_object_unref (info); + + goto out; + } + + type = g_file_info_get_file_type (info); + content_type = g_file_info_get_content_type (info); + + is_archive = g_content_type_equals (content_type, "application/x-gzip"); + + if (type != (G_FILE_TYPE_REGULAR || G_FILE_TYPE_SYMBOLIC_LINK) || + (!g_content_type_is_a (content_type, "text/plain") && !is_archive)) + { + err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_NOT_A_LOG, + _("The file is not a regular file or is not a text file.")); + g_object_unref (info); + + goto out; + } + + log->priv->file_size = g_file_info_get_size (info); + g_file_info_get_modification_time (info, &timeval); + log->priv->file_time = timeval.tv_sec; + log->priv->display_name = g_strdup (g_file_info_get_display_name (info)); + + g_object_unref (info); + + /* initialize the stream */ + is = G_INPUT_STREAM (g_file_read (f, NULL, &err)); + + if (err) { + if (err->code == G_IO_ERROR_PERMISSION_DENIED) { + /* TODO: PolicyKit integration */ + } + + goto out; + } + + if (is_archive) { +#ifdef HAVE_ZLIB + GZHandle *gz; + gboolean res; + guchar * buffer; + gsize bytes_read; + GInputStream *real_is; + time_t mtime; /* seconds */ + + /* this also skips the header from |is| */ + res = read_gzip_header (is, &mtime); + + if (!res) { + g_object_unref (is); + + err = create_zlib_error (); + goto out; + } + + log->priv->file_time = mtime; + + gz = gz_handle_new (f, is); + res = gz_handle_init (gz); + + if (!res) { + g_object_unref (is); + gz_handle_free (gz); + + err = create_zlib_error (); + goto out; + } + + real_is = g_memory_input_stream_new (); + + do { + buffer = g_malloc (1024); + res = gz_handle_read (gz, buffer, 1024, &bytes_read); + g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (real_is), + buffer, bytes_read, g_free); + } while (res == TRUE && bytes_read > 0); + + if (!res) { + gz_handle_free (gz); + g_object_unref (real_is); + g_object_unref (is); + + err = create_zlib_error (); + goto out; + } + + g_object_unref (is); + is = real_is; + + gz_handle_free (gz); +#else /* HAVE_ZLIB */ + g_object_unref (is); + + err = g_error_new_literal (LOGVIEW_ERROR_QUARK, LOGVIEW_ERROR_NOT_SUPPORTED, + _("This version of System Log does not support GZipped logs.")); + goto out; +#endif /* HAVE_ZLIB */ + } + + log->priv->stream = g_data_input_stream_new (is); + + /* sniff into the stream for a timestamped line */ + g_buffered_input_stream_fill (G_BUFFERED_INPUT_STREAM (log->priv->stream), + (gssize) g_buffered_input_stream_get_buffer_size (G_BUFFERED_INPUT_STREAM (log->priv->stream)), + NULL, &err); + if (err == NULL) { + peeked_buffer = g_buffered_input_stream_peek_buffer + (G_BUFFERED_INPUT_STREAM (log->priv->stream), NULL); + parse_data[0] = peeked_buffer; + parse_data[1] = NULL; + + if ((days = log_read_dates (parse_data, time (NULL))) != NULL) { + log->priv->has_days = TRUE; + g_slist_foreach (days, (GFunc) logview_utils_day_free, NULL); + g_slist_free (days); + } else { + log->priv->has_days = FALSE; + } + } else { + log->priv->has_days = FALSE; + g_clear_error (&err); + } + + g_object_unref (is); + +out: + if (err) { + job->err = err; + } + + g_io_scheduler_job_send_to_mainloop_async (io_job, + log_load_done, + job, NULL); + return FALSE; +} + +static void +log_setup_load (LogviewLog *log, LogviewCreateCallback callback, + gpointer user_data) +{ + LoadJob *job; + + job = g_slice_new0 (LoadJob); + job->callback = callback; + job->user_data = user_data; + job->log = log; + job->err = NULL; + + /* push the loading job into another thread */ + g_io_scheduler_push_job (log_load, + job, + NULL, 0, NULL); +} + +/* public methods */ + +void +logview_log_read_new_lines (LogviewLog *log, + GCancellable *cancellable, + LogviewNewLinesCallback callback, + gpointer user_data) +{ + NewLinesJob *job; + + /* initialize the job struct with sensible values */ + job = g_slice_new0 (NewLinesJob); + job->callback = callback; + job->user_data = user_data; + job->cancellable = (cancellable != NULL) ? g_object_ref (cancellable) : NULL; + job->log = g_object_ref (log); + job->err = NULL; + job->lines = NULL; + job->new_days = NULL; + + /* push the fetching job into another thread */ + g_io_scheduler_push_job (do_read_new_lines, + job, + NULL, 0, + job->cancellable); +} + +void +logview_log_create (const char *filename, LogviewCreateCallback callback, + gpointer user_data) +{ + LogviewLog *log = g_object_new (LOGVIEW_TYPE_LOG, NULL); + + log->priv->file = g_file_new_for_path (filename); + + log_setup_load (log, callback, user_data); +} + +void +logview_log_create_from_gfile (GFile *file, LogviewCreateCallback callback, + gpointer user_data) +{ + LogviewLog *log = g_object_new (LOGVIEW_TYPE_LOG, NULL); + + log->priv->file = g_object_ref (file); + + log_setup_load (log, callback, user_data); +} + +const char * +logview_log_get_display_name (LogviewLog *log) +{ + g_assert (LOGVIEW_IS_LOG (log)); + + return log->priv->display_name; +} + +time_t +logview_log_get_timestamp (LogviewLog *log) +{ + g_assert (LOGVIEW_IS_LOG (log)); + + return log->priv->file_time; +} + +goffset +logview_log_get_file_size (LogviewLog *log) +{ + g_assert (LOGVIEW_IS_LOG (log)); + + return log->priv->file_size; +} + +guint +logview_log_get_cached_lines_number (LogviewLog *log) +{ + g_assert (LOGVIEW_IS_LOG (log)); + + return log->priv->lines_no; +} + +const char ** +logview_log_get_cached_lines (LogviewLog *log) +{ + const char ** lines = NULL; + + g_assert (LOGVIEW_IS_LOG (log)); + + if (log->priv->lines) { + lines = (const char **) log->priv->lines->pdata; + } + + return lines; +} + +GSList * +logview_log_get_days_for_cached_lines (LogviewLog *log) +{ + g_assert (LOGVIEW_IS_LOG (log)); + + return log->priv->days; +} + +gboolean +logview_log_has_new_lines (LogviewLog *log) +{ + g_assert (LOGVIEW_IS_LOG (log)); + + return log->priv->has_new_lines; +} + +char * +logview_log_get_uri (LogviewLog *log) +{ + g_assert (LOGVIEW_IS_LOG (log)); + + return g_file_get_uri (log->priv->file); +} + +GFile * +logview_log_get_gfile (LogviewLog *log) +{ + g_assert (LOGVIEW_IS_LOG (log)); + + return g_object_ref (log->priv->file); +} + +gboolean +logview_log_get_has_days (LogviewLog *log) +{ + g_assert (LOGVIEW_IS_LOG (log)); + + return log->priv->has_days; +} + diff --git a/logview/src/logview-log.h b/logview/src/logview-log.h new file mode 100644 index 00000000..4f81af14 --- /dev/null +++ b/logview/src/logview-log.h @@ -0,0 +1,110 @@ +/* logview-log.h - object representation of a logfile + * + * Copyright (C) 1998 Cesar Miquel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +/* logview-log.h */ + +#ifndef __LOGVIEW_LOG_H__ +#define __LOGVIEW_LOG_H__ + +#include +#include + +G_BEGIN_DECLS + +#define LOGVIEW_TYPE_LOG logview_log_get_type() +#define LOGVIEW_LOG(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_LOG, LogviewLog)) +#define LOGVIEW_LOG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_LOG, LogviewLogClass)) +#define LOGVIEW_IS_LOG(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_LOG)) +#define LOGVIEW_IS_LOG_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_LOG)) +#define LOGVIEW_LOG_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_LOG, LogviewLogClass)) + +typedef struct _LogviewLog LogviewLog; +typedef struct _LogviewLogClass LogviewLogClass; +typedef struct _LogviewLogPrivate LogviewLogPrivate; + +/* callback signatures for async I/O operations */ + +typedef void (* LogviewCreateCallback) (LogviewLog *log, + GError *error, + gpointer user_data); +typedef void (* LogviewNewLinesCallback) (LogviewLog *log, + const char **lines, + GSList *new_days, + GError *error, + gpointer user_data); + +#define LOGVIEW_ERROR_QUARK g_quark_from_static_string ("logview-error") + +typedef enum { + LOGVIEW_ERROR_FAILED, + LOGVIEW_ERROR_PERMISSION_DENIED, + LOGVIEW_ERROR_ZLIB, + LOGVIEW_ERROR_NOT_SUPPORTED, + LOGVIEW_ERROR_NOT_A_LOG +} LogviewErrorEnum; + +struct _LogviewLog { + GObject parent; + LogviewLogPrivate *priv; +}; + +struct _LogviewLogClass { + GObjectClass parent_class; + + /* signals */ + void (* log_changed) (LogviewLog *log); +}; + +GType logview_log_get_type (void); + +/* public methods */ + +/* these two do I/O, so they are wrapped async */ +void logview_log_create (const char *filename, + LogviewCreateCallback callback, + gpointer user_data); +void logview_log_create_from_gfile (GFile *file, + LogviewCreateCallback callback, + gpointer user_data); +void logview_log_read_new_lines (LogviewLog *log, + GCancellable *cancellable, + LogviewNewLinesCallback callback, + gpointer user_data); + +const char * logview_log_get_display_name (LogviewLog *log); +time_t logview_log_get_timestamp (LogviewLog *log); +goffset logview_log_get_file_size (LogviewLog *log); +const char ** logview_log_get_cached_lines (LogviewLog *log); +guint logview_log_get_cached_lines_number (LogviewLog *log); +GSList * logview_log_get_days_for_cached_lines (LogviewLog *log); +gboolean logview_log_has_new_lines (LogviewLog *log); +char * logview_log_get_uri (LogviewLog *log); +GFile * logview_log_get_gfile (LogviewLog *log); +gboolean logview_log_get_has_days (LogviewLog *log); + +G_END_DECLS + +#endif /* __LOGVIEW_LOG_H__ */ diff --git a/logview/src/logview-loglist.c b/logview/src/logview-loglist.c new file mode 100644 index 00000000..847626d9 --- /dev/null +++ b/logview/src/logview-loglist.c @@ -0,0 +1,500 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-loglist.c - displays a list of the opened logs + * + * Copyright (C) 2005 Vincent Noel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "logview-manager.h" +#include "logview-log.h" +#include "logview-utils.h" + +#include "logview-loglist.h" + +struct _LogviewLoglistPrivate { + GtkTreeStore *model; + LogviewManager *manager; + GtkTreePath *selection; + gboolean has_day_selection; +}; + +G_DEFINE_TYPE (LogviewLoglist, logview_loglist, GTK_TYPE_TREE_VIEW); + +#define GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_LOGLIST, LogviewLoglistPrivate)) + +enum { + LOG_OBJECT = 0, + LOG_NAME, + LOG_WEIGHT, + LOG_WEIGHT_SET, + LOG_DAY +}; + +enum { + DAY_SELECTED, + DAY_CLEARED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +static void +save_day_selection (LogviewLoglist *loglist, GtkTreeIter *iter) +{ + if (loglist->priv->selection) { + gtk_tree_path_free (loglist->priv->selection); + } + + loglist->priv->selection = gtk_tree_model_get_path + (GTK_TREE_MODEL (loglist->priv->model), iter); +} + +static void +update_days_and_lines_for_log (LogviewLoglist *loglist, + GtkTreeIter *log, GSList *days) +{ + gboolean res; + GtkTreeIter iter, dummy; + GSList *l; + int i; + char date[200]; + Day *day; + + /* if we have some days, we can't remove all the items immediately, otherwise, + * if the row is expanded, it will be collapsed because there are no items, + * so we create a dummy entry, remove all the others and then remove the + * dummy one. + */ + res = gtk_tree_model_iter_children (GTK_TREE_MODEL (loglist->priv->model), + &iter, log); + if (res) { + gtk_tree_store_insert_before (loglist->priv->model, &dummy, log, &iter); + gtk_tree_store_set (loglist->priv->model, &dummy, + LOG_NAME, "", -1); + do { + gtk_tree_store_remove (loglist->priv->model, &iter); + } while (gtk_tree_store_iter_is_valid (loglist->priv->model, &iter)); + } + + for (i = 1, l = days; l; l = l->next) { + /* now insert all the days */ + day = l->data; + + g_date_strftime (date, 200, "%A, %e %b", day->date); + + gtk_tree_store_insert (GTK_TREE_STORE (loglist->priv->model), + &iter, log, i); + gtk_tree_store_set (GTK_TREE_STORE (loglist->priv->model), + &iter, LOG_NAME, date, LOG_DAY, day, -1); + i++; + } + + if (res) { + gtk_tree_store_remove (loglist->priv->model, &dummy); + } +} + +static GtkTreeIter * +logview_loglist_find_log (LogviewLoglist *list, LogviewLog *log) +{ + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeIter *retval = NULL; + LogviewLog *current; + + model = GTK_TREE_MODEL (list->priv->model); + + if (!gtk_tree_model_get_iter_first (model, &iter)) { + return NULL; + } + + do { + gtk_tree_model_get (model, &iter, LOG_OBJECT, ¤t, -1); + if (current == log) { + retval = gtk_tree_iter_copy (&iter); + } + if (current) + g_object_unref (current); + } while (gtk_tree_model_iter_next (model, &iter) != FALSE && retval == NULL); + + return retval; +} + +static void +log_changed_cb (LogviewLog *log, + gpointer user_data) +{ + LogviewLoglist *list = user_data; + LogviewLog *active; + GtkTreeIter *iter; + + active = logview_manager_get_active_log (list->priv->manager); + + if (log == active) { + g_object_unref (active); + return; + } + + iter = logview_loglist_find_log (list, log); + + if (!iter) { + return; + } + + /* make the log bold in the list */ + gtk_tree_store_set (list->priv->model, iter, + LOG_WEIGHT, PANGO_WEIGHT_BOLD, + LOG_WEIGHT_SET, TRUE, -1); + + gtk_tree_iter_free (iter); +} + + +static void +tree_selection_changed_cb (GtkTreeSelection *selection, + gpointer user_data) +{ + LogviewLoglist *list = user_data; + GtkTreeModel *model; + GtkTreeIter iter, parent; + LogviewLog *log; + gboolean is_bold, is_active; + Day *day; + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + return; + } + + gtk_tree_model_get (model, &iter, LOG_OBJECT, &log, + LOG_WEIGHT_SET, &is_bold, + LOG_DAY, &day, -1); + if (log) { + is_active = logview_manager_log_is_active (list->priv->manager, log); + + if (is_active && list->priv->has_day_selection) { + list->priv->has_day_selection = FALSE; + g_signal_emit (list, signals[DAY_CLEARED], 0, NULL); + } else if (!is_active) { + logview_manager_set_active_log (list->priv->manager, log); + } + } else if (day) { + list->priv->has_day_selection = TRUE; + gtk_tree_model_iter_parent (model, &parent, &iter); + gtk_tree_model_get (model, &parent, LOG_OBJECT, &log, -1); + + if (!logview_manager_log_is_active (list->priv->manager, log)) { + save_day_selection (list, &iter); + logview_manager_set_active_log (list->priv->manager, log); + } else { + g_signal_emit (list, signals[DAY_SELECTED], 0, day, NULL); + } + } + + if (is_bold) { + gtk_tree_store_set (GTK_TREE_STORE (model), &iter, + LOG_WEIGHT_SET, FALSE, -1); + } + + if (log) { + g_object_unref (log); + } +} + +static void +manager_active_changed_cb (LogviewManager *manager, + LogviewLog *log, + LogviewLog *old_log, + gpointer user_data) +{ + LogviewLoglist *list = user_data; + GtkTreeIter * iter, sel_iter; + GtkTreeSelection * selection; + + if (list->priv->selection && + gtk_tree_model_get_iter (GTK_TREE_MODEL (list->priv->model), + &sel_iter, list->priv->selection)) + { + Day *day; + + iter = gtk_tree_iter_copy (&sel_iter); + + gtk_tree_model_get (GTK_TREE_MODEL (list->priv->model), iter, + LOG_DAY, &day, -1); + + if (day) { + g_signal_emit (list, signals[DAY_SELECTED], 0, day, NULL); + } + + gtk_tree_path_free (list->priv->selection); + list->priv->selection = NULL; + } else { + iter = logview_loglist_find_log (list, log); + } + + if (!iter) { + return; + } + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); + g_signal_handlers_block_by_func (selection, tree_selection_changed_cb, list); + + gtk_tree_selection_select_iter (selection, iter); + + g_signal_handlers_unblock_by_func (selection, tree_selection_changed_cb, list); + gtk_tree_iter_free (iter); +} + +static void +manager_log_closed_cb (LogviewManager *manager, + LogviewLog *log, + gpointer user_data) +{ + LogviewLoglist *list = user_data; + GtkTreeIter *iter; + gboolean res; + + iter = logview_loglist_find_log (list, log); + + if (!iter) { + return; + } + + g_signal_handlers_disconnect_by_func (log, log_changed_cb, list); + + res = gtk_tree_store_remove (list->priv->model, iter); + if (res) { + GtkTreeSelection *selection; + + /* iter now points to the next valid row */ + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); + gtk_tree_selection_select_iter (selection, iter); + } else { + /* FIXME: what shall we do here? */ + } + + gtk_tree_iter_free (iter); +} + +static void +manager_log_added_cb (LogviewManager *manager, + LogviewLog *log, + gpointer user_data) +{ + LogviewLoglist *list = user_data; + GtkTreeIter iter, child; + + gtk_tree_store_append (list->priv->model, &iter, NULL); + gtk_tree_store_set (list->priv->model, &iter, + LOG_OBJECT, g_object_ref (log), + LOG_NAME, logview_log_get_display_name (log), -1); + if (logview_log_get_has_days (log)) { + gtk_tree_store_insert (list->priv->model, + &child, &iter, 0); + gtk_tree_store_set (list->priv->model, &child, + LOG_NAME, _("Loading..."), -1); + } + + g_signal_connect (log, "log-changed", + G_CALLBACK (log_changed_cb), list); +} + +static void +row_expanded_cb (GtkTreeView *view, + GtkTreeIter *iter, + GtkTreePath *path, + gpointer user_data) +{ + LogviewLoglist *list = user_data; + LogviewLog *log; + + gtk_tree_model_get (GTK_TREE_MODEL (list->priv->model), iter, + LOG_OBJECT, &log, -1); + if (!logview_manager_log_is_active (list->priv->manager, log)) { + logview_manager_set_active_log (list->priv->manager, log); + } + + g_object_unref (log); +} + +static int +loglist_sort_func (GtkTreeModel *model, + GtkTreeIter *a, + GtkTreeIter *b, + gpointer user_data) +{ + char *name_a, *name_b; + Day *day_a, *day_b; + int retval = 0; + + switch (gtk_tree_store_iter_depth (GTK_TREE_STORE (model), a)) { + case 0: + gtk_tree_model_get (model, a, LOG_NAME, &name_a, -1); + gtk_tree_model_get (model, b, LOG_NAME, &name_b, -1); + retval = g_utf8_collate (name_a, name_b); + g_free (name_a); + g_free (name_b); + + break; + case 1: + gtk_tree_model_get (model, a, LOG_DAY, &day_a, -1); + gtk_tree_model_get (model, b, LOG_DAY, &day_b, -1); + if (day_a && day_b) { + retval = days_compare (day_a, day_b); + } else { + retval = 0; + } + + break; + default: + g_assert_not_reached (); + + break; + } + + return retval; +} + +static void +do_finalize (GObject *obj) +{ + LogviewLoglist *list = LOGVIEW_LOGLIST (obj); + + g_object_unref (list->priv->model); + list->priv->model = NULL; + + if (list->priv->selection) { + gtk_tree_path_free (list->priv->selection); + list->priv->selection = NULL; + } + + G_OBJECT_CLASS (logview_loglist_parent_class)->finalize (obj); +} + +static void +logview_loglist_init (LogviewLoglist *list) +{ + GtkTreeStore *model; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + GtkCellRenderer *cell; + + list->priv = GET_PRIVATE (list); + list->priv->has_day_selection = FALSE; + list->priv->selection = NULL; + + model = gtk_tree_store_new (5, LOGVIEW_TYPE_LOG, G_TYPE_STRING, G_TYPE_INT, + G_TYPE_BOOLEAN, G_TYPE_POINTER); + gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (model)); + list->priv->model = model; + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); + g_signal_connect (selection, "changed", + G_CALLBACK (tree_selection_changed_cb), list); + + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new (); + gtk_tree_view_column_pack_start (column, cell, TRUE); + gtk_tree_view_column_set_attributes (column, cell, + "text", LOG_NAME, + "weight-set", LOG_WEIGHT_SET, + "weight", LOG_WEIGHT, + NULL); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list->priv->model), LOG_NAME, GTK_SORT_ASCENDING); + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list->priv->model), + LOG_NAME, + (GtkTreeIterCompareFunc) loglist_sort_func, + list, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (list), column); + gtk_tree_view_set_search_column (GTK_TREE_VIEW (list), -1); + + list->priv->manager = logview_manager_get (); + + g_signal_connect (list->priv->manager, "log-added", + G_CALLBACK (manager_log_added_cb), list); + g_signal_connect (list->priv->manager, "log-closed", + G_CALLBACK (manager_log_closed_cb), list); + g_signal_connect_after (list->priv->manager, "active-changed", + G_CALLBACK (manager_active_changed_cb), list); + g_signal_connect (list, "row-expanded", + G_CALLBACK (row_expanded_cb), list); +} + +static void +logview_loglist_class_init (LogviewLoglistClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + oclass->finalize = do_finalize; + + signals[DAY_SELECTED] = g_signal_new ("day-selected", + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewLoglistClass, day_selected), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[DAY_CLEARED] = g_signal_new ("day-cleared", + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewLoglistClass, day_cleared), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_type_class_add_private (klass, sizeof (LogviewLoglistPrivate)); +} + +/* public methods */ + +GtkWidget * +logview_loglist_new (void) +{ + GtkWidget *widget; + widget = g_object_new (LOGVIEW_TYPE_LOGLIST, NULL); + return widget; +} + +void +logview_loglist_update_lines (LogviewLoglist *loglist, LogviewLog *log) +{ + GSList *days; + GtkTreeIter *parent; + + g_assert (LOGVIEW_IS_LOGLIST (loglist)); + g_assert (LOGVIEW_IS_LOG (log)); + + parent = logview_loglist_find_log (loglist, log); + + if (parent) { + days = logview_log_get_days_for_cached_lines (log); + update_days_and_lines_for_log (loglist, parent, days); + gtk_tree_iter_free (parent); + } +} + diff --git a/logview/src/logview-loglist.h b/logview/src/logview-loglist.h new file mode 100644 index 00000000..ebfbf04f --- /dev/null +++ b/logview/src/logview-loglist.h @@ -0,0 +1,68 @@ +/* logview-loglist.h - displays a list of the opened logs + * + * Copyright (C) 2005 Vincent Noel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __LOGVIEW_LOGLIST_H__ +#define __LOGVIEW_LOGLIST_H__ + +#define LOGVIEW_TYPE_LOGLIST logview_loglist_get_type() +#define LOGVIEW_LOGLIST(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_LOGLIST, LogviewLoglist)) +#define LOGVIEW_LOGLIST_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_LOGLIST, LogviewLogListClass)) +#define LOGVIEW_IS_LOGLIST(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_LOGLIST)) +#define LOGVIEW_IS_LOGLIST_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_LOGLIST)) +#define LOGVIEW_LOGLIST_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_LOGLIST, LogviewLoglistClass)) + +#include +#include + +#include "logview-log.h" +#include "logview-utils.h" + +typedef struct _LogviewLoglist LogviewLoglist; +typedef struct _LogviewLoglistClass LogviewLoglistClass; +typedef struct _LogviewLoglistPrivate LogviewLoglistPrivate; + +struct _LogviewLoglist { + GtkTreeView parent_instance; + LogviewLoglistPrivate *priv; +}; + +struct _LogviewLoglistClass { + GtkTreeViewClass parent_class; + + void (* day_selected) (LogviewLoglist *loglist, + Day *day); + void (* day_cleared) (LogviewLoglist *loglist); +}; + +GType logview_loglist_get_type (void); + +/* public methods */ +GtkWidget * logview_loglist_new (void); +void logview_loglist_update_lines (LogviewLoglist *loglist, + LogviewLog *log); +GDate * logview_loglist_get_date_selection (LogviewLoglist *loglist); +void logview_loglist_clear_date (LogviewLoglist *loglist); + +#endif /* __LOGVIEW_LOGLIST_H__ */ diff --git a/logview/src/logview-main.c b/logview/src/logview-main.c new file mode 100644 index 00000000..74dcb44b --- /dev/null +++ b/logview/src/logview-main.c @@ -0,0 +1,120 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-main.c - logview main + * + * Copyright (C) 2005 Vincent Noel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" + +#include + +#include +#include + +#include + +#include "logview-app.h" + +/* log files specified on the command line */ +static char **log_files = NULL; + +static void +app_quit_cb (LogviewApp *app, + gpointer user_data) +{ + gtk_main_quit (); +} + +static void +logview_show_version_and_quit (void) +{ + g_print ("%s - Version %s\n" + "Copyright (C) 2004-2008 Vincent Noel, Cosimo Cecchi and others.\n", + g_get_application_name (), + VERSION); + + exit (0); +} + +static GOptionContext * +create_option_context (void) +{ + GOptionContext *context; + + const GOptionEntry entries[] = { + { "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, + logview_show_version_and_quit, N_("Show the application's version"), NULL }, + { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &log_files, + NULL, N_("[LOGFILE...]") }, + { NULL }, + }; + + context = g_option_context_new (_(" - Browse and monitor logs")); + g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + g_option_context_set_ignore_unknown_options (context, TRUE); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + + return context; +} + +int +main (int argc, char *argv[]) +{ + GError *error = NULL; + GOptionContext *context; + LogviewApp *app; + + bindtextdomain (GETTEXT_PACKAGE, MATELOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + context = create_option_context (); + + g_option_context_parse (context, &argc, &argv, &error); + + if (error) { + g_critical ("Unable to parse arguments: %s", error->message); + g_error_free (error); + g_option_context_free (context); + + exit (1); + } + + g_option_context_free (context); + g_set_application_name (_("Log Viewer")); + + app = logview_app_get (); + + if (!app) { + g_critical ("Unable to create the user interface."); + + exit (1); + } else { + g_signal_connect (app, "app-quit", + G_CALLBACK (app_quit_cb), NULL); + } + + logview_app_initialize (app, log_files); + + gtk_main (); + + g_object_unref (app); + + return EXIT_SUCCESS; +} diff --git a/logview/src/logview-manager.c b/logview/src/logview-manager.c new file mode 100644 index 00000000..54b5320b --- /dev/null +++ b/logview/src/logview-manager.c @@ -0,0 +1,432 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-manager.c - manager for the opened log objects + * + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +/* logview-manager.c */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "logview-manager.h" + +#include + +#include "logview-prefs.h" +#include "logview-marshal.h" +#include "logview-app.h" + +enum { + LOG_ADDED, + LOG_CLOSED, + ACTIVE_CHANGED, + LAST_SIGNAL +}; + +typedef struct { + LogviewManager *manager; + gboolean set_active; + gboolean is_multiple; + GFile *file; +} CreateCBData; + +typedef struct { + int total; + int current; + GPtrArray *errors; +} MultipleCreation; + +struct _LogviewManagerPrivate { + GHashTable *logs; + LogviewLog *active_log; +}; + +static LogviewManager *singleton = NULL; +static MultipleCreation *op = NULL; +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (LogviewManager, logview_manager, G_TYPE_OBJECT); + +#define GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_MANAGER, LogviewManagerPrivate)) + +static void +logview_manager_finalize (GObject *object) +{ + LogviewManager *manager; + + manager = LOGVIEW_MANAGER (object); + + if (manager->priv->active_log) { + g_object_unref (manager->priv->active_log); + } + + g_hash_table_destroy (manager->priv->logs); + + G_OBJECT_CLASS (logview_manager_parent_class)->finalize (object); +} + +static void +logview_manager_class_init (LogviewManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = logview_manager_finalize; + + signals[LOG_ADDED] = g_signal_new ("log-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewManagerClass, log_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + LOGVIEW_TYPE_LOG); + + signals[LOG_CLOSED] = g_signal_new ("log-closed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewManagerClass, log_closed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + LOGVIEW_TYPE_LOG); + + signals[ACTIVE_CHANGED] = g_signal_new ("active-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewManagerClass, active_changed), + NULL, NULL, + logview_marshal_VOID__OBJECT_OBJECT, + G_TYPE_NONE, 2, + LOGVIEW_TYPE_LOG, + LOGVIEW_TYPE_LOG); + + g_type_class_add_private (klass, sizeof (LogviewManagerPrivate)); +} + +static void +logview_manager_init (LogviewManager *self) +{ + LogviewManagerPrivate *priv = self->priv = GET_PRIVATE (self); + + priv->active_log = NULL; + priv->logs = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); +} + +static MultipleCreation * +multiple_creation_op_new (int total) +{ + MultipleCreation *retval; + + retval = g_slice_new0 (MultipleCreation); + retval->total = total; + retval->current = 0; + retval->errors = g_ptr_array_new (); + + return retval; +} + +static void +multiple_creation_op_free (MultipleCreation *mc) +{ + g_ptr_array_foreach (mc->errors, (GFunc) g_strfreev, NULL); + g_ptr_array_free (mc->errors, TRUE); + + g_slice_free (MultipleCreation, mc); +} + +static void +create_log_cb (LogviewLog *log, + GError *error, + gpointer user_data) +{ + CreateCBData *data = user_data; + + if (log) { + char *log_uri; + LogviewPrefs *prefs; + GFile *file; + + log_uri = logview_log_get_uri (log); + + /* creation went well, store the log and notify */ + g_hash_table_insert (data->manager->priv->logs, + log_uri, log); + + prefs = logview_prefs_get (); + file = logview_log_get_gfile (log); + logview_prefs_store_log (prefs, file); + + g_object_unref (file); + + g_signal_emit (data->manager, signals[LOG_ADDED], 0, log, NULL); + + if (data->set_active) { + logview_manager_set_active_log (data->manager, log); + } + } else { + char *path; + + /* notify the error */ + path = g_file_get_path (data->file); + + if (!data->is_multiple) { + logview_app_add_error (logview_app_get (), + path, error->message); + } else { + char **error_arr = g_new0 (char *, 3); + + error_arr[0] = g_strdup (path); + error_arr[1] = g_strdup (error->message); + error_arr[2] = NULL; + + g_ptr_array_add (op->errors, error_arr); + } + + g_free (path); + } + + if (data->is_multiple) { + op->current++; + + if (op->total == op->current) { + logview_app_add_errors (logview_app_get (), op->errors); + multiple_creation_op_free (op); + op = NULL; + } + } + + g_object_unref (data->file); + g_slice_free (CreateCBData, data); +} + +static void +add_log_from_gfile_internal (LogviewManager *manager, + GFile *file, + gboolean set_active, + gboolean is_multiple) +{ + char *file_uri; + LogviewLog *log; + CreateCBData *data; + + file_uri = g_file_get_uri (file); + + if (set_active == FALSE) { + /* if it's the first log being added, set it as active anyway */ + set_active = (manager->priv->logs == NULL); + } + + if ((log = g_hash_table_lookup (manager->priv->logs, file_uri)) != NULL) { + /* log already exists, don't load it */ + if (set_active) { + logview_manager_set_active_log (manager, log); + } + } else { + data = g_slice_new0 (CreateCBData); + data->manager = manager; + data->set_active = set_active; + data->is_multiple = is_multiple; + data->file = g_object_ref (file); + + logview_log_create_from_gfile (file, create_log_cb, data); + } + + g_free (file_uri); +} + +static void +logview_manager_add_log_from_name (LogviewManager *manager, + const char *filename, gboolean set_active, + gboolean is_multiple) +{ + GFile *file; + + file = g_file_new_for_path (filename); + + add_log_from_gfile_internal (manager, file, set_active, is_multiple); + + g_object_unref (file); +} + +/* public methods */ + +LogviewManager* +logview_manager_get (void) +{ + if (!singleton) { + singleton = g_object_new (LOGVIEW_TYPE_MANAGER, NULL); + } + + return singleton; +} + +void +logview_manager_set_active_log (LogviewManager *manager, + LogviewLog *log) +{ + LogviewLog *old_log = NULL; + GFile *file; + char *path; + + g_assert (LOGVIEW_IS_MANAGER (manager)); + + if (manager->priv->active_log) { + old_log = manager->priv->active_log; + } + + manager->priv->active_log = g_object_ref (log); + + file = logview_log_get_gfile (log); + path = g_file_get_path (file); + logview_prefs_store_active_logfile (logview_prefs_get (), path); + g_free (path); + g_object_unref (file); + + g_signal_emit (manager, signals[ACTIVE_CHANGED], 0, log, old_log, NULL); + + if (old_log) { + g_object_unref (old_log); + } +} + +LogviewLog * +logview_manager_get_active_log (LogviewManager *manager) +{ + g_assert (LOGVIEW_IS_MANAGER (manager)); + + return (manager->priv->active_log != NULL) ? + g_object_ref (manager->priv->active_log) : + NULL; +} + +void +logview_manager_add_log_from_gfile (LogviewManager *manager, + GFile *file, + gboolean set_active) +{ + g_assert (LOGVIEW_IS_MANAGER (manager)); + + add_log_from_gfile_internal (manager, file, set_active, FALSE); +} + +void +logview_manager_add_logs_from_name_list (LogviewManager *manager, + GSList *names, + const char *active) +{ + GSList *l; + + g_assert (LOGVIEW_IS_MANAGER (manager)); + g_assert (op == NULL); + + op = multiple_creation_op_new (g_slist_length (names)); + + for (l = names; l; l = l->next) { + logview_manager_add_log_from_name (manager, l->data, + (g_ascii_strcasecmp (active, l->data) == 0), + TRUE); + } +} + +void +logview_manager_add_logs_from_names (LogviewManager *manager, + char ** names, + const gchar *active) +{ + int i; + gboolean set_active; + + g_assert (LOGVIEW_IS_MANAGER (manager)); + g_assert (op == NULL); + + op = multiple_creation_op_new (g_strv_length (names)); + + for (i = 0; names[i]; i++) { + set_active = (active != NULL) && (!g_ascii_strcasecmp (active, names[i])); + logview_manager_add_log_from_name (manager, names[i], set_active, + TRUE); + } +} + +int +logview_manager_get_log_count (LogviewManager *manager) +{ + g_assert (LOGVIEW_IS_MANAGER (manager)); + + return g_hash_table_size (manager->priv->logs); +} + +LogviewLog * +logview_manager_get_if_loaded (LogviewManager *manager, char *uri) +{ + LogviewLog *log; + + g_assert (LOGVIEW_IS_MANAGER (manager)); + + log = g_hash_table_lookup (manager->priv->logs, uri); + + if (log != NULL) { + return g_object_ref (log); + } + + return NULL; +} + +void +logview_manager_close_active_log (LogviewManager *manager) +{ + LogviewLog *active_log; + char *log_uri; + GFile *file; + + g_assert (LOGVIEW_IS_MANAGER (manager)); + + active_log = manager->priv->active_log; + if (active_log == NULL) { + return; + } + + log_uri = logview_log_get_uri (active_log); + file = logview_log_get_gfile (active_log); + + g_signal_emit (manager, signals[LOG_CLOSED], 0, active_log, NULL); + + logview_prefs_remove_stored_log (logview_prefs_get (), file); + + g_object_unref (file); + + /* drop the hash table ref */ + g_hash_table_remove (manager->priv->logs, log_uri); + + g_free (log_uri); + + /* someone else will take care of setting the next active log to us */ +} + +gboolean +logview_manager_log_is_active (LogviewManager *manager, + LogviewLog *log) +{ + g_assert (LOGVIEW_IS_MANAGER (manager)); + + return (manager->priv->active_log == log); +} diff --git a/logview/src/logview-manager.h b/logview/src/logview-manager.h new file mode 100644 index 00000000..b9444323 --- /dev/null +++ b/logview/src/logview-manager.h @@ -0,0 +1,90 @@ +/* logview-manager.h - manager for the opened log objects + * + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + */ + +/* logview-manager.h */ + +#ifndef __LOGVIEW_MANAGER_H__ +#define __LOGVIEW_MANAGER_H__ + +#include + +#include "logview-log.h" + +G_BEGIN_DECLS + +#define LOGVIEW_TYPE_MANAGER logview_manager_get_type() +#define LOGVIEW_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_MANAGER, LogviewManager)) +#define LOGVIEW_MANAGER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_MANAGER, LogviewManagerClass)) +#define LOGVIEW_IS_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_MANAGER)) +#define LOGVIEW_IS_MANAGER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_MANAGER)) +#define LOGVIEW_MANAGER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_MANAGER, LogviewManagerClass)) + +typedef struct _LogviewManager LogviewManager; +typedef struct _LogviewManagerClass LogviewManagerClass; +typedef struct _LogviewManagerPrivate LogviewManagerPrivate; + +struct _LogviewManager { + GObject parent; + LogviewManagerPrivate *priv; +}; + +struct _LogviewManagerClass { + GObjectClass parent_class; + + void (* log_added) (LogviewManager *manager, + LogviewLog *log); + void (* log_closed) (LogviewManager *manager, + LogviewLog *log); + void (* active_changed) (LogviewManager *manager, + LogviewLog *log, + LogviewLog *old_log); +}; + +GType logview_manager_get_type (void); + +/* public methods */ +LogviewManager* logview_manager_get (void); +void logview_manager_add_logs_from_name_list (LogviewManager *manager, + GSList *names, + const char *active); +void logview_manager_add_log_from_gfile (LogviewManager *manager, + GFile *file, + gboolean set_active); +void logview_manager_add_logs_from_names (LogviewManager *manager, + char ** names, + const gchar *active); +void logview_manager_set_active_log (LogviewManager *manager, + LogviewLog *log); +LogviewLog * logview_manager_get_active_log (LogviewManager *manager); +int logview_manager_get_log_count (LogviewManager *manager); +LogviewLog * logview_manager_get_if_loaded (LogviewManager *manager, + char *filename); +gboolean logview_manager_log_is_active (LogviewManager *manager, + LogviewLog *log); +void logview_manager_close_active_log (LogviewManager *manager); + +G_END_DECLS + +#endif /* __LOGVIEW_MANAGER_H__ */ diff --git a/logview/src/logview-marshal.list b/logview/src/logview-marshal.list new file mode 100644 index 00000000..38076d6c --- /dev/null +++ b/logview/src/logview-marshal.list @@ -0,0 +1 @@ +VOID:OBJECT,OBJECT diff --git a/logview/src/logview-prefs.c b/logview/src/logview-prefs.c new file mode 100644 index 00000000..0a2e0093 --- /dev/null +++ b/logview/src/logview-prefs.c @@ -0,0 +1,546 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-prefs.c - logview user preferences handling + * + * Copyright (C) 1998 Cesar Miquel + * Copyright (C) 2004 Vincent Noel + * Copyright (C) 2006 Emmanuele Bassi + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "logview-prefs.h" + +#define LOGVIEW_DEFAULT_HEIGHT 400 +#define LOGVIEW_DEFAULT_WIDTH 600 + +/* logview settings */ +#define LOGVIEW_SCHEMA "org.mate.system-log" +#define PREF_WIDTH "width" +#define PREF_HEIGHT "height" +#define PREF_LOGFILE "logfile" +#define PREF_LOGFILES "logfiles" +#define PREF_FONTSIZE "fontsize" +#define PREF_FILTERS "filters" + +/* desktop-wide settings */ +#define MATE_MONOSPACE_FONT_NAME "monospace-font-name" +#define MATE_MENUS_HAVE_TEAROFF "menus-have-tearoff" + +static LogviewPrefs *singleton = NULL; + +enum { + SYSTEM_FONT_CHANGED, + HAVE_TEAROFF_CHANGED, + 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) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_PREFS, LogviewPrefsPrivate)) + +struct _LogviewPrefsPrivate { + GSettings *logview_prefs; + GSettings *interface_prefs; + + GHashTable *filters; +}; + +G_DEFINE_TYPE (LogviewPrefs, logview_prefs, G_TYPE_OBJECT); + +static void +do_finalize (GObject *obj) +{ + LogviewPrefs *prefs = LOGVIEW_PREFS (obj); + + g_hash_table_destroy (prefs->priv->filters); + + g_object_unref (prefs->priv->logview_prefs); + g_object_unref (prefs->priv->interface_prefs); + + G_OBJECT_CLASS (logview_prefs_parent_class)->finalize (obj); +} + +static void +logview_prefs_class_init (LogviewPrefsClass *klass) +{ + GObjectClass *oclass = G_OBJECT_CLASS (klass); + + oclass->finalize = do_finalize; + + signals[SYSTEM_FONT_CHANGED] = g_signal_new ("system-font-changed", + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewPrefsClass, system_font_changed), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + signals[HAVE_TEAROFF_CHANGED] = g_signal_new ("have-tearoff-changed", + G_OBJECT_CLASS_TYPE (oclass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LogviewPrefsClass, have_tearoff_changed), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, + G_TYPE_BOOLEAN); + + g_type_class_add_private (klass, sizeof (LogviewPrefsPrivate)); +} + +static void +have_tearoff_changed_cb (GSettings *settings, + gchar *key, + gpointer data) +{ + LogviewPrefs *prefs = data; + gboolean add_tearoffs; + + add_tearoffs = g_settings_get_boolean (settings, key); + g_signal_emit (prefs, signals[HAVE_TEAROFF_CHANGED], 0, add_tearoffs, NULL); +} + +static void +monospace_font_changed_cb (GSettings *settings, + gchar *key, + gpointer data) +{ + LogviewPrefs *prefs = data; + gchar *monospace_font_name; + + monospace_font_name = g_settings_get_string (settings, key); + g_signal_emit (prefs, signals[SYSTEM_FONT_CHANGED], 0, monospace_font_name, NULL); + + g_free (monospace_font_name); +} + +#define DELIMITER ":" + +static void +load_filters (LogviewPrefs *prefs) +{ + gchar **filters; + gchar **tokens; + const gchar *str; + LogviewFilter *filter; + GtkTextTag *tag; + GdkColor color; + gint idx; + + filters = g_settings_get_strv (prefs->priv->logview_prefs, + PREF_FILTERS); + + prefs->priv->filters = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + + for (idx = 0; filters[idx] != NULL; idx++) { + str = filters[idx]; + tokens = g_strsplit (str, DELIMITER, MAX_TOKENS); + filter = logview_filter_new (tokens[FILTER_NAME], tokens[FILTER_REGEX]); + 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])) { + gdk_color_parse (tokens[FILTER_FOREGROUND], &color); + g_object_set (tag, "foreground-gdk", &color, + "foreground-set", TRUE, NULL); + } + + if (strlen (tokens[FILTER_BACKGROUND])) { + gdk_color_parse (tokens[FILTER_BACKGROUND], &color); + g_object_set (tag, "paragraph-background-gdk", &color, + "paragraph-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_strfreev (filters); +} + +static void +save_filter_foreach_func (gpointer key, gpointer value, gpointer user_data) +{ + GPtrArray *filters; + const gchar *name; + LogviewFilter *filter; + GdkColor *foreground; + gboolean foreground_set; + GdkColor *background; + gboolean background_set; + gchar *regex, *color; + gboolean invisible; + GtkTextTag *tag; + GString *prefs_string; + + filters = user_data; + filter = LOGVIEW_FILTER (value); + name = key; + color = NULL; + + prefs_string = g_string_new (name); + g_string_append (prefs_string, DELIMITER); + + g_object_get (filter, + "regex", ®ex, + "texttag", &tag, + NULL); + g_object_get (tag, + "foreground-gdk", &foreground, + "paragraph-background-gdk", &background, + "foreground-set", &foreground_set, + "paragraph-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) { + color = gdk_color_to_string (foreground); + g_string_append (prefs_string, color); + g_free (color); + } + + if (foreground) { + gdk_color_free (foreground); + } + + g_string_append (prefs_string, DELIMITER); + + if (background_set) { + color = gdk_color_to_string (background); + g_string_append (prefs_string, color); + g_free (color); + } + + if (background) { + gdk_color_free (background); + } + + g_string_append (prefs_string, DELIMITER); + g_string_append (prefs_string, regex); + + g_free (regex); + g_object_unref (tag); + + g_ptr_array_add (filters, g_string_free (prefs_string, FALSE)); +} + +static void +save_filters (LogviewPrefs *prefs) +{ + GPtrArray *filters; + gchar **filters_strv; + + filters = g_ptr_array_new (); + g_hash_table_foreach (prefs->priv->filters, + save_filter_foreach_func, + filters); + g_ptr_array_add (filters, NULL); + + filters_strv = (gchar **) g_ptr_array_free (filters, FALSE); + g_settings_set_strv (prefs->priv->logview_prefs, + PREF_FILTERS, + (const gchar **) filters_strv); + + g_strfreev (filters_strv); +} + +static void +get_filters_foreach (gpointer key, gpointer value, gpointer user_data) +{ + GList **list; + list = user_data; + *list = g_list_append (*list, value); +} + +static void +logview_prefs_init (LogviewPrefs *self) +{ + LogviewPrefsPrivate *priv; + + priv = self->priv = GET_PRIVATE (self); + + priv->logview_prefs = g_settings_new (LOGVIEW_SCHEMA); + priv->interface_prefs = g_settings_new ("org.mate.interface"); + + g_signal_connect (priv->interface_prefs, "changed::" MATE_MONOSPACE_FONT_NAME, + G_CALLBACK (monospace_font_changed_cb), self); + g_signal_connect (priv->interface_prefs, "changed::" MATE_MENUS_HAVE_TEAROFF, + G_CALLBACK (have_tearoff_changed_cb), self); + + load_filters (self); +} + +/* public methods */ + +LogviewPrefs * +logview_prefs_get () +{ + if (!singleton) + singleton = g_object_new (LOGVIEW_TYPE_PREFS, NULL); + + return singleton; +} + +void +logview_prefs_store_window_size (LogviewPrefs *prefs, + int width, int height) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + g_settings_set_int (prefs->priv->logview_prefs, + PREF_WIDTH, width); + g_settings_set_int (prefs->priv->logview_prefs, + PREF_HEIGHT, height); +} + +void +logview_prefs_get_stored_window_size (LogviewPrefs *prefs, + int *width, int *height) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + *width = g_settings_get_int (prefs->priv->logview_prefs, + PREF_WIDTH); + *height = g_settings_get_int (prefs->priv->logview_prefs, + PREF_HEIGHT); + + if ((*width == 0) ^ (*height == 0)) { + /* if one of the two failed, return default for both */ + *width = LOGVIEW_DEFAULT_WIDTH; + *height = LOGVIEW_DEFAULT_HEIGHT; + } +} + +char * +logview_prefs_get_monospace_font_name (LogviewPrefs *prefs) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + return (g_settings_get_string (prefs->priv->interface_prefs, MATE_MONOSPACE_FONT_NAME)); +} + +gboolean +logview_prefs_get_have_tearoff (LogviewPrefs *prefs) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + return (g_settings_get_boolean (prefs->priv->interface_prefs, MATE_MENUS_HAVE_TEAROFF)); +} + +/* the elements should be freed with g_free () */ + +gchar ** +logview_prefs_get_stored_logfiles (LogviewPrefs *prefs) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + return g_settings_get_strv (prefs->priv->logview_prefs, + PREF_LOGFILES); +} + +void +logview_prefs_store_log (LogviewPrefs *prefs, GFile *file) +{ + gchar **stored_logs; + GFile *stored; + gboolean found = FALSE; + gint idx, old_size; + + g_assert (LOGVIEW_IS_PREFS (prefs)); + g_assert (G_IS_FILE (file)); + + stored_logs = logview_prefs_get_stored_logfiles (prefs); + + for (idx = 0; stored_logs[idx] != NULL; idx++) { + stored = g_file_parse_name (stored_logs[idx]); + if (g_file_equal (file, stored)) { + found = TRUE; + } + + g_object_unref (stored); + + if (found) { + break; + } + } + + if (!found) { + old_size = g_strv_length (stored_logs); + stored_logs = g_realloc (stored_logs, (old_size + 2) * sizeof (gchar *)); + stored_logs[old_size] = g_file_get_parse_name (file); + stored_logs[old_size + 1] = NULL; + + g_settings_set_strv (prefs->priv->logview_prefs, + PREF_LOGFILES, + (const gchar **) stored_logs); + } + + g_strfreev (stored_logs); +} + +void +logview_prefs_remove_stored_log (LogviewPrefs *prefs, GFile *target) +{ + gchar **stored_logs; + GFile *stored; + GPtrArray *new_value; + gint idx; + gboolean removed = FALSE; + + g_assert (LOGVIEW_IS_PREFS (prefs)); + g_assert (G_IS_FILE (target)); + + stored_logs = logview_prefs_get_stored_logfiles (prefs); + new_value = g_ptr_array_new (); + + for (idx = 0; stored_logs[idx] != NULL; idx++) { + stored = g_file_parse_name (stored_logs[idx]); + if (!g_file_equal (stored, target)) { + g_ptr_array_add (new_value, g_strdup (stored_logs[idx])); + } + + g_object_unref (stored); + } + + g_ptr_array_add (new_value, NULL); + g_strfreev (stored_logs); + stored_logs = (gchar **) g_ptr_array_free (new_value, FALSE); + + g_settings_set_strv (prefs->priv->logview_prefs, + PREF_LOGFILES, + (const gchar **) stored_logs); + + g_strfreev (stored_logs); +} + +void +logview_prefs_store_fontsize (LogviewPrefs *prefs, int fontsize) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + g_assert (fontsize > 0); + + g_settings_set_int (prefs->priv->logview_prefs, PREF_FONTSIZE, fontsize); +} + +int +logview_prefs_get_stored_fontsize (LogviewPrefs *prefs) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + return g_settings_get_int (prefs->priv->logview_prefs, PREF_FONTSIZE); +} + +void +logview_prefs_store_active_logfile (LogviewPrefs *prefs, + const char *filename) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + g_settings_set_string (prefs->priv->logview_prefs, + PREF_LOGFILE, filename); +} + +char * +logview_prefs_get_active_logfile (LogviewPrefs *prefs) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + return g_settings_get_string (prefs->priv->logview_prefs, + PREF_LOGFILE); +} + +GList * +logview_prefs_get_filters (LogviewPrefs *prefs) +{ + GList *filters = NULL; + + g_assert (LOGVIEW_IS_PREFS (prefs)); + + g_hash_table_foreach (prefs->priv->filters, + get_filters_foreach, + &filters); + + return filters; +} + +void +logview_prefs_remove_filter (LogviewPrefs *prefs, + const gchar *name) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + g_hash_table_remove (prefs->priv->filters, + name); + + save_filters (prefs); +} + +void +logview_prefs_add_filter (LogviewPrefs *prefs, + LogviewFilter *filter) +{ + gchar* name; + + g_assert (LOGVIEW_IS_PREFS (prefs)); + g_assert (LOGVIEW_IS_FILTER (filter)); + + 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) +{ + g_assert (LOGVIEW_IS_PREFS (prefs)); + + return g_hash_table_lookup (prefs->priv->filters, name); +} + diff --git a/logview/src/logview-prefs.h b/logview/src/logview-prefs.h new file mode 100644 index 00000000..bc9c6608 --- /dev/null +++ b/logview/src/logview-prefs.h @@ -0,0 +1,89 @@ +/* logview-prefs.h - logview user preferences handling + * + * Copyright (C) 2004 Vincent Noel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#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)) +#define LOGVIEW_PREFS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_PREFS, LogviewPrefsClass)) +#define LOGVIEW_IS_PREFS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_PREFS)) +#define LOGVIEW_IS_PREFS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_PREFS)) +#define LOGVIEW_PREFS_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_PREFS, LogviewPrefsClass)) + +typedef struct _LogviewPrefs LogviewPrefs; +typedef struct _LogviewPrefsClass LogviewPrefsClass; +typedef struct _LogviewPrefsPrivate LogviewPrefsPrivate; + +struct _LogviewPrefs { + GObject parent; + LogviewPrefsPrivate *priv; +}; + +struct _LogviewPrefsClass { + GObjectClass parent_class; + + /* signals */ + void (* system_font_changed) (LogviewPrefs *prefs, + 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); +gchar ** 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); + +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__ */ diff --git a/logview/src/logview-utils.c b/logview/src/logview-utils.c new file mode 100644 index 00000000..c8a61ed1 --- /dev/null +++ b/logview/src/logview-utils.c @@ -0,0 +1,282 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-utils.c - misc logview utilities + * + * Copyright (C) 1998 Cesar Miquel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _XOPEN_SOURCE +#define _XOPEN_SOURCE_EXTENDED 1 /* strptime is XPG4v2 */ +#include +#include +#include +#include + +#include + +#include "logview-utils.h" + +void +logview_utils_day_free (Day *day) +{ + if (!day) { + return; + } + + g_date_free (day->date); + g_slice_free (Day, day); +} + +Day * +logview_utils_day_copy (Day *day) +{ + Day *retval; + + retval = g_slice_new0 (Day); + retval->date = g_date_new_julian (g_date_get_julian (day->date)); + retval->first_line = day->first_line; + retval->last_line = day->last_line; + retval->timestamp_len = day->timestamp_len; + + return retval; +} + +GSList * +logview_utils_day_list_copy (GSList *days) +{ + GSList *l, *retval = NULL; + + for (l = days; l; l = l->next) { + retval = g_slist_prepend (retval, logview_utils_day_copy (l->data)); + } + + return g_slist_reverse (retval); +} + +gint +days_compare (gconstpointer a, gconstpointer b) +{ + const Day *day1 = a, *day2 = b; + + return g_date_compare (day1->date, day2->date); +} + +static GDate * +string_get_date (const char *line, char **time_string, int *timestamp_len) +{ + GDate *date = NULL; + struct tm tp; + char *cp = NULL, *timestamp = NULL; + + /* it's safe to assume that if strptime returns NULL, it's + * because of an error (format unmatched). being a log file, it's very + * unlikely that there aren't any more characters after the date. + */ + + if (line == NULL || line[0] == '\0') { + return NULL; + } + + /* this parses the "MonthName DayNo" format */ + cp = strptime (line, "%b %d", &tp); + if (cp) { + goto out; + } + + /* this parses the YYYY-MM-DD format */ + cp = strptime (line, "%F", &tp); + if (cp) { + goto out; + } + +out: + if (cp) { + /* the year doesn't matter to us now */ + date = g_date_new_dmy (tp.tm_mday, tp.tm_mon + 1, 1); + *time_string = g_strndup (line, cp - line); + + timestamp = strptime (cp, "%X", &tp); + if (timestamp) { + *timestamp_len = timestamp - line; + } + } + + return date; +} + +/** + * log_read_dates: + * + * @buffer_lines: an array of text lines. + * @current: the mtime of the file being parsed. + * + * Reads all the dates inside the text buffer. + * All dates are given with respect to the 1/1/1970 + * and are then corrected to the correct year once we + * reach the end. + * + * Returns: a #GSList of #Day structures. + */ + +GSList * +log_read_dates (const char **buffer_lines, time_t current) +{ + int current_year, offsetyear, i, n, rangemin, rangemax, timestamp_len = 0; + GSList *days = NULL; + GDate *date = NULL; + struct tm *tmptm; + char *date_string = NULL; + Day *day; + gboolean done = FALSE; + + g_return_val_if_fail (buffer_lines != NULL, NULL); + + n = g_strv_length ((char **) buffer_lines); + + tmptm = localtime (¤t); + current_year = tmptm->tm_year + 1900; + offsetyear = 0; + + /* find the first line with a date we're able to parse */ + for (i = 0; buffer_lines[i]; i++) { + if ((date = string_get_date (buffer_lines[i], &date_string, ×tamp_len)) != NULL) + break; + } + + if (!date) { + /* no valid dates in the array, return NULL */ + return NULL; + } + + if (!g_date_valid (date)) { + g_date_free (date); + g_free (date_string); + return NULL; + } + + g_date_set_year (date, current_year); + + day = g_slice_new0 (Day); + days = g_slist_append (days, day); + + /* $i now contains the line number for the first good date */ + day->date = date; + day->first_line = i; + day->last_line = -1; + day->timestamp_len = timestamp_len; + + /* now scan the logfile to get the last line of the day */ + rangemin = i; + rangemax = n - 1; + + while (!done) { + /* find out the last line of the day we're currently building */ + + i = n - 1; + + while (day->last_line < 0) { + if (strstr (buffer_lines[i], date_string)) { + /* if we find the same string on the last line of the log, we're done */ + if (i == n - 1) { + done = TRUE; + day->last_line = i; + break; + } + + /* we're still in a section of lines with the same date; + * - if the next one changes, then we're on the last. + * - else we keep searching in the following. + */ + + if (!strstr (buffer_lines[i + 1], date_string)) { + day->last_line = i; + break; + } else { + rangemin = i; + i = floor (((float) i + (float) rangemax) / 2.); + } + } else { + /* we can't find the same date here; go back to a safer range. */ + rangemax = i; + i = floor (((float) rangemin + (float) i) / 2.); + } + } + + g_free (date_string); + date_string = NULL; + + if (!done) { + /* this means we finished the current day but we're not at the end + * of the buffer: reset the parameters for the next day. + */ + GDate *newdate = NULL; + + for (i = day->last_line + 1; buffer_lines[i]; i++) { + if ((newdate = string_get_date (buffer_lines[i], &date_string, ×tamp_len)) != NULL) + break; + } + + if (date_string == NULL && i == n - 1) { + done = TRUE; + } + + /* this will set the last line of the "old" log to either: + * - "n - 1" if we can't find another date + * - the line before the new date else. + */ + day->last_line = i - 1; + + if (newdate) { + /* append a new day to the list */ + + g_date_set_year (newdate, current_year + offsetyear); + + if (g_date_compare (newdate, date) < 1) { + /* this isn't possible, as we're reading the log forward. + * so it means that newdate is the next year. + */ + g_date_add_years (newdate, 1); + offsetyear++; + } + + date = newdate; + day = g_slice_new0 (Day); + days = g_slist_prepend (days, day); + + day->date = date; + day->first_line = i; + day->last_line = -1; + day->timestamp_len = timestamp_len; + rangemin = i; + rangemax = n - 1; + } + } + } + + if (date_string) { + g_free (date_string); + } + + /* sort the days in chronological order */ + days = g_slist_sort (days, days_compare); + + return days; +} diff --git a/logview/src/logview-utils.h b/logview/src/logview-utils.h new file mode 100644 index 00000000..27242917 --- /dev/null +++ b/logview/src/logview-utils.h @@ -0,0 +1,40 @@ +/* logview-utils.h - misc logview utilities + * + * Copyright (C) 1998 Cesar Miquel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 551 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + */ + +#ifndef __LOGVIEW_UTILS_H__ +#define __LOGVIEW_UTILS_H__ + +#include + +typedef struct { + GDate *date; + int first_line; + int last_line; + int timestamp_len; +} Day; + +GSList * log_read_dates (const char **buffer_lines, time_t current); +gint days_compare (gconstpointer a, gconstpointer b); +void logview_utils_day_free (Day *day); +Day * logview_utils_day_copy (Day *day); +GSList * logview_utils_day_list_copy (GSList *days); + + +#endif /* __LOGVIEW_UTILS_H__ */ \ No newline at end of file diff --git a/logview/src/logview-window.c b/logview/src/logview-window.c new file mode 100644 index 00000000..d0728f92 --- /dev/null +++ b/logview/src/logview-window.c @@ -0,0 +1,1548 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ +/* logview-window.c - main window of logview + * + * Copyright (C) 1998 Cesar Miquel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "logview-window.h" + +#include "logview-loglist.h" +#include "logview-findbar.h" +#include "logview-about.h" +#include "logview-prefs.h" +#include "logview-manager.h" +#include "logview-filter-manager.h" + +#define APP_NAME _("System Log Viewer") +#define SEARCH_START_MARK "lw-search-start-mark" +#define SEARCH_END_MARK "lw-search-end-mark" + +struct _LogviewWindowPrivate { + GtkUIManager *ui_manager; + GtkActionGroup *action_group; + GtkActionGroup *filter_action_group; + + GtkWidget *find_bar; + GtkWidget *loglist; + GtkWidget *sidebar; + GtkWidget *version_bar; + GtkWidget *version_selector; + GtkWidget *hpaned; + GtkWidget *text_view; + GtkWidget *statusbar; + + GtkWidget *message_area; + GtkWidget *message_primary; + GtkWidget *message_secondary; + + GtkTextTagTable *tag_table; + + int original_fontsize, fontsize; + + LogviewPrefs *prefs; + LogviewManager *manager; + + gulong monitor_id; + guint search_timeout_id; + + GCancellable *read_cancellable; + + guint filter_merge_id; + GList *active_filters; + gboolean matches_only; +}; + +#define GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_WINDOW, LogviewWindowPrivate)) + +G_DEFINE_TYPE (LogviewWindow, logview_window, GTK_TYPE_WINDOW); + +static void findbar_close_cb (LogviewFindbar *findbar, + gpointer user_data); +static void read_new_lines_cb (LogviewLog *log, + const char **lines, + GSList *new_days, + GError *error, + gpointer user_data); + +/* private functions */ + +static void +logview_version_selector_changed (GtkComboBox *version_selector, gpointer user_data) +{ + +} +#if 0 + LogviewWindow *logview = user_data; + Log *log = logview->curlog; + int selected; + + g_assert (LOGVIEW_IS_WINDOW (logview)); + + selected = gtk_combo_box_get_active (version_selector); + + if (selected == log->current_version) + return; + + /* select a new version */ + if (selected == 0) { + logview_select_log (logview, log->parent_log); + } else { + Log *new; + if (log->parent_log) { + new = log->parent_log->older_logs[selected]; + } else { + new = log->older_logs[selected]; + } + + logview_select_log (logview, new); + } +} + +#endif + +/* private helpers */ + +static void +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); + + gtk_text_tag_table_add (tag_table, tag); + + 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); +} + + +static void +populate_style_tag_table (GtkStyle *style, + GtkTextTagTable *tag_table) +{ + GtkTextTag *tag; + GdkColor color; + + tag = gtk_text_tag_table_lookup (tag_table, "gray"); + + if (tag) { + /* FIXME: do we need a way to update the buffer/view? */ + gtk_text_tag_table_remove (tag_table, tag); + } + + tag = gtk_text_tag_new ("gray"); + color = style->text[GTK_STATE_INSENSITIVE]; + g_object_set (tag, "foreground-gdk", &color, "foreground-set", TRUE, NULL); + + gtk_text_tag_table_add (tag_table, tag); +} + +static void +_gtk_text_buffer_apply_tag_to_rectangle (GtkTextBuffer *buffer, int line_start, int line_end, + int offset_start, int offset_end, char *tag_name) +{ + GtkTextIter start, end; + int line_cur; + + gtk_text_buffer_get_iter_at_line (buffer, &start, line_start); + gtk_text_buffer_get_iter_at_line (buffer, &end, line_start); + + for (line_cur = line_start; line_cur < line_end + 1; line_cur++) { + + if (offset_start > 0) { + gtk_text_iter_forward_chars (&start, offset_start); + } + + gtk_text_iter_forward_chars (&end, offset_end); + + gtk_text_buffer_apply_tag_by_name (buffer, tag_name, &start, &end); + + gtk_text_iter_forward_line (&start); + gtk_text_iter_forward_line (&end); + } +} + +static void +logview_update_statusbar (LogviewWindow *logview, LogviewLog *active) +{ + char *statusbar_text; + char *size, *modified, *timestring_utf8; + time_t timestamp; + char timestring[255]; + + if (active == NULL) { + gtk_statusbar_pop (GTK_STATUSBAR (logview->priv->statusbar), 0); + return; + } + + timestamp = logview_log_get_timestamp (active); + strftime (timestring, sizeof (timestring), "%a %b %e %T %Y", localtime (×tamp)); + timestring_utf8 = g_locale_to_utf8 (timestring, -1, NULL, NULL, NULL); + + modified = g_strdup_printf (_("last update: %s"), timestring_utf8); + + size = g_format_size (logview_log_get_file_size (active)); + + statusbar_text = g_strdup_printf (_("%d lines (%s) - %s"), + logview_log_get_cached_lines_number (active), + size, modified); + + gtk_statusbar_pop (GTK_STATUSBAR (logview->priv->statusbar), 0); + gtk_statusbar_push (GTK_STATUSBAR (logview->priv->statusbar), 0, statusbar_text); + + g_free (size); + g_free (timestring_utf8); + g_free (modified); + g_free (statusbar_text); +} + +#define DEFAULT_LOGVIEW_FONT "Monospace 10" + +static void +logview_set_font (LogviewWindow *logview, + const char *fontname) +{ + PangoFontDescription *font_desc; + + if (fontname == NULL) + fontname = DEFAULT_LOGVIEW_FONT; + + font_desc = pango_font_description_from_string (fontname); + if (font_desc) { + gtk_widget_modify_font (logview->priv->text_view, font_desc); + pango_font_description_free (font_desc); + } +} + +static void +logview_set_fontsize (LogviewWindow *logview, gboolean store) +{ + PangoFontDescription *fontdesc; + PangoContext *context; + LogviewWindowPrivate *priv = logview->priv; + + context = gtk_widget_get_pango_context (priv->text_view); + fontdesc = pango_context_get_font_description (context); + pango_font_description_set_size (fontdesc, (priv->fontsize) * PANGO_SCALE); + gtk_widget_modify_font (priv->text_view, fontdesc); + + if (store) { + logview_prefs_store_fontsize (logview->priv->prefs, priv->fontsize); + } +} + +static void +logview_set_window_title (LogviewWindow *logview, const char * log_name) +{ + char *window_title; + + if (log_name) { + window_title = g_strdup_printf ("%s - %s", log_name, APP_NAME); + } else { + window_title = g_strdup_printf (APP_NAME); + } + + gtk_window_set_title (GTK_WINDOW (logview), window_title); + + g_free (window_title); +} + +/* actions callbacks */ + +static void +open_file_selected_cb (GtkWidget *chooser, gint response, LogviewWindow *logview) +{ + GFile *f; + char *file_uri; + LogviewLog *log; + + gtk_widget_hide (GTK_WIDGET (chooser)); + if (response != GTK_RESPONSE_OK) { + return; + } + + f = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (chooser)); + file_uri = g_file_get_uri (f); + + log = logview_manager_get_if_loaded (logview->priv->manager, file_uri); + + g_free (file_uri); + + if (log) { + logview_manager_set_active_log (logview->priv->manager, log); + g_object_unref (log); + goto out; + } + + logview_manager_add_log_from_gfile (logview->priv->manager, f, TRUE); + +out: + g_object_unref (f); +} + +static void +logview_open_log (GtkAction *action, LogviewWindow *logview) +{ + static GtkWidget *chooser = NULL; + char *active; + + if (chooser == NULL) { + chooser = gtk_file_chooser_dialog_new (_("Open Log"), + GTK_WINDOW (logview), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_OK, + NULL); + gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK); + gtk_window_set_modal (GTK_WINDOW (chooser), TRUE); + g_signal_connect (chooser, "response", + G_CALLBACK (open_file_selected_cb), logview); + g_signal_connect (chooser, "destroy", + G_CALLBACK (gtk_widget_destroyed), &chooser); + active = logview_prefs_get_active_logfile (logview->priv->prefs); + if (active != NULL) { + gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), active); + g_free (active); + } + } + + gtk_window_present (GTK_WINDOW (chooser)); +} + +static void +logview_close_log (GtkAction *action, LogviewWindow *logview) +{ + findbar_close_cb (LOGVIEW_FINDBAR (logview->priv->find_bar), logview); + logview_manager_close_active_log (logview->priv->manager); +} + +static void +logview_help (GtkAction *action, GtkWidget *parent_window) +{ + GError *error = NULL; + + gtk_show_uri (gtk_widget_get_screen (parent_window), + "help:mate-system-log", gtk_get_current_event_time (), + &error); + + if (error) { + g_warning (_("There was an error displaying help: %s"), error->message); + g_error_free (error); + } +} + +static void +logview_bigger_text (GtkAction *action, LogviewWindow *logview) +{ + logview->priv->fontsize = MIN (logview->priv->fontsize + 1, 24); + logview_set_fontsize (logview, TRUE); +} + +static void +logview_smaller_text (GtkAction *action, LogviewWindow *logview) +{ + logview->priv->fontsize = MAX (logview->priv->fontsize-1, 6); + logview_set_fontsize (logview, TRUE); +} + +static void +logview_normal_text (GtkAction *action, LogviewWindow *logview) +{ + logview->priv->fontsize = logview->priv->original_fontsize; + logview_set_fontsize (logview, TRUE); +} + +static void +logview_select_all (GtkAction *action, LogviewWindow *logview) +{ + GtkTextIter start, end; + GtkTextBuffer *buffer; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); + + gtk_text_buffer_get_bounds (buffer, &start, &end); + gtk_text_buffer_select_range (buffer, &start, &end); + + gtk_widget_grab_focus (GTK_WIDGET (logview->priv->text_view)); +} + +static void +logview_copy (GtkAction *action, LogviewWindow *logview) +{ + GtkTextBuffer *buffer; + GtkClipboard *clipboard; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + + gtk_text_buffer_copy_clipboard (buffer, clipboard); + + gtk_widget_grab_focus (GTK_WIDGET (logview->priv->text_view)); +} + +static void +findbar_close_cb (LogviewFindbar *findbar, + gpointer user_data) +{ + gtk_widget_hide (GTK_WIDGET (findbar)); + logview_findbar_set_message (findbar, NULL); +} + +static void +logview_search_text (LogviewWindow *logview, gboolean forward) +{ + GtkTextBuffer *buffer; + GtkTextMark *search_start, *search_end; + GtkTextIter search, start_m, end_m; + const char *text; + gboolean res, wrapped; + + wrapped = FALSE; + + text = logview_findbar_get_text (LOGVIEW_FINDBAR (logview->priv->find_bar)); + + if (!text || g_strcmp0 (text, "") == 0) { + return; + } + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); + search_start = gtk_text_buffer_get_mark (buffer, SEARCH_START_MARK); + search_end = gtk_text_buffer_get_mark (buffer, SEARCH_END_MARK); + + if (!search_start) { + /* this is our first search on the buffer, create a new search mark */ + gtk_text_buffer_get_start_iter (buffer, &search); + search_start = gtk_text_buffer_create_mark (buffer, SEARCH_START_MARK, + &search, TRUE); + search_end = gtk_text_buffer_create_mark (buffer, SEARCH_END_MARK, + &search, TRUE); + } else { + if (forward) { + gtk_text_buffer_get_iter_at_mark (buffer, &search, search_end); + } else { + gtk_text_buffer_get_iter_at_mark (buffer, &search, search_start); + } + } + +wrap: + + if (forward) { + res = gtk_text_iter_forward_search (&search, text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start_m, &end_m, NULL); + } else { + res = gtk_text_iter_backward_search (&search, text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start_m, &end_m, NULL); + } + + if (res) { + gtk_text_buffer_select_range (buffer, &start_m, &end_m); + gtk_text_buffer_move_mark (buffer, search_start, &start_m); + gtk_text_buffer_move_mark (buffer, search_end, &end_m); + + gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (logview->priv->text_view), search_end); + + if (wrapped) { + logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), _("Wrapped")); + } + } else { + if (wrapped) { + + GtkTextMark *mark; + GtkTextIter iter; + + if (gtk_text_buffer_get_has_selection (buffer)) { + /* unselect */ + mark = gtk_text_buffer_get_mark (buffer, "insert"); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark); + gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter); + } + + logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), _("Not found")); + } else { + if (forward) { + gtk_text_buffer_get_start_iter (buffer, &search); + } else { + gtk_text_buffer_get_end_iter (buffer, &search); + } + + wrapped = TRUE; + goto wrap; + } + } +} + +static void +findbar_previous_cb (LogviewFindbar *findbar, + gpointer user_data) +{ + LogviewWindow *logview = user_data; + + logview_search_text (logview, FALSE); +} + +static void +findbar_next_cb (LogviewFindbar *findbar, + gpointer user_data) +{ + LogviewWindow *logview = user_data; + + logview_search_text (logview, TRUE); +} + +static gboolean +text_changed_timeout_cb (gpointer user_data) +{ + LogviewWindow *logview = user_data; + GtkTextMark *search_start, *search_end; + GtkTextIter start; + GtkTextBuffer *buffer; + + logview->priv->search_timeout_id = 0; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); + search_start = gtk_text_buffer_get_mark (buffer, SEARCH_START_MARK); + search_end = gtk_text_buffer_get_mark (buffer, SEARCH_END_MARK); + + if (search_start) { + /* reset the search mark to the start */ + gtk_text_buffer_get_start_iter (buffer, &start); + gtk_text_buffer_move_mark (buffer, search_start, &start); + gtk_text_buffer_move_mark (buffer, search_end, &start); + } + + logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), NULL); + + logview_search_text (logview, TRUE); + + return FALSE; +} + +static void +findbar_text_changed_cb (LogviewFindbar *findbar, + gpointer user_data) +{ + LogviewWindow *logview = user_data; + + if (logview->priv->search_timeout_id != 0) { + g_source_remove (logview->priv->search_timeout_id); + } + + logview->priv->search_timeout_id = g_timeout_add (300, text_changed_timeout_cb, logview); +} + +static void +logview_search (GtkAction *action, LogviewWindow *logview) +{ + logview_findbar_open (LOGVIEW_FINDBAR (logview->priv->find_bar)); +} + +static void +filter_buffer (LogviewWindow *logview, gint start_line) +{ + GtkTextBuffer *buffer; + GtkTextIter start, *end; + gchar* text; + GList* cur_filter; + gboolean matched; + int lines, i; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); + lines = gtk_text_buffer_get_line_count (buffer); + + for (i = start_line; i < lines; i++) { + matched = FALSE; + + gtk_text_buffer_get_iter_at_line (buffer, &start, i); + end = gtk_text_iter_copy (&start); + gtk_text_iter_forward_line (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; + } + } + + g_free (text); + + 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); + } + + gtk_text_iter_free (end); + } +} + +static void +filter_remove (LogviewWindow *logview, LogviewFilter *filter) +{ + GtkTextIter start, end; + GtkTextBuffer *buffer; + + 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; + LogviewFilter *filter; + + 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 (priv->prefs, + name)); + filter_buffer(logview, 0); + } else { + filter = logview_prefs_get_filter (priv->prefs, 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; + guint id; + GList *filters; + GtkTextBuffer *buffer; + GtkTextTagTable *table; + GtkTextTag *tag; + GtkToggleAction *action; + gchar* name; + + 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)) { + 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)) { + 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); + } + + g_list_free (filters); + + priv->filter_merge_id = id; +} + +static void +on_logview_filter_manager_response (GtkDialog *dialog, + gint response, + LogviewWindow *logview) +{ + update_filter_menu (logview); + + g_list_free (logview->priv->active_filters); + logview->priv->active_filters = NULL; +} + +static void +logview_manage_filters (GtkAction *action, LogviewWindow *logview) +{ + GtkWidget *manager; + + manager = logview_filter_manager_new (); + + g_signal_connect (manager, "response", + G_CALLBACK (on_logview_filter_manager_response), + logview); + + gtk_window_set_transient_for (GTK_WINDOW (manager), + GTK_WINDOW (logview)); + gtk_widget_show (GTK_WIDGET (manager)); +} + +static void +logview_about (GtkWidget *widget, GtkWidget *window) +{ + g_return_if_fail (GTK_IS_WINDOW (window)); + + char *license_trans = g_strjoin ("\n\n", _(logview_about_license[0]), + _(logview_about_license[1]), + _(logview_about_license[2]), NULL); + + gtk_show_about_dialog (GTK_WINDOW (window), + "name", _("System Log Viewer"), + "version", VERSION, + "copyright", "Copyright \xc2\xa9 1998-2008 Free Software Foundation, Inc.", + "license", license_trans, + "wrap-license", TRUE, + "comments", _("A system log viewer for MATE."), + "authors", logview_about_authors, + "documenters", logview_about_documenters, + "translator_credits", strcmp (logview_about_translator_credits, + "translator-credits") != 0 ? + logview_about_translator_credits : NULL, + "logo_icon_name", "mate-system-log", + NULL); + g_free (license_trans); + + return; +} + +static void +logview_toggle_statusbar (GtkAction *action, LogviewWindow *logview) +{ + if (gtk_widget_get_visible (logview->priv->statusbar)) + gtk_widget_hide (logview->priv->statusbar); + else + gtk_widget_show (logview->priv->statusbar); +} + +static void +logview_toggle_sidebar (GtkAction *action, LogviewWindow *logview) +{ + if (gtk_widget_get_visible (logview->priv->sidebar)) + gtk_widget_hide (logview->priv->sidebar); + else + 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 */ + +static GtkActionEntry entries[] = { + { "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..."), "O", N_("Open a log from file"), + G_CALLBACK (logview_open_log) }, + { "CloseLog", GTK_STOCK_CLOSE, N_("_Close"), "W", N_("Close this log"), + G_CALLBACK (logview_close_log) }, + { "Quit", GTK_STOCK_QUIT, N_("_Quit"), "Q", N_("Quit the log viewer"), + G_CALLBACK (gtk_main_quit) }, + + { "Copy", GTK_STOCK_COPY, N_("_Copy"), "C", N_("Copy the selection"), + G_CALLBACK (logview_copy) }, + { "SelectAll", NULL, N_("Select _All"), "A", N_("Select the entire log"), + G_CALLBACK (logview_select_all) }, + { "Search", GTK_STOCK_FIND, N_("_Find..."), "F", N_("Find a word or phrase in the log"), + G_CALLBACK (logview_search) }, + + { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "plus", N_("Bigger text size"), + G_CALLBACK (logview_bigger_text)}, + { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "minus", N_("Smaller text size"), + G_CALLBACK (logview_smaller_text)}, + { "ViewZoom100", GTK_STOCK_ZOOM_100, NULL, "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"), + G_CALLBACK (logview_about) }, +}; + +static GtkToggleActionEntry toggle_entries[] = { + { "ShowStatusBar", NULL, N_("_Statusbar"), NULL, N_("Show Status Bar"), + 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 +window_size_changed_cb (GtkWidget *widget, GdkEventConfigure *event, + gpointer data) +{ + LogviewWindow *window = data; + + logview_prefs_store_window_size (window->priv->prefs, + event->width, event->height); + + return FALSE; +} + +static void +real_select_day (LogviewWindow *logview, + GDate *date, int first_line, int last_line) +{ + GtkTextBuffer *buffer; + GtkTextIter start_iter, end_iter, start_vis, end_vis; + GdkRectangle visible_rect; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); + + gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter); + gtk_text_buffer_get_iter_at_line (buffer, &start_vis, first_line); + gtk_text_buffer_get_iter_at_line (buffer, &end_vis, last_line + 1); + + /* clear all previous invisible tags */ + gtk_text_buffer_remove_tag_by_name (buffer, "invisible", + &start_iter, &end_iter); + + gtk_text_buffer_apply_tag_by_name (buffer, "invisible", + &start_iter, &start_vis); + gtk_text_buffer_apply_tag_by_name (buffer, "invisible", + &end_vis, &end_iter); + + /* FIXME: why is this needed to update the view when selecting a day back? */ + gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (logview->priv->text_view), + &visible_rect); + gdk_window_invalidate_rect (gtk_widget_get_window (logview->priv->text_view), + &visible_rect, TRUE); +} + +static void +loglist_day_selected_cb (LogviewLoglist *loglist, + Day *day, + gpointer user_data) +{ + LogviewWindow *logview = user_data; + + real_select_day (logview, day->date, day->first_line, day->last_line); +} + +static void +loglist_day_cleared_cb (LogviewLoglist *loglist, + gpointer user_data) +{ + LogviewWindow *logview = user_data; + GtkTextBuffer *buffer; + GtkTextIter start, end; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view)); + gtk_text_buffer_get_bounds (buffer, &start, &end); + + /* clear all previous invisible tags */ + gtk_text_buffer_remove_tag_by_name (buffer, "invisible", + &start, &end); +} + +static void +logview_window_schedule_log_read (LogviewWindow *window, + LogviewLog *log) +{ + if (window->priv->read_cancellable != NULL) { + g_cancellable_cancel (window->priv->read_cancellable); + g_clear_object (&window->priv->read_cancellable); + } + + window->priv->read_cancellable = g_cancellable_new (); + logview_log_read_new_lines (log, + window->priv->read_cancellable, + (LogviewNewLinesCallback) read_new_lines_cb, + window); +} + +static void +log_monitor_changed_cb (LogviewLog *log, + gpointer user_data) +{ + LogviewWindow *window = user_data; + + /* reschedule a read */ + logview_window_schedule_log_read (window, log); +} + +static void +paint_timestamps (GtkTextBuffer *buffer, int old_line_count, + GSList *days) +{ + GSList *l; + + for (l = days; l; l = l->next) { + Day *day = l->data; + + _gtk_text_buffer_apply_tag_to_rectangle (buffer, + old_line_count + day->first_line - 1, + old_line_count + day->last_line, + 0, day->timestamp_len, "gray"); + } +} + +static void +read_new_lines_cb (LogviewLog *log, + const char **lines, + GSList *new_days, + GError *error, + gpointer user_data) +{ + LogviewWindow *window = user_data; + GtkTextBuffer *buffer; + gboolean boldify = FALSE; + int i, old_line_count, filter_start_line; + GtkTextIter iter, start; + GtkTextMark *mark; + char *converted, *primary; + gsize len; + + if (error != NULL) { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + primary = g_strdup_printf (_("Can't read from \"%s\""), + logview_log_get_display_name (log)); + logview_window_add_error (window, primary, error->message); + g_free (primary); + } + + return; + } + + if (lines == NULL) { + /* there's no error, but no lines have been read */ + return; + } + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->priv->text_view)); + old_line_count = gtk_text_buffer_get_line_count (buffer); + filter_start_line = old_line_count > 0 ? (old_line_count - 1) : 0; + + if (gtk_text_buffer_get_char_count (buffer) != 0) { + boldify = TRUE; + } + + gtk_text_buffer_get_end_iter (buffer, &iter); + + if (boldify) { + mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE); + } + + for (i = 0; lines[i]; i++) { + len = strlen (lines[i]); + + if (!g_utf8_validate (lines[i], len, NULL)) { + converted = g_locale_to_utf8 (lines[i], (gssize) len, NULL, &len, NULL); + gtk_text_buffer_insert (buffer, &iter, converted, len); + g_free (converted); + } else { + gtk_text_buffer_insert (buffer, &iter, lines[i], strlen (lines[i])); + } + + gtk_text_iter_forward_to_end (&iter); + gtk_text_buffer_insert (buffer, &iter, "\n", 1); + gtk_text_iter_forward_char (&iter); + } + + if (boldify) { + gtk_text_buffer_get_iter_at_mark (buffer, &start, mark); + gtk_text_buffer_apply_tag_by_name (buffer, "bold", &start, &iter); + gtk_text_buffer_delete_mark (buffer, mark); + } + filter_buffer (window, filter_start_line); + + gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (window->priv->text_view), + &iter, 0.0, FALSE, 0.0, 0.0); + + paint_timestamps (buffer, old_line_count, new_days); + + if (window->priv->monitor_id == 0) { + window->priv->monitor_id = g_signal_connect (log, "log-changed", + G_CALLBACK (log_monitor_changed_cb), window); + } + + logview_update_statusbar (window, log); + logview_loglist_update_lines (LOGVIEW_LOGLIST (window->priv->loglist), log); +} + +static void +active_log_changed_cb (LogviewManager *manager, + LogviewLog *log, + LogviewLog *old_log, + gpointer data) +{ + LogviewWindow *window = data; + const char **lines; + GtkTextBuffer *buffer; + + findbar_close_cb (LOGVIEW_FINDBAR (window->priv->find_bar), + window); + + logview_set_window_title (window, logview_log_get_display_name (log)); + + if (window->priv->monitor_id) { + g_signal_handler_disconnect (old_log, window->priv->monitor_id); + window->priv->monitor_id = 0; + } + + lines = logview_log_get_cached_lines (log); + buffer = gtk_text_buffer_new (window->priv->tag_table); + + if (lines != NULL) { + int i; + GtkTextIter iter; + + /* update the text view to show the current lines */ + gtk_text_buffer_get_end_iter (buffer, &iter); + + for (i = 0; lines[i]; i++) { + gtk_text_buffer_insert (buffer, &iter, lines[i], strlen (lines[i])); + gtk_text_iter_forward_to_end (&iter); + gtk_text_buffer_insert (buffer, &iter, "\n", 1); + gtk_text_iter_forward_char (&iter); + } + + paint_timestamps (buffer, 1, logview_log_get_days_for_cached_lines (log)); + } + + if (lines == NULL || logview_log_has_new_lines (log)) { + /* read the new lines */ + logview_window_schedule_log_read (window, log); + } else { + /* start now monitoring the log for changes */ + window->priv->monitor_id = g_signal_connect (log, "log-changed", + G_CALLBACK (log_monitor_changed_cb), window); + } + + /* we set the buffer to the view anyway; + * if there are no lines it will be empty for the duration of the thread + * and will help us to distinguish the two cases of the following if + * cause in the callback. + */ + gtk_text_view_set_buffer (GTK_TEXT_VIEW (window->priv->text_view), buffer); + g_object_unref (buffer); +} + +static void +font_changed_cb (LogviewPrefs *prefs, + const char *font_name, + gpointer user_data) +{ + LogviewWindow *window = user_data; + + logview_set_font (window, font_name); +} + +static void +tearoff_changed_cb (LogviewPrefs *prefs, + gboolean have_tearoffs, + gpointer user_data) +{ + LogviewWindow *window = user_data; + + gtk_ui_manager_set_add_tearoffs (window->priv->ui_manager, have_tearoffs); +} + +static void +style_set_cb (GtkWidget *widget, + GtkStyle *prev, + gpointer user_data) +{ + LogviewWindow *logview = user_data; + GtkStyle *style = gtk_widget_get_style (widget); + + populate_style_tag_table (style, logview->priv->tag_table); +} + +static const struct { + guint keyval; + GdkModifierType modifier; + const gchar *action; +} extra_keybindings [] = { + { GDK_KEY_KP_Add, GDK_CONTROL_MASK, "ViewZoomIn" }, + { GDK_KEY_KP_Subtract, GDK_CONTROL_MASK, "ViewZoomOut" }, + { GDK_KEY_KP_0, GDK_CONTROL_MASK, "ViewZoom100" } +}; + +static gboolean +key_press_event_cb (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + LogviewWindow *window = user_data; + guint modifier = event->state & gtk_accelerator_get_default_mod_mask (); + GtkAction *action; + int i; + + /* handle accelerators that we want bound, but aren't associated with + * an action */ + for (i = 0; i < G_N_ELEMENTS (extra_keybindings); i++) { + if (event->keyval == extra_keybindings[i].keyval && + modifier == extra_keybindings[i].modifier) { + + action = gtk_action_group_get_action (window->priv->action_group, + extra_keybindings[i].action); + gtk_action_activate (action); + return TRUE; + } + } + + return FALSE; +} + +/* adapted from GEdit */ + +static void +message_area_create_error_box (LogviewWindow *window, + GtkWidget *message_area) +{ + GtkWidget *hbox_content; + GtkWidget *image; + GtkWidget *vbox; + GtkWidget *primary_label; + GtkWidget *secondary_label; + + hbox_content = gtk_hbox_new (FALSE, 8); + gtk_widget_show (hbox_content); + + image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, + GTK_ICON_SIZE_DIALOG); + gtk_widget_show (image); + gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0); + gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0); + + vbox = gtk_vbox_new (FALSE, 6); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0); + + primary_label = gtk_label_new (NULL); + gtk_widget_show (primary_label); + gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0); + gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5); + gtk_widget_set_can_focus (primary_label, TRUE); + gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE); + + window->priv->message_primary = primary_label; + + secondary_label = gtk_label_new (NULL); + gtk_widget_show (secondary_label); + gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0); + gtk_widget_set_can_focus (secondary_label, TRUE); + gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE); + gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE); + gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5); + + window->priv->message_secondary = secondary_label; + + gtk_container_add + (GTK_CONTAINER (gtk_info_bar_get_content_area + (GTK_INFO_BAR (message_area))), + hbox_content); +} + +static void +message_area_set_labels (LogviewWindow *window, + const char *primary, + const char *secondary) +{ + char *primary_markup, *secondary_markup; + + primary_markup = g_markup_printf_escaped ("%s", primary); + secondary_markup = g_markup_printf_escaped ("%s", + secondary); + + gtk_label_set_markup (GTK_LABEL (window->priv->message_primary), + primary_markup); + gtk_label_set_markup (GTK_LABEL (window->priv->message_secondary), + secondary_markup); + + g_free (primary_markup); + g_free (secondary_markup); +} + +static void +message_area_response_cb (GtkInfoBar *message_area, + int response_id, gpointer user_data) +{ + gtk_widget_hide (GTK_WIDGET (message_area)); + + g_signal_handlers_disconnect_by_func (message_area, + message_area_response_cb, + user_data); +} + +static void +logview_window_finalize (GObject *object) +{ + LogviewWindow *logview = LOGVIEW_WINDOW (object); + + if (logview->priv->read_cancellable != NULL) { + g_cancellable_cancel (logview->priv->read_cancellable); + g_clear_object (&logview->priv->read_cancellable); + } + + g_object_unref (logview->priv->ui_manager); + G_OBJECT_CLASS (logview_window_parent_class)->finalize (object); +} + +static void +logview_window_init (LogviewWindow *logview) +{ + GtkActionGroup *action_group; + GtkAccelGroup *accel_group; + GError *error = NULL; + GtkWidget *hpaned, *main_view, *vbox, *w; + PangoContext *context; + PangoFontDescription *fontdesc; + gchar *monospace_font_name; + LogviewWindowPrivate *priv; + int width, height; + gboolean res; + + priv = logview->priv = GET_PRIVATE (logview); + priv->prefs = logview_prefs_get (); + priv->manager = logview_manager_get (); + priv->monitor_id = 0; + + logview_prefs_get_stored_window_size (priv->prefs, &width, &height); + gtk_window_set_default_size (GTK_WINDOW (logview), width, height); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (logview), vbox); + + /* create menus */ + action_group = gtk_action_group_new ("LogviewMenuActions"); + gtk_action_group_set_translation_domain (action_group, NULL); + gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), logview); + gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), logview); + priv->action_group = action_group; + + priv->ui_manager = gtk_ui_manager_new (); + + gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, 0); + accel_group = gtk_ui_manager_get_accel_group (priv->ui_manager); + gtk_window_add_accel_group (GTK_WINDOW (logview), accel_group); + + res = gtk_ui_manager_add_ui_from_file (priv->ui_manager, + LOGVIEW_DATADIR "/logview-toolbar.xml", + &error); + + if (res == FALSE) { + priv->ui_manager = NULL; + g_critical ("Can't load the UI description: %s", error->message); + g_error_free (error); + return; + } + + gtk_ui_manager_set_add_tearoffs (priv->ui_manager, + logview_prefs_get_have_tearoff (priv->prefs)); + + w = gtk_ui_manager_get_widget (priv->ui_manager, "/LogviewMenu"); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); + gtk_widget_show (w); + + /* panes */ +#if GTK_CHECK_VERSION (3, 0, 0) + hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); +#else + hpaned = gtk_hpaned_new (); +#endif + gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0); + priv->hpaned = hpaned; + gtk_widget_show (hpaned); + + /* first pane : sidebar (list of logs) */ + priv->sidebar = gtk_vbox_new (FALSE, 0); + gtk_widget_show (priv->sidebar); + + /* first pane: log list */ + w = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), + GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), + GTK_SHADOW_ETCHED_IN); + + priv->loglist = logview_loglist_new (); + gtk_container_add (GTK_CONTAINER (w), priv->loglist); + gtk_box_pack_start (GTK_BOX (priv->sidebar), w, TRUE, TRUE, 0); + gtk_paned_pack1 (GTK_PANED (hpaned), priv->sidebar, FALSE, FALSE); + gtk_widget_show (w); + gtk_widget_show (priv->loglist); + + g_signal_connect (priv->loglist, "day_selected", + G_CALLBACK (loglist_day_selected_cb), logview); + g_signal_connect (priv->loglist, "day_cleared", + G_CALLBACK (loglist_day_cleared_cb), logview); + + /* second pane: log */ + main_view = gtk_vbox_new (FALSE, 0); + gtk_paned_pack2 (GTK_PANED (hpaned), main_view, TRUE, TRUE); + + /* second pane: error message area */ + priv->message_area = gtk_info_bar_new (); + message_area_create_error_box (logview, priv->message_area); + gtk_info_bar_add_button (GTK_INFO_BAR (priv->message_area), + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); + gtk_box_pack_start (GTK_BOX (main_view), priv->message_area, FALSE, FALSE, 0); + + /* second pane: text view */ + w = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (main_view), w, TRUE, TRUE, 0); + gtk_widget_show (w); + + priv->tag_table = gtk_text_tag_table_new (); + populate_tag_table (priv->tag_table); + priv->text_view = gtk_text_view_new (); + g_object_set (priv->text_view, "editable", FALSE, NULL); + + gtk_container_add (GTK_CONTAINER (w), priv->text_view); + gtk_widget_show (priv->text_view); + + /* use the desktop monospace font */ + monospace_font_name = logview_prefs_get_monospace_font_name (priv->prefs); + logview_set_font (logview, monospace_font_name); + g_free (monospace_font_name); + + /* remember the original font size */ + context = gtk_widget_get_pango_context (priv->text_view); + fontdesc = pango_context_get_font_description (context); + priv->original_fontsize = pango_font_description_get_size (fontdesc) / PANGO_SCALE; + + /* restore saved zoom */ + priv->fontsize = logview_prefs_get_stored_fontsize (priv->prefs); + + if (priv->fontsize <= 0) { + /* restore the default */ + logview_normal_text (NULL, logview); + } else { + logview_set_fontsize (logview, FALSE); + } + + /* version selector */ + priv->version_bar = gtk_hbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (priv->version_bar), 3); + priv->version_selector = gtk_combo_box_text_new (); + g_signal_connect (priv->version_selector, "changed", + G_CALLBACK (logview_version_selector_changed), logview); + w = gtk_label_new (_("Version: ")); + + gtk_box_pack_end (GTK_BOX (priv->version_bar), priv->version_selector, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->version_bar), w, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (main_view), priv->version_bar, FALSE, FALSE, 0); + + priv->find_bar = logview_findbar_new (); + gtk_box_pack_end (GTK_BOX (main_view), priv->find_bar, FALSE, FALSE, 0); + + g_signal_connect (priv->find_bar, "previous", + G_CALLBACK (findbar_previous_cb), logview); + g_signal_connect (priv->find_bar, "next", + G_CALLBACK (findbar_next_cb), logview); + g_signal_connect (priv->find_bar, "text_changed", + G_CALLBACK (findbar_text_changed_cb), logview); + g_signal_connect (priv->find_bar, "close", + G_CALLBACK (findbar_close_cb), logview); + + /* signal handlers + * - first is used to remember/restore the window size on quit. + */ + g_signal_connect (logview, "configure_event", + G_CALLBACK (window_size_changed_cb), logview); + g_signal_connect (priv->prefs, "system-font-changed", + G_CALLBACK (font_changed_cb), logview); + g_signal_connect (priv->prefs, "have-tearoff-changed", + G_CALLBACK (tearoff_changed_cb), logview); + g_signal_connect (priv->manager, "active-changed", + G_CALLBACK (active_log_changed_cb), logview); + g_signal_connect (logview, "style-set", + G_CALLBACK (style_set_cb), logview); + g_signal_connect (logview, "key-press-event", + G_CALLBACK (key_press_event_cb), logview); + + /* status area at bottom */ + priv->statusbar = gtk_statusbar_new (); +#if GTK_CHECK_VERSION (3, 0, 0) + gtk_widget_set_margin_top (GTK_WIDGET (logview->priv->statusbar), 0); + gtk_widget_set_margin_bottom (GTK_WIDGET (logview->priv->statusbar), 0); +#endif + 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); +} + +static void +logview_window_class_init (LogviewWindowClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + + object_class->finalize = logview_window_finalize; + + g_type_class_add_private (klass, sizeof (LogviewWindowPrivate)); +} + +/* public methods */ + +GtkWidget * +logview_window_new () +{ + LogviewWindow *logview; + + logview = g_object_new (LOGVIEW_TYPE_WINDOW, NULL); + + if (logview->priv->ui_manager == NULL) { + return NULL; + } + + return GTK_WIDGET (logview); +} + +void +logview_window_add_error (LogviewWindow *window, + const char *primary, + const char *secondary) +{ + LogviewWindowPrivate *priv; + + g_assert (LOGVIEW_IS_WINDOW (window)); + priv = window->priv; + + message_area_set_labels (window, + primary, secondary); + + gtk_widget_show (priv->message_area); + + g_signal_connect (priv->message_area, "response", + G_CALLBACK (message_area_response_cb), window); +} + +void +logview_window_add_errors (LogviewWindow *window, + GPtrArray *errors) +{ + char *primary, *secondary; + GString *str; + char **err; + int i; + + g_assert (LOGVIEW_IS_WINDOW (window)); + g_assert (errors->len > 1); + + primary = g_strdup (_("Could not open the following files:")); + str = g_string_new (NULL); + + for (i = 0; i < errors->len; i++) { + err = (char **) g_ptr_array_index (errors, i); + g_string_append (str, err[0]); + g_string_append (str, ": "); + g_string_append (str, err[1]); + g_string_append (str, "\n"); + } + + secondary = g_string_free (str, FALSE); + + message_area_set_labels (window, primary, secondary); + + gtk_widget_show (window->priv->message_area); + + g_signal_connect (window->priv->message_area, "response", + G_CALLBACK (message_area_response_cb), window); + + g_free (primary); + g_free (secondary); +} + + diff --git a/logview/src/logview-window.h b/logview/src/logview-window.h new file mode 100644 index 00000000..f9fd5303 --- /dev/null +++ b/logview/src/logview-window.h @@ -0,0 +1,56 @@ +/* logview-window.h - main window of logview + * + * Copyright (C) 1998 Cesar Miquel + * Copyright (C) 2008 Cosimo Cecchi + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __LOGVIEW_WINDOW_H__ +#define __LOGVIEW_WINDOW_H__ + +#include + +#define LOGVIEW_TYPE_WINDOW (logview_window_get_type ()) +#define LOGVIEW_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_WINDOW, LogviewWindow)) +#define LOGVIEW_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_WINDOW, LogviewWindowClass)) +#define LOGVIEW_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_WINDOW)) +#define LOGVIEW_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), LOGVIEW_TYPE_WINDOW)) +#define LOGVIEW_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_WINDOW, LogviewWindowClass)) + +typedef struct _LogviewWindow LogviewWindow; +typedef struct _LogviewWindowClass LogviewWindowClass; +typedef struct _LogviewWindowPrivate LogviewWindowPrivate; + +struct _LogviewWindow { + GtkWindow parent_instance; + LogviewWindowPrivate *priv; +}; + +struct _LogviewWindowClass { + GtkWindowClass parent_class; +}; + +GType logview_window_get_type (void); + +/* public methods */ +GtkWidget * logview_window_new (void); +void logview_window_add_error (LogviewWindow *window, + const char *primary, + const char *secondary); +void logview_window_add_errors (LogviewWindow *window, + GPtrArray *errors); + +#endif /* __LOGVIEW_WINDOW_H__ */ diff --git a/logview/src/tests/Makefile.am b/logview/src/tests/Makefile.am new file mode 100644 index 00000000..b7b668c3 --- /dev/null +++ b/logview/src/tests/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = \ + $(GLIB_CFLAGS) \ + $(GIO_CFLAGS) \ + -I../ + +noinst_PROGRAMS = test-reader + +test_reader_SOURCES = test-reader.c ../logview-log.c ../logview-utils.c +test_reader_LDADD = $(GLIB_LIBS) $(GIO_LIBS) $(Z_LIBS) -lm diff --git a/logview/src/tests/test-reader.c b/logview/src/tests/test-reader.c new file mode 100644 index 00000000..b9ef5d40 --- /dev/null +++ b/logview/src/tests/test-reader.c @@ -0,0 +1,60 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "../logview-log.h" +#include "../logview-utils.h" + +#include +#include + +static GMainLoop *loop; + +static void +new_lines_cb (LogviewLog *log, + const char **lines, + GSList *new_days, + GError *error, + gpointer user_data) +{ + int i; + guint8 day; + Day *day_s; + GSList *days, *l; + + for (i = 0; lines[i]; i++) { + g_print ("line %d: %s\n", i, lines[i]); + } + g_print ("outside read, lines no %u\n", logview_log_get_cached_lines_number (log)); + + days = log_read_dates (lines, logview_log_get_timestamp (log)); + g_print ("\ndays %p\n", days); + + for (l = days; l; l = l->next) { + day_s = l->data; + g_print ("\nday %u month %u\n", g_date_get_day (day_s->date), g_date_get_month (day_s->date)); + } + + g_object_unref (log); + + g_main_loop_quit (loop); +} + +static void +callback (LogviewLog *log, + GError *error, + gpointer user_data) +{ + g_print ("callback! err %p, log %p\n", error, log); + + logview_log_read_new_lines (log, NULL, new_lines_cb, NULL); +} + +int main (int argc, char **argv) +{ + loop = g_main_loop_new (NULL, FALSE); + logview_log_create ("/var/log/dpkg.log.2.gz", callback, NULL); + g_main_loop_run (loop); + + return 0; +} diff --git a/logview/tests/Makefile.am b/logview/tests/Makefile.am deleted file mode 100644 index b7b668c3..00000000 --- a/logview/tests/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -AM_CPPFLAGS = \ - $(GLIB_CFLAGS) \ - $(GIO_CFLAGS) \ - -I../ - -noinst_PROGRAMS = test-reader - -test_reader_SOURCES = test-reader.c ../logview-log.c ../logview-utils.c -test_reader_LDADD = $(GLIB_LIBS) $(GIO_LIBS) $(Z_LIBS) -lm diff --git a/logview/tests/test-reader.c b/logview/tests/test-reader.c deleted file mode 100644 index b9ef5d40..00000000 --- a/logview/tests/test-reader.c +++ /dev/null @@ -1,60 +0,0 @@ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "../logview-log.h" -#include "../logview-utils.h" - -#include -#include - -static GMainLoop *loop; - -static void -new_lines_cb (LogviewLog *log, - const char **lines, - GSList *new_days, - GError *error, - gpointer user_data) -{ - int i; - guint8 day; - Day *day_s; - GSList *days, *l; - - for (i = 0; lines[i]; i++) { - g_print ("line %d: %s\n", i, lines[i]); - } - g_print ("outside read, lines no %u\n", logview_log_get_cached_lines_number (log)); - - days = log_read_dates (lines, logview_log_get_timestamp (log)); - g_print ("\ndays %p\n", days); - - for (l = days; l; l = l->next) { - day_s = l->data; - g_print ("\nday %u month %u\n", g_date_get_day (day_s->date), g_date_get_month (day_s->date)); - } - - g_object_unref (log); - - g_main_loop_quit (loop); -} - -static void -callback (LogviewLog *log, - GError *error, - gpointer user_data) -{ - g_print ("callback! err %p, log %p\n", error, log); - - logview_log_read_new_lines (log, NULL, new_lines_cb, NULL); -} - -int main (int argc, char **argv) -{ - loop = g_main_loop_new (NULL, FALSE); - logview_log_create ("/var/log/dpkg.log.2.gz", callback, NULL); - g_main_loop_run (loop); - - return 0; -} diff --git a/po/POTFILES.in b/po/POTFILES.in index 18be842e..1ce32a0c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -25,14 +25,14 @@ libeggsmclient/eggsmclient.c logview/data/mate-system-log.desktop.in.in [type: gettext/gsettings]logview/data/org.mate.system-log.gschema.xml.in [type: gettext/glade]logview/data/logview-filter.ui -logview/logview-about.h -logview/logview-app.c -logview/logview-filter-manager.c -logview/logview-findbar.c -logview/logview-log.c -logview/logview-loglist.c -logview/logview-main.c -logview/logview-window.c +logview/src/logview-about.h +logview/src/logview-app.c +logview/src/logview-filter-manager.c +logview/src/logview-findbar.c +logview/src/logview-log.c +logview/src/logview-loglist.c +logview/src/logview-main.c +logview/src/logview-window.c mate-dictionary/data/default.desktop.in mate-dictionary/data/mate-dictionary.desktop.in.in mate-dictionary/data/mate-dictionary.appdata.xml.in -- cgit v1.2.1