[gcalctool] Improve conversion bar



commit 3ba2f24a8a5de3e58ce8eab1c6e5cfab7568fc11
Author: Robert Ancell <robert ancell canonical com>
Date:   Mon Nov 29 13:33:40 2010 +1100

    Improve conversion bar

 NEWS                                    |    1 +
 data/buttons-advanced.ui                |   49 ++++++---
 data/org.gnome.gcalctool.gschema.xml.in |   10 ++
 src/Makefile.am                         |    6 +-
 src/gcalctool.c                         |    9 ++
 src/math-buttons.c                      |  163 +++++++++++++++++++---------
 src/math-equation.c                     |   81 ++++++++++++--
 src/math-equation.h                     |    6 +
 src/mp-equation.c                       |  176 +-----------------------------
 src/units.c                             |  182 +++++++++++++++++++++++++++++++
 src/units.h                             |    8 ++
 11 files changed, 438 insertions(+), 253 deletions(-)
---
diff --git a/NEWS b/NEWS
index ccefe61..6bda71d 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,7 @@ Overview of changes in gcalctool 5.91.3
 
     * Fix incorrect calculation of tanh
     * Fix dropping of decimal points when thousand separator is '.' (Bug #635517)
+    * Improve conversion bar
 
 Overview of changes in gcalctool 5.91.2
 
diff --git a/data/buttons-advanced.ui b/data/buttons-advanced.ui
index 691c4be..607afdc 100644
--- a/data/buttons-advanced.ui
+++ b/data/buttons-advanced.ui
@@ -12,9 +12,38 @@
             <property name="visible">True</property>
             <property name="spacing">6</property>
             <child>
-              <object class="GtkComboBox" id="convert_from_combo">
+              <object class="GtkHBox" id="hbox3">
                 <property name="visible">True</property>
-                <property name="focus_on_click">False</property>
+                <child>
+                  <object class="GtkComboBox" id="convert_from_combo">
+                    <property name="visible">True</property>
+                    <property name="focus_on_click">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label7">
+                    <property name="visible">True</property>
+                    <property name="label" translatable="yes" comments="This is between the unit selector dropdowns, for example: meters in kilometers"> in </property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkComboBox" id="convert_to_combo">
+                    <property name="visible">True</property>
+                    <property name="focus_on_click">False</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -22,25 +51,15 @@
               </packing>
             </child>
             <child>
-              <object class="GtkLabel" id="label7">
+              <object class="GtkLabel" id="convert_result_label">
                 <property name="visible">True</property>
-                <property name="label" translatable="yes" comments="This is between the unit selector dropdowns, for example: meters in kilometers"> in </property>
+                <property name="xalign">1</property>
+                <property name="label">1m = 100cm</property>
               </object>
               <packing>
-                <property name="expand">False</property>
                 <property name="position">1</property>
               </packing>
             </child>
-            <child>
-              <object class="GtkComboBox" id="convert_to_combo">
-                <property name="visible">True</property>
-                <property name="focus_on_click">False</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="position">2</property>
-              </packing>
-            </child>
           </object>
           <packing>
             <property name="expand">False</property>
diff --git a/data/org.gnome.gcalctool.gschema.xml.in b/data/org.gnome.gcalctool.gschema.xml.in
index eff5b95..909e4a1 100644
--- a/data/org.gnome.gcalctool.gschema.xml.in
+++ b/data/org.gnome.gcalctool.gschema.xml.in
@@ -71,5 +71,15 @@
       <_summary>Target currency</_summary>
       <_description>Currency to convert the current calculation into</_description>
     </key>
+    <key type="s" name="source-units">
+      <default>'degrees'</default>
+      <_summary>Source units</_summary>
+      <_description>Units of the current calculation</_description>
+    </key>
+    <key type="s" name="target-units">
+      <default>'radians'</default>
+      <_summary>Target units</_summary>
+      <_description>Units to convert the current calculation into</_description>
+    </key>
   </schema>
 </schemalist>
diff --git a/src/Makefile.am b/src/Makefile.am
index 4691314..0404e3f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -43,6 +43,8 @@ gcalctool_SOURCES = \
 	mp-serializer.h \
 	financial.c \
 	financial.h \
+	units.c \
+	units.h \
 	unittest.c \
 	unittest.h
 
@@ -61,7 +63,9 @@ gcalccmd_SOURCES = \
 	mp-serializer.c \
 	mp-serializer.h\
 	math-enums.c \
-	math-enums.h
+	math-enums.h \
+	units.c \
+	units.h
 
 gcalccmd_LDADD = \
 	$(GCALCCMD_LIBS) \
diff --git a/src/gcalctool.c b/src/gcalctool.c
index e9121f4..146f270 100644
--- a/src/gcalctool.c
+++ b/src/gcalctool.c
@@ -195,6 +195,8 @@ quit_cb(MathWindow *window)
     g_settings_set_enum(settings, "button-mode", math_buttons_get_mode(buttons));
     g_settings_set_string(settings, "source-currency", math_equation_get_source_currency(equation));
     g_settings_set_string(settings, "target-currency", math_equation_get_target_currency(equation));
+    g_settings_set_string(settings, "source-units", math_equation_get_source_units(equation));
+    g_settings_set_string(settings, "target-units", math_equation_get_target_units(equation));
     g_settings_sync();
 
     currency_free_resources();
@@ -212,6 +214,7 @@ main(int argc, char **argv)
     MPAngleUnit angle_units;
     ButtonMode button_mode;
     gchar *source_currency, *target_currency;
+    gchar *source_units, *target_units;
 
     g_type_init();
 
@@ -236,6 +239,8 @@ main(int argc, char **argv)
     button_mode = g_settings_get_enum(settings, "button-mode");
     source_currency = g_settings_get_string(settings, "source-currency");
     target_currency = g_settings_get_string(settings, "target-currency");
+    source_units = g_settings_get_string(settings, "source-units");
+    target_units = g_settings_get_string(settings, "target-units");
 
     equation = math_equation_new();
     math_equation_set_accuracy(equation, accuracy);
@@ -246,8 +251,12 @@ main(int argc, char **argv)
     math_equation_set_angle_units(equation, angle_units);
     math_equation_set_source_currency(equation, source_currency);
     math_equation_set_target_currency(equation, target_currency);
+    math_equation_set_source_units(equation, source_units);
+    math_equation_set_target_units(equation, target_units);
     g_free(source_currency);
     g_free(target_currency);
+    g_free(source_units);
+    g_free(target_units);
 
     gtk_init(&argc, &argv);
 
diff --git a/src/math-buttons.c b/src/math-buttons.c
index 209d900..bdf2f13 100644
--- a/src/math-buttons.c
+++ b/src/math-buttons.c
@@ -22,6 +22,7 @@
 #include "financial.h"
 #include "currency.h"
 #include "mp-serializer.h"
+#include "units.h"
 
 enum {
     PROP_0,
@@ -56,7 +57,7 @@ struct MathButtonsPrivate
 
     GtkWidget *convert_from_combo;
     GtkWidget *convert_to_combo;
-    gchar *previous_ans;
+    GtkWidget *convert_result_label;
 
     GtkWidget *base_combo;
     GtkWidget *base_label;
@@ -313,12 +314,12 @@ static char *finc_dialog_fields[][5] = {
 
 #define MAX_UNITS 20
 struct Unit {
-    char* ui_name;
-    char* internal_name;
+    char *ui_name;
+    char *internal_name;
 };
 
 struct UnitCategory {
-    char* name;
+    char *name;
     struct Unit units[MAX_UNITS];
 };
 
@@ -337,7 +338,7 @@ static struct UnitCategory categories[] = {
                           /* Length unit */
                           {N_("Light Years"), "lightyears"},
                           /* Length unit */
-                          {N_("Astronomical Unit"), "au"},
+                          {N_("Astronomical Units"), "au"},
                           /* Length unit */
                           {N_("Nautical Miles"), "nm"},
                           /* Length unit */
@@ -617,10 +618,47 @@ update_currency_label(MathButtons *buttons)
 
 
 static void
+update_conversion_bar(MathButtons *buttons)
+{
+    MPNumber x, z;
+    gboolean enabled;
+    gchar *label;
+    const gchar *source_units, *target_units;
+    char *source_value, *target_value;
+
+    if (!buttons->priv->convert_result_label)
+        return;
+
+    enabled = math_equation_get_number(buttons->priv->equation, &x);
+
+    source_units = math_equation_get_source_units(buttons->priv->equation);
+    target_units = math_equation_get_target_units(buttons->priv->equation);
+    if (!source_units || !target_units)
+        enabled = FALSE;
+    else if (!units_convert(&x, source_units, target_units, &z))
+        enabled = FALSE;
+
+    gtk_widget_set_sensitive(buttons->priv->convert_result_label, enabled);
+    if (!enabled)
+        return;
+  
+    mp_serializer_to_specific_string(&x, 10, 2, TRUE, TRUE, &source_value);
+    mp_serializer_to_specific_string(&z, 10, 2, TRUE, TRUE, &target_value);
+
+    label = g_strdup_printf("%s %s = %s %s", source_value, source_units, target_value, target_units);
+    gtk_label_set_text(GTK_LABEL(buttons->priv->convert_result_label), label);
+    g_free(source_value);
+    g_free(target_value);
+    g_free(label);
+}
+
+
+static void
 display_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
 {
     update_currency_label(buttons);
     update_bit_panel(buttons);
+    update_conversion_bar(buttons);
 }
 
 
@@ -628,76 +666,98 @@ static void
 convert_from_combobox_changed_cb(GtkWidget *combo, MathButtons *buttons)
 {
     GtkTreeModel *model;
-    GtkTreeIter iter, unittype;
-    int typeindex, i;
+    GtkTreeIter iter;
+    int typeindex, unitindex, i;
 
     model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
     gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
+    gtk_tree_model_get(model, &iter, 1, &typeindex, 2, &unitindex, -1);
 
-    if (!gtk_tree_model_iter_parent(model, &unittype, &iter))
-        return;
-
-    gtk_tree_model_get(model, &unittype, 1, &typeindex, -1);
-
-    model = GTK_TREE_MODEL(gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT));
+    model = GTK_TREE_MODEL(gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT));
     for (i = 0; categories[typeindex].units[i].ui_name != NULL; i++) {
+        if (i == unitindex)
+            continue;
         gtk_list_store_append(GTK_LIST_STORE(model), &iter);
-        gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, categories[typeindex].units[i].ui_name, 1, i, -1);
+        gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, categories[typeindex].units[i].ui_name, 1, typeindex, 2, i, -1);
     }
     gtk_combo_box_set_model(GTK_COMBO_BOX(buttons->priv->convert_to_combo), model);
+
+    math_equation_set_source_units(buttons->priv->equation, categories[typeindex].units[unitindex].internal_name);
+
+    gtk_combo_box_set_active(GTK_COMBO_BOX(buttons->priv->convert_to_combo), 0);
 }
 
 
 static void
