summaryrefslogtreecommitdiffstats
path: root/plugins/snippets/snippets/manager.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/snippets/snippets/manager.py')
-rw-r--r--plugins/snippets/snippets/manager.py1143
1 files changed, 1143 insertions, 0 deletions
diff --git a/plugins/snippets/snippets/manager.py b/plugins/snippets/snippets/manager.py
new file mode 100644
index 0000000..ca64f18
--- /dev/null
+++ b/plugins/snippets/snippets/manager.py
@@ -0,0 +1,1143 @@
+# Gedit snippets plugin
+# Copyright (C) 2005-2006 Jesse van den Kieboom <jesse@icecrew.nl>
+#
+# 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
+
+from gi.repository import Gtk, Gio, Gdk, GObject
+
+from .snippet import Snippet
+from . import helper
+from .library import Library
+from .importer import Importer
+from .exporter import Exporter
+from .languagemanager import get_language_manager
+
+try:
+ import gettext
+ gettext.bindtextdomain('gedit')
+ gettext.textdomain('gedit')
+ _ = gettext.gettext
+except:
+ _ = lambda s: s
+
+class Manager(Gtk.Window, Gtk.Buildable):
+ NAME_COLUMN = 0
+ SORT_COLUMN = 1
+ LANG_COLUMN = 2
+ SNIPPET_COLUMN = 3
+ TARGET_URI = 105
+
+ __gtype_name__ = "GeditSnippetsManager"
+
+ model = None
+ drag_icons = ('gnome-mime-application-x-tarz', 'gnome-package', 'package')
+ default_export_name = _('Snippets archive') + '.tar.gz'
+ dragging = False
+
+ def __init__(self):
+ self.snippet = None
+ self._temp_export = None
+ self._size = (0, 0)
+
+ self.key_press_id = 0
+ self.dnd_target_list = Gtk.TargetList.new([])
+ self.dnd_target_list.add(Gdk.atom_intern("text/uri-list", True), 0, self.TARGET_URI)
+
+ def get_final_size(self):
+ return self._size
+
+ 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, ('<i>' + _('Add a new snippet…') + \
+ '</i>', '', None, 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 = Gio.Application.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()
+ 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, GObject.Object, object)
+ self.model.set_sort_column_id(self.SORT_COLUMN, Gtk.SortType.ASCENDING)
+
+ manager = get_language_manager()
+
+ langs = [manager.get_language(x) for x in manager.get_language_ids()]
+ langs.sort(key=lambda x: x.get_name())
+
+ piter = self.model.append(None, (_('Global'), '', None, None))
+
+ # Add dummy node
+ self.model.append(piter, ('', '', None, 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, None))
+
+ # Add dummy node
+ self.model.append(parent, ('', '', None, 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_first()
+
+ 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, data):
+ snippet = model.get_value(iter, self.SNIPPET_COLUMN)
+
+ if snippet and not snippet.valid:
+ cell.set_property('icon-name', 'dialog-error')
+ else:
+ cell.set_property('icon-name', None)
+
+ cell.set_property('xalign', 1.0)
+
+ def get_cell_data_cb(self, column, cell, model, iter, data):
+ snippet = model.get_value(iter, self.SNIPPET_COLUMN)
+
+ cell.set_property('editable', snippet != None)
+ 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_new_for_path(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:
+ Gtk.drag_set_icon_name(context, 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()
+
+ files = [Gio.file_new_for_uri(u) for u in uris]
+
+ self.import_snippets(files)
+
+ 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.DragAction.COPY:
+ action = Gdk.DragAction.COPY
+ else:
+ for act in context.actions:
+ if act == Gdk.DragAction.COPY:
+ action = Gdk.DragAction.COPY
+ break
+
+ if action == Gdk.DragAction.COPY:
+ context.drag_status(Gdk.DragAction.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.ModifierType.BUTTON1_MASK, [], Gdk.DragAction.DEFAULT | Gdk.DragAction.COPY)
+ tv.drag_source_set_target_list(self.dnd_target_list)
+
+ # Set it as a drag destination for importing snippets
+ tv.drag_dest_set(Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP,
+ [], Gdk.DragAction.DEFAULT | Gdk.DragAction.COPY)
+
+ tv.drag_dest_set_target_list(self.dnd_target_list)
+
+ 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.IconTheme.get_for_screen(tv.get_screen())
+
+ self.dnd_name = None
+ for name in self.drag_icons:
+ icon = theme.lookup_icon(name, Gtk.IconSize.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, None)
+
+ renderer = Gtk.CellRendererPixbuf()
+ self.column.pack_start(renderer, True)
+ self.column.set_cell_data_func(renderer, self.get_cell_data_pixbuf_cb, None)
+
+ 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.SelectionMode.MULTIPLE)
+ selection.connect('changed', self.on_tree_view_selection_changed)
+
+ self.build_dnd()
+
+ def do_parser_finished(self, builder):
+ self.builder = builder
+
+ handlers_dic = {
+ 'on_add_snippet_button_clicked': self.on_add_snippet_button_clicked,
+ 'on_remove_snippet_button_clicked': self.on_remove_snippet_button_clicked,
+ 'on_import_snippets_button_clicked': self.on_import_snippets_button_clicked,
+ 'on_export_snippets_button_clicked': self.on_export_snippets_button_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()
+
+ # join treeview and toolbar
+ context = self['scrolled_window_snippets'].get_style_context()
+ context.set_junction_sides(Gtk.JunctionSides.BOTTOM)
+ context = self['toolbar'].get_style_context()
+ context.set_junction_sides(Gtk.JunctionSides.TOP)
+ context.set_junction_sides(Gtk.JunctionSides.BOTTOM)
+
+ 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)
+
+ combo = self['combo_drop_targets']
+
+ entry = combo.get_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.add_uri_targets(self.TARGET_URI)
+
+ def do_configure_event(self, event):
+ if self.get_realized():
+ alloc = self.get_allocation()
+ self._size = (alloc.width, alloc.height)
+
+ return Gtk.Dialog.do_configure_event(self, event)
+
+ 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)
+ lang = self.model.get_value(child, self.LANG_COLUMN)
+ snippet = self.model.get_value(child, self.SNIPPET_COLUMN)
+
+ return (lang or snippet 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):
+ sn = self.model.get_value(piter, self.SNIPPET_COLUMN)
+
+ if sn == 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_toolbar_buttons(self):
+ button_add = self['add_snippet_button']
+ button_remove = self['remove_snippet_button']
+
+ button_add.set_sensitive(self.language_path != None)
+ override, remove, system = self.selected_snippets_state()
+
+ if not (override ^ remove) or system:
+ button_remove.set_sensitive(False)
+ button_remove.set_icon_name('list-remove-symbolic')
+ else:
+ button_remove.set_sensitive(True)
+
+ if override:
+ button_remove.set_icon_name('edit-undo-symbolic')
+ tooltip = _('Revert selected snippet')
+ else:
+ button_remove.set_icon_name('list-remove-symbolic')
+ 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.SNIPPET_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_value(piter, self.NAME_COLUMN, nm)
+ self.model.set_value(piter, self.SORT_COLUMN, nm)
+ self.update_toolbar_buttons()
+ self.entry_tab_trigger_update_valid()
+
+ return piter
+
+ def add_snippet(self, parent, snippet):
+ piter = self.model.append(parent, ('', '', None, snippet))
+
+ return self.snippet_changed(piter)
+
+ def snippet_from_iter(self, model, piter):
+ parent = model.iter_parent(piter)
+
+ if parent:
+ return model.get_value(piter, self.SNIPPET_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'].get_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'].get_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_toolbar_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.get_indices()[0] == 0:
+ return None
+ else:
+ return self.model.get_value(self.model.get_iter(path),
+ self.LANG_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.SNIPPET_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 do_destroy(self):
+ Gtk.Dialog.do_destroy(self)
+
+ if not self.model:
+ return
+
+ # Remove temporary drag export
+ if self._temp_export:
+ shutil.rmtree(os.path.dirname(self._temp_export))
+ self._temp_export = None
+
+ self.unref_languages()
+ self.snippet = None
+ self.model = None
+
+ 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.SNIPPET_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_value(piter, self.SNIPPET_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_icon_name('dialog-error', Gtk.IconSize.BUTTON)
+ img.show()
+
+ #self['hbox_tab_trigger'].set_spacing(3)
+ tip = _('This is not a valid Tab trigger. Triggers can either contain alphanumeric characters (or _, : and .) 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(), False)
+
+ self.snippet['text'] = text
+ self.snippet_changed()
+
+ def on_add_snippet_button_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, files):
+ success = True
+
+ for gfile in files:
+ if not gfile.has_uri_scheme('file'):
+ continue
+
+ # Remove file://
+ filename = gfile.get_path()
+
+ importer = Importer(filename)
+ error = importer.run()
+
+ if error:
+ message = _('The following error occurred while importing: %s') % error
+ success = False
+ helper.message_dialog(self.get_toplevel(), Gtk.MessageType.ERROR, message)
+
+ self.build_model(True)
+
+ if success:
+ message = _('Import successfully completed')
+ helper.message_dialog(self.get_toplevel(), Gtk.MessageType.INFO, message)
+
+ def on_import_response(self, dialog, response):
+ if response == Gtk.ResponseType.CANCEL or response == Gtk.ResponseType.CLOSE:
+ dialog.destroy()
+ return
+
+ f = dialog.get_files()
+ dialog.destroy()
+
+ self.import_snippets(f)
+
+ def on_import_snippets_button_clicked(self, button):
+ dlg = Gtk.FileChooserDialog(parent=self.get_toplevel(), title=_("Import snippets"),
+ action=Gtk.FileChooserAction.OPEN,
+ buttons=(_("_Cancel"), Gtk.ResponseType.CANCEL,
+ _("_Open"), Gtk.ResponseType.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.MessageType.ERROR
+ retval = False
+ else:
+ message = _('Export successfully completed')
+ msgtype = Gtk.MessageType.INFO
+ retval = True
+
+ if show_dialogs:
+ helper.message_dialog(self.get_toplevel(), msgtype, message)
+
+ return retval
+
+ def on_export_response(self, dialog, response):
+ filename = dialog.get_filename()
+ snippets = dialog._export_snippets
+
+ dialog.destroy()
+
+ if response != Gtk.ResponseType.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 <b>system</b> snippets in your export?')
+ mes = Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL,
+ type=Gtk.MessageType.QUESTION,
+ buttons=Gtk.ButtonsType.YES_NO,
+ message_format=message)
+ mes.set_property('use-markup', True)
+ resp = mes.run()
+ mes.destroy()
+
+ if resp == Gtk.ResponseType.NO:
+ export_snippets = usersnippets
+ elif resp != Gtk.ResponseType.YES:
+ return False
+
+ if len(export_snippets) == 0 and show_dialogs:
+ message = _('There are no snippets selected to be exported')
+ helper.message_dialog(self.get_toplevel(), Gtk.MessageType.QUESTION, message)
+ return False
+
+ if not filename:
+ dlg = Gtk.FileChooserDialog(parent=self.get_toplevel(), title=_('Export snippets'),
+ action=Gtk.FileChooserAction.SAVE,
+ buttons=(_("_Cancel"), Gtk.ResponseType.CANCEL,
+ _("_Save"), Gtk.ResponseType.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_export_snippets_button_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.get_toplevel(), title=_('Export snippets'),
+ action=Gtk.FileChooserAction.SAVE,
+ buttons=(_('_Cancel'), Gtk.ResponseType.CANCEL,
+ _('_Save'), Gtk.ResponseType.OK))
+
+ dlg._export_snippets = snippets
+
+ if len(systemsnippets) != 0:
+ # Ask if system snippets should also be exported
+ message = _('Do you want to include selected <b>system</b> snippets in your export?')
+ mes = Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL,
+ type=Gtk.MessageType.QUESTION,
+ buttons=Gtk.ButtonsType.YES_NO,
+ message_format=message)
+ mes.set_property('use-markup', True)
+ resp = mes.run()
+ mes.destroy()
+
+ if resp == Gtk.ResponseType.NO:
+ dlg._export_snippets = usersnippets
+ elif resp != Gtk.ResponseType.YES:
+ dlg.destroy()
+ return
+
+ if len(dlg._export_snippets) == 0:
+ dlg.destroy()
+
+ message = _('There are no snippets selected to be exported')
+ helper.message_dialog(self.get_toplevel(), Gtk.MessageType.QUESTION, 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)
+ idx = path.get_indices()
+
+ if self.model.remove(piter):
+ return piter
+ elif idx[-1] != 0:
+ self.select_iter(self.model.get_iter((idx[0], idx[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_remove_snippet_button_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:
+ # FIXME: this should be fixed in pygobject or something
+ references.append(Gtk.TreeRowReference.new(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):
+ 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.get_state()):
+ # New accelerator
+ self.set_accelerator(event.keyval, \
+ event.get_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'].get_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_remove_snippet_button_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):
+ uris = helper.drop_get_uris(selection_data)
+ if not uris:
+ return
+
+ text = entry.get_text()
+
+ if text:
+ mimes = [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=4:et: