summaryrefslogtreecommitdiffstats
path: root/src/gui/Roster.vala
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/Roster.vala')
-rw-r--r--src/gui/Roster.vala392
1 files changed, 283 insertions, 109 deletions
diff --git a/src/gui/Roster.vala b/src/gui/Roster.vala
index be0a5ed..65119e2 100644
--- a/src/gui/Roster.vala
+++ b/src/gui/Roster.vala
@@ -1,154 +1,328 @@
-public class Roster : Object, Gtk.TreeModel {
- private int stamp;
- private Gee.TreeMap<string, Contact> entries = new Gee.TreeMap<string, Contact>();
+public class Roster {
+ private Gtk.VBox rosterView;
+ private RosterModel model;
+ private Gee.TreeMap<string, GroupInfo> groups = new Gee.TreeMap<string, GroupInfo>();
+ public signal void start_conversation(string jid);
- public Roster() {
- stamp = 0;
+
+ public Roster(Gtk.VBox rosterView0) {
+ rosterView = rosterView0;
+ model = new RosterModel(this);
+ }
+
+ public Gtk.TreeModel get_model() {
+ return model;
}
public void update_contact(Contact c) {
- ++stamp;
- bool added = !entries.has_key(c.jid);
-
- entries[c.jid] = c;
-
- Gtk.TreeIter iter = Gtk.TreeIter();
- iter.stamp = stamp;
- iter.user_data = this;
- iter.user_data2 = c;
-
- Gtk.TreePath path = get_path(iter);
-
- if (added)
- row_inserted(path, iter);
- else
- row_changed(path, iter);
+ model.update_contact(c);
}
public Contact get_contact(string jid) {
- string bareJID = jid.split("/", 2)[0];
-
- return entries[bareJID];
+ return model.get_contact(jid);
}
- public Type get_column_type (int index) {
- switch(index) {
- case 0:
- return typeof(Contact);
- }
+ private Gtk.TreeView new_tree_view() {
+ Gtk.TreeView view = new Gtk.TreeView();
+
+ view.headers_visible = false;
+
+ view.query_tooltip.connect((x, y, keyboard_tip, tooltip) => {
+ Gtk.TreeModel model;
+ Gtk.TreeIter iter;
+
+ if(!view.get_tooltip_context(out x, out y, keyboard_tip, out model, null, out iter))
+ return false;
+
+ Value value;
+ model.get_value(iter, 0, out value);
+
+ Contact? c = value.get_object() as Contact;
+ if(c == null)
+ return false;
+
+ Gee.Map.Entry<string, Contact.Resource>? r = c.get_resource_with_highest_priority();
+
+ if(r == null)
+ return false;
+
+ tooltip.set_text("Resource: " + r.key + " (" + r.value.priority.to_string() + ")");
+
+ return true;
+ });
+ view.has_tooltip = true;
+
+ view.row_activated.connect((view, path, column) => {
+ Gtk.TreeIter iter;
+ view.model.get_iter(out iter, path);
+
+ Value value;
+ view.model.get_value(iter, 0, out value);
+
+ Contact contact = value.get_object() as Contact;
+ if(contact == null)
+ return;
+
+ Gee.Map.Entry<string, Contact.Resource> res = contact.get_resource_with_highest_priority();
+ if(res == null)
+ return; //FIXME
+
+ start_conversation(contact.jid + "/" + res.key);
+ });
+
+ Gtk.TreeViewColumn presenceColumn = new Gtk.TreeViewColumn.with_attributes(null, new CellRendererPresence(), "contact", 0, null);
+ presenceColumn.min_width = 32;
+ view.append_column(presenceColumn);
+
+ Gtk.TreeViewColumn contactColumn = new Gtk.TreeViewColumn();
- return Type.INVALID;
+ Gtk.CellRenderer cellRendererContact = new CellRendererContact();
+ contactColumn.pack_start(cellRendererContact, true);
+ contactColumn.set_attributes(cellRendererContact, "contact", 0, null);
+
+ Gtk.CellRenderer cellRendererAvatar = new CellRendererAvatar();
+ contactColumn.pack_end(cellRendererAvatar, false);
+ contactColumn.set_attributes(cellRendererAvatar, "contact", 0, null);
+
+ view.append_column(contactColumn);
+
+ return view;
}
+
+ private void update_groups() {
+ int i = 0;
- public Gtk.TreeModelFlags get_flags () {
- return Gtk.TreeModelFlags.LIST_ONLY;
+ foreach(Gee.Map.Entry<string, GroupInfo> group in groups) {
+ if(group.value.count <= 0) {
+ rosterView.remove(group.value.expander);
+ group.value.expander.remove(group.value.view);
+ groups.remove(group.key);
+ continue;
+ }
+
+ if(group.value.count > 0 && group.value.view == null) {
+ group.value.view = new_tree_view();
+ group.value.view.model = new GroupFilter(this, group.key);
+
+ group.value.expander = new Gtk.Expander("<i>" + Markup.escape_text(group.key) + "</i>");
+ group.value.expander.set_use_markup(true);
+ group.value.expander.expanded = true;
+ group.value.expander.add(group.value.view);
+ group.value.expander.show_all();
+
+ rosterView.pack_start(group.value.expander, false, false, 0);
+ }
+
+ rosterView.reorder_child(group.value.expander, i++);
+ }
}
+
+ private class RosterModel : Object, Gtk.TreeModel {
+ private Roster roster;
+ private int stamp = 0;
+ private Gee.TreeMap<string, Contact> entries = new Gee.TreeMap<string, Contact>();
+
- public bool get_iter (out Gtk.TreeIter iter, Gtk.TreePath path) {
- if(path.get_depth() != 1)
- return false;
+ public RosterModel(Roster roster0) {
+ roster = roster0;
+ }
+
+ public void update_contact(Contact c) {
+ ++stamp;
+ bool added = true;
+ if(c.jid in entries) {
+ added = false;
+
+ foreach(string group in entries[c.jid].get_groups()) {
+ if(group in roster.groups) {
+ roster.groups[group].count--;
+ }
+ else {
+ warn_if_reached();
+ }
+ }
+ }
- int index = path.get_indices()[0];
- if(index < 0 || index >= entries.size)
- return false;
- Gee.MapIterator<string, Contact> it = entries.map_iterator();
- it.first();
- for(int i = 0; i < index; ++i)
- it.next();
+ entries[c.jid] = c;
- iter.stamp = stamp;
- iter.user_data = this;
- iter.user_data2 = it.get_value();
+ Gtk.TreeIter iter = Gtk.TreeIter();
+ iter.stamp = stamp;
+ iter.user_data = this;
+ iter.user_data2 = c;
- return true;
- }
+ Gtk.TreePath path = get_path(iter);
+
+ if(added)
+ row_inserted(path, iter);
+ else
+ row_changed(path, iter);
+
+ foreach(string group in c.get_groups()) {
+ if(!(group in roster.groups))
+ roster.groups[group] = new GroupInfo();
+
+ roster.groups[group].count++;
+ }
+
+ roster.update_groups();
+ }
- public int get_n_columns () {
- return 1;
- }
+ public Contact get_contact(string jid) {
+ string bareJID = jid.split("/", 2)[0];
+
+ return entries[bareJID];
+ }
+
+ public Type get_column_type(int index) {
+ switch(index) {
+ case 0:
+ return typeof(Contact);
+ }
+
+ return Type.INVALID;
+ }
+
+ public Gtk.TreeModelFlags get_flags() {
+ return Gtk.TreeModelFlags.LIST_ONLY;
+ }
+
+ public bool get_iter(out Gtk.TreeIter iter, Gtk.TreePath path) {
+ if(path.get_depth() != 1)
+ return false;
+
+ int index = path.get_indices()[0];
+ if(index < 0 || index >= entries.size)
+ return false;
+
+ Gee.MapIterator<string, Contact> it = entries.map_iterator();
+ it.first();
+ for(int i = 0; i < index; ++i)
+ it.next();
+
+ iter.stamp = stamp;
+ iter.user_data = this;
+ iter.user_data2 = it.get_value();
+
+ return true;
+ }
- public Gtk.TreePath get_path (Gtk.TreeIter iter) {
- if(iter.stamp != stamp || iter.user_data != this)
- return (Gtk.TreePath)null;
+ public int get_n_columns() {
+ return 1;
+ }
+
+ public Gtk.TreePath get_path(Gtk.TreeIter iter) {
+ if(iter.stamp != stamp || iter.user_data != this)
+ return (Gtk.TreePath)null;
- int index = 0;
+ int index = 0;
- foreach(Contact c in entries.values) {
- if(c == iter.user_data2)
- break;
+ foreach(Contact c in entries.values) {
+ if(c == iter.user_data2)
+ break;
- ++index;
- }
+ ++index;
+ }
- return new Gtk.TreePath.from_indices(index, -1);
- }
+ return new Gtk.TreePath.from_indices(index, -1);
+ }
- public void get_value (Gtk.TreeIter iter, int column, out Value value) {
- if (column != 0 || iter.stamp != stamp || iter.user_data != this) {
- value = Value(Type.INVALID);
- return;
+ public void get_value(Gtk.TreeIter iter, int column, out Value value) {
+ if (column != 0 || iter.stamp != stamp || iter.user_data != this) {
+ value = Value(Type.INVALID);
+ return;
+ }
+
+ Contact c = iter.user_data2 as Contact;
+ value = Value(typeof(Contact));
+ value.take_object(c);
}
+
+ public bool iter_children(out Gtk.TreeIter iter, Gtk.TreeIter? parent) {
+ if (parent != null) {
+ iter.stamp = -1;
+ return false;
+ }
- Contact c = iter.user_data2 as Contact;
- value = Value(typeof(Contact));
- value.take_object(c);
- }
+ return get_iter(out iter, new Gtk.TreePath.from_indices(0, -1));
+ }
- public bool iter_children (out Gtk.TreeIter iter, Gtk.TreeIter? parent) {
- if (parent != null) {
- iter.stamp = -1;
+ public bool iter_has_child(Gtk.TreeIter iter) {
return false;
}
-
- return get_iter(out iter, new Gtk.TreePath.from_indices(0, -1));
- }
-
- public bool iter_has_child (Gtk.TreeIter iter) {
- return false;
- }
- public int iter_n_children (Gtk.TreeIter? iter) {
- if (iter == null)
- return entries.size;
- else
- return 0;
- }
+ public int iter_n_children(Gtk.TreeIter? iter) {
+ if (iter == null)
+ return entries.size;
+ else
+ return 0;
+ }
- public bool iter_next (ref Gtk.TreeIter iter) {
- if(iter.stamp != stamp || iter.user_data != this)
- return false;
+ public bool iter_next(ref Gtk.TreeIter iter) {
+ if(iter.stamp != stamp || iter.user_data != this)
+ return false;
- bool next = false;
- foreach(Contact c in entries.values) {
- if(next) {
- iter.user_data2 = c;
- return true;
- }
+ bool next = false;
+ foreach(Contact c in entries.values) {
+ if(next) {
+ iter.user_data2 = c;
+ return true;
+ }
- if(c == iter.user_data2)
- next = true;
+ if(c == iter.user_data2)
+ next = true;
+ }
+
+ iter.stamp = -1;
+ return false;
}
+
+ public bool iter_nth_child(out Gtk.TreeIter iter, Gtk.TreeIter? parent, int n) {
+ if (parent != null) {
+ iter.stamp = -1;
+ return false;
+ }
- iter.stamp = -1;
- return false;
- }
+ return get_iter(out iter, new Gtk.TreePath.from_indices(n, -1));
+ }
- public bool iter_nth_child (out Gtk.TreeIter iter, Gtk.TreeIter? parent, int n) {
- if (parent != null) {
+ public bool iter_parent(out Gtk.TreeIter iter, Gtk.TreeIter child) {
iter.stamp = -1;
return false;
}
+
+ public void ref_node(Gtk.TreeIter iter) {}
+ public void unref_node(Gtk.TreeIter iter) {}
+ }
+
+ private class GroupFilter : Gtk.TreeModelFilter {
+ private Roster roster;
+ private string group;
+
+ public GroupFilter(Roster roster0, string group0) {
+ Object(child_model: roster0.model);
+
+ roster = roster0;
+ group = group0;
- return get_iter(out iter, new Gtk.TreePath.from_indices(n, -1));
+ set_visible_func((model, iter) => {
+ Value value;
+ model.get_value(iter, 0, out value);
+
+ Contact c = value.get_object() as Contact;
+
+ if(c == null)
+ return true;
+
+ return (group in c.get_groups());
+ });
+ }
}
-
- public bool iter_parent (out Gtk.TreeIter iter, Gtk.TreeIter child) {
- iter.stamp = -1;
- return false;
+
+ private class GroupInfo {
+ public int count = 0;
+ public Gtk.Expander expander = null;
+ public Gtk.TreeView view = null;
}
-
- public void ref_node (Gtk.TreeIter iter) {}
- public void unref_node (Gtk.TreeIter iter) {}
}