#!/usr/local/bin/python # twander - Wander around the file system # Copyright (c) 2002 TundraWare Inc. All Rights Reserved. PROGNAME = "twander" RCSID = "$Id: twander.py,v 1.32 2002/11/09 00:31:08 tundra Exp $" VERSION = RCSID.split()[2] #----------------------------------------------------------# # Variables User Might Change # #----------------------------------------------------------# #------------------- Nothing Below Here Should Need Changing ------------------# #----------------------------------------------------------# # Imports # #----------------------------------------------------------# from Tkinter import * import getopt import os import sys #----------------------------------------------------------# # Aliases & Redefinitions # #----------------------------------------------------------# #----------------------------------------------------------# # Constants & Literals # #----------------------------------------------------------# ##### # Constants ##### FALSE = 0 == 1 # Booleans TRUE = not FALSE ##### # General Literals ##### DIR_LDELIM = '[' # Directory left dsply. delimiter DIR_RDELIM = ']' # Directory left dsply. delimiter PSEP = os.sep # Character separating path components ##### # Configuration File Related Literals ##### CONFFILE = os.path.join(os.getenv("HOME"), # Name of default config file "." + PROGNAME ) CMDKEY = r'&' # Command key delimiter COMMENT = r"#" # Comment character NAME = r'[NAME]' # Substitution field in config files ENVIRO = r'$' # Introduces environment variables #----------------------------------------------------------# # Prompts, & Application Strings # #----------------------------------------------------------# ##### # Error & Warning Messages ##### eBADROOT = " %s Is Not A Directory" eDIRRD = " Problem Reading Directory : %s" eDUPKEY = "Duplicate Key In Configuration File Found In Entry: \'%s\'" eERROR = "ERROR" eNOCONF = "Cannot Find Configuration File: %s" eNOENV = "Configuration File References Undefined Environment Variable: %s" eOPEN = "Cannot Open File: %s" eTOOMANY = "You Can Only Specify One Starting Directory." wCMDKEY = "Configuration File Entry For: \'%s\' Has No Command Key Defined." wWARN = "WARNING" ##### # Informational Messages ##### ##### # Usage Prompts ##### uTable = [PROGNAME + " " + VERSION + " - Copyright 2002, TundraWare Inc., All Rights Reserved\n", "usage: " + PROGNAME + " [-d dir] [-hv] [startdir] where,\n", " startdir name of directory in which to begin (default: current dir)", " -b color background color", " -c file name of configuration file (default: " + CONFFILE + ")", " -f color foreground color", " -h print this help information", " -n name name of font to use", " -s size size of font to use", " -v print detailed version information", " -w wght weight/style of font to use", ] ##### # Prompts ##### #----------------------------------------------------------# # Global Variables & Data Structures # #----------------------------------------------------------# #---------------------------Code Begins Here----------------------------------# #----------------------------------------------------------# # Object Base Class Definitions # #----------------------------------------------------------# #----------------------------------------------------------# # GUI Handlers & Supporting Functions # #----------------------------------------------------------# ##### # Event Handler For Directory Listing ListBox ##### def DirList_Handler(**kwargs): global rootdir selected = DirList.items[DirList._get_selection()] # If selection is a directory, move there and list contents. # We examine this by checking the string for the directory # delimiter characters previously inserted in BuildDirList() if selected[0] == DIR_LDELIM and selected[-1] == DIR_RDELIM: # Strip off delimiters to get real name selected = selected[1:-1] # Build full path name selected = os.path.join(os.path.abspath(rootdir), selected) # Convert ending ".." into canonical path if selected.endswith(".."): selected = PSEP.join(selected.split(PSEP)[:-2]) # Need to end the directory string with a path # separator character so that subsequent navigation # will work when we hit the root directory of the file # system. In the case of Unix, this means that # if we ended up at the root directory, we'll just # get "/". In the case of Win32, we will get # "DRIVE:/". selected += PSEP # Save the new root location and get its contents rootdir = selected DirList.items = BuildDirList(rootdir) # Update main window to reflect new location MainWin.set(title= PROGNAME + " " + VERSION + " " + rootdir) else: # os.system(rcfile["ls"][1].replace("[NAME]", os.path.join(rootdir, selected)) + "&") pass # End of 'DirList_Handler()' #----------------------------------------------------------# # Supporting Function Definitions # #----------------------------------------------------------# ##### # Return Ordered List Of Directories & Files For Current Root ##### def BuildDirList(rootdir): dList, fList = [], [] dList.append(DIR_LDELIM + ".." + DIR_RDELIM) # Always show one directory up try: for file in os.listdir(rootdir): if os.path.isdir(os.path.join(rootdir,file)): dList.append(DIR_LDELIM + file + DIR_RDELIM) else: fList.append(file) except: ErrMsg(eDIRRD % rootdir) dList.sort() fList.sort() return dList + fList # End 'BuildDirList()' ##### # Print An Error Message ##### def ErrMsg(emsg): print PROGNAME + " " + VERSION + " " + eERROR + ": " + emsg # End of 'ErrMsg()' ##### # Parse & Process The Configuraton File ##### def ParseRC(): try: cf = open(conf) except: ErrMsg(eOPEN % conf) sys.exit(1) # Process and massage the configuration file for line in cf.read().splitlines(): # Lex for comment token and discard until EOL # A line beginning with the comment token is thus # turned into a blank line, which is discarded. idx = line.find(COMMENT) if idx > -1: # found a comment character line = line[:idx] # Anything which gets through the next conditional # must be a non-blank line - i.e., Configuration information # we care about, so process it and save for future use. if line != "": fields = line.split() for x in range(1,len(fields)): # Process environment variables if fields[x][0] == ENVIRO: envval = os.getenv(fields[x][1:]) if not envval: # Environment variable not defined ErrMsg(eNOENV % fields[x]) sys.exit(1) else: fields[x] = envval # Get command key value and store in dictionary keypos = fields[0].find(CMDKEY) # Look for key delimiter # No delimiter or delimiter at end of string if (keypos < 0) or (CMDKEY == fields[0][-1]): WrnMsg(wCMDKEY % fields[0]) key = fields[0] # Use whole word as index # Found legit delimiter else: key = fields[0][keypos+1] # Use selected key as index if key in rcfile: # This is a Python 2.2 or later idiom ErrMsg(eDUPKEY % fields[0]) # Duplicate key found cf.close() sys.exit(1) # Save command name and command using key as index rcfile[key] = ["".join(fields[0].split(CMDKEY)), " ".join(fields[1:]) ] cf.close() # End of 'ParseRC()' ##### # Print Usage Information ##### def Usage(): for x in uTable: print x # End of 'Usage()' ##### # Print A Warning Message ##### def WrnMsg(wmsg): print PROGNAME + " " + VERSION + " " + wWARN + ": " + wmsg # End of 'WrnMsg()' #----------------------------------------------------------# # Program Entry Point # #----------------------------------------------------------# # Newline to make sure cursor of invoking window is # at LHS in case we get errors or warnings. print "" # Command line processing try: opts, args = getopt.getopt(sys.argv[1:], '-b:c:f:hn:s:vw:') except getopt.GetoptError: Usage() sys.exit(1) # Defaults # Configuration file conf = CONFFILE # Starting directory rootdir = "." + PSEP # Colors bcolor = "black" fcolor = "green" # Fonts fname = "Courier" fsz = 12 fwt = "bold" # Parse command line for opt, val in opts: if opt == "-b": bcolor = val if opt == "-c": conf = val if opt == "-f": fcolor = val if opt == "-h": Usage() sys.exit(0) if opt == "-n": fname = val if opt == "-s": fsz = val if opt == "-v": print RCSID sys.exit(0) if opt == "-w": fwt = val # Can only have 0 or 1 arguments # Make sure any starting directory argument is legit if len(args) > 1: ErrMsg(eTOOMANY) sys.exit(1) if len(args) == 1: rootdir = args[0] if not os.path.isdir(rootdir): ErrMsg(eBADROOT % rootdir) sys.exit(1) # This program requires a config file if not os.path.exists(conf): ErrMsg(eNOCONF % conf) sys.exit(1) rcfile = {} ParseRC() # Canonicalize the rootdir rootdir = os.path.abspath(rootdir) ##### # GUI Related Setup ##### UIroot = Tk() SB = Scrollbar(UIroot, orient=VERTICAL) DirList = Listbox(UIroot, foreground = fcolor, background = bcolor, font = (fname, fsz, fwt), selectmode=SINGLE, exportselection=0, yscrollcommand=SB.set) SB.config(command=DirList.yview) SB.pack(side=RIGHT, fill=Y) DirList.pack(side=LEFT, fill=BOTH, expand=1) # Initialize the UI directory listing for x in BuildDirList(rootdir): DirList.insert(END, x) # Set the window title UIroot.wm_title(PROGNAME + " " + VERSION + " " + rootdir) # Run the program interface UIroot.mainloop()