Example #1
0
File: main.py Project: skeptycal/iv
class MainWindow(QMainWindow):
    def __init__(self, files):
        QMainWindow.__init__(self)
        sys.excepthook = self.excepthook
        self.profile = create_profile(files)
        self.view = View(self.profile, self)
        self.profile.setParent(self.view)
        self.view.set_title.connect(self.set_title)
        self.view.refresh_all.connect(self.refresh_all)
        self.setCentralWidget(self.view)
        self.files = files
        self.directories = {os.path.dirname(f['path']) for f in files.values()}
        self.file_watcher = QFileSystemWatcher(
            [f['path'] for f in files.values()] + list(self.directories), self)
        self.file_watcher.fileChanged.connect(self.file_changed,
                                              type=Qt.QueuedConnection)
        self.file_watcher.directoryChanged.connect(self.directory_changed,
                                                   type=Qt.QueuedConnection)
        self.changed_files = set()
        self.changed_dirs = set()
        self.debounce_files, self.debounce_dirs = QTimer(), QTimer()
        for t in self.debounce_files, self.debounce_dirs:
            t.setInterval(1000), t.setSingleShot(True)
        self.debounce_files.timeout.connect(self.do_file_changed)
        self.debounce_dirs.timeout.connect(self.do_dir_changed)
        self.set_title(None)

    def excepthook(self, exctype, value, traceback):
        if exctype == KeyboardInterrupt:
            return
        sys.__excepthook__(exctype, value, traceback)
        try:
            msg = str(value)
        except Exception:
            msg = repr(value)
        QMessageBox.critical(self, _('Unhandled error'), msg)

    def set_title(self, val):
        title = val or (_('{} images').format(len(self.files)))
        title += ' :: ' + appname
        self.setWindowTitle(title)

    def file_changed(self, path):
        if not os.access(path, os.R_OK):
            self.files.pop(path_to_url(path), None)
        self.changed_files.add(path)
        self.debounce_files.start()

    def directory_changed(self, path):
        self.changed_dirs.add(path)
        self.debounce_dirs.start()

    def do_file_changed(self):
        files, self.changed_files = self.changed_files, set()
        for path in files:
            url = path_to_url(path)
            if url in self.files:
                try:
                    self.view.image_changed(url, file_metadata(path))
                except EnvironmentError:
                    del self.files[url]

    def do_dir_changed(self):
        dirs, self.changed_dirs = self.changed_dirs, set()
        all_files = {f['path'] for f in self.files.values()}
        added_files = set()
        for path in dirs:
            for f in files_from_dir(path):
                if f not in all_files:
                    added_files.add(f)
        for f in added_files:
            try:
                self.files[path_to_url(f)] = file_metadata(f)
            except EnvironmentError:
                continue
            else:
                d = os.path.dirname(f)
                self.directories.add(d)
                self.file_watcher.addPaths([d, f])
        self.view.refresh_files(self.files)

    def refresh_all(self):
        roots = set()
        for d in sorted(self.directories):
            for r in roots:
                if d.startswith(r):
                    break
            else:
                roots.add(d)
        files = {}
        for cf in original_files:
            try:
                files[path_to_url(cf)] = file_metadata(cf)
            except EnvironmentError:
                continue
        for f in roots:
            for cf in files_from_dir(f):
                try:
                    files[path_to_url(cf)] = file_metadata(cf)
                except EnvironmentError:
                    continue
        self.files = files
        self.directories = {os.path.dirname(f['path']) for f in files.values()}
        self.view.refresh_files(self.files)