-convert_to_combobox_changed_cb(GtkWidget *combo, MathButtons *buttons)
+source_units_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
 {
     GtkTreeModel *model;
-    GtkTreeIter iter, catiter;
-    gchar *from, *to, *display;
-    int category, fromindex, toindex;
-
-    model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
-    gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
-    gtk_tree_model_get(model, &iter, 1, &toindex, -1);
+    GtkTreeIter iter;
 
     model = gtk_combo_box_get_model(GTK_COMBO_BOX(buttons->priv->convert_from_combo));
-    gtk_combo_box_get_active_iter(GTK_COMBO_BOX(buttons->priv->convert_from_combo), &iter);
-    if (!gtk_tree_model_iter_parent(model, &catiter, &iter))
+    if (!gtk_tree_model_get_iter_first(model, &iter))
         return;
+    do
+    {
+        GtkTreeIter child_iter;
 
-    gtk_tree_model_get(model, &catiter, 1, &category, -1);
-    gtk_tree_model_get(model, &iter, 1, &fromindex, -1);
+        if (gtk_tree_model_iter_children(model, &child_iter, &iter))
+        {
+            do
+            {
+                gint i, j;
+
+                gtk_tree_model_get(model, &child_iter, 1, &i, 2, &j, -1);
+                if (strcmp(categories[i].units[j].internal_name, math_equation_get_source_units(equation)) == 0)
+                {
+                    gtk_combo_box_set_active_iter(GTK_COMBO_BOX(buttons->priv->convert_from_combo), &child_iter);
+                    update_conversion_bar(buttons);
+                    return;
+                }             
+            } while (gtk_tree_model_iter_next(model, &child_iter));
+        }
+    } while (gtk_tree_model_iter_next(model, &iter));
+}
 
