There are few examples on creating Treeviews in Gtk4. I have managed to create the Treeview below in JavaScript with one nesting level. The problem is in the filtering. I don’t want to filter out those items with nested items. And the nested items are not being filtered in the code below.
The basic code is here. How do I implement the above feature in this example.
#! usr/bin/env/gjs -m gjs
import Gtk from "gi://Gtk?version=4.0";
import GLib from "gi://GLib";
import GObject from "gi://GObject";
import Gio from "gi://Gio";
Gtk.init();
const options = {
GtypeName: "MyObject",
Properties: {
string: GObject.ParamSpec.string(
"string",
"String",
"A string",
GObject.ParamFlags.READWRITE,
"0"
),
hasChildren: GObject.ParamSpec.boolean(
"hasChildren",
"Whether object has children",
"Whether object has children",
GObject.ParamFlags.READWRITE,
0
),
},
Signals: {},
};
const MyObject = GObject.registerClass(
options,
class MyString extends GObject.Object {
constructor(string = "", hasChildren = false) {
super();
this.string = string;
this.hasChildren = hasChildren;
}
}
);
const loop = GLib.MainLoop.new(null, false);
const store = Gio.ListStore.new(MyObject);
for (let i = 0; i < 20; i++) {
store.append(new MyObject(i.toString(), i % 2 ? false : true));
}
const propertyExpression = Gtk.PropertyExpression.new(MyObject, null, "string");
const stringFilter = Gtk.StringFilter.new(propertyExpression);
const filter = Gtk.FilterListModel.new(store, stringFilter);
const tree = Gtk.TreeListModel.new(filter, false, false, (item) => {
if (item.hasChildren) {
const nestedModel = Gio.ListStore.new(MyObject);
for (const letter of "aei") {
nestedModel.append(new MyObject(letter));
}
return nestedModel;
}
return null;
});
const selection = Gtk.SingleSelection.new(tree);
const factory = new Gtk.SignalListItemFactory();
factory.connect("setup", (_, listItem) => {
listItem.child = new Gtk.TreeExpander({
child: new Gtk.Label(),
indent_for_icon: true,
});
});
factory.connect("bind", (_, listItem) => {
const listRow = listItem.item;
const expander = listItem.child;
expander.list_row = listRow;
const label = expander.child;
const object = listRow.item;
label.label = object.string;
});
const listView = new Gtk.ListView({
model: selection,
factory,
show_separators: false,
});
const scrolledWin = new Gtk.ScrolledWindow({
child: listView,
min_content_width: 300,
min_content_height: 300,
});
const win = new Gtk.Window({
defaultWidth: 600,
defaultHeight: 550,
title: "Tree View",
});
const vBox = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
halign: Gtk.Align.CENTER,
valign: Gtk.Align.CENTER,
spacing: 18,
margin_top: 18,
margin_bottom: 18,
margin_start: 18,
margin_end: 18,
});
const entry = new Gtk.Entry({
primary_icon_name: "edit-find-symbolic",
placeholder_text: "Search",
});
entry.buffer.connect("notify::length", (buffer) => {
const text = buffer.get_text();
console.log(text);
stringFilter.set_search(text);
});
vBox.append(entry);
vBox.append(scrolledWin);
win.child = vBox;
win.present();
win.connect("close-request", () => {
loop.quit();
});
loop.run();