#	Programmer:	Daniel Pozmanter
#	E-mail:		drpython@bluebottle.com
#	Note:		You must reply to the verification e-mail to get through.
#
#	Copyright 2003-2005 Daniel Pozmanter
#
#	Distributed under the terms of the GPL (GNU Public License)
#
#    DrPython 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
	
#Plugins Dialog

import os, os.path, shutil, zipfile, tempfile, urllib, thread, sys
import wx, wx.wizard, wx.lib.dialogs, wx.html, wx.lib.newevent
import drScrolledMessageDialog
import drFileDialog
from drPrefsFile import ExtractPreferenceFromText

#*******************************************************************************
#Update Plugin List Dialog

(UpdatePluginDialog, EVT_UPDATE_PLUGINDIALOG) = wx.lib.newevent.NewEvent()

class drUpdatePluginListDialog(wx.Dialog):
	def __init__(self, parent):
		wx.Dialog.__init__(self, parent, -1, "Updating Plugin List", wx.DefaultPosition, wx.Size(300, 200), wx.DEFAULT_DIALOG_STYLE)
		
		self.parent = parent.parent
		
		self.stxtDownload = wx.StaticText(self, -1, "Downloading...")		
		
		self.txtStatus = wx.TextCtrl(self, -1, '', size=(250, -1), style=wx.TE_READONLY)
				
		self.theSizer = wx.BoxSizer(wx.VERTICAL)
		
		self.theSizer.Add(self.stxtDownload, 0, wx.EXPAND)
		self.theSizer.Add(self.txtStatus, 1, wx.EXPAND)
		
		self.SetAutoLayout(True)
		self.SetSizerAndFit(self.theSizer)		
		
		self.Bind(EVT_UPDATE_PLUGINDIALOG, self.UpdateUI)
		
		self.error = False
		
		thread.start_new_thread(self.RunInThread, ())
				
	def RunInThread(self):
		self.error = False
		wx.PostEvent(self, UpdatePluginDialog(status = 'Plugin List: Connecting...'))
		targetfile = self.parent.ancestor.userpreferencesdirectory + '/drpython.plugin.list.dat'
		try:
			u = urllib.urlopen('http://drpython.sourceforge.net/cgi-bin/GetPluginList.py')
			
			result = 'Philosophia'
			data = ''
			x = 0
			while len(result) > 0:
				result = u.read(1)
				
				if (x % 1024) == 0:
					wx.PostEvent(self, UpdatePluginDialog(status = 'Plugin List: ' + str(x / 1024) + 'kb Read'))
								
				x += 1
				
				if len(result) > 0:
					data += result
			
			u.close()
		except:
			self.error = True
			wx.PostEvent(self, UpdatePluginDialog(status = 'Plugin List: Error'))
			return
		
		if data.find('<Plugins>') != 0:
			self.error = True
			wx.PostEvent(self, UpdatePluginDialog(status = 'Plugin List: Error'))
			return

		try:
			f = file(targetfile, 'wb')
			f.write(data)
			f.close()
		except:
			self.error = True
			wx.PostEvent(self, UpdatePluginDialog(status = 'Plugin List: Error'))
			return
		
		wx.PostEvent(self, UpdatePluginDialog(status = 'Plugin List: Done.'))
		
		self.EndModal(0)
					
	def UpdateUI(self, event):
		self.txtStatus.SetValue(event.status)
		if self.error:
			errormessage = '''Error Downloading Plugin List From Selected Mirror.
If you proceed, DrPython will use the copy 
which came with this version of the core program.
This copy may be out of date.

Please try a different mirror.'''
			drScrolledMessageDialog.ShowMessage(self, errormessage, 'Plugin List Error')
			self.EndModal(0)
			
		