-    from = categories[category].units[fromindex].internal_name;
-    to = categories[category].units[toindex].internal_name;
 
-    if (buttons->priv->previous_ans == NULL) {
-        display = math_equation_get_display(buttons->priv->equation);
-        buttons->priv->previous_ans = display;
-    }
-    else {
-        display = buttons->priv->previous_ans;
-    }
-    math_equation_set(buttons->priv->equation, g_strdup_printf("%s %s in %s", display, from, to));
+static void
+convert_to_combobox_changed_cb(GtkWidget *combo, MathButtons *buttons)
+{
+    GtkTreeModel *model;
+    GtkTreeIter iter;
+    int category, toindex;
+
+    model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+    gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter);
+    gtk_tree_model_get(model, &iter, 1, &category, 2, &toindex, -1);
+    math_equation_set_target_units(buttons->priv->equation, categories[category].units[toindex].internal_name);
 }
 
+
 static void
-update_conversion_combos(MathEquation *equation, MathButtons *buttons)
+target_units_changed_cb(MathEquation *equation, GParamSpec *spec, MathButtons *buttons)
 {
     GtkTreeModel *model;
     GtkTreeIter iter;
 
-    model = gtk_combo_box_get_model(GTK_COMBO_BOX(buttons->priv->convert_from_combo));
-    gtk_tree_model_get_iter_first(model, &iter);
-    gtk_combo_box_set_active_iter(GTK_COMBO_BOX(buttons->priv->convert_from_combo), &iter);
-
-    model = GTK_TREE_MODEL(gtk_list_store_new(1, G_TYPE_STRING));
-    gtk_combo_box_set_model(GTK_COMBO_BOX(buttons->priv->convert_to_combo), model);
+    model = gtk_combo_box_get_model(GTK_COMBO_BOX(buttons->priv->convert_to_combo));
+    if (!gtk_tree_model_get_iter_first(model, &iter))
+        return;
+    do
+    {
+        gint i, j;
 
-    g_free(buttons->priv->previous_ans);
-    buttons->priv->previous_ans = NULL;
+        gtk_tree_model_get(model, &iter, 1, &i, 2, &j, -1);
+        if (strcmp(categories[i].units[j].internal_name, math_equation_get_target_units(equation)) == 0)
+        {
+            gtk_combo_box_set_active_iter(GTK_COMBO_BOX(buttons->priv->convert_to_combo), &iter);
+            update_conversion_bar(buttons);
+            return;
+        }
+    } while (gtk_tree_model_iter_next(model, &iter));
 }
 
