[gnome-shell-extensions] workspace-indicator: Bind list to model



commit f91275ffd2a6ee9dc200d5ba7b868269e5ed3688
Author: Florian Müllner <fmuellner gnome org>
Date:   Sun Feb 13 07:09:33 2022 +0100

    workspace-indicator: Bind list to model
    
    Using a model gives us a clear separation between data and representation,
    as well as between regular rows and the "new item" row at the end.
    
    Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/218>

 extensions/workspace-indicator/prefs.js | 162 ++++++++++++++++++++++----------
 1 file changed, 112 insertions(+), 50 deletions(-)
---
diff --git a/extensions/workspace-indicator/prefs.js b/extensions/workspace-indicator/prefs.js
index b0dfca8..5a1da46 100644
--- a/extensions/workspace-indicator/prefs.js
+++ b/extensions/workspace-indicator/prefs.js
@@ -11,80 +11,142 @@ const N_ = e => e;
 const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences';
 const WORKSPACE_KEY = 'workspace-names';
 
-class WorkspaceSettingsWidget extends Adw.PreferencesGroup {
+class NewItem extends GObject.Object {}
+GObject.registerClass(NewItem);
+
+class NewItemModel extends GObject.Object {
+    static [GObject.interfaces] = [Gio.ListModel];
     static {
         GObject.registerClass(this);
+    }
 
-        this.install_action('workspaces.add', null,
-            self => self._addNewName());
-        this.install_action('workspaces.remove', 's',
-            (self, name, param) => self._removeName(param.unpack()));
-        this.install_action('workspaces.rename', '(ss)',
-            (self, name, param) => self._changeName(...param.deepUnpack()));
+    #item = new NewItem();
+
+    vfunc_get_item_type() {
+        return NewItem;
     }
 
-    constructor() {
-        super({
-            title: _('Workspace Names'),
-        });
+    vfunc_get_n_items() {
+        return 1;
+    }
 
-        this._list = new Gtk.ListBox({
-            selection_mode: Gtk.SelectionMode.NONE,
-            css_classes: ['boxed-list'],
-        });
-        this._list.connect('row-activated', (l, row) => row.edit());
-        this.add(this._list);
+    vfunc_get_item(_pos) {
+        return this.#item;
+    }
+}
 
-        this._list.append(new NewWorkspaceRow());
+class WorkspacesList extends GObject.Object {
+    static [GObject.interfaces] = [Gio.ListModel];
+    static {
+        GObject.registerClass(this);
+    }
 
-        this._settings = new Gio.Settings({
-            schema_id: WORKSPACE_SCHEMA,
-        });
-        this._settings.connect(`changed::${WORKSPACE_KEY}`,
-            this._sync.bind(this));
-        this._sync();
+    #settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA });
+    #names = this.#settings.get_strv(WORKSPACE_KEY);
+    #items = Gtk.StringList.new(this.#names);
+    #changedId;
+
+    constructor() {
+        super();
+
+        this.#changedId =
+            this.#settings.connect(`changed::${WORKSPACE_KEY}`, () => {
+                const removed = this.#names.length;
+                this.#names = this.#settings.get_strv(WORKSPACE_KEY);
+                this.#items.splice(0, removed, this.#names);
+                this.items_changed(0, removed, this.#names.length);
+            });
     }
 
-    _addNewName() {
-        const names = this._settings.get_strv(WORKSPACE_KEY);
-        this._settings.set_strv(WORKSPACE_KEY, [
-            ...names,
-            _('Workspace %d').format(names.length + 1),
-        ]);
+    append() {
+        const name = _('Workspace %d').format(this.#names.length + 1);
+
+        this.#names.push(name);
+        this.#settings.block_signal_handler(this.#changedId);
+        this.#settings.set_strv(WORKSPACE_KEY, this.#names);
+        this.#settings.unblock_signal_handler(this.#changedId);
+
+        const pos = this.#items.get_n_items();
+        this.#items.append(name);
+        this.items_changed(pos, 0, 1);
     }
 
-    _removeName(removedName) {
-        this._settings.set_strv(WORKSPACE_KEY,
-            this._settings.get_strv(WORKSPACE_KEY)
-                .filter(name => name !== removedName));
+    remove(name) {
+        const pos = this.#names.indexOf(name);
+        if (pos < 0)
+            return;
+
+        this.#names.splice(pos, 1);
+
+        this.#settings.block_signal_handler(this.#changedId);
+        this.#settings.set_strv(WORKSPACE_KEY, this.#names);
+        this.#settings.unblock_signal_handler(this.#changedId);
+
+        this.#items.remove(pos);
+        this.items_changed(pos, 1, 0);
     }
 
-    _changeName(oldName, newName) {
-        const names = this._settings.get_strv(WORKSPACE_KEY);
-        const pos = names.indexOf(oldName);
+    rename(oldName, newName) {
+        const pos = this.#names.indexOf(oldName);
         if (pos < 0)
             return;
 
-        names.splice(pos, 1, newName);
-        this._settings.set_strv(WORKSPACE_KEY, names);
+        this.#names.splice(pos, 1, newName);
+        this.#items.splice(pos, 1, [newName]);
+
+        this.#settings.block_signal_handler(this.#changedId);
+        this.#settings.set_strv(WORKSPACE_KEY, this.#names);
+        this.#settings.unblock_signal_handler(this.#changedId);
     }
 
-    _getWorkspaceRows() {
-        return [...this._list].filter(row => row.name);
+    vfunc_get_item_type() {
+        return Gtk.StringObject;
     }
 
-    _sync() {
-        const rows = this._getWorkspaceRows();
+    vfunc_get_n_items() {
+        return this.#items.get_n_items();
+    }
 
-        const oldNames = rows.map(row => row.name);
-        const newNames = this._settings.get_strv(WORKSPACE_KEY);
+    vfunc_get_item(pos) {
+        return this.#items.get_item(pos);
+    }
+}
 
-        const removed = oldNames.filter(n => !newNames.includes(n));
-        const added = newNames.filter(n => !oldNames.includes(n));
+class WorkspaceSettingsWidget extends Adw.PreferencesGroup {
+    static {
+        GObject.registerClass(this);
+
+        this.install_action('workspaces.add', null,
+            self => self._workspaces.append());
+        this.install_action('workspaces.remove', 's',
+            (self, name, param) => self._workspaces.remove(param.unpack()));
+        this.install_action('workspaces.rename', '(ss)',
+            (self, name, param) => self._workspaces.rename(...param.deepUnpack()));
+    }
+
+    constructor() {
+        super({
+            title: _('Workspace Names'),
+        });
+
+        this._workspaces = new WorkspacesList();
+
+        const store = new Gio.ListStore({ item_type: Gio.ListModel });
+        const listModel = new Gtk.FlattenListModel({ model: store });
+        store.append(this._workspaces);
+        store.append(new NewItemModel());
+
+        this._list = new Gtk.ListBox({
+            selection_mode: Gtk.SelectionMode.NONE,
+            css_classes: ['boxed-list'],
+        });
+        this._list.connect('row-activated', (l, row) => row.edit());
+        this.add(this._list);
 
-        removed.forEach(n => this._list.remove(rows.find(r => r.name === n)));
-        added.forEach(n => {
-            this._list.insert(new WorkspaceRow(n), newNames.indexOf(n));
+        this._list.bind_model(listModel, item => {
+            return item instanceof NewItem
+                ? new NewWorkspaceRow()
+                : new WorkspaceRow(item.string);
         });
     }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]