diff --git a/twander.py b/twander.py index 8ccee1b..e6cdcea 100755 --- a/twander.py +++ b/twander.py @@ -6,7 +6,7 @@ # Program Information PROGNAME = "twander" -RCSID = "$Id: twander.py,v 2.82 2003/01/28 17:37:46 tundra Exp $" +RCSID = "$Id: twander.py,v 2.83 2003/01/29 01:13:30 tundra Exp $" VERSION = RCSID.split()[2] # Copyright Information @@ -51,7 +51,9 @@ if OSNAME == 'nt': try: from win32api import GetLogicalDriveStrings as GetDrives - from win32api import GetUserName, GetFileAttributes, GetComputerName + from win32api import GetUserName, GetFileAttributes, GetComputerName, GetDiskFreeSpace, GetVolumeInformation + from win32file import GetDriveType + from win32wnet import WNetGetUniversalName import win32con from win32security import * WIN32HOST = GetComputerName() @@ -331,6 +333,28 @@ (win32con.FILE_ATTRIBUTE_READONLY, 'R'), (win32con.FILE_ATTRIBUTE_SYSTEM, 'S')) + win32all_type = ((win32con.DRIVE_CDROM, 'CD/DVD'), + (win32con.DRIVE_FIXED, 'Fixed'), + (win32con.DRIVE_RAMDISK, 'Ramdisk'), + (win32con.DRIVE_REMOTE, 'Remote'), + (win32con.DRIVE_REMOVABLE, 'Removable')) + + # Size of each of the drive detail fields, including room for trailing space. + # Since the LABEL, FREE, and TOTAL fields can be filled with the UNAVAILABLE + # string, they must be at least that long (+1 for trailing space) + + SZ_DRIVE_NAME = 4 + SZ_DRIVE_LABEL = 12 + SZ_DRIVE_FREE = 13 # In this case there is no trailing space but a trailing '/' + SZ_DRIVE_TTL = 13 # so we can have a 'free/total' presentation + SZ_DRIVE_TYPE = 20 + SZ_DRIVE_HOST = 19 # Leave room for leading '\\' - no trailing space, trailing '\' + + SZ_DRIVE_TOTAL = SZ_DRIVE_LABEL + SZ_DRIVE_FREE + SZ_DRIVE_TTL + SZ_DRIVE_TYPE + SZ_DRIVE_HOST + +# Constants used with the more usual Unix-style details +# Used both by Unix and Win32 when win32all is not present or disabled. + # Permissions ST_PERMIT = ["---", "--x", "-w-", "-wx", @@ -1264,16 +1288,9 @@ ##### def AllSelection(self): + sellist = [] - - # On Win32 Systems a Drive List View is always forced - # to display with no details. So we have to consider this - # when figuring out where the selection name begins. - - if self.CurrentDir == SHOWDRIVES: - nameindex = 0 - else: - nameindex = self.NameFirst + nameindex = self.NameFirst for entry in self.DirList.curselection(): sellist.append(self.DirList.get(entry)[nameindex:].split(SYMPTR)[0]) @@ -1289,14 +1306,9 @@ def LastInSelection(self): - # As above in AllSelection() - - if self.CurrentDir == SHOWDRIVES: - nameindex = 0 - else: - nameindex = self.NameFirst - + nameindex = self.NameFirst index = self.DirList.curselection() + if index: return self.DirList.get(index[-1])[nameindex:].split(SYMPTR)[0] else: @@ -1322,7 +1334,9 @@ if AUTOREFRESH: self.ElapsedTime += POLLINT if self.ElapsedTime >= REFRESHINT: - RefreshDirList() + # Don't autorefresh on drive list views + if UI.CurrentDir != SHOWDRIVES: + RefreshDirList() self.ElapsedTime = 0 # Setup next polling event @@ -1343,23 +1357,6 @@ else: self.DetailsOn = details - # Tell system where actual file name begins - # For both choices below, we have to set the UI.NameFirst - # value. This tells other handlers where in a given - # selection the actual name of the file can be found. - # This is necessary because we may be selecting a from - # a detailed view and need to know where in that view - # the file name lives. It is not good enough to just - # split() the selected string and use the [-1] entry because - # we may be dealing with a file which has spaces in its - # name. - - - if self.DetailsOn: - self.NameFirst = ST_SZTOTAL - else: - self.NameFirst = 0 - # End of method 'twanderUI.SetDetailedView()' @@ -2315,13 +2312,82 @@ all = dList + fList - # The user requested Drive List View. This is always displayed - # without details, so we can return directly from here. + # The user requested Drive List View. else: UI.TotalSize = 0 - return GetWin32Drives() + drivelist = GetWin32Drives() + # If details are off, just return the list of drives + if not UI.DetailsOn: + UI.NameFirst = 0 + return drivelist + + # We're returning detailed information about each drive + else: + + details = [] + + # Create a detailed entry for each drive on the system + # Store it as a string in the details list which will + # then be returned to the caller + + for drive in drivelist: + + # Type Of Drive - We need this now to get hostname + drivetype = GetDriveType(drive) + typestring = '' + + for type, stype in win32all_type: + if drivetype == type: + typestring = stype + + # Starts with hostname in Microsoft naming format + entry = '\\\\' + + # Machine Hosting The Drive + if typestring == win32con.DRIVE_REMOTE: + name = WNetGetUniversalName(drive, 1).split('\\')[2].capitalize() + else: + name = WIN32HOST.capitalize() + + entry += name + "\\" + + # Drive Label - Drive Might Not Be Available + try: + label = GetVolumeInformation(drive)[0] + except: + label = UNAVAILABLE + + entry += label + " " * ((SZ_DRIVE_HOST + SZ_DRIVE_LABEL) - len(entry + label)) + + # Add the drive type + entry += typestring + " " * (SZ_DRIVE_TYPE - len(typestring)) + + # Get Drive Space Information - Drive Might Not Be Available + try: + clustersz, sectorsz, freeclusters, totalclusters = GetDiskFreeSpace(drive) + + # Free Space + freespace = FileLength(clustersz * sectorsz * freeclusters) + + # Total Space + totalspace = FileLength(clustersz * sectorsz * totalclusters) + except: + freespace, totalspace = ('0', '0') + + sizes = "%s/%s" % (freespace, totalspace) + entry += sizes + " " * ((SZ_DRIVE_FREE + SZ_DRIVE_TTL) - len(sizes)) + + # Finally, tack on the drive name + entry += drive + + # Save final result in detailed list + details.append(entry) + + UI.NameFirst = SZ_DRIVE_TOTAL + return details + # Get details on directory contents detlist = [] @@ -2352,7 +2418,6 @@ # Do Win32-specific mode if win32all is loaded if WIN32ALL and USEWIN32ALL and WIN32ALLON: - modlen = len(win32all_mode) try: @@ -2517,8 +2582,10 @@ detlist[index] += SYMPTR + f if UI.DetailsOn: + UI.NameFirst = ST_SZTOTAL return detlist else: + UI.NameFirst = 0 return dList + fList # End of 'BuildDirList()'