Updated Spanish translation
[gnome-utils.git] / logview / logview-window.c
blob9398cf8e8fac06771b936a493e68506112ad2842
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* logview-window.c - main window of logview
4 * Copyright (C) 1998 Cesar Miquel <miquel@df.uba.ar>
5 * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <config.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <gtk/gtk.h>
26 #include <gdk/gdkkeysyms.h>
27 #include <glib/gi18n.h>
29 #include "logview-window.h"
31 #include "logview-loglist.h"
32 #include "logview-findbar.h"
33 #include "logview-about.h"
34 #include "logview-prefs.h"
35 #include "logview-manager.h"
36 #include "logview-filter-manager.h"
38 #define APP_NAME _("System Log Viewer")
39 #define SEARCH_START_MARK "lw-search-start-mark"
40 #define SEARCH_END_MARK "lw-search-end-mark"
42 struct _LogviewWindowPrivate {
43 GtkUIManager *ui_manager;
44 GtkActionGroup *action_group;
45 GtkActionGroup *filter_action_group;
47 GtkWidget *find_bar;
48 GtkWidget *loglist;
49 GtkWidget *sidebar;
50 GtkWidget *version_bar;
51 GtkWidget *version_selector;
52 GtkWidget *hpaned;
53 GtkWidget *text_view;
54 GtkWidget *statusbar;
56 GtkWidget *message_area;
57 GtkWidget *message_primary;
58 GtkWidget *message_secondary;
60 GtkTextTagTable *tag_table;
62 int original_fontsize, fontsize;
64 LogviewPrefs *prefs;
65 LogviewManager *manager;
67 gulong monitor_id;
68 guint search_timeout_id;
70 guint filter_merge_id;
71 GList *active_filters;
72 gboolean matches_only;
73 gboolean auto_scroll;
76 #define GET_PRIVATE(o) \
77 (G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_WINDOW, LogviewWindowPrivate))
79 G_DEFINE_TYPE (LogviewWindow, logview_window, GTK_TYPE_WINDOW);
81 static void findbar_close_cb (LogviewFindbar *findbar,
82 gpointer user_data);
83 static void read_new_lines_cb (LogviewLog *log,
84 const char **lines,
85 GSList *new_days,
86 GError *error,
87 gpointer user_data);
89 /* private functions */
91 static void
92 logview_version_selector_changed (GtkComboBox *version_selector, gpointer user_data)
96 #if 0
97 LogviewWindow *logview = user_data;
98 Log *log = logview->curlog;
99 int selected;
101 g_assert (LOGVIEW_IS_WINDOW (logview));
103 selected = gtk_combo_box_get_active (version_selector);
105 if (selected == log->current_version)
106 return;
108 /* select a new version */
109 if (selected == 0) {
110 logview_select_log (logview, log->parent_log);
111 } else {
112 Log *new;
113 if (log->parent_log) {
114 new = log->parent_log->older_logs[selected];
115 } else {
116 new = log->older_logs[selected];
119 logview_select_log (logview, new);
123 #endif
125 /* private helpers */
127 static void
128 populate_tag_table (GtkTextTagTable *tag_table)
130 GtkTextTag *tag;
132 tag = gtk_text_tag_new ("bold");
133 g_object_set (tag, "weight", PANGO_WEIGHT_BOLD,
134 "weight-set", TRUE, NULL);
136 gtk_text_tag_table_add (tag_table, tag);
138 tag = gtk_text_tag_new ("invisible");
139 g_object_set (tag, "invisible", TRUE, "invisible-set", TRUE, NULL);
140 gtk_text_tag_table_add (tag_table, tag);
142 tag = gtk_text_tag_new ("invisible-filter");
143 g_object_set (tag, "invisible", TRUE, "invisible-set", TRUE, NULL);
144 gtk_text_tag_table_add (tag_table, tag);
148 static void
149 populate_style_tag_table (GtkStyle *style,
150 GtkTextTagTable *tag_table)
152 GtkTextTag *tag;
153 GdkColor color;
155 tag = gtk_text_tag_table_lookup (tag_table, "gray");
157 if (tag) {
158 /* FIXME: do we need a way to update the buffer/view? */
159 gtk_text_tag_table_remove (tag_table, tag);
162 tag = gtk_text_tag_new ("gray");
163 color = style->text[GTK_STATE_INSENSITIVE];
164 g_object_set (tag, "foreground-gdk", &color, "foreground-set", TRUE, NULL);
166 gtk_text_tag_table_add (tag_table, tag);
169 static void
170 _gtk_text_buffer_apply_tag_to_rectangle (GtkTextBuffer *buffer, int line_start, int line_end,
171 int offset_start, int offset_end, char *tag_name)
173 GtkTextIter start, end;
174 int line_cur;
176 gtk_text_buffer_get_iter_at_line (buffer, &start, line_start);
177 gtk_text_buffer_get_iter_at_line (buffer, &end, line_start);
179 for (line_cur = line_start; line_cur < line_end + 1; line_cur++) {
181 if (offset_start > 0) {
182 gtk_text_iter_forward_chars (&start, offset_start);
185 gtk_text_iter_forward_chars (&end, offset_end);
187 gtk_text_buffer_apply_tag_by_name (buffer, tag_name, &start, &end);
189 gtk_text_iter_forward_line (&start);
190 gtk_text_iter_forward_line (&end);
194 static void
195 logview_update_statusbar (LogviewWindow *logview, LogviewLog *active)
197 char *statusbar_text;
198 char *size, *modified, *timestring_utf8;
199 time_t timestamp;
200 char timestring[255];
202 if (active == NULL) {
203 gtk_statusbar_pop (GTK_STATUSBAR (logview->priv->statusbar), 0);
204 return;
207 timestamp = logview_log_get_timestamp (active);
208 strftime (timestring, sizeof (timestring), "%a %b %e %T %Y", localtime (&timestamp));
209 timestring_utf8 = g_locale_to_utf8 (timestring, -1, NULL, NULL, NULL);
211 modified = g_strdup_printf (_("last update: %s"), timestring_utf8);
213 size = g_format_size_for_display (logview_log_get_file_size (active));
214 statusbar_text = g_strdup_printf (_("%d lines (%s) - %s"),
215 logview_log_get_cached_lines_number (active),
216 size, modified);
218 gtk_statusbar_pop (GTK_STATUSBAR (logview->priv->statusbar), 0);
219 gtk_statusbar_push (GTK_STATUSBAR (logview->priv->statusbar), 0, statusbar_text);
221 g_free (size);
222 g_free (timestring_utf8);
223 g_free (modified);
224 g_free (statusbar_text);
227 #define DEFAULT_LOGVIEW_FONT "Monospace 10"
229 static void
230 logview_set_font (LogviewWindow *logview,
231 const char *fontname)
233 PangoFontDescription *font_desc;
235 if (fontname == NULL)
236 fontname = DEFAULT_LOGVIEW_FONT;
238 font_desc = pango_font_description_from_string (fontname);
239 if (font_desc) {
240 gtk_widget_modify_font (logview->priv->text_view, font_desc);
241 pango_font_description_free (font_desc);
245 static void
246 logview_set_fontsize (LogviewWindow *logview, gboolean store)
248 PangoFontDescription *fontdesc;
249 PangoContext *context;
250 LogviewWindowPrivate *priv = logview->priv;
252 context = gtk_widget_get_pango_context (priv->text_view);
253 fontdesc = pango_context_get_font_description (context);
254 pango_font_description_set_size (fontdesc, (priv->fontsize) * PANGO_SCALE);
255 gtk_widget_modify_font (priv->text_view, fontdesc);
257 if (store) {
258 logview_prefs_store_fontsize (logview->priv->prefs, priv->fontsize);
262 static void
263 logview_set_window_title (LogviewWindow *logview, const char * log_name)
265 char *window_title;
267 if (log_name) {
268 window_title = g_strdup_printf ("%s - %s", log_name, APP_NAME);
269 } else {
270 window_title = g_strdup_printf (APP_NAME);
273 gtk_window_set_title (GTK_WINDOW (logview), window_title);
275 g_free (window_title);
278 /* actions callbacks */
280 static void
281 open_file_selected_cb (GtkWidget *chooser, gint response, LogviewWindow *logview)
283 GFile *f;
284 char *file_uri;
285 LogviewLog *log;
287 gtk_widget_hide (GTK_WIDGET (chooser));
288 if (response != GTK_RESPONSE_OK) {
289 return;
292 f = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (chooser));
293 file_uri = g_file_get_uri (f);
295 log = logview_manager_get_if_loaded (logview->priv->manager, file_uri);
297 g_free (file_uri);
299 if (log) {
300 logview_manager_set_active_log (logview->priv->manager, log);
301 g_object_unref (log);
302 goto out;
305 logview_manager_add_log_from_gfile (logview->priv->manager, f, TRUE);
307 out:
308 g_object_unref (f);
311 static void
312 logview_open_log (GtkAction *action, LogviewWindow *logview)
314 static GtkWidget *chooser = NULL;
315 char *active;
317 if (chooser == NULL) {
318 chooser = gtk_file_chooser_dialog_new (_("Open Log"),
319 GTK_WINDOW (logview),
320 GTK_FILE_CHOOSER_ACTION_OPEN,
321 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
322 GTK_STOCK_OPEN, GTK_RESPONSE_OK,
323 NULL);
324 gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
325 gtk_window_set_modal (GTK_WINDOW (chooser), TRUE);
326 g_signal_connect (chooser, "response",
327 G_CALLBACK (open_file_selected_cb), logview);
328 g_signal_connect (chooser, "destroy",
329 G_CALLBACK (gtk_widget_destroyed), &chooser);
330 active = logview_prefs_get_active_logfile (logview->priv->prefs);
331 if (active != NULL) {
332 gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), active);
333 g_free (active);
337 gtk_window_present (GTK_WINDOW (chooser));
340 static void
341 logview_close_log (GtkAction *action, LogviewWindow *logview)
343 findbar_close_cb (LOGVIEW_FINDBAR (logview->priv->find_bar), logview);
344 logview_manager_close_active_log (logview->priv->manager);
347 static void
348 logview_help (GtkAction *action, GtkWidget *parent_window)
350 GError *error = NULL;
352 gtk_show_uri (gtk_widget_get_screen (parent_window),
353 "ghelp:gnome-system-log", gtk_get_current_event_time (),
354 &error);
356 if (error) {
357 g_warning (_("There was an error displaying help: %s"), error->message);
358 g_error_free (error);
362 static void
363 logview_bigger_text (GtkAction *action, LogviewWindow *logview)
365 logview->priv->fontsize = MIN (logview->priv->fontsize + 1, 24);
366 logview_set_fontsize (logview, TRUE);
369 static void
370 logview_smaller_text (GtkAction *action, LogviewWindow *logview)
372 logview->priv->fontsize = MAX (logview->priv->fontsize-1, 6);
373 logview_set_fontsize (logview, TRUE);
376 static void
377 logview_normal_text (GtkAction *action, LogviewWindow *logview)
379 logview->priv->fontsize = logview->priv->original_fontsize;
380 logview_set_fontsize (logview, TRUE);
383 static void
384 logview_select_all (GtkAction *action, LogviewWindow *logview)
386 GtkTextIter start, end;
387 GtkTextBuffer *buffer;
389 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
391 gtk_text_buffer_get_bounds (buffer, &start, &end);
392 gtk_text_buffer_select_range (buffer, &start, &end);
394 gtk_widget_grab_focus (GTK_WIDGET (logview->priv->text_view));
397 static void
398 logview_copy (GtkAction *action, LogviewWindow *logview)
400 GtkTextBuffer *buffer;
401 GtkClipboard *clipboard;
403 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
404 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
406 gtk_text_buffer_copy_clipboard (buffer, clipboard);
408 gtk_widget_grab_focus (GTK_WIDGET (logview->priv->text_view));
411 static void
412 findbar_close_cb (LogviewFindbar *findbar,
413 gpointer user_data)
415 gtk_widget_hide (GTK_WIDGET (findbar));
416 logview_findbar_set_message (findbar, NULL);
419 static void
420 logview_search_text (LogviewWindow *logview, gboolean forward)
422 GtkTextBuffer *buffer;
423 GtkTextMark *search_start, *search_end;
424 GtkTextIter search, start_m, end_m;
425 const char *text;
426 gboolean res, wrapped;
428 wrapped = FALSE;
430 text = logview_findbar_get_text (LOGVIEW_FINDBAR (logview->priv->find_bar));
432 if (!text || g_strcmp0 (text, "") == 0) {
433 return;
436 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
437 search_start = gtk_text_buffer_get_mark (buffer, SEARCH_START_MARK);
438 search_end = gtk_text_buffer_get_mark (buffer, SEARCH_END_MARK);
440 if (!search_start) {
441 /* this is our first search on the buffer, create a new search mark */
442 gtk_text_buffer_get_start_iter (buffer, &search);
443 search_start = gtk_text_buffer_create_mark (buffer, SEARCH_START_MARK,
444 &search, TRUE);
445 search_end = gtk_text_buffer_create_mark (buffer, SEARCH_END_MARK,
446 &search, TRUE);
447 } else {
448 if (forward) {
449 gtk_text_buffer_get_iter_at_mark (buffer, &search, search_end);
450 } else {
451 gtk_text_buffer_get_iter_at_mark (buffer, &search, search_start);
455 wrap:
457 if (forward) {
458 res = gtk_text_iter_forward_search (&search, text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start_m, &end_m, NULL);
459 } else {
460 res = gtk_text_iter_backward_search (&search, text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start_m, &end_m, NULL);
463 if (res) {
464 gtk_text_buffer_select_range (buffer, &start_m, &end_m);
465 gtk_text_buffer_move_mark (buffer, search_start, &start_m);
466 gtk_text_buffer_move_mark (buffer, search_end, &end_m);
468 gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (logview->priv->text_view), search_end);
470 if (wrapped) {
471 logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), _("Wrapped"));
473 } else {
474 if (wrapped) {
476 GtkTextMark *mark;
477 GtkTextIter iter;
479 if (gtk_text_buffer_get_has_selection (buffer)) {
480 /* unselect */
481 mark = gtk_text_buffer_get_mark (buffer, "insert");
482 gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
483 gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter);
486 logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), _("Not found"));
487 } else {
488 if (forward) {
489 gtk_text_buffer_get_start_iter (buffer, &search);
490 } else {
491 gtk_text_buffer_get_end_iter (buffer, &search);
494 wrapped = TRUE;
495 goto wrap;
500 static void
501 findbar_previous_cb (LogviewFindbar *findbar,
502 gpointer user_data)
504 LogviewWindow *logview = user_data;
506 logview_search_text (logview, FALSE);
509 static void
510 findbar_next_cb (LogviewFindbar *findbar,
511 gpointer user_data)
513 LogviewWindow *logview = user_data;
515 logview_search_text (logview, TRUE);
518 static gboolean
519 text_changed_timeout_cb (gpointer user_data)
521 LogviewWindow *logview = user_data;
522 GtkTextMark *search_start, *search_end;
523 GtkTextIter start;
524 GtkTextBuffer *buffer;
526 logview->priv->search_timeout_id = 0;
528 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
529 search_start = gtk_text_buffer_get_mark (buffer, SEARCH_START_MARK);
530 search_end = gtk_text_buffer_get_mark (buffer, SEARCH_END_MARK);
532 if (search_start) {
533 /* reset the search mark to the start */
534 gtk_text_buffer_get_start_iter (buffer, &start);
535 gtk_text_buffer_move_mark (buffer, search_start, &start);
536 gtk_text_buffer_move_mark (buffer, search_end, &start);
539 logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), NULL);
541 logview_search_text (logview, TRUE);
543 return FALSE;
546 static void
547 findbar_text_changed_cb (LogviewFindbar *findbar,
548 gpointer user_data)
550 LogviewWindow *logview = user_data;
552 if (logview->priv->search_timeout_id != 0) {
553 g_source_remove (logview->priv->search_timeout_id);
556 logview->priv->search_timeout_id = g_timeout_add (300, text_changed_timeout_cb, logview);
559 static void
560 logview_search (GtkAction *action, LogviewWindow *logview)
562 logview_findbar_open (LOGVIEW_FINDBAR (logview->priv->find_bar));
565 static void
566 filter_buffer (LogviewWindow *logview, gint start_line)
568 GtkTextBuffer *buffer;
569 GtkTextIter start, *end;
570 gchar* text;
571 GList* cur_filter;
572 gboolean matched;
573 int lines, i;
575 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
576 lines = gtk_text_buffer_get_line_count (buffer);
578 for (i = start_line; i < lines; i++) {
579 matched = FALSE;
581 gtk_text_buffer_get_iter_at_line (buffer, &start, i);
582 end = gtk_text_iter_copy (&start);
583 gtk_text_iter_forward_line (end);
585 text = gtk_text_buffer_get_text (buffer, &start, end, TRUE);
587 for (cur_filter = logview->priv->active_filters; cur_filter != NULL;
588 cur_filter = g_list_next (cur_filter))
590 if (logview_filter_filter (LOGVIEW_FILTER (cur_filter->data), text)) {
591 gtk_text_buffer_apply_tag (buffer,
592 logview_filter_get_tag (LOGVIEW_FILTER (cur_filter->data)),
593 &start, end);
594 matched = TRUE;
598 g_free (text);
600 if (!matched && logview->priv->matches_only) {
601 gtk_text_buffer_apply_tag_by_name (buffer,
602 "invisible-filter",
603 &start, end);
604 } else {
605 gtk_text_buffer_remove_tag_by_name (buffer,
606 "invisible-filter",
607 &start, end);
610 gtk_text_iter_free (end);
614 static void
615 filter_remove (LogviewWindow *logview, LogviewFilter *filter)
617 GtkTextIter start, end;
618 GtkTextBuffer *buffer;
620 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
621 gtk_text_buffer_get_bounds (buffer, &start, &end);
623 gtk_text_buffer_remove_tag (buffer, logview_filter_get_tag (filter),
624 &start, &end);
627 static void
628 on_filter_toggled (GtkToggleAction *action, LogviewWindow *logview)
630 LogviewWindowPrivate *priv = GET_PRIVATE (logview);
631 const gchar* name;
632 LogviewFilter *filter;
634 name = gtk_action_get_name (GTK_ACTION (action));
636 if (gtk_toggle_action_get_active (action)) {
637 priv->active_filters = g_list_append (priv->active_filters,
638 logview_prefs_get_filter (priv->prefs,
639 name));
640 filter_buffer(logview, 0);
641 } else {
642 filter = logview_prefs_get_filter (priv->prefs, name);
643 priv->active_filters = g_list_remove (priv->active_filters,
644 filter);
646 filter_remove (logview, filter);
650 #define FILTER_PLACEHOLDER "/LogviewMenu/FilterMenu/PlaceholderFilters"
651 static void
652 update_filter_menu (LogviewWindow *window)
654 LogviewWindowPrivate *priv;
655 GtkUIManager* ui;
656 GList *actions, *l;
657 guint id;
658 GList *filters;
659 GtkTextBuffer *buffer;
660 GtkTextTagTable *table;
661 GtkTextTag *tag;
662 GtkToggleAction *action;
663 gchar* name;
665 priv = GET_PRIVATE (window);
666 ui = priv->ui_manager;
668 g_return_if_fail (priv->filter_action_group != NULL);
670 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
671 table = priv->tag_table;
673 if (priv->filter_merge_id != 0) {
674 gtk_ui_manager_remove_ui (ui,
675 priv->filter_merge_id);
678 actions = gtk_action_group_list_actions (priv->filter_action_group);
680 for (l = actions; l != NULL; l = g_list_next (l)) {
681 tag = gtk_text_tag_table_lookup (table, gtk_action_get_name (GTK_ACTION (l->data)));
682 gtk_text_tag_table_remove (table, tag);
684 g_signal_handlers_disconnect_by_func (GTK_ACTION (l->data),
685 G_CALLBACK (on_filter_toggled),
686 window);
687 gtk_action_group_remove_action (priv->filter_action_group,
688 GTK_ACTION (l->data));
691 g_list_free (actions);
693 filters = logview_prefs_get_filters (logview_prefs_get ());
695 id = (g_list_length (filters) > 0) ? gtk_ui_manager_new_merge_id (ui) : 0;
697 for (l = filters; l != NULL; l = g_list_next (l)) {
698 g_object_get (l->data, "name", &name, NULL);
700 action = gtk_toggle_action_new (name, name, NULL, NULL);
701 gtk_action_group_add_action (priv->filter_action_group,
702 GTK_ACTION (action));
704 g_signal_connect (action,
705 "toggled",
706 G_CALLBACK (on_filter_toggled),
707 window);
709 gtk_ui_manager_add_ui (ui, id, FILTER_PLACEHOLDER,
710 name, name, GTK_UI_MANAGER_MENUITEM, FALSE);
711 gtk_text_tag_table_add (table,
712 logview_filter_get_tag (LOGVIEW_FILTER (l->data)));
714 g_object_unref (action);
715 g_free(name);
718 g_list_free (filters);
720 priv->filter_merge_id = id;
723 static void
724 on_logview_filter_manager_response (GtkDialog *dialog,
725 gint response,
726 LogviewWindow *logview)
728 update_filter_menu (logview);
730 g_list_free (logview->priv->active_filters);
731 logview->priv->active_filters = NULL;
734 static void
735 logview_manage_filters (GtkAction *action, LogviewWindow *logview)
737 GtkWidget *manager;
739 manager = logview_filter_manager_new ();
741 g_signal_connect (manager, "response",
742 G_CALLBACK (on_logview_filter_manager_response),
743 logview);
745 gtk_window_set_transient_for (GTK_WINDOW (manager),
746 GTK_WINDOW (logview));
747 gtk_widget_show (GTK_WIDGET (manager));
750 static void
751 logview_about (GtkWidget *widget, GtkWidget *window)
753 g_return_if_fail (GTK_IS_WINDOW (window));
755 char *license_trans = g_strjoin ("\n\n", _(logview_about_license[0]),
756 _(logview_about_license[1]),
757 _(logview_about_license[2]), NULL);
759 gtk_show_about_dialog (GTK_WINDOW (window),
760 "name", _("System Log Viewer"),
761 "version", VERSION,
762 "copyright", "Copyright \xc2\xa9 1998-2008 Free Software Foundation, Inc.",
763 "license", license_trans,
764 "wrap-license", TRUE,
765 "comments", _("A system log viewer for GNOME."),
766 "authors", logview_about_authors,
767 "documenters", logview_about_documenters,
768 "translator_credits", strcmp (logview_about_translator_credits,
769 "translator-credits") != 0 ?
770 logview_about_translator_credits : NULL,
771 "logo_icon_name", "logview",
772 NULL);
773 g_free (license_trans);
775 return;
778 static void
779 logview_toggle_statusbar (GtkAction *action, LogviewWindow *logview)
781 if (gtk_widget_get_visible (logview->priv->statusbar))
782 gtk_widget_hide (logview->priv->statusbar);
783 else
784 gtk_widget_show (logview->priv->statusbar);
787 static void
788 logview_toggle_sidebar (GtkAction *action, LogviewWindow *logview)
790 if (gtk_widget_get_visible (logview->priv->sidebar))
791 gtk_widget_hide (logview->priv->sidebar);
792 else
793 gtk_widget_show (logview->priv->sidebar);
796 static void
797 logview_toggle_match_filters (GtkToggleAction *action, LogviewWindow *logview)
799 logview->priv->matches_only = gtk_toggle_action_get_active (action);
800 filter_buffer (logview, 0);
803 static void
804 logview_toggle_autoscroll (GtkToggleAction *action, LogviewWindow *logview)
806 logview->priv->auto_scroll = gtk_toggle_action_get_active (action);
809 /* GObject functions */
811 /* Menus */
813 static GtkActionEntry entries[] = {
814 { "FileMenu", NULL, N_("_File"), NULL, NULL, NULL },
815 { "EditMenu", NULL, N_("_Edit"), NULL, NULL, NULL },
816 { "ViewMenu", NULL, N_("_View"), NULL, NULL, NULL },
817 { "FilterMenu", NULL, N_("_Filters"), NULL, NULL, NULL },
818 { "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
820 { "OpenLog", GTK_STOCK_OPEN, N_("_Open..."), "<control>O", N_("Open a log from file"),
821 G_CALLBACK (logview_open_log) },
822 { "CloseLog", GTK_STOCK_CLOSE, N_("_Close"), "<control>W", N_("Close this log"),
823 G_CALLBACK (logview_close_log) },
824 { "Quit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", N_("Quit the log viewer"),
825 G_CALLBACK (gtk_main_quit) },
827 { "Copy", GTK_STOCK_COPY, N_("_Copy"), "<control>C", N_("Copy the selection"),
828 G_CALLBACK (logview_copy) },
829 { "SelectAll", NULL, N_("Select _All"), "<Control>A", N_("Select the entire log"),
830 G_CALLBACK (logview_select_all) },
831 { "Search", GTK_STOCK_FIND, N_("_Find..."), "<control>F", N_("Find a word or phrase in the log"),
832 G_CALLBACK (logview_search) },
834 { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus", N_("Bigger text size"),
835 G_CALLBACK (logview_bigger_text)},
836 { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus", N_("Smaller text size"),
837 G_CALLBACK (logview_smaller_text)},
838 { "ViewZoom100", GTK_STOCK_ZOOM_100, NULL, "<control>0", N_("Normal text size"),
839 G_CALLBACK (logview_normal_text)},
841 { "FilterManage", NULL, N_("Manage Filters"), NULL, N_("Manage filters"),
842 G_CALLBACK (logview_manage_filters)},
844 { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", N_("Open the help contents for the log viewer"),
845 G_CALLBACK (logview_help) },
846 { "AboutAction", GTK_STOCK_ABOUT, N_("_About"), NULL, N_("Show the about dialog for the log viewer"),
847 G_CALLBACK (logview_about) },
850 static GtkToggleActionEntry toggle_entries[] = {
851 { "ShowStatusBar", NULL, N_("_Statusbar"), NULL, N_("Show Status Bar"),
852 G_CALLBACK (logview_toggle_statusbar), TRUE },
853 { "ShowSidebar", NULL, N_("Side _Pane"), "F9", N_("Show Side Pane"),
854 G_CALLBACK (logview_toggle_sidebar), TRUE },
855 { "FilterMatchOnly", NULL, N_("Show matches only"), NULL, N_("Only show lines that match one of the given filters"),
856 G_CALLBACK (logview_toggle_match_filters), FALSE },
857 { "AutoScroll", NULL, N_("_Auto Scroll"), "F8", N_("Automatically scroll down when new lines appear"),
858 G_CALLBACK (logview_toggle_autoscroll), TRUE }
861 static gboolean
862 window_size_changed_cb (GtkWidget *widget, GdkEventConfigure *event,
863 gpointer data)
865 LogviewWindow *window = data;
867 logview_prefs_store_window_size (window->priv->prefs,
868 event->width, event->height);
870 return FALSE;
873 static void
874 real_select_day (LogviewWindow *logview,
875 GDate *date, int first_line, int last_line)
877 GtkTextBuffer *buffer;
878 GtkTextIter start_iter, end_iter, start_vis, end_vis;
879 GdkRectangle visible_rect;
881 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
883 gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
884 gtk_text_buffer_get_iter_at_line (buffer, &start_vis, first_line);
885 gtk_text_buffer_get_iter_at_line (buffer, &end_vis, last_line + 1);
887 /* clear all previous invisible tags */
888 gtk_text_buffer_remove_tag_by_name (buffer, "invisible",
889 &start_iter, &end_iter);
891 gtk_text_buffer_apply_tag_by_name (buffer, "invisible",
892 &start_iter, &start_vis);
893 gtk_text_buffer_apply_tag_by_name (buffer, "invisible",
894 &end_vis, &end_iter);
896 /* FIXME: why is this needed to update the view when selecting a day back? */
897 gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (logview->priv->text_view),
898 &visible_rect);
899 gdk_window_invalidate_rect (gtk_widget_get_window (logview->priv->text_view),
900 &visible_rect, TRUE);
903 static void
904 loglist_day_selected_cb (LogviewLoglist *loglist,
905 Day *day,
906 gpointer user_data)
908 LogviewWindow *logview = user_data;
910 real_select_day (logview, day->date, day->first_line, day->last_line);
913 static void
914 loglist_day_cleared_cb (LogviewLoglist *loglist,
915 gpointer user_data)
917 LogviewWindow *logview = user_data;
918 GtkTextBuffer *buffer;
919 GtkTextIter start, end;
921 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
922 gtk_text_buffer_get_bounds (buffer, &start, &end);
924 /* clear all previous invisible tags */
925 gtk_text_buffer_remove_tag_by_name (buffer, "invisible",
926 &start, &end);
929 static void
930 log_monitor_changed_cb (LogviewLog *log,
931 gpointer user_data)
933 /* reschedule a read */
934 logview_log_read_new_lines (log, (LogviewNewLinesCallback) read_new_lines_cb,
935 user_data);
938 static void
939 paint_timestamps (GtkTextBuffer *buffer, int old_line_count,
940 GSList *days)
942 GSList *l;
944 for (l = days; l; l = l->next) {
945 Day *day = l->data;
947 _gtk_text_buffer_apply_tag_to_rectangle (buffer,
948 old_line_count + day->first_line - 1,
949 old_line_count + day->last_line,
950 0, day->timestamp_len, "gray");
954 static void
955 read_new_lines_cb (LogviewLog *log,
956 const char **lines,
957 GSList *new_days,
958 GError *error,
959 gpointer user_data)
961 LogviewWindow *window = user_data;
962 GtkTextBuffer *buffer;
963 gboolean boldify = FALSE;
964 int i, old_line_count, filter_start_line;
965 GtkTextIter iter, start;
966 GtkTextMark *mark;
967 char *converted, *primary;
968 gsize len;
970 if (error != NULL) {
971 primary = g_strdup_printf (_("Can't read from \"%s\""),
972 logview_log_get_display_name (log));
973 logview_window_add_error (window, primary, error->message);
974 g_free (primary);
976 return;
979 if (lines == NULL) {
980 /* there's no error, but no lines have been read */
981 return;
984 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->priv->text_view));
985 old_line_count = gtk_text_buffer_get_line_count (buffer);
986 filter_start_line = old_line_count > 0 ? (old_line_count - 1) : 0;
988 if (gtk_text_buffer_get_char_count (buffer) != 0) {
989 boldify = TRUE;
992 gtk_text_buffer_get_end_iter (buffer, &iter);
994 if (boldify) {
995 mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);
998 for (i = 0; lines[i]; i++) {
999 len = strlen (lines[i]);
1001 if (!g_utf8_validate (lines[i], len, NULL)) {
1002 converted = g_locale_to_utf8 (lines[i], (gssize) len, NULL, &len, NULL);
1003 gtk_text_buffer_insert (buffer, &iter, lines[i], len);
1004 } else {
1005 gtk_text_buffer_insert (buffer, &iter, lines[i], strlen (lines[i]));
1008 gtk_text_iter_forward_to_end (&iter);
1009 gtk_text_buffer_insert (buffer, &iter, "\n", 1);
1010 gtk_text_iter_forward_char (&iter);
1013 if (boldify) {
1014 gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
1015 gtk_text_buffer_apply_tag_by_name (buffer, "bold", &start, &iter);
1016 gtk_text_buffer_delete_mark (buffer, mark);
1018 filter_buffer (window, filter_start_line);
1020 if (window->priv->auto_scroll) {
1021 gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (window->priv->text_view),
1022 &iter, 0.0, FALSE, 0.0, 0.0);
1025 paint_timestamps (buffer, old_line_count, new_days);
1027 if (window->priv->monitor_id == 0) {
1028 window->priv->monitor_id = g_signal_connect (log, "log-changed",
1029 G_CALLBACK (log_monitor_changed_cb), window);
1032 logview_update_statusbar (window, log);
1033 logview_loglist_update_lines (LOGVIEW_LOGLIST (window->priv->loglist), log);
1036 static void
1037 active_log_changed_cb (LogviewManager *manager,
1038 LogviewLog *log,
1039 LogviewLog *old_log,
1040 gpointer data)
1042 LogviewWindow *window = data;
1043 const char **lines;
1044 GtkTextBuffer *buffer;
1046 findbar_close_cb (LOGVIEW_FINDBAR (window->priv->find_bar),
1047 window);
1049 logview_set_window_title (window, logview_log_get_display_name (log));
1051 if (window->priv->monitor_id) {
1052 g_signal_handler_disconnect (old_log, window->priv->monitor_id);
1053 window->priv->monitor_id = 0;
1056 lines = logview_log_get_cached_lines (log);
1057 buffer = gtk_text_buffer_new (window->priv->tag_table);
1059 if (lines != NULL) {
1060 int i;
1061 GtkTextIter iter;
1063 /* update the text view to show the current lines */
1064 gtk_text_buffer_get_end_iter (buffer, &iter);
1066 for (i = 0; lines[i]; i++) {
1067 gtk_text_buffer_insert (buffer, &iter, lines[i], strlen (lines[i]));
1068 gtk_text_iter_forward_to_end (&iter);
1069 gtk_text_buffer_insert (buffer, &iter, "\n", 1);
1070 gtk_text_iter_forward_char (&iter);
1073 paint_timestamps (buffer, 1, logview_log_get_days_for_cached_lines (log));
1076 if (lines == NULL || logview_log_has_new_lines (log)) {
1077 /* read the new lines */
1078 logview_log_read_new_lines (log, (LogviewNewLinesCallback) read_new_lines_cb, window);
1079 } else {
1080 /* start now monitoring the log for changes */
1081 window->priv->monitor_id = g_signal_connect (log, "log-changed",
1082 G_CALLBACK (log_monitor_changed_cb), window);
1085 /* we set the buffer to the view anyway;
1086 * if there are no lines it will be empty for the duration of the thread
1087 * and will help us to distinguish the two cases of the following if
1088 * cause in the callback.
1090 gtk_text_view_set_buffer (GTK_TEXT_VIEW (window->priv->text_view), buffer);
1091 g_object_unref (buffer);
1094 static void
1095 font_changed_cb (LogviewPrefs *prefs,
1096 const char *font_name,
1097 gpointer user_data)
1099 LogviewWindow *window = user_data;
1101 logview_set_font (window, font_name);
1104 static void
1105 tearoff_changed_cb (LogviewPrefs *prefs,
1106 gboolean have_tearoffs,
1107 gpointer user_data)
1109 LogviewWindow *window = user_data;
1111 gtk_ui_manager_set_add_tearoffs (window->priv->ui_manager, have_tearoffs);
1114 static void
1115 style_set_cb (GtkWidget *widget,
1116 GtkStyle *prev,
1117 gpointer user_data)
1119 LogviewWindow *logview = user_data;
1120 GtkStyle *style = gtk_widget_get_style (widget);
1122 populate_style_tag_table (style, logview->priv->tag_table);
1125 static const struct {
1126 guint keyval;
1127 GdkModifierType modifier;
1128 const gchar *action;
1129 } extra_keybindings [] = {
1130 { GDK_KEY_KP_Add, GDK_CONTROL_MASK, "ViewZoomIn" },
1131 { GDK_KEY_KP_Subtract, GDK_CONTROL_MASK, "ViewZoomOut" },
1132 { GDK_KEY_KP_0, GDK_CONTROL_MASK, "ViewZoom100" }
1135 static gboolean
1136 key_press_event_cb (GtkWidget *widget,
1137 GdkEventKey *event,
1138 gpointer user_data)
1140 LogviewWindow *window = user_data;
1141 guint modifier = event->state & gtk_accelerator_get_default_mod_mask ();
1142 GtkAction *action;
1143 int i;
1145 /* handle accelerators that we want bound, but aren't associated with
1146 * an action */
1147 for (i = 0; i < G_N_ELEMENTS (extra_keybindings); i++) {
1148 if (event->keyval == extra_keybindings[i].keyval &&
1149 modifier == extra_keybindings[i].modifier) {
1151 action = gtk_action_group_get_action (window->priv->action_group,
1152 extra_keybindings[i].action);
1153 gtk_action_activate (action);
1154 return TRUE;
1158 return FALSE;
1161 /* adapted from GEdit */
1163 static void
1164 message_area_create_error_box (LogviewWindow *window,
1165 GtkWidget *message_area)
1167 GtkWidget *hbox_content;
1168 GtkWidget *image;
1169 GtkWidget *vbox;
1170 GtkWidget *primary_label;
1171 GtkWidget *secondary_label;
1173 hbox_content = gtk_hbox_new (FALSE, 8);
1174 gtk_widget_show (hbox_content);
1176 image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR,
1177 GTK_ICON_SIZE_DIALOG);
1178 gtk_widget_show (image);
1179 gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
1180 gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0);
1182 vbox = gtk_vbox_new (FALSE, 6);
1183 gtk_widget_show (vbox);
1184 gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
1186 primary_label = gtk_label_new (NULL);
1187 gtk_widget_show (primary_label);
1188 gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
1189 gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
1190 gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
1191 gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5);
1192 gtk_widget_set_can_focus (primary_label, TRUE);
1193 gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
1195 window->priv->message_primary = primary_label;
1197 secondary_label = gtk_label_new (NULL);
1198 gtk_widget_show (secondary_label);
1199 gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
1200 gtk_widget_set_can_focus (secondary_label, TRUE);
1201 gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
1202 gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
1203 gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
1204 gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5);
1206 window->priv->message_secondary = secondary_label;
1208 gtk_container_add
1209 (GTK_CONTAINER (gtk_info_bar_get_content_area
1210 (GTK_INFO_BAR (message_area))),
1211 hbox_content);
1214 static void
1215 message_area_set_labels (LogviewWindow *window,
1216 const char *primary,
1217 const char *secondary)
1219 char *primary_markup, *secondary_markup;
1221 primary_markup = g_markup_printf_escaped ("<b>%s</b>", primary);
1222 secondary_markup = g_markup_printf_escaped ("<small>%s</small>",
1223 secondary);
1225 gtk_label_set_markup (GTK_LABEL (window->priv->message_primary),
1226 primary_markup);
1227 gtk_label_set_markup (GTK_LABEL (window->priv->message_secondary),
1228 secondary_markup);
1230 g_free (primary_markup);
1231 g_free (secondary_markup);
1234 static void
1235 message_area_response_cb (GtkInfoBar *message_area,
1236 int response_id, gpointer user_data)
1238 gtk_widget_hide (GTK_WIDGET (message_area));
1240 g_signal_handlers_disconnect_by_func (message_area,
1241 message_area_response_cb,
1242 user_data);
1245 static void
1246 logview_window_finalize (GObject *object)
1248 LogviewWindow *logview = LOGVIEW_WINDOW (object);
1250 g_object_unref (logview->priv->ui_manager);
1251 G_OBJECT_CLASS (logview_window_parent_class)->finalize (object);
1254 static void
1255 logview_window_init (LogviewWindow *logview)
1257 GtkActionGroup *action_group;
1258 GtkAccelGroup *accel_group;
1259 GError *error = NULL;
1260 GtkWidget *hpaned, *main_view, *vbox, *w;
1261 PangoContext *context;
1262 PangoFontDescription *fontdesc;
1263 gchar *monospace_font_name;
1264 LogviewWindowPrivate *priv;
1265 int width, height;
1266 gboolean res;
1268 priv = logview->priv = GET_PRIVATE (logview);
1269 priv->prefs = logview_prefs_get ();
1270 priv->manager = logview_manager_get ();
1271 priv->monitor_id = 0;
1273 logview_prefs_get_stored_window_size (priv->prefs, &width, &height);
1274 gtk_window_set_default_size (GTK_WINDOW (logview), width, height);
1276 vbox = gtk_vbox_new (FALSE, 0);
1277 gtk_container_add (GTK_CONTAINER (logview), vbox);
1279 /* create menus */
1280 action_group = gtk_action_group_new ("LogviewMenuActions");
1281 gtk_action_group_set_translation_domain (action_group, NULL);
1282 gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), logview);
1283 gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), logview);
1284 priv->action_group = action_group;
1285 priv->auto_scroll = TRUE;
1287 priv->ui_manager = gtk_ui_manager_new ();
1289 gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, 0);
1290 accel_group = gtk_ui_manager_get_accel_group (priv->ui_manager);
1291 gtk_window_add_accel_group (GTK_WINDOW (logview), accel_group);
1293 res = gtk_ui_manager_add_ui_from_file (priv->ui_manager,
1294 LOGVIEW_DATADIR "/logview-toolbar.xml",
1295 &error);
1297 if (res == FALSE) {
1298 priv->ui_manager = NULL;
1299 g_critical ("Can't load the UI description: %s", error->message);
1300 g_error_free (error);
1301 return;
1304 gtk_ui_manager_set_add_tearoffs (priv->ui_manager,
1305 logview_prefs_get_have_tearoff (priv->prefs));
1307 w = gtk_ui_manager_get_widget (priv->ui_manager, "/LogviewMenu");
1308 gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
1309 gtk_widget_show (w);
1311 /* panes */
1312 hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
1313 gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
1314 priv->hpaned = hpaned;
1315 gtk_widget_show (hpaned);
1317 /* first pane : sidebar (list of logs) */
1318 priv->sidebar = gtk_vbox_new (FALSE, 0);
1319 gtk_widget_show (priv->sidebar);
1321 /* first pane: log list */
1322 w = gtk_scrolled_window_new (NULL, NULL);
1323 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w),
1324 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1325 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w),
1326 GTK_SHADOW_ETCHED_IN);
1328 priv->loglist = logview_loglist_new ();
1329 gtk_container_add (GTK_CONTAINER (w), priv->loglist);
1330 gtk_box_pack_start (GTK_BOX (priv->sidebar), w, TRUE, TRUE, 0);
1331 gtk_paned_pack1 (GTK_PANED (hpaned), priv->sidebar, FALSE, FALSE);
1332 gtk_widget_show (w);
1333 gtk_widget_show (priv->loglist);
1335 g_signal_connect (priv->loglist, "day_selected",
1336 G_CALLBACK (loglist_day_selected_cb), logview);
1337 g_signal_connect (priv->loglist, "day_cleared",
1338 G_CALLBACK (loglist_day_cleared_cb), logview);
1340 /* second pane: log */
1341 main_view = gtk_vbox_new (FALSE, 0);
1342 gtk_paned_pack2 (GTK_PANED (hpaned), main_view, TRUE, TRUE);
1344 /* second pane: error message area */
1345 priv->message_area = gtk_info_bar_new ();
1346 message_area_create_error_box (logview, priv->message_area);
1347 gtk_info_bar_add_button (GTK_INFO_BAR (priv->message_area),
1348 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
1349 gtk_box_pack_start (GTK_BOX (main_view), priv->message_area, FALSE, FALSE, 0);
1351 /* second pane: text view */
1352 w = gtk_scrolled_window_new (NULL, NULL);
1353 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w),
1354 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1355 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_IN);
1356 gtk_box_pack_start (GTK_BOX (main_view), w, TRUE, TRUE, 0);
1357 gtk_widget_show (w);
1359 priv->tag_table = gtk_text_tag_table_new ();
1360 populate_tag_table (priv->tag_table);
1361 priv->text_view = gtk_text_view_new ();
1362 g_object_set (priv->text_view, "editable", FALSE, NULL);
1364 gtk_container_add (GTK_CONTAINER (w), priv->text_view);
1365 gtk_widget_show (priv->text_view);
1367 /* use the desktop monospace font */
1368 monospace_font_name = logview_prefs_get_monospace_font_name (priv->prefs);
1369 logview_set_font (logview, monospace_font_name);
1370 g_free (monospace_font_name);
1372 /* remember the original font size */
1373 context = gtk_widget_get_pango_context (priv->text_view);
1374 fontdesc = pango_context_get_font_description (context);
1375 priv->original_fontsize = pango_font_description_get_size (fontdesc) / PANGO_SCALE;
1377 /* restore saved zoom */
1378 priv->fontsize = logview_prefs_get_stored_fontsize (priv->prefs);
1380 if (priv->fontsize <= 0) {
1381 /* restore the default */
1382 logview_normal_text (NULL, logview);
1383 } else {
1384 logview_set_fontsize (logview, FALSE);
1387 /* version selector */
1388 priv->version_bar = gtk_hbox_new (FALSE, 0);
1389 gtk_container_set_border_width (GTK_CONTAINER (priv->version_bar), 3);
1390 priv->version_selector = gtk_combo_box_text_new ();
1391 g_signal_connect (priv->version_selector, "changed",
1392 G_CALLBACK (logview_version_selector_changed), logview);
1393 w = gtk_label_new (_("Version: "));
1395 gtk_box_pack_end (GTK_BOX (priv->version_bar), priv->version_selector, FALSE, FALSE, 0);
1396 gtk_box_pack_end (GTK_BOX (priv->version_bar), w, FALSE, FALSE, 0);
1397 gtk_box_pack_end (GTK_BOX (main_view), priv->version_bar, FALSE, FALSE, 0);
1399 priv->find_bar = logview_findbar_new ();
1400 gtk_box_pack_end (GTK_BOX (main_view), priv->find_bar, FALSE, FALSE, 0);
1402 g_signal_connect (priv->find_bar, "previous",
1403 G_CALLBACK (findbar_previous_cb), logview);
1404 g_signal_connect (priv->find_bar, "next",
1405 G_CALLBACK (findbar_next_cb), logview);
1406 g_signal_connect (priv->find_bar, "text_changed",
1407 G_CALLBACK (findbar_text_changed_cb), logview);
1408 g_signal_connect (priv->find_bar, "close",
1409 G_CALLBACK (findbar_close_cb), logview);
1411 /* signal handlers
1412 * - first is used to remember/restore the window size on quit.
1414 g_signal_connect (logview, "configure_event",
1415 G_CALLBACK (window_size_changed_cb), logview);
1416 g_signal_connect (priv->prefs, "system-font-changed",
1417 G_CALLBACK (font_changed_cb), logview);
1418 g_signal_connect (priv->prefs, "have-tearoff-changed",
1419 G_CALLBACK (tearoff_changed_cb), logview);
1420 g_signal_connect (priv->manager, "active-changed",
1421 G_CALLBACK (active_log_changed_cb), logview);
1422 g_signal_connect (logview, "style-set",
1423 G_CALLBACK (style_set_cb), logview);
1424 g_signal_connect (logview, "key-press-event",
1425 G_CALLBACK (key_press_event_cb), logview);
1427 /* status area at bottom */
1428 priv->statusbar = gtk_statusbar_new ();
1429 gtk_box_pack_start (GTK_BOX (vbox), priv->statusbar, FALSE, FALSE, 0);
1430 gtk_widget_show (priv->statusbar);
1432 /* Filter menu */
1433 priv->filter_action_group = gtk_action_group_new ("ActionGroupFilter");
1434 gtk_ui_manager_insert_action_group (priv->ui_manager, priv->filter_action_group,
1436 priv->active_filters = NULL;
1437 update_filter_menu (logview);
1439 gtk_widget_show (vbox);
1440 gtk_widget_show (main_view);
1443 static void
1444 logview_window_class_init (LogviewWindowClass *klass)
1446 GObjectClass *object_class = (GObjectClass *) klass;
1448 object_class->finalize = logview_window_finalize;
1450 g_type_class_add_private (klass, sizeof (LogviewWindowPrivate));
1453 /* public methods */
1455 GtkWidget *
1456 logview_window_new ()
1458 LogviewWindow *logview;
1460 logview = g_object_new (LOGVIEW_TYPE_WINDOW, NULL);
1462 if (logview->priv->ui_manager == NULL) {
1463 return NULL;
1466 return GTK_WIDGET (logview);
1469 void
1470 logview_window_add_error (LogviewWindow *window,
1471 const char *primary,
1472 const char *secondary)
1474 LogviewWindowPrivate *priv;
1476 g_assert (LOGVIEW_IS_WINDOW (window));
1477 priv = window->priv;
1479 message_area_set_labels (window,
1480 primary, secondary);
1482 gtk_widget_show (priv->message_area);
1484 g_signal_connect (priv->message_area, "response",
1485 G_CALLBACK (message_area_response_cb), window);
1488 void
1489 logview_window_add_errors (LogviewWindow *window,
1490 GPtrArray *errors)
1492 char *primary, *secondary;
1493 GString *str;
1494 char **err;
1495 int i;
1497 g_assert (LOGVIEW_IS_WINDOW (window));
1498 g_assert (errors->len > 1);
1500 primary = g_strdup (_("Could not open the following files:"));
1501 str = g_string_new (NULL);
1503 for (i = 0; i < errors->len; i++) {
1504 err = (char **) g_ptr_array_index (errors, i);
1505 g_string_append (str, err[0]);
1506 g_string_append (str, ": ");
1507 g_string_append (str, err[1]);
1508 g_string_append (str, "\n");
1511 secondary = g_string_free (str, FALSE);
1513 message_area_set_labels (window, primary, secondary);
1515 gtk_widget_show (window->priv->message_area);
1517 g_signal_connect (window->priv->message_area, "response",
1518 G_CALLBACK (message_area_response_cb), window);
1520 g_free (primary);
1521 g_free (secondary);