#
# FtpCube
# Copyright (C) 2001 Michael Gilfix
#
# This file is part of FtpCube.
#
# You should have received a file COPYING containing license terms
# along with this program; if not, write to Michael Gilfix
# (mgilfix@eecs.tufts.edu) for a copy.
#
# This version of FtpCube is open source; you can redistribute it and/or
# modify it under the terms listed in the file COPYING.
#
# 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.
#

import gtk, GtkExtra
import sys, os, time, re
import string # For backwards compatibility with 1.5.x
import main, app, ftp, cache
import browsewin

from intl import _

# For compatibility with win32 pygtk
if sys.platform == "win32":
	import GTKconst
	GTK = GTKconst
else:
	import GTK

class AbstractFileWin:

	UNSORTED = 0
	SORT_BY_NAME = 1
	SORT_BY_SIZE = 2
	SORT_BY_DATE = 3

	hidden_re = re.compile ("^\..*")

	def __init__ (self, container, headings):

		# Initialize instance variables
		self.sorted = 1
		self.directories_first = 1
		self.hidden_files = 1
		self.dir = ''

		box = gtk.GtkVBox ()
		box.show ()
		container.add (box)

		self.win = gtk.GtkScrolledWindow ()
		self.win.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		self.win.show ()
		box.pack_start (self.win)

		self.status_bar = gtk.GtkHBox ()
		self.status_bar.set_usize (-1, 15)
		self.status_bar.show ()
		box.pack_start (self.status_bar, expand=gtk.FALSE, fill=gtk.TRUE)

		self.list = gtk.GtkCList (len (headings), headings)
		self.list.connect ("select_row", self.select_items)
		self.list.connect ("button_press_event", self.popup_menu)

		self.list.set_selection_mode (GTK.SELECTION_MULTIPLE)
		self.win.add_with_viewport (self.list)
		self.list.show ()

		self.load_pixmaps ()

	def load_pixmaps (self):

		self.folder_pixmap, self.folder_mask = gtk.create_pixmap_from_xpm (self.list, None, os.path.join (main.ICONS_PREFIX, "folder.xpm"))
		self.link_pixmap, self.link_mask = gtk.create_pixmap_from_xpm (self.list, None, os.path.join (main.ICONS_PREFIX, "link.xpm"))
		self.file_pixmap, self.file_mask = gtk.create_pixmap_from_xpm (self.list, None, os.path.join (main.ICONS_PREFIX, "file.xpm"))

	def select_pixmap (self, listitem):

		file, size, mtime, type, truesize = listitem
		if not type:
			return self.folder_pixmap, self.folder_mask
		else:
			if type[0] == 'l':
				return self.link_pixmap, self.link_mask
			elif type[0] in 'd ':
				return self.folder_pixmap, self.folder_mask
			else:
				return self.file_pixmap, self.file_mask

	def select_items (self, list, r, c, event):

		# This needs to be overridden in the subclass
		pass

	def popup_menu (self, list, event):

		# This needs to be overridden in the subclass
		pass

	def hide_hidden (self, button):

		self.hidden_files = (self.hidden_files + 1) % 2
		self.update_listing ('.')

	def unsorted (self, action, button):

		self.sorted = self.UNSORTED
		self.directories_first = 0
		self.update_listing ('.')

	def sort_by_name (self, action, button):

		self.sorted = self.SORT_BY_NAME
		self.directories_first = 1
		self.update_listing ('.')

	def sort_by_size (self, action, button):

		self.sorted = self.SORT_BY_SIZE
		self.directories_first = 1
		self.update_listing ('.')

	def sort_by_date (self, action, button):

		self.sorted = self.SORT_BY_DATE
		self.directories_first = 1
		self.update_listing ('.')

	def sort_directories_first (self, button):

		self.directories_first = (self.directories_first + 1) % 2
		self.update_listing ('.')

	def clear_items (self):
		self.list.clear ()

	def get_dir (self):
		return self.dir

	def set_dir (self, dir):
		self.dir = dir

	def get_file_size (self, file):

		for i in range (self.list.rows):
			if self.list.get_pixtext (i, 0)[0] == file:
				return int (self.list.get_text (i, 4))
		return None

	def update_listing (self, dir):

		# To be overridden in the subclass
		raise NotImplementedError

	def sort_list (self, list):

		# To be overridden in the subclass
		raise NotImplementedError

	def perform_sort (self, list):

		if self.sorted == self.SORT_BY_NAME:
			list.sort (lambda x, y: cmp (x[0], y[0]))
		elif self.sorted == self.SORT_BY_SIZE:
			list.sort (lambda x, y: cmp (int (x[4]), int (y[4])))
		elif self.sorted == self.SORT_BY_DATE:
			list.sort (lambda x, y: cmp (time.strptime (x[2], "%b %d %H:%M"), time.strptime (y[2], "%b %d %H:%M")))
		return list

class LocalWin (AbstractFileWin):

	headings = [ _('Filename'), _('Size'), _('Date'), _('Type'), _('Truesize') ]
	time_re = re.compile ('[A-Za-z]+\s+([A-Za-z]+\s+\d+\s+\d+:\d+):(\d+)\s+\d+')

	def __init__ (self, container):

		AbstractFileWin.__init__ (self, container, self.headings)

		toolbar = gtk.GtkToolbar (gtk.ORIENTATION_HORIZONTAL, gtk.TOOLBAR_ICONS)
		toolbar.show ()
		pic, mask = gtk.create_pixmap_from_xpm (toolbar, None, os.path.join (main.ICONS_PREFIX, "enable.xpm"))
		toolbar.append_element (GTK.TOOLBAR_CHILD_TOGGLEBUTTON, None,
			"", _("Enable/Disable automatic updates"),
			_("Enable/Disable automatic updates"),
			gtk.GtkPixmap (pic, mask),
			None)
		self.status_bar.pack_start (toolbar, expand=gtk.FALSE, fill=gtk.FALSE)

		self.status_label = gtk.GtkLabel ("")
		self.status_label.show ()
		self.status_bar.pack_start (self.status_label, expand=gtk.FALSE, fill=gtk.FALSE, padding=6)

		# Set the settings for our list
		for i in range(len (self.headings)):
			self.list.set_column_width (i, 100)
			self.list.set_column_justification (i, GTK.JUSTIFY_LEFT)
		# Explicitly make the first column for the filename bigger
		self.list.set_column_width (0, 200)
		# Hide the flags column
		self.list.set_column_visibility (3, 0)
		self.list.set_column_visibility (4, 0)
		# Make file sizes right justified
		self.list.set_column_justification (1, GTK.JUSTIFY_RIGHT)
		# So we can't click the titles as buttons
		self.list.column_titles_passive ()

		# Open up the default directory for display
		if os.environ.has_key ('HOME'):
			self.dir = os.environ['HOME']
		else:
			self.dir = os.getcwd ()
		self.update_listing (self.dir)

	def select_items (self, list, r, c, event):

		if hasattr (event, 'type'):
			# Check for double clicks
			if event.type == 5:
				selected = list.get_pixtext (r, 0)[0]
				self.update_listing (selected)

	def popup_menu (self, list, event):

		if event.button == 3:
			opts = [
				(_('/Upload Files'),             None, self.upload_selected,  0, ''),
				#('/Open',                     None, self.open_selected,    0, ''),
				#('/Edit',                     None, self.edit_selected,    0, ''),
				#('/View File',                None, None,                  0, ''),
				(_('/Rename Files'),             None, self.rename_selected,  0, ''),
				(_('/Delete Selected Files'),    None, self.delete_selected,  0, ''),
				('/Sep1',                     None, None,                  0, '<Separator>'),
				(_('/Create Directory'),         None, self.create_directory, 0, ''),
				('/Change Directory',            None, self.cd_selected,      0, ''),
				#('/Change Drive',             None, None,                  0, ''),
				#('/Sep2',                     None, None,                  0, '<Separator>'),
				#('/Compare Directories',      None, None,                  0, ''),
				#('/Open Current in Browser',  None, None,                  0, ''),
				#('/Open Selected in Browser', None, None,                  0, ''),
				#('/Command Prompt Here',      None, None,                  0, ''),
				#('/Sep3',                     None, None,                  0, '<Separator>'),
				#('/Directory Info',           None, None,                  0, ''),
				('/Sep4',                     None, None,                  0, '<Separator>'),
				(_('/Hide Hidden Files'),        None, None,                  0, '<ToggleItem>'),
				('/Sep5',                     None, None,                  0, '<Separator>'),
				(_('/Sort Order'),               None, None,                  0, '<Branch>'),
				(_('/Sort Order/Unsorted'),      None, self.unsorted,         0, ''),
				(_('/Sort Order/Sort by Name'),  None, self.sort_by_name,     0, ''),
				(_('/Sort Order/Sort by Size'),  None, self.sort_by_size,     0, ''),
				(_('/Sort Order/Sort by Date'),  None, self.sort_by_date,     0, ''),
				(_('/Sort Order/<separator>'),   None, None,                  0, '<Separator>'),
				(_('/Sort Order/Order Directories-Links-Files'), None, None, 0, '<ToggleItem>')
			]

			ag = gtk.GtkAccelGroup()
			items = gtk.GtkItemFactory(gtk.GtkMenu.get_type(), "<popup>", ag)
			items.create_items (opts)

			checked = items.get_widget (_('/Hide Hidden Files'))
			if self.hidden_files:
				checked.set_active (gtk.TRUE)
			checked.connect ("activate", self.hide_hidden)

			checked = items.get_widget (_('/Sort Order/Order Directories-Links-Files'))
			if self.directories_first:
				checked.set_active (gtk.TRUE)
			checked.connect ("activate", self.sort_directories_first)

			menu = items.get_widget ("<popup>")
			menu.popup (None, None, None, event.button, event.time)
			menu.show ()

	def upload_selected (self, action, button):

		files = [ ]

		for i in self.list.selection:
			entry = [ ]
			entry.append (self.list.get_pixtext (i, 0)[0])
			# Get remaining entries
			for j in range (self.list.columns - 1):
				entry.append (self.list.get_text (i, j + 1))

			# Check if the file already exists remotely. If so replace
			# the file's size with the remote size. Later we'll check
			# if the size is smaller and perform a resume if it is
			remote_size = main.app.get_file_size (entry[0])
			if remote_size is not None:
				entry[4] = remote_size

			if entry[0] == "..":
				continue
			else:
				files.append (tuple (entry))

		self.list.unselect_all ()
		main.app.transfer (main.app.get_remote_dir (), self.get_dir (), files, ftp.UPLOAD, main.app['transfer_type'])

	def cd_selected (self, action, button):

		browse_win = browsewin.LocalCWD (self.get_dir ())

	def open_selected (self, action, button):

		for i in self.list.selection:
			file = self.list.get_pixtext (i, 0)[0]
			path = os.path.join (self.get_dir (), file)

			# Skip the home directory entry
			if file == ".." or \
			   not os.path.isfile (path) or \
			   not os.access (path, os.X_OK):
				continue
			else:
				# Execing code will go here
				pass

	def edit_selected (self, action, button):

		for i in self.list.selection:
			file = self.list.get_pixtext (i, 0)[0]
			path = os.path.join (self.get_dir (), file)

			# Editing code will go here

	def delete_selected (self, action, button):

		for i in self.list.selection:
			file = self.list.get_pixtext (i, 0)[0]
			type = self.list.get_text (i, 3)[0]
			path = os.path.join (self.dir, file)
			if type in '-lf':
				os.remove (path)
			else:
				os.rmdir (path)
		self.list.unselect_all ()
		self.update_listing (self.dir)

	def rename_selected (self, action, button):

		for i in self.list.selection:
			file = self.list.get_pixtext (i, 0)[0]
			orig_path = os.path.join (self.get_dir (), file)
			new = GtkExtra.input_box (title=_("ftpcube - Rename"), message=_("Rename %s to:") %file)
			if new:
				new_path = os.path.join (self.get_dir (), new)
				try:
					os.rename (orig_path, new_path)
				except OSError, strerror:
					GtkExtra.message_box (title=_("ftpcube Error"), message=_("ftpcube error: %s") %strerror, buttons=( [ _("Ok") ]))
					return
		self.update_listing (self.dir)

	def create_directory (self, action, button):

		dir = GtkExtra.input_box (title=_("ftpcube - Create Directory"), message=_("Directory Name:"))
		if dir is not None:
			path = os.path.join (self.get_dir (), dir)
			try:
				os.mkdir (path)
			except OSError, strerror:
				GtkExtra.message_box (title=_("ftpcube Error"), message=_("ftpcube error: %s") %strerror, buttons=( [ _("Ok") ]))
				return
			self.update_listing (self.dir)

	def update_status_dir (self, dir):
		self.status_label.set_text (dir)

	def enable_dir_update (self, button):
		pass

	def read_dir (self, dir):

		# If we say '.', we really mean our current directory
		if dir == '.':
			dir = self.dir

		try:
			files = os.listdir (dir)
		except OSError, (errno, strerror):
			GtkExtra.message_box (title=_("ftpcube Error"), message=_("ftpcube Error: %s") %strerror, buttons=( [ _("Ok") ]))
			return

		if self.hidden_files:
			files = filter (lambda x, self=self: not self.hidden_re.match (x), files)

		# Add the special file ".."
		files.insert (0, "..")

		# Now grab the file info and load it into the load
		listitems = []
		for f in files:

			# Attempt to retrieve the file and modification times
			try:
				# lstat is preferrable for systems that support it
				if os.name == 'posix':
					(st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, st_size,
					 st_atime, st_mtime, st_ctime) = os.lstat (os.path.join (dir, f))
				else:
					(st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, st_size,
					 st_atime, st_mtime, st_ctime) = os.stat (os.path.join (dir, f))
			except OSError, strerror:
				# Set the size and mtime to 0 then and carry on if we can't stat
				# the file for some reason but know it's there
				st_size = 0
				st_mtime = 0

			# Beautify the size string
			size = app.beautify_size (st_size)

			# Beautify the time
			match = self.time_re.match (time.ctime (st_mtime))
			mtime = match.group (1)

			# Set the appropriate file type
			if os.path.islink (os.path.join (self.dir, f)):
				type = "l"
			elif os.path.isdir (os.path.join (self.dir, f)):
				type = "d"
			else:
				type = "f"

			listitems.append ((f, size, mtime, type, "%s" %st_size))

		return listitems

	def update_listing (self, dir):

		# Strip off any trailing '/' characters
		if dir[-1] == '/':
			dir = dir[:-1]

		# Construct our new path
		if dir == '..':
			self.dir = os.path.dirname (self.dir)
		elif dir == '.':
			# Don't modify the path
			pass
		else:
			newpath = os.path.join (self.dir, dir)
			if not os.path.isdir (newpath):
				return
			else:
				self.dir = newpath

		# Get the new listing
		listitems = self.read_dir (self.dir)

		# Now change the list to reflect the new listing. Notice that we
		# pause the visuals during the update so it doesn't look funny
		self.list.freeze ()
		self.clear_items ()
		if self.sorted:
			listitems = self.sort_list (listitems)
		for i in range (len (listitems)):
			self.list.append (listitems[i])
			listitem = listitems[i]
			pixmap, mask = self.select_pixmap (listitem)
			self.list.set_pixmap (i, 0, pixmap, mask)
			self.list.set_pixtext (i, 0, listitem[0], 4, pixmap, mask)
		self.list.thaw ()

		# Update the status
		self.update_status_dir (self.dir)

	def sort_list (self, list):

		if self.directories_first:
			dirs = filter (lambda i: i[3] == 'd', list)
			links = filter (lambda i: i[3] == 'l', list)
			files = filter (lambda i: i[3] in 'f-', list)

			list = [ ]
			list.extend (self.perform_sort (dirs))
			list.extend (self.perform_sort (links))
			list.extend (self.perform_sort (files))
		else:
			list = self.perform_sort (list)
		return list

