~ubuntu-branches/debian/sid/gworldclock/sid

« back to all changes in this revision

Viewing changes to zones.c

  • Committer: Bazaar Package Importer
  • Author(s): Drew Parsons
  • Date: 2005-03-28 13:50:18 UTC
  • mfrom: (1.2.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050328135018-jk2szisqaovghn3s
Tags: 1.4.4-1
* New upstream version.
  - modernised design of AddZone dialog. Closes: #193952.
  - removed use of deprecated GTK functions and objects.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* functions related to selecting time zones */
 
2
 
 
3
#include <stdio.h>
 
4
#include <errno.h>
 
5
#include <gtk/gtk.h>
 
6
#include <libintl.h>
 
7
 
 
8
#include "gworldclock.h"
 
9
#include "zones.h"
 
10
#include "misc.h"
 
11
 
 
12
#define _(A) gettext(A)
 
13
 
 
14
 
 
15
void DeleteZone( GtkWidget *w, gpointer clocklist )
 
16
{
 
17
   extern gint changed;
 
18
   GString *title, *msg;
 
19
   gchar *button[]={"OK"};
 
20
   GtkTreeModel *clocklistModel;
 
21
   GtkTreeIter iter;
 
22
 
 
23
   if ( gtk_tree_selection_get_selected( 
 
24
           gtk_tree_view_get_selection( clocklist ),
 
25
           &clocklistModel,
 
26
           &iter ) )
 
27
   {
 
28
      gtk_list_store_remove( GTK_LIST_STORE(clocklistModel), &iter );
 
29
      changed = 1;
 
30
      resizeWindow( gtk_widget_get_toplevel( GTK_WIDGET(clocklist) ), 
 
31
                    clocklist );
 
32
   }
 
33
   else 
 
34
   {
 
35
      title = g_string_new(_("Delete Zone"));
 
36
      msg = g_string_new(_("No zone chosen for deleting."));
 
37
      showMessageDialog( msg->str, GTK_MESSAGE_WARNING );
 
38
      g_string_free(msg,TRUE);
 
39
      g_string_free(title,TRUE);
 
40
   }
 
41
}
 
42
 
 
43
 
 
44
/*  Save list of time zones to configfile */
 
45
gint SaveZones(GtkWidget *w, gpointer clocklist)
 
46
{
 
47
  FILE *cf;
 
48
  extern GString *configfile;
 
49
  extern gint changed;
 
50
  gint N,i;
 
51
  gchar *description, *timezone;
 
52
  GtkTreeModel *clocklistModel;
 
53
  GtkTreeIter iter;
 
54
  gboolean gotIter = FALSE;
 
55
 
 
56
  if ( !(cf=fopen(configfile->str,"w")) ) {
 
57
    return 0;
 
58
  }
 
59
 
 
60
  clocklistModel = gtk_tree_view_get_model( clocklist );
 
61
  gotIter =  gtk_tree_model_get_iter_first(clocklistModel, &iter);
 
62
 
 
63
  while( gotIter )
 
64
  {
 
65
     gtk_tree_model_get( clocklistModel, &iter,
 
66
                         TZ_NAME, &timezone,
 
67
                         TZ_DESCRIPTION, &description,
 
68
                         -1);
 
69
 
 
70
    /* only write description if there is one! */
 
71
    if(strlen(description)==0)
 
72
      fprintf(cf,"%s\n", timezone );
 
73
    else
 
74
       fprintf(cf,"%s    \"%s\"\n", timezone, description );
 
75
 
 
76
    g_free(timezone);
 
77
    g_free(description);
 
78
    gotIter = gtk_tree_model_iter_next( clocklistModel, &iter );
 
79
  }
 
80
 
 
81
  changed=0;
 
82
  return ( ! fclose( cf ) );
 
83
}
 
84
 
 
85
/* Handle "rows_reordered" signal, indicating the rows in the clock have been
 
86
   moved */
 
87
/* Note this callback function does not get  called for some reason,
 
88
   I don't know why.  A bug in GTK+ ? 
 
89
   You will have to save the reordered list by hand for the time being.
 
90
*/
 
91
void registerReorderedRows( GtkTreeModel* clocklistModel,
 
92
                             GtkTreePath *arg1,
 
93
                             GtkTreeIter *arg2,
 
94
                             gpointer new_order,
 
95
                             gpointer user_data)
 
96
{
 
97
  extern gint changed;
 
98
 
 
99
  /* mark clocklist as "changed" */
 
100
  changed = 1;
 
101
}
 
102
 
 
103
gint CodeInList(gchar *code, GSList *List)
 
104
{
 
105
  /* can't use g_slist_find, unfortunately, since the data in the list is both the
 
106
     country code and (unknown) country name
 
107
  */
 
108
 
 
109
  GSList *item;
 
110
 
 
111
  item = List;
 
112
  while (item) {
 
113
    if ( ! strcmp(code,((NameCodeType *)item->data)->code) )
 
114
      return TRUE;  /* found match */
 
115
    item = item->next;
 
116
  }
 
117
  return FALSE;
 
118
}
 
119
 
 
120
GSList* AddNameCodeEntry(gchar *code, gchar *name, GSList *List)
 
121
{
 
122
  NameCodeType *entry;
 
123
 
 
124
  entry = g_malloc0(sizeof(NameCodeType));
 
125
  if(!entry)
 
126
    g_print(_("Could not create list: %s"),g_strerror(errno));
 
127
  entry->name = g_strdup(name);
 
128
  entry->code = g_strdup(code);
 
129
  List = g_slist_append(List, (gpointer)entry);
 
130
 
 
131
  /* we don't free entry here do we?  It's on record and is only to be freed when
 
132
     the item is released from the list */
 
133
  return List;
 
134
}
 
135
 
 
136
/* the documentation is not too clear about allocating and free lists */
 
137
/* does g_slist_free deallocate all the links in the list, or just the first? */
 
138
/* I will assume it does the entire list */
 
139
void  ClearNameCodeList(GSList **List) 
 
140
{
 
141
  GSList *item;
 
142
 
 
143
  if(*List) {
 
144
    item = *List;
 
145
    while (item) {
 
146
      g_free( ((NameCodeType *)item->data)->name );
 
147
      g_free( ((NameCodeType *)item->data)->code );
 
148
      item = item->next;
 
149
    }
 
150
    g_slist_free(*List);
 
151
  }
 
152
  *List=NULL;
 
153
}
 
154
 
 
155
/* for given continent, find corresponding countries as identified in ZONE_TABLE
 
156
   and prepare list of country name using COUNTRY_TABLE
 
157
*/
 
158
 
 
159
GSList* FetchCountries(gchar *continent)
 
160
{
 
161
  FILE *fpc, *fpz;
 
162
  GString *title, *msg;
 
163
  gchar *button[]={"OK"};
 
164
  gchar line[500];
 
165
  gchar *codec, *codez, *name;
 
166
  GSList *Countries;
 
167
  
 
168
  if (strlen(continent)==0 )
 
169
    return NULL;
 
170
 
 
171
  if ( !(fpz=fopen(ZONE_TABLE,"r")) ) {  
 
172
    title = g_string_new(_("Read Zone Table"));
 
173
    msg = g_string_new(NULL);
 
174
    g_string_sprintf(msg,_(" Error reading zone table \"%s\": \n %s \nHow very sad.\n"),
 
175
                     ZONE_TABLE , g_strerror(errno) );
 
176
    showMessageDialog( msg->str, GTK_MESSAGE_ERROR );
 
177
    g_string_free(msg,TRUE);
 
178
    g_string_free(title,TRUE);
 
179
  }
 
180
  if ( !(fpc=fopen(COUNTRY_TABLE,"r")) ) {  
 
181
    title = g_string_new(_("Read Zone Table"));
 
182
    msg = g_string_new(NULL);
 
183
    g_string_sprintf(msg,_(" Error reading country table \"%s\": \n %s \nHow very sad.\n"),
 
184
                     COUNTRY_TABLE , g_strerror(errno) );
 
185
    showMessageDialog( msg->str, GTK_MESSAGE_ERROR );
 
186
    g_string_free(msg,TRUE);
 
187
    g_string_free(title,TRUE);
 
188
  }
 
189
 
 
190
  Countries=NULL;
 
191
  while(fgets(line,500,fpz)) {
 
192
    if (line[0] != '#') {
 
193
      
 
194
      /* check for continent in TZ value (third item on the line in ZONE_TABLE)
 
195
         Also read country code at beginning of zone table entry.
 
196
         Strictly this is only 2 characters, but I will allow for a whole string
 
197
         (in my opinion 3 character would be more meaningful.  The standard sux */
 
198
      sscanf(line,"%as %*s %as",&codez,&name);
 
199
      if(strstr(name,continent)) {
 
200
        if(!CodeInList(codez,Countries)) {
 
201
          g_free(name);
 
202
          rewind(fpc);
 
203
          while(fgets(line,500,fpc)) {
 
204
            if (line[0] != '#') {
 
205
 
 
206
              /* first, identify country */
 
207
              if(sscanf(line,"%as",&codec)==1) {
 
208
                if (!strcmp(codez,codec)) {
 
209
 
 
210
                  /* then extract name as entire string to \0 after tab */
 
211
                  /* (first make sure \n in line is reset to \0) */
 
212
                  name = (gchar *) strchr(line,'\n');
 
213
                  *name = '\0';
 
214
                  name = (gchar *) strchr(line,'\t');
 
215
                  name++;
 
216
 
 
217
                  Countries = AddNameCodeEntry(codec,name,Countries);
 
218
                }
 
219
                g_free(codec);
 
220
              } 
 
221
            }
 
222
          }  
 
223
        }
 
224
      }
 
225
      else
 
226
        g_free(name);
 
227
      g_free(codez);
 
228
    }
 
229
  }
 
230
  fclose(fpc);
 
231
  fclose(fpz);
 
232
 
 
233
  return Countries;
 
234
}
 
235
 
 
236
 
 
237
 
 
238
/* from given country code ("*country"), find list of regions in ZONE_TABLE */
 
239
/* input: country is the two-letter country code from ISO3166 */
 
240
GSList* FetchRegions(gchar *country)
 
241
{
 
242
  FILE *fp;
 
243
  GString *title, *msg;
 
244
  gchar *button[]={"OK"};
 
245
  gchar line[500];
 
246
  gchar *code, *TZvalue, *region, *ptr;
 
247
  GSList *Regions;
 
248
 
 
249
  if (strlen(country)==0 )
 
250
    return NULL;
 
251
 
 
252
  if ( !(fp=fopen(ZONE_TABLE,"r")) ) {  
 
253
    title = g_string_new(_("Read Zone Table"));
 
254
    msg = g_string_new(NULL);
 
255
    g_string_sprintf(msg,_(" Error reading zone table \"%s\": \n %s \nHow very sad.\n"),
 
256
                     ZONE_TABLE , g_strerror(errno) );
 
257
    showMessageDialog( msg->str, GTK_MESSAGE_ERROR );
 
258
    g_string_free(msg,TRUE);
 
259
    g_string_free(title,TRUE);
 
260
  }
 
261
 
 
262
  Regions=NULL;
 
263
  while(fgets(line,500,fp)) {
 
264
    if (line[0] != '#') {
 
265
      /* check for entries corresponding to country code value 
 
266
         (first item on the line in ZONE_TABLE)
 
267
         Get name of region from third item on the line. */
 
268
      /* alternatively we may want to get the description from the optional
 
269
         fourth item, where available.  Worry about that some other time */
 
270
      sscanf(line,"%as %*s %as",&code,&TZvalue);
 
271
      if(!strcmp(code,country)) {
 
272
        /* region name is in format:  continent/region
 
273
           Extract the region part from the continent */
 
274
        ptr = (gchar *) strchr(TZvalue,'/');
 
275
        if(ptr)
 
276
          region = g_strdup((gchar*)(ptr+1));
 
277
        else
 
278
          region = g_strdup(TZvalue);
 
279
 
 
280
        /* Some regions have an underscore '_' in place of space */
 
281
        /* convert these to a real space */
 
282
        while( (ptr=(gchar*)strchr(region,'_')) ) 
 
283
          *ptr = ' ';
 
284
 
 
285
        if(!CodeInList(TZvalue,Regions))
 
286
          Regions = AddNameCodeEntry(TZvalue,region,Regions);
 
287
        g_free(region);
 
288
      }
 
289
      g_free(TZvalue);
 
290
      g_free(code);
 
291
    }
 
292
  }
 
293
  fclose(fp);
 
294
 
 
295
  return Regions;
 
296
}
 
297
 
 
298
void UpdateCountries(GtkTreeSelection *selection, gpointer ZoneNotes)
 
299
{
 
300
    GtkTreeIter iter ;
 
301
    GtkTreeModel *model;
 
302
    gchar *continent;
 
303
 
 
304
    GtkTreeModel *store;
 
305
    GtkTreeModel *filteredStore;
 
306
    GtkTreePath *path;
 
307
    GtkWidget *tree;
 
308
    GtkWidget *scrolled_window;
 
309
    GtkTreeSelection *countrySelection;
 
310
    
 
311
    AddZoneStruct *zoneData;
 
312
 
 
313
    if (gtk_tree_selection_get_selected (selection, &model, &iter))
 
314
    {
 
315
        gtk_tree_model_get (model, &iter, CONTINENT_NAME, &continent, -1);
 
316
 
 
317
        filteredStore = gtk_tree_view_get_model( gtk_tree_selection_get_tree_view(selection) );
 
318
        store = gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER(filteredStore) );
 
319
        path = gtk_tree_model_get_path( GTK_TREE_MODEL(filteredStore), &iter );     
 
320
        path = gtk_tree_model_filter_convert_path_to_child_path( GTK_TREE_MODEL_FILTER(filteredStore), path );
 
321
 
 
322
 
 
323
        filteredStore = gtk_tree_model_filter_new( GTK_TREE_MODEL(store), path );
 
324
        if ( path ) gtk_tree_path_free( path );
 
325
        
 
326
        gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filteredStore),
 
327
                                               FilterCountries,
 
328
                                               NULL, NULL );
 
