~kroq-gar78/ubuntu/precise/gnome-control-center/fix-885947

« back to all changes in this revision

Viewing changes to panels/datetime/cc-datetime-panel.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodrigo Moya
  • Date: 2011-05-17 10:47:27 UTC
  • mfrom: (0.1.11 experimental) (1.1.45 upstream)
  • Revision ID: james.westby@ubuntu.com-20110517104727-lqel6m8vhfw5jby1
Tags: 1:3.0.1.1-1ubuntu1
* Rebase on Debian, remaining Ubuntu changes:
* debian/control:
  - Build-Depend on hardening-wrapper, dpkg-dev and dh-autoreconf
  - Add dependency on ubuntu-system-service
  - Remove dependency on gnome-icon-theme-symbolic
  - Move dependency on apg, gnome-icon-theme-symbolic and accountsservice to
    be a Recommends: until we get them in main
* debian/rules:
  - Use autoreconf
  - Add binary-post-install rule for gnome-control-center-data
  - Run dh-autoreconf
* debian/gnome-control-center.dirs:
* debian/gnome-control-center.links:
  - Add a link to the control center shell for indicators
* debian/patches/00_disable-nm.patch:
  - Temporary patch to disable building with NetworkManager until we get
    the new one in the archive
* debian/patches/01_git_remove_gettext_calls.patch:
  - Remove calls to AM_GNU_GETTEXT, IT_PROG_INTLTOOL should be enough
* debian/patches/01_git_kill_warning.patch:
  - Kill warning
* debian/patches/50_ubuntu_systemwide_prefs.patch:
  - Ubuntu specific proxy preferences
* debian/patches/51_ubuntu_system_keyboard.patch:
  - Implement the global keyboard spec at https://wiki.ubuntu.com/DefaultKeyboardSettings

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010 Intel, Inc
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
17
 *
 
18
 * Author: Thomas Wood <thomas.wood@intel.com>
 
19
 *
 
20
 */
 
21
 
 
22
#include "cc-datetime-panel.h"
 
23
 
 
24
#include <sys/time.h>
 
25
#include "cc-timezone-map.h"
 
26
#include "set-timezone.h"
 
27
#include "libgnome-control-center/cc-lockbutton.h"
 
28
#include "date-endian.h"
 
29
 
 
30
#include <gdesktop-enums.h>
 
31
#include <string.h>
 
32
#include <stdlib.h>
 
33
#include <libintl.h>
 
34
#include <polkit/polkit.h>
 
35
 
 
36
/* FIXME: This should be "Etc/GMT" instead */
 
37
#define DEFAULT_TZ "Europe/London"
 
38
#define GETTEXT_PACKAGE_TIMEZONES GETTEXT_PACKAGE "-timezones"
 
39
 
 
40
G_DEFINE_DYNAMIC_TYPE (CcDateTimePanel, cc_date_time_panel, CC_TYPE_PANEL)
 
41
 
 
42
#define DATE_TIME_PANEL_PRIVATE(o) \
 
43
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CC_TYPE_DATE_TIME_PANEL, CcDateTimePanelPrivate))
 
44
 
 
45
enum {
 
46
  CITY_COL_CITY,
 
47
  CITY_COL_REGION,
 
48
  CITY_COL_CITY_TRANSLATED,
 
49
  CITY_COL_REGION_TRANSLATED,
 
50
  CITY_COL_ZONE,
 
51
  CITY_NUM_COLS
 
52
};
 
53
 
 
54
enum {
 
55
  REGION_COL_REGION,
 
56
  REGION_COL_REGION_TRANSLATED,
 
57
  REGION_NUM_COLS
 
58
};
 
59
 
 
60
#define W(x) (GtkWidget*) gtk_builder_get_object (priv->builder, x)
 
61
 
 
62
#define CLOCK_SCHEMA "org.gnome.desktop.interface"
 
63
#define CLOCK_FORMAT_KEY "clock-format"
 
64
 
 
65
struct _CcDateTimePanelPrivate
 
66
{
 
67
  GtkBuilder *builder;
 
68
  GtkWidget *map;
 
69
 
 
70
  TzLocation *current_location;
 
71
 
 
72
  GtkTreeModel *locations;
 
73
  GtkTreeModelFilter *city_filter;
 
74
 
 
75
  GDateTime *date;
 
76
 
 
77
  GSettings *settings;
 
78
  GDesktopClockFormat clock_format;
 
79
 
 
80
  guint update_id;
 
81
};
 
82
 
 
83
static void update_time (CcDateTimePanel *self);
 
84
static void queue_clock_update (CcDateTimePanel *self);
 
85
 
 
86
static void
 
87
cc_date_time_panel_get_property (GObject    *object,
 
88
                               guint       property_id,
 
89
                               GValue     *value,
 
90
                               GParamSpec *pspec)
 
91
{
 
92
  switch (property_id)
 
93
    {
 
94
    default:
 
95
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
96
    }
 
97
}
 
98
 
 
99
static void
 
100
cc_date_time_panel_set_property (GObject      *object,
 
101
                               guint         property_id,
 
102
                               const GValue *value,
 
103
                               GParamSpec   *pspec)
 
104
{
 
105
  switch (property_id)
 
106
    {
 
107
    default:
 
108
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
109
    }
 
110
}
 