#*******************************************************************************
#Select Plugins Dialog
class drSelectPluginsDialog(wx.Dialog):
	def __init__(self, parent):
		wx.Dialog.__init__(self, parent, -1, "Select DrPython Plugin", wx.DefaultPosition, wx.Size(600, 400), wx.DEFAULT_DIALOG_STYLE)
		
		ID_CANCEL = 1
		ID_OK = 2
		
		ID_PLUGINS = 3
		
		ID_SEARCH = 4
		ID_CLEAR = 5
		
		self.Plugins = []
		
		self.parent = parent
		
		#Local For Test
		self.pluginlistfile = parent.userpreferencesdirectory + '/drpython.plugin.list.dat'
		if not os.path.exists(self.pluginlistfile):
			self.pluginlistfile = parent.programdirectory + '/drpython.plugin.list.dat'
						
		self.txtSearch = wx.TextCtrl(self, -1, '', size=(150, -1), style=wx.TE_PROCESS_ENTER)
		self.choType = wx.Choice(self, -1, choices=['Keyword', 'Title', 'Author', 'Description'])
		self.chkCaseSensitive = wx.CheckBox(self, -1, 'Case Sensitive')
		self.btnSearch = wx.Button(self, ID_SEARCH, 'Search')
		self.btnClear = wx.Button(self, ID_CLEAR, 'Clear')
		
		self.choType.SetSelection(0)
		
		self.lstPlugins = wx.CheckListBox(self, ID_PLUGINS, size=(300, 300))
		self.htmlData = wx.html.HtmlWindow(self, size=(300, 300))
		
		self.btnCancel = wx.Button(self, ID_CANCEL, " &Cancel ")
		self.btnOk = wx.Button(self, ID_OK, " &Ok ")
		
		self.theSizer = wx.BoxSizer(wx.VERTICAL)		
		self.mainSizer = wx.FlexGridSizer(3, 2, 10, 10)
		self.searchSizer = wx.BoxSizer(wx.HORIZONTAL)
		
		self.searchSizer.Add(self.txtSearch, 1, wx.EXPAND)
		self.searchSizer.Add(self.choType, 0, wx.SHAPED)
		self.searchSizer.Add(self.chkCaseSensitive, 0, wx.SHAPED)
		self.searchSizer.Add(self.btnSearch, 0, wx.SHAPED)
		self.searchSizer.Add(self.btnClear, 0, wx.SHAPED)
		
		self.mainSizer.Add(self.lstPlugins, 0, wx.SHAPED)
		self.mainSizer.Add(self.htmlData, 0, wx.SHAPED)
		self.mainSizer.Add(self.btnCancel, 0, wx.SHAPED)
		self.mainSizer.Add(self.btnOk, 0, wx.SHAPED | wx.ALIGN_RIGHT)
		
		self.theSizer.Add(self.searchSizer, 0, wx.EXPAND)
		self.theSizer.Add(self.mainSizer, 0, wx.EXPAND)
						
		self.SetAutoLayout(True)
		self.SetSizerAndFit(self.theSizer)
		
		self.ReadPluginList()
		
		self.Bind(wx.EVT_LISTBOX, self.OnSelectPlugin, id=ID_PLUGINS)
		self.Bind(wx.EVT_BUTTON, self.OnbtnCancel, id=ID_CANCEL)
		self.Bind(wx.EVT_BUTTON, self.OnbtnOk, id=ID_OK)
		self.Bind(wx.EVT_BUTTON, self.OnbtnSearch, id=ID_SEARCH)
		self.Bind(wx.EVT_BUTTON, self.OnbtnClear, id=ID_CLEAR)
		self.txtSearch.Bind(wx.EVT_CHAR, self.OnChar)

	def GetPluginFileText(self, text):		
		#Protects against invalid values in the plugin list file.
		data = ''
		for character in text:
			c = ord(character)
			if (c < 128) and (c >= 0):
				data += character
		
		return data
		

	def GetPluginData(self, pluginindex, dataindex, casesensitive):
		data = self.PluginDataArray[pluginindex][dataindex]
				
		if casesensitive:
			return data.lower()
		return data

	def GetSelectedPlugins(self):		
		selections = []
		l = self.lstPlugins.GetCount()		
		x = 0
		
		while x < l:
			if self.lstPlugins.IsChecked(x):
				selections.append(x)
			x += 1
		
		pluginfilenames = []
		
		for selection in selections:
			pluginfilenames.append(self.lstPlugins.GetString(selection) + '-' + self.PluginDataArray[selection][0] + '.zip')
			
		return pluginfilenames

	def OnbtnCancel(self, event):
		self.EndModal(wx.ID_CANCEL)
	
	def OnbtnClear(self, event):
		self.txtSearch.SetValue('')
		self.OnbtnSearch(event)
		
	def OnbtnOk(self, event):		
		self.EndModal(wx.ID_OK)
	
	def OnbtnSearch(self, event):
		stext = self.txtSearch.GetValue()
		if len(stext) < 1:
			self.PluginDataArrayForLST = list(self.PluginDataArray)
			self.lstPlugins.Set(self.Plugins)
			return
		
		t = self.choType.GetSelection() - 1	
				
		self.PluginDataArrayForLST = []
		pluginlist = []
		x = 0
		casesensitive = self.chkCaseSensitive.GetValue()
		for plugin in self.Plugins:
			if self.SearchPlugin(stext, t, plugin, casesensitive):
				pluginlist.append(plugin)
				self.PluginDataArrayForLST.append(self.PluginDataArray[x])
			x += 1
		self.lstPlugins.Set(pluginlist)
	
	def OnChar(self, event):
		if (event.GetKeyCode() == wx.WXK_RETURN):
			self.OnbtnSearch(None)
		event.Skip()
	
	def OnSelectPlugin(self, event):		
		sel = self.lstPlugins.GetSelection()
		if sel == -1:
			return
		txt = self.lstPlugins.GetStringSelection()
		
		htmltxt = '''<html><body><b>Name:</b> %s<br>
<br>
<b>Version:</b> %s<br>
<br>
<b>Author(s):</b> %s<br>
<br>
<b>Description:</b><br>
<br> %s<br>
<br></html></body>''' % (txt, self.PluginDataArrayForLST[sel][0], self.PluginDataArrayForLST[sel][1], self.PluginDataArrayForLST[sel][2])

		self.htmlData.SetPage(htmltxt)
		
	def ReadPluginList(self):
		try:
			f = file(self.pluginlistfile, 'r')
			text = self.GetPluginFileText(f.read())
			f.close()
			
			self.Plugins = ExtractPreferenceFromText(text, 'Plugins').strip().split('\n')
			
			if len(self.Plugins) < 1:
				drScrolledMessageDialog.ShowMessage(self, 'Corrupt Plugin List, Trying Default', 'Error')
				self.pluginlistfile = self.parent.programdirectory + '/drpython.plugin.list.dat'
				f = file(self.pluginlistfile, 'r')
				text = f.read()
				f.close()
				
				self.Plugins = ExtractPreferenceFromText(text, 'Plugins').strip().split('\n')
			
			self.PluginDataArray = []
			
			for plugin in self.Plugins:
				plugintext = ExtractPreferenceFromText(text, plugin).strip()
				version = ExtractPreferenceFromText(plugintext, 'Version').strip()
				author = ExtractPreferenceFromText(plugintext, 'Author').strip()
				description = ExtractPreferenceFromText(plugintext, 'Description').strip()
				self.PluginDataArray.append([version, author, description])						
			
			self.PluginDataArrayForLST = list(self.PluginDataArray)
							
			self.lstPlugins.Set(self.Plugins)				
			
		except:
			drScrolledMessageDialog.ShowMessage(self, 'Error Reading "' + self.pluginlistfile + '".', 'Error Reading Plugin List')

	def SearchPlugin(self, searchtext, type, pluginname, casesensitive):
		if casesensitive:
			if type == 0:
				return pluginname.find(searchtext) > -1
			elif (type < 3) and (type > -1):
				if pluginname in self.Plugins:
					i = self.Plugins.index(pluginname)
					return self.GetPluginData(i, type, 0).find(searchtext) > -1
				return False
			else:
				if pluginname.find(searchtext) > -1:
					return True
				elif pluginname in self.Plugins:
					i = self.Plugins.index(pluginname)
					if self.GetPluginData(i, 0, 0).find(searchtext) > -1:
						return True
					elif self.GetPluginData(i, 1, 0).find(searchtext) > -1:
						return True
					elif self.GetPluginData(i, 2, 0).find(searchtext) > -1:
						return True			
		else:
			searchtext = searchtext.lower()		
			if type == 0:
				return pluginname.lower().find(searchtext) > -1
			elif (type < 3) and (type > -1):
				if pluginname in self.Plugins:
					i = self.Plugins.index(pluginname)
					return self.GetPluginData(i, type, 1).find(searchtext) > -1
				return False
			else:
				if pluginname.lower().find(searchtext) > -1:
					return True
				elif pluginname in self.Plugins:
					i = self.Plugins.index(pluginname)
					if self.GetPluginData(i, 0, 1).find(searchtext) > -1:
						return True
					elif self.GetPluginData(i, 1, 1).find(searchtext) > -1:
						return True
					elif self.GetPluginData(i, 2, 1).find(searchtext) > -1:
						return True
		return False

#*******************************************************************************
#Install Wizard

class drPluginInstallLocationPage(wx.wizard.WizardPageSimple):
	def __init__(self, parent):
		wx.wizard.WizardPageSimple.__init__(self, parent)
		
		self.parent = parent
		
		ID_LOCATION = 78
		ID_MIRROR = 79
		
		title = wx.StaticText(self, -1, "Select Location:")
		title.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD))
		
		self.radLocation = wx.RadioBox(self, ID_LOCATION, "", wx.DefaultPosition, wx.DefaultSize, ["Local", "SourceForge Mirror"], 1, wx.RA_SPECIFY_COLS | wx.NO_BORDER)
		
		mirrors = ['Bern, Switzerland (Europe)', 'Brussels, Belgium (Europe)', 'Chapel Hill, NC (North America)', 'Duesseldorf, Germany (Europe)', \
		'Dublin, Ireland (Europe)', 'Minneapolis, MN (North America)', 'New York, New York (North America)', 'Paris, France (Europe)', \
		'Phoenix, AZ (North America)', 'Reston, VA (North America)', 'SourceForge (OSDN)', 'Sydney, Australia (Australia)', 'Zurich, Switzerland  (Europe)']
		
		self.mirrorAddresses = ['http://puzzle.dl.sourceforge.net/', 'http://belnet.dl.sourceforge.net/', 'http://unc.dl.sourceforge.net/', 'http://mesh.dl.sourceforge.net/', \
		'http://heanet.dl.sourceforge.net/', 'http://umn.dl.sourceforge.net/', 'http://voxel.dl.sourceforge.net/', 'http://ovh.dl.sourceforge.net/', \
		'http://easynews.dl.sourceforge.net/sourceforge/', 'http://aleron.dl.sourceforge.net/', 'http://osdn.dl.sourceforge.net/', 'http://optusnet.dl.sourceforge.net/', 'http://switch.dl.sourceforge.net/']
		
		self.lstMirrors = wx.ListBox(self, ID_MIRROR, size=(300, 300), choices=mirrors)
		self.lstMirrors.SetSelection(0)
		self.lstMirrors.Enable(False)	
		
		self.theSizer = wx.BoxSizer(wx.VERTICAL)
		
		self.theSizer.Add(title, 0, wx.SHAPED)
		self.theSizer.Add(self.radLocation, 0, wx.SHAPED)
		self.theSizer.Add(self.lstMirrors, 0, wx.SHAPED)
		
		self.SetAutoLayout(True)
		self.SetSizer(self.theSizer)
		
		self.Bind(wx.EVT_RADIOBOX, self.OnLocationChanged, id=ID_LOCATION)
		self.Bind(wx.EVT_LISTBOX, self.OnMirrorChanged, id=ID_MIRROR)
		
	def OnLocationChanged(self, event):
		isSF = self.radLocation.GetSelection()
		self.lstMirrors.Enable(isSF)
		self.parent.Location = isSF
		if isSF:
			self.OnMirrorChanged(None)
		
	def OnMirrorChanged(self, event):
		i = self.lstMirrors.GetSelection()
		if i < 0:
			i = 0
		self.parent.Mirror = self.mirrorAddresses[i]
		