+
 static void
 base_combobox_changed_cb(GtkWidget *combo, MathButtons *buttons)
 {
@@ -992,10 +1052,10 @@ load_mode(MathButtons *buttons, ButtonMode mode)
         GtkCellRenderer *renderer;
         int i, j;
 
-//        buttons->priv->angle_label = GET_WIDGET(builder, "angle_label");
+        buttons->priv->convert_result_label = GET_WIDGET(builder, "convert_result_label");
 
         buttons->priv->convert_from_combo = GET_WIDGET(builder, "convert_from_combo");
-        from_model = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
+        from_model = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT);
         gtk_combo_box_set_model(GTK_COMBO_BOX(buttons->priv->convert_from_combo), GTK_TREE_MODEL(from_model));
 
         for (i = 0; i < sizeof(categories) / sizeof(categories[0]); i++) {
@@ -1003,7 +1063,7 @@ load_mode(MathButtons *buttons, ButtonMode mode)
             gtk_tree_store_set(from_model, &parent, 0, categories[i].name, 1, i, -1);
             for (j = 0; categories[i].units[j].ui_name != NULL; j++) {
                 gtk_tree_store_append(from_model, &iter, &parent);
-                gtk_tree_store_set(from_model, &iter, 0, categories[i].units[j].ui_name, 1, j, -1);
+                gtk_tree_store_set(from_model, &iter, 0, categories[i].units[j].ui_name, 1, i, 2, j, -1);
             }
         }
         renderer = gtk_cell_renderer_text_new();
@@ -1021,7 +1081,10 @@ load_mode(MathButtons *buttons, ButtonMode mode)
 
         g_signal_connect(buttons->priv->convert_from_combo, "changed", G_CALLBACK(convert_from_combobox_changed_cb), buttons);
         g_signal_connect(buttons->priv->convert_to_combo, "changed", G_CALLBACK(convert_to_combobox_changed_cb), buttons);
-        g_signal_connect(buttons->priv->equation, "answer-changed", G_CALLBACK(update_conversion_combos), buttons);
+        g_signal_connect(buttons->priv->equation, "notify::source-units", G_CALLBACK(source_units_changed_cb), buttons);
+        g_signal_connect(buttons->priv->equation, "notify::target-units", G_CALLBACK(target_units_changed_cb), buttons);
+        source_units_changed_cb(buttons->priv->equation, NULL, buttons);
+        target_units_changed_cb(buttons->priv->equation, NULL, buttons);
     }
 
     if (mode == PROGRAMMING) {
diff --git a/src/math-equation.c b/src/math-equation.c
index 7764eed..7bbb3da 100644
--- a/src/math-equation.c
+++ b/src/math-equation.c
@@ -49,6 +49,8 @@ enum {
     PROP_ANGLE_UNITS,
     PROP_SOURCE_CURRENCY,
     PROP_TARGET_CURRENCY,
+    PROP_SOURCE_UNITS,
+    PROP_TARGET_UNITS,  
     PROP_SERIALIZER
 };
 
@@ -76,6 +78,8 @@ struct MathEquationPrivate
     MPAngleUnit angle_units;  /* Units for trigonometric functions */
     char *source_currency;
     char *target_currency;
+    char *source_units;
+    char *target_units;
     NumberMode number_mode;   /* ??? */
     gboolean can_super_minus; /* TRUE if entering minus can generate a superscript minus */
 
@@ -292,8 +296,6 @@ reformat_display(MathEquation *equation, gint old_base)
 
     /* Add/remove thousands separators */
     reformat_separators(equation);
-
-    g_signal_emit_by_name(equation, "answer-changed");
 }
 
 
@@ -649,6 +651,7 @@ math_equation_set_source_currency(MathEquation *equation, const gchar *currency)
     g_object_notify(G_OBJECT(equation), "source-currency");
 }
 