111
 
 
112
static void
 
113
cc_date_time_panel_dispose (GObject *object)
 
114
{
 
115
  CcDateTimePanelPrivate *priv = CC_DATE_TIME_PANEL (object)->priv;
 
116
 
 
117
  if (priv->update_id != 0)
 
118
    {
 
119
      g_source_remove (priv->update_id);
 
120
      priv->update_id = 0;
 
121
    }
 
122
 
 
123
  if (priv->builder)
 
124
    {
 
125
      g_object_unref (priv->builder);
 
126
      priv->builder = NULL;
 
127
    }
 
128
 
 
129
  if (priv->settings)
 
130
    {
 
131
      g_object_unref (priv->settings);
 
132
      priv->settings = NULL;
 
133
    }
 
134
 
 
135
  if (priv->date)
 
136
    {
 
137
      g_date_time_unref (priv->date);
 
138
      priv->date = NULL;
 
139
    }
 
140
 
 
141
  G_OBJECT_CLASS (cc_date_time_panel_parent_class)->dispose (object);
 
142
}
 
143
 
 
144
static void
 
145
cc_date_time_panel_class_init (CcDateTimePanelClass *klass)
 
146
{
 
147
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
148
 
 
149
  g_type_class_add_private (klass, sizeof (CcDateTimePanelPrivate));
 
150
 
 
151
  object_class->get_property = cc_date_time_panel_get_property;
 
152
  object_class->set_property = cc_date_time_panel_set_property;
 
153
  object_class->dispose = cc_date_time_panel_dispose;
 
154
}
 
155
 
 
156
static void
 
157
cc_date_time_panel_class_finalize (CcDateTimePanelClass *klass)
 
158
{
 
159
 
 
160
}
 
161
 
 
162
static void clock_settings_changed_cb (GSettings       *settings,
 
163
                                       gchar           *key,
 
164
                                       CcDateTimePanel *panel);
 
165
 
 
166
static void
 
167
change_clock_settings (GObject         *gobject,
 
168
                       GParamSpec      *pspec,
 
169
                       CcDateTimePanel *panel)
 
170
{
 
171
  CcDateTimePanelPrivate *priv = panel->priv;
 
172
  GDesktopClockFormat value;
 
173
 
 
174
  g_signal_handlers_block_by_func (priv->settings, clock_settings_changed_cb,
 
175
                                   panel);
 
176
 
 
177
  if (gtk_switch_get_active (GTK_SWITCH (W ("24h_time_switch"))))
 
178
    value = G_DESKTOP_CLOCK_FORMAT_24H;
 
179
  else
 
180
    value = G_DESKTOP_CLOCK_FORMAT_12H;
 
181
 
 
182
  g_settings_set_enum (priv->settings, CLOCK_FORMAT_KEY, value);
 
183
  priv->clock_format = value;
 
184
 
 
185
  update_time (panel);
 
186
 
 
187
  g_signal_handlers_unblock_by_func (priv->settings, clock_settings_changed_cb,
 
188
                                     panel);
 
189
}
 
190
 
 
191
static void
 
192
clock_settings_changed_cb (GSettings       *settings,
 
193
                           gchar           *key,
 
194
                           CcDateTimePanel *panel)
 
195
{
 
196
  CcDateTimePanelPrivate *priv = panel->priv;
 
197
  GtkWidget *switch24h;
 
198
  gboolean use_24_hour;
 
199
  GDesktopClockFormat value;
 
200
 
 
201
  value = g_settings_get_enum (settings, CLOCK_FORMAT_KEY);
 
202
  priv->clock_format = value;
 
203
 
 
204
  switch24h = W ("24h_time_switch");
 
205
 
 
206
  use_24_hour = (value == G_DESKTOP_CLOCK_FORMAT_24H);
 
207
 
 
208
  g_signal_handlers_block_by_func (switch24h, change_clock_settings, panel);
 
209
 
 
210
  gtk_switch_set_active (GTK_SWITCH (switch24h), use_24_hour);
 
211
 
 
212
  update_time (panel);
 
213
 
 
214
  g_signal_handlers_unblock_by_func (switch24h, change_clock_settings, panel);
 
215
}
 
216
 
 
217
static void
 
218
update_time (CcDateTimePanel *self)
 
219
{
 
220
  CcDateTimePanelPrivate *priv = self->priv;
 
221
  char *label;
 
222
  char *am_pm_widgets[] = {"ampm_up_button", "ampm_down_button", "ampm_label" };
 
223
  guint i;
 
224
 
 
225
  if (priv->clock_format == G_DESKTOP_CLOCK_FORMAT_24H)
 
226
    {
 
227
      /* Update the hours label */
 
228
      label = g_date_time_format (priv->date, "%H");
 
229
      gtk_label_set_text (GTK_LABEL (W("hours_label")), label);
 
230
      g_free (label);
 
231
    }
 
232
  else
 
233
    {
 
234
      /* Update the hours label */
 
235
      label = g_date_time_format (priv->date, "%I");
 
236
      gtk_label_set_text (GTK_LABEL (W("hours_label")), label);
 
237
      g_free (label);
 
238
 
 
239
      /* Set AM/PM */
 
240
      label = g_date_time_format (priv->date, "%p");
 
241
      gtk_label_set_text (GTK_LABEL (W("ampm_label")), label);
 
242
      g_free (label);
 
243
    }
 
244
 
 
245
  for (i = 0; i < G_N_ELEMENTS (am_pm_widgets); i++)
 
246
    gtk_widget_set_visible (W(am_pm_widgets[i]),
 
247
                            priv->clock_format == G_DESKTOP_CLOCK_FORMAT_12H);
 
248
 
 
249
  /* Update the minutes label */
 
250
  label = g_date_time_format (priv->date, "%M");
 
251
  gtk_label_set_text (GTK_LABEL (W("minutes_label")), label);
 
252
  g_free (label);
 
253
}
 
254
 
 
255
static void
 
256
set_time_cb (CcDateTimePanel *self,
 
257
             GError          *error)
 
258
{
 
259
  /* TODO: display any error in a user friendly way */
 
260
  if (error)
 
261
    {
 
262
      g_warning ("Could not set system time: %s", error->message);
 
263
    }
 
264
  else
 
265
    {
 
266
      update_time (self);
 
267
    }
 
268
}
 
269
 
 
270
static void
 
271
set_timezone_cb (CcDateTimePanel *self,
 
272
                 GError          *error)
 
273
{
 
274
  /* TODO: display any error in a user friendly way */
 
275
  if (error)
 
276
    {
 
277
      g_warning ("Could not set system timezone: %s", error->message);
 
278
    }
 
279
}
 
280
 
 
281
static void
 
282
set_using_ntp_cb (CcDateTimePanel *self,
 
283
                  GError          *error)
 
284
{
 
285
  /* TODO: display any error in a user friendly way */
 
286
  if (error)
 
287
    {
 
288
      g_warning ("Could not set system to use NTP: %s", error->message);
 
289
    }
 
290
}
 
291
 
 
292
static void
 
293
queue_set_datetime (CcDateTimePanel *self)
 
294
{
 
295
  time_t unixtime;
 
296
 
 
297
  /* for now just do it */
 
298
  unixtime = g_date_time_to_unix (self->priv->date);
 
299
  set_system_time_async (unixtime, (GFunc) set_time_cb, self, NULL);
 
300
}
 
301
 
 
302
static void
 
303
queue_set_ntp (CcDateTimePanel *self)
 
304
{
 
305
  CcDateTimePanelPrivate *priv = self->priv;
 
306
  gboolean using_ntp;
 
307
  /* for now just do it */
 
308
  using_ntp = gtk_switch_get_active (GTK_SWITCH (W("network_time_switch")));
 
309
  set_using_ntp_async (using_ntp, (GFunc) set_using_ntp_cb, self, NULL);
 
310
}
 
311
 
 
312
static void
 
313
queue_set_timezone (CcDateTimePanel *self)
 
314
{
 
315
  /* for now just do it */
 
316
  if (self->priv->current_location)
 
317
    {
 
318
      set_system_timezone_async (self->priv->current_location->zone, (GFunc) set_timezone_cb, self, NULL);
 
319
    }
 
320
}
 
321
 
 
322
static void
 
323
change_date (CcDateTimePanel *self)
 
324
{
 
325
  CcDateTimePanelPrivate *priv = self->priv;
 
326
  guint mon, y, d;
 
327
  GDateTime *old_date;
 
328
 
 
329
  old_date = priv->date;
 
330
 
 
331
  mon = 1 + gtk_combo_box_get_active (GTK_COMBO_BOX (W ("month-combobox")));
 
332
  y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (W ("year-spinbutton")));
 
333
  d = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (W ("day-spinbutton")));
 
334
 
 
335
  priv->date = g_date_time_new_local (y, mon, d,
 
336
                                      g_date_time_get_hour (old_date),
 
337
                                      g_date_time_get_minute (old_date),
 
338
                                      g_date_time_get_second (old_date));
 
339
  g_date_time_unref (old_date);
 
340
  queue_set_datetime (self);
 
341
}
 
342
 
 
343
static void
 
344
region_changed_cb (GtkComboBox     *box,
 
345
                   CcDateTimePanel *self)
 
346
{
 
347
  GtkTreeModelFilter *modelfilter;
 
348
 
 
349
  modelfilter = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (self->priv->builder, "city-modelfilter"));
 
350
 
 
351
  gtk_tree_model_filter_refilter (modelfilter);
 
352
}
 
353
 
 
354
static void
 
355
city_changed_cb (GtkComboBox     *box,
 
356
                 CcDateTimePanel *self)
 
357
{
 
358
  static gboolean inside = FALSE;
 
359
  GtkTreeIter iter;
 
360
  gchar *zone;
 
361
 
 
362
  /* prevent re-entry from location changed callback */
 
363
  if (inside)
 
364
    return;
 
365
 
 
366
  inside = TRUE;
 
367
 
 
368
  if (gtk_combo_box_get_active_iter (box, &iter))
 
369
    {
 
370
      gtk_tree_model_get (gtk_combo_box_get_model (box), &iter,
 
371
                          CITY_COL_ZONE, &zone, -1);
 
372
 
 
373
      cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), zone);
 
374
 
 
375
      g_free (zone);
 
376
    }
 
377
 
 
378
  inside = FALSE;
 
379
}
 
380
 
 
381
static void
 
382
update_timezone (CcDateTimePanel *self)
 
383
{
 
384
  CcDateTimePanelPrivate *priv = self->priv;
 
385
  GtkWidget *widget;
 
386
  gchar **split;
 
387
  GtkTreeIter iter;
 
388
  GtkTreeModel *model;
 
389
 
 
390
  /* tz.c updates the local timezone, which means the spin buttons can be
 
391
   * updated with the current time of the new location */
 
392
 
 
393
  split = g_strsplit (priv->current_location->zone, "/", 2);
 
394
 
 
395
  /* remove underscores */
 
396
  g_strdelimit (split[1], "_", ' ');
 
397
 
 
398
  /* update region combo */
 
399
  widget = (GtkWidget *) gtk_builder_get_object (priv->builder,
 
400
                                                 "region_combobox");
 
401
  model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
 
402
  gtk_tree_model_get_iter_first (model, &iter);
 
403
 
 
404
  do
 
405
    {
 
406
      gchar *string;
 
407
 
 
408
      gtk_tree_model_get (model, &iter, CITY_COL_CITY, &string, -1);
 
409
 
 
410
      if (!g_strcmp0 (string, split[0]))
 
411
        {
 
412
          g_free (string);
 
413
          gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
 
414
          break;
 
415
        }
 
416
      g_free (string);
 
417
    }
 
418
  while (gtk_tree_model_iter_next (model, &iter));
 
419
 
 
420
 
 
421
  /* update city combo */
 
422
  widget = (GtkWidget *) gtk_builder_get_object (priv->builder,
 
423
                                                 "city_combobox");
 
424
  model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
 
425
  gtk_tree_model_filter_refilter ((GtkTreeModelFilter *) gtk_builder_get_object (priv->builder, "city-modelfilter"));
 
426
  gtk_tree_model_get_iter_first (model, &iter);
 
427
 
 
428
  do
 
429
    {
 
430
      gchar *string;
 
431
 
 
432
      gtk_tree_model_get (model, &iter, CITY_COL_CITY, &string, -1);
 
433
 
 
434
      if (!g_strcmp0 (string, split[1]))
 
435
        {
 
436
          g_free (string);
 
437
          gtk_combo_box_set_active_iter (GTK_COMBO_BOX (widget), &iter);
 
438
          break;
 
439
        }
 
440
      g_free (string);
 
441
    }
 
442
  while (gtk_tree_model_iter_next (model, &iter));
 
443
 
 
444
  g_strfreev (split);
 
445
}
 
446
 
 
447
static void
 
448
location_changed_cb (CcTimezoneMap   *map,
 
449
                     TzLocation      *location,
 
450
                     CcDateTimePanel *self)
 
451
{
 
452
  CcDateTimePanelPrivate *priv = self->priv;
 
453
  GtkWidget *region_combo, *city_combo;
 
454
 
 
455
  g_debug ("location changed to %s/%s", location->country, location->zone);
 
456
 
 
457
  self->priv->current_location = location;
 
458
 
 
459
  /* Update the combo boxes */
 
460
  region_combo = W("region_combobox");
 
461
  city_combo = W("city_combobox");
 
462
 
 
463
  g_signal_handlers_block_by_func (region_combo, region_changed_cb, self);
 
464
  g_signal_handlers_block_by_func (city_combo, city_changed_cb, self);
 
465
 
 
466
  update_timezone (self);
 
467
 
 
468
  g_signal_handlers_unblock_by_func (region_combo, region_changed_cb, self);
 
469
  g_signal_handlers_unblock_by_func (city_combo, city_changed_cb, self);
 
470
 
 
471
  queue_set_timezone (self);
 
472
}
 
473
 
 
474
static void
 
475
get_timezone_cb (CcDateTimePanel *self,
 
476
                 const gchar     *timezone,
 
477
                 GError          *error)
 
478
{
 
479
  GtkWidget *widget;
 
480
 
 
481
  if (error)
 
482
    {
 
483
      g_warning ("Could not get current timezone: %s", error->message);
 
484
    }
 
485
  else
 
486
    {
 
487
      if (!cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), timezone))
 
488
        {
 
489
          g_warning ("Timezone '%s' is unhandled, setting %s as default", timezone, DEFAULT_TZ);
 
490
          cc_timezone_map_set_timezone (CC_TIMEZONE_MAP (self->priv->map), DEFAULT_TZ);
 
491
        }
 
492
      self->priv->current_location = cc_timezone_map_get_location (CC_TIMEZONE_MAP (self->priv->map));
 
493
      update_timezone (self);
 
494
    }
 
495
 
 
496
  /* now that the initial state is loaded set connect the signals */
 
497
  widget = (GtkWidget*) gtk_builder_get_object (self->priv->builder,
 
498
                                                "region_combobox");
 
499
  g_signal_connect (widget, "changed", G_CALLBACK (region_changed_cb), self);
 
500
 
 
501
  widget = (GtkWidget*) gtk_builder_get_object (self->priv->builder,
 
502
                                                "city_combobox");
 
503
  g_signal_connect (widget, "changed", G_CALLBACK (city_changed_cb), self);
 
