only the tree is needed
[psensor.git] / src / ui_sensorpref.c
1 /*
2  * Copyright (C) 2010-2013 jeanfi@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * 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., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA
18  */
19 #include <stdlib.h>
20
21 #include <gtk/gtk.h>
22
23 #include "cfg.h"
24 #include "ui_pref.h"
25 #include "ui_sensorlist.h"
26 #include "ui_sensorpref.h"
27 #include "ui_color.h"
28
29 #if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
30 #include "ui_appindicator.h"
31 #endif
32
33 enum {
34         COL_NAME = 0,
35         COL_SENSOR
36 };
37
38 struct sensor_pref {
39         struct psensor *sensor;
40         char *name;
41         int enabled;
42         struct color *color;
43         int alarm_enabled;
44         int alarm_high_threshold;
45         int alarm_low_threshold;
46         unsigned int appindicator_enabled;
47 };
48
49 struct cb_data {
50         struct ui_psensor *ui;
51         GtkBuilder *builder;
52 };
53
54 static struct sensor_pref *sensor_pref_new(struct psensor *s,
55                                            struct config *cfg)
56 {
57         struct sensor_pref *p;
58
59         p = malloc(sizeof(struct sensor_pref));
60
61         p->sensor = s;
62         p->name = strdup(s->name);
63         p->enabled = s->enabled;
64         p->alarm_enabled = s->alarm_enabled;
65         p->color = color_dup(s->color);
66
67         if (cfg->temperature_unit == CELCIUS) {
68                 p->alarm_high_threshold = s->alarm_high_threshold;
69                 p->alarm_low_threshold = s->alarm_low_threshold;
70         } else {
71                 p->alarm_high_threshold
72                         = celcius_to_fahrenheit(s->alarm_high_threshold);
73                 p->alarm_low_threshold
74                         = celcius_to_fahrenheit(s->alarm_low_threshold);
75         }
76
77         p->appindicator_enabled = s->appindicator_enabled;
78
79         return p;
80 }
81
82 static void sensor_pref_free(struct sensor_pref *p)
83 {
84         if (!p)
85                 return ;
86
87         free(p->name);
88         free(p->color);
89
90         free(p);
91 }
92
93 static struct sensor_pref *
94 get_selected_sensor_pref(GtkTreeView *tree)
95 {
96         GtkTreeModel *model;
97         GtkTreeIter iter;
98         struct sensor_pref *pref;
99         GtkTreeSelection *selection;
100
101         selection = gtk_tree_view_get_selection(tree);
102
103         pref = NULL;
104         if (gtk_tree_selection_get_selected(selection, &model, &iter))
105                 gtk_tree_model_get(model, &iter, COL_SENSOR, &pref, -1);
106
107         return pref;
108 }
109
110 static void on_name_changed(GtkEntry *entry, gpointer data)
111 {
112         struct sensor_pref *p;
113         const char *str;
114
115         str = gtk_entry_get_text(entry);
116
117         p = get_selected_sensor_pref(GTK_TREE_VIEW(data));
118
119         if (p && strcmp(p->name, str)) {
120                 free(p->name);
121                 p->name = strdup(str);
122         }
123 }
124
125 static void
126 on_drawed_toggled(GtkToggleButton *btn, gpointer data)
127 {
128         struct sensor_pref *p;
129
130         p = get_selected_sensor_pref(GTK_TREE_VIEW(data));
131
132         if (p)
133                 p->enabled = gtk_toggle_button_get_active(btn);
134 }
135
136 static void
137 on_alarm_toggled(GtkToggleButton *btn, gpointer data)
138 {
139         struct sensor_pref *p;
140
141         p = get_selected_sensor_pref(GTK_TREE_VIEW(data));
142
143         if (p)
144                 p->alarm_enabled = gtk_toggle_button_get_active(btn);
145 }
146
147 static void
148 on_appindicator_toggled(GtkToggleButton *btn, gpointer data)
149 {
150         struct sensor_pref *p;
151
152         p = get_selected_sensor_pref(GTK_TREE_VIEW(data));
153
154         if (p)
155                 p->appindicator_enabled = gtk_toggle_button_get_active(btn);
156 }
157
158 static void on_color_set(GtkColorButton *widget, gpointer data)
159 {
160         struct sensor_pref *p;
161         GdkColor color;
162
163         p = get_selected_sensor_pref(GTK_TREE_VIEW(data));
164
165         if (p) {
166                 gtk_color_button_get_color(widget, &color);
167                 color_set(p->color, color.red, color.green, color.blue);
168         }
169 }
170
171 static void on_alarm_high_threshold_changed(GtkSpinButton *btn, gpointer data)
172 {
173         struct sensor_pref *p;
174
175         p = get_selected_sensor_pref(GTK_TREE_VIEW(data));
176
177         if (p)
178                 p->alarm_high_threshold = gtk_spin_button_get_value(btn);
179 }
180
181 static void on_alarm_low_threshold_changed(GtkSpinButton *btn, gpointer data)
182 {
183         struct sensor_pref *p;
184
185         p = get_selected_sensor_pref(GTK_TREE_VIEW(data));
186
187         if (p)
188                 p->alarm_low_threshold = gtk_spin_button_get_value(btn);
189 }
190
191 static void connect_signals(GtkBuilder *builder, GtkTreeView *tree)
192 {
193         g_signal_connect(gtk_builder_get_object(builder, "sensor_name"),
194                          "changed", G_CALLBACK(on_name_changed), tree);
195
196         g_signal_connect(gtk_builder_get_object(builder, "sensor_draw"),
197                          "toggled", G_CALLBACK(on_drawed_toggled), tree);
198
199         g_signal_connect(gtk_builder_get_object(builder, "sensor_color"),
200                          "color-set", G_CALLBACK(on_color_set), tree);
201
202         g_signal_connect(gtk_builder_get_object(builder, "sensor_alarm"),
203                          "toggled", G_CALLBACK(on_alarm_toggled), tree);
204
205         g_signal_connect(gtk_builder_get_object(builder,
206                                                 "sensor_alarm_high_threshold"),
207                          "value-changed",
208                          G_CALLBACK(on_alarm_high_threshold_changed),
209                          tree);
210
211         g_signal_connect(gtk_builder_get_object(builder,
212                                                 "sensor_alarm_low_threshold"),
213                          "value-changed",
214                          G_CALLBACK(on_alarm_low_threshold_changed),
215                          tree);
216
217         g_signal_connect(gtk_builder_get_object(builder,
218                                                 "indicator_checkbox"),
219                          "toggled",
220                          G_CALLBACK(on_appindicator_toggled),
221                          tree);
222 }
223
224 static void
225 update_pref(struct sensor_pref *p, struct config *cfg, GtkBuilder *builder)
226 {
227         GtkLabel *w_id, *w_type, *w_high_threshold_unit, *w_low_threshold_unit,
228                 *w_chipname;
229         GtkEntry *w_name;
230         GtkToggleButton *w_draw, *w_alarm, *w_appindicator_enabled;
231         GtkColorButton *w_color;
232         GtkSpinButton *w_high_threshold, *w_low_threshold;
233         GdkColor *color;
234         struct psensor *s;
235         int use_celcius;
236
237         s = p->sensor;
238
239         w_id = GTK_LABEL(gtk_builder_get_object(builder, "sensor_id"));
240         gtk_label_set_text(w_id, s->id);
241
242         w_type = GTK_LABEL(gtk_builder_get_object(builder, "sensor_type"));
243         gtk_label_set_text(w_type, psensor_type_to_str(s->type));
244
245         w_name = GTK_ENTRY(gtk_builder_get_object(builder, "sensor_name"));
246         gtk_entry_set_text(w_name, p->name);
247
248         w_chipname = GTK_LABEL(gtk_builder_get_object(builder, "chip_name"));
249         if (s->chip)
250                 gtk_label_set_text(w_chipname, s->chip);
251         else
252                 gtk_label_set_text(w_chipname, _("Unknown"));
253
254         w_draw = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder,
255                                                           "sensor_draw"));
256         gtk_toggle_button_set_active(w_draw, p->enabled);
257
258         color = color_to_gdkcolor(p->color);
259         w_color = GTK_COLOR_BUTTON(gtk_builder_get_object(builder,
260                                                           "sensor_color"));
261         gtk_color_button_set_color(w_color, color);
262
263         w_alarm = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder,
264                                                            "sensor_alarm"));
265         w_high_threshold = GTK_SPIN_BUTTON(gtk_builder_get_object
266                                           (builder,
267                                            "sensor_alarm_high_threshold"));
268         w_low_threshold = GTK_SPIN_BUTTON(gtk_builder_get_object
269                                          (builder,
270                                           "sensor_alarm_low_threshold"));
271
272         w_high_threshold_unit = GTK_LABEL(gtk_builder_get_object
273                                          (builder,
274                                           "sensor_alarm_high_threshold_unit"));
275         w_low_threshold_unit = GTK_LABEL(gtk_builder_get_object
276                                         (builder,
277                                          "sensor_alarm_low_threshold_unit"));
278
279         use_celcius = cfg->temperature_unit == CELCIUS ? 1 : 0;
280         gtk_label_set_text(w_high_threshold_unit,
281                            psensor_type_to_unit_str(s->type,
282                                                     use_celcius));
283         gtk_label_set_text(w_low_threshold_unit,
284                            psensor_type_to_unit_str(s->type,
285                                                     use_celcius));
286
287         w_appindicator_enabled = GTK_TOGGLE_BUTTON
288                 (gtk_builder_get_object(builder, "indicator_checkbox"));
289
290         if (is_temp_type(s->type) || is_fan_type(s->type)) {
291                 gtk_toggle_button_set_active(w_alarm, p->alarm_enabled);
292                 gtk_spin_button_set_value(w_high_threshold,
293                                           p->alarm_high_threshold);
294                 gtk_spin_button_set_value(w_low_threshold,
295                                           p->alarm_low_threshold);
296                 gtk_widget_set_sensitive(GTK_WIDGET(w_alarm), TRUE);
297                 gtk_widget_set_sensitive(GTK_WIDGET(w_high_threshold), TRUE);
298                 gtk_widget_set_sensitive(GTK_WIDGET(w_low_threshold), TRUE);
299         } else {
300                 gtk_toggle_button_set_active(w_alarm, 0);
301                 gtk_spin_button_set_value(w_high_threshold, 0);
302                 gtk_spin_button_set_value(w_low_threshold, 0);
303                 gtk_widget_set_sensitive(GTK_WIDGET(w_alarm), FALSE);
304                 gtk_widget_set_sensitive(GTK_WIDGET(w_high_threshold), FALSE);
305                 gtk_widget_set_sensitive(GTK_WIDGET(w_low_threshold), FALSE);
306         }
307
308         gtk_toggle_button_set_active(w_appindicator_enabled,
309                                      p->appindicator_enabled);
310
311 }
312
313 static void on_changed(GtkTreeSelection *selection, gpointer data)
314 {
315         struct cb_data *cbdata = data;
316         struct ui_psensor *ui = cbdata->ui;
317         struct sensor_pref *p;
318         GtkTreeView *tree;
319         
320         tree = GTK_TREE_VIEW(gtk_builder_get_object(cbdata->builder,
321                                                     "sensors_list"));
322         p = get_selected_sensor_pref(tree);
323         update_pref(p, ui->config, cbdata->builder);
324 }
325
326 static void
327 select_sensor(struct psensor *s, struct psensor **sensors, GtkTreeView *tree)
328 {
329         struct psensor **s_cur = sensors;
330         int i = 0;
331         GtkTreePath *p = NULL;
332
333         while (*s_cur) {
334                 if (s == *s_cur) {
335                         p = gtk_tree_path_new_from_indices(i, -1);
336                         break;
337                 }
338
339                 i++;
340                 s_cur++;
341         }
342
343         if (p) {
344                 GtkTreeSelection *s = gtk_tree_view_get_selection(tree);
345
346                 gtk_tree_selection_select_path(s, p);
347                 gtk_tree_path_free(p);
348         }
349 }
350
351 static void apply_pref(struct sensor_pref *p, struct config *cfg)
352 {
353         struct psensor *s;
354
355         s = p->sensor;
356
357         if (strcmp(p->name, s->name)) {
358                 free(s->name);
359                 s->name = strdup(p->name);
360                 config_set_sensor_name(s->id, s->name);
361         }
362
363         if (s->enabled != p->enabled) {
364                 s->enabled = p->enabled;
365                 config_set_sensor_enabled(s->id, s->enabled);
366         }
367
368         if (is_temp_type(s->type)
369             && cfg->temperature_unit == FAHRENHEIT) {
370                 s->alarm_high_threshold
371                         = fahrenheit_to_celcius(p->alarm_high_threshold);
372                 s->alarm_low_threshold
373                         = fahrenheit_to_celcius(p->alarm_low_threshold);
374         } else {
375                 s->alarm_high_threshold = p->alarm_high_threshold;
376                 s->alarm_low_threshold = p->alarm_low_threshold;
377         }
378
379         config_set_sensor_alarm_high_threshold(s->id, s->alarm_high_threshold);
380         config_set_sensor_alarm_low_threshold(s->id, s->alarm_low_threshold);
381
382         if (s->alarm_enabled != p->alarm_enabled) {
383                 s->alarm_enabled = p->alarm_enabled;
384                 config_set_sensor_alarm_enabled(s->id, s->alarm_enabled);
385         }
386
387         color_set(s->color, p->color->red, p->color->green, p->color->blue);
388         config_set_sensor_color(s->id, s->color);
389
390         if (s->appindicator_enabled != p->appindicator_enabled) {
391                 s->appindicator_enabled = p->appindicator_enabled;
392                 config_set_appindicator_enabled(s->id, s->appindicator_enabled);
393         }
394 }
395
396 static void
397 apply_prefs(GtkTreeModel *model, struct config *cfg)
398 {
399         gboolean valid;
400         struct sensor_pref *spref;
401         GtkTreeIter iter;
402
403         valid = gtk_tree_model_get_iter_first(model, &iter);
404         while (valid) {
405                 gtk_tree_model_get(model, &iter, COL_SENSOR, &spref, -1);
406                 apply_pref(spref, cfg);
407                 valid = gtk_tree_model_iter_next(model, &iter);
408         }
409 }
410
411 void ui_sensorpref_dialog_run(struct psensor *sensor, struct ui_psensor *ui)
412 {
413         GtkDialog *diag;
414         gint result;
415         guint ok;
416         GtkBuilder *builder;
417         GError *error;
418         GtkTreeView *w_sensors_list;
419         GtkListStore *store;
420         struct psensor **s_cur, *s, **ordered_sensors;
421         GtkTreeSelection *selection;
422         struct cb_data cbdata;
423         GtkTreeIter iter;
424         struct sensor_pref *spref;
425         gboolean valid;
426         GtkTreeModel *model;
427
428         cbdata.ui = ui;
429
430         builder = gtk_builder_new();
431         cbdata.builder = builder;
432
433         error = NULL;
434         ok = gtk_builder_add_from_file
435                 (builder,
436                  PACKAGE_DATA_DIR G_DIR_SEPARATOR_S "sensor-edit.glade",
437                  &error);
438
439         if (!ok) {
440                 log_printf(LOG_ERR, error->message);
441                 g_error_free(error);
442                 return ;
443         }
444
445         w_sensors_list
446                 = GTK_TREE_VIEW(gtk_builder_get_object(builder,
447                                                        "sensors_list"));
448         connect_signals(builder, w_sensors_list);
449
450         store = GTK_LIST_STORE(gtk_builder_get_object(builder,
451                                                       "sensors_liststore"));
452
453         ordered_sensors = ui_get_sensors_ordered_by_position(ui);
454         for (s_cur = ordered_sensors; *s_cur; s_cur++) {
455                 s = *s_cur;
456                 gtk_list_store_append(store, &iter);
457
458                 spref = sensor_pref_new(s, ui->config);
459                 gtk_list_store_set(store, &iter,
460                                    COL_NAME, s->name,
461                                    COL_SENSOR, spref,
462                                    -1);
463
464                 if (s == sensor)
465                         update_pref(spref, ui->config, builder);
466         }
467
468         selection = gtk_tree_view_get_selection(w_sensors_list);
469         g_signal_connect(selection, "changed", G_CALLBACK(on_changed), &cbdata);
470         select_sensor(sensor, ordered_sensors, w_sensors_list);
471
472         free(ordered_sensors);
473
474         diag = GTK_DIALOG(gtk_builder_get_object(builder, "dialog1"));
475         result = gtk_dialog_run(diag);
476
477         model = gtk_tree_view_get_model(w_sensors_list);
478
479         if (result == GTK_RESPONSE_ACCEPT) {
480                 apply_prefs(model, ui->config);
481                 ui_sensorlist_update(ui, 1);
482 #if defined(HAVE_APPINDICATOR) || defined(HAVE_APPINDICATOR_029)
483                 ui_appindicator_update_menu(ui);
484 #endif
485         }
486
487         valid = gtk_tree_model_get_iter_first(model, &iter);
488         while (valid) {
489                 gtk_tree_model_get(model, &iter, COL_SENSOR, &spref, -1);
490                 sensor_pref_free(spref);
491                 valid = gtk_tree_model_iter_next(model, &iter);
492         }
493
494         g_object_unref(G_OBJECT(builder));
495
496         gtk_widget_destroy(GTK_WIDGET(diag));
497 }