class drPluginInstallSelectPage(wx.wizard.WizardPageSimple):
	def __init__(self, parent):
		wx.wizard.WizardPageSimple.__init__(self, parent)	
		self.parent = parent
		
		ID_ADD = 77
		ID_REMOVE = 78
		ID_PLUGINS = 79
		
		title = wx.StaticText(self, -1, "Select Plugins to Install:")
		title.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD))
		
		self.btnAdd = wx.Button(self, ID_ADD, "Add")
		self.btnRemove = wx.Button(self, ID_REMOVE, "Remove")
		
		self.lstPlugins = wx.ListBox(self, ID_PLUGINS, size=(300, 300))
		
		self.theSizer = wx.BoxSizer(wx.VERTICAL)
		
		self.bSizer = wx.BoxSizer(wx.HORIZONTAL)
		
		self.bSizer.Add(self.btnAdd, 0, wx.SHAPED | wx.ALIGN_LEFT)
		self.bSizer.Add(self.btnRemove, 0, wx.SHAPED | wx.ALIGN_RIGHT)
		
		self.theSizer.Add(title, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.bSizer, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.lstPlugins, 0, wx.SHAPED)
		
		self.SetAutoLayout(True)
		self.SetSizer(self.theSizer)
		
		self.Bind(wx.EVT_BUTTON, self.OnAdd, id=ID_ADD)
		self.Bind(wx.EVT_BUTTON, self.OnRemove, id=ID_REMOVE)
	
	def OnAdd(self, event):
		if self.parent.Location:
			#SourceForge
			d = drSelectPluginsDialog(self.parent.ancestor)
			answer = d.ShowModal()
			self.Raise()
			self.SetFocus()
			if answer == wx.ID_OK:
				selectedplugins = d.GetSelectedPlugins()
				for plugin in selectedplugins:
					self.parent.pluginstodownload.append(self.parent.Mirror + 'sourceforge/drpython/' + plugin)
				labels = map(lambda x: os.path.splitext(x)[0], selectedplugins)
				self.parent.pluginlabels.extend(labels)
				self.parent.pluginsinstallmethod.extend(map(lambda x: 0, labels))
				self.lstPlugins.Set(self.parent.pluginlabels)				
			d.Destroy()
		else:
			#Local
			dlg = drFileDialog.FileDialog(self.parent.ancestor, "Select DrPython Plugin(s)", self.parent.wildcard, MultipleSelection=True)
			if (len(self.parent.ancestor.prefs.pluginsdefaultdirectory) > 0):
				try:
					dlg.SetDirectory(self.parent.ancestor.prefs.pluginsdefaultdirectory)			
				except:
					drScrolledMessageDialog.ShowMessage(self.parent, ("Error Setting Default Directory To: " + self.parent.ancestor.prefs.pluginsdefaultdirectory), "DrPython Error")
			if (dlg.ShowModal() == wx.ID_OK):
				filenames = dlg.GetPaths()
				filenames = map(lambda x: x.replace("\\", '/'), filenames)
				self.parent.pluginstoinstall.extend(filenames)
				labels = map(lambda x: os.path.splitext(os.path.split(x)[1])[0], filenames)
				self.parent.pluginlabels.extend(labels)
				self.parent.pluginsinstallmethod.extend(map(lambda x: 0, labels))
				self.lstPlugins.Set(self.parent.pluginlabels)
			dlg.Destroy()
			
	def OnRemove(self, event):
		i = self.lstPlugins.GetSelection()
		if i < 0:
			return
		d = wx.MessageDialog(self, 'Remove "%s"?' % self.parent.pluginlabels[i], "Remove Plugin From List", wx.YES_NO | wx.ICON_QUESTION)
		answer = d.ShowModal()
		d.Destroy()
		if (answer == wx.ID_YES):
			self.parent.pluginlabels.pop(i)
			if self.parent.Location:
				self.parent.pluginstodownload.pop(i)
			else:
				self.parent.pluginstoinstall.pop(i)
			self.lstPlugins.Set(self.parent.pluginlabels)	

	def Run(self):
		if self.parent.Location:
			d = wx.MessageDialog(self, 'Update Plugin List?', "Update Plugin List", wx.YES_NO | wx.ICON_QUESTION)
			answer = d.ShowModal()
			d.Destroy()
			if (answer == wx.ID_YES):
				e = drUpdatePluginListDialog(self)
				e.ShowModal()
				e.Destroy()
				
			#Make sure plugion labels are synced with list:
			self.lstPlugins.Set(self.parent.pluginlabels)

(UpdateDownloadPage, EVT_UPDATE_DOWNLOADPAGE) = wx.lib.newevent.NewEvent()

class drPluginInstallDownloadPage(wx.wizard.WizardPageSimple):
	def __init__(self, parent):
		wx.wizard.WizardPageSimple.__init__(self, parent)	
		
		self.parent = parent
		
		self.errors = []

		title = wx.StaticText(self, -1, "Getting Selected Plugins:")
		title.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD))		
		
		self.stxtDownload = wx.StaticText(self, -1, "Downloading...")
		self.stxtUnPacking = wx.StaticText(self, -1, "UnPacking...")
		self.stxtDone = wx.StaticText(self, -1, "Done")
		
		self.stxtDownload.SetForegroundColour(wx.Colour(175, 175, 175))
		self.stxtUnPacking.SetForegroundColour(wx.Colour(175, 175, 175))
		self.stxtDone.SetForegroundColour(self.GetBackgroundColour())
		
		self.gDownload = wx.Gauge(self, -1, 0, size=(250, -1))
		self.gUnPack = wx.Gauge(self, -1, 0, size=(250, -1))
		
		self.txtStatus = wx.TextCtrl(self, -1, '', size=(250, -1), style=wx.TE_READONLY)
		
		self.theSizer = wx.BoxSizer(wx.VERTICAL)
		
		self.theSizer.Add(title, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.stxtDownload, 0, wx.SHAPED)
		self.theSizer.Add(self.gDownload, 0, wx.SHAPED)
		self.theSizer.Add(self.txtStatus, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.stxtUnPacking, 0, wx.SHAPED)
		self.theSizer.Add(self.gUnPack, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.stxtDone, 0, wx.SHAPED)
		
		self.SetAutoLayout(True)
		self.SetSizer(self.theSizer)
				
		self.Bind(EVT_UPDATE_DOWNLOADPAGE, self.UpdateUI)
	
	def CreateDirectories(self, targetdir, zippedfilename):
		zippedfilename = zippedfilename.replace('\\', '/')
		d = zippedfilename.find('/')
		while d > -1:
			dir = zippedfilename[:d]
			targetdir = targetdir + '/' + dir
			if not os.path.exists(targetdir):
				os.mkdir(targetdir)	
			zippedfilename = zippedfilename[d+1:]
			d = zippedfilename.find('/')

	def Download(self, remotefile, label):
		try:
			targetfile = self.parent.tempdir + label + '.zip'
			wx.PostEvent(self, UpdateDownloadPage(step = 0, range = -1, value = -1, done = False, status = label + '.zip: Connecting...'))
			u = urllib.urlopen(remotefile)
			mimetype = u.info().gettype()
			if mimetype != 'application/zip':
				u.close()
				self.errors.append([remotefile, 'MimeType Info: "' + mimetype + '"'])
				return ''
			
			result = 'Philosophia'
			data = ''
			x = 0
			while len(result) > 0:
				result = u.read(1)
				
				if (x % 1024) == 0:
					wx.PostEvent(self, UpdateDownloadPage(step = 0, range = -1, value = -1, done = False, status = label + '.zip: ' + str(x / 1024) + 'kb Read'))
								
				x += 1
				
				if len(result) > 0:
					data += result
			
			u.close()
			
			f = file(targetfile, 'wb')
			f.write(data)
			f.close()
			
			return targetfile
		except:
			self.errors.append([remotefile, str(sys.exc_info()[0]).lstrip("exceptions.") + ": " + str(sys.exc_info()[1])])
		return ''	

	def Run(self):
		thread.start_new_thread(self.RunInThread, ())

	def RunInThread(self):
		#Download
		if self.parent.Location:
			l = len(self.parent.pluginstodownload)
			x = 0
			wx.PostEvent(self, UpdateDownloadPage(step = 0, range = l, value = x, done = False, status=''))
			self.parent.pluginstoinstall = []
			while x < l:
				result = self.Download(self.parent.pluginstodownload[x], self.parent.pluginlabels[x])
				if len(result) > 0:
					self.parent.pluginstoinstall.append(result)
				x = x + 1
				wx.PostEvent(self, UpdateDownloadPage(step = 0, range = l, value = x, done = False, status= ''))
		
			#Update arrays based on what was downloaded
			self.parent.pluginlabels = map(lambda x: os.path.splitext(os.path.split(x)[1])[0], self.parent.pluginstoinstall)
			self.parent.pluginsinstallmethod = (map(lambda x: 0, self.parent.pluginlabels))
		
			wx.PostEvent(self, UpdateDownloadPage(step = 0, range = l, value = x, done = True, status= ''))
			
		#UnPack
		l = len(self.parent.pluginstoinstall)
		
		wx.PostEvent(self, UpdateDownloadPage(step = 1, range = l, value = 0, done = False, status= ''))
						
		x = 0
		while x < l:
			self.UnPack(self.parent.pluginstoinstall[x], self.parent.pluginlabels[x])
			x = x + 1
			wx.PostEvent(self, UpdateDownloadPage(step = 1, range = l, value = x, done = False, status= ''))
		
		wx.PostEvent(self, UpdateDownloadPage(step = 1, range = l, value = x, done = True, status= ''))
	
	def UnPack(self, filename, label):
		zf = zipfile.ZipFile(filename, 'r')
		
		dir = self.parent.tempdir + label
		
		if not os.path.exists(dir):
			os.mkdir(dir)
		
		zippedfiles = zf.namelist()
		
		self.parent.UnZippedFilesArray.append(zippedfiles)
				
		for zippedfile in zippedfiles:
			l = len(zippedfile)
			if (zippedfile[l-1] == '/') or (zippedfile[l-1] == '\\'):
				self.CreateDirectories(dir, zippedfile)
			else:
				self.CreateDirectories(dir, zippedfile)
				data = zf.read(zippedfile)
				f = file(dir + '/' + zippedfile, 'wb')
				f.write(data)
				f.close()
		
		zf.close()
		
	def UpdateUI(self, event):
		if event.step == 0:
			if len(event.status) > 0:
				self.txtStatus.SetValue(event.status)
			else:
				if not event.done:
					self.stxtDownload.SetForegroundColour(self.GetForegroundColour())
				else:
					self.stxtDownload.SetForegroundColour(wx.Colour(175, 175, 175))
				if event.range != self.gDownload.GetRange():
					self.gDownload.SetRange(event.range)
				self.gDownload.SetValue(event.value)
		elif event.step == 1:
			if not event.done:
				self.stxtUnPacking.SetForegroundColour(self.GetForegroundColour())
			else:
				self.stxtUnPacking.SetForegroundColour(wx.Colour(175, 175, 175))
				self.stxtDone.SetForegroundColour(self.GetForegroundColour())
			if event.range != self.gUnPack.GetRange():
				self.gUnPack.SetRange(event.range)
			self.gUnPack.SetValue(event.value)
			
		self.Refresh()

		if len(self.errors) > 0:
			error = self.errors.pop(0)
			drScrolledMessageDialog.ShowMessage(self.parent, 'Error Downloading File "' + error[0] + '".\n\n' + error[1], "Error", wx.DefaultPosition, wx.Size(550,300))		
				
class drPluginInstallIndexPage(wx.wizard.WizardPageSimple):
	def __init__(self, parent):
		wx.wizard.WizardPageSimple.__init__(self, parent)
		
		self.parent = parent
		
		title = wx.StaticText(self, -1, "Set Loading Method:")
		title.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD))		
		
		self.chklLoadByDefault = wx.CheckListBox(self, 1, wx.DefaultPosition, (200, 100), self.parent.pluginlabels)
		
		self.chklLoadFromIndex = wx.CheckListBox(self, 2, wx.DefaultPosition, (200, 100), self.parent.pluginlabels)
			
		self.theSizer = wx.FlexGridSizer(6, 1, 5, 5)
		
		self.theSizer.Add(title, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.EXPAND)
		self.theSizer.Add(wx.StaticText(self, -1, "Load By Default:"), 0, wx.EXPAND)
		self.theSizer.Add(self.chklLoadByDefault, 0, wx.EXPAND)
		self.theSizer.Add(wx.StaticText(self, -1, "Load From Index:"), 0, wx.EXPAND)
		self.theSizer.Add(self.chklLoadFromIndex, 0, wx.EXPAND)
		
		self.SetAutoLayout(True)
		self.SetSizer(self.theSizer)
		
		self.Bind(wx.EVT_CHECKLISTBOX, self.OnLoadByDefault, id=1)
		self.Bind(wx.EVT_CHECKLISTBOX, self.OnLoadFromIndex, id=2)

	def GetDefSel(self, IndexSel):
		txt = self.chklLoadFromIndex.GetString(IndexSel)
		return self.chklLoadByDefault.FindString(txt)

	def GetIdxSel(self, DefaultSel):
		txt = self.chklLoadByDefault.GetString(DefaultSel)
		return self.chklLoadFromIndex.FindString(txt)
		
	def OnLoadByDefault(self, event):
		sel = event.GetSelection()
		i = self.GetIdxSel(sel)
		if sel > -1:
			if self.chklLoadByDefault.IsChecked(sel) and (i > -1):
				self.parent.pluginsinstallmethod[sel] = 0
				self.chklLoadFromIndex.Check(i, False)
			elif i > -1:	
				if not self.chklLoadFromIndex.IsChecked(i):
					self.parent.pluginsinstallmethod[sel] = -1

	def OnLoadFromIndex(self, event):
		sel = event.GetSelection()
		i = self.GetDefSel(sel)
		if sel > -1:
			if self.chklLoadFromIndex.IsChecked(sel) and (i > -1):
				self.parent.pluginsinstallmethod[i] = 1
				self.chklLoadByDefault.Check(i, False)
			elif not self.chklLoadByDefault.IsChecked(sel) and (i > -1):
				self.parent.pluginsinstallmethod[i] = -1
		
	def Run(self):
		if len(self.parent.pluginstoinstall) < 1:
			return
		self.chklLoadByDefault.Set(self.parent.pluginlabels)
		indexlabels = []
		x = 0		
		for label in self.parent.pluginlabels:
			pluginname = label
			if pluginname.find('-') > -1:
				pluginname = pluginname[:pluginname.find('-')]
			if pluginname.find('.') > -1:
				pluginname = pluginname[:pluginname.find('.')]
			for fn in self.parent.UnZippedFilesArray[x]:
				if fn.find(pluginname + '.idx') > -1:
					indexlabels.append(label)
					break
			x += 1
		self.chklLoadFromIndex.Set(indexlabels)
		
		x = 0
		l = len(self.parent.pluginlabels)
		while x < l:
			self.chklLoadByDefault.Check(x, True)
			x = x + 1
			