329
        
 
330
        GtkWidget *label = gtk_label_new( _("Countries") );
 
331
        tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(filteredStore));
 
332
        gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(tree), FALSE );
 
333
        gtk_widget_show(tree);
 
334
 
 
335
        GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
 
336
        GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes ("Name",
 
337
                                                           renderer,
 
338
                                                           "text", COUNTRY_NAME,
 
339
                                                           NULL);
 
340
        gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
 
341
 
 
342
        scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 
343
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
 
344
                                  GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
 
345
        gtk_widget_show (scrolled_window);
 
346
        gtk_container_add(GTK_CONTAINER(scrolled_window), tree);
 
347
 
 
348
        gtk_notebook_remove_page( (GtkNotebook*)ZoneNotes, COUNTRY_NAME );
 
349
        gtk_notebook_insert_page ( (GtkNotebook*)ZoneNotes, scrolled_window, 
 
350
                                  label, COUNTRY_NAME );
 
351
 
 
352
        countrySelection = gtk_tree_view_get_selection( GTK_TREE_VIEW(tree) );
 
353
        gtk_tree_selection_set_mode (countrySelection, GTK_SELECTION_SINGLE);
 
354
        g_signal_connect (G_OBJECT (countrySelection), "changed",
 
355
                          G_CALLBACK (UpdateRegions),
 
356
                          ZoneNotes);
 
357
 
 
358
        zoneData = (AddZoneStruct*) g_object_get_data(G_OBJECT(ZoneNotes),ZONE_DATA);
 
359
        zoneData->countryTreeView = GTK_TREE_VIEW(tree);
 
360
 
 
361
        /* update region list straight away to match first country on
 
362
          this continent  */
 
363
        gtk_tree_model_get_iter_first(GTK_TREE_MODEL(filteredStore),
 
364
                                      &iter);
 
365
        gtk_tree_selection_select_iter(countrySelection, &iter);
 
366
 
 
367
        g_free (continent);
 
368
    }
 
369
}
 
370
 
 
371
void UpdateRegions(GtkTreeSelection *selection, gpointer ZoneNotes)
 
372
{
 
373
    GtkTreeIter iter ;
 
374
    GtkTreeModel *model;
 
375
    gchar *country;
 
376
 
 
377
    GtkTreeModel *store;
 
378
    GtkTreeModel *filteredStore;
 
379
    GtkTreePath *path;
 
380
    GtkWidget *tree;
 
381
    GtkTreeSelection *regionSelection;
 
382
    GtkWidget *scrolled_window;
 
383
 
 
384
    AddZoneStruct *zoneData;
 
385
 
 
386
    if (gtk_tree_selection_get_selected (selection, &model, &iter))
 
387
    {
 
388
        gtk_tree_model_get (model, &iter, COUNTRY_NAME, &country, -1);
 
389
 
 
390
        filteredStore = gtk_tree_view_get_model( gtk_tree_selection_get_tree_view(selection) );
 
391
        store = gtk_tree_model_filter_get_model( GTK_TREE_MODEL_FILTER(filteredStore) );
 
392
        path = gtk_tree_model_get_path( GTK_TREE_MODEL(filteredStore), &iter );     
 
393
        path = gtk_tree_model_filter_convert_path_to_child_path( GTK_TREE_MODEL_FILTER(filteredStore), path );
 
394
 
 
395
 
 
396
        filteredStore = gtk_tree_model_filter_new( GTK_TREE_MODEL(store), path );
 
397
        if ( path ) gtk_tree_path_free( path );
 
398
        
 
399
        gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filteredStore),
 
400
                                               FilterRegions,
 
401
                                               NULL, NULL );
 
402
        
 
403
        GtkWidget *label = gtk_label_new( _("Regions") );
 
404
        tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(filteredStore));
 
405
        gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(tree), FALSE );
 
406
        gtk_widget_show(tree);
 
407
 
 
408
        GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
 
409
        GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes ("Name",
 
410
                                                           renderer,
 
411
                                                           "text", REGION_NAME,
 
412
                                                           NULL);
 
413
        gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
 
414
 
 
415
        scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 
416
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
 
417
                                  GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
 
418
        gtk_widget_show (scrolled_window);
 
419
        gtk_container_add(GTK_CONTAINER(scrolled_window), tree);
 
420
 
 
421
        gtk_notebook_remove_page( (GtkNotebook*)ZoneNotes, REGION_NAME );
 
422
        gtk_notebook_insert_page( (GtkNotebook*)ZoneNotes, scrolled_window, 
 
423
                                  label, REGION_NAME );
 
424
 
 
425
        regionSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW (tree));
 
426
        gtk_tree_selection_set_mode (regionSelection, GTK_SELECTION_SINGLE);
 
427
        g_signal_connect( G_OBJECT(regionSelection), "changed",
 
428
                          G_CALLBACK(SelectRegion),
 
429
                          g_object_get_data(G_OBJECT(ZoneNotes),ZONE_DATA));
 
430
 
 
431
        g_signal_connect(G_OBJECT(tree),
 
432
                         "button_press_event",
 
433
                         G_CALLBACK(ButtonPressedInRegionList),
 
434
                         (gpointer)g_object_get_data(G_OBJECT(ZoneNotes),ZONE_DATA));
 
435
 
 
436
        zoneData = (AddZoneStruct*) g_object_get_data(G_OBJECT(ZoneNotes),ZONE_DATA);
 
437
        zoneData->regionTreeView = GTK_TREE_VIEW(tree);
 
438
 
 
439
        g_free (country);
 
440
    }
 
441
}
 
442
 
 
443
void SelectRegion(GtkTreeSelection *selection, gpointer ZoneData)
 
444
{
 
445
    GtkTreeIter iter ;
 
446
    GtkTreeModel *model;
 
447
    gchar *description, *TZ;
 
448
 
 
449
    if (gtk_tree_selection_get_selected (selection, &model, &iter))
 
450
    {
 
451
        gtk_tree_model_get (model, &iter, REGION_NAME, &description, 
 
452
                            CODE, &TZ,
 
453
                            -1);
 
454
    
 
455
        gtk_entry_set_text( (GtkEntry *)((AddZoneStruct*)ZoneData)->DescriptionEntry, 
 
456
                            description);
 
457
        gtk_entry_set_text( (GtkEntry *)((AddZoneStruct*)ZoneData)->TZEntry, TZ);
 
458
 
 
459
        g_free( description );
 
460
        g_free( TZ );
 
461
    }
 
462
}
 
463
 
 
464
/* when left mouse button is double-clicked,
 
465
   send "key-pressed-event" to one of the Entry boxes 
 
466
   which will be handled by adding the given zone.
 
467
   We're assuming here that "select-row" preceded the double-click event */
 
468
gboolean ButtonPressedInRegionList (GtkWidget *regionTreeView, 
 
469
                                     GdkEventButton *event,
 
470
                                     gpointer ZoneData)
 
471
{
 
472
    GdkEventKey *KeyEvent;
 
473
    
 
474
    static GtkWidget *popup;
 
475
    
 
476
    gboolean returnVal = FALSE;
 
477
    
 
478
    if( (event->button==1) && ( event->type==GDK_2BUTTON_PRESS))
 
479
    {
 
480
       KeyEvent = (GdkEventKey*)g_malloc(sizeof(GdkEventKey));
 
481
       KeyEvent->keyval=GDK_Return;
 
482
       gint return_val;
 
483
       g_signal_emit_by_name( G_OBJECT( ((AddZoneStruct*)ZoneData)->TZEntry ),
 
484
                                "key-press-event", (GdkEvent*)KeyEvent, &return_val);
 
485
       g_free(KeyEvent);
 
486
       returnVal = TRUE;
 
487
    }
 
488
 
 
489
    return returnVal;
 
490
}
 
491
 
 
492
 
 
493
/* Initialises (preexisting) iter to the node for the given column
 
494
   (whose value is identified by name) and returns TRUE.  Iter is
 
495
   invalid and FALSE returned, if there is no such name in the column.
 
496
*/ 
 
497
gboolean findRow( GtkTreeModel *model, const gint column, const gchar *nameToMatch, GtkTreeIter *iter )
 
