#!/usr/bin/python
# -*- coding: utf-8 -*-
### BEGIN LICENSE
# Copyright (C) 2009 <Marc Gariépy> <mgariepy@revolutionlinux.com> Révolution Linux
#This program is free software: you can redistribute it and/or modify it
#under the terms of the GNU General Public License version 3  or (at your option)
#any later version, as published by the Free Software Foundation.
#
#This program is distributed in the hope that it will be useful, but
#WITHOUT ANY WARRANTY; without even the implied warranties of
#MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
### END LICENSE

import sys
import os
import gtk

import gettext
from gettext import gettext as _
gettext.textdomain("edubuntu-menueditor")

# Check if we are working in the source tree or from the installed
# package and mangle the python path accordingly
if os.path.dirname(sys.argv[0]) != ".":
    if sys.argv[0][0] == "/":
        fullPath = os.path.dirname(sys.argv[0])
    else:
        fullPath = os.getcwd() + "/" + os.path.dirname(sys.argv[0])
else:
    fullPath = os.getcwd()
sys.path.insert(0, os.path.dirname(fullPath))

from menueditor import AboutMenueditorDialog, AddsubmenuDialog, \
        MenuTreeModel, FileWriter

from menueditor.menueditorconfig import getdatapath

class MenueditorWindow(gtk.Window):
    __gtype_name__ = "MenueditorWindow"
    TARGETS = [
        ('Row', gtk.TARGET_SAME_WIDGET, 0),
    ]

    def __init__(self):
        """__init__ - This function is typically not called directly.
        Creation a MenueditorWindow requires redeading the associated ui
        file and parsing the ui definition extrenally,
        and then calling MenueditorWindow.finish_initializing().

        Use the convenience function NewMenueditorWindow to create
        MenueditorWindow object.

        """
        pass

    def finish_initializing(self, builder):
        """finish_initalizing should be called after parsing the ui definition
        and creating a MenueditorWindow object with it in order to finish
        initializing the start of the new MenueditorWindow instance.

        """
        #get a reference to the builder and set up the signals
        self.builder = builder
        self.builder.connect_signals(self)

        #code for other initialization actions should be added here
        self.tvMenuModel = MenuTreeModel.MenuTreeModel([])
        self.tvMenu = self.builder.get_object("tvMenu")
        self.menuPopup = self.builder.get_object("menuPopup")
        self.setup_tvMenu()
        self.tvMenu.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, self.TARGETS , gtk.gdk.ACTION_COPY)
        self.tvMenu.enable_model_drag_dest(self.TARGETS,gtk.gdk.ACTION_COPY)
        #self.tvDebug = builder.get_object("tvDebug")
        #self.setup_tvDebug()

    def about(self, widget, data=None):
        """about - display the about box for menueditor """
        about = AboutMenueditorDialog.NewAboutMenueditorDialog()
        response = about.run()
        about.destroy()
        
    def launch_help(self, widget, data=None):
        import webbrowser
        webbrowser.open("https://wiki.ubuntu.com/Edubuntu/Documentation/Edubuntu-menueditor")

    def setup_tvMenu(self):
        self.tvMenu.set_model(self.tvMenuModel)
        self.tvMenu.get_selection().set_mode (gtk.SELECTION_SINGLE)
        self.tvMenu.set_headers_visible (True)

        column = gtk.TreeViewColumn(_("Name"))
        column.set_spacing(6)
        cell = gtk.CellRendererPixbuf ()
        column.pack_start (cell, False)
        column.set_attributes (cell, pixbuf = self.tvMenuModel.COLUMN_ICON)
        cell = gtk.CellRendererText ()
        column.pack_start (cell, False)
        column.set_expand(True)
        column.set_attributes (cell, text = self.tvMenuModel.COLUMN_NAME)
        # Adding the column Name to the treeview
        self.tvMenu.append_column(column)

        column = gtk.TreeViewColumn (_("Show"))
        cell = gtk.CellRendererToggle()
        cell.set_property("xalign",.5)
        cell.set_property("is-expanded",True)
        column.set_spacing(6)
        # TODO: add third state : inconsistant = true if not all child are selected.
        # this will require of using number instead of a bool.
        cell.connect("toggled", self.on_toggled, self.tvMenuModel)
        column.pack_start(cell, True)
        column.set_alignment(0.5)
        column.set_attributes(cell, active = self.tvMenuModel.COLUMN_USER_VISIBLE)
        # Adding the column Show to the treeview
        self.tvMenu.append_column(column)
        # expand the two menus
        self.tvMenu.expand_row( (0,), False)
        self.tvMenu.expand_row( (1,), False)

    def setup_tvDebug(self):
        """
        This is debug code only for developpement purpose. To have an
        actual view of the data.
        """
        self.tvDebug.set_model(self.tvMenuModel)
        self.tvDebug.set_headers_visible(True)
        lists = [ "COLUMN_IS_ENTRY",
                  "COLUMN_ID",
                  "COLUMN_NAME",
                  "COLUMN_ICON",
                  "COLUMN_ICON_NAME",
                  "COLUMN_MENU_FILE",
                  "COLUMN_SYSTEM_VISIBLE",
                  "COLUMN_USER_VISIBLE",
                  "COLUMN_USER_ADDED",
                  "COLUMN_COMMENT" ]

        for i in range(10):
            column = gtk.TreeViewColumn(lists[i])
            self.tvDebug.append_column(column)
            if i == 3:
                cell=gtk.CellRendererPixbuf()
                column.set_spacing(6)
                column.pack_start(cell,True)
                column.set_attributes(cell, pixbuf = self.tvMenuModel.__getattribute__(lists[i]))
            else:
                cell=gtk.CellRendererText()
                column.pack_start(cell,True)
                column.set_attributes(cell, text = self.tvMenuModel.__getattribute__(lists[i]))
        self.tvDebug.expand_all()

    def treeview_copy_row(self, treeview, model, source, target, drop_position):
        # TODO: need to insert the item at the correct place.
        #  sort menu then entry, + alpha.
        source_row = model[source]
        source_isentry = model.get_value(source,model.COLUMN_IS_ENTRY)
        target_isentry = model.get_value(target,model.COLUMN_IS_ENTRY)

        # If the user drop into a desktop, assume he want to drop into the parent.
        if target_isentry:
            target = model.iter_parent(target)

        # Verify the content of the parent to be sure not to make a copy twice.
        iter = model.iter_children (target)
        while iter:
            if model.get_value(iter, model.COLUMN_ID) == \
                    model.get_value(source, model.COLUMN_ID):
                return
            iter = model.iter_next(iter)

        # test if the user try to drop the items into his parent.
        # i assume he want to reorder the menu.
        if model.get_path(model.iter_parent(source)) == model.get_path(target):
            error_dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, \
                message_format = _("Sorry, layout in the menu is not yet supported."), \
                buttons=gtk.BUTTONS_OK)
            error_dlg.run()
            error_dlg.destroy()
            return

        if not source_isentry:
            new = model.prepend(target, source_row)
        else:
            new = model.append(target, source_row)

        model.set_value(new, model.COLUMN_SYSTEM_VISIBLE ,False)
        model.set_value(new, model.COLUMN_USER_ADDED, True)
        # this copy all the children of the source into the new position.
        for n in range(model.iter_n_children(source)):
            child = model.iter_nth_child(source, n)
            self.treeview_copy_row(treeview, model, child, new, gtk.TREE_VIEW_DROP_INTO_OR_BEFORE)

        treeview.expand_to_path(model.get_path(new))

    def on_tvMenu_button_press_event(self, treeview, event):
        if event.button == 3:
            x = int(event.x)
            y = int(event.y)
            time = event.time
            pthinfo = treeview.get_path_at_pos(x, y)
            if pthinfo is not None:
                path, col, cellx, celly = pthinfo
                treeview.grab_focus()
                treeview.set_cursor(path, col, 0)
                # Show menu item only if they are user added.
                selection = self.tvMenu.get_selection()
                model, iter = selection.get_selected()
                if model[iter][model.COLUMN_USER_ADDED]:
                    self.builder.get_object("menuDelSub").set_property("sensitive",True)
                    if not model[iter][model.COLUMN_IS_ENTRY]:
                        self.builder.get_object("menuEditSub").set_property("sensitive",True)
                else:
                    self.builder.get_object("menuDelSub").set_property("sensitive",False)
                    self.builder.get_object("menuEditSub").set_property("sensitive",False)
                self.menuPopup.popup( None, None, None, event.button, time)
            return True

    def on_tvMenu_drag_data_received(self, treeview, drag_context, x, y, selection_data, info, eventtime):
        target_path, drop_position = treeview.get_dest_row_at_pos(x, y)
        model, source = treeview.get_selection().get_selected()
        target = model.get_iter(target_path)
        # test if the target is a child of the source
        # and if the target and the source are the same.
        if not model.is_ancestor(source, target) and \
                not (model.get_path(source) == model.get_path(target)):
            self.treeview_copy_row(treeview, model, source, target, drop_position)
            # drag_context.finish( success=True, del_=bool, time=eventtime)
            # The del_=False make the copy instead of the moving.
            drag_context.finish(True, False, eventtime)
        else:
            drag_context.finish(False, False, eventtime)

    def on_menuAddSub_activate(self, widget):
        # TODO: need to insert new submenu in order by the name
        selection = self.tvMenu.get_selection()
        model, iter = selection.get_selected()

        response, name, comment = (None, "", "")

        while not name and not (response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT):
            response, name, comment = self.submenuDialog(name, comment)
            #if response == gtk.RESPONSE_CANCEL or response == gtk.RESPONSE_DELETE_EVENT:
            #    return
            if response == gtk.RESPONSE_OK and not name:
                error_dlg = gtk.MessageDialog(type=gtk.MESSAGE_ERROR, \
                    message_format = _("You need to enter the name with at least one character in the Name field."), \
                    buttons=gtk.BUTTONS_OK)
                error_dlg.run()
                error_dlg.destroy()
            elif response == gtk.RESPONSE_OK and name:
                data = (False , "MenuEditor-" + name.replace(" ","_"), \
                        name, \
                        MenuTreeModel.load_icon(gtk.icon_theme_get_default(), "distributor-logo"), \
                        "distributor-logo", None, False, True, True, comment)
                if model.get_value(iter, model.COLUMN_IS_ENTRY):
                    model.prepend(model.iter_parent(iter),data)
                else:
                    model.prepend(iter,data)
        return

    def on_menuDelSub_activate(self, widget):
        selection = self.tvMenu.get_selection()
        model, iter = selection.get_selected()
        if model[iter][self.tvMenuModel.COLUMN_USER_ADDED]:
            model.remove(iter)
        else:
            pass

    def on_menuEditSub_activate(self, widget):
        selection = self.tvMenu.get_selection()
        model, iter = selection.get_selected()

        old_name = model[iter][self.tvMenuModel.COLUMN_NAME]
        old_comment = model[iter][self.tvMenuModel.COLUMN_COMMENT]

        response, name, comment = self.submenuDialog(old_name, old_comment)
        if response == gtk.RESPONSE_OK:
            model.set(iter, model.COLUMN_COMMENT, \
                            comment, model.COLUMN_NAME, \
                            name, \
                            model.COLUMN_ID, \
                            "MenuEditor-" + name.replace(" ","_"))

    def on_toggled(self, toggle, path, model):
        iter = model.get_iter_from_string(path)
        val = model.get_value(iter, model.COLUMN_USER_VISIBLE)
        self.set_recursively_child_of_parent(model, iter, model.COLUMN_USER_VISIBLE,  not val)

    def set_recursively_child_of_parent (self, model, parent_iter, column, value):
        model.set_value(parent_iter, column, value)
        iter = model.iter_children (parent_iter)
        while iter:
            if model.get_value(iter, model.COLUMN_IS_ENTRY):
                model.set_value(iter, column, value)
            else:
                self.set_recursively_child_of_parent(model, iter, column, value)
            iter = model.iter_next(iter)

    def create_filechooser_save(self):
        #TODO: Validate the filename (automaticly add extention, etc)
        buttons     = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, \
                       gtk.STOCK_SAVE,   gtk.RESPONSE_OK)
        filechooser = gtk.FileChooserDialog(_("Save As..."), \
                                            None, \
                                            gtk.FILE_CHOOSER_ACTION_SAVE, \
                                            buttons)
        filechooser.set_do_overwrite_confirmation(True)
        self.add_filters(filechooser)
        return filechooser

    def add_filters(self, filechooser):
        filter = gtk.FileFilter()
        filter.set_name(_("Archive"))
        filter.add_pattern("*.tar.gz")
        filechooser.add_filter(filter)

        filter = gtk.FileFilter()
        filter.set_name(_("All files"))
        filter.add_pattern("*")
        filechooser.add_filter(filter)

    def saveDialog(self,widget):
        filechooser = self.create_filechooser_save()
        response = filechooser.run()

        if response == gtk.RESPONSE_OK:
            FileWriter.FileWriter(self.tvMenuModel, \
                                  filechooser.get_filename())
        filechooser.destroy()
        return

    def submenuDialog(self, name="", comment=""):

        NewSubmenuDialog = AddsubmenuDialog.NewAddsubmenuDialog()
        NewSubmenuDialog.set_name(name)
        NewSubmenuDialog.set_comment(comment)
        response = NewSubmenuDialog.run()
        name = NewSubmenuDialog.name
        comment = NewSubmenuDialog.comment
        NewSubmenuDialog.destroy()
        return  (response, name, comment)

    def quit(self, widget, data=None):
        """quit - signal handler for closing the MenueditorWindow"""
        self.destroy()

    def on_destroy(self, widget, data=None):
        """on_destroy - called when the MenueditorWindow is close. """
        #clean up code for saving application state should be added here

        gtk.main_quit()

def NewMenueditorWindow():
    """NewMenueditorWindow - returns a fully instantiated
    MenueditorWindow object. Use this function rather than
    creating a MenueditorWindow directly.
    """

    if not gtk.gdk.display_get_default():
        logging.critical("Display not found")
        sys.exit(1)

    #look for the ui file that describes the ui
    ui_filename = os.path.join(getdatapath(), 'ui', 'MenueditorWindow.ui')
    if not os.path.exists(ui_filename):
        ui_filename = None

    builder = gtk.Builder()
    builder.add_from_file(ui_filename)
    window = builder.get_object("menueditor_window")
    window.finish_initializing(builder)
    return window

if __name__ == "__main__":
    #support for command line options
    import logging, optparse
    parser = optparse.OptionParser(version="%prog %ver")
    parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="Show debug messages")
    (options, args) = parser.parse_args()

    #set the logging level to show debug messages
    if options.verbose:
        logging.basicConfig(level=logging.DEBUG)
        logging.debug('logging enabled')

    #run the application
    window = NewMenueditorWindow()
    window.show()
    gtk.main()

