# Copyright (C) 2009 LottaNZB Development Team
# 
# 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; version 3.
# 
# 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 gtk

from kiwi.ui.delegates import GladeDelegate

from lottanzb.plugins import PluginBase, PluginConfig, PluginPrefsTabBase
from lottanzb.util import gproperty, _

class Config(PluginConfig):
    """The plug-in is enabled by default."""
    
    enabled = gproperty(type=bool, default=True)

class Plugin(PluginBase):
    title = _("Notification area icon")
    description = _("Displays an icon in the notification area and allows "
        "LottaNZB to be controlled through it.")
    author = _("LottaNZB Development Team")
    
    # The gtk.StatusIcon object that represents the icon in the
    # notification area.
    icon = None
    
    menu_delegate = None
    main_window = None
    
    def refresh(self):
        """
        Makes sure that the application is not entirely shut down if the main
        window is closed while the plug-in is enabled.
        """
        
        if self.main_window:
            self.main_window.quit_on_close = not self.enabled
    
    def load(self):
        """
        Creates the status icon if necessary and makes sure that it's visible.
        """
        
        if self.icon:
            def show_icon():
                self.icon.set_visible(True)
            
            self.do_with_rgb_colormap(show_icon)
        elif self.main_window:
            def create_icon():
                """
                Helper method that creates the notification area icon and
                registers all event handlers.
                """
                
                self.icon = gtk.StatusIcon()
                self.icon.set_from_icon_name("lottanzb")
                self.icon.set_tooltip("LottaNZB")
                self.icon.connect("popup-menu", self.show_menu)
                self.icon.connect("activate", self.toggle_main_window)
            
            self.do_with_rgb_colormap(create_icon)
        
        PluginBase.load(self)
    
    def unload(self):
        """Hides the status menu if necessary."""
        
        if self.icon:
            self.icon.set_visible(False)
        
        PluginBase.unload(self)
    
    def do_with_rgb_colormap(self, function):
        """
        Workaround for bug http://bugzilla.gnome.org/show_bug.cgi?id=501842
        
        This method ensures that the default RGB color map is active while the
        passed function is being executed and returns to the previous color
        map afterwards.
        """
        
        # We cannot do it without the gtk.Screen provided by the main window.
        if self.main_window:
            screen = self.main_window.toplevel.get_screen()
            current_colormap = screen.get_default_colormap()
            
            try:
                assert current_colormap == screen.get_rgba_colormap()
            except (AttributeError, AssertionError):
                rgba_support = False
            else:
                screen.set_default_colormap(screen.get_rgb_colormap())
                rgba_support = True
            
            function()
            
            # Restore the RGBA color map if necessary.
            if rgba_support:
                screen.set_default_colormap(current_colormap)
    
    def show_menu(self, icon, button, activate_time):
        """Display the status icon menu."""
        
        position = gtk.status_icon_position_menu
        
        self.menu_delegate.menu.popup(None, None, position, button, \
            activate_time, icon)
    
    def toggle_main_window(self, *args):
        """
        Does what the method name says. ;-) It just changes the visibility of
        the main window.
        """
        
        if self.main_window_visible:
            self.main_window.hide()
        else:
            self.main_window.show()
        
        return True
    
    def on_main_window_ready(self, main_window):
        """
        Internal method that registers the 'Close' file menu entry as well
        as the notification area icon menu.
        """
        
        self.main_window = main_window
        
        close_menu_item = gtk.ImageMenuItem(gtk.STOCK_CLOSE)
        close_menu_item.connect("activate", self.toggle_main_window)
        
        self.insert_menu_item(main_window.file_menu, close_menu_item, -2)
        
        self.connect_when_enabled(
            self.main_window.toplevel,
            "delete-event",
            self.toggle_main_window
        )
        
        self.menu_delegate = MenuDelegate()
        
        self.menu_delegate.open.connect("toggled", self.on_open_toggled)
        self.menu_delegate.add.connect("activate", self.on_add_activated)
        self.menu_delegate.pause.connect("toggled", self.on_pause_toggled)
        self.menu_delegate.quit.connect("activate", self.on_quit_activated)
        
        self.main_window.toplevel.connect("show", self.update_open_checkbox)
        self.main_window.toplevel.connect("hide", self.update_open_checkbox)
        self.main_window.pause.connect("activate", self.update_pause_checkbox)
        
        if self.enabled:
            self.load()
    
    def on_open_toggled(self, widget):
        """
        Makes sure that the main window's visibility matches the state of the
        'Show main window' checkbox.
        """
        
        if widget.get_active() != self.main_window_visible:
            self.toggle_main_window()
    
    def on_add_activated(self, *args):
        """
        Show the 'Add file' dialog.
        
        Wrapper method that ensures that no unwanted arguments are passed to the
        corresponding `gui.main.Window` method.
        """
        
        self.main_window.show_add_dialog()
    
    def on_pause_toggled(self, widget):
        """Pause or resume downloads."""
        
        self.main_window.pause.set_active(widget.get_active())
    
    def on_quit_activated(self, *args):
        """
        Quit the application.
        
        Wrapper method that ensures that no unwanted arguments are passed to the
        corresponding `core.App` method.
        """
        
        self.app.quit()
    
    def update_open_checkbox(self, window):
        """
        If the main window is visibility of the main window is changed by the
        user by closing the window etc, this method changes the 'Show main
        window' checkbox in the notification area icon menu accordingly.
        """
        
        self.menu_delegate.open.set_active(window.get_property("visible"))
    
    def update_pause_checkbox(self, widget):
        """
        If the downloads are paused from the main window, also update the
        checkbox in the notification area menu.
        """
        
        self.menu_delegate.pause.set_active(widget.get_active())
    
    @property
    def main_window_visible(self):
        """
        Simple shortcut property that returns the visibility of the main
        window.
        """
        
        return self.main_window.toplevel.get_property("visible")

class MenuDelegate(GladeDelegate):
    """
    This glade file contains a nearly empty gtk.Window, which isn't actually
    used, but necessary because Kiwi doesn't allow delegates with a gtk.Menu
    root object.
    """
    
    gladefile = "plugin_notification_area_menu"
