#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# 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.
#
# Authors: Quinn Storm (quinn@beryl-project.org)
#          Patrick Niklaus (marex@opencompositing.org)
# Copyright (C) 2007 Quinn Storm

import pygtk
import gtk
import gtk.gdk

from ccm.Pages import *
from ccm.Utils import *
from ccm.Constants import *
from ccm.Conflicts import *

import locale
import gettext
locale.setlocale(locale.LC_ALL, "")
gettext.bindtextdomain("ccsm", DataDir + "/locale")
gettext.textdomain("ccsm")
_ = gettext.gettext

class MainWin(gtk.Window):
    def __init__(self, Context):
        gtk.Window.__init__(self)
        self.ShowingPlugin = None
        self.Context = Context
        self.connect("destroy", self.Quit)
        self.set_default_size(960, 580)
        self.set_title(_("CompizConfig Settings Manager"))
        try:
            self.set_icon (gtk.gdk.pixbuf_new_from_file(IconDir+"/apps/ccsm.svg"))
        except:
            pass
        
        self.Style = Style()
        
        # build the panes
        self.MainBox = gtk.HBox()
        self.add(self.MainBox)
        self.LeftPane = gtk.Alignment()
        self.LeftPane.set_size_request(230, 520)
        self.RightPane = gtk.Alignment()
        self.RightPane.set_border_width(5)
        self.RightPane.props.yscale = 1
        self.RightPane.props.xscale = 1
        self.RightPane.props.xalign = 0
        self.RightPane.props.yalign = 0
        self.LeftPane.props.yscale = 1
        self.LeftPane.props.xscale = 1
        self.LeftPane.props.xalign = 0
        self.LeftPane.props.yalign = 0
        self.MainBox.pack_start(self.LeftPane, False, False)
        self.MainBox.pack_start(self.RightPane, True, True)
        self.Categories = {}
        self.PluginImages = {}
        self.RightVadj = 0.0
        
        for pluginName, plugin in self.Context.Plugins.items():
            self.PluginImages[pluginName] = Image(plugin.Name, ImagePlugin)
        
        for category in sorted(self.Context.Categories, self.CatSortCompare):
            self.Categories[category] = []
            for pluginName, plugin in self.Context.Plugins.items():
                if plugin.Category == category:
                    self.Categories[category].append(plugin)
        
        self.BlockEnablePlugin = 0
        self.ResetMainWidgets()

    def Quit(self, *args):
        gtk.main_quit()

    def ResetMainWidgets(self):
        pluginsVPort = gtk.Viewport()
        leftChild = gtk.VBox(False, 10)
        leftChild.set_border_width(15)
        
        # Filter
        filterLabel = Label()
        filterLabel.set_markup("<span color='%s' size='large' weight='800'>%s</span>" % (self.Style.BrightColor, _("Filter")))
        filterLabel.props.xalign = 0.1
        if has_sexy:
            filterEntry = sexy.IconEntry()
            filterEntry.add_clear_button()
        else:
            filterEntry = gtk.Entry()
        Tooltips.set_tip(filterEntry, _("Filter your Plugin list"))
        filterEntry.connect("changed", self.FilterTable)
        leftChild.pack_start(filterLabel, False, False)
        leftChild.pack_start(filterEntry, False, False)

        # Screens
        if len(getScreens()) > 1:
            screenBox = gtk.combo_box_new_text()
            for screen in getScreens():
                screenBox.append_text(_("Screen %i") % screen)
            name = self.Context.CurrentBackend.Name
            screenBox.set_active(CurrentScreenNum)
            screenBox.connect("changed", self.ScreenChanged)
            screenLabel = Label()
            screenLabel.set_markup("<span color='%s' size='large' weight='800'>%s</span>" % (self.Style.BrightColor, _("Screen")))
            leftChild.pack_start(screenLabel, False, False)
            leftChild.pack_start(screenBox, False, False)

        # Categories
        categoryBox = gtk.VBox()
        categoryBox.set_border_width(10)
        for category in sorted(self.Categories, self.CatSortCompare):
            name = category or _("Uncategorized")
            categoryToggleLabel = Label(name)
            categoryToggle = PrettyButton()
            categoryToggle.set_relief(gtk.RELIEF_NONE)
            categoryToggle.add(categoryToggleLabel)
            categoryToggle.connect("clicked", self.ToggleCategory, category)
            categoryBox.pack_start(categoryToggle, False, False)
        categoryLabel = Label()
        categoryLabel.props.xalign = 0.1
        categoryLabel.set_markup("<span color='%s' size='large' weight='800'>%s</span>" % (self.Style.BrightColor, _("Category")))
        leftChild.pack_start(categoryLabel, False, False)
        leftChild.pack_start(categoryBox, False, False)

        # Exit Button
        exitButton = gtk.Button(gtk.STOCK_CLOSE)
        exitButton.set_use_stock(True)
        exitButton.connect('clicked', self.Quit)
        leftChild.pack_end(exitButton, False, False)

        # Advanced Search
        searchLabel = Label()
        searchLabel.set_markup("<span color='%s' size='large' weight='800'>%s</span>" % (self.Style.BrightColor, _("Advanced Search")))
        searchImage = gtk.Image()
        searchImage.set_from_stock(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
        searchButton = gtk.Button()
        searchButton.connect("clicked", self.ShowAdvancedFilter)
        searchButton.set_relief(gtk.RELIEF_NONE)
        searchFrame = gtk.HBox()
        searchFrame.pack_start(searchLabel, False, False)
        searchFrame.pack_end(searchImage, False, False)
        searchButton.add(searchFrame)
        leftChild.pack_end(searchButton, False, False)

        # Preferences
        prefLabel = Label()
        prefLabel.set_markup("<span color='%s' size='large' weight='800'>%s</span>" % (self.Style.BrightColor, _("Preferences")))
        prefImage = gtk.Image()
        prefImage.set_from_stock(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
        prefButton = gtk.Button()
        prefButton.connect("clicked", self.ShowPreferences)
        prefButton.set_relief(gtk.RELIEF_NONE)
        prefFrame = gtk.HBox()
        prefFrame.pack_start(prefLabel, False, False)
        prefFrame.pack_end(prefImage, False, False)
        prefButton.add(prefFrame)
        leftChild.pack_end(prefButton, False, False)

        pluginsVPort.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse(self.Style.BackgroundColor))
        rightChild = gtk.ScrolledWindow()
        rightChild.props.hscrollbar_policy = gtk.POLICY_NEVER
        rightChild.props.vscrollbar_policy = gtk.POLICY_AUTOMATIC
        rightChild.set_size_request(280,-1)
        pluginsVPort.set_focus_vadjustment (rightChild.get_vadjustment ())
        rightChild.add(pluginsVPort)
        self.BuildTable(pluginsVPort)
        rightChild.connect('size-allocate', self.RebuildTable)
        self.SetMainWidgets(leftChild, rightChild)

    def BuildTable(self, viewPort):
        pluginWindow = gtk.VBox()
        pluginWindow.set_border_width(10)
        viewPort.add(pluginWindow)

        self.TableCats = {}
        self.TableAttached = False
        self.LastCols = -1
        for category in sorted(self.Categories, self.CatSortCompare):
            pluginList = sorted(self.Categories[category], PluginSortCompare)
            categoryBox = gtk.VBox()
            categoryHeader = gtk.HBox()
            categoryHeader.set_spacing(10)
            categoryLabel = Label('', -1)
            pluginWindow.pack_start(categoryBox, False, False)

            name = category or _("Uncategorized")
            categoryLabel.set_markup("<span color='#aaa' size='x-large' weight='800'>%s</span>" % name)
            categoryImg = Image(name.lower().replace(" ", "_"), ImageCategory)
            if categoryImg:
                categoryHeader.pack_start(categoryImg, False, False)
            categoryHeader.pack_start(categoryLabel, False, False)
            categoryBox.pack_start(categoryHeader, False, False)
            
            categoryTab = gtk.Table()
            categoryTab.set_border_width(10)
            self.TableCats[category] = (categoryTab, [], [])
            categoryBox.pack_start(categoryTab, False, False)
            
            for plugin in pluginList:
                pluginButton = PrettyButton ()
                pluginButton.connect('clicked', self.ShowPlugin, plugin)
                pluginButton.set_size_request(200, -1)
                pluginButtonBox = gtk.HBox(False, 10)
                pluginButtonBox.set_border_width(10)
                pluginImage = self.PluginImages[plugin.Name]
                pluginLabel = Label(plugin.ShortDesc, 120)
                pluginButtonBox.pack_start(pluginImage, False, False)
                pluginButtonBox.pack_start(pluginLabel, True, True)
                pluginButton.add(pluginButtonBox)
                pluginBox = gtk.HBox()

                if plugin.Name !=  'core':
                    pluginEnable = gtk.CheckButton()
                    Tooltips.set_tip(pluginEnable, _("Enable %s") % plugin.ShortDesc)
                    pluginEnable.set_active(plugin.Enabled)
                    pluginEnable.connect("toggled", self.EnablePlugin, plugin)
                    pluginEnable.set_sensitive(self.Context.AutoSort)
                    pluginBox.pack_start(pluginEnable, False, False)

                Tooltips.set_tip(pluginButton, plugin.LongDesc)
                pluginBox.pack_start(pluginButton, True, True)
                pluginBox.set_size_request(220, -1)
                self.TableCats[category][1].append(pluginBox)
                self.TableCats[category][2].append(plugin)

    # targets:
    # 0 = plugin name and short description
    # 1 = plugin long description
    # 2 = category
    def FilterTable(self, widget, target=0):
        text = widget.get_text().lower()
        cols = self.LastCols
        foundPlugin = False

        if self.TableAttached:
            for categoryName, categoryContainer in self.TableCats.items():
                for pluginButton in categoryContainer[1]:
                    if pluginButton.get_parent():
                        categoryContainer[0].remove(pluginButton)

        for categoryName, categoryContainer in self.TableCats.items():
            col = 0
            row = 0
            empty = True
            for pluginButton in categoryContainer[1]:
                index = categoryContainer[1].index(pluginButton)
                shortDesc = categoryContainer[2][index].ShortDesc.lower()
                longDesc = categoryContainer[2][index].LongDesc.lower()
                name = categoryContainer[2][index].Name.lower()
                category = categoryName.lower()
                show = False

                if target == 0:
                    show = name.find(text) != -1 \
                    or shortDesc.find(text) != -1
                elif target == 1:
                    show = name.find(text) != -1 \
                    or shortDesc.find(text) != -1 \
                    or longDesc.find(text) != -1
                elif target == 2:
                    show = category.find(text) != -1

                if show:
                    empty = False
                    foundPlugin = True
                    categoryContainer[0].attach(pluginButton, col, col+1, row, row+1, 0)
                    col = col+1
                    if col >=  cols:
                        col = 0
                        row = row+1
            if empty:
                categoryContainer[0].get_parent().set_no_show_all(True)
                categoryContainer[0].get_parent().hide()
            else:
                categoryContainer[0].get_parent().set_no_show_all(False)
                categoryContainer[0].attach(gtk.Label(), cols+5, cols+6, 0, 1, gtk.EXPAND)
    
        # Search in long description
        if not foundPlugin and target == 0:
            self.FilterTable(widget, 1)
        # Search in category
        elif not foundPlugin and target == 1:
            self.FilterTable(widget, 2)
        # Nothing found -- Ported from Gnome-Control-Center.
        elif not foundPlugin and target == 2:

            # Already created only update message
            if not self.TableAttached:
                notFound = self.RightPane.get_child().get_child().get_child().get_children()[-1]
                notFound.update(text)
                return
            
            self.TableAttached = False
            
            box = self.RightPane.get_child().get_child().get_child()
            notFound = NotFoundBox(text)
            box.pack_start(notFound, True, False)
            
            self.show_all()
        # Something found, display it
        elif foundPlugin:
            # Clean up not found Message
            if not self.TableAttached:
                self.RightPane.get_child().get_child().get_child().get_children()[-1].destroy()
            
            self.TableAttached = True
            self.show_all()

    def RebuildTable(self, widget, request):
        cols = (request.width - 60) / 220
        if cols == self.LastCols:
            return
        
        self.LastCols = cols
        if self.TableAttached:
            for categoryName, categoryContainer in self.TableCats.items():
                for pluginButton in categoryContainer[1]:
                    categoryContainer[0].remove(pluginButton)
        
        for categoryName, categoryContainer in self.TableCats.items():
            col = 0
            row = 0
            for pluginButton in categoryContainer[1]:
                categoryContainer[0].attach(pluginButton, col, col+1, row, row+1, 0)
                col = col+1
                if col >= cols:
                    col = 0
                    row = row+1
            categoryContainer[0].attach(gtk.Label(), cols+5, cols+6, 0, 1, gtk.EXPAND)
        self.TableAttached = True
        self.show_all()
        self.RightPane.get_child().props.vadjustment.value = self.RightVadj

    def SetMainWidgets(self, leftWidget, rightWidget):
        pane = self.LeftPane.get_child()
        if pane:
            pane.destroy()
        pane = self.RightPane.get_child()
        if (pane):
            pane.destroy()
        self.LeftPane.add(leftWidget)
        self.RightPane.add(rightWidget)
        self.show_all()

    def CatSortCompare(self, v1, v2):
        if v1 == v2:
            return cmp(v1, v2)
        if self.Context.Plugins['core'].Category == v1:
            return cmp('', v2 or 'zzzzzzzz')
        if self.Context.Plugins['core'].Category == v2:
            return cmp(v1 or 'zzzzzzz', '')
        return cmp(v1 or 'zzzzzzzz', v2 or 'zzzzzzzz')

    def ShowPlugin(self, obj, select):
        self.RightVadj = self.RightPane.get_child().get_vadjustment().get_value()
        for name, value in self.PluginImages.items():
            widget = value.get_parent()
            if widget:
                widget.remove(value)
        pluginPage = PluginPage(select, self)
        self.ShowingPlugin = pluginPage
        self.SetMainWidgets(pluginPage.LeftWidget, pluginPage.RightWidget)
    
    def ShowAdvancedFilter(self, widget, run=0):
        if run == 0: # Well thats rather a hack but it works...
            self.TitleBuffer = self.get_title()
            self.set_title(self.TitleBuffer + " - Loading...")
            gobject.timeout_add(100, self.ShowAdvancedFilter, widget, 1)
            return

        self.RightVadj = self.RightPane.get_child().get_vadjustment().get_value()
        for name, value in self.PluginImages.items():
            widget = value.get_parent()
            if widget:
                widget.remove(value)
        filterPage = FilterPage(self, self.Context)
        self.SetMainWidgets(filterPage.LeftWidget, filterPage.RightWidget)
    
        self.set_title(self.TitleBuffer)
        self.TitleBuffer = False

        return False
    
    def ShowPreferences(self, widget):
        self.RightVadj = self.RightPane.get_child().get_vadjustment().get_value()
        for name, value in self.PluginImages.items():
            widget = value.get_parent()
            if widget:
                widget.remove(value)
        preferencesPage = PreferencesPage(self, self.Context)
        self.SetMainWidgets(preferencesPage.LeftWidget, preferencesPage.RightWidget)

    def UpdatePlugins(self):
        for category, container, plugins in self.TableCats.values():
                for i in range(len(plugins)):
                    if plugins[i].Name != 'core':
                        check = container[i].get_children()[0]
                        self.BlockEnablePlugin += 1
                        check.set_active(plugins[i].Enabled)
                        self.BlockEnablePlugin -= 1
    
    def EnablePlugin(self, widget, plugin):
        if self.BlockEnablePlugin > 0:
            return 

        # attempt to resolve conflicts...
        conflicts = plugin.Enabled and plugin.DisableConflicts or plugin.EnableConflicts
        conflict = PluginConflict(plugin, conflicts)
        if conflict.Resolve():
            plugin.Enabled = widget.get_active()
            self.UpdatePlugins()
        else:
            self.BlockEnablePlugin += 1
            widget.set_active(plugin.Enabled)
            self.BlockEnablePlugin -= 1
        plugin.Context.Write()

    def ToggleCategory(self, widget, category):
        categoryContainer = self.TableCats[category]
        categoryY = categoryContainer[0].get_parent().get_allocation().y
        parentY = self.RightPane.get_child().get_allocation().y
        parentHeight = self.RightPane.get_child().get_allocation().height
        categoryBox = self.RightPane.get_child().get_child().get_child()
        boxHeight = categoryBox.get_allocation().height
        posY = categoryY - parentY
        neededHeight = posY + parentHeight
        if neededHeight > boxHeight:
            posY =  boxHeight - parentHeight
        self.RightPane.get_child().props.vadjustment.value = posY
    
    def ScreenChanged(self, widget):
        self.Context.Write()
        self.CurrentScreenNum = widget.get_active()
        self.Context.Read()

    def BackToMain(self, obj):
        self.VisibleSettings = []
        self.ResetMainWidgets()
        del self.ShowingPlugin
        # make sure its cleaned up here, since this is a nice safe place to do so
        self.ShowingPlugin = None


syntax highlighted by Code2HTML, v. 0.9.1