498
{
 
499
    if( ! gtk_tree_model_get_iter_first( model, iter ) )
 
500
        return FALSE;
 
501
 
 
502
    gchar* name;
 
503
    gtk_tree_model_get( model, iter, column, &name, -1 );
 
504
    if ( name && !strcmp( nameToMatch, name ) )
 
505
    {
 
506
        g_free( name );
 
507
        return TRUE;
 
508
    }
 
509
    g_free(name);
 
510
 
 
511
    while( gtk_tree_model_iter_next( model, iter) )
 
512
    {
 
513
        gtk_tree_model_get( model, iter, column, &name, -1 );
 
514
        if ( name && !strcmp( nameToMatch, name ) )
 
515
        {
 
516
            g_free(name);
 
517
            return TRUE;
 
518
        }
 
519
    }
 
520
    g_free(name);
 
521
 
 
522
    return FALSE;
 
523
}
 
524
 
 
525
 
 
526
/* Implements GtkTreeModelFilterVisibleFunc, making continent entries
 
527
   only visible.
 
528
*/
 
529
gboolean FilterContinents(GtkTreeModel *model,
 
530
                          GtkTreeIter *iter,
 
531
                          gpointer data)
 
532
{
 
533
    gboolean visible;
 
534
 
 
535
    gchar *continentName;
 
536
    gchar *countryName;
 
537
    gchar *regionName;
 
538
 
 
539
    gtk_tree_model_get( model, iter, 
 
540
                        CONTINENT_NAME, &continentName, 
 
541
                        COUNTRY_NAME, &countryName, 
 
542
                        REGION_NAME, &regionName, 
 
543
                        -1 );
 
544
 
 
545
    visible = ( continentName && strlen(continentName)>0 ) && 
 
546
        ( (!countryName) || strlen(countryName)==0 ) &&
 
547
        ( (!regionName) || strlen(regionName)==0 ) ;
 
548
 
 
549
    g_free( continentName );
 
550
    g_free( countryName );
 
551
    g_free( regionName );
 
552
 
 
553
    return visible;
 
554
}
 
555
 
 
556
gboolean FilterCountries(GtkTreeModel *model,
 
557
                         GtkTreeIter *iter,
 
558
                         gpointer data)
 
559
{
 
560
    gboolean visible;
 
561
    gchar *countryName;
 
562
    gtk_tree_model_get( model, iter, 
 
563
                        COUNTRY_NAME, &countryName, 
 
564
                        -1 );
 
565
 
 
566
    visible = ( countryName && strlen(countryName)>0 );
 
567
 
 
568
    g_free( countryName );
 
569
 
 
570
    return visible;
 
571
}
 
572
 
 
573
gboolean FilterRegions(GtkTreeModel *model,
 
574
                       GtkTreeIter *iter,
 
575
                       gpointer data)
 
576
{
 
577
    gboolean visible;
 
578
    gchar *regionName;
 
579
    gtk_tree_model_get( model, iter, 
 
580
                        REGION_NAME, &regionName, 
 
581
                        -1 );
 
582
 
 
583
    visible = ( regionName && strlen(regionName)>0 );
 
584
    g_free( regionName );
 
585
 
 
586
    return visible;
 
587
}
 
588
 
 
589
 
 
590
/* zones are selected according to the method used in tzselect:
 
591
   First the continent is chosen, then, if necessary, the country is chosen,
 
592
   with countries being identified from the two-letter code in the
 
593
   entries of  [/usr/share/zoneinfo/]zone.tab (and country names taken from 
 
594
   iso3166.tab)  Then the region (or city) of that country is identified, from 
 
595
   zone.tab.
 
596
*/
 
597
 
 
598
void  PrepareZoneNotes(GtkWidget **ZoneNotes, AddZoneStruct *Zone)
 
599
{
 
600
    gint i;
 
601
    GtkTreeIter continentIter, countryIter, regionIter, iter;
 
602
    GtkTreePath *path;
 
603
    GtkTreeSelection *selection;
 
604
    GSList *countryList, *countryItem;
 
605
    GSList *regionList, *regionItem;
 
606
    gchar *name, *code;
 
607
    gchar *continentName, *ptr;
 
608
    gchar *ContinentLabel=_("Continents");
 
609
    gchar *CountryLabel=_("Countries");
 
610
    gchar *RegionLabel=_("Regions");
 
611
    gint columnId;
 
612
 
 
613
    /* collate date into a three-level tree.
 
614
       The first level represents continents,
 
615
       the second is regions/countries,
 
616
       the third is cities.
 
617
    */
 
618
   GtkTreeStore *store = gtk_tree_store_new (N_COLUMNS, 
 
619
                                             G_TYPE_STRING,
 
620
                                             G_TYPE_STRING,
 
621
                                             G_TYPE_STRING,
 
622
                                             G_TYPE_STRING ); 
 
623
 
 
624
    for( i=0; i<Ncontinents; i++) 
 
625
    {
 
626
        gtk_tree_store_append (store, &continentIter, NULL);
 
627
        gtk_tree_store_set (store, &continentIter,
 
628
                            CONTINENT_NAME, continents[i],
 
629
                            -1);
 
630
 
 
631
        /* add countries within that continent */
 
632
        continentName = g_strdup(continents[i]);
 
633
        /* change "Americas" to "America" by wiping out the 's' */
 
634
        if(!strcmp(continentName,"Americas"))
 
635
            continentName[7]='\0';
 
636
 
 
637
        /* similarly remove " Ocean" in "Pacific Ocean", etc
 
638
           by making the ' ' a null character */
 
639
        ptr = (gchar *) strchr(continentName,' ');
 
640
        if(ptr)
 
641
            *ptr='\0';
 
642
 
 
643
        countryList=FetchCountries(continentName);
 
644
        g_free(continentName);
 
645
        countryItem = countryList;
 
646
        while( countryItem ) 
 
647
        {
 
648
            name = ((NameCodeType *)countryItem->data)->name;
 
649
            code = ((NameCodeType *)countryItem->data)->code;
 
650
            gtk_tree_store_append (store, &countryIter, &continentIter);
 
651
            gtk_tree_store_set (store, &countryIter,
 
652
                                COUNTRY_NAME, name,
 
653
                                CODE, code,
 
654
                                -1);
 
655
 
 
656
 
 
657
            /* add regions and cities within that country */
 
658
            regionList=FetchRegions(code);
 
659
            regionItem = regionList;
 
660
            while( regionItem ) 
 
661
            {
 
662
                gtk_tree_store_append (store, &regionIter, &countryIter);
 
663
                name = ((NameCodeType *)regionItem->data)->name;
 
664
                code = ((NameCodeType *)regionItem->data)->code;
 
665
 
 
666
                gtk_tree_store_set (store, &regionIter,
 
667
                                    REGION_NAME, name,
 
668
                                    CODE, code,
 
669
                                    -1);
 
670
                regionItem = regionItem->next;
 
671
            }
 
672
            ClearNameCodeList(&regionList);
 
673
 
 
674
            countryItem = countryItem->next;
 
675
        }
 
676
        ClearNameCodeList(&countryList);
 
677
    }
 
678
 
 
679
 
 
680
    /* form the view of the tree */
 
681
 
 
682
    // continents
 
683
    GtkTreeModel* filteredStore = gtk_tree_model_filter_new( GTK_TREE_MODEL(store), NULL );
 
684
    
 
685
    gtk_tree_model_filter_set_visible_func(GTK_TREE_MODEL_FILTER(filteredStore),
 
686
                                           FilterContinents,
 
687
                                           NULL, NULL );
 
688
 
 
689
 
 
690
    *ZoneNotes = gtk_notebook_new ();
 
691
    gtk_widget_show(*ZoneNotes);
 
692
    g_object_set_data(G_OBJECT(*ZoneNotes), ZONE_DATA, Zone );
 
693
 
 
694
    GtkWidget *label;
 
695
    label = gtk_label_new (ContinentLabel);
 
696
    GtkWidget *tree;
 
697
 
 
698
    tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(filteredStore));
 
699
    gtk_tree_view_set_headers_visible( GTK_TREE_VIEW(tree), FALSE );
 
700
    gtk_widget_show(tree);
 
701
 
 
702
    GtkCellRenderer *renderer;
 
703
    GtkTreeViewColumn *column;
 
704
 
 
705
    renderer = gtk_cell_renderer_text_new ();
 
706
    column = gtk_tree_view_column_new_with_attributes ("Name",
 
707
                                                       renderer,
 
708
                                                       "text", CONTINENT_NAME,
 
709
                                                       NULL);
 
710
    gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
 
711
    gtk_notebook_insert_page(GTK_NOTEBOOK(*ZoneNotes), tree, 
 
712
                             label, CONTINENT_NAME );
 
713
 
 
714
    selection = gtk_tree_view_get_selection(GTK_TREE_VIEW (tree));
 
715
    gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
 
716
    g_signal_connect (G_OBJECT (selection), "changed",
 
717
                      G_CALLBACK (UpdateCountries),
 
718
                      (void*)*ZoneNotes);
 
719
 
 
720
 
 
721
    // countries, in default continent
 
722
    gboolean gotIt = findRow( GTK_TREE_MODEL(filteredStore),
 
723
                              CONTINENT_NAME, defaultContinent, &continentIter );
 
724
    path = NULL;
 
725
    if ( gotIt )
 
726
        gtk_tree_selection_select_iter( selection, &continentIter);
 
727
 
 
728
    filteredStore = gtk_tree_view_get_model( Zone->countryTreeView );
 
729
    selection = gtk_tree_view_get_selection( Zone->countryTreeView );
 
730
    gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
 
731
    g_signal_connect (G_OBJECT (selection), "changed",
 
732
                      G_CALLBACK (UpdateRegions),
 
733
                      (void*)*ZoneNotes);
 
734
 
 
735
 
 
736
 
 
737
    // regions, in default country
 
738
    gotIt = findRow( GTK_TREE_MODEL(filteredStore), COUNTRY_NAME, defaultCountry, &countryIter );
 
739
    if ( gotIt )
 
740
        gtk_tree_selection_select_iter( selection, &countryIter);
 
741
 
 
742
    filteredStore = gtk_tree_view_get_model( Zone->regionTreeView );
 
743
    selection = gtk_tree_view_get_selection( Zone->regionTreeView );
 
744
    gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
 
745
    g_signal_connect (G_OBJECT(selection), "changed",
 
746
                      G_CALLBACK (SelectRegion),
 
747
                      g_object_get_data(G_OBJECT(*ZoneNotes),ZONE_DATA));
 
748
 
 
749
    g_signal_connect(G_OBJECT(Zone->regionTreeView),
 
750
                     "button_press_event",
 
751
                     G_CALLBACK(ButtonPressedInRegionList),
 
752
                     (gpointer)Zone);
 
753
 
 
754
    /* default region/city  */
 
755
    gotIt = findRow( GTK_TREE_MODEL(filteredStore), REGION_NAME, defaultRegion, &regionIter );
 
756
    if ( gotIt )
 
757
    {
 
758
        gtk_tree_selection_select_iter( selection, &regionIter);
 
759
    }
 
760
 
 
761
 
 
762
}
 
763
 
 
764
 
 
765
void AddZoneToList(GtkWidget *w, gpointer NewZone)
 
766
{
 
767
  gchar *rowdata[2];
 
768
  gint row;
 
769
  extern gint changed;
 
770
  GtkTreeView *clocklist;
 
771
  GtkListStore *clocklistModel;
 
772
  GString *description;
 
773
  GString *TZ;
 
774
  GtkTreeIter iter;
 
775
 
 
776
  description = g_string_new(
 
777
     gtk_entry_get_text((GtkEntry *)((AddZoneStruct *)NewZone)->DescriptionEntry));
 
778
  TZ = g_string_new(
 
779
     gtk_entry_get_text((GtkEntry *)((AddZoneStruct *)NewZone)->TZEntry));
 
780
 
 
781
  /* check a time zone was given, if not, set to GMT */
 
782
  /* GST-0 is the "formal" TZ value for GMT */
 
783
  if ( TZ->len == 0 )
 
784
     g_string_assign(TZ,"GST-0");
 
785
  
 
786
  clocklist =  (GtkTreeView *)((AddZoneStruct *)NewZone)->clocklist;
 
787
  clocklistModel = GTK_LIST_STORE(gtk_tree_view_get_model( clocklist ));
 
788
  gtk_list_store_append ( clocklistModel, &iter);
 
789
  gtk_list_store_set ( clocklistModel, &iter,
 
790
                       TZ_NAME, TZ->str,
 
791
                       TZ_DESCRIPTION, description->str,
 
792
                       -1);     
 
793
 
 
794
  /* make new zone visible */
 
795
  gtk_tree_view_scroll_to_cell (clocklist,    
 
796
                                gtk_tree_model_get_path(GTK_TREE_MODEL(clocklistModel), &iter),
 
797
                                NULL, 
 
798
                                /* attn: non use_align not implemented yet in GTK+
 
799
                                   FALSE, 0, 0); */
 
800
                                TRUE, 0, 1);
 
801
  gtk_tree_selection_select_iter( 
 
802
     gtk_tree_view_get_selection( clocklist ),
 
803
     &iter );
 
804
 
 
805
  SetTime((gpointer)clocklist);
 
806
  changed=1;
 
807
 
 
808
  g_string_free(description,TRUE);
 
809
  g_string_free(TZ,TRUE);
 
810
}
 
811
 
 
812
void AddZone( GtkWidget *w, gpointer clocklist )
 
813
{
 
814
  GtkWidget *window; 
 
815
  GtkWidget *vbox, *hbox;
 
816
  GtkWidget *AddButton, *DoneButton;
 
817
  GtkWidget *ZoneNotes;
 
818
  GtkWidget *Frame;
 
819
  GtkWidget *EntryDescription, *EntryTZ;
 
820
  static AddZoneStruct NewZone;
 
821
 
 
822
  NewZone.clocklist = (GObject *) clocklist;
 
823
 
 
824
  EntryDescription = gtk_entry_new();
 
825
  NewZone.DescriptionEntry = (GtkWidget *)EntryDescription;
 
826
  EntryTZ = gtk_entry_new();
 
827
  NewZone.TZEntry = (GtkWidget *) EntryTZ;
 
828
 
 
829
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 
830
  gtk_window_set_title ((GtkWindow *)window, _("Add Time Zone"));
 
831
  gtk_window_position((GtkWindow *)window,GTK_WIN_POS_CENTER);
 
832
  gtk_container_set_border_width (GTK_CONTAINER (window), 5);
 
833
  
 
834
  vbox = gtk_vbox_new (FALSE, 0);
 
835
  gtk_container_add (GTK_CONTAINER (window), vbox);
 
836
  gtk_widget_show (vbox);
 
837
 
 
838
 
 
839
  /* display zone choices as notebook:
 
840
     Continents on one page, cities/countries on other
 
841
  */
 
842
  PrepareZoneNotes(&ZoneNotes,&NewZone);
 
843
  gtk_box_pack_start (GTK_BOX (vbox), ZoneNotes, TRUE, FALSE, 5);
 
844
 
 
845
 
 
846
  /* place zone in text entry box (allowing for manual entry if desired) */
 
847
  hbox = gtk_hbox_new (FALSE, 0);
 
848
  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 5);
 
849
  gtk_widget_show (hbox);
 
850
 
 
851
 
 
852
  /* box for text description of zone */
 
853
  Frame = gtk_frame_new (_("Description"));
 
854
  gtk_frame_set_shadow_type( (GtkFrame *)Frame, GTK_SHADOW_NONE); 
 
855
  gtk_box_pack_start (GTK_BOX (hbox), Frame, TRUE, FALSE, 5);
 
856
  gtk_widget_show (Frame);
 
857
  gtk_container_add (GTK_CONTAINER (Frame), EntryDescription);
 
858
  /* where did the entry boxes get their default size from?
 
859
     Not setting the size here (and below for TZ) makes the dialog box too large 
 
860
     Arguably too large, anyway - this is a question of taste of course */
 
861
  gtk_widget_set_usize( GTK_WIDGET(EntryDescription),125,0);
 
862
  gtk_widget_show (EntryDescription);
 
863
 
 
864
 
 
865
  /* box for TZ value of zone */
 
866
  Frame = gtk_frame_new (_("TZ value"));
 
867
  gtk_frame_set_shadow_type( (GtkFrame *)Frame, GTK_SHADOW_NONE); 
 
868
  gtk_box_pack_start (GTK_BOX (hbox), Frame, TRUE, FALSE, 5);
 
869
  gtk_widget_show (Frame);
 
870
  gtk_container_add (GTK_CONTAINER (Frame), EntryTZ);
 
871
  gtk_widget_set_usize( GTK_WIDGET(EntryTZ),125,0);
 
872
  gtk_widget_show (EntryTZ);
 
873
 
 
874
  /* buttons to accept zone, or exit */
 
875
  hbox = gtk_hbox_new (FALSE, 0);
 
876
  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 5);
 
