#!/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 == 0:
            if stat.S_ISDIR(mode):
                return folderpb
            else:
                return filepb
        elif column == 1:
            return rowref
        elif column == 2:
            return filestat.st_size
        elif column == 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()
