diff options
author | Simon Feltman <sfeltman@src.gnome.org> | 2014-01-14 23:08:33 -0800 |
---|---|---|
committer | Simon Feltman <sfeltman@src.gnome.org> | 2014-01-14 23:10:04 -0800 |
commit | f89fa08ba756a1c529ff48beb39025f834a249bf (patch) | |
tree | a8d603a1d087cb7afd1096d1dfc9b1b3cc4b3d7d | |
parent | 0b7d85f3379adfb3cf1122588e333707ee089e46 (diff) | |
download | pygobject-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__.py | 0 | ||||
-rw-r--r-- | demos/gtk-demo/demos/IconView/iconviewbasics.py | 220 | ||||
-rw-r--r-- | demos/gtk-demo/demos/IconView/iconviewedit.py | 98 | ||||
-rw-r--r-- | demos/gtk-demo/demos/TreeView/__init__.py | 0 | ||||
-rw-r--r-- | demos/gtk-demo/demos/TreeView/liststore.py | 210 | ||||
-rw-r--r-- | demos/gtk-demo/demos/TreeView/treemodel_filelist.py | 234 | ||||
-rw-r--r-- | demos/gtk-demo/demos/TreeView/treemodel_filetree.py | 279 |
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() |