##
# 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
##

import gtk, gtk.glade, gobject
import time
import DSApp
import DlgAbout, DlgDiskAdd, DlgDiskEdit, DlgSearch, DlgPrint
import Constants

class DSView:
    """This class is the view (from MVC view) implementation of the application."""

    def __init__ (self):
        """Constructor of DSView class."""

    def init_gui (self):
        """This methods initializes the application GUI."""

        # load widget tree and get widgets
        self.app_widget_tree = gtk.glade.XML (Constants.RESOURCE_DIR + "/disksearch.glade", "app_disksearch")
        self.app_disksearch = self.app_widget_tree.get_widget ("app_disksearch")
        self.list_disks = self.app_widget_tree.get_widget ("list_disks")

        # connect signals to methods
        self.app_widget_tree.signal_connect ("on_app_disksearch_delete", self.quit_app)
        self.app_widget_tree.signal_connect ("on_quit_clicked", self.quit_app)
        self.app_widget_tree.signal_connect ("on_print_clicked", self.print_disk)
        self.app_widget_tree.signal_connect ("on_about_clicked", self.about_app)
        self.app_widget_tree.signal_connect ("on_add_disk_clicked", self.add_disk)
        self.app_widget_tree.signal_connect ("on_remove_disk_clicked", self.remove_disk)
        self.app_widget_tree.signal_connect ("on_edit_disk_clicked", self.edit_disk)
        self.app_widget_tree.signal_connect ("on_search_files_clicked", self.search_files)

        self.app_widget_tree.signal_connect ("on_list_disks_doubleclick", self.edit_disk)

        # load application icon image using GdkPixbuf and set window icon
        self.pxb_appicon = gtk.gdk.pixbuf_new_from_file ("resource/disksearch.png")
        self.app_disksearch.set_icon (self.pxb_appicon)

        # setup list coulumns
        column1 = gtk.TreeViewColumn (_("Type"), gtk.CellRendererText (), text = 0)
        column2 = gtk.TreeViewColumn (_("Name"), gtk.CellRendererText (), text = 1)
        cellRendererDate = gtk.CellRendererText ()
        column3 = gtk.TreeViewColumn (_("Date"), cellRendererDate)
        column3.set_cell_data_func (cellRendererDate, self.cellRenderDate)

        column1.set_resizable (True)
        column2.set_resizable (True)
        column1.set_sort_column_id (0)
        column2.set_sort_column_id (1)
        column3.set_sort_column_id (2)
        column2.set_expand (True)

        self.list_disks.append_column (column1)
        self.list_disks.append_column (column2)
        self.list_disks.append_column (column3)
        self.list_disks.get_selection ().set_mode (gtk.SELECTION_SINGLE)

        # show app window
        self.app_disksearch.show ()

    def quit_app (self, *args):
        """If the disk list was modified, then the use will be asked, if he
        wants to save the changes. If yes, then the app only quits after
        successfull saving of the disk list. When list was not modified the app
        quits immediatly."""

        if DSApp.DSApp.doc.diskList.modified != 0:
            if self.display_question_dialog (gtk.MESSAGE_QUESTION, _("Do you want to save your changes?")) != 0:

                self.show_wait_cursor (self.app_disksearch.window)
                ret_code = DSApp.DSApp.doc.diskList.save_disk_list (DSApp.DSApp.doc.archiveName)
                self.show_default_cursor (self.app_disksearch.window)

                if ret_code != 0:
                    self.display_message_dialog (gtk.MESSAGE_ERROR, _("Failed to save disk list!\nSee console output for more informations..."))
                    return 1

        gtk.main_quit()

    def display_disk_list (self, name2Select = None):
        """This method fills all disks in the GUI list. If a disk name is specified,
        it will be selected after the list update and the list will scroll to it.
        When no disk name is specified, then the previous selected disk will be
        selected again, if there is one."""

        # remember the sorting column and order if there is one
        table_sort_tuple = None
        if self.list_disks.get_model () != None:
            table_sort_tuple = self.list_disks.get_model ().get_sort_column_id ()

        # was no disk2select specified? => get current selected disk name
        iter2Select = None
        if name2Select == None:
            selectionTuple = self.list_disks.get_selection ().get_selected ()
            selectedIter = selectionTuple[1]
            if selectedIter != None:
                name2Select = self.list_disks.get_model ().get_value (selectedIter, 1)

        # create a dictionary for fast mapping of media type id to text
        dictTypes = dict (DSApp.DSApp.doc.diskList.media_types)

        # rebuild the liststore and remember the iter for later selection
        store = gtk.ListStore (str, str, int)
        for disk in DSApp.DSApp.doc.diskList.content:
            iter = store.append ()
            # type and name columns
            store.set (iter, 0, dictTypes[disk.type])
            store.set (iter, 1, disk.name)
            # timestamp column (optional)
            if disk.timestamp != None:
                store.set (iter, 2, disk.timestamp)

            if name2Select != None and disk.name == name2Select:
                iter2Select = iter

        # restore the sorting (column and order) if there was one
        if table_sort_tuple != None and table_sort_tuple[0] >= 0:
            store.set_sort_column_id (table_sort_tuple[0], table_sort_tuple[1])

        self.list_disks.set_model (store)

        # select the previous selected or specfied disk and scroll to it
        if iter2Select != None:
            self.list_disks.get_selection ().select_iter (iter2Select)
            self.list_disks.scroll_to_cell (store.get_path (iter2Select), None, False, 0, 0)

    def cellRenderDate (self, column, cell, model, iter):
        """Curstom cellrenderer which formats the date from the python
        date representation (int value). This is neccessary, othwerise
        sorting doesn't work correctly."""

        timestamp = model.get_value (iter, 2)
        strTimestamp = ""
        if timestamp != None and timestamp > 0:
            strTimestamp = time.strftime ("%x", time.localtime (timestamp))
        cell.set_property ('text', strTimestamp)
        return

    def about_app (self, *args):
        """Displays the applications about box."""

        DlgAbout.DlgAbout ()

    def add_disk (self, *args):
        """Starts the dialog for adding a new disk to list."""

        DlgDiskAdd.DlgDiskAdd ()

    def remove_disk (self, *args):
        """Removes the selected disk from the list (ask the user first)."""

        # get the name of the selected disk
        selection = self.list_disks.get_selection ()
        selected_tuple = selection.get_selected ()
        selected_tree_iter = selected_tuple[1]
        if selected_tree_iter == None:
            self.display_message_dialog (gtk.MESSAGE_ERROR, _("You need to select a disk first!"))
        else:
            # ask the user if he really wants to delete the disk
            if self.display_question_dialog (gtk.MESSAGE_QUESTION, _("Do you want to remove the selected disk?")) == 0:
                return
            # remove disk and update GUI list
            selected_name = self.list_disks.get_model ().get_value (selected_tree_iter, 1)
            DSApp.DSApp.doc.diskList.remove_disk (selected_name)
            self.display_disk_list ()

    def edit_disk (self, *args):
        """Starts the dialog for editing the selected disk."""

        DlgDiskEdit.DlgDiskEdit ()

    def search_files (self, *args):
        """Starts the dialog for searching files on the disks."""

        DlgSearch.DlgSearch ()

    def print_disk (self, *args):
        """Starts the dialog  for printing the selected disk"""

        DlgPrint.DlgPrint ()


    def display_message_dialog (self, dialog_type, dialog_text):
        """Displays the message dialog of the speicifed type with the passed text.
        The parrent window will be the main application window."""

        self.display_message_dialog_with_parrent (self.app_disksearch, dialog_type, dialog_text)

    def display_message_dialog_with_parrent (self, parrent_window, dialog_type, dialog_text):
        """Displays the message dialog of the speicifed type with the passed text
        with the specified parrent window."""

        dialog = gtk.MessageDialog (parrent_window, gtk.DIALOG_MODAL, dialog_type, gtk.BUTTONS_OK, dialog_text)
        dialog.connect ('response', lambda dialog, response: dialog.destroy ())
        dialog.set_resizable (False)
        dialog.show ()

    def display_question_dialog (self, dialog_type, dialog_text):
        """Displays the question dialog (with a YES and o NO button) of the
        speicifed type with the passed text. If the user presses NO, then 0
        will be returned. If he presses YES, "1" will be returned."""

        dialog = gtk.MessageDialog (self.app_disksearch, gtk.DIALOG_MODAL, dialog_type, gtk.BUTTONS_YES_NO, dialog_text)
        dialog.set_resizable (False)
        response = dialog.run ()
        dialog.destroy ()
        if response == gtk.RESPONSE_YES:
            return 1
        else:
            return 0

    def fill_media_type_optionmenu (self, option_menu, selected_type):
        """Fills the passed optionmenu with all media types and selects the spcefied one."""

        mTypes = gtk.Menu ()
        foundTypeIndex = 0
        for index in range (len (DSApp.DSApp.doc.diskList.media_types)):
            type = DSApp.DSApp.doc.diskList.media_types[index]
            miType = gtk.MenuItem (type[1])
            miType.show ()
            mTypes.append (miType)
            if (type[0] == selected_type):
                foundTypeIndex = index
        option_menu.set_menu (mTypes)
        option_menu.set_history (foundTypeIndex)

    def show_wait_cursor (self, gdk_window):
        """Shows a waitcursor on the specified GDK window."""

        gdk_window.set_cursor (gtk.gdk.Cursor (gtk.gdk.WATCH))
        self.process_pending_events ()

    def show_default_cursor (self, gdk_window):
        """Shows the default cursor (of parrent) on the specified GDK window."""

        gdk_window.set_cursor (None)
        self.process_pending_events ()

    def process_pending_events (self):
        """Processes all the pending events in the GTK event queue."""

        while gtk.events_pending ():
            gtk.main_iteration (False)

