/*
* Copyright (C) 2008-2012 Robert Ancell
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
* license.
*/
[GtkTemplate (ui = "/org/gnome/calculator/math-converter.ui")]
public class MathConverter : Gtk.Grid
{
private MathEquation equation = null;
private string category;
[GtkChild]
private Gtk.CellRendererText from_renderer;
[GtkChild]
private Gtk.ComboBox from_combo;
[GtkChild]
private Gtk.ComboBox to_combo;
[GtkChild]
private Gtk.Label from_label;
[GtkChild]
private Gtk.Label to_label;
public signal void changed ();
construct
{
from_combo.set_cell_data_func (from_renderer, from_cell_data_func);
CurrencyManager.get_default ().updated.connect (() => { update_result_label (); });
update_from_model ();
}
public MathConverter (MathEquation equation)
{
set_equation (equation);
}
public void set_equation (MathEquation equation)
{
this.equation = equation;
equation.notify["display"].connect ((pspec) => { update_result_label (); });
}
public void set_category (string? category)
{
if (this.category == category)
return;
this.category = category;
update_from_model ();
}
public string get_category ()
{
return category;
}
public void set_conversion (/*string category,*/ string unit_a, string unit_b)
{
var ua = UnitManager.get_default ().get_unit_by_name (unit_a);
var ub = UnitManager.get_default ().get_unit_by_name (unit_b);
if (ua == null || ub == null)
{
/* Select the first unit */
var model = from_combo.get_model ();
Gtk.TreeIter iter;
if (model.get_iter_first (out iter))
{
Gtk.TreeIter child_iter;
while (model.iter_children (out child_iter, iter))
iter = child_iter;
from_combo.set_active_iter (iter);
}
return;
}
set_active_unit (from_combo, null, ua);
set_active_unit (to_combo, null, ub);
}
public void get_conversion (out Unit from_unit, out Unit to_unit)
{
Gtk.TreeIter from_iter, to_iter;
from_combo.get_active_iter (out from_iter);
to_combo.get_active_iter (out to_iter);
from_combo.get_model ().get (from_iter, 2, out from_unit, -1);
to_combo.get_model ().get (to_iter, 2, out to_unit, -1);
}
private void update_result_label ()
{
var x = equation.number;
if (x == null)
return;
var z = convert_equation (x);
if (z != null)
{
Unit source_unit, target_unit;
get_conversion (out source_unit, out target_unit);
var source_text = source_unit.format (x);
var target_text = target_unit.format (z);
from_label.set_text (source_text);
to_label.set_text (target_text);
}
}
private void update_from_model ()
{
var from_model = new Gtk.TreeStore (3, typeof (string), typeof (UnitCategory), typeof (Unit));
if (category == null)
{
var categories = UnitManager.get_default ().get_categories ();
foreach (var category in categories)
{
Gtk.TreeIter parent;
from_model.append (out parent, null);
from_model.set (parent, 0, category.display_name, 1, category, -1);
foreach (var unit in category.get_units ())
{
Gtk.TreeIter iter;
from_model.append (out iter, parent);
from_model.set (iter, 0, unit.display_name, 1, category, 2, unit, -1);
}
}
}
else
{
var c = UnitManager.get_default ().get_category (category);
foreach (var unit in c.get_units ())
{
Gtk.TreeIter iter;
from_model.append (out iter, null);
from_model.set (iter, 0, unit.display_name, 1, c, 2, unit, -1);
}
}
from_combo.model = from_model;
}
private bool iter_is_unit (Gtk.TreeModel model, Gtk.TreeIter iter, Unit unit)
{
Unit u;
model.get (iter, 2, out u, -1);
return u == unit;
}
private bool set_active_unit (Gtk.ComboBox combo, Gtk.TreeIter? iter, Unit unit)
{
var model = combo.get_model ();
if (iter != null && iter_is_unit (model, iter, unit))
{
combo.set_active_iter (iter);
return true;
}
Gtk.TreeIter child_iter;
if (!model.iter_children (out child_iter, iter))
return false;
do
{
if (set_active_unit (combo, child_iter, unit))
return true;
} while (model.iter_next (ref child_iter));
return false;
}
[GtkCallback]
private void from_combobox_changed_cb ()
{
UnitCategory? category = null, to_category = null;
Unit unit;
Gtk.TreeIter iter, to_iter;
var model = from_combo.get_model ();
var to_model = to_combo.get_model () as Gtk.ListStore;
if (!from_combo.get_active_iter (out iter))
return;
model.get (iter, 1, out category, 2, out unit, -1);
if (to_combo.get_active_iter (out to_iter))
to_model.get (to_iter, 1, out to_category);
if (category != to_category)
{
/* Set the to combobox to be the list of units can be converted to */
to_model = new Gtk.ListStore (3, typeof (string), typeof (UnitCategory), typeof (Unit));
foreach (var u in category.get_units ())
{
to_model.append (out iter);
to_model.set (iter, 0, u.display_name, 1, category, 2, u, -1);
}
to_combo.model = to_model;
/* Select the first possible unit */
to_combo.set_active (0);
}
}
[GtkCallback]
private void to_combobox_changed_cb ()
{
/* Conversion must have changed */
update_result_label ();
changed ();
}
private void from_cell_data_func (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel tree_model, Gtk.TreeIter iter)
{
cell.set ("sensitive", !tree_model.iter_has_child (iter));
}
[GtkCallback]
private void swap_button_clicked_cb ()
{
var x = equation.number;
if (x != null)
{
var z = convert_equation (x);
if (z != null)
equation.set_number (z);
}
Unit from_unit, to_unit;
get_conversion (out from_unit, out to_unit);
set_active_unit (from_combo, null, to_unit);
set_active_unit (to_combo, null, from_unit);
update_result_label ();
}
private Number? convert_equation (Number x)
{
Gtk.TreeIter from_iter, to_iter;
if (!from_combo.get_active_iter (out from_iter))
return null;
if (!to_combo.get_active_iter (out to_iter))
return null;
UnitCategory category;
Unit source_unit, target_unit;
from_combo.model.get (from_iter, 1, out category, 2, out source_unit, -1);
to_combo.model.get (to_iter, 2, out target_unit, -1);
return category.convert (x, source_unit, target_unit);
}
}