#    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

import gobject
import gtk
from gtk import gdk
import gtksourceview2 as gsv
import pango
import gedit
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 = ('gnome-mime-application-x-tarz', 'gnome-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, ('<i>' + _('Add a new snippet...') + \
                                '</i>', '', 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 = gedit.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 = gedit.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:
                        gedit.help_display(self.dlg, 'gedit', 'gedit-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 gedit.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 <b>system</b> 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 <b>system</b> 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:
