from gtk import *
from gnome.ui import *
from iw import *
from string import *
from thread import *
from examine import *
import rpm
import GdkImlib
import string
import sys
import xpms
from gui import _

class IndividualPackageSelectionWindow (InstallWindow):

   def __init__ (self, ics):
       InstallWindow.__init__ (self, ics)

       self.todo = ics.getToDo ()
       ics.setTitle (_("Individual Package Selection"))
       ics.setNextEnabled (1)
       ics.readHTML ("sel-indiv")
       ics.setHelpEnabled (FALSE)
       self.DIR = 0
       self.DIR_UP = 1
       self.RPM = 2

       self.updatingIcons = FALSE

       self.idirImage = GdkImlib.create_image_from_xpm (xpms.I_DIRECTORY_XPM)
       self.idirUpImage = GdkImlib.create_image_from_xpm (xpms.I_DIRECTORY_UP_XPM)
       self.packageImage = GdkImlib.create_image_from_xpm (xpms.PACKAGE_XPM)
       self.packageSelectedImage = GdkImlib.create_image_from_xpm (xpms.PACKAGE_SELECTED_XPM)

   def getPrev (self):
       for x in self.ics.getICW ().stateList:
           if isinstance (x, PackageSelectionWindow):
               return PackageSelectionWindow
           elif isinstance (x, UpgradeExamineWindow):
               return UpgradeExamineWindow
       return None


   def build_tree (self, x):
       if (x == ()): return ()
       if (len (x) == 1): return (x[0],)
       else: return (x[0], self.build_tree (x[1:]))

   def merge (self, a, b):
       if a == (): return self.build_tree (b)
       if b == (): return a
       if b[0] == a[0]:
           if len (a) > 1 and isinstance (a[1], type (())):
               return (a[0],) + (self.merge (a[1], b[1:]),) + a[2:]
           elif b[1:] == (): return a
           else: return (a[0],) + (self.build_tree (b[1:]),) + a[1:]
       else:
           return (a[0],) + self.merge (a[1:], b)

   def build_ctree (self, list, cur_parent = None, prev_node = None, path = ""):
       if (list == ()): return

       if (len (list) > 1 and isinstance (list[1], type (()))): leaf = FALSE
       else: leaf = TRUE

       if isinstance (list[0], type (())):
           self.build_ctree (list[0], prev_node, None, self.ctree.node_get_row_data (prev_node))
           self.build_ctree (list[1:], cur_parent, None, path)
       else:
           node = self.ctree.insert_node (cur_parent, None, (list[0],), 2,
                                          self.closed_p, self.closed_b, self.open_p, self.open_b, leaf)
           cur_path = path + "/" + list[0]
           self.ctree.node_set_row_data (node, cur_path)
           self.build_ctree (list[1:], cur_parent, node, path)

   def draw_root_icons (self):
       self.iconList.freeze ()
       self.iconList.clear ()
       for x in self.ctree.base_nodes ():
           dirName = self.ctree.get_node_info (x)[0]
           pos = self.iconList.append_imlib (self.idirImage, dirName)
           self.iconList.set_icon_data (pos, (self.DIR, x))
       self.iconList.thaw ()


   def get_rpm_desc (self, header):
       desc = replace (header[rpm.RPMTAG_DESCRIPTION], "\n\n", "\x00")
       desc = replace (desc, "\n", " ")
       desc = replace (desc, "\x00", "\n\n")
       return desc

   def clear_package_desc (self):
       self.currentPackage = None
       self.packageName.set_text ("")
       self.packageSize.set_text ("")
       self.packageDesc.freeze ()
       self.packageDesc.delete_text (0, -1)
       self.packageDesc.thaw ()
       self.cbutton.set_active (FALSE)
       self.cbutton.set_sensitive (FALSE)


   def select_icon (self, iconList, arg1, event, *args):
       if event and event.type != GDK._2BUTTON_PRESS and event.type != GDK.BUTTON_PRESS:
           return
       icon_data = iconList.get_icon_data (arg1)
       if not icon_data: return

       if event and iconList.icon_is_visible (arg1) != VISIBILITY_FULL:
           allocation = iconList.get_allocation ()
           if (event.y - self.iconListAdj.value) < (allocation[3]/2):
               self.iconList.moveto (arg1, 0.0)
           else:
               self.iconList.moveto (arg1, 1.0)

       if event == None or event.type == GDK.BUTTON_PRESS:
           if icon_data[0] == self.RPM:
               header = icon_data[1]
               # if we're already displaying the current package, don't redraw
               if self.packageName.get () == "%s-%s-%s" % (header[rpm.RPMTAG_NAME],
                                                           header[rpm.RPMTAG_VERSION],
                                                           header[rpm.RPMTAG_RELEASE]):
                   return

               self.currentPackage = header
               self.currentPackagePos = arg1
               self.cbutton.set_sensitive (TRUE)
               if header.selected:
                   self.cbutton.set_active (TRUE)
               else:
                   self.cbutton.set_active (FALSE)

               self.packageName.set_text ("%s-%s-%s" % (header[rpm.RPMTAG_NAME],
                                                        header[rpm.RPMTAG_VERSION],
                                                        header[rpm.RPMTAG_RELEASE]))
               self.packageSize.set_text ("%.1f KBytes" % (header[rpm.RPMTAG_SIZE] / 1024.0))
               self.packageDesc.freeze ()
               self.packageDesc.delete_text (0, -1)
               self.packageDesc.insert_defaults (self.get_rpm_desc (header))
               self.packageDesc.thaw ()
           else:
               self.clear_package_desc ()
           return

       if icon_data[0] == self.RPM:
           active = self.cbutton.get_active ()
           if active == TRUE:
               self.cbutton.set_active (FALSE)
           else:
               self.cbutton.set_active (TRUE)

       if icon_data[0] == self.DIR_UP:
           current_node = icon_data[1].parent
           if current_node:
               self.ctree.select (current_node)
           else:
               # handle the imaginary root node
               current_node = self.ctree.base_nodes ()[0]
               self.ctree.unselect (icon_data[1])
               self.draw_root_icons ()

       elif icon_data[0] == self.DIR:
           current_node = icon_data[1]
           self.ctree.select (current_node)
           if (current_node.parent):
               self.ctree.expand_to_depth (current_node.parent, 1)
       else: return

       if self.ctree.node_is_visible (current_node) != VISIBILITY_FULL:
           self.ctree.node_moveto (current_node, 0, 0.5, 0.0)

   def select (self, ctree, node, *args):
       self.clear_package_desc ()
       self.iconList.freeze ()
       self.iconList.clear ()
       self.iconList.append_imlib (self.idirUpImage, _("Up"))
       self.iconList.set_icon_data (0, (self.DIR_UP, node))
       for x in node.children:
           dirName = ctree.get_node_info (x)[0]
           pos = self.iconList.append_imlib (self.idirImage, dirName)
           self.iconList.set_icon_data (pos, (self.DIR, x))

       try:
           # this code is wrapped in a generic exception handler since we dont
           # care if we access a namespace that lacks rpms

           # drop the leading slash off the package namespace
           for header in self.flat_groups[ctree.node_get_row_data (node)[1:]]:
               if header.selected:
                   packageIcon = self.packageSelectedImage
                   self.cbutton.set_active (TRUE)
               else:
                   packageIcon = self.packageImage
                   self.cbutton.set_active (FALSE)

               pos = self.iconList.append_imlib (packageIcon, header[rpm.RPMTAG_NAME])
               self.iconList.set_icon_data (pos, (self.RPM, header))
       except:
           pass

       # make sure that the iconList is reset to show the initial files in a dir,
       # unless we re rebuilding the icons because one has been selected for install
       if not self.updatingIcons:
           self.iconListSW.get_vadjustment ().set_value (0.0)
       self.iconList.thaw ()
       self.iconList.show_all ()


   def installButtonToggled (self, cbutton, *args):
       if not self.currentPackage: return
       oldSelectedStatus = self.currentPackage.selected

       if cbutton.get_active ():
           self.currentPackage.selected = 1
       else:
           self.currentPackage.selected = 0


       if oldSelectedStatus != self.currentPackage.selected:
           self.updatingIcons = TRUE
           self.ctree.select (self.ctree.selection[0])
           self.iconList.select_icon (self.currentPackagePos)
           self.updatingIcons = FALSE

#            self.iconList.freeze ()
#            if self.currentPackage.selected:
#                packageIcon = "/home/devel/pnfisher/gnome-package-checked.png"
#            else:
#                packageIcon = "/usr/src/gnorpm/gnome-package.xpm"

#            print self.currentPackagePos
#            self.iconList.remove (self.currentPackagePos)
#            print _("got here")
#            self.iconList.insert (self.currentPackagePos, packageIcon,
#                                  self.currentPackage[rpm.RPMTAG_NAME])
#            self.iconList.set_icon_data (self.currentPackagePos, (self.RPM, self.currentPackage))

#            self.iconList.thaw ()


   def getScreen (self):
       threads_leave ()
       self.todo.getHeaderList()
       threads_enter ()

       self.path_mapping = {}
       self.ctree = GtkCTree ()
       self.ctree.set_selection_mode (SELECTION_BROWSE)
       # Kludge to get around CTree s extremely broken focus behavior
       self.ctree.unset_flags (CAN_FOCUS)

       if (not self.__dict__.has_key ("open_p")):
           self.open_p, self.open_b = create_pixmap_from_xpm_d (self.ctree,
                                                                None, xpms.DIRECTORY_OPEN_XPM)
           self.closed_p, self.closed_b = create_pixmap_from_xpm_d (self.ctree,
                                                                    None, xpms.DIRECTORY_CLOSE_XPM)

       groups = {}

       # go through all the headers and grok out the group names, placing
       # packages in lists in the groups dictionary.

       for key in self.todo.hdList.packages.keys():
           header = self.todo.hdList.packages[key]
           if not groups.has_key (header[rpm.RPMTAG_GROUP]):
               groups[header[rpm.RPMTAG_GROUP]] = []
           groups[header[rpm.RPMTAG_GROUP]].append (header)

       keys = groups.keys ()
       keys.sort ()
       self.flat_groups = groups
       index = 0

       # now insert the groups into the list, then each group s packages
       # after sorting the list
       def cmpHdrName(first, second):
           if first[rpm.RPMTAG_NAME] < second[rpm.RPMTAG_NAME]:
               return -1
           elif first[rpm.RPMTAG_NAME] == second[rpm.RPMTAG_NAME]:
               return 0
           return 1

       groups = ()
       for key in keys:
           self.flat_groups[key].sort (cmpHdrName)
           groups = self.merge (groups, split (key, "/"))
       self.ctree.freeze ()
       self.build_ctree (groups)

       for base_node in self.ctree.base_nodes ():
           self.ctree.expand_recursive (base_node)
       self.ctree.columns_autosize ()
       for base_node in self.ctree.base_nodes ():
           self.ctree.collapse_recursive (base_node)
       self.ctree.thaw ()

       self.ctree.connect ("tree_select_row", self.select)
       sw = GtkScrolledWindow ()
       sw.set_border_width (5)
       sw.set_policy (POLICY_NEVER, POLICY_AUTOMATIC)
       sw.add (self.ctree)
       iconHBox = GtkHBox ()
       iconHBox.pack_start (sw, FALSE)

       self.iconList = GnomeIconList (90)
       self.iconList.set_selection_mode (SELECTION_MULTIPLE)
       self.iconList.connect ("select_icon", self.select_icon)
       self.draw_root_icons ()

       self.iconListSW = GtkScrolledWindow ()
       self.iconListSW.set_border_width (5)
       self.iconListSW.set_policy (POLICY_NEVER, POLICY_AUTOMATIC)
       self.iconListSW.add (self.iconList)
       self.iconListAdj = self.iconListSW.get_vadjustment ()
       iconHBox.pack_start (self.iconListSW)

       descVBox = GtkVBox ()
       descVBox.pack_start (GtkHSeparator (), FALSE, padding=3)


       hbox = GtkHBox ()
       label = GtkLabel (_("Name: "))
       self.packageName = GtkLabel ()
       self.packageName.set_alignment (0.0, 0.0)
       hbox.pack_start (label, FALSE, padding=5)
       hbox.pack_start (self.packageName, FALSE)
       label = GtkLabel (_("Package Details"))
       label.set_alignment (1.0, 1.0)
       hbox.pack_start (label, padding=5)
       descVBox.pack_start (hbox, FALSE)

       hbox = GtkHBox ()
       label = GtkLabel (_("Size: "))
       self.packageSize = GtkLabel ()
       self.packageSize.set_alignment (0.0, 0.5)
       hbox.pack_start (label, FALSE, padding=5)
       hbox.pack_start (self.packageSize, FALSE)
       align = GtkAlignment (1.0, 0.0)
       self.cbutton = GtkCheckButton (_("Select Package For Installation"))
       self.cbutton.set_sensitive (FALSE)
       self.cbutton.connect ("toggled", self.installButtonToggled)
       self.cbutton.children()[0].set_alignment (1.0, 0.5)
       align.add (self.cbutton)
       hbox.pack_start (align, padding=5)
       descVBox.pack_start (hbox, FALSE)

       descSW = GtkScrolledWindow ()
       descSW.set_border_width (5)
       descSW.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC)

       self.packageDesc = GtkText ()
       self.packageDesc.set_word_wrap (TRUE)
       self.packageDesc.set_line_wrap (TRUE)
       self.packageDesc.set_editable (FALSE)
       descSW.add (self.packageDesc)
       descSW.set_usize (-1, 100)

       descVBox.pack_start (descSW)

