[polari/wip/fmuellner/room-list: 21/23] serverRoomManager: Use a treeview instead of listbox
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [polari/wip/fmuellner/room-list: 21/23] serverRoomManager: Use a treeview instead of listbox
- Date: Wed, 15 Feb 2017 22:17:36 +0000 (UTC)
commit 8ad6ecd4457712bc1a7a0336e7e6833cce4b4ab6
Author: Florian Müllner <fmuellner gnome org>
Date: Mon Nov 28 19:03:52 2016 +0100
serverRoomManager: Use a treeview instead of listbox
For potentially large lists, a treeview is significantly more performant
than a listbox with many composite row widgets. As the ServerRoomList
doesn't require anything that cannot be achieved with a treeview, drop
the listbox for a nice performance gain.
https://bugzilla.gnome.org/show_bug.cgi?id=763200
data/resources/application.css | 4 +
src/serverRoomManager.js | 177 +++++++++++++++++++++------------------
2 files changed, 99 insertions(+), 82 deletions(-)
---
diff --git a/data/resources/application.css b/data/resources/application.css
index cbdb332..ab94219 100644
--- a/data/resources/application.css
+++ b/data/resources/application.css
@@ -92,6 +92,10 @@
background-color: mix(@theme_unfocused_selected_bg_color, @theme_unfocused_selected_fg_color, 0.1);
}
+treeview.polari-server-room-list {
+ padding: 6px 12px;
+}
+
.irc-feedback {
color: @theme_fg_color;
background-color: @theme_bg_color;
diff --git a/src/serverRoomManager.js b/src/serverRoomManager.js
index 9420d8b..145cc1b 100644
--- a/src/serverRoomManager.js
+++ b/src/serverRoomManager.js
@@ -1,6 +1,7 @@
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
+const Pango = imports.gi.Pango;
const Tp = imports.gi.TelepathyGLib;
const AccountsMonitor = imports.accountsMonitor;
@@ -97,6 +98,15 @@ const _ServerRoomManager = new Lang.Class({
});
Signals.addSignalMethods(_ServerRoomManager.prototype);
+
+const RoomListColumn = {
+ CHECKED: 0,
+ NAME: 1,
+ COUNT: 2,
+
+ SENSITIVE: 3,
+};
+
const ServerRoomList = new Lang.Class({
Name: 'ServerRoomList',
Extends: Gtk.ScrolledWindow,
@@ -122,19 +132,62 @@ const ServerRoomList = new Lang.Class({
this.setAccount(null);
});
- this._list = new Gtk.ListBox({ visible: true });
- this._list.set_header_func(Lang.bind(this, this._updateHeader));
- this._list.connect('row-activated',
- Lang.bind(this, this._onRowActivated));
+ let store = new Gtk.ListStore();
+ store.set_column_types([GObject.TYPE_BOOLEAN,
+ GObject.TYPE_STRING,
+ GObject.TYPE_STRING,
+ GObject.TYPE_BOOLEAN]);
+
+ this._list = new Gtk.TreeView({ model: store,
+ activate_on_single_click: true,
+ enable_grid_lines: Gtk.TreeViewGridLines.HORIZONTAL,
+ headers_visible: false,
+ visible: true });
+ this._list.get_style_context().add_class('polari-server-room-list');
+ this._list.connect('row-activated', (view, path, column) => {
+ this._toggleChecked(path);
+ });
this.add(this._list);
+ let renderer;
+
+ let column = new Gtk.TreeViewColumn();
+ this._list.append_column(column);
+
+ renderer = new Gtk.CellRendererToggle();
+ renderer.connect('toggled', (cell, pathStr) => {
+ this._toggleChecked(Gtk.TreePath.new_from_string(pathString));
+ });
+
+ column.pack_start(renderer, false);
+ column.add_attribute(renderer, 'active', RoomListColumn.CHECKED);
+ column.add_attribute(renderer, 'sensitive', RoomListColumn.SENSITIVE);
+
+ renderer = new Gtk.CellRendererText({ ellipsize: Pango.EllipsizeMode.END });
+
+ column.pack_start(renderer, true);
+ column.add_attribute(renderer, 'text', RoomListColumn.NAME);
+ column.add_attribute(renderer, 'sensitive', RoomListColumn.SENSITIVE);
+
+ renderer = new Gtk.CellRendererText();
+
+ column.pack_start(renderer, false);
+ column.add_attribute(renderer, 'text', RoomListColumn.COUNT);
+ column.add_attribute(renderer, 'sensitive', RoomListColumn.SENSITIVE);
+
this._manager = getDefault();
this._manager.connect('loading-changed',
Lang.bind(this, this._onLoadingChanged));
},
get can_join() {
- return this._list.get_children().some(r => r.sensitive && r.checked);
+ let canJoin = false;
+ this._list.model.foreach((model, path, iter) => {
+ canJoin = model.get_value(iter, RoomListColumn.SENSITIVE) &&
+ model.get_value(iter, RoomListColumn.CHECKED);
+ return canJoin;
+ });
+ return canJoin;
},
get loading() {
@@ -142,13 +195,16 @@ const ServerRoomList = new Lang.Class({
(this._account && this._manager.isLoading(this._account));
},
- _onRowActivated: function(list, row) {
- row.activate();
- },
-
get selectedRooms() {
- let selectedRows = this._list.get_children().filter(r => r.checked);
- return selectedRows.map(r => r.info.get_name());
+ let rooms = [];
+ let [valid, iter] = this._list.model.get_iter_first();
+ for (; valid; valid = this._list.model.iter_next(iter)) {
+ if (!this._list.model.get_value(iter, RoomListColumn.SENSITIVE) ||
+ !this._list.model.get_value(iter, RoomListColumn.CHECKED))
+ continue;
+ rooms.push(this._list.model.get_value(iter, RoomListColumn.NAME));
+ }
+ return rooms;
},
setAccount: function(account) {
@@ -157,17 +213,10 @@ const ServerRoomList = new Lang.Class({
this._account = account;
this._pendingInfos = [];
- this._list.foreach(function(w) { w.destroy(); });
+ this._list.model.clear();
this._onLoadingChanged(this._manager, account);
},
- _updateHeader: function(row, before) {
- if (!before)
- row.set_header(null);
- else if (!row.get_header())
- row.set_header(new Gtk.Separator());
- },
-
_onLoadingChanged: function(mgr, account) {
if (account != this._account)
return;
@@ -177,7 +226,7 @@ const ServerRoomList = new Lang.Class({
if (this.loading)
return;
- this._list.foreach(function(w) { w.destroy(); });
+ this._list.model.clear();
if (this._idleId)
Mainloop.source_remove(this._idleId);
@@ -197,11 +246,27 @@ const ServerRoomList = new Lang.Class({
this.notify('loading');
+ let roomManager = RoomManager.getDefault();
+
this._idleId = Mainloop.idle_add(() => {
this._pendingInfos.splice(0, LIST_CHUNK_SIZE).forEach(roomInfo => {
- let row = new ServerRoomRow({ info: roomInfo });
- row.connect('notify::checked', () => { this.notify('can-join'); });
- this._list.add(row);
+ let store = this._list.model;
+
+ let name = roomInfo.get_name();
+ if (name[0] == '#')
+ name = name.substr(1, name.length);
+
+ let room = roomManager.lookupRoomByName(roomInfo.get_name());
+ let sensitive = room == null;
+ let checked = !sensitive;
+ let count = '%d'.format(roomInfo.get_members_count(null));
+
+ store.insert_with_valuesv(-1,
+ [RoomListColumn.CHECKED,
+ RoomListColumn.NAME,
+ RoomListColumn.COUNT,
+ RoomListColumn.SENSITIVE],
+ [checked, name, count, sensitive]);
});
if (this._pendingInfos.length)
return GLib.SOURCE_CONTINUE;
@@ -210,67 +275,15 @@ const ServerRoomList = new Lang.Class({
this.notify('loading');
return GLib.SOURCE_REMOVE;
});
- }
-});
-
-const ServerRoomRow = new Lang.Class({
- Name: 'ServerRoomRow',
- Extends: Gtk.ListBoxRow,
- Properties: { 'checked': GObject.ParamSpec.boolean('checked',
- 'checked',
- 'checked',
- GObject.ParamFlags.READABLE,
- false),
- },
-
- _init: function(params) {
- if (!params || !params.info)
- throw new Error('No info in parameters');
-
- this._info = params.info;
- delete params.info;
-
- this.parent(params);
-
- let room = RoomManager.getDefault().lookupRoomByName(this._info.get_name());
- this.sensitive = !room;
-
- let name = this._info.get_name();
- if (name[0] == '#')
- name = name.substr(1, name.length);
-
- let box = new Gtk.Box({ spacing: 12, margin: 12 });
- this.add(box);
-
- this._checkbox = new Gtk.CheckButton({ active: !this.sensitive });
- this._checkbox.connect('toggled', Lang.bind(this,
- function() {
- this.notify('checked');
- }));
-
- box.add(this._checkbox);
-
- box.add(new Gtk.Label({ label: name,
- hexpand: true,
- halign: Gtk.Align.START }));
-
- let count = this._info.get_members_count(null);
- let label = new Gtk.Label({ label: "%d".format(count) });
- label.get_style_context().add_class('dim-label');
- box.add(label);
-
- this.show_all();
- },
-
- get info() {
- return this._info;
},
- get checked() {
- return this._checkbox.active;
- },
+ _toggleChecked: function(path) {
+ let [valid, iter] = this._list.model.get_iter(path);
+ if (!this._list.model.get_value(iter, RoomListColumn.SENSITIVE))
+ return;
+ let checked = this._list.model.get_value(iter, RoomListColumn.CHECKED);
+ this._list.model.set_value(iter, RoomListColumn.CHECKED, !checked);
- vfunc_activate: function() {
- this._checkbox.activate();
+ this.notify('can-join');
}
});
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]