From 57a0ca523f0e3a2aa4355636b7ccf60d33f8aaf7 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Thu, 19 Aug 2010 00:07:09 +0200 Subject: Renamed Roster class to ContactList as it will also be used for the MUC participant list --- data/ephraim.glade | 81 ++++++ src/gui/CMakeLists.txt | 2 +- src/gui/ContactList.vala | 729 +++++++++++++++++++++++++++++++++++++++++++++++ src/gui/Ephraim.vala | 2 +- src/gui/Roster.vala | 725 ---------------------------------------------- 5 files changed, 812 insertions(+), 727 deletions(-) create mode 100644 src/gui/ContactList.vala delete mode 100644 src/gui/Roster.vala diff --git a/data/ephraim.glade b/data/ephraim.glade index d5bf424..50ec1ab 100644 --- a/data/ephraim.glade +++ b/data/ephraim.glade @@ -181,4 +181,85 @@ + + True + vertical + 5 + + + True + 5 + label + + + False + 0 + + + + + True + True + + + True + vertical + + + True + queue + + + True + True + False + 3 + 3 + False + + + + + 0 + + + + + True + True + + + + False + 1 + + + + + False + True + + + + + True + queue + + + True + True + + + + + True + True + + + + + 1 + + + diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 42b7734..65ecbe7 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -4,9 +4,9 @@ vala_precompile(VALA_C "Ephraim.vala" "CellRendererContact.vala" "Contact.vala" + "ContactList.vala" "Conversation.vala" "CoreConnector.vala" - "Roster.vala" "String.vala" PACKAGES gtk+-2.0 diff --git a/src/gui/ContactList.vala b/src/gui/ContactList.vala new file mode 100644 index 0000000..8696f93 --- /dev/null +++ b/src/gui/ContactList.vala @@ -0,0 +1,729 @@ +public class ContactList { + private Gtk.TreeView contactView; + private ContactListModel contactList; + private ContactGroupModel model; + private Gee.Map> groups = new Gee.HashMap>(); + + public signal void start_conversation(string jid); + + public ContactList(Gtk.TreeView contactView0) { + contactView = contactView0; + contactList = new ContactListModel(this); + model = new ContactGroupModel(contactList); + + contactView.set_model(new ContactListFilter(this, new ContactListSorter(model))); + + contactView.query_tooltip.connect((x, y, keyboard_tip, tooltip) => { + Gtk.TreeModel model; + Gtk.TreeIter iter; + + if(!contactView.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? 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; + }); + contactView.has_tooltip = true; + + contactView.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 res = contact.get_resource_with_highest_priority(); + if(res == null) + return; //FIXME + + start_conversation(contact.jid + "/" + res.key); + }); + + contactView.model.row_has_child_toggled.connect((path, iter) => { + contactView.expand_row(path, true); + }); + + Gtk.TreeViewColumn contactColumn = new Gtk.TreeViewColumn.with_attributes(null, new CellRendererContact(), "data", 0, null); + contactView.append_column(contactColumn); + } + + public void update_contact(Contact c) { + contactList.update_contact(c); + } + + public Contact get_contact(string jid) { + return contactList.get_contact(jid); + } + + private void update_groups() { + foreach(Gee.Map.Entry> group in groups) { + if(group.value.is_empty) { + model.remove_group(group.key); + groups.unset(group.key); + } + else { + model.add_group(group.key); + } + } + } + + public Gee.Map get_group(string group) { + return groups[group]; + } + + private class ContactGroupModel : Object, Gtk.TreeModel { + private int stamp = 0; + private Gee.Map groupModels = new Gee.TreeMap(); + private Gee.ArrayList childIters = new Gee.ArrayList(); + private ContactListModel contactList; + + + private void incrementStamp() { + stamp++; + childIters.clear(); + } + + public ContactGroupModel(ContactListModel contactList0) { + contactList = contactList0; + } + + public void add_group(string name) { + int index = 0; + foreach(String group in groupModels.keys) { + if(group.data == name) { + Gtk.TreePath path = new Gtk.TreePath.from_indices(index, -1); + Gtk.TreeIter iter; + get_iter(out iter, path); + row_changed(path, iter); + + return; + } + + index++; + } + + Gtk.TreeModel model = new GroupFilter(contactList, name); + + model.row_changed.connect((subpath, subiter) => { + Gtk.TreePath path = child_path_to_path(name, subpath); + Gtk.TreeIter iter; + get_iter(out iter, path); + row_changed(path, iter); + }); + + model.row_deleted.connect((path) => { + path.prepend_index(0); + row_deleted(path); + + Gtk.TreePath parent = path.copy(); + parent.up(); + if(parent.get_depth() == 1) { + Gtk.TreeIter iter; + get_iter(out iter, parent); + if(!iter_has_child(iter)) { + row_has_child_toggled(parent, iter); + } + } + }); + + model.row_has_child_toggled.connect((subpath, subiter) => { + Gtk.TreePath path = child_path_to_path(name, subpath); + Gtk.TreeIter iter; + get_iter(out iter, path); + row_has_child_toggled(path, iter); + }); + + model.row_inserted.connect((subpath, subiter) => { + Gtk.TreePath path = child_path_to_path(name, subpath); + + incrementStamp(); + Gtk.TreeIter iter; + get_iter(out iter, path); + row_inserted(path, iter); + + Gtk.TreePath parent = path.copy(); + parent.up(); + if(parent.get_depth() == 1) { + get_iter(out iter, parent); + Value value; + get_value(iter, 0, out value); + if(iter_n_children(iter) == 0) { + row_has_child_toggled(parent, iter); + } + } + }); + + model.rows_reordered.connect((subpath, subiter, new_order) => { + Gtk.TreePath path = child_path_to_path(name, subpath); + Gtk.TreeIter iter; + get_iter(out iter, path); + rows_reordered(path, iter, new_order); + }); + + groupModels[new String(name)] = model; + + index = 0; + foreach(String group in groupModels.keys) { + if(group.data == name) + break; + + index++; + } + + Gtk.TreePath path = new Gtk.TreePath.from_indices(index, -1); + Gtk.TreeIter iter; + get_iter(out iter, path); + row_inserted(path, iter); + + model.foreach((childModel, childPath, childIter) => { + Gtk.TreePath subpath = child_path_to_path(name, childPath); + Gtk.TreeIter subiter; + get_iter(out subiter, subpath); + row_inserted(subpath, subiter); + + return false; + }); + } + + public void remove_group(string name) { + int index = 0; + foreach(String group in groupModels.keys) { + if(group.data == name) { + Gee.LinkedList children = new Gee.LinkedList(); + + groupModels[group].foreach((childModel, childPath, childIter) => { + children.offer_head(childPath); + + return false; + }); + + while(!children.is_empty) { + row_deleted(child_path_to_path(name, children.poll_head())); + } + + Gtk.TreePath path = new Gtk.TreePath.from_indices(index, -1); + row_deleted(path); + + groupModels.unset(group); + + return; + } + + index++; + } + } + + private Gtk.TreePath child_path_to_path(string groupName, Gtk.TreePath childPath) { + int index = 0; + foreach(String group in groupModels.keys) { + if(group.data == groupName) { + Gtk.TreePath path = childPath.copy(); + path.prepend_index(index); + + return path; + } + + index++; + } + + assert_not_reached(); + } + + private int pointer_to_int(void* ptr) { + return (int)(long)ptr; + } + + private int child_iter_index(Gtk.TreeIter iter) { + for(int index = 0; index < childIters.size; ++index) { + if(childIters[index].stamp != iter.stamp) + continue; + if(childIters[index].user_data != iter.user_data) + continue; + if(childIters[index].user_data2 != iter.user_data2) + continue; + if(childIters[index].user_data3 != iter.user_data3) + continue; + + return index; + } + + childIters.add(iter); + return childIters.size-1; + } + + private Gtk.TreeIter get_nth_child_iter(int n) { + return childIters[n]; + } + + private Gtk.TreeIter? get_child_iter(Gtk.TreeIter iter) { + assert(iter.stamp == stamp && iter.user_data == this); + if(pointer_to_int(iter.user_data3) != -1) + return get_nth_child_iter(pointer_to_int(iter.user_data3)); + else + return null; + } + + private Gtk.TreeModel get_child_model(Gtk.TreeIter iter) { + assert(iter.stamp == stamp && iter.user_data == this); + return groupModels[iter.user_data2 as String]; + } + + public Type get_column_type(int index) { + switch(index) { + case 0: + return typeof(Object); + } + + assert_not_reached(); + } + + public Gtk.TreeModelFlags get_flags() { + return 0; + } + + public bool get_iter(out Gtk.TreeIter iter, Gtk.TreePath path) { + if(path.get_depth() == 0) + return false; + + unowned int[] indices = path.get_indices(); + int index = indices[0]; + if(index < 0 || index >= groupModels.size) + return false; + + Gee.MapIterator it = groupModels.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_key(); + iter.user_data3 = (-1).to_pointer(); + + if(path.get_depth() > 1) { + Gtk.TreePath subpath = new Gtk.TreePath(); + for(int i = 1; i < path.get_depth(); ++i) { + subpath.append_index(indices[i]); + } + + Gtk.TreeIter subiter; + + if(!it.get_value().get_iter(out subiter, subpath)) + return false; + + iter.user_data3 = child_iter_index(subiter).to_pointer(); + } + + return true; + } + + public int get_n_columns() { + return 1; + } + + public Gtk.TreePath get_path(Gtk.TreeIter iter) { + assert(iter.stamp == stamp && iter.user_data == this); + + int index = 0; + + foreach(String group in groupModels.keys) { + if(group == iter.user_data2) + break; + + ++index; + } + + Gtk.TreePath subpath = new Gtk.TreePath(); + + if(pointer_to_int(iter.user_data3) != -1) { + Gtk.TreeIter subiter = get_child_iter(iter); + subpath = get_child_model(iter).get_path(subiter); + } + subpath.prepend_index(index); + return subpath; + } + + public void get_value(Gtk.TreeIter iter, int column, out Value value) { + assert (column == 0 && iter.stamp == stamp && iter.user_data == this); + + if(pointer_to_int(iter.user_data3) == -1) { + value = Value(typeof(String)); + value.take_object(iter.user_data2 as String); + } + else { + get_child_model(iter).get_value(get_child_iter(iter), 0, out value); + } + } + + public bool iter_children(out Gtk.TreeIter iter, Gtk.TreeIter? parent) { + if (parent == null) { + return get_iter(out iter, new Gtk.TreePath.from_indices(0, -1)); + } + + assert(parent.stamp == stamp && parent.user_data == this); + + Gtk.TreeIter childIter; + if(!get_child_model(parent).iter_children(out childIter, get_child_iter(parent))) + return false; + + iter.stamp = stamp; + iter.user_data = this; + iter.user_data2 = parent.user_data2; + iter.user_data3 = child_iter_index(childIter).to_pointer(); + + return true; + } + + public bool iter_has_child(Gtk.TreeIter iter) { + assert(iter.stamp == stamp && iter.user_data == this); + + return (iter_n_children(iter) > 0); + } + + public int iter_n_children(Gtk.TreeIter? iter) { + if (iter == null) + return groupModels.size; + + assert(iter.stamp == stamp && iter.user_data == this); + + return get_child_model(iter).iter_n_children(get_child_iter(iter)); + } + + public bool iter_next(ref Gtk.TreeIter iter) { + assert(iter.stamp == stamp && iter.user_data == this); + + if(pointer_to_int(iter.user_data3) == -1) { + bool next = false; + foreach(String group in groupModels.keys) { + if(next) { + iter.user_data2 = group; + return true; + } + + if(group == iter.user_data2) + next = true; + } + + iter.stamp = -1; + return false; + } + + else { + Gtk.TreeModel m = get_child_model(iter); + Gtk.TreeIter subiter = get_child_iter(iter); + if(!m.iter_next(ref subiter)) { + iter.stamp = -1; + return false; + } + + iter.user_data3 = child_iter_index(subiter).to_pointer(); + return true; + } + } + + public bool iter_nth_child(out Gtk.TreeIter iter, Gtk.TreeIter? parent, int n) { + if (parent == null) { + return get_iter(out iter, new Gtk.TreePath.from_indices(n, -1)); + } + else { + Gtk.TreePath path = get_path(parent); + path.append_index(n); + return get_iter(out iter, path); + } + } + + public bool iter_parent(out Gtk.TreeIter iter, Gtk.TreeIter child) { + assert(child.stamp == stamp && child.user_data == this); + + if(pointer_to_int(child.user_data3) == -1) { + iter.stamp = -1; + return false; + } + + iter.stamp = stamp; + iter.user_data = this; + iter.user_data2 = child.user_data2; + + Gtk.TreeIter childParent; + if(get_child_model(child).iter_parent(out childParent, get_child_iter(child))) { + iter.user_data3 = child_iter_index(childParent).to_pointer(); + } + else { + iter.user_data3 = (-1).to_pointer(); + } + + return true; + } + + public void ref_node(Gtk.TreeIter iter) {} + public void unref_node(Gtk.TreeIter iter) {} + } + + private class ContactListModel : Object, Gtk.TreeModel { + private unowned ContactList contactList; + private int stamp = 0; + private Gee.TreeMap entries = new Gee.TreeMap(); + + + public ContactListModel(ContactList contactList0) { + contactList = contactList0; + } + + public void update_contact(Contact c) { + ++stamp; + bool added = true; + if(c.jid in entries.keys) { + added = false; + + foreach(string group in entries[c.jid].get_groups()) { + contactList.groups[group].unset(c.jid); + } + } + + entries[c.jid] = c; + + Gtk.TreeIter iter = Gtk.TreeIter(); + iter.stamp = stamp; + iter.user_data = this; + iter.user_data2 = c; + iter.user_data3 = null; + + 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 contactList.groups.keys)) { + contactList.groups[group] = new Gee.HashMap(); + } + + contactList.groups[group][c.jid] = c; + } + + contactList.update_groups(); + } + + 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); + } + + assert_not_reached(); + } + + 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 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(); + iter.user_data3 = null; + + return true; + } + + public int get_n_columns() { + return 1; + } + + public Gtk.TreePath get_path(Gtk.TreeIter iter) { + assert(iter.stamp == stamp && iter.user_data == this); + + int index = 0; + + foreach(Contact c in entries.values) { + if(c == iter.user_data2) + break; + + ++index; + } + + return new Gtk.TreePath.from_indices(index, -1); + } + + public void get_value(Gtk.TreeIter iter, int column, out Value value) { + assert (column == 0 && iter.stamp == stamp && iter.user_data == this); + + 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; + } + + 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 bool iter_next(ref Gtk.TreeIter iter) { + assert(iter.stamp == stamp && iter.user_data == this); + + bool next = false; + foreach(Contact c in entries.values) { + if(next) { + iter.user_data2 = c; + return 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; + } + + return get_iter(out iter, new Gtk.TreePath.from_indices(n, -1)); + } + + 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 string group; + + public GroupFilter(Gtk.TreeModel childModel, string group0) { + Object(child_model: childModel); + + group = group0; + + 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()); + }); + } + } + + private class ContactListFilter : Gtk.TreeModelFilter { + private unowned ContactList contactList; + + private bool show_contact(Contact c) { + return (c.get_resource_with_highest_priority() != null); + } + + public ContactListFilter(ContactList contactList0, Gtk.TreeModel childModel) { + Object(child_model: childModel); + contactList = contactList0; + + 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 show_contact(c); + } + else { + assert(value.get_object() is String); + string group = (value.get_object() as String).data; + + foreach(Gee.Map.Entry contact in contactList.get_group(group)) { + if(show_contact(contact.value)) + return true; + } + + return false; + } + }); + } + } + + private class ContactListSorter : Gtk.TreeModelSort { + public ContactListSorter(Gtk.TreeModel childModel) { + Object(model: childModel); + + set_sort_column_id(0, Gtk.SortType.ASCENDING); + set_sort_func(0, (model, itera, iterb) => { + Value value; + model.get_value(itera, 0, out value); + Object a = value.get_object(); + model.get_value(iterb, 0, out value); + Object b = value.get_object(); + + if(a is String && b is String) { + return (a as String).data.collate((b as String).data); + } + else if(a is Contact && b is Contact) { + return (a as Contact).display_string.collate((b as Contact).display_string); + } + + assert_not_reached(); + }); + } + } +} diff --git a/src/gui/Ephraim.vala b/src/gui/Ephraim.vala index b0e2571..5801966 100644 --- a/src/gui/Ephraim.vala +++ b/src/gui/Ephraim.vala @@ -20,7 +20,7 @@ public class Ephraim { Gee.TreeMap conversations = new Gee.TreeMap(); unowned Gtk.Notebook conversationNotebook = builder.get_object("Conversations") as Gtk.Notebook; - Roster roster = new Roster(rosterView); + ContactList roster = new ContactList(rosterView); CoreConnector coreconn = new CoreConnector(); diff --git a/src/gui/Roster.vala b/src/gui/Roster.vala deleted file mode 100644 index ade3161..0000000 --- a/src/gui/Roster.vala +++ /dev/null @@ -1,725 +0,0 @@ -public class Roster { - private Gtk.TreeView rosterView; - private ContactListModel contactList; - private RosterModel model; - private Gee.Map> groups = new Gee.HashMap>(); - - public signal void start_conversation(string jid); - - public Roster(Gtk.TreeView rosterView0) { - rosterView = rosterView0; - contactList = new ContactListModel(this); - model = new RosterModel(contactList); - - rosterView.set_model(new RosterFilter(this, new RosterSorter(model))); - - rosterView.query_tooltip.connect((x, y, keyboard_tip, tooltip) => { - Gtk.TreeModel model; - Gtk.TreeIter iter; - - if(!rosterView.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? 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; - }); - rosterView.has_tooltip = true; - - rosterView.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 res = contact.get_resource_with_highest_priority(); - if(res == null) - return; //FIXME - - start_conversation(contact.jid + "/" + res.key); - }); - - rosterView.model.row_has_child_toggled.connect((path, iter) => { - rosterView.expand_row(path, true); - }); - - Gtk.TreeViewColumn contactColumn = new Gtk.TreeViewColumn.with_attributes(null, new CellRendererContact(), "data", 0, null); - rosterView.append_column(contactColumn); - } - - public void update_contact(Contact c) { - contactList.update_contact(c); - } - - public Contact get_contact(string jid) { - return contactList.get_contact(jid); - } - - private void update_groups() { - foreach(Gee.Map.Entry> group in groups) { - if(group.value.is_empty) { - model.remove_group(group.key); - groups.unset(group.key); - } - else { - model.add_group(group.key); - } - } - } - - public Gee.Map get_group(string group) { - return groups[group]; - } - - private class RosterModel : Object, Gtk.TreeModel { - private int stamp = 0; - private Gee.Map groupModels = new Gee.TreeMap(); - private Gee.ArrayList childIters = new Gee.ArrayList(); - private ContactListModel contactList; - - - private void incrementStamp() { - stamp++; - childIters.clear(); - } - - public RosterModel(ContactListModel contactList0) { - contactList = contactList0; - } - - public void add_group(string name) { - int index = 0; - foreach(String group in groupModels.keys) { - if(group.data == name) { - Gtk.TreePath path = new Gtk.TreePath.from_indices(index, -1); - Gtk.TreeIter iter; - get_iter(out iter, path); - row_changed(path, iter); - - return; - } - - index++; - } - - Gtk.TreeModel model = new GroupFilter(contactList, name); - - model.row_changed.connect((subpath, subiter) => { - Gtk.TreePath path = child_path_to_path(name, subpath); - Gtk.TreeIter iter; - get_iter(out iter, path); - row_changed(path, iter); - }); - - model.row_deleted.connect((path) => { - path.prepend_index(0); - row_deleted(path); - - Gtk.TreePath parent = path.copy(); - parent.up(); - if(parent.get_depth() == 1) { - Gtk.TreeIter iter; - get_iter(out iter, parent); - if(!iter_has_child(iter)) { - row_has_child_toggled(parent, iter); - } - } - }); - - model.row_has_child_toggled.connect((subpath, subiter) => { - Gtk.TreePath path = child_path_to_path(name, subpath); - Gtk.TreeIter iter; - get_iter(out iter, path); - row_has_child_toggled(path, iter); - }); - - model.row_inserted.connect((subpath, subiter) => { - Gtk.TreePath path = child_path_to_path(name, subpath); - - incrementStamp(); - Gtk.TreeIter iter; - get_iter(out iter, path); - row_inserted(path, iter); - - Gtk.TreePath parent = path.copy(); - parent.up(); - if(parent.get_depth() == 1) { - get_iter(out iter, parent); - Value value; - get_value(iter, 0, out value); - if(iter_n_children(iter) == 0) { - row_has_child_toggled(parent, iter); - } - } - }); - - model.rows_reordered.connect((subpath, subiter, new_order) => { - Gtk.TreePath path = child_path_to_path(name, subpath); - Gtk.TreeIter iter; - get_iter(out iter, path); - rows_reordered(path, iter, new_order); - }); - - groupModels[new String(name)] = model; - - index = 0; - foreach(String group in groupModels.keys) { - if(group.data == name) - break; - - index++; - } - - Gtk.TreePath path = new Gtk.TreePath.from_indices(index, -1); - Gtk.TreeIter iter; - get_iter(out iter, path); - row_inserted(path, iter); - - model.foreach((childModel, childPath, childIter) => { - Gtk.TreePath subpath = child_path_to_path(name, childPath); - Gtk.TreeIter subiter; - get_iter(out subiter, subpath); - row_inserted(subpath, subiter); - - return false; - }); - } - - public void remove_group(string name) { - int index = 0; - foreach(String group in groupModels.keys) { - if(group.data == name) { - Gee.LinkedList children = new Gee.LinkedList(); - - groupModels[group].foreach((childModel, childPath, childIter) => { - children.offer_head(childPath); - - return false; - }); - - while(!children.is_empty) { - row_deleted(child_path_to_path(name, children.poll_head())); - } - - Gtk.TreePath path = new Gtk.TreePath.from_indices(index, -1); - row_deleted(path); - - groupModels.unset(group); - - return; - } - - index++; - } - } - - private Gtk.TreePath child_path_to_path(string groupName, Gtk.TreePath childPath) { - int index = 0; - foreach(String group in groupModels.keys) { - if(group.data == groupName) { - Gtk.TreePath path = childPath.copy(); - path.prepend_index(index); - - return path; - } - - index++; - } - - assert_not_reached(); - } - - private long child_iter_index(Gtk.TreeIter iter) { - for(int index = 0; index < childIters.size; ++index) { - if(childIters[index].stamp != iter.stamp) - continue; - if(childIters[index].user_data != iter.user_data) - continue; - if(childIters[index].user_data2 != iter.user_data2) - continue; - if(childIters[index].user_data3 != iter.user_data3) - continue; - - return index; - } - - childIters.add(iter); - return childIters.size-1; - } - - private Gtk.TreeIter get_nth_child_iter(long n) { - return childIters[(int)n]; - } - - private Gtk.TreeIter? get_child_iter(Gtk.TreeIter iter) { - assert(iter.stamp == stamp && iter.user_data == this); - if((long)iter.user_data3 != -1) - return get_nth_child_iter((long)iter.user_data3); - else - return null; - } - - private Gtk.TreeModel get_child_model(Gtk.TreeIter iter) { - assert(iter.stamp == stamp && iter.user_data == this); - return groupModels[iter.user_data2 as String]; - } - - public Type get_column_type(int index) { - switch(index) { - case 0: - return typeof(Object); - } - - assert_not_reached(); - } - - public Gtk.TreeModelFlags get_flags() { - return 0; - } - - public bool get_iter(out Gtk.TreeIter iter, Gtk.TreePath path) { - if(path.get_depth() == 0) - return false; - - unowned int[] indices = path.get_indices(); - int index = indices[0]; - if(index < 0 || index >= groupModels.size) - return false; - - Gee.MapIterator it = groupModels.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_key(); - iter.user_data3 = (void*)(-1); - - if(path.get_depth() > 1) { - Gtk.TreePath subpath = new Gtk.TreePath(); - for(int i = 1; i < path.get_depth(); ++i) { - subpath.append_index(indices[i]); - } - - Gtk.TreeIter subiter; - - if(!it.get_value().get_iter(out subiter, subpath)) - return false; - - iter.user_data3 = (void*)child_iter_index(subiter); - } - - return true; - } - - public int get_n_columns() { - return 1; - } - - public Gtk.TreePath get_path(Gtk.TreeIter iter) { - assert(iter.stamp == stamp && iter.user_data == this); - - int index = 0; - - foreach(String group in groupModels.keys) { - if(group == iter.user_data2) - break; - - ++index; - } - - Gtk.TreePath subpath = new Gtk.TreePath(); - - if((long)iter.user_data3 != -1) { - Gtk.TreeIter subiter = get_child_iter(iter); - subpath = get_child_model(iter).get_path(subiter); - } - subpath.prepend_index(index); - return subpath; - } - - public void get_value(Gtk.TreeIter iter, int column, out Value value) { - assert (column == 0 && iter.stamp == stamp && iter.user_data == this); - - if((long)iter.user_data3 == -1) { - value = Value(typeof(String)); - value.take_object(iter.user_data2 as String); - } - else { - get_child_model(iter).get_value(get_child_iter(iter), 0, out value); - } - } - - public bool iter_children(out Gtk.TreeIter iter, Gtk.TreeIter? parent) { - if (parent == null) { - return get_iter(out iter, new Gtk.TreePath.from_indices(0, -1)); - } - - assert(parent.stamp == stamp && parent.user_data == this); - - Gtk.TreeIter childIter; - if(!get_child_model(parent).iter_children(out childIter, get_child_iter(parent))) - return false; - - iter.stamp = stamp; - iter.user_data = this; - iter.user_data2 = parent.user_data2; - iter.user_data3 = (void*)child_iter_index(childIter); - - return true; - } - - public bool iter_has_child(Gtk.TreeIter iter) { - assert(iter.stamp == stamp && iter.user_data == this); - - return (iter_n_children(iter) > 0); - } - - public int iter_n_children(Gtk.TreeIter? iter) { - if (iter == null) - return groupModels.size; - - assert(iter.stamp == stamp && iter.user_data == this); - - return get_child_model(iter).iter_n_children(get_child_iter(iter)); - } - - public bool iter_next(ref Gtk.TreeIter iter) { - assert(iter.stamp == stamp && iter.user_data == this); - - if((long)iter.user_data3 == -1) { - bool next = false; - foreach(String group in groupModels.keys) { - if(next) { - iter.user_data2 = group; - return true; - } - - if(group == iter.user_data2) - next = true; - } - - iter.stamp = -1; - return false; - } - - else { - Gtk.TreeModel m = get_child_model(iter); - Gtk.TreeIter subiter = get_child_iter(iter); - if(!m.iter_next(ref subiter)) { - iter.stamp = -1; - return false; - } - - iter.user_data3 = (void*)child_iter_index(subiter); - return true; - } - } - - public bool iter_nth_child(out Gtk.TreeIter iter, Gtk.TreeIter? parent, int n) { - if (parent == null) { - return get_iter(out iter, new Gtk.TreePath.from_indices(n, -1)); - } - else { - Gtk.TreePath path = get_path(parent); - path.append_index(n); - return get_iter(out iter, path); - } - } - - public bool iter_parent(out Gtk.TreeIter iter, Gtk.TreeIter child) { - assert(child.stamp == stamp && child.user_data == this); - - if((long)child.user_data3 == -1) { - iter.stamp = -1; - return false; - } - - iter.stamp = stamp; - iter.user_data = this; - iter.user_data2 = child.user_data2; - - Gtk.TreeIter childParent; - if(get_child_model(child).iter_parent(out childParent, get_child_iter(child))) { - iter.user_data3 = (void*)child_iter_index(childParent); - } - else { - iter.user_data3 = (void*)(-1); - } - - return true; - } - - public void ref_node(Gtk.TreeIter iter) {} - public void unref_node(Gtk.TreeIter iter) {} - } - - private class ContactListModel : Object, Gtk.TreeModel { - private unowned Roster roster; - private int stamp = 0; - private Gee.TreeMap entries = new Gee.TreeMap(); - - - public ContactListModel(Roster roster0) { - roster = roster0; - } - - public void update_contact(Contact c) { - ++stamp; - bool added = true; - if(c.jid in entries.keys) { - added = false; - - foreach(string group in entries[c.jid].get_groups()) { - roster.groups[group].unset(c.jid); - } - } - - entries[c.jid] = c; - - Gtk.TreeIter iter = Gtk.TreeIter(); - iter.stamp = stamp; - iter.user_data = this; - iter.user_data2 = c; - iter.user_data3 = null; - - 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.keys)) { - roster.groups[group] = new Gee.HashMap(); - } - - roster.groups[group][c.jid] = c; - } - - roster.update_groups(); - } - - 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); - } - - assert_not_reached(); - } - - 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 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(); - iter.user_data3 = null; - - return true; - } - - public int get_n_columns() { - return 1; - } - - public Gtk.TreePath get_path(Gtk.TreeIter iter) { - assert(iter.stamp == stamp && iter.user_data == this); - - int index = 0; - - foreach(Contact c in entries.values) { - if(c == iter.user_data2) - break; - - ++index; - } - - return new Gtk.TreePath.from_indices(index, -1); - } - - public void get_value(Gtk.TreeIter iter, int column, out Value value) { - assert (column == 0 && iter.stamp == stamp && iter.user_data == this); - - 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; - } - - 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 bool iter_next(ref Gtk.TreeIter iter) { - assert(iter.stamp == stamp && iter.user_data == this); - - bool next = false; - foreach(Contact c in entries.values) { - if(next) { - iter.user_data2 = c; - return 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; - } - - return get_iter(out iter, new Gtk.TreePath.from_indices(n, -1)); - } - - 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 string group; - - public GroupFilter(Gtk.TreeModel childModel, string group0) { - Object(child_model: childModel); - - group = group0; - - 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()); - }); - } - } - - private class RosterFilter : Gtk.TreeModelFilter { - private unowned Roster roster; - - private bool show_contact(Contact c) { - return (c.get_resource_with_highest_priority() != null); - } - - public RosterFilter(Roster roster0, Gtk.TreeModel childModel) { - Object(child_model: childModel); - roster = roster0; - - 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 show_contact(c); - } - else { - assert(value.get_object() is String); - string group = (value.get_object() as String).data; - - foreach(Gee.Map.Entry contact in roster.get_group(group)) { - if(show_contact(contact.value)) - return true; - } - - return false; - } - }); - } - } - - private class RosterSorter : Gtk.TreeModelSort { - public RosterSorter(Gtk.TreeModel childModel) { - Object(model: childModel); - - set_sort_column_id(0, Gtk.SortType.ASCENDING); - set_sort_func(0, (model, itera, iterb) => { - Value value; - model.get_value(itera, 0, out value); - Object a = value.get_object(); - model.get_value(iterb, 0, out value); - Object b = value.get_object(); - - if(a is String && b is String) { - return (a as String).data.collate((b as String).data); - } - else if(a is Contact && b is Contact) { - return (a as Contact).display_string.collate((b as Contact).display_string); - } - - assert_not_reached(); - }); - } - } -} -- cgit v1.2.3