#        descFrame = GtkFrame (_("Package Details"))
#        descFrame.set_border_width (5)
#        descFrame.add (descVBox)

       vbox = GtkVBox ()
       vbox.pack_start (iconHBox)
       vbox.pack_start (descVBox, FALSE)

       return vbox

class PackageSelectionWindow (InstallWindow):
   def __init__ (self, ics):
       InstallWindow.__init__ (self, ics)

       ics.setTitle (_("Package Group Selection"))
       ics.setNextEnabled (1)
       ics.readHTML ("sel-group")
       self.selectIndividualPackages = FALSE

   def getNext (self):
       if not self.__dict__.has_key ("individualPackages"):
           return None

       # turn off all the comps
       for comp in self.todo.comps:
           if not comp.hidden:
               comp.unselect(0)

       # turn on each package group in order (msw's code requires this)
       for (button, comp) in self.checkButtons:
           if button.get_active ():
               comp.select (1)

       del self.checkButtons

       gotoIndividualPackages = self.individualPackages.get_active ()
       del self.individualPackages

       if gotoIndividualPackages:
           self.selectIndividualPackages = TRUE
           return IndividualPackageSelectionWindow
       else:
           self.selectIndividualPackages = FALSE

       return None

   def getScreen (self):
       threads_leave ()
       self.todo.getHeaderList ()
       self.todo.getCompsList()
       threads_enter ()

       sw = GtkScrolledWindow ()
       sw.set_border_width (5)
       sw.set_policy (POLICY_AUTOMATIC, POLICY_AUTOMATIC)

       box = GtkVBox (FALSE, 0)

       self.checkButtons = []
       for comp in self.todo.comps:
           if not comp.hidden:
               pixname = string.replace (comp.name, ' ', '-')
               pixname = string.replace (pixname, '/', '-')
               pixname = string.replace (pixname, '.', '-')
               pixname = string.replace (pixname, '(', '-')
               pixname = string.replace (pixname, ')', '-')
               pixname = string.lower (pixname) + ".png"
               picture = None
               checkButton = None
               im = self.ics.readPixmap (pixname)
               if im:
                   im.render ()
                   pix = im.make_pixmap ()
                   hbox = GtkHBox (FALSE, 5)
                   hbox.pack_start (pix, FALSE, FALSE, 0)
                   label = GtkLabel (comp.name)
                   label.set_alignment (0.0, 0.5)
                   hbox.pack_start (label, TRUE, TRUE, 0)
                   checkButton = GtkCheckButton ()
                   checkButton.add (hbox)
               else:
                   checkButton = GtkCheckButton (comp.name)

               checkButton.set_active (comp.selected)
               self.checkButtons.append ((checkButton, comp))
               box.pack_start (checkButton)

       sw.add_with_viewport (box)
       box.set_focus_hadjustment(sw.get_hadjustment ())
       box.set_focus_vadjustment(sw.get_vadjustment ())

       vbox = GtkVBox (FALSE, 5)
       self.individualPackages = GtkCheckButton (_("Select individual packages"))
       self.individualPackages.set_active (self.selectIndividualPackages)
       align = GtkAlignment (0.5, 0.5)
       align.add (self.individualPackages)

       vbox.pack_start (sw, TRUE)
       vbox.pack_start (align, FALSE)

       return vbox