class drPluginInstallInstallPage(wx.wizard.WizardPageSimple):
	def __init__(self, parent):
		wx.wizard.WizardPageSimple.__init__(self, parent)	
		
		self.parent = parent

		title = wx.StaticText(self, -1, "Installing Selected Plugins:")
		title.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD))		
		
		self.stxtInstalling = wx.StaticText(self, -1, "Installing...")
		self.stxtIndexing = wx.StaticText(self, -1, "Indexing...")
		self.stxtDone = wx.StaticText(self, -1, "Done")
		
		self.stxtInstalling.SetForegroundColour(wx.Colour(175, 175, 175))
		self.stxtIndexing.SetForegroundColour(wx.Colour(175, 175, 175))
		self.stxtDone.SetForegroundColour(self.GetBackgroundColour())
		
		self.gInstall = wx.Gauge(self, -1, 0, size=(200, -1))
		self.gIndex = wx.Gauge(self, -1, 0, size=(200, -1))
		
		self.theSizer = wx.BoxSizer(wx.VERTICAL)
		
		self.theSizer.Add(title, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.stxtInstalling, 0, wx.SHAPED)
		self.theSizer.Add(self.gInstall, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.stxtIndexing, 0, wx.SHAPED)
		self.theSizer.Add(self.gIndex, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.stxtDone, 0, wx.SHAPED)
		
		self.SetAutoLayout(True)
		self.SetSizer(self.theSizer)
	
	def RemoveTempDir(self, tempdir):
		entries = os.listdir(tempdir)
		
		for entry in entries:
			fname = tempdir + '/' + entry
			if os.path.isdir(fname):
				self.RemoveTempDir(fname)
			else:
				os.remove(fname)
				
		os.rmdir(tempdir)
	
	def Index(self, label, unzippedfiles, installmethod):		
		dir = self.parent.tempdir + label
						
		pluginname = label
		if pluginname.find('-') > -1:
			pluginname = pluginname[:pluginname.find('-')]
		if pluginname.find('.') > -1:
			pluginname = pluginname[:pluginname.find('.')]
			
		if installmethod == 0:
			indexfile = self.parent.plugindirectory + 'default.idx'
			if not os.path.exists(indexfile):				
				f = file(indexfile, 'wb')
				f.write('\n')
				f.close()
			try:
				f = file(indexfile, 'r')
				plugins = f.read().strip().split('\n')
				f.close()
				
				f = file(indexfile, 'w')				
				for p in plugins:
					if p != pluginname:
						f.write(p + '\n')
				f.write(pluginname + '\n')
				f.close()
			except:
				drScrolledMessageDialog.ShowMessage(self.parent, 'Error Adding Plugin "' + pluginname + '" to default.idx"', "Error", wx.DefaultPosition, wx.Size(550,300))
				return				
			
		elif installmethod == 1:
			target = pluginname + '.idx'

			indexfile = ''
		
			for fname in unzippedfiles:
				if os.path.split(fname)[1] == target:
					indexfile = dir + '/' + fname
										
			if len(indexfile) < 1:
				drScrolledMessageDialog.ShowMessage(self.parent, 'Error Installing "' + label + '"', 'Install Index Error')
				return			
			
			shutil.copyfile(indexfile, self.parent.plugindirectory + target)

	def Install(self, filename, label, unzippedfiles):
		pluginname = label
		if pluginname.find('-') > -1:
			pluginname = pluginname[:pluginname.find('-')]
		if pluginname.find('.') > -1:
			pluginname = pluginname[:pluginname.find('.')]
			
		dir = self.parent.tempdir + label
		
		target = pluginname + '.py'
		
		pluginfile = ''
		
		for fname in unzippedfiles:
			if os.path.split(fname)[1] == target:
				pluginfile = dir + '/' + fname
				
		if len(pluginfile) < 1:
			drScrolledMessageDialog.ShowMessage(self.parent, 'Error Installing "' + label + '"', 'Install Error')
		else:
			#Do the Install
			pluginrfile = self.parent.plugindirectory + target
			
			#Install Script
			plugininstallfile = pluginfile + ".install"
			continueinstallation = True
			if os.path.exists(plugininstallfile):	
				f = open(plugininstallfile, 'r')
				scripttext = f.read()
				f.close()
				
				try:
					code = compile((scripttext + '\n'), plugininstallfile, 'exec')
				except:
					drScrolledMessageDialog.ShowMessage(self.parent, ("Error compiling install script."), "Error", wx.DefaultPosition, wx.Size(550,300))
					return				
				try:
					cwd = os.getcwd()
					os.chdir(dir + '/' + os.path.commonprefix(unzippedfiles))
					exec(code)
					continueinstallation = Install(self.parent.ancestor)
					os.chdir(cwd)
				except:
					drScrolledMessageDialog.ShowMessage(self.parent, ("Error running install script."), "Error", wx.DefaultPosition, wx.Size(550,300))
					return
			#/Install Script
			if continueinstallation:
				try:
					copyf = True
					if os.path.exists(pluginrfile):
						d = wx.MessageDialog(self, 'Overwrite"' + pluginrfile + '"?', "DrPython", wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION)
						answer = d.ShowModal()
						d.Destroy()
						if (answer == wx.ID_NO):
							copyf = False
					if copyf:
						shutil.copyfile(pluginfile, pluginrfile)
				except:				
					drScrolledMessageDialog.ShowMessage(self.parent, ("Error with: " + pluginfile), "Install Error")
					return
	
	def Run(self):
		l = len(self.parent.pluginstoinstall)
		if l < 1:
			self.stxtDone.SetForegroundColour(self.GetForegroundColour())
			return
		
		#Install
		self.stxtInstalling.SetForegroundColour(self.GetForegroundColour())
		
		self.gInstall.SetRange(l)
		
		x = 0
		while x < l:
			self.Install(self.parent.pluginstoinstall[x], self.parent.pluginlabels[x], self.parent.UnZippedFilesArray[x])
			x = x + 1
			self.gInstall.SetValue(x)
		
		self.stxtInstalling.SetForegroundColour(wx.Colour(175, 175, 175))
		
		#Index
		self.stxtIndexing.SetForegroundColour(self.GetForegroundColour())
		
		self.gIndex.SetRange(l)
		
		x = 0
		while x < l:
			self.Index(self.parent.pluginlabels[x], self.parent.UnZippedFilesArray[x], self.parent.pluginsinstallmethod[x])
			x = x + 1
			self.gIndex.SetValue(x)		
		
		self.stxtIndexing.SetForegroundColour(wx.Colour(175, 175, 175))	
		
		#Remove All Temporary Files.
		for label in self.parent.pluginlabels:
			dir = self.parent.tempdir + label
			try:
				self.RemoveTempDir(dir)
				if self.parent.Location:
					#Remove the Downloaded File, if it exists.
					downloadedfile = self.parent.tempdir + label + '.zip'
					if os.path.exists(downloadedfile):
						os.remove(downloadedfile)
			except:
				drScrolledMessageDialog.ShowMessage(self.parent, ("Error removing temporary directory for: " + label), "Post Install Error")
				return
		
		self.stxtDone.SetForegroundColour(self.GetForegroundColour())

class drPluginInstallWizard(wx.wizard.Wizard):
	def __init__(self, parent, title, bitmap):
		wx.wizard.Wizard.__init__(self, parent, 303, title, bitmap)
		
		self.ancestor = parent
		
		self.plugindirectory = parent.userpreferencesdirectory + "/plugins/"
		
		self.wildcard = "DrPython Plugin Archive (*.zip)|*.zip"
		
		self.pluginstodownload = []
				
		self.pluginstoinstall = []
		
		self.pluginsinstallmethod = []
		
		self.pluginlabels = []
		
		self.UnZippedFilesArray = []
		
		self.Location = 0
		
		self.Mirror = ''
		
		try:
			#TempDir
			self.tempdir = os.path.split(tempfile.mktemp())[0].replace('\\', '/') + '/'
		except:
			drScrolledMessageDialog.ShowMessage(parent, "Error Getting Temporary Directory.", "Install Error")
			return			
		
		self.LocationPage = drPluginInstallLocationPage(self)
		self.SelectPage = drPluginInstallSelectPage(self)
		self.DownloadPage = drPluginInstallDownloadPage(self)
		self.IndexPage = drPluginInstallIndexPage(self)
		self.InstallPage = drPluginInstallInstallPage(self)
		
		wx.wizard.WizardPageSimple_Chain(self.LocationPage, self.SelectPage)
		wx.wizard.WizardPageSimple_Chain(self.SelectPage, self.DownloadPage)
		wx.wizard.WizardPageSimple_Chain(self.DownloadPage, self.IndexPage)
		wx.wizard.WizardPageSimple_Chain(self.IndexPage, self.InstallPage)
				
		self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged, id=303)
	
	def OnPageChanged(self, event):
		cp = self.GetCurrentPage()
		if cp == self.SelectPage:
			self.SelectPage.Run()
		elif cp == self.DownloadPage:
			self.DownloadPage.Run()
		elif cp == self.IndexPage:
			self.IndexPage.Run()
		elif cp == self.InstallPage:
			self.InstallPage.Run()
		
	def Run(self):
		self.RunWizard(self.LocationPage)

