source: trunk/gtk/msgwin.c @ 2185

Last change on this file since 2185 was 2185, checked in by charles, 15 years ago

add color-coded lines to the gtk debug window -- info is black, debug is grey, errors are red...

  • Property svn:keywords set to Date Rev Author Id
File size: 9.6 KB
Line 
1/******************************************************************************
2 * $Id: msgwin.c 2185 2007-06-22 20:59:23Z charles $
3 *
4 * Copyright (c) 2006-2007 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <errno.h>
26#include <string.h>
27
28#include <gtk/gtk.h>
29#include <glib/gi18n.h>
30
31#include "conf.h"
32#include "msgwin.h"
33#include "tr_prefs.h"
34#include "transmission.h"
35#include "util.h"
36
37#define MAX_MSGCOUNT 5000
38
39#define COL_LVL 0
40#define COL_MSG 1
41
42static GtkTextBuffer * textbuf = NULL;
43
44static GtkTextTag*
45get_or_create_tag (GtkTextTagTable * table, const char * key)
46{
47  g_assert (table);
48  g_assert (key && *key);
49
50  GtkTextTag * tag = gtk_text_tag_table_lookup (table, key);
51  if (!tag) {
52    tag = gtk_text_tag_new (key);
53    gtk_text_tag_table_add (table, tag);
54    g_object_unref (tag); // table refs it
55  }
56
57  return tag;
58}
59
60static GtkTextBuffer*
61debug_window_text_buffer_new ( void )
62{
63  GtkTextBuffer * buffer = gtk_text_buffer_new ( NULL );
64
65  GtkTextTagTable * table = gtk_text_buffer_get_tag_table (buffer);
66
67  g_object_set (get_or_create_tag(table,"bold"),
68      "weight", PANGO_WEIGHT_BOLD,
69      NULL);
70 
71  g_object_set (get_or_create_tag (table, "info"),
72      "foreground", "black",
73      NULL);
74 
75  g_object_set (get_or_create_tag (table, "error"),
76      "foreground", "red",
77      NULL);
78
79  g_object_set (get_or_create_tag (table, "debug"),
80      "foreground", "gray",
81      NULL);
82
83  return buffer;
84}
85
86void
87msgwin_update( void )
88{
89  tr_msg_list_t * msgs, * ii;
90
91  g_assert( textbuf != NULL );
92
93  msgs = tr_getQueuedMessages();
94  for( ii = msgs; NULL != ii; ii = ii->next )
95  {
96    int len;
97    char * line;
98    const char * tag = NULL;
99    struct tm * tm = localtime( &ii->when );
100    GtkTextIter mark_start, mark_end;
101
102    switch( ii->level ) {
103      case TR_MSG_ERR: tag = "error"; break;
104      case TR_MSG_INF: tag = "info"; break;
105      case TR_MSG_DBG: tag = "debug"; break;
106    }
107
108    line = g_strdup_printf( "%02i:%02i:%02i %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, ii->message );
109    len = strlen( line );
110
111    gtk_text_buffer_get_end_iter( textbuf, &mark_end );
112    gtk_text_buffer_insert( textbuf, &mark_end, line, len );
113    mark_start = mark_end;
114    gtk_text_iter_backward_chars( &mark_start, len );
115    gtk_text_buffer_apply_tag_by_name (textbuf, tag, &mark_start, &mark_end);
116
117    g_free( line );
118  }
119  tr_freeMessageList( msgs );
120
121#if 0
122  count = gtk_text_buffer_get_line_count( textbuf );
123  if( MAX_MSGCOUNT < count ) {
124    gtk_text_buffer_get_iter_at_line( textbuf, &front, 0 );
125    gtk_text_buffer_get_iter_at_line( textbuf, &iter, count - MAX_MSGCOUNT );
126    gtk_text_buffer_delete( textbuf, &front, &iter );
127  }
128#endif
129}
130
131static void
132level_combo_changed_cb( GtkWidget * w, TrCore * core )
133{
134    GtkTreeIter iter;
135    if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX(w), &iter ) ) {
136        int id = 0;
137        GtkTreeModel * m = gtk_combo_box_get_model( GTK_COMBO_BOX(w) );
138        gtk_tree_model_get( m, &iter, 1, &id, -1 );
139        tr_setMessageLevel( id );
140        tr_core_set_pref_int( core, PREF_ID_MSGLEVEL, id );
141        msgwin_update( );
142    }
143}
144
145static void
146save_dialog_response_cb( GtkWidget * d, int response, GtkTextBuffer * textbuf )
147{
148  if( response == GTK_RESPONSE_ACCEPT )
149  {
150      char * filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( d ) );
151      FILE * fp = fopen( filename, "w+" );
152      if( !fp )
153      {
154          errmsg( GTK_WINDOW(d),
155                  _("Unable to open \"%s\" for writing: %s"),
156                  filename, g_strerror( errno ) );
157      }
158      else
159      {
160          char * buf;
161          GtkTextIter front, back;
162          gtk_text_buffer_get_start_iter( textbuf, &front );
163          gtk_text_buffer_get_end_iter( textbuf, &back );
164          buf = gtk_text_buffer_get_text( textbuf, &front, &back, FALSE );
165          if( buf ) {
166              const size_t len = strlen( buf );
167              if( len > fwrite( buf, 1, len, fp ) ) {
168                  errmsg( GTK_WINDOW( d ),
169                          _("Error writing to \"%s\": %s"),
170                          filename, strerror( errno ) );
171              }
172              g_free( buf );
173          }
174          fclose( fp );
175      }
176      g_free( filename );
177  }
178
179  gtk_widget_destroy( d );
180}
181
182static void
183save_cb( GtkWidget * w, GtkTextBuffer * textbuf )
184{
185  GtkWindow * window = GTK_WINDOW( gtk_widget_get_toplevel( w ) );
186  GtkWidget * d = gtk_file_chooser_dialog_new( _("Save Debug Log"), window,
187                                               GTK_FILE_CHOOSER_ACTION_SAVE,
188                                               GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
189                                               GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
190                                               NULL );
191  g_signal_connect( d, "response",
192                    G_CALLBACK( save_dialog_response_cb ), textbuf );
193  gtk_widget_show( d );
194}
195
196static void
197clear_cb( GtkWidget * w UNUSED, GtkTextBuffer * textbuf )
198{
199  GtkTextIter front, back;
200  gtk_text_buffer_get_start_iter( textbuf, &front );
201  gtk_text_buffer_get_end_iter( textbuf, &back );
202  gtk_text_buffer_delete( textbuf, &front, &back );
203}
204
205static struct {
206  const char * label;
207  const char * pref;
208  const char * text;
209  int id;
210} trLevels[] = {
211  { N_("Error"), "error", "ERR", TR_MSG_ERR },
212  { N_("Info"),  "info",  "INF", TR_MSG_INF },
213  { N_("Debug"), "debug", "DBG", TR_MSG_DBG },
214};
215
216GtkWidget *
217msgwin_create( TrCore * core )
218{
219  unsigned int i;
220  GtkListStore * store;
221  GtkWidget * win, * vbox, * scroll, * text;
222  GtkWidget * levels;
223  GtkWidget * toolbar;
224  GtkCellRenderer * renderer;
225  int ii, curlevel;
226
227  win = gtk_window_new( GTK_WINDOW_TOPLEVEL );
228  gtk_window_set_role( GTK_WINDOW( win ), "debug-window" );
229  vbox = gtk_vbox_new( FALSE, 0 );
230
231  /**
232  ***  toolbar
233  **/
234
235  toolbar = gtk_toolbar_new ();
236  gtk_toolbar_set_style( GTK_TOOLBAR( toolbar), GTK_TOOLBAR_BOTH_HORIZ );
237
238  gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_SAVE,
239                           _("Save"), NULL,
240                           G_CALLBACK(save_cb), textbuf, -1);
241
242  gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_CLEAR,
243                           _("Clear"), NULL,
244                           G_CALLBACK(clear_cb), textbuf, -1);
245
246  gtk_toolbar_insert_space(GTK_TOOLBAR(toolbar), -1);
247
248
249  gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
250                             GTK_TOOLBAR_CHILD_WIDGET, gtk_label_new(_("Level ")),
251                             NULL, _("Select the debug filter level."),
252                             NULL, NULL, NULL, NULL);
253
254  store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
255
256  curlevel = TR_MSG_INF;
257  tr_prefs_get_int( PREF_ID_MSGLEVEL, &curlevel );
258  for( i=ii=0; i<G_N_ELEMENTS(trLevels); ++i ) {
259      GtkTreeIter iter;
260      gtk_list_store_append (store, &iter);
261      gtk_list_store_set (store, &iter, 0, _(trLevels[i].label),
262                                        1, trLevels[i].id,
263                                       -1);
264      if( trLevels[i].id == curlevel )
265          ii = i;
266  }
267  levels = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
268  g_object_unref (G_OBJECT(store));
269  renderer = gtk_cell_renderer_text_new ();
270  gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(levels), renderer, TRUE);
271  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(levels), renderer, "text", 0, NULL);
272  gtk_combo_box_set_active( GTK_COMBO_BOX( levels ), ii );
273  g_signal_connect( levels, "changed", G_CALLBACK(level_combo_changed_cb), core );
274
275  gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
276                             GTK_TOOLBAR_CHILD_WIDGET, levels,
277                             NULL, _("Select the debug filter level."),
278                             NULL, NULL, NULL, NULL);
279
280  gtk_box_pack_start( GTK_BOX( vbox ), toolbar, FALSE, FALSE, 0 );
281
282  /**
283  ***  text area
284  **/
285
286  text = gtk_text_view_new_with_buffer( textbuf );
287  gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), FALSE );
288
289  scroll = gtk_scrolled_window_new( NULL, NULL );
290  gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scroll ),
291                                  GTK_POLICY_AUTOMATIC,
292                                  GTK_POLICY_AUTOMATIC );
293  gtk_container_add( GTK_CONTAINER( scroll ), text );
294
295  gtk_box_pack_start( GTK_BOX( vbox ), scroll, TRUE, TRUE, 0 );
296
297
298  msgwin_update( );
299  gtk_container_add( GTK_CONTAINER( win ), vbox );
300  gtk_widget_show_all( win );
301  return win;
302}
303
304void
305msgwin_loadpref( void )
306{
307    int level = TR_MSG_INF;
308    textbuf = debug_window_text_buffer_new ( );
309    gboolean b = tr_prefs_get_int( PREF_ID_MSGLEVEL, &level );
310g_message ("level from prefs: %d (b==%d)", level, (int)b );
311    tr_setMessageLevel( level );
312    tr_setMessageQueuing( TRUE );
313}
Note: See TracBrowser for help on using the repository browser.