504
 
 
505
  g_signal_connect (self->priv->map, "location-changed",
 
506
                    G_CALLBACK (location_changed_cb), self);
 
507
 
 
508
}
 
509
 
 
510
/* load region and city tree models */
 
511
struct get_region_data
 
512
{
 
513
  GtkListStore *region_store;
 
514
  GtkListStore *city_store;
 
515
  GHashTable *table;
 
516
};
 
517
 
 
518
/* Slash look-alikes that might be used in translations */
 
519
#define TRANSLATION_SPLIT                                                        \
 
520
        "\342\201\204"        /* FRACTION SLASH */                               \
 
521
        "\342\210\225"        /* DIVISION SLASH */                               \
 
522
        "\342\247\270"        /* BIG SOLIDUS */                                  \
 
523
        "\357\274\217"        /* FULLWIDTH SOLIDUS */                            \
 
524
        "/"
 
525
 
 
526
static void
 
527
get_regions (TzLocation             *loc,
 
528
             struct get_region_data *data)
 
529
{
 
530
  gchar *zone;
 
531
  gchar **split;
 
532
  gchar **split_translated;
 
533
  gchar *translated_city;
 
534
 
 
535
  zone = g_strdup (loc->zone);
 
536
  g_strdelimit (zone, "_", ' ');
 
537
  split = g_strsplit (zone, "/", 2);
 
538
  g_free (zone);
 
539
 
 
540
  /* Load the translation for it */
 
541
  zone = g_strdup (dgettext (GETTEXT_PACKAGE_TIMEZONES, loc->zone));
 
542
  g_strdelimit (zone, "_", ' ');
 
543
  split_translated = g_regex_split_simple ("[\\x{2044}\\x{2215}\\x{29f8}\\x{ff0f}/]", zone, 0, 0);
 
544
  g_free (zone);
 
545
 
 
546
  if (!g_hash_table_lookup_extended (data->table, split[0], NULL, NULL))
 
547
    {
 
548
      g_hash_table_insert (data->table, g_strdup (split[0]),
 
549
                           GINT_TO_POINTER (1));
 
550
      gtk_list_store_insert_with_values (data->region_store, NULL, 0,
 
551
                                         REGION_COL_REGION, split[0],
 
552
                                         REGION_COL_REGION_TRANSLATED, split_translated[0], -1);
 
553
    }
 
554
 
 
555
  /* g_regex_split_simple() splits too much for us, and would break
 
556
   * America/Argentina/Buenos_Aires into 3 strings, so rejoin the city part */
 
557
  translated_city = g_strjoinv ("/", split_translated + 1);
 
558
 
 
559
  gtk_list_store_insert_with_values (data->city_store, NULL, 0,
 
560
                                     CITY_COL_CITY, split[1],
 
561
                                     CITY_COL_CITY_TRANSLATED, translated_city,
 
562
                                     CITY_COL_REGION, split[0],
 
563
                                     CITY_COL_REGION_TRANSLATED, split_translated[0],
 
564
                                     CITY_COL_ZONE, loc->zone,
 
565
                                     -1);
 
566
 
 
567
  g_free (translated_city);
 
568
  g_strfreev (split);
 
569
  g_strfreev (split_translated);
 
570
}
 
571
 
 
572
static gboolean
 
573
city_model_filter_func (GtkTreeModel *model,
 
574
                        GtkTreeIter  *iter,
 
575
                        GtkComboBox  *combo)
 
576
{
 
577
  GtkTreeModel *combo_model;
 
578
  GtkTreeIter combo_iter;
 
579
  gchar *active_region = NULL;
 
580
  gchar *city_region = NULL;
 
581
  gboolean result;
 
582
 
 
583
  if (gtk_combo_box_get_active_iter (combo, &combo_iter) == FALSE)
 
584
    return FALSE;
 
585
 
 
586
  combo_model = gtk_combo_box_get_model (combo);
 
587
  gtk_tree_model_get (combo_model, &combo_iter,
 
588
                      CITY_COL_CITY, &active_region, -1);
 
589
 
 
590
  gtk_tree_model_get (model, iter,
 
591
                      CITY_COL_REGION, &city_region, -1);
 
592
 
 
593
  if (g_strcmp0 (active_region, city_region) == 0)
 
594
    result = TRUE;
 
595
  else
 
596
    result = FALSE;
 
597
 
 
598
  g_free (city_region);
 
599
 
 
600
  g_free (active_region);
 
601
 
 
602
  return result;
 
603
}
 
604
 
 
605
 
 
606
static void
 
607
load_regions_model (GtkListStore *regions, GtkListStore *cities)
 
608
{
 
609
  struct get_region_data data;
 
610
  TzDB *db;
 
611
  GHashTable *table;
 
612
 
 
613
 
 
614
  db = tz_load_db ();
 
615
  table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
616
 
 
617
  data.table = table;
 
618
  data.region_store = regions;
 
619
  data.city_store = cities;
 
620
 
 
621
  g_ptr_array_foreach (db->locations, (GFunc) get_regions, &data);
 
622
 
 
623
  g_hash_table_destroy (table);
 
624
 
 
625
  tz_db_free (db);
 
626
 
 
627
  /* sort the models */
 
628
  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (regions),
 
629
                                        REGION_COL_REGION_TRANSLATED,
 
630
                                        GTK_SORT_ASCENDING);
 
631
}
 
632
 
 
633
static void
 
634
update_widget_state_for_ntp (CcDateTimePanel *panel,
 
635
                             gboolean         using_ntp)
 
636
{
 
637
  CcDateTimePanelPrivate *priv = panel->priv;
 
638
 
 
639
  gtk_widget_set_sensitive (W("table1"), !using_ntp);
 
640
  gtk_widget_set_sensitive (W("table2"), !using_ntp);
 
641
}
 
642
 
 
643
static void
 
644
day_changed (GtkWidget       *widget,
 
645
             CcDateTimePanel *panel)
 
646
{
 
647
  change_date (panel);
 
648
}
 
649
 
 
650
static void
 
651
month_year_changed (GtkWidget       *widget,
 
652
                    CcDateTimePanel *panel)
 
653
{
 
654
  CcDateTimePanelPrivate *priv = panel->priv;
 
655
  guint mon, y;
 
656
  guint num_days;
 
657
  GtkAdjustment *adj;
 
658
  GtkSpinButton *day_spin;
 
659
 
 
660
  mon = 1 + gtk_combo_box_get_active (GTK_COMBO_BOX (W ("month-combobox")));
 
661
  y = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (W ("year-spinbutton")));
 
662
 
 
663
  /* Check the number of days in that month */
 
664
  num_days = g_date_get_days_in_month (mon, y);
 
665
 
 
666
  day_spin = GTK_SPIN_BUTTON (W("day-spinbutton"));
 
667
  adj = GTK_ADJUSTMENT (gtk_spin_button_get_adjustment (day_spin));
 
668
  gtk_adjustment_set_upper (adj, num_days + 1);
 
669
 
 
670
  if (gtk_spin_button_get_value_as_int (day_spin) > num_days)
 
671
    gtk_spin_button_set_value (day_spin, num_days);
 
672
 
 
673
  change_date (panel);
 
674
}
 
675
 
 
676
static void
 
677
change_time (GtkButton       *button,
 
678
             CcDateTimePanel *panel)
 
679
{
 
680
  CcDateTimePanelPrivate *priv = panel->priv;
 
681
  const gchar *widget_name;
 
682
  gint direction;
 
683
  GDateTime *old_date;
 
684
 
 
685
  old_date = priv->date;
 
686
 
 
687
  widget_name = gtk_buildable_get_name (GTK_BUILDABLE (button));
 
688
 
 
689
  if (strstr (widget_name, "up"))
 
690
    direction = 1;
 
691
  else
 
692
    direction = -1;
 
693
 
 
694
  if (widget_name[0] == 'h')
 
695
    {
 
696
      priv->date = g_date_time_add_hours (old_date, direction);
 
697
    }
 
698
  else if (widget_name[0] == 'm')
 
699
    {
 
700
      priv->date = g_date_time_add_minutes (old_date, direction);
 
701
    }
 
702
  else
 
703
    {
 
704
      int hour;
 
705
      hour = g_date_time_get_hour (old_date);
 
706
      if (hour >= 12)
 
707
        priv->date = g_date_time_add_hours (old_date, -12);
 
708
      else
 
709
        priv->date = g_date_time_add_hours (old_date, 12);
 
710
    }
 
711
  g_date_time_unref (old_date);
 
712
 
 
713
  update_time (panel);
 
714
  queue_set_datetime (panel);
 
715
}
 
716
 
 
717
static void
 
718
change_ntp (GObject         *gobject,
 
719
            GParamSpec      *pspec,
 
720
            CcDateTimePanel *self)
 
721
{
 
722
  update_widget_state_for_ntp (self, gtk_switch_get_active (GTK_SWITCH (gobject)));
 
723
  queue_set_ntp (self);
 
724
}
 
725
 
 
726
static gboolean
 
727
update_time_timer (CcDateTimePanel *self)
 
728
{
 
729
  g_date_time_unref (self->priv->date);
 
730
  self->priv->date = g_date_time_new_now_local ();
 
731
  update_time (self);
 
732
  queue_clock_update (self);
 
733
  return FALSE;
 
734
}
 
735
 
 
736
static void
 
737
queue_clock_update (CcDateTimePanel *self)
 
738
{
 
739
  int timeouttime;
 
740
  struct timeval tv;
 
741
 
 
742
  gettimeofday (&tv, NULL);
 
743
  timeouttime = (G_USEC_PER_SEC - tv.tv_usec) / 1000 + 1;
 
744
 
 
745
  /* timeout of one minute if we don't care about the seconds */
 
746
  timeouttime += 1000 * (59 - tv.tv_sec % 60);
 
747
 
 
748
  self->priv->update_id = g_timeout_add (timeouttime, (GSourceFunc)update_time_timer, self);
 
749
}
 
750
 
 
751
static void
 
752
on_permission_changed (GPermission *permission,
 
753
                       GParamSpec  *pspec,
 
754
                       gpointer     data)
 
755
{
 
756
  CcDateTimePanelPrivate *priv = CC_DATE_TIME_PANEL (data)->priv;
 
757
  gboolean allowed;
 
758
 
 
759
  allowed = g_permission_get_allowed (permission);
 
760
 
 
761
  /* All the widgets but the lock button and the 24h setting */
 
762
  gtk_widget_set_sensitive (W("map-vbox"), allowed);
 
763
  gtk_widget_set_sensitive (W("hbox2"), allowed);
 
764
  gtk_widget_set_sensitive (W("alignment2"), allowed);
 
765
  gtk_widget_set_sensitive (W("table1"), allowed);
 
766
}
 
767
 
 
768
static void
 
769
reorder_date_widget (DateEndianess           endianess,
 
770
                     CcDateTimePanelPrivate *priv)
 
771
{
 
772
  GtkWidget *month, *day, *year;
 
773
  GtkBox *box;
 
774
 
 
775
  if (endianess == DATE_ENDIANESS_MIDDLE)
 
776
    return;
 
777
 
 
778
  month = W ("month-combobox");
 
779
  day = W ("day-spinbutton");
 
780
  year = W("year-spinbutton");
 
781
 
 
782
  box = GTK_BOX (W("table1"));
 
783
 
 
784
  switch (endianess) {
 
785
  case DATE_ENDIANESS_LITTLE:
 
786
    gtk_box_reorder_child (box, month, 0);
 
787
    gtk_box_reorder_child (box, day, 0);
 
788
    gtk_box_reorder_child (box, year, -1);
 
789
    break;
 
790
  case DATE_ENDIANESS_BIG:
 
791
    gtk_box_reorder_child (box, month, 0);
 
792
    gtk_box_reorder_child (box, year, 0);
 
793
    gtk_box_reorder_child (box, day, -1);
 
794
    break;
 
795
  case DATE_ENDIANESS_MIDDLE:
 
796
    /* Let's please GCC */
 
797
    g_assert_not_reached ();
 
798
    break;
 
799
  }
 
800
}
 
801
 
 
802
static void
 
803
cc_date_time_panel_init (CcDateTimePanel *self)
 
804
{
 
805
  CcDateTimePanelPrivate *priv;
 
806
  gchar *objects[] = { "datetime-panel", "region-liststore", "city-liststore",
 
807
      "month-liststore", "city-modelfilter", "city-modelsort", NULL };
 
808
  char *buttons[] = { "hour_up_button", "hour_down_button", "min_up_button",
 
809
          "min_down_button", "ampm_up_button", "ampm_down_button" };
 
810
  GtkWidget *widget;
 
811
  GtkAdjustment *adjustment;
 
812
  GError *err = NULL;
 
813
  GtkTreeModelFilter *city_modelfilter;
 
814
  GtkTreeModelSort *city_modelsort;
 
815
  guint i, num_days;
 
816
  gboolean using_ntp;
 
817
  int ret;
 
818
  GtkWidget *lockbutton;
 
819
  GPermission *permission;
 
820
  DateEndianess endianess;
 
821
 
 
822
  priv = self->priv = DATE_TIME_PANEL_PRIVATE (self);
 
823
 
 
824
  priv->builder = gtk_builder_new ();
 
825
 
 
826
  ret = gtk_builder_add_objects_from_file (priv->builder, DATADIR"/datetime.ui",
 
827
                                           objects, &err);
 
828
 
 
829
  if (ret == 0)
 
830
    {
 
831
      g_warning ("Could not load ui: %s", err ? err->message : "No reason");
 
832
      if (err)
 
833
        g_error_free (err);
 
834
      return;
 
835
    }
 
836
 
 
837
  /* set up network time button */
 
838
  using_ntp = get_using_ntp ();
 
839
  gtk_switch_set_active (GTK_SWITCH (W("network_time_switch")), using_ntp);
 
840
  update_widget_state_for_ntp (self, using_ntp);
 
841
  g_signal_connect (W("network_time_switch"), "notify::active",
 
842
                    G_CALLBACK (change_ntp), self);
 
843
 
 
844
  /* set up time editing widgets */
 
845
  for (i = 0; i < G_N_ELEMENTS (buttons); i++)
 
846
    {
 
847
      g_signal_connect (W(buttons[i]), "clicked",
 
848
                        G_CALLBACK (change_time), self);
 
849
    }
 
850
 
 
851
  /* set up date editing widgets */
 
852
  priv->date = g_date_time_new_now_local ();
 
853
  endianess = date_endian_get_default (FALSE);
 
854
  reorder_date_widget (endianess, priv);
 
855
 
 
856
  /* Force the direction for the time, so that the time
 
857
   * is presented correctly for RTL languages */
 
858
  gtk_widget_set_direction (W("table2"), GTK_TEXT_DIR_LTR);
 
859
 
 
860
  gtk_combo_box_set_active (GTK_COMBO_BOX (W ("month-combobox")),
 
861
                            g_date_time_get_month (priv->date) - 1);
 
862
  g_signal_connect (G_OBJECT (W("month-combobox")), "changed",
 
863
                    G_CALLBACK (month_year_changed), self);
 
864
 
 
865
  num_days = g_date_get_days_in_month (g_date_time_get_month (priv->date),
 
866
                                       g_date_time_get_year (priv->date));
 
867
  adjustment = (GtkAdjustment*) gtk_adjustment_new (g_date_time_get_day_of_month (priv->date), 1,
 
868
                                                    num_days + 1, 1, 10, 1);
 
869
  gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (W ("day-spinbutton")),
 
870
                                  adjustment);
 