#*******************************************************************************
#UnInstall Wizard

class drPluginUnInstallSelectPage(wx.wizard.WizardPageSimple):
	def __init__(self, parent):
		wx.wizard.WizardPageSimple.__init__(self, parent)	
		self.parent = parent
		
		ID_ADD = 77
		ID_REMOVE = 78
		ID_PLUGINS = 79
		
		title = wx.StaticText(self, -1, "Select Plugins to UnInstall:")
		title.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD))
		
		self.btnAdd = wx.Button(self, ID_ADD, "Add")
		self.btnRemove = wx.Button(self, ID_REMOVE, "Remove")
		
		self.lstPlugins = wx.ListBox(self, ID_PLUGINS, size=(300, 300))
		
		self.theSizer = wx.BoxSizer(wx.VERTICAL)
		
		self.bSizer = wx.BoxSizer(wx.HORIZONTAL)
		
		self.bSizer.Add(self.btnAdd, 0, wx.SHAPED | wx.ALIGN_LEFT)
		self.bSizer.Add(self.btnRemove, 0, wx.SHAPED | wx.ALIGN_RIGHT)
		
		self.theSizer.Add(title, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.bSizer, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.lstPlugins, 0, wx.SHAPED)
		
		self.SetAutoLayout(True)
		self.SetSizer(self.theSizer)
		
		self.Bind(wx.EVT_BUTTON, self.OnAdd, id=ID_ADD)
		self.Bind(wx.EVT_BUTTON, self.OnRemove, id=ID_REMOVE)
	
	def OnAdd(self, event):
		plist = os.listdir(self.parent.plugindirectory)
				
		PluginList = []
		
		for p in plist:
			i = p.find(".py")			
			l = len(p)
			if i > -1 and (i + 3 == l):			
				PluginList.append(p[:i])
		
		PluginList.sort()
		
		d = wx.lib.dialogs.MultipleChoiceDialog(self, "Select Plugins to Remove:", "Add Plugin(s) to List", PluginList)
		if d.ShowModal() == wx.ID_OK:
			selections = d.GetValueString()
			self.parent.pluginstoremove.extend(selections)
			self.lstPlugins.Set(self.parent.pluginstoremove)
		d.Destroy()
		
	def OnRemove(self, event):
		i = self.lstPlugins.GetSelection()
		if i < 0:
			return
		d = wx.MessageDialog(self, 'Remove "%s"?' % self.parent.pluginstoremove[i], "Remove Plugin From List", wx.YES_NO | wx.ICON_QUESTION)
		answer = d.ShowModal()
		d.Destroy()
		if (answer == wx.ID_YES):
			self.parent.pluginstoremove.pop(i)
			self.lstPlugins.Set(self.parent.pluginstoremove)

class drPluginUnInstallDataPage(wx.wizard.WizardPageSimple):
	def __init__(self, parent):
		wx.wizard.WizardPageSimple.__init__(self, parent)
		
		self.parent = parent
		
		title = wx.StaticText(self, -1, "Remove Preferences and Shortcuts?:")
		title.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD))		
		
		self.chklData = wx.CheckListBox(self, 1, wx.DefaultPosition, (200, 200), self.parent.pluginstoremove)
			
		self.theSizer = wx.FlexGridSizer(3, 1, 5, 5)
		
		self.theSizer.Add(title, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.EXPAND)
		self.theSizer.Add(self.chklData, 0, wx.EXPAND)
		
		self.SetAutoLayout(True)
		self.SetSizer(self.theSizer)
		
		self.Bind(wx.EVT_CHECKLISTBOX, self.OnData, id=1)

	def OnData(self, event):
		sel = event.GetSelection()
		if sel > -1:
			self.parent.removealldataforpluginArray[sel] = self.chklData.IsChecked(sel)

	def Run(self):
		if len(self.parent.pluginstoremove) < 1:
			return
		self.chklData.Set(self.parent.pluginstoremove)
		
		self.parent.removealldataforpluginArray = map(lambda x: True, self.parent.pluginstoremove)
		
		x = 0
		l = len(self.parent.pluginstoremove)
		while x < l:
			self.chklData.Check(x, True)
			x = x + 1

class drPluginUnInstallUnInstallPage(wx.wizard.WizardPageSimple):
	def __init__(self, parent):
		wx.wizard.WizardPageSimple.__init__(self, parent)
		
		self.parent = parent
		
		title = wx.StaticText(self, -1, "UnInstalling Selected Plugins:")
		title.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD))		
		
		self.stxtUnInstalling = wx.StaticText(self, -1, "UnInstalling...")
		self.stxtUnIndexing = wx.StaticText(self, -1, "Removing From Index Files...")
		self.stxtDone = wx.StaticText(self, -1, "Done")
		
		self.stxtUnInstalling.SetForegroundColour(wx.Colour(175, 175, 175))
		self.stxtUnIndexing.SetForegroundColour(wx.Colour(175, 175, 175))
		self.stxtDone.SetForegroundColour(self.GetBackgroundColour())
		
		self.gUnInstall = wx.Gauge(self, -1, 0, size=(200, -1))
		self.gUnIndex = wx.Gauge(self, -1, 0, size=(200, -1))
		
		self.theSizer = wx.BoxSizer(wx.VERTICAL)
		
		self.theSizer.Add(title, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.stxtUnInstalling, 0, wx.SHAPED)
		self.theSizer.Add(self.gUnInstall, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.stxtUnIndexing, 0, wx.SHAPED)
		self.theSizer.Add(self.gUnIndex, 0, wx.SHAPED)
		self.theSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.theSizer.Add(self.stxtDone, 0, wx.SHAPED)
		
		self.SetAutoLayout(True)
		self.SetSizer(self.theSizer)
	
	def RemoveDatFiles(self, plugin):
		pluginfilebase = self.parent.plugindirectory + plugin
		try:
			if os.path.exists(pluginfilebase + '.preferences.dat'):
				os.remove(pluginfilebase + '.preferences.dat')
			if os.path.exists(pluginfilebase + '.shortcuts.dat'):
				os.remove(pluginfilebase + '.shortcuts.dat')
		except:
			drScrolledMessageDialog.ShowMessage(self.parent, "Error Removing Plugin Preference Files", "Uninstall Error")		
	
	def RemoveFromIndex(self, idx):
		f = file(self.parent.plugindirectory + idx, 'r')
		plugins = f.read().strip().split('\n')
		f.close()
						
		pluginstowrite = []				
		for plugin in plugins:
			if not (plugin in self.parent.pluginstoremove):
				pluginstowrite.append(plugin)
		
		if len(pluginstowrite) > 0:
			f = file(self.parent.plugindirectory + idx, 'w')
			for plugin in pluginstowrite:
				f.write(plugin + '\n')				
			f.close()
		else:
			if idx != 'default.idx':
				os.remove(self.parent.plugindirectory + idx)
		
	def Run(self):
		#UnInstall Plugins
		self.stxtUnInstalling.SetForegroundColour(self.GetForegroundColour())
				
		self.gUnInstall.SetRange(len(self.parent.pluginstoremove))
		self.gUnInstall.SetValue(0)
		x = 0
		for plugin in self.parent.pluginstoremove:
			self.UnInstall(plugin)
			if self.parent.removealldataforpluginArray[x]:
				self.RemoveDatFiles(plugin)
			x = x + 1
			self.gUnInstall.SetValue(x)
			
		self.stxtUnInstalling.SetForegroundColour(self.GetForegroundColour())
		
		#Remove Plugins from any index files.
		self.stxtUnIndexing.SetForegroundColour(self.GetForegroundColour())
		
		plist = os.listdir(self.parent.plugindirectory)
				
		IndexList = []
		
		for p in plist:
			i = p.find(".idx")
			if i > -1:			
				IndexList.append(p)
		
		self.gUnIndex.SetRange(len(IndexList))
		self.gUnIndex.SetValue(0)
		x = 0		
		for idx in IndexList:
			try:
				self.RemoveFromIndex(idx)
			except:
				drScrolledMessageDialog.ShowMessage(self.parent, ('Error Removing Plugins From Index: "' + idx + '".'), "Uninstall Error")
			x = x + 1
			self.gUnIndex.SetValue(x)
		
		self.stxtUnIndexing.SetForegroundColour(wx.Colour(175, 175, 175))
		self.stxtDone.SetForegroundColour(self.GetForegroundColour())
		
	def UnInstall(self, plugin):
		pluginfile = self.parent.plugindirectory + plugin + ".py"
		try:
			continueuninstall = True
			try:
				exec(compile("import " + plugin, plugin, 'exec'))
				exec(compile("continueuninstall = " + plugin + ".UnInstall(self.parent.ancestor)", plugin, 'exec'))
			except:
				pass
			if continueuninstall:
				os.remove(pluginfile)
				if os.path.exists(pluginfile + "c"):
					os.remove(pluginfile + "c")
				if os.path.exists(pluginfile + ".bak"):
					os.remove(pluginfile + ".bak")
		except:
			drScrolledMessageDialog.ShowMessage(self.parent, ("Error Removing Plugin File: " + pluginfile), "Uninstall Error")

