#!/usr/bin/env python

# (c) 2007 Canonical Ltd.
#
# 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.

'''KDE user interface implementation.'''

import sys
import os.path

from jockey.ui import AbstractUI
from jockey.oslib import OSLib

# import UIs - now done via UI
# from kde.manager_window_ui import Ui_manager_window
#from kde.download_progress_ui import Ui_download_progress

from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import uic

# the following will be useful for hardy+1

#from PyKDE4.kdecore import *
#from PyKDE4.kdeui import *

class JockeyTreeWidgetItem(QTreeWidgetItem):
    '''A subclassed QTreeWidgetItem that can store its handler.

    A workaround for the Model/View framework which will be implemented later
    on.
    '''
    def __init__(self, parent, handler):
        self.handler = handler
        QTreeWidgetItem.__init__(self, parent)

class KDEUI(AbstractUI):
    '''KDE user interface implementation.'''

    def convert_keybindings(self,str):
        # does nothing yet
        return str

    def ui_init(self):
        '''Initialize UI.'''

        # load UI template
        if os.path.exists('/usr/share/jockey/ManagerWindowKDE4.ui'): 
            self.mw = uic.loadUi('/usr/share/jockey/ManagerWindowKDE4.ui')
        elif os.path.exists('kde/ManagerWindowKDE4.ui'): 
            self.mw = uic.loadUi('kde/ManagerWindowKDE4.ui')

        # load translations
        self.ui_load_translations()

        # set icon
        if os.path.exists('/usr/share/icons/hicolor/22x22/apps/jockey-kde.png'):
            icon = QPixmap('/usr/share/icons/hicolor/22x22/apps/jockey-kde.png')
            largeIcon = QPixmap('/usr/share/icons/hicolor/48x48/apps/jockey-kde.png')
        elif os.path.exists('data/icons/22x22/apps/jockey-kde.png'):
            icon = QPixmap('data/icons/22x22/apps/jockey-kde.png')
            largeIcon = QPixmap('data/icons/48x48/apps/jockey-kde.png')

        # load tray icon
        # not visible yet
        self.trayicon = QSystemTrayIcon(self.mw)
        #print self.trayicon
        # connect the tray signals
        self.mw.connect(self.trayicon,
                        SIGNAL('activated(QSystemTrayIcon::ActivationReason)'),
                        self.open_app)

        self.mw.connect(self.trayicon,
                        SIGNAL('messageClicked()'), self.open_app)

        self.trayicon.setIcon(QIcon(icon))

        # Set window icon
        self.mw.setWindowIcon(QIcon(icon))

        # connect signals
        self.mw.connect(self.mw.buttonBox, SIGNAL('rejected()'), self.on_quit)
        self.mw.connect(self.mw.buttonBox, SIGNAL('helpRequested()'),
                        self.on_button_help_clicked)

        # Set Logo
        self.mw.logo_image.setPixmap(largeIcon)

        # disable help button if help is not available
        if not OSLib.inst.ui_help_available(self):
            self.mw.buttonBox.setStandardButtons(QDialogButtonBox.Close)

        #parent.set_title_label(self.ui.label_heading, False)
        #self.ui.treeview_drivers.headerItem().setText(0, self.enabled_text)
        #self.ui.treeview_drivers.headerItem().setText(1, self.component_text)
        #self.ui.treeview_drivers.headerItem().setText(2, self.status_text)
        #self.reloadListView()


        # load download progress UI

        if os.path.exists('/usr/share/jockey/DownloadProgressQt.ui'):
            self.dlui = uic.loadUi('/usr/share/jockey/DownloadProgressQt.ui')
        elif os.path.exists('./kde/DownloadProgressQt.ui'):
            self.dlui = uic.loadUi('./kde/DownloadProgressQt.ui')
        
        # connect the signals
        self.dlui.connect(self.dlui.buttonCancel, SIGNAL('clicked()'),
                          self.on_download_cancel)


        # update tree model
        self.update_tree_model()

        # we have to connect this signal here, but that still is a
        # bad solution.
        self.mw.connect(self.mw.treeview_drivers,
                        SIGNAL('itemChanged(QTreeWidgetItem*, int )'),
                        self.on_handler_changed)

        # show the dialog
        # or show the notification
    
        try:
            [title, text] = self.trigger_noti
            self.mw.hide()
            self.load_notification(title, text)

        except AttributeError:
            #print "showing"
            self.mw.show()


    def ui_load_translations(self):
        '''Load the localised strings provided by AbstractUI.'''

        # main title (window caption)
        self.mw.setWindowTitle(self.main_window_title())

        # text on top of the window
        (heading, subtext) = self.main_window_text()
        self.mw.label_heading.setText(heading)

        # captions of the columns
        self.mw.treeview_drivers.headerItem().setText(0, self.string_handler)
        self.mw.treeview_drivers.headerItem().setText(1, self.string_enabled)
        self.mw.treeview_drivers.headerItem().setText(2, self.string_status)

    def ui_main_loop(self):
        '''Main loop for the user interface.'''

        QApplication.exec_()

    def error_message(self, title, text):
        '''Present an error message box.'''

        text = '<h3>' + title + '</h3>' + text

        msgbox = QMessageBox.warning(self.mw, title, text, QMessageBox.Close )

        # QMessageBox returns a StandardButton, output a boolean
        return msgbox == QMessageBox.Close


    def confirm_action(self, title, text, subtext=None, action=None):
        '''Present a confirmation dialog.

        If action is given, it is used as button label instead of the default
        'OK'.  Return True if the user confirms, False otherwise.
        '''
        text = '<h3>%s</h3>' % text
        if subtext:
            text += subtext
        text = text.replace('\n', '<br/>')
        msgbox = QMessageBox(title, text, QMessageBox.Question,
                QMessageBox.Ok | QMessageBox.Default, 
                QMessageBox.Cancel | QMessageBox.Escape, 
                QMessageBox.NoButton,
                self.mw)
        if action:
            msgbox.setButtonText(0, action)

        mb = msgbox.exec_()
        # QMessageBox returns a StandardButton, output a boolean
        return mb == QMessageBox.Ok

    def ui_notification(self, title, text):
        '''Trigger a notification.

        The actual creation of the notification icon has to be done after the
        UI repaint.
        '''
        self.trigger_noti = [title, text]
        if not hasattr(self, 'mw'):
            self.ui_init()

    def load_notification(self, title, text):
        '''Gets called after the UI is built.'''

        self.trayicon.show()
        self.ui_idle()
        self.trayicon.showMessage(title, text)

        #print "Notify us!" # debug

    def open_app(self, argument = None):
        '''Tray activation callback, launch the elevated app.'''

        OSLib.inst.open_app(self)

    def ui_idle(self):
        '''Redraw app while external package manager progresses.'''

        QApplication.processEvents()    

    def ui_download_start(self, url, total_size):
        '''Create a progress dialog for a download of given URL.

        total_size specifes the number of bytes to download, or -1 if it cannot
        be determined. In this case the dialog should display an indeterminated
        progress bar (bouncing back and forth).
        '''

        # hint: you achieve the indeterminate value by setting
        # both min and max to 0

        if(total_size == -1):
            total_size = 0

        self.dlui.progressBar.setMinimum(0)
        self.dlui.progressBar.setMaximum(total_size)

        # set translations
        self.dlui.downloadLabel.setText(self.string_download_progress_title)
        self.dlui.firmwareName.setText(url)

        self.dlui.show()
        self.cancel_download = False 

    def ui_download_progress(self, current_size, total_size):
        '''Update download progress of current download.
        
        This should return True to cancel the current download, and False
        otherwise.
        '''
        #print "setting value to " + current_size
        self.dlui.progressBar.setValue(current_size)

        return self.cancel_download

    def ui_download_finish(self):
        '''Close the current download progress dialog.'''
        self.dlui.close()

    # callbacks

    def on_quit(self):
        '''Callback for clicked Close button.'''

        self.mw.close()

    def on_button_help_clicked(self):
        '''Callback for clicked Help button.'''

        OSLib.inst.ui_help(self)

    def on_handler_changed(self, item, column):
        '''Callback for flipping checkboxes.'''

        if self.user == False:
            pass
        else:
            # check if the click comes from a user
            # it may also have been the update_tree_model() function
            self.toggle_handler(item.handler)
            self.update_tree_model()

    def on_download_cancel(self):
        '''Callback for cancelling the download.'''

        self.cancel_download = True
        return True

    def update_tree_model(self):
        '''Updates the tree model with up to date information.

        Unfortunately, due to time contraints, the KDE frontend does not use a
        Model/View framework yet.'''

        # we have to workaround the model/view with a subclassed
        # QTreeWidgetItem
        
        # it's not the user, disable checkbox toggling
        self.user = False

        # first clear the list
        self.mw.treeview_drivers.clear()

        # then repopulate
        ha = []
        parents = {}
        for handler in sorted(self.handlers, key=lambda x: (x.ui_category(), x.name())):

            is_enabled = handler.enabled()
            is_used = handler.used()
            category = handler.ui_category()
            if category not in parents:
                parents[category] = QTreeWidgetItem(self.mw.treeview_drivers)
                parents[category].setText(0, category)
            # icons not implemented yet
            if (is_enabled != is_used) and handler.changed():
                status, icon = self.string_restart, 'STOCK_REFRESH'
            elif is_used:
                status, icon = self.string_in_use, 'STOCK_YES'
            else:
                status, icon = self.string_not_in_use, 'STOCK_NO'

            # load the item
            # here we make use of the subclassed QTreeWidgetItem
            i = JockeyTreeWidgetItem(parents[category], handler)

            # the first column contains the name
            i.setText(0, handler.name())

            # the second column is checkable, based on the is_enabled
            # boolean
            if(is_enabled):
                i.setCheckState(1, Qt.Checked)
            else:
                i.setCheckState(1, Qt.Unchecked)

            # the third column shows whether the driver is in use
            # or not
            # TODO: make it show an icon, not just True/False
            i.setText(2, status)

            # We want to adjust the columns and expand the tree.
            self.mw.treeview_drivers.expandAll()
            self.mw.treeview_drivers.resizeColumnToContents(0)
            self.mw.treeview_drivers.resizeColumnToContents(1)
            self.mw.treeview_drivers.resizeColumnToContents(2)

            # self.model.append(parents[category], [ handler, is_enabled, is_used,
            #                    handler.name(), is_enabled, pixbuf,
            #                    status, True ])

        # user is allowed to click again
        self.user = True

if __name__ == '__main__':
    qapp = QApplication(sys.argv) 
    OSLib.inst = OSLib()
    u = KDEUI()
    sys.exit(u.run())