+
 const gchar *
 math_equation_get_source_currency(MathEquation *equation)
 {
@@ -679,6 +682,41 @@ math_equation_get_target_currency(MathEquation *equation)
 
 
 void
+math_equation_set_source_units(MathEquation *equation, const gchar *units)
+{
+    if (strcmp(equation->priv->source_units, units) == 0)
+        return;
+    g_free(equation->priv->source_units);
+    equation->priv->source_units = g_strdup(units);
+    g_object_notify(G_OBJECT(equation), "source-units");
+}
+
+const gchar *
+math_equation_get_source_units(MathEquation *equation)
+{
+    return equation->priv->source_units;
+}
+
+
+void
+math_equation_set_target_units(MathEquation *equation, const gchar *units)
+{
+    if (strcmp(equation->priv->target_units, units) == 0)
+        return;
+    g_free(equation->priv->target_units);
+    equation->priv->target_units = g_strdup(units);
+    g_object_notify(G_OBJECT(equation), "target-units");
+}
+
+
+const gchar *
+math_equation_get_target_units(MathEquation *equation)
+{
+    return equation->priv->target_units;
+}
+
+
+void
 math_equation_set_status(MathEquation *equation, const gchar *status)
 {
     if (strcmp(equation->priv->state.status, status) == 0)
@@ -1177,7 +1215,6 @@ math_equation_look_for_answer(gpointer data)
     }
     g_slice_free(SolveData, result);
 
-    g_signal_emit_by_name(equation, "answer-changed");
     return false;
 }
 
@@ -1419,6 +1456,12 @@ math_equation_set_property(GObject      *object,
     case PROP_TARGET_CURRENCY:
         math_equation_set_target_currency(self, g_value_get_string(value));
         break;
+    case PROP_SOURCE_UNITS:
+        math_equation_set_source_units(self, g_value_get_string(value));
+        break;
+    case PROP_TARGET_UNITS:
+        math_equation_set_target_units(self, g_value_get_string(value));
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -1481,6 +1524,12 @@ math_equation_get_property(GObject    *object,
     case PROP_TARGET_CURRENCY:
         g_value_set_string(value, self->priv->target_currency);
         break;
+    case PROP_SOURCE_UNITS:
+        g_value_set_string(value, self->priv->source_units);
+        break;
+    case PROP_TARGET_UNITS:
+        g_value_set_string(value, self->priv->target_units);
+        break;
     case PROP_SERIALIZER:
         g_value_set_object(value, self->priv->serializer);
         break;
@@ -1627,22 +1676,26 @@ math_equation_class_init(MathEquationClass *klass)
                                                         "",
                                                         G_PARAM_READWRITE));
     g_object_class_install_property(object_class,
+                                    PROP_SOURCE_UNITS,
+                                    g_param_spec_string("source-units",
+                                                        "source-units",
+                                                        "Source Units",
+                                                        "",
+                                                        G_PARAM_READWRITE));
+    g_object_class_install_property(object_class,
+                                    PROP_TARGET_UNITS,
+                                    g_param_spec_string("target-units",
+                                                        "target-units",
+                                                        "target Units",
+                                                        "",
+                                                        G_PARAM_READWRITE));
+    g_object_class_install_property(object_class,
                                     PROP_SERIALIZER,
                                     g_param_spec_object("serializer",
                                                         "serializer",
                                                         "Serializer",
                                                         MP_TYPE_SERIALIZER,
                                                         G_PARAM_READABLE));
-
-    g_signal_new("answer-changed",
-                 G_TYPE_FROM_CLASS(object_class),
-                 G_SIGNAL_RUN_FIRST,
-                 0,
-                 NULL,
-                 NULL,
-                 g_cclosure_marshal_VOID__VOID,
-                 G_TYPE_NONE,
-                 0);
 }
 
 
@@ -1798,6 +1851,8 @@ math_equation_init(MathEquation *equation)
     // FIXME: Pick based on locale
     equation->priv->source_currency = g_strdup(currency_names[0].short_name);
     equation->priv->target_currency = g_strdup(currency_names[0].short_name);
+    equation->priv->source_units = g_strdup("");
+    equation->priv->target_units = g_strdup("");
     equation->priv->serializer = mp_serializer_new();
     equation->priv->queue = g_async_queue_new();
 
diff --git a/src/math-equation.h b/src/math-equation.h
index 066413f..697324a 100644
--- a/src/math-equation.h
+++ b/src/math-equation.h
@@ -97,6 +97,12 @@ const gchar *math_equation_get_source_currency(MathEquation *equation);
 void math_equation_set_target_currency(MathEquation *equation, const gchar *currency);
 const gchar *math_equation_get_target_currency(MathEquation *equation);
 
+void math_equation_set_source_units(MathEquation *equation, const gchar *units);
+const gchar *math_equation_get_source_units(MathEquation *equation);
+
+void math_equation_set_target_units(MathEquation *equation, const gchar *units);
+const gchar *math_equation_get_target_units(MathEquation *equation);
+
 gboolean math_equation_in_solve(MathEquation *equation);
 
 const MPNumber *math_equation_get_answer(MathEquation *equation);