class drPluginUnInstallWizard(wx.wizard.Wizard):
	def __init__(self, parent, title, bitmap):
		wx.wizard.Wizard.__init__(self, parent, 303, title, bitmap)
		
		self.ancestor = parent
		
		self.plugindirectory = parent.userpreferencesdirectory + "/plugins/"
		
		self.pluginstoremove = []
		self.removealldataforpluginArray = []
		
		self.SelectPage = drPluginUnInstallSelectPage(self)
		self.DataPage = drPluginUnInstallDataPage(self)
		self.UnInstallPage = drPluginUnInstallUnInstallPage(self)
		
		wx.wizard.WizardPageSimple_Chain(self.SelectPage, self.DataPage)
		wx.wizard.WizardPageSimple_Chain(self.DataPage, self.UnInstallPage)
		
		self.Location = 0
		self.Mirror = ''
		
		self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged, id=303)
	
	def OnPageChanged(self, event):
		cp = self.GetCurrentPage()
		if cp == self.DataPage:
			self.DataPage.Run()
		elif cp == self.UnInstallPage:
			self.UnInstallPage.Run()
		
	def Run(self):
		self.RunWizard(self.SelectPage)

#*******************************************************************************
#Edit Indexes Dialog
		
class drEditIndexDialog(wx.Dialog):

	def __init__(self, parent):
		wx.Dialog.__init__(self, parent, -1, "Edit Indexes", wx.DefaultPosition, wx.Size(-1, -1), wx.DEFAULT_DIALOG_STYLE | wx.THICK_FRAME)
				
		wx.Yield()
		
		#File Type
		self.iwildcard = "DrPython Plugin Index (*.idx)|*.idx|All files (*)|*"
		
		self.ID_SAVE = 102		
		self.ID_DELETE = 103
		self.ID_SAVE_AS = 104		
		self.ID_NEW = 105
				
		self.ID_ADD = 1003
		self.ID_REMOVE = 1004
		self.ID_INDEX = 1005
		
		self.ID_PROGRAM = 1010
		self.ID_POPUP = 1011
		
		self.ID_UP = 1111
		self.ID_DOWN = 2222		

		self.userpreferencesdirectory = parent.userpreferencesdirectory
		
		plist = os.listdir(self.userpreferencesdirectory + "/plugins")
				
		self.PluginList = []
		
		self.IndexList = []
		
		self.indexname = ""
		self.indexplugins = []
		
		for p in plist:
			i = p.find(".py")			
			l = len(p)
			if i > -1 and (i + 3 == l):			
				self.PluginList.append(p[:i])
			else:
				i = p.find(".idx")
				if i > -1:
					self.IndexList.append(p)
		
		self.PluginList.sort()
		self.IndexList.sort()
		
		self.boxPlugins = wx.ListBox(self, self.ID_PROGRAM, wx.DefaultPosition, wx.Size(200, 200), self.PluginList)
		
		self.boxFile = wx.ListBox(self, self.ID_POPUP, wx.DefaultPosition, wx.Size(200, 200))
		
		self.btnAdd = wx.Button(self, self.ID_ADD, " ---> ")
		self.btnRemove = wx.Button(self, self.ID_REMOVE, " Remove ")
						
		self.btnUp = wx.Button(self, self.ID_UP, " Up ")
		self.btnDown = wx.Button(self, self.ID_DOWN, " Down ")
						
		self.cboIndex = wx.Choice(self, self.ID_INDEX, wx.DefaultPosition, (250, -1), self.IndexList)		
		
		self.cboIndex.SetStringSelection('default.idx')
				
		self.btnClose = wx.Button(self, wx.ID_CANCEL, "&Close Dialog")
		self.btnDelete = wx.Button(self, self.ID_DELETE, "&Delete Index")
		self.btnNew = wx.Button(self, self.ID_NEW, "&New Index")
		self.btnSave = wx.Button(self, self.ID_SAVE, "&Save Index")
		self.btnSaveAs = wx.Button(self, self.ID_SAVE_AS, "&Save Index As")

		self.theSizer = wx.BoxSizer(wx.VERTICAL)
		self.indexSizer = wx.BoxSizer(wx.HORIZONTAL)
		self.topmenuSizer = wx.BoxSizer(wx.HORIZONTAL)
		self.mainSizer = wx.FlexGridSizer(4, 4, 5, 10)
		self.menubuttonSizer = wx.BoxSizer(wx.VERTICAL)
		
		self.indexSizer.Add(wx.StaticText(self, -1, "   Current Index:   "), 0, wx.SHAPED)
		self.indexSizer.Add(self.cboIndex, 0, wx.SHAPED)
		self.indexSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.SHAPED)
		self.indexSizer.Add(self.btnClose, 0, wx.SHAPED)
		
		self.topmenuSizer.Add(self.btnDelete, 1, wx.SHAPED)
		self.topmenuSizer.Add(self.btnNew, 1, wx.SHAPED)
		self.topmenuSizer.Add(self.btnSave, 1, wx.SHAPED)
		self.topmenuSizer.Add(self.btnSaveAs, 1, wx.SHAPED)
				
		self.menubuttonSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.menubuttonSizer.Add(self.btnAdd, 0, wx.SHAPED)
		self.menubuttonSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.menubuttonSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.menubuttonSizer.Add(self.btnUp, 0, wx.SHAPED)
		self.menubuttonSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.menubuttonSizer.Add(self.btnDown, 0, wx.SHAPED)
		self.menubuttonSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.menubuttonSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.menubuttonSizer.Add(self.btnRemove, 0, wx.SHAPED)
		
		self.mainSizer.Add(wx.StaticText(self, -1, ""), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.mainSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.mainSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.mainSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.mainSizer.Add(wx.StaticText(self, -1, ""), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.mainSizer.Add(wx.StaticText(self, -1, "Not In Index:"), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.mainSizer.Add(wx.StaticText(self, -1, "   "), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.mainSizer.Add(wx.StaticText(self, -1, "Plugins In Index:"), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.mainSizer.Add(wx.StaticText(self, -1, ""), 0, wx.ALIGN_CENTER | wx.SHAPED)
		self.mainSizer.Add(self.boxPlugins, 0, wx.SHAPED | wx.ALIGN_CENTER)
		self.mainSizer.Add(self.menubuttonSizer, 0, wx.SHAPED | wx.ALIGN_CENTER)
		self.mainSizer.Add(self.boxFile, 0,  wx.SHAPED | wx.ALIGN_CENTER)
				
		self.theSizer.Add(wx.StaticText(self, -1, ""), 1, wx.SHAPED)
		self.theSizer.Add(self.indexSizer, 1, wx.SHAPED | wx.ALIGN_CENTER)
		self.theSizer.Add(wx.StaticText(self, -1, ""), 1, wx.SHAPED | wx.ALIGN_CENTER)
		self.theSizer.Add(self.topmenuSizer, 1, wx.SHAPED | wx.ALIGN_CENTER)
		self.theSizer.Add(self.mainSizer, 9, wx.EXPAND)
		self.theSizer.Add(wx.StaticText(self, -1, ""), 1, wx.SHAPED)
		
		self.parent = parent		

		self.SetAutoLayout(True)
		self.SetSizerAndFit(self.theSizer)	
	
		self.Bind(wx.EVT_BUTTON, self.OnbtnUp, id=self.ID_UP)
		self.Bind(wx.EVT_BUTTON, self.OnbtnDown, id=self.ID_DOWN)
	
		self.Bind(wx.EVT_BUTTON, self.OnbtnAdd, id=self.ID_ADD)
		self.Bind(wx.EVT_BUTTON, self.OnbtnRemove, id=self.ID_REMOVE)
		self.Bind(wx.EVT_BUTTON, self.OnbtnSave, id=self.ID_SAVE)
		self.Bind(wx.EVT_BUTTON, self.OnbtnDelete, id=self.ID_DELETE)
		self.Bind(wx.EVT_BUTTON, self.OnbtnSaveAs, id=self.ID_SAVE_AS)
		self.Bind(wx.EVT_BUTTON, self.OnbtnNew, id=self.ID_NEW)
				
		self.Bind(wx.EVT_CHOICE, self.OnOpen, id=self.ID_INDEX)
				
		self.parent.LoadDialogSizeAndPosition(self, 'editindexdialog.sizeandposition.dat')
		
		self.OnOpen(None)

	def OnCloseW(self, event):
		self.parent.SaveDialogSizeAndPosition(self, 'plugindialog.sizeandposition.dat')
		if event is not None:
			event.Skip()	
			
	def OnbtnAdd(self, event):	
		tselection = self.boxPlugins.GetStringSelection()
		try:
			self.indexplugins.index(tselection)
			d = drScrolledMessageDialog.ScrolledMessageDialog(self, 'Plugin "' + tselection + '" has already been added.', "Already Added")
			d.ShowModal()
			d.Destroy()
		except:			
			tsel = self.boxPlugins.GetSelection()
			if tsel == -1:
				drScrolledMessageDialog.ShowMessage(self, "Nothing Selected to Add", "Mistake")
				return
			sel = self.boxFile.GetSelection()
			if sel == -1:
				sel = 0	
			self.boxFile.Append(tselection)
			self.boxFile.SetSelection(sel)
			self.indexplugins.append(tselection)
			self.SetNotInIndex()
		
	def OnbtnDelete(self, event):
		indexname = self.cboIndex.GetStringSelection()
		if indexname == 'default.idx':
			drScrolledMessageDialog.ShowMessage(self, 'You Cannot Delete the Default Index', 'Error')
			return	
		d = wx.MessageDialog(self, 'Delete "%s"?' % (indexname), "DrPython", wx.YES_NO | wx.ICON_QUESTION)
		answer = d.ShowModal()
		d.Destroy()
		if (answer == wx.ID_YES):
			indexfile = self.userpreferencesdirectory + "/plugins/" + indexname
			if not os.path.exists(indexfile):
				drScrolledMessageDialog.ShowMessage(self, '"%s" does not exist.' % (indexfile), 'Error')
				return
			try:
				os.remove(indexfile)
			except:
				drScrolledMessageDialog.ShowMessage(self, 'Error Removing "%s".' % (indexfile), 'Error')
			if indexname in self.IndexList:
				i = self.IndexList.index(indexname)
				self.IndexList.pop(i)
				self.cboIndex.Delete(i)
			self.cboIndex.SetStringSelection('default.idx')
			self.OnOpen(None)
			if self.parent.prefs.enablefeedback:
				drScrolledMessageDialog.ShowMessage(self, 'Successfully Removed "%s".' % (indexfile), 'Deleted Index')			
	
	def OnbtnDown(self, event):
		sel = self.boxFile.GetSelection()
		if sel < self.boxFile.GetCount() - 1 and sel > -1:
			txt = self.boxFile.GetString(sel)
			self.boxFile.Delete(sel)
			self.boxFile.InsertItems([txt], sel+1)
			self.boxFile.SetSelection(sel+1)
			#franz:swap elements
			self.indexplugins.insert(sel+1, self.indexplugins.pop(sel))			
	
	def OnbtnNew(self, event):
		d = wx.TextEntryDialog(self, "Enter New Index Name (No .idx):", "New Index", "")
		answer = d.ShowModal()
		v = d.GetValue()
		d.Destroy()
		if (answer == wx.ID_OK):
			indexname = v + '.idx'
			indexfile = self.userpreferencesdirectory + '/plugins/' + indexname
			self.IndexList.append(indexname)
			self.cboIndex.Append(indexname)
			self.cboIndex.SetStringSelection(indexname)
			try:
				f = file(indexfile, 'wb')
				f.write('\n')
				f.close()
			except:
				drScrolledMessageDialog.ShowMessage(self, 'Error Creating "%s".' % (indexfile), 'Error')
				return
			
			self.OnOpen(None)
	
	def OnbtnRemove(self, event):
		sel = self.boxFile.GetSelection()
		selection = self.boxFile.GetStringSelection()
		if sel == -1:
			drScrolledMessageDialog.ShowMessage(self, "Nothing Selected to Remove", "Mistake")
			return

		self.indexplugins.pop(sel)
		self.boxFile.Delete(sel)
		self.boxFile.SetSelection(sel-1)
		self.SetNotInIndex()
	
	def OnbtnSave(self, event):
		f = file(self.indexname, 'w')
		for plugin in self.indexplugins:
			f.write(plugin + "\n")
		f.close()
		if self.parent.prefs.enablefeedback:
			drScrolledMessageDialog.ShowMessage(self, ("Succesfully wrote to:\n"  + self.indexname), "Saved Changes to Index File")
	
	def OnbtnSaveAs(self, event):
		idx = self.cboIndex.GetStringSelection()
		d = wx.TextEntryDialog(self, 'Save "%s" As(No .idx):' % (idx), "Save Index As", "")
		answer = d.ShowModal()
		v = d.GetValue()
		d.Destroy()
		if (answer == wx.ID_OK):
			indexname = v + '.idx'
			indexfile = self.userpreferencesdirectory + '/plugins/' + indexname
			self.IndexList.append(indexname)
			self.cboIndex.Append(indexname)
			self.cboIndex.SetStringSelection(indexname)
			try:
				f = file(indexfile, 'wb')
				for plugin in self.indexplugins:
					f.write(plugin + "\n")
				f.close()
				if self.parent.prefs.enablefeedback:
					drScrolledMessageDialog.ShowMessage(self, ("Succesfully wrote to:\n"  + indexfile), "Saved Changes to Index File")
			except:
				drScrolledMessageDialog.ShowMessage(self, 'Error Saving "%s" As "%s".' % (idx, indexname), 'Error')
				return
	
	def OnbtnUp(self, event):
		sel = self.boxFile.GetSelection()		
		if sel > 0:
			txt = self.boxFile.GetString(sel)
			self.boxFile.Delete(sel)
			self.boxFile.InsertItems([txt], sel-1)
			self.boxFile.SetSelection(sel-1)
			#franz:swap elements
			self.indexplugins.insert(sel-1, self.indexplugins.pop(sel))			
				
	def OnOpen(self, event):
		fname = self.cboIndex.GetStringSelection()
		self.indexname = self.userpreferencesdirectory + "/plugins/" + fname
		if not os.path.exists(self.indexname):
			return
		try:
			f = file(self.indexname, 'r')
			self.indexplugins = f.read().rstrip().split('\n')
			f.close()
			
			x = 0
			l = len(self.indexplugins)
			while x < l:
				if len(self.indexplugins[x]) < 1:
					self.indexplugins.pop(x)
					x = x - 1
					l = l - 1
				x = x + 1
			
			self.boxFile.Set(self.indexplugins)
			self.SetNotInIndex()
		except:
			drScrolledMessageDialog.ShowMessage(self.parent, ("Error Reading Index File: " + self.indexname), "Open Error")
			
	def SetNotInIndex (self):
		#Written By Franz
		nlist = []
		for i in self.PluginList:
			if i not in self.indexplugins:
				nlist.append (i)
		#self.PluginList = nlist		
		self.boxPlugins.Set (nlist)

syntax highlighted by Code2HTML, v. 0.9.1