class ProjectListView(PidaView): key = 'project.list' builder_file = 'project_list' locale = locale label_text = _('Projects') icon_name = 'package_utilities' def create_ui(self): self.project_ol.set_columns( [Column(title='Ignored', mappers=[project_mapper])]) self._sort_combo = AttrSortCombo(self.project_ol, [ ('display_name', 'Name'), ('source_directory', 'Full Path'), ('name', 'Directory Name'), ], 'display_name') self._sort_combo.show() self.main_vbox.pack_start(self._sort_combo, expand=False) def on_project_ol__selection_changed(self, ol): self.svc.set_current_project(ol.selected_item) def on_project_ol__item_activated(self, ol, project): self.svc.boss.cmd('filemanager', 'browse', new_path=project.source_directory) self.svc.boss.cmd('filemanager', 'present_view') def on_project_ol__item_right_clicked(self, ol, project, event): self.svc.boss.cmd('contexts', 'popup_menu', context='dir-menu', dir_name=project.source_directory, event=event, project=project) def set_current_project(self, project): self.project_ol.selected_item = project def update_project(self, project): self.project_ol.update(project) def remove(self, project): # each may be None, we get the desired behavior in all cases # desired = if not first item select the one before # else try to select the one after # if empty select none before = self.project_ol.item_before(project) after = self.project_ol.item_after(project) self.project_ol.selected_item = before or after self.project_ol.remove(project) def can_be_closed(self): self.svc.get_action('project_properties').set_active(False)
class ProjectListView(PidaView): key = 'project.list' builder_file = 'project_list' locale = locale label_text = _('Projects') icon_name = 'package_utilities' def create_ui(self): self.project_ol.set_columns([ Column(title='Ignored', mappers=[project_mapper]) ]) self._sort_combo = AttrSortCombo(self.project_ol, [ ('display_name', 'Name'), ('source_directory', 'Full Path'), ('name', 'Directory Name'), ], 'display_name') self._sort_combo.show() self.main_vbox.pack_start(self._sort_combo, expand=False) def on_project_ol__selection_changed(self, ol): self.svc.set_current_project(ol.selected_item) def on_project_ol__item_activated(self, ol, project): self.svc.boss.cmd('filemanager', 'browse', new_path=project.source_directory) self.svc.boss.cmd('filemanager', 'present_view') def on_project_ol__item_right_clicked(self, ol, project, event): self.svc.boss.cmd('contexts', 'popup_menu', context='dir-menu', dir_name=project.source_directory, event=event, project=project) def set_current_project(self, project): self.project_ol.selected_item = project def update_project(self, project): self.project_ol.update(project) def remove(self, project): # each may be None, we get the desired behavior in all cases # desired = if not first item select the one before # else try to select the one after # if empty select none before = self.project_ol.item_before(project) after = self.project_ol.item_after(project) self.project_ol.selected_item = before or after self.project_ol.remove(project) def can_be_closed(self): self.svc.get_action('project_properties').set_active(False)
class BrowserView(PidaView): """ Window with the outliner """ key = 'language.browser' builder_file = 'outline_browser' locale = locale icon_name = 'python-icon' label_text = _('Outliner') def create_ui(self): self.document = None self.tasks = {} self.restart = False self.source_tree.set_columns([ Column(title='name', cells=[ Cell('icon_name', use_stock=True), Cell('markup', use_markup=True, expand=True) ]), Column('type_markup', use_markup=True), Column('sort_by_type_by_name', visible=False), Column('sort_by_type_by_line', visible=False), Column('sort_by_line', visible=False), ]) self.source_tree.set_headers_visible(False) # faster lookups on the id property self.source_tree_ids = {} self.sort_box = AttrSortCombo(self.source_tree, [ ('sort_by_type_by_name', _('Alphabetical by type')), ('sort_by_type_by_line', _('By type by line number')), ('sort_by_line', _('By line number')), ], 'sort_by_type_by_name') self.sort_box.show() self.sort_vbox.pack_start(self.sort_box, expand=False) self.filter_model = self.source_tree.model_filter #FIXME this causes a total crash on win32 self.source_tree.set_visible_func(self._visible_func) self._last_expanded = None self._last_outliner = None def _visible_func(self, node): # FIXME: None objects shouldn't be here, but why ???? if not node: return False ftext = self.filter_name.get_text().lower() #riter = model.convert_child_iter_to_iter(iter) # name filter def if_type(inode): # type filter if inode.filter_type in self.filter_map: if self.filter_map[inode.filter_type]: return True else: return False else: return True if ftext: # we have to test if any children of the current node may match def any_child(parent): if not parent: return False for i in xrange(model.iter_n_children(parent)): child = model.iter_nth_child(parent, i) cnode = model[child][0] if cnode and cnode.name.lower().find( ftext) != -1 and if_type(cnode): return True if model.iter_has_child(child) and any_child(child): return True return False if (node.name and node.name.lower().find(ftext) != -1) or \ (model.iter_has_child(iter_) and any_child(iter_)): return if_type(node) return False return if_type(node) def set_outliner(self, outliner, document): # see comments on set_validator old = self.tasks.get(self.document, None) if old: old.priority = PRIO_DEFAULT self.document = document self.clear() if document in self.tasks: # set the priority of the current validator higher, so it feels # faster on the current view if self.svc.boss.window.paned.is_visible_pane(self.pane): prio = PRIO_FOREGROUND else: prio = PRIO_DEFAULT self.tasks[document].priorty = prio # when restart is set, the set_validator is run again so the # list gets updated from the validator cache. this happens when # the buffer switched to another file and back again self.restart = True self.svc.log.debug(_('Outliner task for {doc} already running'), doc=document) return self.restart = False if outliner: # if self.task: # self.task.stop() # self.task = GeneratorTask(outliner.get_outline_cached, self.add_node) # self.task.start() def wrap_add_node(document, *args): # we need this proxy function as a task may be still running in # background and the document already switched # this way we still can fill up the cache by letting the task run # sometimes args have a lengh of 0 so we have to catch this if self.document == document and args: self.add_node(*args) def on_complete(document, outliner): del self.tasks[document] outliner.sync() # fire refilter so the list is updated after buffer changed self.filter_model.refilter() # refire the task and hope the cache will just display stuff, # elsewise the task is run again if document == self.document and self.restart: self.set_outliner(outliner, document) radd = partial(wrap_add_node, document) rcomp = partial(on_complete, document, outliner) if self.svc.boss.window.paned.is_visible_pane(self.pane): prio = PRIO_FOREGROUND else: prio = PRIO_DEFAULT task = GeneratorTask(outliner.run_cached, radd, complete_callback=rcomp, priority=prio) self.tasks[document] = task task.start() def clear(self): self.source_tree.clear() self.source_tree_ids = {} def get_by_id(self, id_): """ Return the OutlinerItem by it's id property """ def lookup(model, path, iter): if model.get_value(iter, 0).id == id_: lookup.rv = model.get_value(iter, 0) return True self.source_tree.get_model().foreach(lookup) return getattr(lookup, 'rv', None) def add_node(self, node): if not node: return if node.id: self.source_tree_ids[node.id] = node if node.parent_id: try: parent = self.source_tree_ids[node.parent_id] except KeyError: # try a deep lookup parent = self.get_by_id(node.parent_id) else: parent = None try: self.source_tree.append(node, parent=parent) except Exception as e: self.log.exception(e) def can_be_closed(self): self.svc.get_action('show_outliner').set_active(False) def on_source_tree__item_activated(self, ol, item): if item.filename is not None: self.svc.boss.cmd('buffer', 'open_file', file_name=item.filename, line=item.linenumber) self.svc.boss.editor.cmd('grab_focus') elif item.linenumber: self.svc.boss.editor.cmd('goto_line', line=item.linenumber) self.svc.boss.editor.cmd('grab_focus') def update_filterview(self, outliner): if outliner is None: return if ((outliner and not self._last_outliner) or (self._last_outliner and self._last_outliner.name != outliner.name)): self._last_outliner = outliner def rmchild(widget): self.filter_toolbar.remove(widget) self.filter_toolbar.foreach(rmchild) self.filter_map = dict([(f, FILTERMAP[f]['default']) for f in outliner.filter_type]) for f in self.filter_map: tool_button = gtk.ToggleToolButton() tool_button.set_data('pida/outliner', f) tool_button.set_active(self.filter_map[f]) #FIXME no tooltip on win32 if not on_windows: tool_button.set_tooltip_text(FILTERMAP[f]['display']) tool_button.connect("toggled", self.on_filter_toggled, outliner) image_name = FILTERMAP[f]['icon'] #XXX: put into pygtkhelpers? image_data = pkgutil.get_data(__name__, 'pixmaps/%s.png' % image_name) loader = gtk.gdk.PixbufLoader() loader.write(image_data) loader.close() im = gtk.Image() im.set_from_pixbuf(loader.get_pixbuf()) tool_button.set_icon_widget(im) self.filter_toolbar.insert(tool_button, 0) #self.options_vbox.add(self.filter_toolbar) self.options_vbox.show_all() def on_filter_toggled(self, but, outliner): name = but.get_data('pida/outliner') self.filter_map[name] = not self.filter_map[name] #self.set_outliner(outliner, self.document) self.filter_model.refilter() def on_filter_name_clear__clicked(self, widget): self.filter_name.set_text('') def on_filter_name__changed(self, widget): if len(widget.get_text()) >= self.svc.opt('outline_expand_vars'): for i in self.source_tree: self.source_tree.expand(i, open_all=True) else: for i in self.source_tree: self.source_tree.collapse_item(i) self.filter_model.refilter() def on_source_tree__key_press_event(self, tree, event): if event.keyval == gtk.keysyms.space: # FIXME: how to do this right ?? cur = self.source_tree.selected_item if self._last_expanded == cur: self._last_expanded = None self.source_tree.collapse_item(cur) else: self.source_tree.expand_item(cur, open_all=False) self._last_expanded = cur return True def on_type_changed(self): pass
class ValidatorView(PidaView): key = 'language.validator' icon_name = 'python-icon' label_text = _('Validator') def create_ui(self): self._last_selected = None self.document = None self.tasks = {} self.restart = False self.errors_ol = ObjectList([Column('markup', use_markup=True)]) self.errors_ol.set_headers_visible(False) self.scrolled_window = gtk.ScrolledWindow() self.scrolled_window.show() self.scrolled_window.add(self.errors_ol) self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.add_main_widget(self.scrolled_window) self.errors_ol.show_all() self.sort_combo = AttrSortCombo( self.errors_ol, [ ('lineno', _('Line Number')), ('message', _('Message')), ('type_', _('Type')), ], 'lineno', ) self.sort_combo.show() self.add_main_widget(self.sort_combo, expand=False) def set_validator(self, validator, document): # this is quite an act we have to do here because of the many cornercases # 1. Jobs once started run through. This is for caching purpuses as a validator # is supposed to cache results, somehow. # 2. buffers can switch quite often and n background jobs are still # running # set the old task job to default priorty again old = self.tasks.get(self.document, None) if old: old.priority = PRIO_LOW self.document = document self.clear() if self.tasks.has_key(document): # set the priority of the current validator higher, so it feels # faster on the current view if self.svc.boss.window.paned.is_visible_pane(self.pane): prio = PRIO_FOREGROUND else: prio = PRIO_DEFAULT self.tasks[document].priorty = prio # when restart is set, the set_validator is run again so the # list gets updated from the validator cache. this happens when # the buffer switched to another file and back again self.restart = True self.svc.log.debug(_('Validator task for {doc} already running'), doc=document) return self.restart = False if validator: def wrap_add_node(document, *args): # we need this proxy function as a task may be still running in # background and the document already switched # this way we still can fill up the cache by letting the task run # sometimes args have a lengh of 0 so we have to catch this if self.document == document and args: item = args[0] self.add_node(item) if self._last_selected: if self._last_selected[0] == self.document: if item.lineno == self._last_selected[1]: self.errors_ol.selected_item = item def on_complete(document, validator): del self.tasks[document] # refire the task and hope the cache will just display stuff, # elsewise the task is run again validator.sync() if document == self.document and self.restart: self.set_validator(validator, document) radd = partial(wrap_add_node, document) rcomp = partial(on_complete, document, validator) if self.svc.boss.window.paned.is_visible_pane(self.pane): prio = PRIO_FOREGROUND else: prio = PRIO_DEFAULT task = GeneratorTask(validator.run_cached, radd, complete_callback=rcomp, priority=prio) self.tasks[document] = task task.start() def add_node(self, node): if node: node.lookup_color = self.errors_ol.style.lookup_color self.errors_ol.append(node) def clear(self): self.errors_ol.clear() def on_errors_ol__selection_changed(self, ol): item = ol.selected_item # may be None self._last_selected = (self.document, getattr(item, 'lineno', 0)) def on_errors_ol__item_activated(self, ol, item): self.svc.boss.editor.cmd('goto_line', line=int(item.lineno)) def can_be_closed(self): self.svc.get_action('show_validator').set_active(False)
class BrowserView(PidaView): """ Window with the outliner """ key = 'language.browser' builder_file = 'outline_browser' locale = locale icon_name = 'python-icon' label_text = _('Outliner') def create_ui(self): self.document = None self.tasks = {} self.restart = False self.source_tree.set_columns([ Column(title='name', cells=[ Cell('icon_name', use_stock=True), Cell('markup', use_markup=True, expand=True)]), Column('type_markup', use_markup=True), Column('sort_by_type_by_name', visible=False), Column('sort_by_type_by_line', visible=False), Column('sort_by_line', visible=False), ]) self.source_tree.set_headers_visible(False) # faster lookups on the id property self.source_tree_ids = {} self.sort_box = AttrSortCombo( self.source_tree, [ ('sort_by_type_by_name', _('Alphabetical by type')), ('sort_by_type_by_line', _('By type by line number')), ('sort_by_line', _('By line number')), ], 'sort_by_type_by_name' ) self.sort_box.show() self.sort_vbox.pack_start(self.sort_box, expand=False) self.filter_model = self.source_tree.model_filter #FIXME this causes a total crash on win32 self.source_tree.set_visible_func(self._visible_func) self._last_expanded = None self._last_outliner = None def _visible_func(self, node): # FIXME: None objects shouldn't be here, but why ???? if not node: return False ftext = self.filter_name.get_text().lower() #riter = model.convert_child_iter_to_iter(iter) # name filter def if_type(inode): # type filter if inode.filter_type in self.filter_map: if self.filter_map[inode.filter_type]: return True else: return False else: return True if ftext: # we have to test if any children of the current node may match def any_child(parent): if not parent: return False for i in xrange(model.iter_n_children(parent)): child = model.iter_nth_child(parent, i) cnode = model[child][0] if cnode and cnode.name.lower().find(ftext) != -1 and if_type(cnode): return True if model.iter_has_child(child) and any_child(child): return True return False if (node.name and node.name.lower().find(ftext) != -1) or \ (model.iter_has_child(iter_) and any_child(iter_)): return if_type(node) return False return if_type(node) def set_outliner(self, outliner, document): # see comments on set_validator old = self.tasks.get(self.document, None) if old: old.priority = PRIO_DEFAULT self.document = document self.clear() if document in self.tasks: # set the priority of the current validator higher, so it feels # faster on the current view if self.svc.boss.window.paned.is_visible_pane(self.pane): prio = PRIO_FOREGROUND else: prio = PRIO_DEFAULT self.tasks[document].priorty = prio # when restart is set, the set_validator is run again so the # list gets updated from the validator cache. this happens when # the buffer switched to another file and back again self.restart = True self.svc.log.debug(_('Outliner task for {doc} already running'), doc=document) return self.restart = False if outliner: # if self.task: # self.task.stop() # self.task = GeneratorTask(outliner.get_outline_cached, self.add_node) # self.task.start() def wrap_add_node(document, *args): # we need this proxy function as a task may be still running in # background and the document already switched # this way we still can fill up the cache by letting the task run # sometimes args have a lengh of 0 so we have to catch this if self.document == document and args: self.add_node(*args) def on_complete(document, outliner): del self.tasks[document] outliner.sync() # fire refilter so the list is updated after buffer changed self.filter_model.refilter() # refire the task and hope the cache will just display stuff, # elsewise the task is run again if document == self.document and self.restart: self.set_outliner(outliner, document) radd = partial(wrap_add_node, document) rcomp = partial(on_complete, document, outliner) if self.svc.boss.window.paned.is_visible_pane(self.pane): prio = PRIO_FOREGROUND else: prio = PRIO_DEFAULT task = GeneratorTask(outliner.run_cached, radd, complete_callback=rcomp, priority=prio) self.tasks[document] = task task.start() def clear(self): self.source_tree.clear() self.source_tree_ids = {} def get_by_id(self, id_): """ Return the OutlinerItem by it's id property """ def lookup(model, path, iter): if model.get_value(iter, 0).id == id_: lookup.rv = model.get_value(iter, 0) return True self.source_tree.get_model().foreach(lookup) return getattr(lookup, 'rv', None) def add_node(self, node): if not node: return if node.id: self.source_tree_ids[node.id] = node if node.parent_id: try: parent = self.source_tree_ids[node.parent_id] except KeyError: # try a deep lookup parent = self.get_by_id(node.parent_id) else: parent = None try: self.source_tree.append(node, parent=parent) except Exception as e: self.log.exception(e) def can_be_closed(self): self.svc.get_action('show_outliner').set_active(False) def on_source_tree__item_activated(self, ol, item): if item.filename is not None: self.svc.boss.cmd('buffer', 'open_file', file_name=item.filename, line=item.linenumber) self.svc.boss.editor.cmd('grab_focus') elif item.linenumber: self.svc.boss.editor.cmd('goto_line', line=item.linenumber) self.svc.boss.editor.cmd('grab_focus') def update_filterview(self, outliner): if outliner is None: return if ((outliner and not self._last_outliner) or (self._last_outliner and self._last_outliner.name != outliner.name)): self._last_outliner = outliner def rmchild(widget): self.filter_toolbar.remove(widget) self.filter_toolbar.foreach(rmchild) self.filter_map = dict( [(f, FILTERMAP[f]['default']) for f in outliner.filter_type] ) for f in self.filter_map: tool_button = gtk.ToggleToolButton() tool_button.set_data('pida/outliner', f) tool_button.set_active(self.filter_map[f]) #FIXME no tooltip on win32 if not on_windows: tool_button.set_tooltip_text(FILTERMAP[f]['display']) tool_button.connect("toggled", self.on_filter_toggled, outliner) image_name = FILTERMAP[f]['icon'] #XXX: put into pygtkhelpers? image_data = pkgutil.get_data(__name__, 'pixmaps/%s.png' % image_name) loader = gtk.gdk.PixbufLoader() loader.write(image_data) loader.close() im = gtk.Image() im.set_from_pixbuf(loader.get_pixbuf()) tool_button.set_icon_widget(im) self.filter_toolbar.insert(tool_button, 0) #self.options_vbox.add(self.filter_toolbar) self.options_vbox.show_all() def on_filter_toggled(self, but, outliner): name = but.get_data('pida/outliner') self.filter_map[name] = not self.filter_map[name] #self.set_outliner(outliner, self.document) self.filter_model.refilter() def on_filter_name_clear__clicked(self, widget): self.filter_name.set_text('') def on_filter_name__changed(self, widget): if len(widget.get_text()) >= self.svc.opt('outline_expand_vars'): for i in self.source_tree: self.source_tree.expand( i, open_all=True) else: for i in self.source_tree: self.source_tree.collapse_item(i) self.filter_model.refilter() def on_source_tree__key_press_event(self, tree, event): if event.keyval == gtk.keysyms.space: # FIXME: how to do this right ?? cur = self.source_tree.selected_item if self._last_expanded == cur: self._last_expanded = None self.source_tree.collapse_item(cur) else: self.source_tree.expand_item(cur, open_all=False) self._last_expanded = cur return True def on_type_changed(self): pass
class ValidatorView(PidaView): key = 'language.validator' icon_name = 'python-icon' label_text = _('Validator') def create_ui(self): self._last_selected = None self.document = None self.tasks = {} self.restart = False self.errors_ol = ObjectList([ Column('markup', use_markup=True) ]) self.errors_ol.set_headers_visible(False) self.scrolled_window = gtk.ScrolledWindow() self.scrolled_window.show() self.scrolled_window.add(self.errors_ol) self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.add_main_widget(self.scrolled_window) self.errors_ol.show_all() self.sort_combo = AttrSortCombo( self.errors_ol, [ ('lineno', _('Line Number')), ('message', _('Message')), ('type_', _('Type')), ], 'lineno', ) self.sort_combo.show() self.add_main_widget(self.sort_combo, expand=False) def set_validator(self, validator, document): # this is quite an act we have to do here because of the many cornercases # 1. Jobs once started run through. This is for caching purpuses as a validator # is supposed to cache results, somehow. # 2. buffers can switch quite often and n background jobs are still # running # set the old task job to default priorty again old = self.tasks.get(self.document, None) if old: old.priority = PRIO_LOW self.document = document self.clear() if self.tasks.has_key(document): # set the priority of the current validator higher, so it feels # faster on the current view if self.svc.boss.window.paned.is_visible_pane(self.pane): prio = PRIO_FOREGROUND else: prio = PRIO_DEFAULT self.tasks[document].priorty = prio # when restart is set, the set_validator is run again so the # list gets updated from the validator cache. this happens when # the buffer switched to another file and back again self.restart = True self.svc.log.debug(_('Validator task for {doc} already running'), doc=document) return self.restart = False if validator: def wrap_add_node(document, *args): # we need this proxy function as a task may be still running in # background and the document already switched # this way we still can fill up the cache by letting the task run # sometimes args have a lengh of 0 so we have to catch this if self.document == document and args: item = args[0] self.add_node(item) if self._last_selected: if self._last_selected[0] == self.document: if item.lineno == self._last_selected[1]: self.errors_ol.selected_item = item def on_complete(document, validator): del self.tasks[document] # refire the task and hope the cache will just display stuff, # elsewise the task is run again validator.sync() if document == self.document and self.restart: self.set_validator(validator, document) radd = partial(wrap_add_node, document) rcomp = partial(on_complete, document, validator) if self.svc.boss.window.paned.is_visible_pane(self. pane): prio = PRIO_FOREGROUND else: prio = PRIO_DEFAULT task = GeneratorTask(validator.run_cached, radd, complete_callback=rcomp, priority=prio) self.tasks[document] = task task.start() def add_node(self, node): if node: node.lookup_color = self.errors_ol.style.lookup_color self.errors_ol.append(node) def clear(self): self.errors_ol.clear() def on_errors_ol__selection_changed(self, ol): item = ol.selected_item # may be None self._last_selected = (self.document, getattr(item, 'lineno', 0)) def on_errors_ol__item_activated(self, ol, item): self.svc.boss.editor.cmd('goto_line', line=int(item.lineno)) def can_be_closed(self): self.svc.get_action('show_validator').set_active(False)
class BufferListView(PidaView): key = 'buffer.list' builder_file = 'buffer_list' locale = locale icon_name = 'package_office' label_text = _('Buffers') def create_ui(self): self.buffers_ol.set_columns([ Column('markup', cells=[ Cell(None, use_markup=True, mappers=[partial(render, markup='onerow')]) ]), Column('markup_tworow', visible=False, cells=[ Cell(None, use_markup=True, mappers=[partial(render, markup='tworow')]) ]), Column("basename", visible=False, searchable=True), ]) self.buffers_ol.set_headers_visible(False) self._sort_combo = AttrSortCombo(self.buffers_ol, [ ('creation_time', _('Time Opened')), ('filename', _('File path')), ('basename', _('File name')), ('doctype', _('Document Type')), ('mimetype', _('Mime Type')), ('length', _('File Length')), ('modified_time', _('Last Modified')), ('usage', _('View Counter')), ('last_opend', _('Last Opened')), #('Project', _('Project_name')) ], 'creation_time' ) self._sort_combo.show() self.toplevel.pack_start(self._sort_combo, expand=False) def add_document(self, document): self.buffers_ol.append(document) def remove_document(self, document): self.buffers_ol.remove(document) def set_document(self, document): if self.buffers_ol.selected_item is not document: self.buffers_ol.selected_item = document def view_document(self, document): self.svc.view_document(document) self.svc.boss.editor.cmd('grab_focus') def on_buffers_ol__item_double_clicked(self, ol, item, ev=None): self.view_document(item) def on_buffers_ol__item_activated(self, ol, item): self.view_document(item) def on_buffers_ol__item_right_clicked(self, ol, item, event=None): menu = self.svc.boss.cmd('contexts', 'get_menu', context='file-menu', document=item, file_name=item.filename) # Add some stuff to the menu close = self.svc.get_action('close_selected').create_menu_item() menu.insert(close, 2) menu.show_all() menu.popup(None, None, None, event.button, event.time) # Must leave the menu in the same state we found it! def on_deactivate(menu): #menu.remove(sep) menu.remove(close) menu.connect('deactivate', on_deactivate) def on_buffers_ol__key_press_event(self, ol, event): if event.keyval == keysyms.Delete: cur = self.buffers_ol.selected_item next_ = self.buffers_ol.item_after(cur) if next_ is None: next_ = self.buffers_ol[0] self.svc.close_file(document=cur) self.svc.open_file(document=next_) def get_current_buffer_index(self): return self.buffers_ol.selected_item def select_buffer_by_index(self, index): self.buffers_ol.select(self.buffers_ol[index]) self.view_document(self.buffers_ol[index]) # note current is the current buffer, not the current selected buffer def next_buffer(self): next = self.buffers_ol.item_after(self.svc.get_current()) if next is None: next = self.buffers_ol[0] self.svc.open_file(document=next) def prev_buffer(self): prev = self.buffers_ol.item_before(self.svc.get_current()) if prev is None: prev = self.buffers_ol[-1] self.svc.open_file(document=prev) def sort(self): self.buffers_ol.model_sort.sort_column_changed() def set_display_attr(self, newattr): for attr in attributes.values(): for col in self.buffers_ol._viewcols_for_attr(attr): col.props.visible = (attr == newattr)
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)
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)