class RemoteWin (AbstractFileWin):

	headings = [ _('Filename'), _('Size'), _('Date'), _('Flags'), _('Truesize') ]

	list_re = re.compile ('([A-Za-z-]+)\s+(\d+)\s+([A-Za-z0-9]+)\s+([A-Za-z0-9]+)\s+(\d+)\s+([A-Za-z]+\s+[0-9]+\s+[0-9:]+)\s+(.*)', re.IGNORECASE)
	link_re = re.compile ('(.*) -> (.*)')
	broken_link_re = re.compile ('.*-> (.*)')
	time_re = re.compile ('[A-Za-z]+\s+([A-Za-z]+\s+\d+\s+\d+:\d+):(\d+)\s+\d+')

	def __init__ (self, container):

		AbstractFileWin.__init__ (self, container, self.headings)

		self.status_label = gtk.GtkLabel ()
		self.status_label.show ()
		self.status_bar.pack_start (self.status_label, expand=GTK.FALSE, padding=6)

		# Set the list settings for our file window
		for i in range(len (self.headings)):
			self.list.set_column_width (i, 100)
			self.list.set_column_justification (i, gtk.JUSTIFY_LEFT)
		# Explicitly make the first column for the filename bigger
		self.list.set_column_width (0, 200)
		self.list.set_column_visibility (4, 0)
		# Make file sizes right justified
		self.list.set_column_justification (1, GTK.JUSTIFY_RIGHT)
		# So we can't click the titles as buttons
		self.list.column_titles_passive ()

		self.cache = cache.CacheTree ()

	def select_items (self, list, r, c, event):

		if hasattr (event, 'type'):
			# Check for double clicks
			if event.type == 5 and not main.app.main_thread.busy ():
				selected = list.get_pixtext (r, 0)[0]

				# Construct our new dir path
				if selected == "..":
					main.app.main_thread.cwd ('..')

					# Update the status directory
					text = self.get_dir ()
					index = string.rfind (text, "/")
					if index == 0:
						self.update_status_dir ("/")
					else:
						self.update_status_dir (text[:index])

					self.get_listing ()
				else:
					# Check if we have a directory
					f = list.get_text (r, 3)[0]
					if f in 'ld':
						# Update the status directory before the action
						# so we can roll back in the case of an exception
						self.update_status_dir (os.path.join (self.get_dir (), selected))

						main.app.main_thread.set_exception_handler (self.set_listing_callback)
						main.app.main_thread.cwd (selected)
						main.app.main_thread.set_exception_handler (self.set_listing_callback)
						self.get_listing ()

	def set_listing_callback (self, errmsg):

		gtk.threads_enter ()
		main.app.ftp_error_tell_user (errmsg)
		self.update_status_dir (self.get_dir ())
		gtk.threads_leave ()

	def popup_menu (self, list, event):

		if event.button == 3:
			opts = [
				(_("/Download Selected"),         None, self.download_selected, 0, ''),
				#("/View File",                 None, None, 0, ''),
				(_("/Rename Selected"),           None, self.rename_selected, 0, ''),
				(_("/Delete Selected"),           None, self.delete_selected, 0, ''),
				#("/Recursive Delete",          None, None, 0, ''),
				("/Sep1",                         None,    None, 0, '<Separator>'),
				(_("/Create Directory"),          None, self.mkdir_selected, 0, ''),
				(_("/Remove Directories"),        None, self.rmdir_selected, 0, ''),
				(_("/Change Directory"),          None, self.cd_selected, 0, ''),
				(_("/Refresh Cache"),             None, self.refresh_selected, 0, ''),
				#("/Sep2",                      None, None, 0, '<Separator>'),
				#("/Compare Directories",       None, None, 0, ''),
				#("/Add Bookmarks",             None, None, 0, ''),
				#("/Sep3",                      None, None, 0, '<Separator>'),
				#("/Set Attributes",            None, None, 0, ''),
				#("/Custom Commands",           None, None, 0, ''),
				#("/Directory Info",            None, None, 0, ''),
				(_("/Sep4"),                      None, None, 0, '<Separator>'),
				(_("/Sort Order"),                None, None, 0, '<Branch>'),
				(_("/Sort Order/Unsorted"),       None, self.unsorted, 0, ''),
				(_("/Sort Order/Sort by Name"),   None, self.sort_by_name, 0, ''),
				(_("/Sort Order/Sort by Size"),   None, self.sort_by_size, 0, ''),
				(_("/Sort Order/Sort by Date"),   None, self.sort_by_date, 0, ''),
				(_("/Sort Order/Sep5"),           None, None, 0, '<Separator>'),
				(_("/Sort Order/Order Directories-Links-Files"), None, None, 0, '<ToggleItem>')
			]

			ag = gtk.GtkAccelGroup()
			items = gtk.GtkItemFactory(gtk.GtkMenu.get_type(), "<popup>", ag)
			items.create_items (opts)

			checked = items.get_widget (_('/Sort Order/Order Directories-Links-Files'))
			if self.directories_first:
				checked.set_active (gtk.TRUE)
			checked.connect ("activate", self.sort_directories_first)

			menu = items.get_widget ("<popup>")
			menu.popup (None, None, None, event.button, event.time)
			menu.show ()

	def clear_cache (self):

		del self.cache
		self.cache = cache.CacheTree ()

	def get_listing (self):

		path_node = self.cache.find_node (self.get_dir ())
		if path_node is None:
			main.app.main_thread.list ()
		else:
			listing = path_node.data
			self.set_list (listing)

	def update_listing (self, listing):

		# Create the ".." entry
		match = self.time_re.match (time.ctime (time.time ()))
		localtime = match.group (1)
		dotdotentry = ('..', _('4.00 KBytes'), localtime, '', '0')
		listitems = [ dotdotentry ]

		cache_node = self.cache.add_node (self.get_dir ())

		# Update the last listing array and parse the entries to update
		# the remote listing
		for entry in listing:
			tuple = self.parse_list_entry (entry)
			if tuple is None:
				continue
			else:
				file, truesize, date, flags = tuple

			# Beautify the size string
			size = app.beautify_size (truesize)

			# Check if the file is a link and if so, clean up the file name
			if flags and flags[0] == 'l':
				match = self.link_re.match (file)
				if match is not None:
					file, dest = match.groups ()
				else:
					# Try the broken link match
					match = self.broken_link_re.match (file)
					if match is not None:
						file = match.group (1)
						file = os.path.basename (file)
					else:
						print "WARNING: Match failed for: %s" %file

			listitems.append ((file, size, date, flags, "%s" %truesize))

		# Now change the list to reflect the new listing. Notice that we
		# pause the visuals during the update so it doesn't look funny
		if self.sorted:
			listitems = self.sort_list (listitems)
		cache_node.data = listitems
		self.set_list (listitems)

	def get_status (self):
		return self.status_label.get ()

	def update_status_dir (self, dir):

		self.dir = dir
		self.update_status (self.dir)
		main.app.update_dir_entry_status (self.dir)

	def update_status (self, text):
		self.status_label.set_text (text)

	def parse_list_entry (self, entry):

		match = self.list_re.match (entry)
		if match is None:
			#print "WARNING: listing match failed for: %s" %entry
			return None
		else:
			flags, hardlinks, user, group, size, date, file =  match.groups ()
			size = int (size)
			return file, size, date, flags

	def download_selected (self, action, button):

		files = [ ]

		# Extract the data from the CList. Note we don't use
		# get_row_data because it appears to be broken
		for i in self.list.selection:
			entry = [ ]
			entry.append (self.list.get_pixtext (i, 0)[0])
			# Get rest of entries
			for j in range (self.list.columns - 1):
				entry.append (self.list.get_text (i, j + 1))

			# Discard the ".." entry
			if entry[0] == "..":
				continue

			# Fix up the type
			if not entry[3][0] == '-':
				entry[3] = entry [3][0]
			else:
				entry[3] = 'f'

			files.append (tuple (entry))

		self.list.unselect_all ()
		main.app.transfer (self.get_dir (), main.app.get_local_dir (), files, ftp.DOWNLOAD, main.app['transfer_type'])

	def rename_selected (self, action, button):

		for i in self.list.selection:
			file = self.list.get_pixtext (i, 0)[0]
			new_name = GtkExtra.input_box (title=_("ftpcube - Remote Rename"), message=_("Rename %s to:" %file))
			if new_name is None:
				break
			main.app.main_thread.rename (file, new_name)
		main.app.main_thread.list ()

	def delete_selected (self, action, button):

		for i in self.list.selection:
			file = self.list.get_pixtext (i, 0)[0]
			type = self.list.get_text (i, 3)[0]
			if type in 'l-':
				main.app.main_thread.delete (file)
			else:
				main.app.main_thread.rmdir (file)

		self.list.unselect_all ()
		main.app.main_thread.list ()

	def mkdir_selected (self, action, button):

		dir = GtkExtra.input_box (title=_("ftpcube - Create Remote Directory"), message=_("Directory Name:"))
		if dir is not None:
			main.app.main_thread.mkdir (dir)
			main.app.main_thread.list ()

	def rmdir_selected (self, action, button):

		for i in self.list.selection:
			dir = self.list.get_pixtext (i, 0)[0]
			type = self.list.get_text (i, 3)[0]
			if type == 'd':
				main.app.main_thread.rmdir (dir)
		main.app.main_thread.list ()

	def cd_selected (self, action, button):

		browse_win = browsewin.RemoteCWD (self.cache, self.get_dir ())

	def refresh_selected (self, action, button):

		self.cache.remove_node (self.get_dir ())
		self.get_listing ()

	def set_list (self, list):

		self.list.freeze ()
		self.clear_items ()
		for i in range (len (list)):
			self.list.append (list[i])
			listitem = list[i]
			pixmap, mask = self.select_pixmap (listitem)
			self.list.set_pixmap (i, 0, pixmap, mask)
			self.list.set_pixtext (i, 0, listitem[0], 4, pixmap, mask)
		self.list.thaw ()

	def get_list (self):

		list = [ ]
		for i in range (self.list.rows):
			entry = [ ]
			for j in range (self.list.columns):
				if j == 0:
					entry.append (self.list.get_pixtext (i, j)[0])
				else:
					entry.append (self.list.get_text (i, j))
			list.append (tuple (entry))
		return list

	def sort_list (self, list):

		if self.directories_first:
			dirs = filter (lambda i: not i[3] or i[3][0] == 'd', list)
			links = filter (lambda i: i[3] and i[3][0] == 'l', list)
			files = filter (lambda i: i[3] and i[3][0] in 'f-', list)

			list = [ ]
			list.extend (self.perform_sort (dirs))
			list.extend (self.perform_sort (links))
			list.extend (self.perform_sort (files))
		else:
			list = self.perform_sort (list)
		return list
