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 convert_equation(MathConverter
*converter
, const MPNumber
*x
, MPNumber
*z
)
56 GtkTreeIter from_iter
, to_iter
;
57 UnitCategory
*category
= NULL
;
58 Unit
*source_unit
= NULL
, *target_unit
= NULL
;
61 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(converter
->priv
->from_combo
), &from_iter
) ||
62 !gtk_combo_box_get_active_iter(GTK_COMBO_BOX(converter
->priv
->to_combo
), &to_iter
))
65 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->from_combo
)), &from_iter
, 1, &category
, 2, &source_unit
, -1);
66 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->to_combo
)), &to_iter
, 2, &target_unit
, -1);
68 result
= unit_category_convert(category
, x
, source_unit
, target_unit
, z
);
71 g_object_unref(category
);
73 g_object_unref(source_unit
);
75 g_object_unref(target_unit
);
82 update_result_label(MathConverter
*converter
)
87 if (!converter
->priv
->result_label
)
90 if (math_equation_get_number(converter
->priv
->equation
, &x
))
91 enabled
= convert_equation(converter
, &x
, &z
);
95 gtk_widget_set_sensitive(converter
->priv
->result_label
, enabled
);
97 gchar
*source_text
, *target_text
, *label
;
98 Unit
*source_unit
, *target_unit
;
100 math_converter_get_conversion(converter
, &source_unit
, &target_unit
);
102 source_text
= unit_format(source_unit
, &x
);
103 target_text
= unit_format(target_unit
, &z
);
104 label
= g_strdup_printf("%s = %s", source_text
, target_text
);
105 gtk_label_set_text(GTK_LABEL(converter
->priv
->result_label
), label
);
111 g_object_unref(source_unit
);
112 g_object_unref(target_unit
);
118 display_changed_cb(MathEquation
*equation
, GParamSpec
*spec
, MathConverter
*converter
)
120 update_result_label(converter
);
125 update_from_model(MathConverter
*converter
)
127 GtkTreeStore
*from_model
;
129 from_model
= gtk_tree_store_new(3, G_TYPE_STRING
, G_TYPE_OBJECT
, G_TYPE_OBJECT
);
131 if (converter
->priv
->category
== NULL
) {
132 const GList
*categories
, *iter
;
134 categories
= unit_manager_get_categories(unit_manager_get_default());
135 for (iter
= categories
; iter
; iter
= iter
->next
) {
136 UnitCategory
*category
= iter
->data
;
138 const GList
*unit_iter
;
140 gtk_tree_store_append(from_model
, &parent
, NULL
);
141 gtk_tree_store_set(from_model
, &parent
, 0, unit_category_get_display_name(category
), 1, category
, -1);
143 for (unit_iter
= unit_category_get_units(category
); unit_iter
; unit_iter
= unit_iter
->next
) {
144 Unit
*unit
= unit_iter
->data
;
147 gtk_tree_store_append(from_model
, &iter
, &parent
);
148 gtk_tree_store_set(from_model
, &iter
, 0, unit_get_display_name(unit
), 1, category
, 2, unit
, -1);
153 UnitCategory
*category
;
154 const GList
*unit_iter
;
156 category
= unit_manager_get_category(unit_manager_get_default(), converter
->priv
->category
);
157 for (unit_iter
= unit_category_get_units(category
); unit_iter
; unit_iter
= unit_iter
->next
) {
158 Unit
*unit
= unit_iter
->data
;
161 gtk_tree_store_append(from_model
, &iter
, NULL
);
162 gtk_tree_store_set(from_model
, &iter
, 0, unit_get_display_name(unit
), 1, category
, 2, unit
, -1);
166 gtk_combo_box_set_model(GTK_COMBO_BOX(converter
->priv
->from_combo
), GTK_TREE_MODEL(from_model
));
171 math_converter_set_category(MathConverter
*converter
, const gchar
*category
)
173 g_return_if_fail (converter
!= NULL
);
175 if (category
== NULL
&& converter
->priv
->category
== NULL
)
177 if (category
!= NULL
&& converter
->priv
->category
!= NULL
&& strcmp(category
, converter
->priv
->category
) == 0)
180 g_free(converter
->priv
->category
);
181 converter
->priv
->category
= g_strdup(category
);
183 update_from_model(converter
);
188 math_converter_get_category(MathConverter
*converter
)
190 g_return_val_if_fail (converter
!= NULL
, NULL
);
191 return converter
->priv
->category
;
196 iter_is_unit(GtkTreeModel
*model
, GtkTreeIter
*iter
, Unit
*unit
)
200 gtk_tree_model_get(model
, iter
, 2, &u
, -1);
214 set_active_unit(GtkComboBox
*combo
, GtkTreeIter
*iter
, Unit
*unit
)
217 GtkTreeIter child_iter
;
219 model
= gtk_combo_box_get_model(combo
);
221 if (iter
&& iter_is_unit(model
, iter
, unit
)) {
222 gtk_combo_box_set_active_iter(combo
, iter
);
226 if (!gtk_tree_model_iter_children(model
, &child_iter
, iter
))
230 if (set_active_unit(combo
, &child_iter
, unit
))
232 } while (gtk_tree_model_iter_next(model
, &child_iter
));
239 math_converter_set_conversion(MathConverter
*converter
, /*const gchar *category,*/ const gchar
*unit_a
, const gchar
*unit_b
)
244 g_return_if_fail (converter
!= NULL
);
245 g_return_if_fail (unit_a
!= NULL
);
246 g_return_if_fail (unit_b
!= NULL
);
248 ua
= unit_manager_get_unit_by_name(unit_manager_get_default(), unit_a
);
249 ub
= unit_manager_get_unit_by_name(unit_manager_get_default(), unit_b
);
255 /* Select the first unit */
256 model
= gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->from_combo
));
257 if (gtk_tree_model_get_iter_first(model
, &iter
)) {
258 GtkTreeIter child_iter
;
259 while (gtk_tree_model_iter_children(model
, &child_iter
, &iter
))
261 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(converter
->priv
->from_combo
), &iter
);
266 set_active_unit(GTK_COMBO_BOX(converter
->priv
->from_combo
), NULL
, ua
);
267 set_active_unit(GTK_COMBO_BOX(converter
->priv
->to_combo
), NULL
, ub
);
272 math_converter_get_conversion(MathConverter
*converter
, Unit
**from_unit
, Unit
**to_unit
)
274 GtkTreeIter from_iter
, to_iter
;
276 g_return_if_fail (converter
!= NULL
);
277 g_return_if_fail (from_unit
!= NULL
);
278 g_return_if_fail (to_unit
!= NULL
);
280 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(converter
->priv
->from_combo
), &from_iter
);
281 gtk_combo_box_get_active_iter(GTK_COMBO_BOX(converter
->priv
->to_combo
), &to_iter
);
283 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->from_combo
)), &from_iter
, 2, from_unit
, -1);
284 gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(converter
->priv
->to_combo
)), &to_iter
, 2, to_unit
, -1);
289 math_converter_class_init(MathConverterClass
*klass
)
291 g_type_class_add_private(klass
, sizeof(MathConverterPrivate
));
294 g_signal_new("changed",
295 G_TYPE_FROM_CLASS (klass
),
297 G_STRUCT_OFFSET (MathConverterClass
, changed
),
299 g_cclosure_marshal_VOID__VOID
,
305 from_combobox_changed_cb(GtkWidget
*combo
, MathConverter
*converter
)
309 UnitCategory
*category
;
311 const GList
*unit_iter
;
313 model
= gtk_combo_box_get_model(GTK_COMBO_BOX(combo
));
314 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo
), &iter
))
316 gtk_tree_model_get(model
, &iter
, 1, &category
, 2, &unit
, -1);
318 /* Set the to combobox to be the list of units can be converted to */
319 model
= GTK_TREE_MODEL(gtk_list_store_new(3, G_TYPE_STRING
, G_TYPE_OBJECT
, G_TYPE_OBJECT
));
320 for (unit_iter
= unit_category_get_units(category
); unit_iter
; unit_iter
= unit_iter
->next
) {
321 Unit
*u
= unit_iter
->data
;
324 gtk_list_store_append(GTK_LIST_STORE(model
), &iter
);
325 gtk_list_store_set(GTK_LIST_STORE(model
), &iter
, 0, unit_get_display_name(u
), 1, category
, 2, u
, -1);
327 gtk_combo_box_set_model(GTK_COMBO_BOX(converter
->priv
->to_combo
), model
);
329 /* Select the first possible unit */
330 gtk_combo_box_set_active(GTK_COMBO_BOX(converter
->priv
->to_combo
), 0);
332 g_object_unref(category
);
333 g_object_unref(unit
);
338 to_combobox_changed_cb(GtkWidget
*combo
, MathConverter
*converter
)
340 /* Conversion must have changed */
341 update_result_label(converter
);
343 g_signal_emit(converter
, signals
[CHANGED
], 0);
348 from_cell_data_func(GtkCellLayout
*cell_layout
,
349 GtkCellRenderer
*cell
,
350 GtkTreeModel
*tree_model
,
354 g_object_set(cell
, "sensitive", !gtk_tree_model_iter_has_child(tree_model
, iter
), NULL
);
359 currency_updated_cb(CurrencyManager
*manager
, MathConverter
*converter
)
361 update_result_label(converter
);
365 swap_button_clicked_cb(GtkButton
*button
, MathConverter
*converter
)
367 Unit
*from_unit
, *to_unit
;
370 if (math_equation_get_number(converter
->priv
->equation
, &x
) &&
371 convert_equation(converter
, &x
, &z
))
372 math_equation_set_number(converter
->priv
->equation
, &z
);
374 math_converter_get_conversion(converter
, &from_unit
, &to_unit
);
375 set_active_unit(GTK_COMBO_BOX(converter
->priv
->from_combo
), NULL
, to_unit
);
376 set_active_unit(GTK_COMBO_BOX(converter
->priv
->to_combo
), NULL
, from_unit
);
378 update_result_label(converter
);
380 g_object_unref(from_unit
);
381 g_object_unref(to_unit
);
385 math_converter_init(MathConverter
*converter
)
387 GtkWidget
*hbox
, *label
, *swap_button
;
388 GtkCellRenderer
*renderer
;
390 converter
->priv
= G_TYPE_INSTANCE_GET_PRIVATE(converter
, math_converter_get_type(), MathConverterPrivate
);
392 gtk_box_set_spacing(GTK_BOX(converter
), 6);
394 hbox
= gtk_hbox_new(FALSE
, 0);
395 gtk_widget_show(hbox
);
396 gtk_box_pack_start(GTK_BOX(converter
), hbox
, FALSE
, TRUE
, 0);
398 converter
->priv
->from_combo
= gtk_combo_box_new ();
400 renderer
= gtk_cell_renderer_text_new();
401 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(converter
->priv
->from_combo
), renderer
, TRUE
);
402 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(converter
->priv
->from_combo
), renderer
, "text", 0);
403 gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(converter
->priv
->from_combo
),
407 g_signal_connect(converter
->priv
->from_combo
, "changed", G_CALLBACK(from_combobox_changed_cb
), converter
);
408 gtk_widget_show(converter
->priv
->from_combo
);
409 gtk_box_pack_start(GTK_BOX(hbox
), converter
->priv
->from_combo
, FALSE
, TRUE
, 0);
411 label
= gtk_label_new(/* Label that is displayed between the two conversion combo boxes, e.g. "[degrees] in [radians]" */
413 gtk_widget_show(label
);
414 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, TRUE
, 5);
416 converter
->priv
->to_combo
= gtk_combo_box_new();
417 renderer
= gtk_cell_renderer_text_new();
418 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(converter
->priv
->to_combo
), renderer
, TRUE
);
419 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(converter
->priv
->to_combo
), renderer
, "text", 0);
420 g_signal_connect(converter
->priv
->to_combo
, "changed", G_CALLBACK(to_combobox_changed_cb
), converter
);
421 gtk_widget_show(converter
->priv
->to_combo
);
422 gtk_box_pack_start(GTK_BOX(hbox
), converter
->priv
->to_combo
, FALSE
, TRUE
, 0);
424 swap_button
= gtk_button_new_with_label ("⇆");
425 gtk_widget_set_tooltip_text (swap_button
,
426 /* Tooltip for swap conversion button */
427 _("Switch conversion units"));
428 gtk_button_set_relief (GTK_BUTTON (swap_button
), GTK_RELIEF_NONE
);
429 g_signal_connect (swap_button
, "clicked", G_CALLBACK (swap_button_clicked_cb
), converter
);
430 gtk_widget_show(swap_button
);
431 gtk_box_pack_start(GTK_BOX(hbox
), swap_button
, FALSE
, TRUE
, 0);
433 converter
->priv
->result_label
= gtk_label_new("");
434 gtk_misc_set_alignment(GTK_MISC(converter
->priv
->result_label
), 1.0, 0.5);
435 gtk_widget_set_sensitive(converter
->priv
->result_label
, FALSE
);
436 gtk_widget_show(converter
->priv
->result_label
);
437 gtk_box_pack_start(GTK_BOX(converter
), converter
->priv
->result_label
, TRUE
, TRUE
, 0);
439 g_signal_connect(currency_manager_get_default(), "updated", G_CALLBACK(currency_updated_cb
), converter
);