Changeset 5250


Ignore:
Timestamp:
Mar 13, 2008, 7:34:08 PM (14 years ago)
Author:
charles
Message:

(gtk) improve the message log's look with the recent libT changes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/gtk/msgwin.c

    r5243 r5250  
    2727#include <string.h>
    2828
     29#include <glib/gi18n.h>
    2930#include <gtk/gtk.h>
    30 #include <glib/gi18n.h>
    3131
    3232#include <libtransmission/transmission.h>
     
    3838#include "util.h"
    3939
    40 #define MAX_MSGCOUNT 5000
    41 
    42 #define COL_LVL 0
    43 #define COL_MSG 1
    44 
    45 static GtkTextBuffer * textbuf = NULL;
    46 
    47 static GtkTextTag*
    48 get_or_create_tag (GtkTextTagTable * table, const char * key)
    49 {
    50   GtkTextTag * tag;
    51 
    52   g_assert (table);
    53   g_assert (key && *key);
    54 
    55   tag = gtk_text_tag_table_lookup (table, key);
    56   if (!tag) {
    57     tag = gtk_text_tag_new (key);
    58     gtk_text_tag_table_add (table, tag);
    59     g_object_unref (tag); /* table refs it */
    60   }
    61 
    62   return tag;
    63 }
    64 
    65 static GtkTextBuffer*
    66 debug_window_text_buffer_new ( void )
    67 {
    68   GtkTextBuffer * buffer = gtk_text_buffer_new ( NULL );
    69 
    70   GtkTextTagTable * table = gtk_text_buffer_get_tag_table (buffer);
    71 
    72   g_object_set (get_or_create_tag(table,"bold"),
    73       "weight", PANGO_WEIGHT_BOLD,
    74       NULL);
    75  
    76   g_object_set (get_or_create_tag (table, "info"),
    77       "foreground", "black",
    78       NULL);
    79  
    80   g_object_set (get_or_create_tag (table, "error"),
    81       "foreground", "red",
    82       NULL);
    83 
    84   g_object_set (get_or_create_tag (table, "debug"),
    85       "foreground", "gray",
    86       NULL);
    87 
    88   return buffer;
    89 }
    90 
    91 void
    92 msgwin_update( void )
    93 {
    94   tr_msg_list * msgs, * ii;
    95 
    96   g_assert( textbuf != NULL );
    97 
    98   msgs = tr_getQueuedMessages();
    99   for( ii = msgs; NULL != ii; ii = ii->next )
    100   {
    101     int len;
    102     char * line;
    103     const char * tag = NULL;
    104     struct tm * tm = localtime( &ii->when );
    105     GtkTextIter mark_start, mark_end;
    106 
    107     switch( ii->level ) {
    108       case TR_MSG_ERR: tag = "error"; break;
    109       case TR_MSG_INF: tag = "info"; break;
    110       case TR_MSG_DBG: tag = "debug"; break;
    111     }
    112 
    113     line = ( ii->name != NULL )
    114         ? g_strdup_printf( "%02i:%02i:%02i [%s] %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, ii->name, ii->message )
    115         : g_strdup_printf( "%02i:%02i:%02i %s\n", tm->tm_hour, tm->tm_min, tm->tm_sec, ii->message );
    116     len = strlen( line );
    117 
    118     gtk_text_buffer_get_end_iter( textbuf, &mark_end );
    119     gtk_text_buffer_insert( textbuf, &mark_end, line, len );
    120     mark_start = mark_end;
    121     gtk_text_iter_backward_chars( &mark_start, len );
    122     gtk_text_buffer_apply_tag_by_name (textbuf, tag, &mark_start, &mark_end);
    123 
    124     g_free( line );
    125   }
    126   tr_freeMessageList( msgs );
    127 
    128 #if 0
    129   count = gtk_text_buffer_get_line_count( textbuf );
    130   if( MAX_MSGCOUNT < count ) {
    131     gtk_text_buffer_get_iter_at_line( textbuf, &front, 0 );
    132     gtk_text_buffer_get_iter_at_line( textbuf, &iter, count - MAX_MSGCOUNT );
    133     gtk_text_buffer_delete( textbuf, &front, &iter );
    134   }
    135 #endif
    136 }
    137 
    138 static void
    139 level_combo_changed_cb( GtkWidget * w, TrCore * core )
    140 {
     40enum
     41{
     42    COL_LEVEL,
     43    COL_LINE,
     44    COL_FILE,
     45    COL_TIME,
     46    COL_CATEGORY,
     47    COL_MESSAGE,
     48    COL_SEQUENCE,
     49    N_COLUMNS
     50};
     51
     52struct MsgData
     53{
     54    TrCore * core;
     55    GtkTreeView * view;
     56    GtkListStore * store;
     57    GtkTreeModel * filter;
     58    GtkTreeModel * sort;
     59    int maxLevel;
     60};
     61
     62static struct MsgData myData;
     63
     64/***
     65****
     66***/
     67
     68static void
     69level_combo_changed_cb( GtkWidget * w, gpointer gdata )
     70{
     71    struct MsgData * data = gdata;
    14172    GtkTreeIter iter;
    142     if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX(w), &iter ) ) {
    143         int id = 0;
    144         GtkTreeModel * m = gtk_combo_box_get_model( GTK_COMBO_BOX(w) );
    145         gtk_tree_model_get( m, &iter, 1, &id, -1 );
    146         tr_setMessageLevel( id );
    147         tr_core_set_pref_int( core, PREF_KEY_MSGLEVEL, id );
    148         msgwin_update( );
    149     }
    150 }
    151 
    152 static void
    153 save_dialog_response_cb( GtkWidget * d, int response, GtkTextBuffer * textbuf )
     73    if( gtk_combo_box_get_active_iter( GTK_COMBO_BOX(w), &iter ) )
     74    {
     75        int level = 0;
     76        GtkTreeModel * m = gtk_combo_box_get_model( GTK_COMBO_BOX( w ) );
     77        gtk_tree_model_get( m, &iter, 1, &level, -1 );
     78
     79        tr_setMessageLevel( level );
     80        tr_core_set_pref_int( data->core, PREF_KEY_MSGLEVEL, level );
     81        data->maxLevel = level;
     82        gtk_tree_model_filter_refilter( GTK_TREE_MODEL_FILTER( data->filter ) );
     83    }
     84}
     85
     86static void
     87doSave( GtkWindow      * parent,
     88        struct MsgData * data,
     89        const char     * filename )
     90{
     91    FILE * fp = fopen( filename, "w+" );
     92    if( !fp )
     93    {
     94        errmsg( parent,
     95                _("Couldn't write file \"%s\": %s"),
     96                filename, g_strerror( errno ) );
     97    }
     98    else
     99    {
     100        GtkTreeIter iter;
     101        GtkTreeModel * model = GTK_TREE_MODEL( data->sort );
     102        if( gtk_tree_model_iter_children( model, &iter, NULL ) ) do
     103        {
     104            int level;
     105            uint64_t time;
     106            char * category;
     107            char * message;
     108            char * date;
     109            const char * levelStr;
     110
     111            gtk_tree_model_get( model, &iter,
     112                                COL_LEVEL, &level,
     113                                COL_TIME, &time,
     114                                COL_CATEGORY, &category,
     115                                COL_MESSAGE, &message,
     116                                -1 );
     117            date = rfc822date( time*1000u );
     118            switch( level ) {
     119                case TR_MSG_DBG: levelStr = "debug"; break;
     120                case TR_MSG_ERR: levelStr = "error"; break;
     121                default:         levelStr = "     "; break;
     122            }
     123            fprintf( fp, "%s\t%s\t%s\t%s\n", date, levelStr, category, message );
     124
     125            /* cleanup */
     126            g_free( date );
     127            g_free( message );
     128            g_free( category );
     129        }
     130        while( gtk_tree_model_iter_next( model, &iter ) );
     131        fclose( fp );
     132    }
     133}
     134
     135static void
     136onSaveDialogResponse( GtkWidget * d, int response, gpointer data )
    154137{
    155138  if( response == GTK_RESPONSE_ACCEPT )
    156139  {
    157140      char * filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( d ) );
    158       FILE * fp = fopen( filename, "w+" );
    159       if( !fp )
    160       {
    161           errmsg( GTK_WINDOW(d),
    162                   _("Couldn't write file \"%s\": %s"),
    163                   filename, g_strerror( errno ) );
    164       }
    165       else
    166       {
    167           char * buf;
    168           GtkTextIter front, back;
    169           gtk_text_buffer_get_start_iter( textbuf, &front );
    170           gtk_text_buffer_get_end_iter( textbuf, &back );
    171           buf = gtk_text_buffer_get_text( textbuf, &front, &back, FALSE );
    172           if( buf ) {
    173               const size_t len = strlen( buf );
    174               if( len > fwrite( buf, 1, len, fp ) ) {
    175                   errmsg( GTK_WINDOW( d ),
    176                           _("Couldn't write file \"%s\": %s"),
    177                           filename, g_strerror( errno ) );
    178               }
    179               g_free( buf );
    180           }
    181           fclose( fp );
    182       }
     141      doSave( GTK_WINDOW( d ), data, filename );
    183142      g_free( filename );
    184143  }
     
    188147
    189148static void
    190 save_cb( GtkWidget * w, GtkTextBuffer * textbuf )
     149onSaveRequest( GtkWidget * w, gpointer data )
    191150{
    192151  GtkWindow * window = GTK_WINDOW( gtk_widget_get_toplevel( w ) );
     
    201160                                           -1 );
    202161  g_signal_connect( d, "response",
    203                     G_CALLBACK( save_dialog_response_cb ), textbuf );
     162                    G_CALLBACK( onSaveDialogResponse ), data );
    204163  gtk_widget_show( d );
    205164}
    206165
    207166static void
    208 clear_cb( GtkWidget * w UNUSED, GtkTextBuffer * textbuf )
    209 {
    210   GtkTextIter front, back;
    211   gtk_text_buffer_get_start_iter( textbuf, &front );
    212   gtk_text_buffer_get_end_iter( textbuf, &back );
    213   gtk_text_buffer_delete( textbuf, &front, &back );
     167onClearRequest( GtkWidget * w UNUSED, gpointer unused UNUSED )
     168{
     169    struct MsgData * data = &myData;
     170    gtk_list_store_clear( data->store );
    214171}
    215172
     
    217174  const char * label;
    218175  const char * pref;
    219   const char * text;
    220176  int id;
    221177} trLevels[] = {
    222   { N_("Error"), "error", "ERR", TR_MSG_ERR },
    223   { N_("Information"),  "info",  "INF", TR_MSG_INF },
    224   { N_("Debug"), "debug", "DBG", TR_MSG_DBG },
     178  { N_("Error"), "error", TR_MSG_ERR },
     179  { N_("Information"), "info", TR_MSG_INF },
     180  { N_("Debug"), "debug", TR_MSG_DBG },
    225181};
     182
     183static void
     184renderLevel( GtkTreeViewColumn  * column UNUSED,
     185             GtkCellRenderer    * renderer,
     186             GtkTreeModel       * model,
     187             GtkTreeIter        * iter,
     188             gpointer             data UNUSED )
     189{
     190    int level;
     191    const char * stock;
     192    gtk_tree_model_get( model, iter, COL_LEVEL, &level, -1 );
     193    switch( level ) {
     194        case TR_MSG_ERR: stock = GTK_STOCK_DIALOG_ERROR; break;
     195        case TR_MSG_DBG: stock = GTK_STOCK_INFO; break;
     196        default: stock = NULL; break;
     197    }
     198    g_object_set (renderer, "xalign", (gfloat)0.5,
     199                            "yalign", (gfloat)0.5,
     200                            "stock-id", stock,
     201                            NULL);
     202}
     203
     204static const char*
     205getForegroundColor( int msgLevel )
     206{
     207    const char * foreground;
     208    switch( msgLevel ) {
     209        case TR_MSG_DBG: foreground = "gray"; break;
     210        case TR_MSG_INF: foreground = "black"; break;
     211        case TR_MSG_ERR: foreground = "red"; break;
     212        default: g_assert_not_reached( );
     213    }
     214    return foreground;
     215}
     216
     217static void
     218renderText( GtkTreeViewColumn  * column UNUSED,
     219            GtkCellRenderer    * renderer,
     220            GtkTreeModel       * tree_model,
     221            GtkTreeIter        * iter,
     222            gpointer             gcol )
     223{
     224    int col = GPOINTER_TO_INT( gcol );
     225    int level;
     226    char * str = NULL;
     227    gtk_tree_model_get( tree_model, iter, col, &str, COL_LEVEL, &level, -1 );
     228    g_object_set( renderer, "text", str,
     229                            "foreground", getForegroundColor( level ),
     230                            NULL );
     231    g_free( str );
     232}
     233
     234static void
     235renderTime( GtkTreeViewColumn  * column UNUSED,
     236            GtkCellRenderer    * renderer,
     237            GtkTreeModel       * tree_model,
     238            GtkTreeIter        * iter,
     239            gpointer             data UNUSED )
     240{
     241    int level;
     242    uint64_t tmp;
     243    time_t time;
     244    struct tm tm;
     245    char buf[16];
     246
     247    gtk_tree_model_get(tree_model, iter, COL_TIME, &tmp, COL_LEVEL, &level, -1 );
     248    time = tmp;
     249    tm = *localtime( &time );
     250    g_snprintf( buf, sizeof( buf ), "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec );
     251    g_object_set (renderer, "text", buf,
     252                            "foreground", getForegroundColor( level ),
     253                            NULL );
     254}
     255
     256static void
     257appendColumn( GtkTreeView * view, int col )
     258{
     259    gboolean resizable;
     260    GtkCellRenderer * r;
     261    GtkTreeViewColumn * c;
     262    int sort_col = col;
     263    const char * title = NULL;
     264
     265    switch( col ) {
     266        case COL_LEVEL:    title = NULL; break;
     267        case COL_LINE:     title = NULL; break;
     268        case COL_FILE:     title = _( "Filename" ); break;
     269        case COL_TIME:     title = _( "Time" ); break;
     270        case COL_CATEGORY: title = _( "Name"); break;
     271        case COL_MESSAGE:  title = _( "Message" ); break;
     272        default: g_assert_not_reached( );
     273    }
     274
     275    switch( col )
     276    {
     277        case COL_LEVEL:
     278            resizable = FALSE;
     279            r = gtk_cell_renderer_pixbuf_new( );
     280            c = gtk_tree_view_column_new_with_attributes( title, r, NULL );
     281            gtk_tree_view_column_set_sizing( c, GTK_TREE_VIEW_COLUMN_FIXED );
     282            gtk_tree_view_column_set_fixed_width( c, 20 );
     283            gtk_tree_view_column_set_cell_data_func( c, r, renderLevel, NULL, NULL );
     284            break;
     285
     286        case COL_FILE:
     287            resizable = TRUE;
     288            r = gtk_cell_renderer_text_new( );
     289            c = gtk_tree_view_column_new_with_attributes( title, r, "text", col, NULL );
     290            break;
     291
     292        case COL_LINE:
     293        case COL_CATEGORY:
     294        case COL_MESSAGE:
     295            resizable = TRUE;
     296            r = gtk_cell_renderer_text_new( );
     297            c = gtk_tree_view_column_new_with_attributes( title, r, NULL );
     298            gtk_tree_view_column_set_cell_data_func( c, r, renderText, GINT_TO_POINTER(col), NULL );
     299            break;
     300
     301        case COL_TIME:
     302            resizable = TRUE;
     303            r = gtk_cell_renderer_text_new( );
     304            c = gtk_tree_view_column_new_with_attributes( title, r, NULL );
     305            gtk_tree_view_column_set_cell_data_func( c, r, renderTime, NULL, NULL );
     306            sort_col = COL_SEQUENCE;
     307            break;
     308
     309        default:
     310            g_assert_not_reached( );
     311            break;
     312    }
     313
     314    gtk_tree_view_column_set_resizable( c, resizable );
     315    gtk_tree_view_column_set_sort_column_id( c, sort_col );
     316    gtk_tree_view_append_column( view, c );
     317}
     318
     319static gboolean
     320isRowVisible( GtkTreeModel * model, GtkTreeIter * iter, gpointer gdata )
     321{
     322    struct MsgData * data = gdata;
     323    int level;
     324    gtk_tree_model_get( model, iter, COL_LEVEL, &level, -1 );
     325    return level <= data->maxLevel;
     326}
     327
     328/**
     329***  Public Functions
     330**/
    226331
    227332GtkWidget *
     
    230335  unsigned int i;
    231336  GtkListStore * store;
    232   GtkWidget * win, * vbox, * scroll, * text;
     337  GtkWidget * win;
     338  GtkWidget * vbox;
    233339  GtkWidget * levels;
    234340  GtkWidget * toolbar;
    235341  GtkWidget * w;
     342  GtkWidget * view;
    236343  GtkWidget * l;
    237344  GtkCellRenderer * renderer;
    238345  int ii, curlevel;
     346  struct MsgData * data;
     347
     348  data = &myData;
     349  data->core = core;
    239350
    240351  win = gtk_window_new( GTK_WINDOW_TOPLEVEL );
     
    248359  **/
    249360
    250   toolbar = gtk_toolbar_new ();
     361  toolbar = gtk_toolbar_new( );
    251362  gtk_toolbar_set_style( GTK_TOOLBAR( toolbar), GTK_TOOLBAR_BOTH_HORIZ );
    252363
    253364  gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_SAVE,
    254365                           NULL, NULL,
    255                            G_CALLBACK(save_cb), textbuf, -1);
     366                           G_CALLBACK(onSaveRequest), data, -1);
    256367
    257368  gtk_toolbar_insert_stock(GTK_TOOLBAR(toolbar), GTK_STOCK_CLEAR,
    258369                           NULL, NULL,
    259                            G_CALLBACK(clear_cb), textbuf, -1);
     370                           G_CALLBACK(onClearRequest), data, -1);
    260371
    261372  gtk_toolbar_insert_space(GTK_TOOLBAR(toolbar), -1);
     
    288399  }
    289400  levels = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
    290   g_object_unref (G_OBJECT(store));
     401  g_object_unref( G_OBJECT( store ) );
     402  store = NULL;
     403
    291404  renderer = gtk_cell_renderer_text_new ();
    292   gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(levels), renderer, TRUE);
    293   gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(levels), renderer, "text", 0, NULL);
     405  gtk_cell_layout_pack_start( GTK_CELL_LAYOUT(levels), renderer, TRUE );
     406  gtk_cell_layout_set_attributes( GTK_CELL_LAYOUT(levels), renderer,
     407                                  "text", 0,
     408                                  NULL );
    294409  gtk_combo_box_set_active( GTK_COMBO_BOX( levels ), ii );
    295   g_signal_connect( levels, "changed", G_CALLBACK(level_combo_changed_cb), core );
    296 
    297   gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
    298                              GTK_TOOLBAR_CHILD_WIDGET, levels,
    299                              NULL, _("Set the verbosity level"),
    300                              NULL, NULL, NULL, NULL);
     410  g_signal_connect( levels, "changed",
     411                    G_CALLBACK(level_combo_changed_cb), data );
     412
     413  gtk_toolbar_append_element( GTK_TOOLBAR( toolbar ),
     414                              GTK_TOOLBAR_CHILD_WIDGET, levels,
     415                              NULL, _("Set the verbosity level"),
     416                              NULL, NULL, NULL, NULL);
    301417
    302418  gtk_box_pack_start( GTK_BOX( vbox ), toolbar, FALSE, FALSE, 0 );
    303419
    304420  /**
    305   ***  text area
     421  ***  messages
    306422  **/
    307423
    308   text = gtk_text_view_new_with_buffer( textbuf );
    309   gtk_text_view_set_editable( GTK_TEXT_VIEW( text ), FALSE );
    310 
    311   scroll = gtk_scrolled_window_new( NULL, NULL );
    312   gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scroll ),
    313                                   GTK_POLICY_AUTOMATIC,
     424  view = gtk_tree_view_new_with_model( data->sort );
     425  data->view = GTK_TREE_VIEW( view );
     426  gtk_tree_view_set_rules_hint( data->view, TRUE );
     427  appendColumn( data->view, COL_TIME );
     428  appendColumn( data->view, COL_CATEGORY );
     429  appendColumn( data->view, COL_MESSAGE );
     430  w = gtk_scrolled_window_new( NULL, NULL );
     431  gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( w ),
     432                                  GTK_POLICY_NEVER,
    314433                                  GTK_POLICY_AUTOMATIC );
    315   gtk_container_add( GTK_CONTAINER( scroll ), text );
    316 
    317   gtk_box_pack_start( GTK_BOX( vbox ), scroll, TRUE, TRUE, 0 );
     434  gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( w ),
     435                                       GTK_SHADOW_IN);
     436  gtk_container_add( GTK_CONTAINER( w ), view );
     437  gtk_box_pack_start( GTK_BOX( vbox ), w, TRUE, TRUE, 0 );
     438  gtk_container_add( GTK_CONTAINER( win ), vbox );
     439
    318440
    319441  msgwin_update( );
    320   gtk_container_add( GTK_CONTAINER( win ), vbox );
    321442  gtk_widget_show_all( win );
    322443  return win;
     
    326447msgwin_loadpref( void )
    327448{
    328     textbuf = debug_window_text_buffer_new ( );
    329 }
     449    struct MsgData * data = &myData;
     450
     451    data->store = gtk_list_store_new( N_COLUMNS,
     452                                      G_TYPE_INT,       /* level */
     453                                      G_TYPE_INT,       /* line number */
     454                                      G_TYPE_STRING,    /* file */
     455                                      G_TYPE_UINT64,    /* time */
     456                                      G_TYPE_STRING,    /* category */
     457                                      G_TYPE_STRING,    /* message */
     458                                      G_TYPE_INT );     /* sequence */
     459
     460    data->filter = gtk_tree_model_filter_new( GTK_TREE_MODEL( data->store ), NULL );
     461    data->sort = gtk_tree_model_sort_new_with_model( data->filter );
     462    data->maxLevel = pref_int_get( PREF_KEY_MSGLEVEL );
     463    gtk_tree_model_filter_set_visible_func( GTK_TREE_MODEL_FILTER( data->filter ),
     464                                            isRowVisible, data, NULL );
     465}
     466
     467void
     468msgwin_update( void )
     469{
     470    tr_msg_list * i;
     471    tr_msg_list * msgs;
     472    struct MsgData * data = &myData;
     473    static int sequence = 1;
     474    const char * default_category = g_get_application_name( );
     475
     476    msgs = tr_getQueuedMessages();
     477    for( i=msgs; i; i=i->next )
     478    {
     479        GtkTreeIter unused;
     480
     481        gtk_list_store_insert_with_values( data->store, &unused, -1,
     482                                           COL_LEVEL, (int)i->level,
     483                                           COL_LINE, i->line,
     484                                           COL_FILE, i->file,
     485                                           COL_TIME, (uint64_t)i->when,
     486                                           COL_CATEGORY, ( i->name ? i->name : default_category ),
     487                                           COL_MESSAGE, i->message,
     488                                           COL_SEQUENCE, sequence++,
     489                                           -1 );
     490    }
     491    tr_freeMessageList( msgs );
     492}
Note: See TracChangeset for help on using the changeset viewer.