LINUX.ORG.RU

[pygtk] Пара проблем при использовании gio.FileMonitor


0

1

Приветствую.

Вот решил переписать свой виджет дерева директорий на gio и заодно добавить в него автоматическое обновление при изменении в структуре директорий. Для реализации автообновления решил заюзать gio.FileMonitor и вот тут-то у меня возникли проблемы.

Во-первых т.к. gio.FileMonitor не умеет следить за изменениями в директориях рекурсивно, его приходится вешать на каждую директорию отображаемую в дереве. Соответственно при удалении директории обработчик сигнала «changed» вызывается 2 раза, один раз от монитора удаленной директории, а второй от монитора родительской директории. Это конечно не большая проблема, но может можно как-нибудь решить?

Вторая проблема намного более серьезная. При удалении и последующем создании директории с одним и тем же именем и путем, пайтон уходит в сегфолт.

Кстати еще заметил странное поведение обработчика сигнала «test-expand-row» виджета gtk.TreeView. В документации написано, что раскрытие происходит если он возвращает True. На практике все с точностью до наоборот.

Вот код:

import glib
import gtk
import gio


class DirectoryTree(gtk.TreeView):
    __gsignals__ = {
        "test-expand-row": "override"
    }

    def __init__(self, uri, show_hidden=False):
        model = gtk.TreeStore(gio.File, gio.Icon, str)
        super(DirectoryTree, self).__init__(model)
        self.__show_hidden = show_hidden
        self.__uri = uri
        self.__gemblem_noread = gio.Emblem(gio.ThemedIcon("emblem-noread"),
                gio.EMBLEM_ORIGIN_LIVEMETADATA)
        self.__gemblem_symlink = gio.Emblem(gio.ThemedIcon(
                "emblem-symbolic-link"), gio.EMBLEM_ORIGIN_LIVEMETADATA)
        
        column = gtk.TreeViewColumn()
        
        renderer = gtk.CellRendererPixbuf()
        column.pack_start(renderer, False)
        column.set_attributes(renderer, gicon=1)
        renderer = gtk.CellRendererText()
        column.pack_start(renderer, True)
        column.set_attributes(renderer, text=2)

        self.set_headers_visible(False)
        # Sort files by their names
        model.set_sort_column_id(2, gtk.SORT_ASCENDING)
        self.append_column(column)

        # Create root item
        gfile = gio.File(uri)
        title = gfile.query_info("standard::display-name").get_display_name()
        gicon = self.__get_emblemed_icon(gfile)
        iter = model.append(None, (gfile, gicon, title))
        self.__install_gfile_monitor(gfile, iter)
        model.append(iter)
        self.__check_for_subdirs(iter)

    def __check_for_subdirs(self, iter):
        model = self.get_model()
        gfile = model.get_value(iter, 0)
        try:
            gfinfos = gfile.enumerate_children("standard::type")
            for i in gfinfos:
                if i.get_file_type() == gio.FILE_TYPE_DIRECTORY:
                    return
        except gio.Error:
            pass
        model.remove(model.iter_children(iter))

    def __install_gfile_monitor(self, gfile, iter):
        monitor = gfile.monitor()
        monitor.connect("changed", self.__on_gfile_changed, iter)

    def __on_gfile_delete(self, parent, gfile):
        model = self.get_model()
        child = model.iter_children(parent)
        if child is None:
            return
        if model.get_value(child, 0) is None:
            glib.idle_add(self.__check_for_subdirs, parent)
        else:
            while child:
                stored_gfile = model.get_value(child, 0)
                if gfile.equal(stored_gfile):
                    model.remove(child)
                    child = None
                else:
                    child = model.iter_next(child)

    def __on_gfile_create(self, parent, gfile):
        model = self.get_model()
        try:
            gfinfo = gfile.query_info("standard::type,"
                    "standard::display-name,standard::is-hidden")
        except gio.Error, e:
            return
        if gfinfo.get_file_type() != gio.FILE_TYPE_DIRECTORY:
            return
        # Not show hidden items if we not want them
        if not self.__show_hidden and gfinfo.get_is_hidden():
            return
        child = model.iter_children(parent)
        if child is None:
            model.append(parent)
        elif model.get_value(child, 0) is not None:
            gicon = self.__get_emblemed_icon(gfile)
            title = gfinfo.get_display_name()
            child = model.append(parent, (gfile, gicon, title))
            self.__install_gfile_monitor(gfile, child)
            model.append(child)
            glib.idle_add(self.__check_for_subdirs, child)

    def __on_gfile_changed(self, monitor, gfile, other_gfile, event_type, iter):
        if event_type == gio.FILE_MONITOR_EVENT_CREATED:
            self.__on_gfile_create(iter, gfile)
        elif event_type == gio.FILE_MONITOR_EVENT_DELETED:
            self.__on_gfile_delete(iter, gfile)

    def __get_emblemed_icon(self, gfile):
        gfinfo = gfile.query_info("standard::icon,standard::is-symlink,"
                "access::can-read,access::can-write")
        if not gfinfo.get_attribute_boolean("access::can-read"):
            gicon = gio.EmblemedIcon(gfinfo.get_icon(), self.__gemblem_noread)
        elif gfinfo.get_attribute_boolean("standard::is-symlink"):
            gicon = gio.EmblemedIcon(gfinfo.get_icon(), self.__gemblem_symlink)
        else:
            gicon = gfinfo.get_icon()
        return gicon

    def __fill_model(self, iter):
        model = self.get_model()
        gfile = model.get_value(iter, 0)

        gfinfos = gfile.enumerate_children("standard::type,standard::name,"
                "standard::display-name,standard::is-hidden")
        for i in gfinfos:
            if i.get_file_type() != gio.FILE_TYPE_DIRECTORY:
                continue
            # Not show hidden items if we not want them
            if not self.__show_hidden and i.get_is_hidden():
                continue
            child = gfile.get_child(i.get_name())
            gicon = self.__get_emblemed_icon(child)
            title = i.get_display_name()
            child_iter = model.append(iter, (child, gicon, title))
            self.__install_gfile_monitor(child, child_iter)
            model.append(child_iter)
            glib.idle_add(self.__check_for_subdirs, child_iter)

    def do_test_expand_row(self, iter, path):
        model = self.get_model()
        child = model.iter_children(iter)
        if model.get_value(child, 0) is None:
            model.remove(child)
            self.__fill_model(iter)

def main():
    window = gtk.Window()
    window.set_title("Directory Tree")
    window.set_default_size(600, 400)
    window.connect("destroy", gtk.main_quit)
    sw = gtk.ScrolledWindow()
    dirtree = DirectoryTree("file:///")
    sw.add(dirtree)
    window.add(sw)
    window.show_all()
    gtk.main()


if __name__ == "__main__":
    main()

★★★★★

Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.