summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Feltman <sfeltman@src.gnome.org>2014-01-14 23:08:33 -0800
committerSimon Feltman <sfeltman@src.gnome.org>2014-01-14 23:10:04 -0800
commitf89fa08ba756a1c529ff48beb39025f834a249bf (patch)
treea8d603a1d087cb7afd1096d1dfc9b1b3cc4b3d7d
parent0b7d85f3379adfb3cf1122588e333707ee089e46 (diff)
downloadpygobject-f89fa08ba756a1c529ff48beb39025f834a249bf.tar.gz
demo: Remove spaces from demo sub-directories
Move "Icon View" to IconView and "Tree View" to TreeView. This will help ability to package the demos in tarball releases in future versions.
-rw-r--r--demos/gtk-demo/demos/IconView/__init__.py0
-rw-r--r--demos/gtk-demo/demos/IconView/iconviewbasics.py220
-rw-r--r--demos/gtk-demo/demos/IconView/iconviewedit.py98
-rw-r--r--demos/gtk-demo/demos/TreeView/__init__.py0
-rw-r--r--demos/gtk-demo/demos/TreeView/liststore.py210
-rw-r--r--demos/gtk-demo/demos/TreeView/treemodel_filelist.py234
-rw-r--r--demos/gtk-demo/demos/TreeView/treemodel_filetree.py279
7 files changed, 1041 insertions, 0 deletions
diff --git a/demos/gtk-demo/demos/IconView/__init__.py b/demos/gtk-demo/demos/IconView/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/demos/gtk-demo/demos/IconView/__init__.py
diff --git a/demos/gtk-demo/demos/IconView/iconviewbasics.py b/demos/gtk-demo/demos/IconView/iconviewbasics.py
new file mode 100644
index 00000000..ea1ceb41
--- /dev/null
+++ b/demos/gtk-demo/demos/IconView/iconviewbasics.py
@@ -0,0 +1,220 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "Icon View Basics"
+description = """The GtkIconView widget is used to display and manipulate
+icons. It uses a GtkTreeModel for data storage, so the list store example might
+be helpful. We also use the Gio.File API to get the icons for each file type.
+"""
+
+
+import os
+
+from gi.repository import GLib, Gio, GdkPixbuf, Gtk
+
+
+class IconViewApp:
+ (COL_PATH,
+ COL_DISPLAY_NAME,
+ COL_PIXBUF,
+ COL_IS_DIRECTORY,
+ NUM_COLS) = range(5)
+
+ def __init__(self, demoapp):
+ self.pixbuf_lookup = {}
+
+ self.demoapp = demoapp
+
+ self.window = Gtk.Window()
+ self.window.set_title('Gtk.IconView demo')
+ self.window.set_default_size(650, 400)
+ self.window.connect('destroy', Gtk.main_quit)
+
+ vbox = Gtk.VBox()
+ self.window.add(vbox)
+
+ tool_bar = Gtk.Toolbar()
+ vbox.pack_start(tool_bar, False, False, 0)
+
+ up_button = Gtk.ToolButton(stock_id=Gtk.STOCK_GO_UP)
+ up_button.set_is_important(True)
+ up_button.set_sensitive(False)
+ tool_bar.insert(up_button, -1)
+
+ home_button = Gtk.ToolButton(stock_id=Gtk.STOCK_HOME)
+ home_button.set_is_important(True)
+ tool_bar.insert(home_button, -1)
+
+ sw = Gtk.ScrolledWindow()
+ sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
+ sw.set_policy(Gtk.PolicyType.AUTOMATIC,
+ Gtk.PolicyType.AUTOMATIC)
+
+ vbox.pack_start(sw, True, True, 0)
+
+ # create the store and fill it with content
+ self.parent_dir = '/'
+ store = self.create_store()
+ self.fill_store(store)
+
+ icon_view = Gtk.IconView(model=store)
+ icon_view.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
+ sw.add(icon_view)
+
+ # connect to the 'clicked' signal of the "Up" tool button
+ up_button.connect('clicked', self.up_clicked, store)
+
+ # connect to the 'clicked' signal of the "home" tool button
+ home_button.connect('clicked', self.home_clicked, store)
+
+ self.up_button = up_button
+ self.home_button = home_button
+
+ # we now set which model columns that correspond to the text
+ # and pixbuf of each item
+ icon_view.set_text_column(self.COL_DISPLAY_NAME)
+ icon_view.set_pixbuf_column(self.COL_PIXBUF)
+
+ # connect to the "item-activated" signal
+ icon_view.connect('item-activated', self.item_activated, store)
+ icon_view.grab_focus()
+
+ self.window.show_all()
+
+ def sort_func(self, store, a_iter, b_iter, user_data):
+ (a_name, a_is_dir) = store.get(a_iter,
+ self.COL_DISPLAY_NAME,
+ self.COL_IS_DIRECTORY)
+
+ (b_name, b_is_dir) = store.get(b_iter,
+ self.COL_DISPLAY_NAME,
+ self.COL_IS_DIRECTORY)
+
+ if a_name is None:
+ a_name = ''
+
+ if b_name is None:
+ b_name = ''
+
+ if (not a_is_dir) and b_is_dir:
+ return 1
+ elif a_is_dir and (not b_is_dir):
+ return -1
+ elif a_name > b_name:
+ return 1
+ elif a_name < b_name:
+ return -1
+ else:
+ return 0
+
+ def up_clicked(self, item, store):
+ self.parent_dir = os.path.split(self.parent_dir)[0]
+ self.fill_store(store)
+ # de-sensitize the up button if we are at the root
+ self.up_button.set_sensitive(self.parent_dir != '/')
+
+ def home_clicked(self, item, store):
+ self.parent_dir = GLib.get_home_dir()
+ self.fill_store(store)
+
+ # Sensitize the up button
+ self.up_button.set_sensitive(True)
+
+ def item_activated(self, icon_view, tree_path, store):
+ iter_ = store.get_iter(tree_path)
+ (path, is_dir) = store.get(iter_, self.COL_PATH, self.COL_IS_DIRECTORY)
+ if not is_dir:
+ return
+
+ self.parent_dir = path
+ self.fill_store(store)
+
+ self.up_button.set_sensitive(True)
+
+ def create_store(self):
+ store = Gtk.ListStore(str, str, GdkPixbuf.Pixbuf, bool)
+
+ # set sort column and function
+ store.set_default_sort_func(self.sort_func)
+ store.set_sort_column_id(-1, Gtk.SortType.ASCENDING)
+
+ return store
+
+ def file_to_icon_pixbuf(self, path):
+ pixbuf = None
+
+ # get the theme icon
+ f = Gio.file_new_for_path(path)
+ info = f.query_info(Gio.FILE_ATTRIBUTE_STANDARD_ICON,
+ Gio.FileQueryInfoFlags.NONE,
+ None)
+ gicon = info.get_icon()
+
+ # check to see if it is an image format we support
+ for format in GdkPixbuf.Pixbuf.get_formats():
+ for mime_type in format.get_mime_types():
+ content_type = Gio.content_type_from_mime_type(mime_type)
+ if content_type is not None:
+ break
+
+ format_gicon = Gio.content_type_get_icon(content_type)
+ if format_gicon.equal(gicon):
+ gicon = f.icon_new()
+ break
+
+ if gicon in self.pixbuf_lookup:
+ return self.pixbuf_lookup[gicon]
+
+ if isinstance(gicon, Gio.ThemedIcon):
+ names = gicon.get_names()
+ icon_theme = Gtk.IconTheme.get_default()
+ for name in names:
+ try:
+ pixbuf = icon_theme.load_icon(name, 64, 0)
+ break
+ except GLib.GError:
+ pass
+
+ self.pixbuf_lookup[gicon] = pixbuf
+
+ elif isinstance(gicon, Gio.FileIcon):
+ icon_file = gicon.get_file()
+ path = icon_file.get_path()
+ pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path, 72, 72)
+ self.pixbuf_lookup[gicon] = pixbuf
+
+ return pixbuf
+
+ def fill_store(self, store):
+ store.clear()
+ for name in os.listdir(self.parent_dir):
+ path = os.path.join(self.parent_dir, name)
+ is_dir = os.path.isdir(path)
+ pixbuf = self.file_to_icon_pixbuf(path)
+ store.append((path, name, pixbuf, is_dir))
+
+
+def main(demoapp=None):
+ IconViewApp(demoapp)
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/demos/gtk-demo/demos/IconView/iconviewedit.py b/demos/gtk-demo/demos/IconView/iconviewedit.py
new file mode 100644
index 00000000..44f3ffea
--- /dev/null
+++ b/demos/gtk-demo/demos/IconView/iconviewedit.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "Editing and Drag-and-Drop"
+description = """The GtkIconView widget supports Editing and Drag-and-Drop.
+This example also demonstrates using the generic GtkCellLayout interface to set
+up cell renderers in an icon view.
+"""
+
+from gi.repository import Gtk, Gdk, GdkPixbuf
+
+
+class IconviewEditApp:
+ COL_TEXT = 0
+ NUM_COLS = 1
+
+ def __init__(self):
+ self.window = Gtk.Window()
+ self.window.set_title('Editing and Drag-and-Drop')
+ self.window.set_border_width(8)
+ self.window.connect('destroy', Gtk.main_quit)
+
+ store = Gtk.ListStore(str)
+ colors = ['Red', 'Green', 'Blue', 'Yellow']
+ store.clear()
+ for c in colors:
+ store.append([c])
+
+ icon_view = Gtk.IconView(model=store)
+ icon_view.set_selection_mode(Gtk.SelectionMode.SINGLE)
+ icon_view.set_item_orientation(Gtk.Orientation.HORIZONTAL)
+ icon_view.set_columns(2)
+ icon_view.set_reorderable(True)
+
+ renderer = Gtk.CellRendererPixbuf()
+ icon_view.pack_start(renderer, True)
+ icon_view.set_cell_data_func(renderer,
+ self.set_cell_color,
+ None)
+
+ renderer = Gtk.CellRendererText()
+ icon_view.pack_start(renderer, True)
+ renderer.props.editable = True
+ renderer.connect('edited', self.edited, icon_view)
+ icon_view.add_attribute(renderer, 'text', self.COL_TEXT)
+
+ self.window.add(icon_view)
+
+ self.window.show_all()
+
+ def set_cell_color(self, cell_layout, cell, tree_model, iter_, icon_view):
+
+ # FIXME return single element instead of tuple
+ text = tree_model.get(iter_, self.COL_TEXT)[0]
+ color = Gdk.color_parse(text)
+ pixel = 0
+ if color is not None:
+ pixel = ((color.red >> 8) << 24 |
+ (color.green >> 8) << 16 |
+ (color.blue >> 8) << 8)
+
+ pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, 24, 24)
+ pixbuf.fill(pixel)
+
+ cell.props.pixbuf = pixbuf
+
+ def edited(self, cell, path_string, text, icon_view):
+ model = icon_view.get_model()
+ path = Gtk.TreePath(path_string)
+
+ iter_ = model.get_iter(path)
+ model.set_row(iter_, [text])
+
+
+def main(demoapp=None):
+ IconviewEditApp()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/demos/gtk-demo/demos/TreeView/__init__.py b/demos/gtk-demo/demos/TreeView/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/demos/gtk-demo/demos/TreeView/__init__.py
diff --git a/demos/gtk-demo/demos/TreeView/liststore.py b/demos/gtk-demo/demos/TreeView/liststore.py
new file mode 100644
index 00000000..bad99d3a
--- /dev/null
+++ b/demos/gtk-demo/demos/TreeView/liststore.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Red Hat, Inc., John (J5) Palmieri <johnp@redhat.com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+title = "List Store"
+description = """
+The GtkListStore is used to store data in list form, to be used later on by a
+GtkTreeView to display it. This demo builds a simple GtkListStore and displays
+it. See the Stock Browser demo for a more advanced example.
+"""
+
+
+from gi.repository import Gtk, GObject, GLib
+
+
+class Bug:
+ def __init__(self, is_fixed, number, severity, description):
+ self.is_fixed = is_fixed
+ self.number = number
+ self.severity = severity
+ self.description = description
+
+# initial data we use to fill in the store
+data = [Bug(False, 60482, "Normal", "scrollable notebooks and hidden tabs"),
+ Bug(False, 60620, "Critical", "gdk_window_clear_area (gdkwindow-win32.c) is not thread-safe"),
+ Bug(False, 50214, "Major", "Xft support does not clean up correctly"),
+ Bug(True, 52877, "Major", "GtkFileSelection needs a refresh method. "),
+ Bug(False, 56070, "Normal", "Can't click button after setting in sensitive"),
+ Bug(True, 56355, "Normal", "GtkLabel - Not all changes propagate correctly"),
+ Bug(False, 50055, "Normal", "Rework width/height computations for TreeView"),
+ Bug(False, 58278, "Normal", "gtk_dialog_set_response_sensitive () doesn't work"),
+ Bug(False, 55767, "Normal", "Getters for all setters"),
+ Bug(False, 56925, "Normal", "Gtkcalender size"),
+ Bug(False, 56221, "Normal", "Selectable label needs right-click copy menu"),
+ Bug(True, 50939, "Normal", "Add shift clicking to GtkTextView"),
+ Bug(False, 6112, "Enhancement", "netscape-like collapsable toolbars"),
+ Bug(False, 1, "Normal", "First bug :=)")]
+
+
+class ListStoreApp:
+ (COLUMN_FIXED,
+ COLUMN_NUMBER,
+ COLUMN_SEVERITY,
+ COLUMN_DESCRIPTION,
+ COLUMN_PULSE,
+ COLUMN_ICON,
+ COLUMN_ACTIVE,
+ COLUMN_SENSITIVE,
+ NUM_COLUMNS) = range(9)
+
+ def __init__(self):
+ self.window = Gtk.Window()
+ self.window.set_title('Gtk.ListStore Demo')
+ self.window.connect('destroy', Gtk.main_quit)
+
+ vbox = Gtk.VBox(spacing=8)
+ self.window.add(vbox)
+
+ label = Gtk.Label(label='This is the bug list (note: not based on real data, it would be nice to have a nice ODBC interface to bugzilla or so, though).')
+ vbox.pack_start(label, False, False, 0)
+
+ sw = Gtk.ScrolledWindow()
+ sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
+ sw.set_policy(Gtk.PolicyType.NEVER,
+ Gtk.PolicyType.AUTOMATIC)
+ vbox.pack_start(sw, True, True, 0)
+
+ self.create_model()
+ treeview = Gtk.TreeView(model=self.model)
+ treeview.set_rules_hint(True)
+ treeview.set_search_column(self.COLUMN_DESCRIPTION)
+ sw.add(treeview)
+
+ self.add_columns(treeview)
+
+ self.window.set_default_size(280, 250)
+ self.window.show_all()
+
+ self.window.connect('delete-event', self.window_closed)
+ self.timeout = GLib.timeout_add(80, self.spinner_timeout)
+
+ def window_closed(self, window, event):
+ if self.timeout != 0:
+ GLib.source_remove(self.timeout)
+
+ def spinner_timeout(self):
+ if self.model is None:
+ return False
+
+ iter_ = self.model.get_iter_first()
+ pulse = self.model.get(iter_, self.COLUMN_PULSE)[0]
+ if pulse == 999999999:
+ pulse = 0
+ else:
+ pulse += 1
+
+ self.model.set_value(iter_, self.COLUMN_PULSE, pulse)
+ self.model.set_value(iter_, self.COLUMN_ACTIVE, True)
+
+ return True
+
+ def create_model(self):
+ self.model = Gtk.ListStore(bool,
+ GObject.TYPE_INT,
+ str,
+ str,
+ GObject.TYPE_INT,
+ str,
+ bool,
+ bool)
+
+ col = 0
+ for bug in data:
+ if col == 1 or col == 3:
+ icon_name = 'battery-critical-charging-symbolic'
+ else:
+ icon_name = ''
+ if col == 3:
+ is_sensitive = False
+ else:
+ is_sensitive = True
+
+ self.model.append([bug.is_fixed,
+ bug.number,
+ bug.severity,
+ bug.description,
+ 0,
+ icon_name,
+ False,
+ is_sensitive])
+ col += 1
+
+ def add_columns(self, treeview):
+ model = treeview.get_model()
+
+ # column for is_fixed toggle
+ renderer = Gtk.CellRendererToggle()
+ renderer.connect('toggled', self.is_fixed_toggled, model)
+
+ column = Gtk.TreeViewColumn("Fixed?", renderer,
+ active=self.COLUMN_FIXED)
+ column.set_fixed_width(50)
+ column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
+ treeview.append_column(column)
+
+ # column for severities
+ renderer = Gtk.CellRendererText()
+ column = Gtk.TreeViewColumn("Severity", renderer,
+ text=self.COLUMN_SEVERITY)
+ column.set_sort_column_id(self.COLUMN_SEVERITY)
+ treeview.append_column(column)
+
+ # column for description
+ renderer = Gtk.CellRendererText()
+ column = Gtk.TreeViewColumn("Description", renderer,
+ text=self.COLUMN_DESCRIPTION)
+ column.set_sort_column_id(self.COLUMN_DESCRIPTION)
+ treeview.append_column(column)
+
+ # column for spinner
+ renderer = Gtk.CellRendererSpinner()
+ column = Gtk.TreeViewColumn("Spinning", renderer,
+ pulse=self.COLUMN_PULSE,
+ active=self.COLUMN_ACTIVE)
+ column.set_sort_column_id(self.COLUMN_PULSE)
+ treeview.append_column(column)
+
+ # column for symbolic icon
+ renderer = Gtk.CellRendererPixbuf()
+ renderer.props.follow_state = True
+ column = Gtk.TreeViewColumn("Symbolic icon", renderer,
+ icon_name=self.COLUMN_ICON,
+ sensitive=self.COLUMN_SENSITIVE)
+ column.set_sort_column_id(self.COLUMN_ICON)
+ treeview.append_column(column)
+
+ def is_fixed_toggled(self, cell, path_str, model):
+ # get toggled iter
+ iter_ = model.get_iter(path_str)
+ is_fixed = model.get_value(iter_, self.COLUMN_FIXED)
+
+ # do something with value
+ is_fixed ^= 1
+
+ model.set_value(iter_, self.COLUMN_FIXED, is_fixed)
+
+
+def main(demoapp=None):
+ ListStoreApp()
+ Gtk.main()
+
+if __name__ == '__main__':
+ main()
diff --git a/demos/gtk-demo/demos/TreeView/treemodel_filelist.py b/demos/gtk-demo/demos/TreeView/treemodel_filelist.py
new file mode 100644
index 00000000..f3c7565c
--- /dev/null
+++ b/demos/gtk-demo/demos/TreeView/treemodel_filelist.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python
+
+title = "File List (GenericTreeModel)"
+description = """
+This is a file list demo which makes use of the GenericTreeModel python
+implementation of the Gtk.TreeModel interface. This demo shows what methods
+need to be overridden to provide a valid TreeModel to a TreeView.
+"""
+
+import os
+import stat
+import time
+
+import pygtkcompat
+pygtkcompat.enable()
+pygtkcompat.enable_gtk('3.0')
+
+import gtk
+
+
+folderxpm = [
+ "17 16 7 1",
+ " c #000000",
+ ". c #808000",
+ "X c yellow",
+ "o c #808080",
+ "O c #c0c0c0",
+ "+ c white",
+ "@ c None",
+ "@@@@@@@@@@@@@@@@@",
+ "@@@@@@@@@@@@@@@@@",
+ "@@+XXXX.@@@@@@@@@",
+ "@+OOOOOO.@@@@@@@@",
+ "@+OXOXOXOXOXOXO. ",
+ "@+XOXOXOXOXOXOX. ",
+ "@+OXOXOXOXOXOXO. ",
+ "@+XOXOXOXOXOXOX. ",
+ "@+OXOXOXOXOXOXO. ",
+ "@+XOXOXOXOXOXOX. ",
+ "@+OXOXOXOXOXOXO. ",
+ "@+XOXOXOXOXOXOX. ",
+ "@+OOOOOOOOOOOOO. ",
+ "@ ",
+ "@@@@@@@@@@@@@@@@@",
+ "@@@@@@@@@@@@@@@@@"
+ ]
+folderpb = gtk.gdk.pixbuf_new_from_xpm_data(folderxpm)
+
+filexpm = [
+ "12 12 3 1",
+ " c #000000",
+ ". c #ffff04",
+ "X c #b2c0dc",
+ "X XXX",
+ "X ...... XXX",
+ "X ...... X",
+ "X . ... X",
+ "X ........ X",
+ "X . .... X",
+ "X ........ X",
+ "X . .. X",
+ "X ........ X",
+ "X . .. X",
+ "X ........ X",
+ "X X"
+ ]
+filepb = gtk.gdk.pixbuf_new_from_xpm_data(filexpm)
+
+
+class FileListModel(gtk.GenericTreeModel):
+ __gtype_name__ = 'DemoFileListModel'
+
+ column_types = (gtk.gdk.Pixbuf, str, int, str, str)
+ column_names = ['Name', 'Size', 'Mode', 'Last Changed']
+
+ def __init__(self, dname=None):
+ gtk.GenericTreeModel.__init__(self)
+ self._sort_column_id = 0
+ self._sort_order = gtk.SORT_ASCENDING
+
+ if not dname:
+ self.dirname = os.path.expanduser('~')
+ else:
+ self.dirname = os.path.abspath(dname)
+ self.files = ['..'] + [f for f in os.listdir(self.dirname)]
+ return
+
+ def get_pathname(self, path):
+ filename = self.files[path[0]]
+ return os.path.join(self.dirname, filename)
+
+ def is_folder(self, path):
+ filename = self.files[path[0]]
+ pathname = os.path.join(self.dirname, filename)
+ filestat = os.stat(pathname)
+ if stat.S_ISDIR(filestat.st_mode):
+ return True
+ return False
+
+ def get_column_names(self):
+ return self.column_names[:]
+
+ #
+ # GenericTreeModel Implementation
+ #
+ def on_get_flags(self):
+ return 0 # gtk.TREE_MODEL_ITERS_PERSIST
+
+ def on_get_n_columns(self):
+ return len(self.column_types)
+
+ def on_get_column_type(self, n):
+ return self.column_types[n]
+
+ def on_get_iter(self, path):
+ return self.files[path[0]]
+
+ def on_get_path(self, rowref):
+ return self.files.index(rowref)
+
+ def on_get_value(self, rowref, column):
+ fname = os.path.join(self.dirname, rowref)
+ try:
+ filestat = os.stat(fname)
+ except OSError:
+ return None
+ mode = filestat.st_mode
+ if column is 0:
+ if stat.S_ISDIR(mode):
+ return folderpb
+ else:
+ return filepb
+ elif column is 1:
+ return rowref
+ elif column is 2:
+ return filestat.st_size
+ elif column is 3:
+ return oct(stat.S_IMODE(mode))
+ return time.ctime(filestat.st_mtime)
+
+ def on_iter_next(self, rowref):
+ try:
+ i = self.files.index(rowref) + 1
+ return self.files[i]
+ except IndexError:
+ return None
+
+ def on_iter_children(self, rowref):
+ if rowref:
+ return None
+ return self.files[0]
+
+ def on_iter_has_child(self, rowref):
+ return False
+
+ def on_iter_n_children(self, rowref):
+ if rowref:
+ return 0
+ return len(self.files)
+
+ def on_iter_nth_child(self, rowref, n):
+ if rowref:
+ return None
+ try:
+ return self.files[n]
+ except IndexError:
+ return None
+
+ def on_iter_parent(child):
+ return None
+
+
+class GenericTreeModelExample:
+ def delete_event(self, widget, event, data=None):
+ gtk.main_quit()
+ return False
+
+ def __init__(self):
+ # Create a new window
+ self.window = gtk.Window(type=gtk.WINDOW_TOPLEVEL)
+
+ self.window.set_size_request(300, 200)
+
+ self.window.connect("delete_event", self.delete_event)
+
+ self.listmodel = FileListModel()
+
+ # create the TreeView
+ self.treeview = gtk.TreeView()
+
+ self.tvcolumns = []
+
+ # create the TreeViewColumns to display the data
+ for n, name in enumerate(self.listmodel.get_column_names()):
+ if n == 0:
+ cellpb = gtk.CellRendererPixbuf()
+ col = gtk.TreeViewColumn(name, cellpb, pixbuf=0)
+ cell = gtk.CellRendererText()
+ col.pack_start(cell, False)
+ col.add_attribute(cell, 'text', 1)
+ else:
+ cell = gtk.CellRendererText()
+ col = gtk.TreeViewColumn(name, cell, text=n + 1)
+ if n == 1:
+ cell.set_property('xalign', 1.0)
+
+ self.treeview.append_column(col)
+
+ self.treeview.connect('row-activated', self.open_file)
+
+ self.scrolledwindow = gtk.ScrolledWindow()
+ self.scrolledwindow.add(self.treeview)
+ self.window.add(self.scrolledwindow)
+ self.treeview.set_model(self.listmodel)
+ self.window.set_title(self.listmodel.dirname)
+ self.window.show_all()
+
+ def open_file(self, treeview, path, column):
+ model = treeview.get_model()
+ if model.is_folder(path):
+ pathname = model.get_pathname(path)
+ new_model = FileListModel(pathname)
+ self.window.set_title(new_model.dirname)
+ treeview.set_model(new_model)
+ return
+
+
+def main(demoapp=None):
+ demo = GenericTreeModelExample()
+ demo
+ gtk.main()
+
+if __name__ == "__main__":
+ main()
diff --git a/demos/gtk-demo/demos/TreeView/treemodel_filetree.py b/demos/gtk-demo/demos/TreeView/treemodel_filetree.py
new file mode 100644
index 00000000..0549436f
--- /dev/null
+++ b/demos/gtk-demo/demos/TreeView/treemodel_filetree.py
@@ -0,0 +1,279 @@
+#!/usr/bin/env python
+
+title = "File Tree (GenericTreeModel)"
+description = """
+This is a file list demo which makes use of the GenericTreeModel python
+implementation of the Gtk.TreeModel interface. This demo shows what methods
+need to be overridden to provide a valid TreeModel to a TreeView.
+"""
+
+import os
+import stat
+import time
+from collections import OrderedDict
+
+import pygtkcompat
+pygtkcompat.enable_gtk('3.0')
+
+import gtk
+
+
+folderxpm = [
+ "17 16 7 1",
+ " c #000000",
+ ". c #808000",
+ "X c yellow",
+ "o c #808080",
+ "O c #c0c0c0",
+ "+ c white",
+ "@ c None",
+ "@@@@@@@@@@@@@@@@@",
+ "@@@@@@@@@@@@@@@@@",
+ "@@+XXXX.@@@@@@@@@",
+ "@+OOOOOO.@@@@@@@@",
+ "@+OXOXOXOXOXOXO. ",
+ "@+XOXOXOXOXOXOX. ",
+ "@+OXOXOXOXOXOXO. ",
+ "@+XOXOXOXOXOXOX. ",
+ "@+OXOXOXOXOXOXO. ",
+ "@+XOXOXOXOXOXOX. ",
+ "@+OXOXOXOXOXOXO. ",
+ "@+XOXOXOXOXOXOX. ",
+ "@+OOOOOOOOOOOOO. ",
+ "@ ",
+ "@@@@@@@@@@@@@@@@@",
+ "@@@@@@@@@@@@@@@@@"
+ ]
+folderpb = gtk.gdk.pixbuf_new_from_xpm_data(folderxpm)
+
+filexpm = [
+ "12 12 3 1",
+ " c #000000",
+ ". c #ffff04",
+ "X c #b2c0dc",
+ "X XXX",
+ "X ...... XXX",
+ "X ...... X",
+ "X . ... X",
+ "X ........ X",
+ "X . .... X",
+ "X ........ X",
+ "X . .. X",
+ "X ........ X",
+ "X . .. X",
+ "X ........ X",
+ "X X"
+ ]
+filepb = gtk.gdk.pixbuf_new_from_xpm_data(filexpm)
+
+
+class FileTreeModel(gtk.GenericTreeModel):
+ __gtype_name__ = 'DemoFileTreeModel'
+
+ column_types = (gtk.gdk.Pixbuf, str, int, str, str)
+ column_names = ['Name', 'Size', 'Mode', 'Last Changed']
+
+ def __init__(self, dname=None):
+ gtk.GenericTreeModel.__init__(self)
+ if not dname:
+ self.dirname = os.path.expanduser('~')
+ else:
+ self.dirname = os.path.abspath(dname)
+ self.files = self.build_file_dict(self.dirname)
+ return
+
+ def build_file_dict(self, dirname):
+ """
+ :Returns:
+ A dictionary containing the files in the given dirname keyed by filename.
+ If the child filename is a sub-directory, the dict value is a dict.
+ Otherwise it will be None.
+ """
+ d = OrderedDict()
+ for fname in os.listdir(dirname):
+ try:
+ filestat = os.stat(os.path.join(dirname, fname))
+ except OSError:
+ d[fname] = None
+ else:
+ d[fname] = OrderedDict() if stat.S_ISDIR(filestat.st_mode) else None
+
+ return d
+
+ def get_node_from_treepath(self, path):
+ """
+ :Returns:
+ The node stored at the given tree path in local storage.
+ """
+ # TreePaths are a series of integer indices so just iterate through them
+ # and index values by each integer since we are using an OrderedDict
+ if path is None:
+ path = []
+ node = self.files
+ for index in path:
+ node = list(node.values())[index]
+ return node
+
+ def get_node_from_filepath(self, filepath):
+ """
+ :Returns:
+ The node stored at the given file path in local storage.
+ """
+ if not filepath:
+ return self.files
+ node = self.files
+ for key in filepath.split(os.path.sep):
+ node = node[key]
+ return node
+
+ def get_column_names(self):
+ return self.column_names[:]
+
+ #
+ # GenericTreeModel Implementation
+ #
+
+ def on_get_flags(self):
+ return 0
+
+ def on_get_n_columns(self):
+ return len(self.column_types)
+
+ def on_get_column_type(self, n):
+ return self.column_types[n]
+
+ def on_get_path(self, relpath):
+ path = []
+ node = self.files
+ for key in relpath.split(os.path.sep):
+ path.append(list(node.keys()).index(key))
+ node = node[key]
+ return path
+
+ def on_get_value(self, relpath, column):
+ fname = os.path.join(self.dirname, relpath)
+ try:
+ filestat = os.stat(fname)
+ except OSError:
+ return None
+ mode = filestat.st_mode
+ if column is 0:
+ if stat.S_ISDIR(mode):
+ return folderpb
+ else:
+ return filepb
+ elif column is 1:
+ return os.path.basename(relpath)
+ elif column is 2:
+ return filestat.st_size
+ elif column is 3:
+ return oct(stat.S_IMODE(mode))
+ return time.ctime(filestat.st_mtime)
+
+ def on_get_iter(self, path):
+ filepath = ''
+ value = self.files
+ for index in path:
+ filepath = os.path.join(filepath, list(value.keys())[index])
+ value = list(value.values())[index]
+ return filepath
+
+ def on_iter_next(self, filepath):
+ parent_path, child_path = os.path.split(filepath)
+ parent = self.get_node_from_filepath(parent_path)
+
+ # Index of filepath within its parents child list
+ sibling_names = list(parent.keys())
+ index = sibling_names.index(child_path)
+ try:
+ return os.path.join(parent_path, sibling_names[index + 1])
+ except IndexError:
+ return None
+
+ def on_iter_children(self, filepath):
+ if filepath:
+ children = list(self.get_node_from_filepath(filepath).keys())
+ if children:
+ return os.path.join(filepath, children[0])
+ elif self.files:
+ return list(self.files.keys())[0]
+
+ return None
+
+ def on_iter_has_child(self, filepath):
+ return bool(self.get_node_from_filepath(filepath))
+
+ def on_iter_n_children(self, filepath):
+ return len(self.get_node_from_filepath(filepath))
+
+ def on_iter_nth_child(self, filepath, n):
+ try:
+ child = list(self.get_node_from_filepath(filepath).keys())[n]
+ if filepath:
+ return os.path.join(filepath, child)
+ else:
+ return child
+ except IndexError:
+ return None
+
+ def on_iter_parent(self, filepath):
+ return os.path.dirname(filepath)
+
+ def on_ref_node(self, filepath):
+ value = self.get_node_from_filepath(filepath)
+ if value is not None:
+ value.update(self.build_file_dict(os.path.join(self.dirname, filepath)))
+
+ def on_unref_node(self, filepath):
+ pass
+
+
+class GenericTreeModelExample:
+ def delete_event(self, widget, event, data=None):
+ gtk.main_quit()
+ return False
+
+ def __init__(self):
+ # Create a new window
+ self.window = gtk.Window(type=gtk.WINDOW_TOPLEVEL)
+ self.window.set_size_request(300, 200)
+ self.window.connect("delete_event", self.delete_event)
+
+ self.listmodel = FileTreeModel()
+
+ # create the TreeView
+ self.treeview = gtk.TreeView()
+
+ # create the TreeViewColumns to display the data
+ column_names = self.listmodel.get_column_names()
+ self.tvcolumn = [None] * len(column_names)
+ cellpb = gtk.CellRendererPixbuf()
+ self.tvcolumn[0] = gtk.TreeViewColumn(column_names[0],
+ cellpb, pixbuf=0)
+ cell = gtk.CellRendererText()
+ self.tvcolumn[0].pack_start(cell, False)
+ self.tvcolumn[0].add_attribute(cell, 'text', 1)
+ self.treeview.append_column(self.tvcolumn[0])
+ for n in range(1, len(column_names)):
+ cell = gtk.CellRendererText()
+ if n == 1:
+ cell.set_property('xalign', 1.0)
+ self.tvcolumn[n] = gtk.TreeViewColumn(column_names[n],
+ cell, text=n + 1)
+ self.treeview.append_column(self.tvcolumn[n])
+
+ self.scrolledwindow = gtk.ScrolledWindow()
+ self.scrolledwindow.add(self.treeview)
+ self.window.add(self.scrolledwindow)
+ self.treeview.set_model(self.listmodel)
+ self.window.set_title(self.listmodel.dirname)
+ self.window.show_all()
+
+
+def main(demoapp=None):
+ demo = GenericTreeModelExample()
+ demo
+ gtk.main()
+
+if __name__ == "__main__":
+ main()