The GtkExpression
and GObject::notify
can’t cover the computed or multiple value scenes, for example:
The Row object has many items (column value object), one of them changed its hold value or property, maybe multiple values at time.
In our case, we make many changes at time, then refresh the UI (GtkListView / GtkColumnView) normally, pls see the Vala code as follow:
public class ValueObject : Object, IValue
{
public virtual string name {
get { return "UNKNOWN"; }
}
public virtual bool is_null {
get { return false; }
}
public virtual string to_string() {
return "";
}
}
public class ValueNull : ValueObject
{
public const string NULL_LABEL = "(Null)";
public const string NULL_VALUE = "NULL";
public const string NULL_EMPTY = "";
public override string name {
get { return "NULL"; }
}
public string itsvalue {
get { return NULL_VALUE; }
}
}
public class RowModel : GLib.Object, GLib.ListModel
{
private Gee.ArrayList<ValueObject> m_values;
public RowModel()
{
m_values = new Gee.ArrayList<ValueObject>();
}
}
public class TableModel : GLib.Object, IResult, ListModel
{
private Gee.ArrayList<RowModel> m_rows;
private Gee.ArrayList<ColumnModel> m_columns;
public TableModel()
{
m_rows = new Gee.ArrayList<RowModel>();
m_columns = new Gee.ArrayList<ColumnModel>();
}
}
public interface IGridable : Object {
// public abstract int page_active { get; }
public abstract Gtk.ColumnView grid { get; }
public void make_grid(TableModel data_model, int[] column_sizes = {})
{
(this.grid.columns as GLib.ListStore)?.remove_all();
for(int index = 0; index < data_model.columns.size; index++) {
factory = new Gtk.SignalListItemFactory();
factory.set_data<int>(PROP_INDEX, index);
factory.set_data<DataType>(PROP_TYPE, data_type);
factory.setup.connect(column_setup_handler);
factory.bind.connect(column_bind_handler);
caption = column_model.title ?? column_model.name;
column = new Gtk.ColumnViewColumn(caption, factory);
column.expand = true;
column.resizable = true;
const_expr = new Gtk.ConstantExpression(typeof(int), index);
if (data_type in INTERGERS) {
expression = new Gtk.CClosureExpression(typeof(int64), null, { const_expr }, (Callback)get_integer_by_index, null, null);
column.sorter = new Gtk.NumericSorter(expression);
} else if (data_type in NUMERICS) {
expression = new Gtk.CClosureExpression(typeof(double), null, { const_expr }, (Callback)get_double_by_index, null, null);
column.sorter = new Gtk.NumericSorter(expression);
} else {
expression = new Gtk.CClosureExpression(typeof(string), null, { const_expr }, (Callback)get_string_by_index, null, null);
column.sorter = new Gtk.StringSorter(expression);
}
this.grid.append_column(column);
}
}
public virtual void column_setup_handler(Gtk.SignalListItemFactory factory, GLib.Object listitem)
{
int index = factory.get_data<int>(PROP_INDEX);
DataType data_type = factory.get_data<DataType>(PROP_TYPE);
Gtk.EditableLabel editable = new Gtk.EditableLabel("");
editable.xalign = 0.0f;
editable.set_data<int>(PROP_INDEX, index);
editable.set_data<DataType>(PROP_TYPE, data_type);
editable.notify["editing"].connect(editable_editing_handler);
(listitem as Gtk.ListItem).child = editable;
}
public virtual void column_bind_handler(Gtk.SignalListItemFactory factory, GLib.Object listitem)
{
Gtk.EditableLabel editable = (listitem as Gtk.ListItem).child as Gtk.EditableLabel;
editable.changed.disconnect(editable_changed_handler);
RowModel row = (listitem as Gtk.ListItem).item as RowModel;
editable.set_data<RowModel>(PROP_ROW, row);
int index = factory.get_data<int>(PROP_INDEX);
if (index < row.values.size) {
bool is_null = row.values[index] is ValueNull;
if (is_null) {
editable.text = ValueNull.NULL_LABEL;
} else if (row.values[index] is ValueBinary) {
var value_binary = row.values[index] as ValueBinary;
editable.text = DatabaseHelper.summary(value_binary);
} else {
editable.text = row.values[index]?.to_string() ?? "";
}
}
editable.changed.connect(editable_changed_handler);
}
public virtual void editable_changed_handler(Gtk.Editable sender)
{
// Save value
// Refresh grid
}
}
@otte @matthiasc @gwillems