871
  g_signal_connect (G_OBJECT (W("day-spinbutton")), "value-changed",
 
872
                    G_CALLBACK (day_changed), self);
 
873
 
 
874
  adjustment = (GtkAdjustment*) gtk_adjustment_new (g_date_time_get_year (priv->date),
 
875
                                                    G_MINDOUBLE, G_MAXDOUBLE, 1,
 
876
                                                    10, 1);
 
877
  gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (W ("year-spinbutton")),
 
878
                                  adjustment);
 
879
  g_signal_connect (G_OBJECT (W("year-spinbutton")), "value-changed",
 
880
                    G_CALLBACK (month_year_changed), self);
 
881
 
 
882
  /* set up timezone map */
 
883
  priv->map = widget = (GtkWidget *) cc_timezone_map_new ();
 
884
  gtk_widget_show (widget);
 
885
 
 
886
  gtk_container_add (GTK_CONTAINER (gtk_builder_get_object (priv->builder,
 
887
                                                            "aspectmap")),
 
888
                     widget);
 
889
 
 
890
  gtk_container_add (GTK_CONTAINER (self),
 
891
                     GTK_WIDGET (gtk_builder_get_object (priv->builder,
 
892
                                                         "datetime-panel")));
 
893
 
 
894
 
 
895
  /* setup the time itself */
 
896
  priv->settings = g_settings_new (CLOCK_SCHEMA);
 
897
  clock_settings_changed_cb (priv->settings, CLOCK_FORMAT_KEY, self);
 
898
  g_signal_connect (priv->settings, "changed::" CLOCK_FORMAT_KEY,
 
899
                    G_CALLBACK (clock_settings_changed_cb), self);
 
900
 
 
901
  g_signal_connect (W("24h_time_switch"), "notify::active",
 
902
                    G_CALLBACK (change_clock_settings), self);
 
903
 
 
904
  update_time (self);
 
905
 
 
906
  priv->locations = (GtkTreeModel*) gtk_builder_get_object (priv->builder,
 
907
                                                            "region-liststore");
 
908
 
 
909
  load_regions_model (GTK_LIST_STORE (priv->locations),
 
910
                      GTK_LIST_STORE (gtk_builder_get_object (priv->builder,
 
911
                                                              "city-liststore")));
 
912
 
 
913
  city_modelfilter = GTK_TREE_MODEL_FILTER (gtk_builder_get_object (priv->builder, "city-modelfilter"));
 
914
 
 
915
  widget = (GtkWidget*) gtk_builder_get_object (priv->builder,
 
916
                                                "region_combobox");
 
917
  city_modelsort = GTK_TREE_MODEL_SORT (gtk_builder_get_object (priv->builder, "city-modelsort"));
 
918
  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (city_modelsort), CITY_COL_CITY_TRANSLATED,
 
919
                                        GTK_SORT_ASCENDING);
 
920
 
 
921
  gtk_tree_model_filter_set_visible_func (city_modelfilter,
 
922
                                          (GtkTreeModelFilterVisibleFunc) city_model_filter_func,
 
923
                                          widget,
 
924
                                          NULL);
 
925
 
 
926
  /* After the initial setup, so we can be sure that
 
927
   * the model is filled up */
 
928
  get_system_timezone_async ((GetTimezoneFunc) get_timezone_cb, self, NULL);
 
929
 
 
930
  queue_clock_update (self);
 
931
 
 
932
  /* add the lock button */
 
933
  permission = polkit_permission_new_sync ("org.gnome.settingsdaemon.datetimemechanism.configure", NULL, NULL, NULL);
 
934
  if (permission == NULL)
 
935
    {
 
936
      g_warning ("Your system does not have the '%s' PolicyKit files installed. Please check your installation",
 
937
                 "org.gnome.settingsdaemon.datetimemechanism.configure");
 
938
      return;
 
939
    }
 
940
 
 
941
  /* DtLockButton takes ownership of the permission */
 
942
  lockbutton = cc_lock_button_new (permission);
 
943
  gtk_widget_set_margin_top (lockbutton, 12);
 
944
  gtk_widget_show (lockbutton);
 
945
  gtk_box_pack_end ((GtkBox *) gtk_builder_get_object (priv->builder, "hbox"),
 
946
                    lockbutton, FALSE, FALSE, 0);
 
947
  g_signal_connect (permission, "notify",
 
948
                    G_CALLBACK (on_permission_changed), self);
 
949
  on_permission_changed (permission, NULL, self);
 
950
}
 
951
 
 
952
void
 
953
cc_date_time_panel_register (GIOModule *module)
 
954
{
 
955
  bind_textdomain_codeset (GETTEXT_PACKAGE_TIMEZONES, "UTF-8");
 
956
 
 
957
  cc_date_time_panel_register_type (G_TYPE_MODULE (module));
 
958
  g_io_extension_point_implement (CC_SHELL_PANEL_EXTENSION_POINT,
 
959
                                  CC_TYPE_DATE_TIME_PANEL,
 
960
                                  "datetime", 0);
 
961
}
 
962