# Pluma snippets plugin # Copyright (C) 2005-2006 Jesse van den Kieboom # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import os import tempfile import shutil import gobject import gtk from gtk import gdk import gtksourceview2 as gsv import pango import pluma import gio from Snippet import Snippet from Helper import * from Library import * from Importer import * from Exporter import * from Document import Document from LanguageManager import get_language_manager class Manager: NAME_COLUMN = 0 SORT_COLUMN = 1 OBJ_COLUMN = 2 TARGET_URI = 105 model = None drag_icons = ('mate-mime-application-x-tarz', 'mate-package', 'package') default_export_name = _('Snippets archive') + '.tar.gz' dragging = False dnd_target_list = [('text/uri-list', 0, TARGET_URI)] def __init__(self, datadir): self.datadir = datadir self.snippet = None self.dlg = None self._temp_export = None self.snippets_doc = None self.manager = None self.default_size = None self.key_press_id = 0 self.run() def get_language_snippets(self, path, name = None): library = Library() name = self.get_language(path) nodes = library.get_snippets(name) return nodes def add_new_snippet_node(self, parent): return self.model.append(parent, ('' + _('Add a new snippet...') + \ '', '', None)) def fill_language(self, piter, expand=True): # Remove all children child = self.model.iter_children(piter) while child and self.model.remove(child): True path = self.model.get_path(piter) nodes = self.get_language_snippets(path) language = self.get_language(path) Library().ref(language) if nodes: for node in nodes: self.add_snippet(piter, node) else: # Add node that tells there are no snippets currently self.add_new_snippet_node(piter) if expand: self.tree_view.expand_row(path, False) def build_model(self, force_reload = False): window = pluma.app_get_default().get_active_window() if window: view = window.get_active_view() if not view: current_lang = None else: current_lang = view.get_buffer().get_language() source_view = self['source_view_snippet'] else: current_lang = None tree_view = self['tree_view_snippets'] expand = None if not self.model or force_reload: self.model = gtk.TreeStore(str, str, object) self.model.set_sort_column_id(self.SORT_COLUMN, gtk.SORT_ASCENDING) manager = get_language_manager() langs = pluma.language_manager_list_languages_sorted(manager, True) piter = self.model.append(None, (_('Global'), '', None)) # Add dummy node self.model.append(piter, ('', '', None)) nm = None if current_lang: nm = current_lang.get_name() for lang in langs: name = lang.get_name() parent = self.model.append(None, (name, name, lang)) # Add dummy node self.model.append(parent, ('', '', None)) if (nm == name): expand = parent else: if current_lang: piter = self.model.get_iter_first() nm = current_lang.get_name() while piter: lang = self.model.get_value(piter, \ self.SORT_COLUMN) if lang == nm: expand = piter break; piter = self.model.iter_next(piter) tree_view.set_model(self.model) if not expand: expand = self.model.get_iter_root() tree_view.expand_row(self.model.get_path(expand), False) self.select_iter(expand) def get_cell_data_pixbuf_cb(self, column, cell, model, iter): s = model.get_value(iter, self.OBJ_COLUMN) snippet = isinstance(s, SnippetData) if snippet and not s.valid: cell.set_property('stock-id', gtk.STOCK_DIALOG_ERROR) else: cell.set_property('stock-id', None) cell.set_property('xalign', 1.0) def get_cell_data_cb(self, column, cell, model, iter): s = model.get_value(iter, self.OBJ_COLUMN) snippet = isinstance(s, SnippetData) cell.set_property('editable', snippet) cell.set_property('markup', model.get_value(iter, self.NAME_COLUMN)) def on_tree_view_drag_data_get(self, widget, context, selection_data, info, time): gfile = gio.File(self._temp_export) selection_data.set_uris([gfile.get_uri()]) def on_tree_view_drag_begin(self, widget, context): self.dragging = True if self._temp_export: shutil.rmtree(os.path.dirname(self._temp_export)) self._temp_export = None if self.dnd_name: context.set_icon_name(self.dnd_name, 0, 0) dirname = tempfile.mkdtemp() filename = os.path.join(dirname, self.default_export_name) # Generate temporary file name self.export_snippets(filename, False) self._temp_export = filename def on_tree_view_drag_end(self, widget, context): self.dragging = False def on_tree_view_drag_data_received(self, widget, context, x, y, selection, info, timestamp): uris = selection.get_uris() self.import_snippets(uris) def on_tree_view_drag_motion(self, widget, context, x, y, timestamp): # Return False if we are dragging if self.dragging: return False # Check uri target if not gtk.targets_include_uri(context.targets): return False # Check action action = None if context.suggested_action == gdk.ACTION_COPY: action = gdk.ACTION_COPY else: for act in context.actions: if act == gdk.ACTION_COPY: action = gdk.ACTION_COPY break if action == gdk.ACTION_COPY: context.drag_status(gdk.ACTION_COPY, timestamp) return True else: return False def build_dnd(self): tv = self.tree_view # Set it as a drag source for exporting snippets tv.drag_source_set(gdk.BUTTON1_MASK, self.dnd_target_list, gdk.ACTION_DEFAULT | gdk.ACTION_COPY) # Set it as a drag destination for importing snippets tv.drag_dest_set(gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_DROP, self.dnd_target_list, gdk.ACTION_DEFAULT | gdk.ACTION_COPY) tv.connect('drag_data_get', self.on_tree_view_drag_data_get) tv.connect('drag_begin', self.on_tree_view_drag_begin) tv.connect('drag_end', self.on_tree_view_drag_end) tv.connect('drag_data_received', self.on_tree_view_drag_data_received) tv.connect('drag_motion', self.on_tree_view_drag_motion) theme = gtk.icon_theme_get_for_screen(tv.get_screen()) self.dnd_name = None for name in self.drag_icons: icon = theme.lookup_icon(name, gtk.ICON_SIZE_DND, 0) if icon: self.dnd_name = name break def build_tree_view(self): self.tree_view = self['tree_view_snippets'] self.column = gtk.TreeViewColumn(None) self.renderer = gtk.CellRendererText() self.column.pack_start(self.renderer, False) self.column.set_cell_data_func(self.renderer, self.get_cell_data_cb) renderer = gtk.CellRendererPixbuf() self.column.pack_start(renderer, True) self.column.set_cell_data_func(renderer, self.get_cell_data_pixbuf_cb) self.tree_view.append_column(self.column) self.renderer.connect('edited', self.on_cell_edited) self.renderer.connect('editing-started', self.on_cell_editing_started) selection = self.tree_view.get_selection() selection.set_mode(gtk.SELECTION_MULTIPLE) selection.connect('changed', self.on_tree_view_selection_changed) self.build_dnd() def build(self): self.builder = gtk.Builder() self.builder.add_from_file(os.path.join(self.datadir, 'ui', 'snippets.ui')) handlers_dic = { 'on_dialog_snippets_response': self.on_dialog_snippets_response, 'on_dialog_snippets_destroy': self.on_dialog_snippets_destroy, 'on_button_new_snippet_clicked': self.on_button_new_snippet_clicked, 'on_button_import_snippets_clicked': self.on_button_import_snippets_clicked, 'on_button_export_snippets_clicked': self.on_button_export_snippets_clicked, 'on_button_remove_snippet_clicked': self.on_button_remove_snippet_clicked, 'on_entry_tab_trigger_focus_out': self.on_entry_tab_trigger_focus_out, 'on_entry_tab_trigger_changed': self.on_entry_tab_trigger_changed, 'on_entry_accelerator_focus_out': self.on_entry_accelerator_focus_out, 'on_entry_accelerator_focus_in': self.on_entry_accelerator_focus_in, 'on_entry_accelerator_key_press': self.on_entry_accelerator_key_press, 'on_source_view_snippet_focus_out': self.on_source_view_snippet_focus_out, 'on_tree_view_snippets_row_expanded': self.on_tree_view_snippets_row_expanded, 'on_tree_view_snippets_key_press': self.on_tree_view_snippets_key_press} self.builder.connect_signals(handlers_dic) self.build_tree_view() self.build_model() image = self['image_remove'] image.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_SMALL_TOOLBAR) source_view = self['source_view_snippet'] manager = get_language_manager() lang = manager.get_language('snippets') if lang: source_view.get_buffer().set_highlight_syntax(True) source_view.get_buffer().set_language(lang) self.snippets_doc = Document(None, source_view) combo = self['combo_drop_targets'] combo.set_text_column(0) entry = combo.child entry.connect('focus-out-event', self.on_entry_drop_targets_focus_out) entry.connect('drag-data-received', self.on_entry_drop_targets_drag_data_received) lst = entry.drag_dest_get_target_list() lst = gtk.target_list_add_uri_targets(entry.drag_dest_get_target_list(), self.TARGET_URI) entry.drag_dest_set_target_list(lst) self.dlg = self['dialog_snippets'] if self.default_size: self.dlg.set_default_size(*self.default_size) def __getitem__(self, key): return self.builder.get_object(key) def is_filled(self, piter): if not self.model.iter_has_child(piter): return True child = self.model.iter_children(piter) nm = self.model.get_value(child, self.NAME_COLUMN) obj = self.model.get_value(child, self.OBJ_COLUMN) return (obj or nm) def fill_if_needed(self, piter, expand=True): if not self.is_filled(piter): self.fill_language(piter, expand) def find_iter(self, parent, snippet): self.fill_if_needed(parent) piter = self.model.iter_children(parent) while (piter): node = self.model.get_value(piter, self.OBJ_COLUMN) if node == snippet.data: return piter piter = self.model.iter_next(piter) return None def selected_snippets_state(self): snippets = self.selected_snippets(False) override = False remove = False system = False for snippet in snippets: if not snippet: continue if snippet.is_override(): override = True elif snippet.can_modify(): remove = True else: system = True # No need to continue if both are found if override and remove: break return (override, remove, system) def update_buttons(self): button_remove = self['button_remove_snippet'] button_new = self['button_new_snippet'] image_remove = self['image_remove'] button_new.set_sensitive(self.language_path != None) override, remove, system = self.selected_snippets_state() if not (override ^ remove) or system: button_remove.set_sensitive(False) image_remove.set_from_stock(gtk.STOCK_DELETE, gtk.ICON_SIZE_BUTTON) else: button_remove.set_sensitive(True) if override: image_remove.set_from_stock(gtk.STOCK_UNDO, gtk.ICON_SIZE_BUTTON) tooltip = _('Revert selected snippet') else: image_remove.set_from_stock(gtk.STOCK_DELETE, gtk.ICON_SIZE_BUTTON) tooltip = _('Delete selected snippet') button_remove.set_tooltip_text(tooltip) def snippet_changed(self, piter = None): if piter: node = self.model.get_value(piter, self.OBJ_COLUMN) s = Snippet(node) else: s = self.snippet piter = self.find_iter(self.model.get_iter(self.language_path), s) if piter: nm = s.display() self.model.set(piter, self.NAME_COLUMN, nm, self.SORT_COLUMN, nm) self.update_buttons() self.entry_tab_trigger_update_valid() return piter def add_snippet(self, parent, snippet): piter = self.model.append(parent, ('', '', snippet)) return self.snippet_changed(piter) def run(self): if not self.dlg: self.build() self.dlg.show() else: self.build_model() self.dlg.present() def snippet_from_iter(self, model, piter): parent = model.iter_parent(piter) if parent: return model.get_value(piter, self.OBJ_COLUMN) else: return None def language_snippets(self, model, parent, as_path=False): self.fill_if_needed(parent, False) piter = model.iter_children(parent) snippets = [] if not piter: return snippets while piter: snippet = self.snippet_from_iter(model, piter) if snippet: if as_path: snippets.append(model.get_path(piter)) else: snippets.append(snippet) piter = model.iter_next(piter) return snippets def selected_snippets(self, include_languages=True, as_path=False): selection = self.tree_view.get_selection() (model, paths) = selection.get_selected_rows() snippets = [] if paths and len(paths) != 0: for p in paths: piter = model.get_iter(p) parent = model.iter_parent(piter) if not piter: continue if parent: snippet = self.snippet_from_iter(model, piter) if not snippet: continue if as_path: snippets.append(p) else: snippets.append(snippet) elif include_languages: snippets += self.language_snippets(model, piter, as_path) return snippets def selected_snippet(self): selection = self.tree_view.get_selection() (model, paths) = selection.get_selected_rows() if len(paths) == 1: piter = model.get_iter(paths[0]) parent = model.iter_parent(piter) snippet = self.snippet_from_iter(model, piter) return parent, piter, snippet else: return None, None, None def selection_changed(self): if not self.snippet: sens = False self['entry_tab_trigger'].set_text('') self['entry_accelerator'].set_text('') buf = self['source_view_snippet'].get_buffer() buf.begin_not_undoable_action() buf.set_text('') buf.end_not_undoable_action() self['combo_drop_targets'].child.set_text('') else: sens = True self['entry_tab_trigger'].set_text(self.snippet['tag']) self['entry_accelerator'].set_text( \ self.snippet.accelerator_display()) self['combo_drop_targets'].child.set_text(', '.join(self.snippet['drop-targets'])) buf = self['source_view_snippet'].get_buffer() buf.begin_not_undoable_action() buf.set_text(self.snippet['text']) buf.end_not_undoable_action() for name in ['source_view_snippet', 'label_tab_trigger', 'entry_tab_trigger', 'label_accelerator', 'entry_accelerator', 'label_drop_targets', 'combo_drop_targets']: self[name].set_sensitive(sens) self.update_buttons() def select_iter(self, piter, unselect=True): selection = self.tree_view.get_selection() if unselect: selection.unselect_all() selection.select_iter(piter) self.tree_view.scroll_to_cell(self.model.get_path(piter), None, \ True, 0.5, 0.5) def get_language(self, path): if path[0] == 0: return None else: return self.model.get_value(self.model.get_iter( \ (path[0],)), self.OBJ_COLUMN).get_id() def new_snippet(self, properties=None): if not self.language_path: return None snippet = Library().new_snippet(self.get_language(self.language_path), properties) return Snippet(snippet) def get_dummy(self, parent): if not self.model.iter_n_children(parent) == 1: return None dummy = self.model.iter_children(parent) if not self.model.get_value(dummy, self.OBJ_COLUMN): return dummy return None def unref_languages(self): piter = self.model.get_iter_first() library = Library() while piter: if self.is_filled(piter): language = self.get_language(self.model.get_path(piter)) library.save(language) library.unref(language) piter = self.model.iter_next(piter) # Callbacks def on_dialog_snippets_destroy(self, dlg): # Remove temporary drag export if self._temp_export: shutil.rmtree(os.path.dirname(self._temp_export)) self._temp_export = None if self.snippets_doc: self.snippets_doc.stop() self.default_size = [dlg.allocation.width, dlg.allocation.height] self.manager = None self.unref_languages() self.snippet = None self.model = None self.dlg = None def on_dialog_snippets_response(self, dlg, resp): if resp == gtk.RESPONSE_HELP: pluma.help_display(self.dlg, 'pluma', 'pluma-snippets-plugin') return self.dlg.destroy() def on_cell_editing_started(self, renderer, editable, path): piter = self.model.get_iter(path) if not self.model.iter_parent(piter): renderer.stop_editing(True) editable.remove_widget() elif isinstance(editable, gtk.Entry): if self.snippet: editable.set_text(self.snippet['description']) else: # This is the `Add a new snippet...` item editable.set_text('') editable.grab_focus() def on_cell_edited(self, cell, path, new_text): if new_text != '': piter = self.model.get_iter(path) node = self.model.get_value(piter, self.OBJ_COLUMN) if node: if node == self.snippet.data: s = self.snippet else: s = Snippet(node) s['description'] = new_text self.snippet_changed(piter) self.select_iter(piter) else: # This is the `Add a new snippet...` item # We create a new snippet snippet = self.new_snippet({'description': new_text}) if snippet: self.model.set(piter, self.OBJ_COLUMN, snippet.data) self.snippet_changed(piter) self.snippet = snippet self.selection_changed() def on_entry_accelerator_focus_out(self, entry, event): if not self.snippet: return entry.set_text(self.snippet.accelerator_display()) def entry_tab_trigger_update_valid(self): entry = self['entry_tab_trigger'] text = entry.get_text() if text and not Library().valid_tab_trigger(text): img = self['image_tab_trigger'] img.set_from_stock(gtk.STOCK_DIALOG_ERROR, gtk.ICON_SIZE_BUTTON) img.show() #self['hbox_tab_trigger'].set_spacing(3) tip = _('This is not a valid Tab trigger. Triggers can either contain letters or a single (non-alphanumeric) character like: {, [, etc.') entry.set_tooltip_text(tip) img.set_tooltip_text(tip) else: self['image_tab_trigger'].hide() #self['hbox_tab_trigger'].set_spacing(0) entry.set_tooltip_text(_('Single word the snippet is activated with after pressing Tab')) return False def on_entry_tab_trigger_focus_out(self, entry, event): if not self.snippet: return text = entry.get_text() # save tag self.snippet['tag'] = text self.snippet_changed() def on_entry_drop_targets_focus_out(self, entry, event): if not self.snippet: return text = entry.get_text() # save drop targets self.snippet['drop-targets'] = text self.snippet_changed() def on_entry_tab_trigger_changed(self, entry): self.entry_tab_trigger_update_valid() def on_source_view_snippet_focus_out(self, source_view, event): if not self.snippet: return buf = source_view.get_buffer() text = buf.get_text(buf.get_start_iter(), \ buf.get_end_iter()) self.snippet['text'] = text self.snippet_changed() def on_button_new_snippet_clicked(self, button): snippet = self.new_snippet() if not snippet: return parent = self.model.get_iter(self.language_path) path = self.model.get_path(parent) dummy = self.get_dummy(parent) if dummy: # Remove the dummy self.model.remove(dummy) # Add the snippet piter = self.add_snippet(parent, snippet.data) self.select_iter(piter) if not self.tree_view.row_expanded(path): self.tree_view.expand_row(path, False) self.select_iter(piter) self.tree_view.grab_focus() path = self.model.get_path(piter) self.tree_view.set_cursor(path, self.column, True) def file_filter(self, name, pattern): fil = gtk.FileFilter() fil.set_name(name) for p in pattern: fil.add_pattern(p) return fil def import_snippets(self, filenames): success = True for filename in filenames: if not pluma.utils.uri_has_file_scheme(filename): continue # Remove file:// gfile = gio.File(filename) filename = gfile.get_path() importer = Importer(filename) error = importer.run() if error: message = _('The following error occurred while importing: %s') % error success = False message_dialog(self.dlg, gtk.MESSAGE_ERROR, message) self.build_model(True) if success: message = _('Import successfully completed') message_dialog(self.dlg, gtk.MESSAGE_INFO, message) def on_import_response(self, dialog, response): if response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_CLOSE: dialog.destroy() return f = dialog.get_uris() dialog.destroy() self.import_snippets(f) def on_button_import_snippets_clicked(self, button): dlg = gtk.FileChooserDialog(parent=self.dlg, title=_("Import snippets"), action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar', '*.xml'))) dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',))) dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',))) dlg.add_filter(self.file_filter(_('Single snippets file'), ('*.xml',))) dlg.add_filter(self.file_filter(_('All files'), '*')) dlg.connect('response', self.on_import_response) dlg.set_local_only(True) dlg.show() def export_snippets_real(self, filename, snippets, show_dialogs=True): export = Exporter(filename, snippets) error = export.run() if error: message = _('The following error occurred while exporting: %s') % error msgtype = gtk.MESSAGE_ERROR retval = False else: message = _('Export successfully completed') msgtype = gtk.MESSAGE_INFO retval = True if show_dialogs: message_dialog(self.dlg, msgtype, message) return retval def on_export_response(self, dialog, response): filename = dialog.get_filename() snippets = dialog._export_snippets dialog.destroy() if response != gtk.RESPONSE_OK: return self.export_snippets_real(filename, snippets); def export_snippets(self, filename=None, show_dialogs=True): snippets = self.selected_snippets() if not snippets or len(snippets) == 0: return False usersnippets = [] systemsnippets = [] # Iterate through snippets and look for system snippets for snippet in snippets: if snippet.can_modify(): usersnippets.append(snippet) else: systemsnippets.append(snippet) export_snippets = snippets if len(systemsnippets) != 0 and show_dialogs: # Ask if system snippets should also be exported message = _('Do you want to include selected system snippets in your export?') mes = gtk.MessageDialog(flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=message) mes.set_property('use-markup', True) resp = mes.run() mes.destroy() if resp == gtk.RESPONSE_NO: export_snippets = usersnippets elif resp != gtk.RESPONSE_YES: return False if len(export_snippets) == 0 and show_dialogs: message = _('There are no snippets selected to be exported') message_dialog(self.dlg, gtk.MESSAGE_INFORMATION, message) return False if not filename: dlg = gtk.FileChooserDialog(parent=self.dlg, title=_('Export snippets'), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) dlg._export_snippets = export_snippets dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar'))) dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',))) dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',))) dlg.add_filter(self.file_filter(_('All files'), '*')) dlg.set_do_overwrite_confirmation(True) dlg.set_current_name(self.default_export_name) dlg.connect('response', self.on_export_response) dlg.set_local_only(True) dlg.show() return True else: return self.export_snippets_real(filename, export_snippets, show_dialogs) def on_button_export_snippets_clicked(self, button): snippets = self.selected_snippets() if not snippets or len(snippets) == 0: return usersnippets = [] systemsnippets = [] # Iterate through snippets and look for system snippets for snippet in snippets: if snippet.can_modify(): usersnippets.append(snippet) else: systemsnippets.append(snippet) dlg = gtk.FileChooserDialog(parent=self.dlg, title=_('Export snippets'), action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) dlg._export_snippets = snippets if len(systemsnippets) != 0: # Ask if system snippets should also be exported message = _('Do you want to include selected system snippets in your export?') mes = gtk.MessageDialog(flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=message) mes.set_property('use-markup', True) resp = mes.run() mes.destroy() if resp == gtk.RESPONSE_NO: dlg._export_snippets = usersnippets elif resp != gtk.RESPONSE_YES: dlg.destroy() return if len(dlg._export_snippets) == 0: dlg.destroy() message = _('There are no snippets selected to be exported') message_dialog(self.dlg, gtk.MESSAGE_INFORMATION, message) return dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar'))) dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',))) dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',))) dlg.add_filter(self.file_filter(_('All files'), '*')) dlg.set_do_overwrite_confirmation(True) dlg.set_current_name(self.default_export_name) dlg.connect('response', self.on_export_response) dlg.set_local_only(True) dlg.show() def remove_snippet_revert(self, path, piter): node = self.snippet_from_iter(self.model, piter) Library().revert_snippet(node) return piter def remove_snippet_delete(self, path, piter): node = self.snippet_from_iter(self.model, piter) parent = self.model.iter_parent(piter) Library().remove_snippet(node) if self.model.remove(piter): return piter elif path[-1] != 0: self.select_iter(self.model.get_iter((path[0], path[1] - 1))) else: dummy = self.add_new_snippet_node(parent) self.tree_view.expand_row(self.model.get_path(parent), False) return dummy def on_button_remove_snippet_clicked(self, button): override, remove, system = self.selected_snippets_state() if not (override ^ remove) or system: return paths = self.selected_snippets(include_languages=False, as_path=True) if override: action = self.remove_snippet_revert else: action = self.remove_snippet_delete # Remove selection self.tree_view.get_selection().unselect_all() # Create tree row references references = [] for path in paths: references.append(gtk.TreeRowReference(self.model, path)) # Remove/revert snippets select = None for reference in references: path = reference.get_path() piter = self.model.get_iter(path) res = action(path, piter) if res: select = res if select: self.select_iter(select) self.selection_changed() def set_accelerator(self, keyval, mod): accelerator = gtk.accelerator_name(keyval, mod) self.snippet['accelerator'] = accelerator return True def on_entry_accelerator_key_press(self, entry, event): source_view = self['source_view_snippet'] if event.keyval == gdk.keyval_from_name('Escape'): # Reset entry.set_text(self.snippet.accelerator_display()) self.tree_view.grab_focus() return True elif event.keyval == gdk.keyval_from_name('Delete') or \ event.keyval == gdk.keyval_from_name('BackSpace'): # Remove the accelerator entry.set_text('') self.snippet['accelerator'] = '' self.tree_view.grab_focus() self.snippet_changed() return True elif Library().valid_accelerator(event.keyval, event.state): # New accelerator self.set_accelerator(event.keyval, \ event.state & gtk.accelerator_get_default_mod_mask()) entry.set_text(self.snippet.accelerator_display()) self.snippet_changed() self.tree_view.grab_focus() else: return True def on_entry_accelerator_focus_in(self, entry, event): if self.snippet['accelerator']: entry.set_text(_('Type a new shortcut, or press Backspace to clear')) else: entry.set_text(_('Type a new shortcut')) def update_language_path(self): model, paths = self.tree_view.get_selection().get_selected_rows() # Check if all have the same language parent current_parent = None for path in paths: piter = model.get_iter(path) parent = model.iter_parent(piter) if parent: path = model.get_path(parent) if current_parent != None and current_parent != path: current_parent = None break else: current_parent = path self.language_path = current_parent def on_tree_view_selection_changed(self, selection): parent, piter, node = self.selected_snippet() if self.snippet: self.on_entry_tab_trigger_focus_out(self['entry_tab_trigger'], None) self.on_source_view_snippet_focus_out(self['source_view_snippet'], None) self.on_entry_drop_targets_focus_out(self['combo_drop_targets'].child, None) self.update_language_path() if node: self.snippet = Snippet(node) else: self.snippet = None self.selection_changed() def iter_after(self, target, after): if not after: return True tp = self.model.get_path(target) ap = self.model.get_path(after) if tp[0] > ap[0] or (tp[0] == ap[0] and (len(ap) == 1 or tp[1] > ap[1])): return True return False def on_tree_view_snippets_key_press(self, treeview, event): if event.keyval == gdk.keyval_from_name('Delete'): self.on_button_remove_snippet_clicked(None) return True def on_tree_view_snippets_row_expanded(self, treeview, piter, path): # Check if it is already filled self.fill_if_needed(piter) self.select_iter(piter) def on_entry_drop_targets_drag_data_received(self, entry, context, x, y, selection_data, info, timestamp): if not gtk.targets_include_uri(context.targets): return uris = drop_get_uris(selection_data) if not uris: return if entry.get_text(): mimes = [entry.get_text()] else: mimes = [] for uri in uris: try: mime = gio.content_type_guess(uri) except: mime = None if mime: mimes.append(mime) entry.set_text(', '.join(mimes)) self.on_entry_drop_targets_focus_out(entry, None) context.finish(True, False, timestamp) entry.stop_emission('drag_data_received') # ex:ts=8:et: