"""
FtpCube
Copyright (C) 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 aboutwin
import bookmarkwin
import browsewin
import connectwin
import consolewin
import ctrlwin
import events
import icons.abort
import icons.bookmark
import icons.connect
import icons.disconnect
import icons.exit
import icons.quick_connect
import icons.refresh
import messages
import optionwin
import protocol
import utils
import wx
import os
class MainWindow(wx.Frame):
"""Application main window.
This serves as the main window for the application and the parent frame for all other
sub-windows. This sets up the main file menu, the console, browsing windows, and
control windows. The main window is also able to handle some events that go across
sub-windows. Sub-windows that wish to reuse the same thread without posting events can
call the on<event> methods directory."""
# File Menu ID's
idCONNECT = wx.NewId()
idQUICKCONNECT = wx.NewId()
idBOOKMARKS = wx.NewId()
idDISCONNECT = wx.NewId()
idCONSOLE = wx.NewId()
idOPTIONS = wx.NewId()
idEXIT = wx.NewId()
# Local Menu ID's
idLOCALUPLOAD = wx.NewId()
idLOCALRENAME = wx.NewId()
idLOCALDELETE = wx.NewId()
idLOCALCREATE = wx.NewId()
idLOCALCHMOD = wx.NewId()
idLOCALCHANGE = wx.NewId()
# Remote Menu ID's
idREMOTEDOWNLOAD = wx.NewId()
idREMOTERENAME = wx.NewId()
idREMOTEDELETE = wx.NewId()
idREMOTECREATE = wx.NewId()
idREMOTECHMOD = wx.NewId()
idREMOTEREMOVE = wx.NewId()
idREMOTECHANGE = wx.NewId()
# Help Menu ID's
idABOUT = wx.NewId()
# Tool ID's
idTOOL_CONNECT = wx.NewId()
idTOOL_QUICKCONNECT = wx.NewId()
idTOOL_DISCONNECT = wx.NewId()
idTOOL_ABORT = wx.NewId()
idTOOL_REFRESH = wx.NewId()
idTOOL_BOOKMARK = wx.NewId()
idTOOL_QUIT = wx.NewId()
idTOOL_ENTRYBOX = wx.NewId()
idTOOL_ASCII = wx.NewId()
idTOOL_BINARY = wx.NewId()
def __init__(self, parent, title):
"""Creates the application main window."""
if __debug__:
print "Making main application window."
wx.Frame.__init__(self, parent, -1, title, wx.DefaultPosition)
self.SetIcon(utils.getAppIcon())
config = utils.getApplicationConfiguration()
try:
width, height = config['win_size']
except:
width, height = None, None
if width and height:
self.SetSize((width, height))
else:
width, height = wx.DisplaySize()
self.SetSize((int(float(width) * 0.75), int(float(height) * 0.75)))
self.makeMenu()
toolbar = self.makeToolBar()
splitter = wx.SplitterWindow(self, -1, style=wx.SP_3DSASH)
self.consolewin = consolewin.ConsoleWindow(splitter)
csplitter = wx.SplitterWindow(splitter, -1, style=wx.SP_3DSASH)
# Set the default control window size
splitter.SplitHorizontally(self.consolewin, csplitter, 150)
self.ctrlwin = ctrlwin.ControlWindow(csplitter)
bsplitter = wx.SplitterWindow(csplitter, -1, style=wx.SP_3DSASH)
# Set the default control window size
csplitter.SplitVertically(self.ctrlwin, bsplitter, 275)
self.localwin = browsewin.LocalWindow(bsplitter)
self.remotewin = browsewin.RemoteWindow(bsplitter)
# Set the browse splitter evenly for the remaining space
size = (width - 275) / 2
bsplitter.SplitVertically(self.localwin, self.remotewin, size)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(splitter, 1, wx.EXPAND)
self.SetAutoLayout(True)
self.SetSizer(sizer)
self.Bind(wx.EVT_CLOSE, self.onQuit)
self.Bind(events.EVT_DIRECTORY_CHANGE, self.onDirectoryChange)
evt_registry = events.getEventRegistry()
evt_registry.registerEventListener(events.EVT_DIRECTORY_CHANGE_TYPE, self)
self.consolewin.displayBanner()
def makeMenu(self):
"""Creates the main menu."""
self.menu_bar = wx.MenuBar()
self.menu_bar.Append(self.createFileMenu(), _("&File"))
self.menu_bar.Append(self.createLocalMenu(), _("&Local"))
self.menu_bar.Append(self.createRemoteMenu(), _("&Remote"))
self.menu_bar.Append(self.createHelpMenu(), _("&Help"))
self.SetMenuBar(self.menu_bar)
def createFileMenu(self):
"""Creates the file menu."""
file_menu = wx.Menu()
file_menu.Append(self.idCONNECT, _("&Connect"), _("Connect to server"))
file_menu.Append(self.idQUICKCONNECT, _("&Quick Connect"),
_("Quick connect to server"))
file_menu.Append(self.idBOOKMARKS, _("&Bookmarks"), _("Display the bookmark window"))
file_menu.Append(self.idDISCONNECT, _("&Disconnect"), _("Disconnect from server"))
file_menu.AppendSeparator()
file_menu.Append(self.idOPTIONS, _("&Options"), _("Ftpcube options window"))
file_menu.AppendSeparator()
file_menu.Append(self.idCONSOLE, _("C&lear Console"), _("Clear console window"))
file_menu.AppendSeparator()
file_menu.Append(self.idEXIT, _("E&xit"), _("Exit Ftpcube"))
self.Bind(wx.EVT_MENU, self.onConnect, id=self.idCONNECT)
self.Bind(wx.EVT_MENU, self.onQuickConnect, id=self.idQUICKCONNECT)
self.Bind(wx.EVT_MENU, self.onBookmarks, id=self.idBOOKMARKS)
self.Bind(wx.EVT_MENU, self.onDisconnect, id=self.idDISCONNECT)
self.Bind(wx.EVT_MENU, self.onClearConsole, id=self.idCONSOLE)
self.Bind(wx.EVT_MENU, self.onOptions, id=self.idOPTIONS)
self.Bind(wx.EVT_MENU, self.onQuit, id=self.idEXIT)
return file_menu
def createLocalMenu(self):
"""Create the local action menu."""
local_menu = wx.Menu()
local_menu.Append(self.idLOCALUPLOAD, _("&Upload Files"), _("Upload files to server"))
local_menu.Append(self.idLOCALRENAME, _("&Rename Files"), _("Rename local files"))
local_menu.Append(self.idLOCALDELETE, _("&Delete Files"), _("Delete local files"))
local_menu.AppendSeparator()
local_menu.Append(self.idLOCALCREATE, _("&Create Directory"),
_("Create local directory"))
local_menu.Append(self.idLOCALCHMOD, _("Change &Permissions"),
_("Change file permissions"))
local_menu.Append(self.idLOCALCHANGE, _("C&hange Directory"),
_("Change local directory"))
self.Bind(wx.EVT_MENU, self.onLocalUpload, id=self.idLOCALUPLOAD)
self.Bind(wx.EVT_MENU, self.onLocalRename, id=self.idLOCALRENAME)
self.Bind(wx.EVT_MENU, self.onLocalDelete, id=self.idLOCALDELETE)
self.Bind(wx.EVT_MENU, self.onLocalCreate, id=self.idLOCALCREATE)
self.Bind(wx.EVT_MENU, self.onLocalChmod, id=self.idLOCALCHMOD)
self.Bind(wx.EVT_MENU, self.onLocalChange, id=self.idLOCALCHANGE)
return local_menu
def createRemoteMenu(self):
"""Create the remote action menu."""
remote_menu = wx.Menu()
remote_menu.Append(self.idREMOTEDOWNLOAD, _("&Download Files"),
_("Download files from server"))
remote_menu.Append(self.idREMOTERENAME, _("&Rename Files"),
_("Rename files on server"))
remote_menu.Append(self.idREMOTEDELETE, _("&Delete Files"),
_("Delete files from server"))
remote_menu.AppendSeparator()
remote_menu.Append(self.idREMOTECREATE, _("&Create Directory"),
_("Create directory on server"))
remote_menu.Append(self.idREMOTECHMOD, _("Change Permissions"),
_("Change permissions on server"))
remote_menu.Append(self.idREMOTECHANGE, _("C&hange Directory"),
_("Change server directory"))
self.Bind(wx.EVT_MENU, self.onRemoteDownload, id=self.idREMOTEDOWNLOAD)
self.Bind(wx.EVT_MENU, self.onRemoteRename, id=self.idREMOTERENAME)
self.Bind(wx.EVT_MENU, self.onRemoteDelete, id=self.idREMOTEDELETE)
self.Bind(wx.EVT_MENU, self.onRemoteCreate, id=self.idREMOTECREATE)
self.Bind(wx.EVT_MENU, self.onRemoteChmod, id=self.idREMOTECHMOD)
self.Bind(wx.EVT_MENU, self.onRemoteRemove, id=self.idREMOTEREMOVE)
self.Bind(wx.EVT_MENU, self.onRemoteChange, id=self.idREMOTECHANGE)
return remote_menu
def createHelpMenu(self):
"""Create the help menu."""
help_menu = wx.Menu()
help_menu.Append(self.idABOUT, _("&About"), _("About Ftpcube"))
self.Bind(wx.EVT_MENU, self.onAbout, id=self.idABOUT)
return help_menu
def makeToolBar(self):
"""Creates the toolbar."""
self.toolbar = self.CreateToolBar()
self.toolbar.SetToolBitmapSize(wx.Size(32, 32))
bitmap = icons.connect.getBitmap()
self.toolbar.AddSimpleTool(self.idTOOL_CONNECT, bitmap,
shortHelpString=_("Normal Connect"))
bitmap = icons.quick_connect.getBitmap()
self.toolbar.AddSimpleTool(self.idTOOL_QUICKCONNECT, bitmap,
shortHelpString=_("Quick Connect"))
bitmap = icons.disconnect.getBitmap()
self.toolbar.AddSimpleTool(self.idTOOL_DISCONNECT, bitmap,
shortHelpString=_("Disconnect"))
bitmap = icons.abort.getBitmap()
self.toolbar.AddSimpleTool(self.idTOOL_ABORT, bitmap,
shortHelpString=_("Abort Current Action"))
bitmap = icons.refresh.getBitmap()
self.toolbar.AddSimpleTool(self.idTOOL_REFRESH, bitmap,
shortHelpString=_("Refresh"))
utils.addLineSeparator(self.toolbar, 16)
bitmap = icons.bookmark.getBitmap()
self.toolbar.AddSimpleTool(self.idTOOL_BOOKMARK, bitmap,
shortHelpString=_("Bookmark"))
utils.addLineSeparator(self.toolbar, 16)
bitmap = icons.exit.getBitmap()
self.toolbar.AddSimpleTool(self.idTOOL_QUIT, bitmap,
shortHelpString=_("Quit"))
self.dir_entry_box = wx.ComboBox(self.toolbar, self.idTOOL_ENTRYBOX,
size=wx.Size(350, -1), style=wx.CB_DROPDOWN)
self.binary_button = wx.RadioButton(self.toolbar, self.idTOOL_BINARY, _("BINARY"))
self.ascii_button = wx.RadioButton(self.toolbar, self.idTOOL_ASCII, _("ASCII"))
config = utils.getApplicationConfiguration()
if config['transfer_type'] == protocol.ProtocolInterface.BINARY:
self.binary_button.SetValue(True)
else:
self.ascii_button.SetValue(True)
utils.addHorizontalSpaceTool(self.toolbar, 75)
self.toolbar.AddControl(self.dir_entry_box)
utils.addHorizontalSpaceTool(self.toolbar, 5)
self.toolbar.AddControl(self.binary_button)
utils.addHorizontalSpaceTool(self.toolbar, 5)
self.toolbar.AddControl(self.ascii_button)
self.Bind(wx.EVT_TOOL, self.onConnect, id=self.idTOOL_CONNECT)
self.Bind(wx.EVT_TOOL, self.onQuickConnect, id=self.idTOOL_QUICKCONNECT)
self.Bind(wx.EVT_TOOL, self.onDisconnect, id=self.idTOOL_DISCONNECT)
self.Bind(wx.EVT_TOOL, self.onAbort, id=self.idTOOL_ABORT)
self.Bind(wx.EVT_TOOL, self.onRefresh, id=self.idTOOL_REFRESH)
self.Bind(wx.EVT_TOOL, self.onBookmarks, id=self.idTOOL_BOOKMARK)
self.Bind(wx.EVT_TOOL, self.onQuit, id=self.idTOOL_QUIT)
self.Bind(wx.EVT_COMBOBOX, self.onComboSelect, id=self.idTOOL_ENTRYBOX)
self.Bind(wx.EVT_RADIOBUTTON, self.onBinarySelect, id=self.idTOOL_BINARY)
self.Bind(wx.EVT_RADIOBUTTON, self.onAsciiSelect, id=self.idTOOL_ASCII)
self.toolbar.Realize()
return self.toolbar
def getConsoleWindow(self):
"""Returns the console window."""
return self.consolewin
def getControlWindow(self):
"""Returns the control window."""
return self.ctrlwin
def getLocalWindow(self):
"""Returns the local window."""
return self.localwin
def getRemoteWindow(self):
"""Returns the remote window."""
return self.remotewin
def onConnect(self, event):
"""Processes a connect initiation event.
This displays the connect window. If the OK button is chosen, then a connection
is initiated."""
thread_mgr = utils.getAppThreadManager()
if thread_mgr.getMainThread():
if not self.promptDisconnect():
return
self.onDisconnect(event)
config = utils.getApplicationConfiguration()
connect = connectwin.ConnectionWindow(self, opts=config.getOptions())
ret = connect.ShowModal()
if ret == wx.ID_OK:
connect_opts = connect.getOptions()
if connect_opts['host'] and connect_opts['port'] and connect_opts['transport']:
app = utils.getApplication()
app.initiateConnection(connect_opts)
else:
messages.displayErrorDialog(self,
_("A hostname, port, and transport must be supplied."))
def onQuickConnect(self, event):
"""Processes a quick connect initiation event.
This displays a box to prompt for the host to connect to and then assumes the
remaining defaults."""
thread_mgr = utils.getAppThreadManager()
if thread_mgr.getMainThread():
if not self.promptDisconnect():
return
self.onDisconnect(event)
config = utils.getApplicationConfiguration()
opts = { }
opts.update(config.getOptions())
host = messages.displayInputDialog(self, _("Ftpcube - Quick Connect"),
_("Remote Host:"))
if host:
opts['host'] = host
app = utils.getApplication()
app.initiateConnection(opts)
def onBookmarks(self, event):
"""Processes an event to display the bookmarks window."""
bookmark = bookmarkwin.BookmarkWindow(self)
bookmark.Show(True)
def promptDisconnect(self):
"""Prompts the user to disconnect from the current established connection."""
thread_mgr = utils.getAppThreadManager()
thread = thread_mgr.getMainThread()
ret = messages.displayMessageDialog(self, _("Ftpcube - Disconnect"),
_("You are currently connected to: %(host)s.\nDo you wish to disconnect and connect to a new host?")
%{ 'host' : thread.getOptions()['host'] }, wx.YES_NO)
if ret == wx.ID_YES:
return True
return False
def onDisconnect(self, event):
"""Disconnects the current connection."""
thread_mgr = utils.getAppThreadManager()
main_thread = thread_mgr.getMainThread()
if main_thread:
main_thread.setDone()
# Clear remote status stuff
self.remotewin.clearCache()
self.remotewin.clearList()
self.dir_entry_box.Remove(0, self.dir_entry_box.GetLastPosition())
def onClearConsole(self, event):
"""Clears the contents of the console window."""
self.consolewin.onClear(event)
def onOptions(self, event):
"""Displays the options window.
If OK is pressed in the options window, then the configuration is updated and
saved to disk."""
config = utils.getApplicationConfiguration()
config_opts = config.getOptions()
options = optionwin.OptionWindow(self, opts=config_opts)
ret = options.ShowModal()
if ret == wx.ID_OK:
newopts = options.getOptions()
config_opts.update(newopts)
config.save()
def onLocalUpload(self, event):
"""Processes a local upload event."""
self.localwin.onUpload(event)
def onLocalRename(self, event):
"""Processes a local rename event."""
self.localwin.onRename(event)
def onLocalDelete(self, event):
"""Processes a local delete event."""
self.localwin.onDelete(event)
def onLocalCreate(self, event):
"""Processes a local create directory event."""
self.localwin.onCreate(event)
def onLocalChmod(self, event):
"""Processes a local change permissions event."""
self.localwin.onChmod(event)
def onLocalChange(self, event):
"""Processes a local change directory event."""
self.localwin.onChange(event)
def onRemoteDownload(self, event):
"""Processes a remote download event."""
self.remotewin.onDownload(event)
def onRemoteRename(self, event):
"""Processes a remote rename event."""
self.remotewin.onRename(event)
def onRemoteDelete(self, event):
"""Processes a remote delete event."""
self.remotewin.onDelete(event)
def onRemoteCreate(self, event):
"""Processes a remote directory create event."""
self.remotewin.onCreate(event)
def onRemoteChmod(self, event):
"""Processes a remote file permissions change."""
self.remotewin.onChmod(event)
def onRemoteRemove(self, event):
"""Processes a remote directory removal event."""
self.remotewin.onRemove(event)
def onRemoteChange(self, event):
"""Processes a remote directory change event."""
self.remotewin.onChange(event)
def onAbout(self, event):
"""Displays the about window box."""
about = aboutwin.AboutWindow(self)
ret = about.ShowModal()
def onAbort(self, event):
"""Aborts the current executing action."""
thread_mgr = utils.getAppThreadManager()
main_thread = thread_mgr.getMainThread()
if main_thread:
main_thread.abort()
def onRefresh(self, event):
"""Performs a refresh on the remote directory if a connection exists.
This applies only if the main thread exists, which signifies that a browsing
connection has been established."""
thread_mgr = utils.getAppThreadManager()
main_thread = thread_mgr.getMainThread()
if main_thread:
self.remotewin.onRefresh(event)
self.localwin.onRefresh(event)
def onBinarySelect(self, event):
"""Processes the selection of binary transfers."""
if __debug__:
print "Using binary mode for transfers."
config = utils.getApplicationConfiguration()
config['transfer_type'] = protocol.ProtocolInterface.BINARY
def onAsciiSelect(self, event):
"""Processes the selection of ascii transfers."""
if __debug__:
print "Using ASCII mode for transfers."
config = utils.getApplicationConfiguration()
config['transfer_type'] = protocol.ProtocolInterface.ASCII
def onDirectoryChange(self, event):
"""Processes a directory change event.
This updates the directory entry box's history."""
found = self.dir_entry_box.FindString(event.directory)
if found == -1:
if __debug__:
print "Adding [%s] to main window combo box." %event.directory
self.dir_entry_box.Append(event.directory)
self.dir_entry_box.SetSelection(self.dir_entry_box.GetCount() - 1)
else:
if __debug__:
print "Changing combo box directory selection: [%s]" %event.directory
self.dir_entry_box.SetSelection(found)
def onComboSelect(self, event):
"""Processes the selection of a new directory within the combo box."""
dir = self.dir_entry_box.GetString(event.GetSelection())
self.remotewin.changeDirectory(dir, self.remotewin.getDir())
def onQuit(self, event):
"""Exits the application."""
config = utils.getApplicationConfiguration()
config['win_size'] = self.GetSizeTuple()
config.save()
self.Destroy()
|