2 * Copyright (C) 2008-2011 Robert Ancell
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License as published by the Free Software
6 * Foundation, either version 2 of the License, or (at your option) any later
7 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
11 #include <glib/gi18n.h>
13 #include "math-converter.h"
14 #include "unit-manager.h"
15 #include "currency-manager.h"
21 static guint signals
[LAST_SIGNAL
] = { 0, };
23 struct MathConverterPrivate
25 MathEquation
*equation
;
29 GtkWidget
*from_combo
;
32 GtkWidget
*result_label
;
36 G_DEFINE_TYPE (MathConverter
, math_converter
, GTK_TYPE_HBOX
);
38 static void display_changed_cb(MathEquation
*equation
, GParamSpec
*spec
, MathConverter
*converter
);
39 static void update_from_model(MathConverter
*converter
);
43 math_converter_new(MathEquation
*equation
)
45 MathConverter
*converter
= g_object_new(math_converter_get_type(), NULL
);
46 converter
->priv
->equation
= g_object_ref(equation
);
47 g_signal_connect(converter
->priv
->equation
, "notify::display", G_CALLBACK(display_changed_cb
), converter
);
48 update_from_model(converter
);
54 update_result_label(MathConverter
*converter
)
56 GtkTreeIter from_iter
, to_iter
;
57 UnitCategory
*category
= NULL
;
58 Unit
*source_unit
= NULL
, *target_unit
= NULL
;
62 if (!converter
->priv
->result_label
)
65 enabled
= math_equation_get_number(converter
->priv
->equation
, &x
);
68 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(converter
->priv
->from_combo
), &from_iter
) &&
69 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(converter
->priv
->to_combo
), &to_iter
)) {
70 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->from_combo
)), &from_iter
, 1, &category
, 2, &source_unit
, -1);
71 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->to_combo
)), &to_iter
, 2, &target_unit
, -1);
72 if (!unit_category_convert(category
, &x
, source_unit
, target_unit
, &z
))
78 gtk_widget_set_sensitive(converter
->priv
->result_label
, enabled
);
80 gchar
*source_text
, *target_text
, *label
;
81 source_text
= unit_format(source_unit
, &x
);
82 target_text
= unit_format(target_unit
, &z
);
83 label
= g_strdup_printf("%s = %s", source_text
, target_text
);
84 gtk_label_set_text(GTK_LABEL(converter
->priv
->result_label
), label
);
91 g_object_unref(category
);
93 g_object_unref(source_unit
);
95 g_object_unref(target_unit
);
100 display_changed_cb(MathEquation
*equation
, GParamSpec
*spec
, MathConverter
*converter
)
102 update_result_label(converter
);
107 update_from_model(MathConverter
*converter
)
109 GtkTreeStore
*from_model
;
111 from_model
= gtk_tree_store_new(3, G_TYPE_STRING
, G_TYPE_OBJECT
, G_TYPE_OBJECT
);
113 if (converter
->priv
->category
== NULL
) {
114 const GList
*categories
, *iter
;
116 categories
= unit_manager_get_categories(unit_manager_get_default());
117 for (iter
= categories
; iter
; iter
= iter
->next
) {
118 UnitCategory
*category
= iter
->data
;
120 const GList
*unit_iter
;
122 gtk_tree_store_append(from_model
, &parent
, NULL
);
123 gtk_tree_store_set(from_model
, &parent
, 0, unit_category_get_display_name(category
), 1, category
, -1);
125 for (unit_iter
= unit_category_get_units(category
); unit_iter
; unit_iter
= unit_iter
->next
) {
126 Unit
*unit
= unit_iter
->data
;
129 gtk_tree_store_append(from_model
, &iter
, &parent
);
130 gtk_tree_store_set(from_model
, &iter
, 0, unit_get_display_name(unit
), 1, category
, 2, unit
, -1);
135 UnitCategory
*category
;
136 const GList
*unit_iter
;
138 category
= unit_manager_get_category(unit_manager_get_default(), converter
->priv
->category
);
139 for (unit_iter
= unit_category_get_units(category
); unit_iter
; unit_iter
= unit_iter
->next
) {
140 Unit
*unit
= unit_iter
->data
;
143 gtk_tree_store_append(from_model
, &iter
, NULL
);
144 gtk_tree_store_set(from_model
, &iter
, 0, unit_get_display_name(unit
), 1, category
, 2, unit
, -1);
148 gtk_combo_box_set_model(GTK_COMBO_BOX(converter
->priv
->from_combo
), GTK_TREE_MODEL(from_model
));
153 math_converter_set_category(MathConverter
*converter
, const gchar
*category
)
155 g_return_if_fail (converter
!= NULL
);
157 if (category
== NULL
&& converter
->priv
->category
== NULL
)
159 if (category
!= NULL
&& converter
->priv
->category
!= NULL
&& strcmp(category
, converter
->priv
->category
) == 0)
162 g_free(converter
->priv
->category
);
163 converter
->priv
->category
= g_strdup(category
);
165 update_from_model(converter
);
170 math_converter_get_category(MathConverter
*converter
)
172 g_return_val_if_fail (converter
!= NULL
, NULL
);
173 return converter
->priv
->category
;
178 iter_is_unit(GtkTreeModel
*model
, GtkTreeIter
*iter
, Unit
*unit
)
182 gtk_tree_model_get(model
, iter
, 2, &u
, -1);
196 set_active_unit(GtkComboBox
*combo
, GtkTreeIter
*iter
, Unit
*unit
)
199 GtkTreeIter child_iter
;
201 model
= gtk_combo_box_get_model(combo
);
203 if (iter
&& iter_is_unit(model
, iter
, unit
)) {
204 gtk_combo_box_set_active_iter(combo
, iter
);
208 if (!gtk_tree_model_iter_children(model
, &child_iter
, iter
))
212 if (set_active_unit(combo
, &child_iter
, unit
))
214 } while (gtk_tree_model_iter_next(model
, &child_iter
));
221 math_converter_set_conversion(MathConverter
*converter
, /*const gchar *category,*/ const gchar
*unit_a
, const gchar
*unit_b
)
226 g_return_if_fail (converter
!= NULL
);
227 g_return_if_fail (unit_a
!= NULL
);
228 g_return_if_fail (unit_b
!= NULL
);
230 ua
= unit_manager_get_unit_by_name(unit_manager_get_default(), unit_a
);
231 ub
= unit_manager_get_unit_by_name(unit_manager_get_default(), unit_b
);
237 /* Select the first unit */
238 model
= gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->from_combo
));
239 if (gtk_tree_model_get_iter_first(model
, &iter
)) {
240 GtkTreeIter child_iter
;
241 while (gtk_tree_model_iter_children(model
, &child_iter
, &iter
))
243 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(converter
->priv
->from_combo
), &iter
);
248 set_active_unit(GTK_COMBO_BOX(converter
->priv
->from_combo
), NULL
, ua
);
249 set_active_unit(GTK_COMBO_BOX(converter
->priv
->to_combo
), NULL
, ub
);
254 math_converter_get_conversion(MathConverter
*converter
, Unit
**from_unit
, Unit
**to_unit
)
256 GtkTreeIter from_iter
, to_iter
;
258 g_return_if_fail (converter
!= NULL
);
259 g_return_if_fail (from_unit
!= NULL
);
260 g_return_if_fail (to_unit
!= NULL
);
262 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(converter
->priv
->from_combo
), &from_iter
);
263 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(converter
->priv
->to_combo
), &to_iter
);
265 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->from_combo
)), &from_iter
, 2, from_unit
, -1);
266 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->to_combo
)), &to_iter
, 2, to_unit
, -1);
271 math_converter_class_init(MathConverterClass
*klass
)
273 g_type_class_add_private(klass
, sizeof(MathConverterPrivate
));
276 g_signal_new("changed",
277 G_TYPE_FROM_CLASS (klass
),
279 G_STRUCT_OFFSET (MathConverterClass
, changed
),
281 g_cclosure_marshal_VOID__VOID
,
287 from_combobox_changed_cb(GtkWidget
*combo
, MathConverter
*converter
)
291 UnitCategory
*category
;
293 const GList
*unit_iter
;
295 model
= gtk_combo_box_get_model(GTK_COMBO_BOX(combo
));
296 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo
), &iter
))
298 gtk_tree_model_get(model
, &iter
, 1, &category
, 2, &unit
, -1);
300 /* Set the to combobox to be the list of units can be converted to */
301 model
= GTK_TREE_MODEL(gtk_list_store_new(3, G_TYPE_STRING
, G_TYPE_OBJECT
, G_TYPE_OBJECT
));
302 for (unit_iter
= unit_category_get_units(category
); unit_iter
; unit_iter
= unit_iter
->next
) {
303 Unit
*u
= unit_iter
->data
;
306 gtk_list_store_append(GTK_LIST_STORE(model
), &iter
);
307 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, 0, unit_get_display_name(u
), 1, category
, 2, u
, -1);
309 gtk_combo_box_set_model(GTK_COMBO_BOX(converter
->priv
->to_combo
), model
);
311 /* Select the first possible unit */
312 gtk_combo_box_set_active(GTK_COMBO_BOX(converter
->priv
->to_combo
), 0);
314 g_object_unref(category
);
315 g_object_unref(unit
);
320 to_combobox_changed_cb(GtkWidget
*combo
, MathConverter
*converter
)
322 /* Conversion must have changed */
323 update_result_label(converter
);
325 g_signal_emit(converter
, signals
[CHANGED
], 0);
330 from_cell_data_func(GtkCellLayout
*cell_layout
,
331 GtkCellRenderer
*cell
,
332 GtkTreeModel
*tree_model
,
336 g_object_set(cell
, "sensitive", !gtk_tree_model_iter_has_child(tree_model
, iter
), NULL
);
341 currency_updated_cb(CurrencyManager
*manager
, MathConverter
*converter
)
343 update_result_label(converter
);
348 math_converter_init(MathConverter
*converter
)
350 GtkWidget
*hbox
, *label
;
351 GtkCellRenderer
*renderer
;
353 converter
->priv
= G_TYPE_INSTANCE_GET_PRIVATE(converter
, math_converter_get_type(), MathConverterPrivate
);
355 gtk_box_set_spacing(GTK_BOX(converter
), 6);
357 hbox
= gtk_hbox_new(FALSE
, 0);
358 gtk_widget_show(hbox
);
359 gtk_box_pack_start(GTK_BOX(converter
), hbox
, FALSE
, TRUE
, 0);
361 converter
->priv
->from_combo
= gtk_combo_box_new ();
363 renderer
= gtk_cell_renderer_text_new();
364 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(converter
->priv
->from_combo
), renderer
, TRUE
);
365 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(converter
->priv
->from_combo
), renderer
, "text", 0);
366 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(converter
->priv
->from_combo
),
370 g_signal_connect(converter
->priv
->from_combo
, "changed", G_CALLBACK(from_combobox_changed_cb
), converter
);
371 gtk_widget_show(converter
->priv
->from_combo
);
372 gtk_box_pack_start(GTK_BOX(hbox
), converter
->priv
->from_combo
, FALSE
, TRUE
, 0);
374 label
= gtk_label_new(/* Label that is displayed between the two conversion combo boxes, e.g. "[degrees] in [radians]" */
376 gtk_widget_show(label
);
377 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, TRUE
, 0);
379 converter
->priv
->to_combo
= gtk_combo_box_new();
380 renderer
= gtk_cell_renderer_text_new();
381 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(converter
->priv
->to_combo
), renderer
, TRUE
);
382 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(converter
->priv
->to_combo
), renderer
, "text", 0);
383 g_signal_connect(converter
->priv
->to_combo
, "changed", G_CALLBACK(to_combobox_changed_cb
), converter
);
384 gtk_widget_show(converter
->priv
->to_combo
);
385 gtk_box_pack_start(GTK_BOX(hbox
), converter
->priv
->to_combo
, FALSE
, TRUE
, 0);
387 converter
->priv
->result_label
= gtk_label_new("");
388 gtk_misc_set_alignment(GTK_MISC(converter
->priv
->result_label
), 1.0, 0.5);
389 gtk_widget_set_sensitive(converter
->priv
->result_label
, FALSE
);
390 gtk_widget_show(converter
->priv
->result_label
);
391 gtk_box_pack_start(GTK_BOX(converter
), converter
->priv
->result_label
, TRUE
, TRUE
, 0);
393 g_signal_connect(currency_manager_get_default(), "updated", G_CALLBACK(currency_updated_cb
), converter
);