#!/usr/local/bin/pythono """ Special PoserPython edition of Poser Compressor script. This will not run fully in Python 2.4/Tk 8.4. There seems to have been some change in the way tuples and strings are handled, somehow. It runs on P5 PoserPython, however. Differences between this and Python 2.4 version: - This uses string, rather than tuple, handling for reassignment of the listbox contents in handleGo. (Thanks to Tromnek for pointing me to that.) - This uses askopenfilename for single file browsing, rather than the more flexible askopenfilenames. PoserPython's version of the TkFileDialog.py does not include askopenfilenames. Kind of a bummer. :( - Changed the handling of string.lstrip for the add box entries, to remove the chars option. - Turned off printed progress report when single files are being processed. Not sure why, but the PoserPython console window kept fighting with the widget for focus. To alter this, look for the print lines in compressFile and uncompressFile which are under the "if recurse ==1:" conditional. This should hypothetically run in native Python if you are using Python version 2.2. Or so I am told.... I haven't tested it. This script is an adaptation of the compression and decompression scripts which shipped with Poser 5. I have made use of Tromnek's altered version of the Poser 5 compression script, which can be found in the archives at the Renderosity Python forum. Other people have done the hard work (and the more effective coding, I'm sure). I have tried to implement the compression functions in ways that are more flexible and easier to use. Mainly that means I slapped a GUI on it. :) I have tried to annotate my changes to the scipts from which this is derived. You should assume that any errors are mine, not those of Tromnek or the original programmer of the script. I seem to understand enough to make it work, but not necessarily enough to have been careful and deliberate - or artful - about it. This script allows you to browse for single files or entire folders to process using PoserPython's Gzip compression. You can also select an option to process all subfolders, as with the default Poser 5 scripts. This script also allows control over the file types which will be processed, without the need to edit the script to change the file tables. Run the program and press "Help" to get basic instructions. This is untested on Macintosh. I have put code in place to update the Mac typeTables when new types are added by the user, but I can't test this to see if I've made the right assumptions about the needs of the Macintosh. I assume, here, that the typeTables don't need to be cleared at all, because they are accessed to subprocess the information, rather than being accessed in the basic processing of the files. So I add to the tables, but never clear them. My apologies if I've guessed incorrectly about the process. This program is set up to automatically close when a recursive search is completed. The original scripts did the same thing. I would prefer to let the program keep running, but something in os.walk seems to alter the value of initialdir. As a result, folder browsing after recursion always starts at C:, rather than the current working directory. I can't seem to alter that. Rather than risk having a cancelled folder browse send the program tearing through the whole C: drive, if I've made any as-yet-unnoticed errors in the coding, I removed the option to do further folder browsing after a recursive search is done. If anyone knows how to fix this, feel free to do so. And I'd love to know what you did. Once again, thanks to Tromnek. Cagedrei@aol.com """ # From Tromnek's edit. #------------------------------------------------------------------------------- # # CompressPoserFiles.py # Recursively Z-lib compresses all Poser-related files in the desired # directory. Optionally deletes original uncompressed files to save # disk space. # #------------------------------------------------------------------------------- # Modified 3/6/2005, # Kenneth R. Mort (aka TromNek, http://www.renderosity.com/members.ez) # changes: # compressFile() # File extension check made case insensitive, test that it was found at the end of the filename. # Store the original file name in the compressed file header. # Before deleting original file, check that the file size matches the size stored in the compressed file. # visit() # File extension check made case insensitive, test that it was found at the end of the filename. # main # NOTE: This has only been tested on Windows. Someone please check the logic for the Mac. # Enable running in both Poser and native Python. # Check path for 'Runtime', if found have compressed pathname header start there. # Make sure that the drive letter is not stored in the compressed pathname header. #------------------------------------------------------------------------------- from Tkinter import * import sys import tkFileDialog import gzip import string import os import tkMessageBox chunksize = 4096 fileToCompress = 0 fileToUncompress = 0 deleteOriginals = 0 onameC = 0 onameU = 0 proceed = 0 message = "." names = "NONE" dirname = "NONE" AddTo = " " AddTo2 = " " addElem = " " root = Tk() #-------------------------------------------------------------------------------- # Suffixes. #-------------------------------------------------------------------------------- suffixTableC = { '.pz3' : '.pzz', '.pz2' : '.p2z', '.cr2' : '.crz', '.cm2' : '.cmz', '.lt2' : '.ltz', '.hd2' : '.hdz', '.hr2' : '.hrz', '.pp2' : '.ppz', '.mt5' : '.mz5', '.fc2' : '.fcz' } suffixTableU = { '.pzz' : '.pz3', '.p2z' : '.pz2', '.crz' : '.cr2', '.cmz' : '.cm2', '.ltz' : '.lt2', '.hdz' : '.hd2', '.hrz' : '.hr2', '.ppz' : '.pp2', '.mz5' : '.mt5', '.fcz' : '.fc2' } openListC = '*.pz3 *.pz2 *.cr2 *.cm2 *.lt2 *.hd2 *.hr2 *.pp2 *.mt5 *.fc2' openListU = '*.pzz *.p2z *.crz *.cmz *.ltz *.hdz *.ppz *.mz5 *.fcz' #-------------------------------------------------------------------------------- # Figure out which OS we're running #-------------------------------------------------------------------------------- macver = 0 winver = 0 if(os.name == 'mac'): macver = 1 separator = ':' elif(os.name == 'dos' or os.name == 'nt'): winver = 1 separator = '\\' else: raise 'unrecognized operating system\n' if(macver): #---------------------------------------------------------------------------- # Keep a table for type #---------------------------------------------------------------------------- typeTableC = { '.pzz' : 'PZZ ', '.p2z' : 'pz2Z', #Cage: I'm unable to test it, but I'm '.crz' : 'cr2Z', #assuming that the Mac tables don't need to be '.cmz' : 'cm2Z', #cleared and re-filled along with the others. '.ltz' : 'lt2Z', #New values need to be added for user-entered '.hdz' : 'hd2Z', ##file extensions. That takes place in the '.hrz' : 'fc2Z', #MyDialog class at the bottom of the script. '.ppz' : 'pp2Z', '.mz5' : 'mt5Z', '.fcz' : 'fc2Z', } typeTableU = { '.pz3':'PZ3 ', '.pz2':'pz2 ', '.cr2':'cr2 ', '.cm2':'cm2 ', '.lt2':'lt2 ', '.hd2':'hd2 ', '.hr2':'fc2 ', #Is this an error? It's consistent in both lists.... '.pp2':'pp2 ', '.mt5':'mt5 ', '.fc2':'fc2 ' } #----------------------------------------------------------------------------------------- def compressFile(fileToCompress, suffix, newSuffix, deleteOriginals): #P5 and Tromnek #if(string.find(fileToCompress, 'Default Guy.cr2') != -1): if(string.find(string.lower(fileToCompress), 'default guy.cr2') != -1): #TromNek case insensitive test return 0 newFileName = fileToCompress #extIndex = string.find(fileToCompress, suffix) extIndex = string.rfind(string.lower(fileToCompress), suffix) #TromNek, a more exact file extension search #if (extIndex == -1): if ( (extIndex + len(suffix)) != len(fileToCompress)): #TromNek, is it really the extension return -1 else: newFileName = newFileName[:extIndex] + newSuffix # change .*z3 to .*zz try: pz3 = open(fileToCompress, 'rb') except: return -2 try: #TromNek open a file object first pzzfo = open(newFileName, 'w+b') pzzfo.truncate(0) except: return -2 #pzz = gzip.GzipFile(newFileName, 'wb') pzz = gzip.GzipFile(fileobj=pzzfo, mode='wb') #TromNek pass gzip the file object instead of the name while 1: chunk = pz3.read(chunksize) # do the compression if(chunk == ""): break pzz.write(chunk) pz3.close() pzz.close() #TromNek next 13 lines hdrNameOffset = 10 # If there's a file name, where is is pzzfo.seek(hdrNameOffset + extIndex,0) # Seek the beginning of the file extension chunk = pzzfo.read( len(suffix) ) if chunk == newSuffix: # Make extra sure we want to do this pzzfo.seek(hdrNameOffset + extIndex,0) # Seek the beginning of the file extension, again pzzfo.write( suffix ) else: print "!!! Couldn't find file extension in header !!!" import struct pzzfo.seek( -4, 2 ) # original file size stored by GzipFile origfsize = struct.unpack("', newFileName if(deleteOriginals == 1): import os if os.stat(fileToCompress)[6] != origfsize: #TromNek minimum sanity check before deletion print '!!!Original file size does not equal value stored in gzip file!!! NOT DELETING ORIGINAL !!! ', os.stat(fileToCompress)[6], " != ",origfsize else: try: os.remove(fileToCompress) if recurse == 1: print ' (', fileToCompress, 'deleted)' except: print ' (Could not delete', fileToCompress print ' Permissions set to Read-Only?' #------------------------------------------------------------------------------------------------------ def uncompressFile(fileToUnCompress, suffix, newSuffix, deleteOriginals): #P5 and Tromnek if(string.find(fileToUnCompress, 'Default Guy.cr2') != -1): #if(string.find(string.lower(fileToCompress), 'default guy.cr2') != -1): #TromNek case insensitive test return 0 newFileName = fileToUnCompress extIndex = string.find(fileToUnCompress, suffix) #extIndex = string.rfind(string.lower(fileToCompress), suffix) #TromNek, a more exact file extension search if (extIndex == -1): #if ( (extIndex + len(suffix)) != len(fileToCompress)): #TromNek, is it really the extension return -1 else: newFileName = newFileName[:extIndex] + newSuffix # change .*z3 to .*zz try: pzz = gzip.GzipFile(fileToUnCompress, 'rb') except: return -2 pz3 = open(newFileName, 'wb') while 1: chunk = pzz.read(chunksize) # do the uncompression if(chunk == ""): break pz3.write(chunk) pz3.close() pzz.close() if(macver): # for mac version, we need to change file's import macfs # type and creator fs = macfs.FSSpec(newFileName) fs.SetCreatorType('PZ3A', typeTable[newSuffix]) if recurse == 1: print ' *** ', fileToUnCompress, ' ***' print ' -->', newFileName if(deleteOriginals == 1): import os try: os.remove(fileToUnCompress) if recurse == 1: print ' (', fileToUnCompress, 'deleted)' except: print ' (Could not delete', fileToUnCompress print ' Permissions set to Read-Only?' #------------------------------------------------------------------------------------------------ def visitC(something, dirname, names): #P5, Tromnek, and "but it's my only line!" if (recursive == 1): if fileToUncompress == 0: print 'Looking under directory:', dirname, '------' for name in names: for key in suffixTableC.keys(): #if (string.find(name, key) != -1): extIndex = string.rfind(string.lower(name), key ) #TromNek make sure it really is the extension. if ( (extIndex + len(key)) == len(name)): compressFile(dirname + separator + name, key, suffixTableC[key], deleteOriginals) break print from Tkinter import * #------------------------------------------------------------------------------------------ def visitU(something, dirname, names): #P5 and Tromnek w/ one line added by Cage if (recursive == 1): if fileToCompress == 0: print 'Looking under directory:', dirname, '------' for name in names: for key in suffixTableU.keys(): #if (string.find(name, key) != -1): extIndex = string.rfind(string.lower(name), key ) #TromNek make sure it really is the extension. if ( (extIndex + len(key)) == len(name)): uncompressFile(dirname + separator + name, key, suffixTableU[key], deleteOriginals) break print from Tkinter import * #----------------------------------------------------------------------------------------------- #Ockham likes to point out that this part is Tkinter, so: this part is Tkinter. Except for the middle. Well, some. A bit. class App: def __init__(self, master, textMessage): global recurse, recursive, deleteOriginals, custUse recurse = IntVar() recurse.set(0) recursive = IntVar() recursive.set(0) custUse = IntVar() custUse.set(0) self.safety = 1 #To prevent "custom file list" checkbutton from looping at start self.refresh = 0 #To enable refresh of custom file tables when open button is pressed self.master = master master.title("Poser Compressor") self.ButtonFrame = Frame(self.master,borderwidth=2,relief=RIDGE) self.ButtonFrame.grid(row=0,column=2) self.ListFrame = Frame(self.master,borderwidth=2,relief=RIDGE) self.ListFrame.grid(row = 0, column = 0) self.Label = Label(self.ListFrame,text="File Types:").grid(row=1, column=1) #Listbox self.ListScroll = Scrollbar(self.ListFrame, orient=VERTICAL) self.ListScroll.grid( row=2, column=0,sticky=N+S+E) self.List = Listbox(self.ListFrame, height=20, width=10,selectmode=MULTIPLE,yscrollcommand = self.ListScroll.set) self.List.grid( row=2, column=1) self.ListScroll["command"] = self.List.yview TypeList = dict.items(suffixTableC) #Fill the listbox from the compress table for i in TypeList: self.List.insert(END,i) #Buttons self.Label = Label(self.ButtonFrame,text="Browse For Files:").grid(row=0, column=0) self.Label = Label(self.ButtonFrame,text="Browse for one or more files,").grid(row=2,column=0) self.Label = Label(self.ButtonFrame,text="or select checkbuttons to process").grid(row=3,column=0) self.Label = Label(self.ButtonFrame,text="entire folders and subfolders.").grid(row=4,column=0) self.buttonCompress = Button(self.ButtonFrame, text="Compress", command=self.openfileC) self.buttonCompress.grid(row = 10, column = 0) self.buttonUncompress = Button(self.ButtonFrame, text="Uncompress", command=self.openfileU) self.buttonUncompress.grid(row = 20, column = 0) self.buttonAddFile = Button(self.ButtonFrame, text="Add File Type", command=self.AddFile) self.buttonAddFile.grid(row = 30, column = 0) self.buttonClose = Button(self.ButtonFrame, text="Close", command=self.die) self.buttonClose.grid(row = 70, column = 0) self.buttonHelp = Button(self.ButtonFrame, text="Help", command=self.HelpMe) self.buttonHelp.grid(row=60, column=0) self.List.bind("",self.handleSelect) #Checkboxes self.deleteOrig = Checkbutton(self.ButtonFrame,text="Delete original files after compressing", variable=deleteOriginals, command=self.delFiles) self.deleteOrig.grid(row = 35, column = 0) self.EntireFolder = Checkbutton(self.ButtonFrame,text="Process Entire Folder", variable=recurse, command=self.openfileR) self.EntireFolder.grid(row = 40, column = 0) self.Subfolders = Checkbutton(self.ButtonFrame, text="Include Subfolders", variable=recursive, command=self.openfileS) self.Subfolders.grid(row=45, column = 0) self.UseCustom = Checkbutton(self.ButtonFrame,text="Use Only Selected File Types", variable=custUse, command=self.handleCustom) self.UseCustom.grid(row=50, column = 0) self.Label = Label(self.master,text="Double-click to remove file types").grid(row = 2, column = 0) #--------------------------------------------------------------------------------------------------- self.openfileR() #Priming the system to fend off IntVar value problems self.openfileS() #Emulate first clicks of checkbuttons self.handleCustom() #Okay, so it's a kludgy workaround.... def handleSelect(self,event): self.List.delete(ACTIVE) #Delete listbox entries w/ double-click def HelpMe(self): tkMessageBox.showinfo("Instructions:","-->Browse for single files by pressing 'Compress' or 'Uncompress'.\012" "-->Browse for a folder by selecting 'Process Entire Folder' before pressing 'Compress'\012" " or 'Uncompress'.\012" "-->Select 'Include Subfolders' together with 'Process Entire Folder' to include all subfolders.\012" "-->Toggle 'Delete Original Files After Compressing' to delete or retain originals.\012" "-->Highlight file types in the 'File Types' list and select 'Use Only Selected File Types' to\012" " specify file types to compress or uncompress.\012" "-->Press 'Add File Type' to add a custom file type to the list.\012" "-->Double click on a file type to remove it from the list.\012" "\012" "-->Special thanks to Tromnek, whose edited Python scripts are implemented herein.\012" "NOTE: This program will automatically close after a recursive search of subfolders has\012" "been completed.") def handleGo(self): #handleGo converts listbox info to file table info global openListC, openListU q = " " p = " " Selecteds = self.List.curselection() #You can see, here, that I have been learning from Ockham's code.... NumSel = len(Selecteds) #Hopefully you can't copyright variable names.... :) if NumSel != 0: #Prevent default file tables from being deleted if no list selection for i in Selecteds: Name = self.List.get(i) q,p = string.split(Name) #PoserPython handling. Thanks, Tromnek. suffixTableC[q] = p #Re-fill the suffix tables suffixTableU[p] = q openListC = (openListC + " " + "*" + q) #Re-fill the file open lists openListU = (openListU + " " + "*" + p) def die(self): self.master.destroy() self.master.quit() def handleCustom(self): #handleCustom handles user interaction w/ listbox global custUse, openListC, openListU, backupC, backupU, openCback, openUback if self.refresh == 0: if custUse ==0: custUse = 1 else: custUse = 0 if self.refresh == 1: self.refresh = 0 if (custUse == 0) and (self.safety ==0): #When custom file types checkbox is unchecked dict.clear(suffixTableC) suffixTableC.update(backupC) #Restore old file tables from backup dict.clear(suffixTableU) suffixTableU.update(backupU) openListC = openCback #Restore old file open lists from backup openListU = openUback if custUse == 1: NumSel = 0 if self.safety == 1: backupC = dict.copy(suffixTableC) #Back up original file tables only at start backupU = dict.copy(suffixTableU) openCback = openListC openUback = openListU Selecteds = self.List.curselection() NumSel = len(Selecteds) #Don't empty the file tables when there's nothing selected to replace them. if NumSel != 0: dict.clear(suffixTableC) #Empty the file tables each time dict.clear(suffixTableU) openListC = " " #Clear the open file lists each time openListU = " " self.safety = 0 #A switch to prevent zero looping and to create backups only at start self.handleGo() def openfileR(self): #Switch for "entire folder" handling. Bad variable name. global recurse if recurse == 0: recurse = 1 else: recurse = 0 def openfileS(self): #Switch for recursive folder handling. global recursive if recursive == 0: recursive = 1 else: recursive = 0 def delFiles(self): #Switch for file delete option. global deleteOriginals if deleteOriginals == 0: deleteOriginals = 1 else: deleteOriginals = 0 def AddFile(self): #Part 1 of Addfile box function. global AddTo, root #Part 2 is a separate Class, below. d = self.MyDialog(root,AddTo) root.wait_window(d.top) self.boxAdd(addElem) def boxAdd(self,addElem): #Part 3 of Addfile box. global AddTo addElem = AddTo AddTo = " " if addElem != " ": self.List.insert(END,addElem) #------------------------------------------------------------------------------------- def openfileC(self): #Compression operations. This is my part. global message, names, dirname, listed, recurse, recursive, custUse onameC = " " if custUse == 1: #This updates custom file lists self.refresh = 1 self.handleCustom() proceed = 0 if recurse == 0: onameC = tkFileDialog.askopenfilename(filetypes=[("All Associated Files", openListC)]) if recurse == 1: message = tkFileDialog.askdirectory() if (message == "") or (message == "."): message = "NONE" #Keeping a dummy control value for cancel if message != "NONE": dirname = message names = os.listdir(message) onameC = names if onameC != " ": proceed = 1 fileToCompress = onameC #---------------------------------------------------------------------------------------------- if recurse == 0: #This part is P5 original, lightly edited. for key in suffixTableC.keys(): if (string.find(fileToCompress, key) != -1): compressFile(fileToCompress, key, suffixTableC[key], deleteOriginals) break exit #--------------------------------------------------------------------------------------------------- elif (recurse ==1) and (recursive ==1): #Mostly P5 original, as altered by Tromnek if message == "NONE": #Beginning, middle, and end lightly altered by Cage proceed = 0 i = 0 for key in suffixTableC.keys(): if (i==0): message = message + key else: message = message + ', ' + key i = i + 1 try: #TromNek this allows us to run the script outside of poser initDir = poser.AppLocation() # <-this line was in the original script except: initDir = os.getcwd() # we must be running in native python fileIndex = string.rfind(initDir, separator) initDir = initDir[:fileIndex] dirToCompress = dirname #(proceed, dirToCompress, deleteOriginals) = message if proceed == 0: #Cage changed this to prevent errors w/ browse for directory being cancelled. message = "." dirname = "NONE" names = "NONE" exit #raise 'Script cancelled' print 'Recursing from ', dirToCompress, '\n\n' arg = None #TromNek next 15 lines reldir = separator+'Runtime'+separator # get path starting with first 'Runtime' folder #reldir = '' # or not dirToCompress = os.path.normpath( dirToCompress ) begpth = string.find( string.lower(dirToCompress+separator), string.lower(reldir) ) if (begpth < 1): begpth = 0 if ((winver==1) and (dirToCompress[1]==':')): begpth = 2 while (begpth < len(dirToCompress)) and (dirToCompress[begpth] == separator): begpth = begpth+1 # skip over path separators to get to the path if begpth > 0: os.chdir( dirToCompress[:begpth] ) # change to drive and initial folder of dirToCompress dirToCompress = dirToCompress[begpth:] # strip 'driveletter:\' and initial folder from dirToCompress os.path.walk(dirToCompress, visitC, arg) print "Compression complete" if dirname != "NONE": #This last bit added by Cage. self.die() #Because the initial directory is replaced by the root directory after the walk, #kill the process after a successful recursion to prevent errors. The original #script automatically ended the program after recursion, as well. message = "." dirname = "NONE" names = "NONE" proceed = 0 #----------------------------------------------------------------------------------------------- elif (recurse == 1) and (recursive==0): #P5 and Tromnek. print 'Looking under directory:', dirname, '------' for name in names: for key in suffixTableC.keys(): #if (string.find(name, key) != -1): extIndex = string.rfind(string.lower(name), key ) #TromNek make sure it really is the extension. if ( (extIndex + len(key)) == len(name)): compressFile(dirname + separator + name, key, suffixTableC[key], deleteOriginals) break print "Compress, Folders, No Recursion, Done" #------------------------------------------------------------------------------------------------- def openfileU(self): #Uncompression functions. This is my part. global recurse, message, names, dirname, recursive, custUse onameU = " " if custUse == 1: self.refresh = 1 self.handleCustom() proceed = 0 if recurse == 0: onameU = tkFileDialog.askopenfilename(filetypes=[("All Associated Files", openListU)]) if recurse == 1: message = tkFileDialog.askdirectory() if (message == "") or (message == "."): message = "NONE" #Keeping a dummy control value for cancel if message != "NONE": dirname = message names = os.listdir(message) onameU = names if onameU != " ": proceed = 1 fileToUncompress = onameU #--------------------------------------------------------------------------------------- if recurse == 0: #P5 original w/ minor alterations. for key in suffixTableU.keys(): if (string.find(fileToUncompress, key) != -1): uncompressFile(fileToUncompress, key, suffixTableU[key], deleteOriginals) break exit #----------------------------------------------------------------------------------------- elif (recurse ==1) and (recursive ==1) and (dirname != 0): #P5 and Tromnek. i = 0 for key in suffixTableU.keys(): if (i==0): message = message + key else: message = message + ', ' + key i = i + 1 try: #TromNek this allows us to run the script outside of poser initDir = poser.AppLocation() # <-this line was in the original script except: initDir = os.getcwd() # we must be running in native python #initDir = poser.AppLocation() fileIndex = string.rfind(initDir, separator) initDir = initDir[:fileIndex] dirToUnCompress = dirname #(proceed, dirToUnCompress, deleteOriginals) = dialog(message, initDir) if proceed == 0: #Cage changed this to prevent errors w/ browse for directory being cancelled. message = "." dirname = "NONE" names = "NONE" exit #raise 'Script cancelled' print 'Recursing from ', dirToUnCompress, '\n\n' arg = None os.path.walk(dirToUnCompress, visitU, arg) print "Uncompression complete" if dirname != "NONE": #This last bit added by Cage. self.die() #Because the initial directory is replaced by the root directory after the walk, #kill the process after a successful recursion to prevent errors. The original #script automatically ended the program, as well. message = "." dirname = "NONE" names = "NONE" proceed = 0 #----------------------------------------------------------------------------------------- elif (recurse == 1) and (recursive == 0): #P5 and Tromnek. print 'Looking under directory:', dirname, '------' for name in names: for key in suffixTableU.keys(): #if (string.find(name, key) != -1): extIndex = string.rfind(string.lower(name), key ) #TromNek make sure it really is the extension. if ( (extIndex + len(key)) == len(name)): uncompressFile(dirname + separator + name, key, suffixTableU[key], deleteOriginals) break print "Uncompress, Folders, No Recursion, Done" #----------------------------------------------------------------------------------------------- class MyDialog: #Part 3 of the Addfile box function. def __init__(self,parent,txt): top = self.top = Toplevel(parent) Label(top,text="Enter New Extensions").pack() Label(top,text="Including Leading Dot ('.')").pack() self.e = Entry(top) self.e.insert(0,txt) self.e.pack(padx=5) Label(top,text="uncompressed extension").pack() self.e2 =Entry(top) self.e2.insert(10,txt) self.e2.pack(padx=5) Label(top,text="compressed extension").pack() b = Button(top, text="OK", command=self.ok) b.pack(pady=5) b2 = Button(top, text="Cancel", command=self.cancel) b2.pack(pady=5) def ok(self): global AddTo, root, parent fixit = self.e.get() fixit2 = self.e2.get() fixit = string.lstrip(fixit) #Remove mysterious space at beginning of entry fixit2 = string.lstrip(fixit2) if (macver): x = " " #Assuming that existing items don't need to be removed y = " " #from the Mac tables, but new items do need to be r = " " #added. s = " " x,r = string.split(fixit,".",1) y,s = string.split(fixit2,".",1) #Strip the dots from the extensions r = r + "Z" s = s + " " typeTableC[fixit] = r #Add to the typeTables. typeTableU[fixit2] = s nAddTo = ((fixit) ,(fixit2)) #Make the tuple self.e = " " #Clear the boxes for the next entry self.e2 = " " if nAddTo and nAddTo != " ": AddTo = nAddTo nAddTo = " " self.top.destroy() if nAddTo == " ": self.top.destroy() def cancel(self): self.e = " " self.e2 = " " AddTo = " " nAddTo = " " self.top.destroy() #-------------------------------------------------------------------------------------------- app = App(root, "") root.mainloop() #--------------------------------------------------------------------------