877
  gtk_widget_show (hbox);
 
878
 
 
879
  AddButton = gtk_button_new_with_label (_("Add Zone"));
 
880
  g_signal_connect (G_OBJECT (AddButton), "clicked",
 
881
                      G_CALLBACK (AddZoneToList), (gpointer)&NewZone );
 
882
  gtk_box_pack_start (GTK_BOX (hbox), AddButton, TRUE, FALSE, 0);
 
883
  g_signal_connect (G_OBJECT (EntryDescription), "key-press-event",
 
884
                      G_CALLBACK (GotOK), (gpointer)AddButton);
 
885
  g_signal_connect (G_OBJECT (EntryTZ), "key-press-event",
 
886
                      G_CALLBACK (GotOK), (gpointer)AddButton);
 
887
  gtk_widget_show (AddButton);
 
888
 
 
889
  DoneButton = gtk_button_new_with_label (_("Done"));
 
890
  g_signal_connect (G_OBJECT (DoneButton), "clicked",
 
891
                      G_CALLBACK (DestroyWindow), (gpointer)window);
 
892
  gtk_box_pack_start (GTK_BOX (hbox), DoneButton, TRUE, FALSE, 0);
 
893
  gtk_widget_show (DoneButton);
 
894
 
 
895
  gtk_widget_show(window); 
 
896
}
 
897
 
 
898
void WriteZoneDescription(GtkDialog *dialog, gint responseId, gpointer Zone)
 
899
{
 
900
  extern gint changed;
 
901
  GString *description;
 
902
  GtkTreeView *clocklist;
 
903
  GtkTreeModel *clocklistModel;
 
904
  GtkTreeIter iter;
 
905
 
 
906
  if ( responseId == OK_BUTTON )
 
907
  {
 
908
     clocklist = GTK_TREE_VIEW(((AddZoneStruct *)Zone)->clocklist);
 
909
     if ( gtk_tree_selection_get_selected( 
 
910
             gtk_tree_view_get_selection(clocklist),
 
911
             &clocklistModel,
 
912
             &iter) )
 
913
     {
 
914
        
 
915
        description = g_string_new(
 
916
           gtk_entry_get_text((GtkEntry *)((AddZoneStruct *)Zone)->DescriptionEntry));
 
917
        
 
918
        gtk_list_store_set ( GTK_LIST_STORE(clocklistModel), 
 
919
                             &iter,
 
920
                             TZ_DESCRIPTION, description->str,
 
921
                             -1);     
 
922
        changed=1;
 
923
 
 
924
/*      gtk_tree_model_row_changed( clocklistModel,
 
925
                                   gtk_tree_model_get_path( clocklistModel, &iter),
 
926
                                    &iter);*/
 
927
//      resizeWindow( gtk_widget_get_toplevel( GTK_WIDGET(clocklist) ), 
 
928
        //clocklist );
 
929
     }
 
930
  }
 
931
 
 
932
  if ( responseId > 0 )
 
933
  {
 
934
     gtk_widget_destroy(GTK_WIDGET(dialog));
 
935
  }
 
936
}
 
937
  
 
938
void ChangeZoneDescription(GtkWidget *w, gpointer clocklist)
 
939
{
 
940
  gchar *description;
 
941
  GtkWidget *window, *vbox, *hbox;
 
942
  GtkWidget *DescriptionEntry, *OKButton, *CancelButton;
 
943
  static AddZoneStruct Zone;
 
944
  GString *title, *msg;
 
945
  gchar *button[]={"OK"};
 
946
  GtkTreeModel *clocklistModel;
 
947
  GtkTreeIter selectedRowIter;
 
948
 
 
949
  if ( ! gtk_tree_selection_get_selected( 
 
950
          gtk_tree_view_get_selection( clocklist ),
 
951
          &clocklistModel,
 
952
          &selectedRowIter ) )
 
953
  {
 
954
    /* is this dialog box useful? */
 
955
     showMessageDialog( _("No zone chosen for changing."), GTK_MESSAGE_WARNING );
 
956
     return;
 
957
  }
 
958
  
 
959
  gtk_tree_model_get( GTK_TREE_MODEL(clocklistModel), &selectedRowIter,
 
960
                      TZ_DESCRIPTION, &description,
 
961
                      -1);
 
962
 
 
963
  Zone.clocklist = (GObject *) clocklist;
 
964
 
 
965
  window = gtk_dialog_new_with_buttons ( _("Change Zone Description"),
 
966
                                         NULL,
 
967
                                         GTK_DIALOG_NO_SEPARATOR,
 
968
                                         "OK", OK_BUTTON,
 
969
                                         "Cancel", CANCEL_BUTTON,
 
970
                                         NULL);
 
971
 
 
972
  gtk_window_position((GtkWindow *)window,GTK_WIN_POS_CENTER);
 
973
  gtk_container_set_border_width (GTK_CONTAINER (window), 5);
 
974
 
 
975
  DescriptionEntry = gtk_entry_new();
 
976
  Zone.DescriptionEntry = DescriptionEntry;
 
977
  gtk_entry_set_text( (GtkEntry *) DescriptionEntry, description);
 
978
  g_signal_connect (G_OBJECT (DescriptionEntry), "key-press-event",
 
979
                      G_CALLBACK (GotOKInDialog), (gpointer)window);
 
980
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(window)->vbox), DescriptionEntry);
 
981
  gtk_widget_show (DescriptionEntry);
 
982
 
 
983
  g_signal_connect (G_OBJECT (window), "response",
 
984
                            G_CALLBACK(WriteZoneDescription), 
 
985
                            (gpointer)&Zone );
 
986
 
 
987
  gtk_widget_show(window);
 
988
}
 
989