[gnome-contacts/nielsdg/filters-and-sorters: 2/4] Add a GtkFilter and GtkSorter for Personas
- From: Niels De Graef <nielsdg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-contacts/nielsdg/filters-and-sorters: 2/4] Add a GtkFilter and GtkSorter for Personas
- Date: Tue, 16 Aug 2022 23:26:11 +0000 (UTC)
commit 83aa3cebdcdc22591fd4c693630ce2cf6bd525a5
Author: Niels De Graef <nielsdegraef gmail com>
Date: Wed Aug 17 00:31:07 2022 +0200
Add a GtkFilter and GtkSorter for Personas
This allows us to split off the logic for filtering and sorting personas
from the generic `Utils` namespace, and allows us to expand on our
GListModel usage, which allows for some bigger cleanups planned ahead.
src/contacts-contact-sheet.vala | 14 ++---
src/contacts-linked-personas-dialog.vala | 87 +++++++++++++++++---------------
src/contacts-persona-filter.vala | 52 +++++++++++++++++++
src/contacts-persona-sorter.vala | 57 +++++++++++++++++++++
src/contacts-utils.vala | 38 ++------------
src/meson.build | 2 +
6 files changed, 170 insertions(+), 80 deletions(-)
---
diff --git a/src/contacts-contact-sheet.vala b/src/contacts-contact-sheet.vala
index b6e71bb5..1b0eecff 100644
--- a/src/contacts-contact-sheet.vala
+++ b/src/contacts-contact-sheet.vala
@@ -133,19 +133,21 @@ public class Contacts.ContactSheet : Gtk.Grid {
this.last_row++;
- var personas = Utils.get_personas_for_display (this.individual);
- /* Cause personas are sorted properly I can do this */
- for (int i = 0; i < personas.get_n_items (); i++) {
- var p = (Persona) personas.get_item (i);
+ var personas = Utils.personas_as_list_model (individual);
+ var personas_filtered = new Gtk.FilterListModel (personas, new PersonaFilter ());
+ var personas_sorted = new Gtk.SortListModel (personas_filtered, new PersonaSorter ());
+
+ for (int i = 0; i < personas_sorted.get_n_items (); i++) {
+ var persona = (Persona) personas_sorted.get_item (i);
int persona_store_pos = this.last_row;
if (i > 0) {
- this.attach (create_persona_store_label (p), 0, this.last_row, 3);
+ this.attach (create_persona_store_label (persona), 0, this.last_row, 3);
this.last_row++;
}
foreach (unowned var prop in SORTED_PROPERTIES)
- add_row_for_property (p, prop);
+ add_row_for_property (persona, prop);
// Nothing to show in the persona: don't mention it
bool is_empty_persona = (this.last_row == persona_store_pos + 1);
diff --git a/src/contacts-linked-personas-dialog.vala b/src/contacts-linked-personas-dialog.vala
index b66e94ce..7d870951 100644
--- a/src/contacts-linked-personas-dialog.vala
+++ b/src/contacts-linked-personas-dialog.vala
@@ -39,46 +39,51 @@ public class Contacts.LinkedPersonasDialog : Gtk.Dialog {
this.linked_accounts_view.set_header_func (add_separator);
// loading personas for display
- var personas = Contacts.Utils.get_personas_for_display (individual);
- for (int i = 1; i < personas.get_n_items (); i++) {
- var p = (Persona) personas.get_item (i);
- var row_grid = new Gtk.Grid ();
-
- var image_frame = new Avatar (AVATAR_SIZE, individual);
- image_frame.set_hexpand (false);
- image_frame.margin_top = 6;
- image_frame.margin_bottom = 6;
- image_frame.margin_start = 6;
- image_frame.margin_end = 12;
- row_grid.attach (image_frame, 0, 0, 1, 2);
-
- var display_name = new Gtk.Label ("");
- display_name.set_halign (Gtk.Align.START);
- display_name.set_valign (Gtk.Align.END);
- display_name.set_hexpand (true);
- display_name.set_markup (Markup.printf_escaped ("<span font='bold'>%s</span>", p.display_id));
-
- row_grid.attach (display_name, 1, 0, 1, 1);
-
- var store_name = new Gtk.Label (Contacts.Utils.format_persona_store_name_for_contact (p));
- store_name.set_halign (Gtk.Align.START);
- store_name.set_valign (Gtk.Align.START);
- store_name.set_hexpand (true);
- store_name.get_style_context ().add_class ("dim-label");
- row_grid.attach (store_name, 1, 1, 1, 1);
-
- var button = new Gtk.Button.with_label (_("Unlink"));
- button.margin_end = 6;
- button.set_valign (Gtk.Align.CENTER);
- // button.get_child ().margin = 1; XXX
- row_grid.attach (button, 2, 0, 1, 2);
-
- /* signal */
- button.clicked.connect (() => {
- // TODO: handly unlinking
- });
-
- this.linked_accounts_view.append (row_grid);
- }
+ var personas = Utils.personas_as_list_model (individual);
+ var personas_filtered = new Gtk.FilterListModel (personas, new PersonaFilter ());
+ var personas_sorted = new Gtk.SortListModel (personas_filtered, new PersonaSorter ());
+ this.linked_accounts_view.bind_model (personas_sorted, create_row_for_persona);
+ }
+
+ private Gtk.Widget create_row_for_persona (GLib.Object item) {
+ unowned var persona = (Persona) item;
+
+ var row_grid = new Gtk.Grid ();
+
+ var image_frame = new Avatar (AVATAR_SIZE, individual);
+ image_frame.set_hexpand (false);
+ image_frame.margin_top = 6;
+ image_frame.margin_bottom = 6;
+ image_frame.margin_start = 6;
+ image_frame.margin_end = 12;
+ row_grid.attach (image_frame, 0, 0, 1, 2);
+
+ var display_name = new Gtk.Label ("");
+ display_name.set_halign (Gtk.Align.START);
+ display_name.set_valign (Gtk.Align.END);
+ display_name.set_hexpand (true);
+ display_name.set_markup (Markup.printf_escaped ("<span font='bold'>%s</span>", persona.display_id));
+
+ row_grid.attach (display_name, 1, 0, 1, 1);
+
+ var store_name = new Gtk.Label (Contacts.Utils.format_persona_store_name_for_contact (persona));
+ store_name.set_halign (Gtk.Align.START);
+ store_name.set_valign (Gtk.Align.START);
+ store_name.set_hexpand (true);
+ store_name.get_style_context ().add_class ("dim-label");
+ row_grid.attach (store_name, 1, 1, 1, 1);
+
+ var button = new Gtk.Button.with_label (_("Unlink"));
+ button.margin_end = 6;
+ button.set_valign (Gtk.Align.CENTER);
+ // button.get_child ().margin = 1; XXX
+ row_grid.attach (button, 2, 0, 1, 2);
+
+ /* signal */
+ button.clicked.connect (() => {
+ // TODO: handly unlinking
+ });
+
+ return row_grid;
}
}
diff --git a/src/contacts-persona-filter.vala b/src/contacts-persona-filter.vala
new file mode 100644
index 00000000..fa5cb4b5
--- /dev/null
+++ b/src/contacts-persona-filter.vala
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 Niels De Graef <nielsdegraef gmail com>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+/**
+ * A custom GtkFilter to filter out {@link Folks.Persona}s, for example to
+ * exclude certain types of persona stores.
+ */
+public class Contacts.PersonaFilter : Gtk.Filter {
+
+ public string[] ignored_store_types {
+ get { return this._ignored_store_types; }
+ set {
+ if (value == null && this.ignored_store_types == null)
+ return;
+ if (GLib.strv_equal (this._ignored_store_types, value))
+ return;
+ // notify ignored-store-types
+ }
+ }
+ private string[] _ignored_store_types = { "key-file", };
+
+ public override bool match (GLib.Object? item) {
+ unowned var persona = item as Persona;
+ return_val_if_fail (persona != null, false);
+
+ return match_persona_store_type (persona);
+ }
+
+ private bool match_persona_store_type (Persona persona) {
+ return !(persona.store.type_id in this.ignored_store_types);
+ }
+
+ public override Gtk.FilterMatch get_strictness () {
+ return Gtk.FilterMatch.SOME;
+ }
+}
diff --git a/src/contacts-persona-sorter.vala b/src/contacts-persona-sorter.vala
new file mode 100644
index 00000000..4ba40060
--- /dev/null
+++ b/src/contacts-persona-sorter.vala
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 Niels De Graef <nielsdegraef gmail com>
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Folks;
+
+/**
+ * A customer sorter that provides a consistent way of sorting
+ * {@link Folks.Persona}s within the whole application.
+ */
+public class Contacts.PersonaSorter : Gtk.Sorter {
+
+ public override Gtk.SorterOrder get_order () {
+ return Gtk.SorterOrder.PARTIAL;
+ }
+
+ public override Gtk.Ordering compare (Object? item1, Object? item2) {
+ unowned var persona_1 = (Persona) item1;
+ unowned var persona_2 = (Persona) item2;
+ unowned var store_1 = persona_1.store;
+ unowned var store_2 = persona_2.store;
+
+ // In the same store, sort Google 'other' contacts last
+ if (store_1 == store_2) {
+ if (!Utils.persona_is_google (persona_1))
+ return Gtk.Ordering.EQUAL;
+
+ var p1_is_other = Utils.persona_is_google_other (persona_1);
+ if (p1_is_other != Utils.persona_is_google_other (persona_2))
+ return p1_is_other? Gtk.Ordering.LARGER : Gtk.Ordering.SMALLER;
+ }
+
+ // Sort primary stores before others
+ if (store_1.is_primary_store != store_2.is_primary_store)
+ return (store_1.is_primary_store)? Gtk.Ordering.SMALLER : Gtk.Ordering.LARGER;
+
+ // E-D-S stores get prioritized
+ if ((store_1.type_id == "eds") != (store_2.type_id == "eds"))
+ return (store_1.type_id == "eds")? Gtk.Ordering.SMALLER : Gtk.Ordering.LARGER;
+
+ // Normal case: use alphabetical sorting
+ return Gtk.Ordering.from_cmpfunc (strcmp (store_1.id, store_2.id));
+ }
+}
diff --git a/src/contacts-utils.vala b/src/contacts-utils.vala
index 012b8db3..ad828335 100644
--- a/src/contacts-utils.vala
+++ b/src/contacts-utils.vala
@@ -264,39 +264,11 @@ namespace Contacts.Utils {
return false;
}
- public ListModel get_personas_for_display (Individual individual) {
- var persona_list = new ListStore(typeof(Persona));
+ public ListModel personas_as_list_model (Individual individual) {
+ var personas = new ListStore (typeof(Persona));
foreach (var persona in individual.personas)
- if (persona.store.type_id != "key-file")
- persona_list.append (persona);
-
- persona_list.sort ((a, b) => {
- unowned var store_a = ((Persona) a).store;
- unowned var store_b = ((Persona) b).store;
-
- // In the same store, sort Google 'other' contacts last
- if (store_a == store_b) {
- if (!persona_is_google ((Persona) a))
- return 0;
-
- var a_is_other = persona_is_google_other ((Persona) a);
- if (a_is_other != persona_is_google_other ((Persona) b))
- return a_is_other? 1 : -1;
- }
-
- // Sort primary stores before others
- if (store_a.is_primary_store != store_b.is_primary_store)
- return (store_a.is_primary_store)? -1 : 1;
-
- // E-D-S stores get prioritized
- if ((store_a.type_id == "eds") != (store_b.type_id == "eds"))
- return (store_a.type_id == "eds")? -1 : 1;
-
- // Normal case: use alphabetical sorting
- return strcmp (store_a.id, store_b.id);
- });
-
- return persona_list;
+ personas.append (persona);
+ return personas;
}
public Persona? find_primary_persona (Individual individual) {
@@ -365,7 +337,7 @@ namespace Contacts.Utils {
return all_unlinkable;
}
- private bool persona_is_google (Persona persona) {
+ public bool persona_is_google (Persona persona) {
return persona.store.type_id == "eds" && esource_uid_is_google (persona.store.id);
}
diff --git a/src/meson.build b/src/meson.build
index 0710d4a9..96d455f3 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -17,6 +17,8 @@ libcontacts_sources = files(
'contacts-link-operation.vala',
'contacts-operation.vala',
'contacts-operation-list.vala',
+ 'contacts-persona-filter.vala',
+ 'contacts-persona-sorter.vala',
'contacts-query-filter.vala',
'contacts-store.vala',
'contacts-typeset.vala',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]