diff --git a/src/mp-equation.c b/src/mp-equation.c
index d09c64e..1e443ab 100644
--- a/src/mp-equation.c
+++ b/src/mp-equation.c
@@ -22,6 +22,7 @@
 #include "mp-equation-private.h"
 #include "mp-equation-parser.h"
 #include "mp-equation-lexer.h"
+#include "units.h"
 
 extern int _mp_equation_parse(yyscan_t yyscanner);
 
@@ -246,184 +247,11 @@ get_function(MPEquationParserState *state, const char *name, const MPNumber *x,
 
 
 static int
-do_convert(const char *units[][2], const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
-{
-    int x_index, z_index;
-    MPNumber x_factor, z_factor;
-    
-    for (x_index = 0; units[x_index][0] != NULL && strcmp(units[x_index][0], x_units) != 0; x_index++);
-    if (units[x_index][0] == NULL)
-        return 0;
-    for (z_index = 0; units[z_index][0] != NULL && strcmp(units[z_index][0], z_units) != 0; z_index++);
-    if (units[z_index][0] == NULL)
-        return 0;
-
-    mp_set_from_string(units[x_index][1], 10, &x_factor);
-    mp_set_from_string(units[z_index][1], 10, &z_factor);
-    mp_multiply(x, &x_factor, z);
-    mp_divide(z, &z_factor, z);
-
-    return 1;
-}
-
-
-static int
 convert(MPEquationParserState *state, const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
 {
-    const char *angle_units[][2] = {
-        /* FIXME: Approximations of 1/(units in a circle)
-         * Therefore, 360 deg != 400 grads */
-        {"grad",     "0.0025"},
-        {"gradian",  "0.0025"},
-        {"gradians", "0.0025"},
-        {"deg",      "0.002777778"},
-        {"degree",   "0.002777778"},
-        {"degrees",  "0.002777778"},
-        {"rad",      "0.159154943"},
-        {"radian",   "0.159154943"},
-        {"radians",  "0.159154943"},
-        {NULL, NULL}
-    };
-
-    const char *length_units[][2] = {
-        {"parsec",     "30857000000000000"},
-        {"parsecs",    "30857000000000000"},
-        {"pc",         "30857000000000000"},
-        {"lightyear",   "9460730472580800"},
-        {"lightyears",  "9460730472580800"},
-        {"ly",          "9460730472580800"},
-        {"au",              "149597870691"},
-        {"nm",                   "1852000"},
-        {"mile",                    "1609.344"},
-        {"miles",                   "1609.344"},
-        {"mi",                      "1609.344"},
-        {"kilometer",               "1000"},
-        {"kilometers",              "1000"},
-        {"km",                      "1000"},
-        {"kms",                     "1000"},
-        {"cable",                    "219.456"},
-        {"cables",                   "219.456"},
-        {"cb",                       "219.456"},
-        {"fathom",                     "1.8288"},
-        {"fathoms",                    "1.8288"},
-        {"ftm",                        "1.8288"},
-        {"meter",                      "1"},
-        {"meters",                     "1"},
-        {"m",                          "1"},
-        {"yard",                       "0.9144"},
-        {"yards",                      "0.9144"},
-        {"yd",                         "0.9144"},
-        {"foot",                       "0.3048"},
-        {"feet",                       "0.3048"},
-        {"ft",                         "0.3048"},
-        {"inch",                       "0.0254"},
-        {"inches",                     "0.0254"},
-        {"centimeter",                 "0.01"},
-        {"centimeters",                "0.01"},
-        {"cm",                         "0.01"},
-        {"cms",                        "0.01"},
-        {"millimeter",                 "0.001"},
-        {"millimeters",                "0.001"},
-        {"mm",                         "0.001"},
-        {"micrometer",                 "0.000001"},
-        {"micrometers",                "0.000001"},
-        {"um",                         "0.000001"},
-        {"nanometer",                  "0.000000001"},
-        {"nanometers",                 "0.000000001"},
-        {NULL, NULL}
-    };
-
-    const char *area_units[][2] = {
-        {"hectare",         "10000"},
-        {"hectares",        "10000"},
-        {"acre",             "4046.8564224"},
-        {"acres",            "4046.8564224"},
-        {"m²",                  "1"},
-        {"cm²",                 "0.001"},
-        {"mm²",                 "0.000001"},
-        {NULL, NULL}
-    };
-
-    const char *volume_units[][2] = {
-        {"m³",               "1000"},
-        {"gallon",              "3.785412"},
-        {"gallons",             "3.785412"},
-        {"gal",                 "3.785412"},
-        {"litre",               "1"},
-        {"litres",              "1"},
-        {"liter",               "1"},
-        {"liters",              "1"},
-        {"L",                   "1"},
-        {"quart",               "0.9463529"},
-        {"quarts",              "0.9463529"},
-        {"qt",                  "0.9463529"},
-        {"pint",                "0.4731765"},
-        {"pints",               "0.4731765"},
-        {"pt",                  "0.4731765"},
-        {"millilitre",          "0.001"},
-        {"millilitres",         "0.001"},
-        {"milliliter",          "0.001"},
-        {"milliliters",         "0.001"},
-        {"mL",                  "0.001"},
-        {"cm³",                 "0.001"},
-        {"mm³",                 "0.000001"},
-        {NULL, NULL}
-    };
-
-    const char *weight_units[][2] = {
-        {"tonne",            "1000"},
-        {"tonnes",           "1000"},
-        {"kilograms",           "1"},
-        {"kilogramme",          "1"},
-        {"kilogrammes",         "1"},
-        {"kg",                  "1"},
-        {"kgs",                 "1"},
-        {"pound",               "0.45359237"},
-        {"pounds",              "0.45359237"},
-        {"lb",                  "0.45359237"},
-        {"ounce",               "0.02834952"},
-        {"ounces",              "0.02834952"},
-        {"oz",                  "0.02834952"},
-        {"gram",                "0.001"},
-        {"grams",               "0.001"},
-        {"gramme",              "0.001"},
-        {"grammes",             "0.001"},
-        {"g",                   "0.001"},
-        {NULL, NULL}
-    };
-    
-    const char *time_units[][2] = {
-        {"year",         "31557600"},
-        {"years",        "31557600"},
-        {"day",             "86400"},
-        {"days",            "86400"},
-        {"hour",             "3600"},
-        {"hours",            "3600"},
-        {"minute",             "60"},
-        {"minutes",            "60"},
-        {"second",              "1"},
-        {"seconds",             "1"},
-        {"s",                   "1"},
-        {"millisecond",         "0.001"},
-        {"milliseconds",        "0.001"},
-        {"ms",                  "0.001"},
-        {"microsecond",         "0.000001"},
-        {"microseconds",        "0.000001"},
-        {"us",                  "0.000001"},
-        {NULL, NULL}
-    };
-
-    if (do_convert(angle_units, x, x_units, z_units, z) ||
-        do_convert(length_units, x, x_units, z_units, z) ||
-        do_convert(area_units, x, x_units, z_units, z) ||
-        do_convert(volume_units, x, x_units, z_units, z) ||
-        do_convert(weight_units, x, x_units, z_units, z) ||
-        do_convert(time_units, x, x_units, z_units, z))
+    if (!units_convert(x, x_units, z_units, z))
         return 1;
 
-    if (state->options->convert)
-        return state->options->convert(x, x_units, z_units, z, state->options->callback_data);
-  
     return 0;
 }
 
diff --git a/src/units.c b/src/units.c
new file mode 100644
index 0000000..6fc4bd8
--- /dev/null
+++ b/src/units.c
@@ -0,0 +1,182 @@
+#include <string.h>
+
+#include "units.h"
+
+static const char *angle_units[][2] = {
+    /* FIXME: Approximations of 1/(units in a circle)
+     * Therefore, 360 deg != 400 grads */
+    {"grad",     "0.0025"},
+    {"gradian",  "0.0025"},
+    {"gradians", "0.0025"},
+    {"deg",      "0.002777778"},
+    {"degree",   "0.002777778"},
+    {"degrees",  "0.002777778"},
+    {"rad",      "0.159154943"},
+    {"radian",   "0.159154943"},
+    {"radians",  "0.159154943"},
+    {NULL, NULL}
+};
+
+static const char *length_units[][2] = {
+    {"parsec",     "30857000000000000"},
+    {"parsecs",    "30857000000000000"},
+    {"pc",         "30857000000000000"},
+    {"lightyear",   "9460730472580800"},
+    {"lightyears",  "9460730472580800"},
+    {"ly",          "9460730472580800"},
+    {"au",              "149597870691"},
+    {"nm",                   "1852000"},
+    {"mile",                    "1609.344"},
+    {"miles",                   "1609.344"},
+    {"mi",                      "1609.344"},
+    {"kilometer",               "1000"},
+    {"kilometers",              "1000"},
+    {"km",                      "1000"},
+    {"kms",                     "1000"},
+    {"cable",                    "219.456"},
+    {"cables",                   "219.456"},
+    {"cb",                       "219.456"},
+    {"fathom",                     "1.8288"},
+    {"fathoms",                    "1.8288"},
+    {"ftm",                        "1.8288"},
+    {"meter",                      "1"},
+    {"meters",                     "1"},
+    {"m",                          "1"},
+    {"yard",                       "0.9144"},
+    {"yards",                      "0.9144"},
+    {"yd",                         "0.9144"},
+    {"foot",                       "0.3048"},
+    {"feet",                       "0.3048"},
+    {"ft",                         "0.3048"},
+    {"inch",                       "0.0254"},
+    {"inches",                     "0.0254"},
+    {"centimeter",                 "0.01"},
+    {"centimeters",                "0.01"},
+    {"cm",                         "0.01"},
+    {"cms",                        "0.01"},
+    {"millimeter",                 "0.001"},
+    {"millimeters",                "0.001"},
+    {"mm",                         "0.001"},
+    {"micrometer",                 "0.000001"},
+    {"micrometers",                "0.000001"},
+    {"um",                         "0.000001"},
+    {"nanometer",                  "0.000000001"},
+    {"nanometers",                 "0.000000001"},
+    {NULL, NULL}
+};
+
+static const char *area_units[][2] = {
+    {"hectare",         "10000"},
+    {"hectares",        "10000"},
+    {"acre",             "4046.8564224"},
+    {"acres",            "4046.8564224"},
+    {"m²",                  "1"},
+    {"cm²",                 "0.001"},
+    {"mm²",                 "0.000001"},
+    {NULL, NULL}
+};
+
+static const char *volume_units[][2] = {
+    {"m³",               "1000"},
+    {"gallon",              "3.785412"},
+    {"gallons",             "3.785412"},
+    {"gal",                 "3.785412"},
+    {"litre",               "1"},
+    {"litres",              "1"},
+    {"liter",               "1"},
+    {"liters",              "1"},
+    {"L",                   "1"},
+    {"quart",               "0.9463529"},
+    {"quarts",              "0.9463529"},
+    {"qt",                  "0.9463529"},
+    {"pint",                "0.4731765"},
+    {"pints",               "0.4731765"},
+    {"pt",                  "0.4731765"},
+    {"millilitre",          "0.001"},
+    {"millilitres",         "0.001"},
+    {"milliliter",          "0.001"},
+    {"milliliters",         "0.001"},
+    {"mL",                  "0.001"},
+    {"cm³",                 "0.001"},
+    {"mm³",                 "0.000001"},
+    {NULL, NULL}
+};
+
+static const char *weight_units[][2] = {
+    {"tonne",            "1000"},
+    {"tonnes",           "1000"},
+    {"kilograms",           "1"},
+    {"kilogramme",          "1"},
+    {"kilogrammes",         "1"},
+    {"kg",                  "1"},
+    {"kgs",                 "1"},
+    {"pound",               "0.45359237"},
+    {"pounds",              "0.45359237"},
+    {"lb",                  "0.45359237"},
+    {"ounce",               "0.02834952"},
+    {"ounces",              "0.02834952"},
+    {"oz",                  "0.02834952"},
+    {"gram",                "0.001"},
+    {"grams",               "0.001"},
+    {"gramme",              "0.001"},
+    {"grammes",             "0.001"},
+    {"g",                   "0.001"},
+    {NULL, NULL}
+};
+    
+static const char *time_units[][2] = {
+    {"year",         "31557600"},
+    {"years",        "31557600"},
+    {"day",             "86400"},
+    {"days",            "86400"},
+    {"hour",             "3600"},
+    {"hours",            "3600"},
+    {"minute",             "60"},
+    {"minutes",            "60"},
+    {"second",              "1"},
+    {"seconds",             "1"},
+    {"s",                   "1"},
+    {"millisecond",         "0.001"},
+    {"milliseconds",        "0.001"},
+    {"ms",                  "0.001"},
+    {"microsecond",         "0.000001"},
+    {"microseconds",        "0.000001"},
+    {"us",                  "0.000001"},
+    {NULL, NULL}
+};
+
+static gboolean
+do_convert(const char *units[][2], const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
+{
+    int x_index, z_index;
+    MPNumber x_factor, z_factor;
+    
+    for (x_index = 0; units[x_index][0] != NULL && strcmp(units[x_index][0], x_units) != 0; x_index++);
+    if (units[x_index][0] == NULL)
+        return FALSE;
+    for (z_index = 0; units[z_index][0] != NULL && strcmp(units[z_index][0], z_units) != 0; z_index++);
+    if (units[z_index][0] == NULL)
+        return FALSE;
+
+    mp_set_from_string(units[x_index][1], 10, &x_factor);
+    mp_set_from_string(units[z_index][1], 10, &z_factor);
+    mp_multiply(x, &x_factor, z);
+    mp_divide(z, &z_factor, z);
+
+    return TRUE;
+}
+
+
+gboolean
+units_convert(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
+{
+    if (do_convert(angle_units, x, x_units, z_units, z) ||
+        do_convert(length_units, x, x_units, z_units, z) ||
+        do_convert(area_units, x, x_units, z_units, z) ||
+        do_convert(volume_units, x, x_units, z_units, z) ||
+        do_convert(weight_units, x, x_units, z_units, z) ||
+        do_convert(time_units, x, x_units, z_units, z))
+        return TRUE;
+  
+    return FALSE;
+}
diff --git a/src/units.h b/src/units.h
new file mode 100644
index 0000000..715b111
--- /dev/null
+++ b/src/units.h
@@ -0,0 +1,8 @@
+#ifndef UNITS_H
+#define UNITS_H
+
+#include "mp.h"
+
+gboolean units_convert(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z);
+
+#endif /* UNITS_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]