示例#1
0
class FilemanagerView(PidaView):

    _columns = [
        Column("icon_stock_id", use_stock=True),
        Column("state_markup", use_markup=True),
        Column("markup", use_markup=True),
        Column("lower_name", visible=False, searchable=True),
    ]

    label_text = _('Files')
    icon_name = 'file-manager'
    key = 'filemanager.list'

    def create_ui(self):
        self._vbox = gtk.VBox()
        self._vbox.show()
        self.create_toolbar()
        self._file_hidden_check_actions = {}
        self._create_file_hidden_check_toolbar()
        self.create_file_list()
        self._clipboard_file = None
        self._fix_paste_sensitivity()
        self.add_main_widget(self._vbox)

    def create_file_list(self):
        self.file_list = ObjectList()
        self.file_list.set_headers_visible(False)

        def visible_func(item):
            return item is not None and item.visible

        self.file_list.set_visible_func(visible_func)
        self.file_list.set_columns(self._columns)
        self.file_list.connect('selection-changed', self.on_selection_changed)
        self.file_list.connect('item-activated', self.on_file_activated)
        self.file_list.connect('item-right-clicked', self.on_file_right_click)
        self.entries = {}
        self.update_to_path(self.svc.path)
        self.file_list.show()

        self._file_scroll = gtk.ScrolledWindow(
            hadjustment=self.file_list.props.hadjustment,
            vadjustment=self.file_list.props.vadjustment,
        )
        self._file_scroll.set_policy(gtk.POLICY_AUTOMATIC,
                                     gtk.POLICY_AUTOMATIC)
        self._file_scroll.add(self.file_list)
        self._file_scroll.show()

        self._vbox.pack_start(self._file_scroll)
        self._sort_combo = AttrSortCombo(self.file_list, [
            ('is_dir_sort', _('Directories First')),
            ('path', _('File Path')),
            ('lower_name', _('File Name')),
            ('name', _('File Name (Case Sensitive)')),
            ('extension_sort', _('Extension')),
            ('state', _('Version Control Status')),
        ], 'is_dir_sort')
        self._sort_combo.show()
        self._vbox.pack_start(self._sort_combo, expand=False)
        self.on_selection_changed(self.file_list)

    def create_toolbar(self):
        self._uim = gtk.UIManager()
        self._uim.insert_action_group(self.svc.get_action_group(), 0)
        self._uim.add_ui_from_string(
            pkgutil.get_data(__name__, 'uidef/filemanager-toolbar.xml'))
        self._uim.ensure_update()
        self._toolbar = self._uim.get_toplevels('toolbar')[0]
        self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._toolbar.set_icon_size(gtk.ICON_SIZE_MENU)
        self._vbox.pack_start(self._toolbar, expand=False)
        self._toolbar.show_all()

    def add_or_update_file(self,
                           name,
                           basepath,
                           state,
                           select=False,
                           parent_link=False):
        if basepath != self.path and not parent_link:
            return
        entry = self.entries.setdefault(
            name, FileEntry(name, basepath, self, parent_link=parent_link))
        entry.state = state

        self.show_or_hide(entry, select=select)

    def show_or_hide(self, entry, select=False):
        def check(checker):
            if (checker.identifier in self._file_hidden_check_actions) and \
               (self._file_hidden_check_actions[checker.identifier].get_active()):
                return checker(
                    name=entry.name,
                    path=entry.parent_path,
                    state=entry.state,
                )
            else:
                return True

        if self.svc.opt('show_hidden') or entry.parent_link:
            show = True
        else:
            show = all(
                check(x) for x in self.svc.features['file_hidden_check'])

        entry.visible = show
        if entry not in self.file_list:
            self.file_list.append(entry)
        self.file_list.update(entry)

        if show and select:
            self.file_list.selected_item = entry

    def update_to_path(self, new_path=None, select=None):
        if new_path is None:
            new_path = self.path
        else:
            self.path = check_or_home(new_path)

        self.file_list.clear()
        self.entries.clear()

        if self.svc.opt('show_parent'):
            parent = os.path.normpath(os.path.join(new_path, os.path.pardir))
            # skip if we are already on the root
            if parent != new_path:
                self.add_or_update_file(os.pardir,
                                        parent,
                                        'normal',
                                        parent_link=True)

        def work(basepath):
            dir_content = listdir(basepath)
            # add all files from vcs and remove the corresponding items
            # from dir_content
            for item in self.svc.boss.cmd('versioncontrol',
                                          'list_file_states',
                                          path=self.path):
                if (item[1] == self.path):
                    try:
                        dir_content.remove(item[0])
                    except:
                        pass
                    yield item
            # handle remaining files
            for filename in dir_content:
                if (path.isdir(path.join(basepath, filename))):
                    state = 'normal'
                else:
                    state = 'unknown'
                yield filename, basepath, state

        # wrap add_or_update_file to set select accordingly
        def _add_or_update_file(name, basepath, state):
            self.add_or_update_file(name,
                                    basepath,
                                    state,
                                    select=(name == select))

        GeneratorTask(work, _add_or_update_file).start(self.path)

        self.create_ancest_tree()

    def update_single_file(self, name, basepath, select=False):
        if basepath != self.path:
            return
        if name not in self.entries:
            self.add_or_update_file(name, basepath, 'normal', select=select)

    def update_removed_file(self, filename):
        entry = self.entries.pop(filename, None)
        if entry is not None and entry.visible:
            self.file_list.remove(entry)

    def create_dir(self, name=None):
        if not name:
            #XXX: inputdialog or filechooser
            name = dialogs.input('Create New Directory',
                                 label=_("Directory name"))
        if name:
            npath = os.path.join(self.path, name)
            if not os.path.exists(npath):
                os.mkdir(npath)
            self.update_single_file(name, self.path, select=True)

    def on_file_activated(self, ol, fileentry):
        if os.path.exists(fileentry.path):
            if fileentry.is_dir:
                self.svc.browse(fileentry.path)
            else:
                self.svc.boss.cmd('buffer',
                                  'open_file',
                                  file_name=fileentry.path)
        else:
            self.update_removed_file(fileentry.name)

    def on_file_right_click(self, ol, item, event=None):
        if item.is_dir:
            self.svc.boss.cmd('contexts',
                              'popup_menu',
                              context='dir-menu',
                              dir_name=item.path,
                              event=event,
                              filemanager=True)
        else:
            self.svc.boss.cmd('contexts',
                              'popup_menu',
                              context='file-menu',
                              file_name=item.path,
                              event=event,
                              filemanager=True)

    def on_selection_changed(self, ol):
        for act_name in ['toolbar_copy', 'toolbar_delete']:
            self.svc.get_action(act_name).set_sensitive(
                ol.selected_item is not None)

    def rename_file(self, old, new, entry):
        print 'renaming', old, 'to', new

    def create_ancest_tree(self):
        task = AsyncTask(self._get_ancestors, self._show_ancestors)
        task.start(self.path)

    def _on_act_up_ancestor(self, action, directory):
        self.svc.browse(directory)

    def _show_ancestors(self, ancs):
        toolitem = self.svc.get_action('toolbar_up').get_proxies()[0]
        menu = gtk.Menu()
        for anc in ancs:
            action = gtk.Action(anc, anc, anc, 'directory')
            action.connect('activate', self._on_act_up_ancestor, anc)
            menuitem = action.create_menu_item()
            menu.add(menuitem)
        menu.show_all()
        toolitem.set_menu(menu)

    def _get_ancestors(self, directory):
        ancs = [directory]
        parent = None
        while True:
            parent = os.path.dirname(directory)
            if parent == directory:
                break
            ancs.append(parent)
            directory = parent
        return ancs

    def _on_act_file_hidden_check(self, action, check):
        if (check.scope == filehiddencheck.SCOPE_GLOBAL):
            # global
            active_checker = self.svc.opt('file_hidden_check')
            if (action.get_active()):
                active_checker.append(check.identifier)
            else:
                active_checker.remove(check.identifier)
            self.svc.set_opt('file_hidden_check', active_checker)
        else:
            # project
            if (self.svc.current_project is not None):
                section = self.svc.current_project.options.get(
                    'file_hidden_check', {})
                section[check.identifier] = action.get_active()
                self.svc.current_project.options['file_hidden_check'] = section
        self.update_to_path()

    def __file_hidden_check_scope_project_set_active(self, action):
        """sets active state of a file hidden check action with
           scope = project
           relies on action name = identifier of checker"""
        if (self.svc.current_project is not None):
            section = self.svc.current_project.options.get('file_hidden_check')
            action.set_active((section is not None)
                              and (action.get_name() in section)
                              and (section[action.get_name()] == 'True'))
        else:
            action.set_active(False)

    def refresh_file_hidden_check(self):
        """refreshes active status of actions of project scope checker"""
        for checker in self.svc.features['file_hidden_check']:
            if (checker.scope == filehiddencheck.SCOPE_PROJECT):
                action = self._file_hidden_check_actions[checker.identifier]
                self.__file_hidden_check_scope_project_set_active(action)

    def _create_file_hidden_check_toolbar(self):
        self._file_hidden_check_actions = {}
        menu = gtk.Menu()
        separator = gtk.SeparatorMenuItem()
        project_scope_count = 0
        menu.append(separator)
        for checker in self.svc.features['file_hidden_check']:
            action = gtk.ToggleAction(checker.identifier, checker.label,
                                      checker.label, None)
            # active?
            if (checker.scope == filehiddencheck.SCOPE_GLOBAL):
                action.set_active(
                    checker.identifier in self.svc.opt('file_hidden_check'))
            else:
                self.__file_hidden_check_scope_project_set_active(action)

            action.connect('activate', self._on_act_file_hidden_check, checker)
            self._file_hidden_check_actions[checker.identifier] = action
            menuitem = action.create_menu_item()
            if (checker.scope == filehiddencheck.SCOPE_GLOBAL):
                menu.prepend(menuitem)
            else:
                menu.append(menuitem)
                project_scope_count += 1
        menu.show_all()
        if (project_scope_count == 0):
            separator.hide()
        toolitem = None
        for proxy in self.svc.get_action('toolbar_hidden_menu').get_proxies():
            if (isinstance(proxy, DropDownMenuToolButton)):
                toolitem = proxy
                break
        if (toolitem is not None):
            toolitem.set_menu(menu)

    def get_selected_filename(self):
        fileentry = self.file_list.selected_item
        if fileentry is not None:
            return fileentry.path

    def copy_clipboard(self):
        current = self.get_selected_filename()
        if os.path.exists(current):
            self._clipboard_file = current
        else:
            self._clipboard_file = None
        self._fix_paste_sensitivity()

    def _fix_paste_sensitivity(self):
        self.svc.get_action('toolbar_paste').set_sensitive(
            self._clipboard_file is not None)

    def paste_clipboard(self):
        newname = os.path.join(self.path,
                               os.path.basename(self._clipboard_file))
        if newname == self._clipboard_file:
            self.svc.error_dlg(_('Cannot copy files to themselves.'))
            return
        if not os.path.exists(self._clipboard_file):
            self.svc.error_dlg(_('Source file has vanished.'))
            return
        if os.path.exists(newname):
            self.svc.error_dlg(_('Destination already exists.'))
            return

        task = AsyncTask(self._paste_clipboard, lambda: None)
        task.start()

    def _paste_clipboard(self):
        #XXX: in thread
        newname = os.path.join(self.path,
                               os.path.basename(self._clipboard_file))
        #XXX: GIO?
        if os.path.isdir(self._clipboard_file):
            shutil.copytree(self._clipboard_file, newname)
        else:
            shutil.copy2(self._clipboard_file, newname)

    def remove_path(self, path):
        task = AsyncTask(self._remove_path, lambda: None)
        task.start(path)

    def _remove_path(self, path):
        if os.path.isdir(path):
            shutil.rmtree(path)
        else:
            os.remove(path)
        if path == self._clipboard_file:
            self._clipboard_file = None
            gcall(self._fix_paste_sensitivity)
