[pygobject] demo: Remove spaces from demo sub-directories



commit f89fa08ba756a1c529ff48beb39025f834a249bf
Author: Simon Feltman <sfeltman src gnome org>
Date:   Tue Jan 14 23:08:33 2014 -0800

    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.

 demos/gtk-demo/demos/IconView/iconviewbasics.py    |  220 +++++++++++++++
 demos/gtk-demo/demos/IconView/iconviewedit.py      |   98 +++++++
 demos/gtk-demo/demos/TreeView/liststore.py         |  210 +++++++++++++++
 .../gtk-demo/demos/TreeView/treemodel_filelist.py  |  234 ++++++++++++++++
 .../gtk-demo/demos/TreeView/treemodel_filetree.py  |  279 ++++++++++++++++++++
 5 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 0000000..e69de29
diff --git a/demos/gtk-demo/demos/IconView/iconviewbasics.py b/demos/gtk-demo/demos/IconView/iconviewbasics.py
new file mode 100644
index 0000000..ea1ceb4
--- /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 0000000..44f3ffe
--- /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 0000000..e69de29
diff --git a/demos/gtk-demo/demos/TreeView/liststore.py b/demos/gtk-demo/demos/TreeView/liststore.py
new file mode 100644
index 0000000..bad99d3
--- /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 0000000..f3c7565
--- /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 0000000..0549436
--- /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()


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