source: trunk/third/gnome-utils/logview/log_repaint.c @ 18641

Revision 18641, 17.2 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18640, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*  ----------------------------------------------------------------------
3
4    Copyright (C) 1998  Cesar Miquel  (miquel@df.uba.ar)
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20    ---------------------------------------------------------------------- */
21
22#include <config.h>
23#include <sys/stat.h>
24#include <unistd.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <malloc.h>
28#include <string.h>
29#include <gnome.h>
30#include "logview.h"
31#include "logrtns.h"
32
33/*
34 * -------------------
35 * Global variables
36 * -------------------
37 */
38
39extern int loginfovisible, calendarvisible;
40extern int zoom_visible;
41extern ConfigData *cfg;
42extern GtkLabel *date_label;
43extern UserPrefsStruct *user_prefs;
44extern GtkWidget *view;
45extern GtkWidget *app;
46
47
48/*
49 * -------------------
50 * Module variables
51 * -------------------
52 */
53
54Log *loglist[MAX_NUM_LOGS];
55Log *curlog;
56int numlogs, curlognum;
57
58char *month[12] =
59{N_("January"), N_("February"), N_("March"), N_("April"), N_("May"),
60 N_("June"), N_("July"), N_("August"), N_("September"), N_("October"),
61 N_("November"), N_("December")};
62
63enum {
64   DATE = 0,
65   HOSTNAME,
66   PROCESS,
67   MESSAGE
68};
69
70/*
71 * -------------------
72 * Function prototypes
73 * -------------------
74 */
75
76int InitPages (void);
77int GetLineAtCursor (int y);
78int RepaintCalendar (GtkWidget * widget, GdkEventExpose * event);
79int RepaintLogInfo (void);
80int repaint_zoom (void);
81gboolean log_repaint (void);
82void log_redrawdetail (void);
83void DrawLogLines (Log *current_log);
84void CloseApp (void);
85void UpdateStatusArea (void);
86void change_log (int direction);
87void create_zoom_view (void);
88void close_zoom_view (GtkWidget *widget, gpointer data);
89gboolean handle_log_mouse_button (GtkWidget *view, GdkEventButton * event_key);
90void handle_selection_changed_cb (GtkTreeSelection *selection, gpointer data);
91void handle_row_activation_cb (GtkTreeView *treeview, GtkTreePath *path,
92     GtkTreeViewColumn *arg2, gpointer user_data);
93void save_rows_to_expand (Log *log);
94
95static void iterate_thru_children(GtkTreeView  *tree_view,
96                      GtkTreeModel *tree_model, GtkTreePath  *tree_path,
97                      GtkTreePath  *orig, gint *count, gint depth);
98
99/**
100 * Recursively called until the row specified by orig is found.
101 *
102 * *count will be set to the visible row number of the child
103 * relative to the row that was initially passed in as tree_path.
104 *
105 * *count will be -1 if orig is not found as a child (a row that is
106 * not visible will not be found, e.g. if the row is inside a
107 * collapsed row).  If NULL is passed in as orig, *count will
108 * be a count of the visible children.
109 *
110 * NOTE: the value for depth must be 0 when this recursive function
111 * is initially called, or it may not function as expected.
112 *
113 * I took this function from gail/gail/gailtreeview.c
114 **/
115
116static void
117iterate_thru_children(GtkTreeView  *tree_view,
118                      GtkTreeModel *tree_model,
119                      GtkTreePath  *tree_path,
120                      GtkTreePath  *orig,
121                      gint         *count,
122                      gint         depth)
123{
124  GtkTreeIter iter;
125
126  gtk_tree_model_get_iter (tree_model, &iter, tree_path);
127
128  if (orig != NULL && !gtk_tree_path_compare (tree_path, orig))
129    /* Found it! */
130    return;
131
132  if (orig != NULL && gtk_tree_path_compare (tree_path, orig) > 0)
133    {
134      /* Past it, so return -1 */
135      *count = -1;
136      return;
137    }
138  else if /* (gtk_tree_view_row_expanded (tree_view, tree_path) && */
139    (gtk_tree_model_iter_has_child (tree_model, &iter))
140    {
141     /* we do not want to count the Date Header row
142        (*count)++; */
143      gtk_tree_path_append_index (tree_path, 0);
144      iterate_thru_children (tree_view, tree_model, tree_path,
145                             orig, count, (depth + 1));
146      return;
147    }
148  else if (gtk_tree_model_iter_next (tree_model, &iter))
149    {
150      (*count)++;
151      tree_path = gtk_tree_model_get_path (tree_model, &iter);
152      iterate_thru_children (tree_view, tree_model, tree_path,
153                             orig, count, depth);
154      gtk_tree_path_free (tree_path);
155      return;
156  }
157  else if (gtk_tree_path_up (tree_path))
158    {
159      GtkTreeIter temp_iter;
160      gboolean exit_loop = FALSE;
161      gint new_depth = depth - 1;
162
163      (*count)++;
164
165     /*
166      * Make sure that we back up until we find a row
167      * where gtk_tree_path_next does not return NULL.
168      */
169      while (!exit_loop)
170        {
171          if (gtk_tree_path_get_depth (tree_path) == 0)
172              /* depth is now zero so */
173            return;
174          gtk_tree_path_next (tree_path);
175
176          /* Verify that the next row is a valid row! */
177          exit_loop = gtk_tree_model_get_iter (tree_model, &temp_iter, tree_path);
178
179          if (!exit_loop)
180            {
181              /* Keep going up until we find a row that has a valid next */
182              if (gtk_tree_path_get_depth(tree_path) > 1)
183                {
184                  new_depth--;
185                  gtk_tree_path_up (tree_path);
186                }
187              else
188                {
189                 /*
190                  * If depth is 1 and gtk_tree_model_get_iter returns FALSE,
191                  * then we are at the last row, so just return.
192                  */
193                  if (orig != NULL)
194                    *count = -1;
195
196                  return;
197                }
198            }
199        }
200
201     /*
202      * This guarantees that we will stop when we hit the end of the
203      * children.
204      */
205      if (new_depth < 0)
206        return;
207
208      iterate_thru_children (tree_view, tree_model, tree_path,
209                            orig, count, new_depth);
210      return;
211    }
212 /*
213  * If it gets here, then the path wasn't found.  Situations
214  * that would cause this would be if the path passed in is
215  * invalid or contained within the last row, but not visible
216  * because the last row is not expanded.  If NULL was passed
217  * in then a row count is desired, so only set count to -1
218  * if orig is not NULL.
219  */
220  if (orig != NULL)
221    *count = -1;
222
223  return;
224
225}
226
227/* ----------------------------------------------------------------------
228   NAME:        handle_row_activation_cb
229   DESCRIPTION: User pressed space bar on a row in the main window
230   ---------------------------------------------------------------------- */
231
232void
233handle_row_activation_cb (GtkTreeView *treeview, GtkTreePath *path,
234     GtkTreeViewColumn *arg2, gpointer user_data)
235{
236    GtkTreeIter iter;
237    GtkTreeModel *model;
238    GtkTreePath *root_tree;
239    gint row = 0;
240
241    model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
242    root_tree = gtk_tree_path_new_root ();
243
244    iterate_thru_children (GTK_TREE_VIEW (view), model, root_tree, path, &row, 0);
245   
246    gtk_tree_path_free (root_tree);
247
248    curlog->current_line_no = row;
249    create_zoom_view ();
250
251}
252
253
254/* ----------------------------------------------------------------------
255   NAME:        handle_selection_changed_cb
256   DESCRIPTION: User clicked on main window
257   ---------------------------------------------------------------------- */
258
259void
260handle_selection_changed_cb (GtkTreeSelection *selection, gpointer data)
261{
262    GtkTreeIter iter;
263    GtkTreeModel *model;
264    GtkTreePath *path, *root_tree;
265    gint row = 0;
266
267    if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
268
269        path = gtk_tree_model_get_path (model, &iter);
270        root_tree = gtk_tree_path_new_root ();
271
272        curlog->current_path = gtk_tree_path_copy (path);
273        iterate_thru_children (GTK_TREE_VIEW (view), model, root_tree, path, &row, 0);
274
275        gtk_tree_path_free (root_tree);
276        gtk_tree_path_free (path);
277
278        curlog->current_line_no = row;
279        log_redrawdetail ();
280    }
281
282}
283
284/* ----------------------------------------------------------------------
285   NAME:        handle_log_mouse_button
286   DESCRIPTION: User clicked on main window: open zoom view.
287   ---------------------------------------------------------------------- */
288
289gboolean
290handle_log_mouse_button (GtkWidget * win, GdkEventButton *event)
291{
292    if (event->type == GDK_2BUTTON_PRESS) {
293        if (!zoom_visible)
294        create_zoom_view ();
295    }
296
297    return FALSE;
298
299}
300
301/* ----------------------------------------------------------------------
302   NAME:        change_log
303   DESCRIPTION: User switchs to another Log file
304   ---------------------------------------------------------------------- */
305
306void
307change_log (int direction)
308{
309   if (numlogs == 1)
310        return;
311   if (direction > 0) {
312       if (curlognum == numlogs - 1)
313               curlognum = 0;
314       else
315               curlognum++;
316   }
317   else {
318       if (curlognum == 0)
319               curlognum = numlogs - 1;
320       else
321               curlognum--;
322   }
323
324   save_rows_to_expand (curlog);
325
326   curlog = loglist[curlognum];
327
328   log_repaint ();
329   if (loginfovisible)
330       RepaintLogInfo ();
331   if (calendarvisible)
332       init_calendar_data ();
333   UpdateStatusArea();
334
335}
336
337void
338save_rows_to_expand (Log *log)
339{
340   GtkTreeModel *tree_model;
341   GtkTreePath *tree_path;
342   GtkTreeIter iter;
343   gint i = 0;
344
345   if (!log->total_lines)
346       return;
347
348   tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
349   tree_path = gtk_tree_path_new_root ();
350   gtk_tree_model_get_iter (tree_model, &iter, tree_path);
351
352   do {
353       tree_path = gtk_tree_model_get_path (tree_model, &iter);
354       if (gtk_tree_model_iter_has_child (tree_model, &iter) &&
355           gtk_tree_view_row_expanded (GTK_TREE_VIEW (view), tree_path)) {
356           log->expand_paths[i] = gtk_tree_path_copy (tree_path);
357           ++i;
358       }
359   }
360   while (gtk_tree_model_iter_next (tree_model, &iter));
361
362   log->expand_paths[i] = NULL;
363
364}
365
366/* ----------------------------------------------------------------------
367   NAME:        log_repaint
368   DESCRIPTION: Redraw screen.
369   ---------------------------------------------------------------------- */
370
371gboolean
372log_repaint ()
373{
374   GtkTreeModel *tree_model;
375
376   /* Clear the tree view first */
377   tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
378   gtk_tree_store_clear (GTK_TREE_STORE (tree_model));
379
380   log_redrawdetail ();
381   UpdateStatusArea ();   
382
383   /* Check that there is at least one log */
384   if (curlog == NULL)
385      return FALSE;
386   
387   /* Draw the tree view */
388   DrawLogLines (curlog);
389
390   return TRUE;
391
392}
393
394void
395UpdateStatusArea ()
396{
397   struct tm *tdm;
398   char status_text[255];
399   char *utf8;
400   char *buffer;
401   char *window_title;
402   /* Translators: Date only format, %x should well do really */
403   const char *time_fmt = _("%x"); /* an evil way to avoid warning */
404 
405   if (curlog == NULL) {
406       gtk_label_set_text (date_label, "");   
407       gtk_window_set_title (GTK_WINDOW (app), APP_NAME);
408       return;
409   }
410
411   if (curlog->name != NULL) {
412       window_title = g_strdup_printf ("%s - %s", curlog->name, APP_NAME);
413       gtk_window_set_title (GTK_WINDOW (app), window_title);
414       g_free (window_title);
415   }
416
417   if (curlog->curmark != NULL) {
418       tdm = &curlog->curmark->fulldate;
419
420       if (strftime (status_text, sizeof (status_text), time_fmt, tdm) <= 0) {
421               /* as a backup print in US style */
422               utf8 = g_strdup_printf ("%02d/%02d/%02d", tdm->tm_mday,
423                    tdm->tm_mon, tdm->tm_year % 100);
424       } else {
425           utf8 = LocaleToUTF8 (status_text);
426       }
427       gtk_label_get (date_label, (char **)&buffer);
428       /* FIXME: is this if statement needed?  would it make sense
429       to set the text every time?  doesn't gtk test for it in
430       a more efficient manner? */
431       if (strcmp (utf8, buffer) != 0)
432               gtk_label_set_text (date_label, utf8);
433
434       g_free (utf8);
435   }
436
437}
438
439/* ----------------------------------------------------------------------
440   NAME:        GetDateHeader
441   DESCRIPTION: Gets the Date to display
442   ---------------------------------------------------------------------- */
443
444char *
445GetDateHeader (LogLine *line)
446{
447   char buf[1024];
448   char *utf8;
449
450   if (line->month >= 0 && line->month < 12) {
451       struct tm tm = {0};
452
453       tm.tm_mday = line->date;
454       tm.tm_year = 2000 /* bogus */;
455       tm.tm_mon = line->month;
456       /* Translators: Make sure this is only Month and Day format, year
457        * will be bogus here */
458       if (strftime (buf, sizeof (buf), _("%B %e"), &tm) <= 0) {
459           /* If we fail just use the US format */
460           utf8 = g_strdup_printf ("%s %d", _(month[(int) line->month]),
461                                   line->date);
462       } else {
463           utf8 = LocaleToUTF8 (buf);
464       }
465   } else {
466       utf8 = g_strdup_printf ("?%d? %d", (int) line->month, line->date);
467   }
468
469   return utf8;
470
471}
472
473/* ----------------------------------------------------------------------
474   NAME:        DrawLogLines
475   DESCRIPTION: Displays a single log line
476   ---------------------------------------------------------------------- */
477
478void
479DrawLogLines (Log *current_log)
480{
481   GtkTreeModel *tree_model;
482   GtkTreeIter iter;
483   GtkTreeIter child_iter;
484   GtkTreePath *path;
485   LogLine *line;
486   char tmp[4096];
487   char *utf8;
488   gint i = 0, count = 0;
489   gint cm, cd;
490
491   
492   if (!current_log->total_lines)
493       return;
494
495   tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
496   cm = cd = -1;
497
498   for (i = 0; i < current_log->total_lines; ++i) {
499             
500       line = (current_log->lines)[i];
501       
502       /* If data has changed then draw the date header */
503       if ((line->month != cm && line->month > 0) ||
504           (line->date != cd && line->date > 0)) {
505           utf8 = GetDateHeader (line);
506           gtk_tree_store_append (GTK_TREE_STORE (tree_model), &iter, NULL);
507           gtk_tree_store_set (GTK_TREE_STORE (tree_model), &iter,
508               DATE, utf8, HOSTNAME, FALSE,
509               PROCESS, FALSE, MESSAGE, FALSE, -1);
510           cm = line->month;
511           cd = line->date;
512       }
513       if (line->hour >= 0 && line->min >= 0 && line->sec >= 0) {
514               struct tm date = {0};
515           date.tm_mon = line->month;
516           date.tm_year = 70 /* bogus */;
517           date.tm_mday = line->date;
518           date.tm_hour = line->hour;
519           date.tm_min = line->min;
520           date.tm_sec = line->sec;
521           date.tm_isdst = 0;
522
523               /* Translators: should be only the time, date could be bogus */
524               if (strftime (tmp, sizeof (tmp), _("%X"), &date) <= 0) {
525               /* as a backup print in 24 hours style */
526                       utf8 = g_strdup_printf ("%02d:%02d:%02d", line->hour,
527                                       line->min, line->sec);
528               } else {
529                       utf8 = LocaleToUTF8 (tmp);
530               }
531       } else {
532               utf8 = g_strdup (" ");
533       }
534
535       gtk_tree_store_append (GTK_TREE_STORE (tree_model), &child_iter, &iter);
536       gtk_tree_store_set (GTK_TREE_STORE (tree_model), &child_iter,
537           DATE, utf8, HOSTNAME, LocaleToUTF8 (line->hostname),
538           PROCESS, LocaleToUTF8 (line->process),
539           MESSAGE, LocaleToUTF8 (line->message), -1);
540   }
541 
542   if (current_log->first_time) {
543
544       /* Expand the rows */
545       path = gtk_tree_model_get_path (tree_model, &iter);
546       gtk_tree_view_expand_row (GTK_TREE_VIEW (view), path, FALSE);
547       current_log->first_time = FALSE;
548
549       /* Scroll and set focus on last row */
550       path = gtk_tree_model_get_path (tree_model, &child_iter);
551       gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path, NULL, FALSE);
552       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), path, NULL, TRUE,
553          1, 1);
554       gtk_tree_path_free (path);
555
556   } else {
557       /* Expand the rows */
558       for (i = 0; current_log->expand_paths[i]; ++i)
559           gtk_tree_view_expand_row (GTK_TREE_VIEW (view),
560               current_log->expand_paths[i], FALSE);
561                           
562       /* Scroll and set focus on the previously focused row */
563       gtk_tree_view_set_cursor (GTK_TREE_VIEW (view),
564           current_log->current_path, NULL, FALSE);
565       gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view),
566           current_log->current_path, NULL, TRUE, 1, 1);
567   }
568
569   g_free (utf8);
570   
571}
572
573/* ----------------------------------------------------------------------
574   NAME:        log_redrawdetail
575   DESCRIPTION: Redraw area were the detailed information is drawn.
576   ---------------------------------------------------------------------- */
577
578void
579log_redrawdetail ()
580{
581  if (zoom_visible)
582    repaint_zoom ();
583
584}
585
586/* ----------------------------------------------------------------------
587   NAME:        InitPages
588   DESCRIPTION: Returns -1 if there was a error otherwise TRUE;
589   ---------------------------------------------------------------------- */
590
591int
592InitPages ()
593{
594   if (user_prefs && user_prefs->logfile == NULL)
595        return -1;
596
597   curlog = OpenLogFile (user_prefs->logfile);
598   if (curlog == NULL)
599      return -1;
600   curlog->first_time = TRUE;
601   loglist[0] = curlog;
602   curlognum = 0;
603   numlogs++;
604   return TRUE;
605}
Note: See TracBrowser for help on using the repository browser.