示例#2
0
class FilemanagerView(PidaView):

    _columns = [
        Column("icon_stock_id", use_stock=True),
        Column("state_markup", use_markup=True),
        Column("markup", use_markup=True),
        Column("lower_name", visible=False, searchable=True),
        ]

    label_text = _('Files')
    icon_name = 'file-manager'
    key = 'filemanager.list'

    def create_ui(self):
        self._vbox = gtk.VBox()
        self._vbox.show()
        self.create_toolbar()
        self._file_hidden_check_actions = {}
        self._create_file_hidden_check_toolbar()
        self.create_file_list()
        self._clipboard_file = None
        self._fix_paste_sensitivity()
        self.add_main_widget(self._vbox)

    def create_file_list(self):
        self.file_list = ObjectList()
        self.file_list.set_headers_visible(False)

        def visible_func(item):
            return item is not None and item.visible
        self.file_list.set_visible_func(visible_func)
        self.file_list.set_columns(self._columns);
        self.file_list.connect('selection-changed', self.on_selection_changed)
        self.file_list.connect('item-activated', self.on_file_activated)
        self.file_list.connect('item-right-clicked', self.on_file_right_click)
        self.entries = {}
        self.update_to_path(self.svc.path)
        self.file_list.show()

        self._file_scroll = gtk.ScrolledWindow(
                hadjustment=self.file_list.props.hadjustment,
                vadjustment=self.file_list.props.vadjustment,
                )
        self._file_scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        self._file_scroll.add(self.file_list)
        self._file_scroll.show()

        self._vbox.pack_start(self._file_scroll)
        self._sort_combo = AttrSortCombo(self.file_list,
            [
                ('is_dir_sort', _('Directories First')),
                ('path', _('File Path')),
                ('lower_name', _('File Name')),
                ('name', _('File Name (Case Sensitive)')),
                ('extension_sort', _('Extension')),
                ('state', _('Version Control Status')),
            ],
            'is_dir_sort')
        self._sort_combo.show()
        self._vbox.pack_start(self._sort_combo, expand=False)
        self.on_selection_changed(self.file_list)

    def create_toolbar(self):
        self._uim = gtk.UIManager()
        self._uim.insert_action_group(self.svc.get_action_group(), 0)
        self._uim.add_ui_from_string(
                pkgutil.get_data(
                    __name__,
                    'uidef/filemanager-toolbar.xml'))
        self._uim.ensure_update()
        self._toolbar = self._uim.get_toplevels('toolbar')[0]
        self._toolbar.set_style(gtk.TOOLBAR_ICONS)
        self._toolbar.set_icon_size(gtk.ICON_SIZE_MENU)
        self._vbox.pack_start(self._toolbar, expand=False)
        self._toolbar.show_all()

    def add_or_update_file(self, name, basepath, state, select=False,
                           parent_link=False):
        if basepath != self.path and not parent_link:
            return
        entry = self.entries.setdefault(name,
                                        FileEntry(name, basepath, self,
                                                  parent_link=parent_link))
        entry.state = state

        self.show_or_hide(entry, select=select)

    def show_or_hide(self, entry, select=False):
        def check(checker):
            if (checker.identifier in self._file_hidden_check_actions) and \
               (self._file_hidden_check_actions[checker.identifier].get_active()):
                return checker(name=entry.name, path=entry.parent_path,
                    state=entry.state, )
            else:
                return True

        if self.svc.opt('show_hidden') or entry.parent_link:
            show = True
        else:
            show = all(check(x)
                        for x in self.svc.features['file_hidden_check'])

        entry.visible = show
        if entry not in self.file_list:
            self.file_list.append(entry)
        self.file_list.update(entry)

        if show and select:
            self.file_list.selected_item = entry

    def update_to_path(self, new_path=None, select=None):
        if new_path is None:
            new_path = self.path
        else:
            self.path = check_or_home(new_path)

        self.file_list.clear()
        self.entries.clear()

        if self.svc.opt('show_parent'):
            parent = os.path.normpath(os.path.join(new_path, os.path.pardir))
            # skip if we are already on the root
            if parent != new_path:
                self.add_or_update_file(os.pardir, parent, 
                                        'normal', parent_link=True)

        def work(basepath):
            dir_content = listdir(basepath)
            # add all files from vcs and remove the corresponding items 
            # from dir_content
            for item in self.svc.boss.cmd('versioncontrol', 'list_file_states',
              path=self.path):
                if (item[1] == self.path):
                    try:
                        dir_content.remove(item[0])
                    except:
                        pass
                    yield item
            # handle remaining files
            for filename in dir_content:
                if (path.isdir(path.join(basepath, filename))):
                    state = 'normal'
                else:
                    state = 'unknown'
                yield filename, basepath, state

        # wrap add_or_update_file to set select accordingly
        def _add_or_update_file(name, basepath, state):
            self.add_or_update_file(name, basepath, state, select=(name==select))

        GeneratorTask(work, _add_or_update_file).start(self.path)

        self.create_ancest_tree()

    def update_single_file(self, name, basepath, select=False):
        if basepath != self.path:
            return
        if name not in self.entries:
            self.add_or_update_file(name, basepath, 'normal', select=select)

    def update_removed_file(self, filename):
        entry = self.entries.pop(filename, None)
        if entry is not None and entry.visible:
            self.file_list.remove(entry)

    def create_dir(self, name=None):
        if not name:
            #XXX: inputdialog or filechooser
            name = dialogs.input('Create New Directory',
                                 label=_("Directory name"))
        if name:
            npath = os.path.join(self.path, name)
            if not os.path.exists(npath):
                os.mkdir(npath)
            self.update_single_file(name, self.path, select=True)

    def on_file_activated(self, ol, fileentry):
        if os.path.exists(fileentry.path): 
            if fileentry.is_dir: 
                self.svc.browse(fileentry.path)
            else:
                self.svc.boss.cmd('buffer', 'open_file', file_name=fileentry.path)
        else:
            self.update_removed_file(fileentry.name)

    def on_file_right_click(self, ol, item, event=None):
        if item.is_dir: 
            self.svc.boss.cmd('contexts', 'popup_menu', context='dir-menu',
                          dir_name=item.path, event=event, filemanager=True) 
        else:
            self.svc.boss.cmd('contexts', 'popup_menu', context='file-menu',
                          file_name=item.path, event=event, filemanager=True)

    def on_selection_changed(self, ol):
        for act_name in ['toolbar_copy',  'toolbar_delete']:
            self.svc.get_action(act_name).set_sensitive(ol.selected_item is not None)

    def rename_file(self, old, new, entry):
        print 'renaming', old, 'to' ,new

    def create_ancest_tree(self):
        task = AsyncTask(self._get_ancestors, self._show_ancestors)
        task.start(self.path)

    def _on_act_up_ancestor(self, action, directory):
        self.svc.browse(directory)

    def _show_ancestors(self, ancs):
        toolitem = self.svc.get_action('toolbar_up').get_proxies()[0]
        menu = gtk.Menu()
        for anc in ancs:
            action = gtk.Action(anc, anc, anc, 'directory')
            action.connect('activate', self._on_act_up_ancestor, anc)
            menuitem = action.create_menu_item()
            menu.add(menuitem)
        menu.show_all()
        toolitem.set_menu(menu)

    def _get_ancestors(self, directory):
        ancs = [directory]
        parent = None
        while True:
            parent = os.path.dirname(directory)
            if parent == directory:
                break
            ancs.append(parent)
            directory = parent
        return ancs

    def _on_act_file_hidden_check(self, action, check):
        if (check.scope == filehiddencheck.SCOPE_GLOBAL):
            # global
            active_checker = self.svc.opt('file_hidden_check')
            if (action.get_active()):
                active_checker.append(check.identifier)
            else:
                active_checker.remove(check.identifier)
            self.svc.set_opt('file_hidden_check', active_checker)
        else:
            # project
            if (self.svc.current_project is not None):
                section = self.svc.current_project.options.get('file_hidden_check', {})
                section[check.identifier] = action.get_active()
                self.svc.current_project.options['file_hidden_check'] = section
        self.update_to_path()
    
    def __file_hidden_check_scope_project_set_active(self, action):
        """sets active state of a file hidden check action with
           scope = project
           relies on action name = identifier of checker"""
        if (self.svc.current_project is not None):
            section = self.svc.current_project.options.get('file_hidden_check')
            action.set_active(
              (section is not None) and
              (action.get_name() in section) and
              (section[action.get_name()] == 'True'))
        else:
            action.set_active(False)
        
    
    def refresh_file_hidden_check(self):
        """refreshes active status of actions of project scope checker"""
        for checker in self.svc.features['file_hidden_check']:
            if (checker.scope == filehiddencheck.SCOPE_PROJECT):
                action = self._file_hidden_check_actions[checker.identifier]
                self.__file_hidden_check_scope_project_set_active(action)
    
    def _create_file_hidden_check_toolbar(self):
        self._file_hidden_check_actions = {}
        menu = gtk.Menu()
        separator = gtk.SeparatorMenuItem()
        project_scope_count = 0
        menu.append(separator)
        for checker in self.svc.features['file_hidden_check']:
            action = gtk.ToggleAction(checker.identifier, checker.label,
              checker.label, None)
            # active?
            if (checker.scope == filehiddencheck.SCOPE_GLOBAL):
                action.set_active(
                    checker.identifier in self.svc.opt('file_hidden_check'))
            else:
                self.__file_hidden_check_scope_project_set_active(action)

            action.connect('activate', self._on_act_file_hidden_check, checker)
            self._file_hidden_check_actions[checker.identifier] = action
            menuitem = action.create_menu_item()
            if (checker.scope == filehiddencheck.SCOPE_GLOBAL):
                menu.prepend(menuitem)
            else:
                menu.append(menuitem)
                project_scope_count += 1
        menu.show_all()
        if (project_scope_count == 0):
            separator.hide()
        toolitem = None
        for proxy in self.svc.get_action('toolbar_hidden_menu').get_proxies():
            if (isinstance(proxy, DropDownMenuToolButton)):
                toolitem = proxy
                break
        if (toolitem is not None):
            toolitem.set_menu(menu)

    def get_selected_filename(self):
        fileentry = self.file_list.selected_item
        if fileentry is not None:
            return fileentry.path

    def copy_clipboard(self):
        current = self.get_selected_filename()
        if os.path.exists(current):
            self._clipboard_file = current
        else:
            self._clipboard_file = None
        self._fix_paste_sensitivity()

    def _fix_paste_sensitivity(self):
        self.svc.get_action('toolbar_paste').set_sensitive(self._clipboard_file
                                                           is not None)

    def paste_clipboard(self):
        newname = os.path.join(self.path, os.path.basename(self._clipboard_file))
        if newname == self._clipboard_file:
            self.svc.error_dlg(_('Cannot copy files to themselves.'))
            return
        if not os.path.exists(self._clipboard_file):
            self.svc.error_dlg(_('Source file has vanished.'))
            return
        if os.path.exists(newname):
            self.svc.error_dlg(_('Destination already exists.'))
            return
        
        task = AsyncTask(self._paste_clipboard, lambda: None)
        task.start()

    def _paste_clipboard(self):
        #XXX: in thread
        newname = os.path.join(self.path, os.path.basename(self._clipboard_file))
        #XXX: GIO?
        if os.path.isdir(self._clipboard_file):
            shutil.copytree(self._clipboard_file, newname)
        else:
            shutil.copy2(self._clipboard_file, newname)

    def remove_path(self, path):
        task = AsyncTask(self._remove_path, lambda: None)
        task.start(path)

    def _remove_path(self, path):
        if os.path.isdir(path):
            shutil.rmtree(path)
        else:
            os.remove(path)
        if path == self._clipboard_file:
            self._clipboard_file = None
            gcall(self._fix_paste_sensitivity)