""" Settings is a collection of utilities to display, read & write the settings and position widgets. """ from __future__ import absolute_import #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module. import __init__ from skeinforge_tools.skeinforge_utilities import euclidean from skeinforge_tools.skeinforge_utilities import gcodec import cStringIO import os import shutil import webbrowser try: import Tkinter except: print( 'You do not have Tkinter, which is needed for the graphical interface, you will only be able to use the command line.' ) print( 'Information on how to download Tkinter is at:\nwww.tcl.tk/software/tcltk/' ) __author__ = "Enrique Perez (perez_enrique@yahoo.com)" __date__ = "$Date: 2008/23/04 $" __license__ = "GPL 3.0" globalRepositoryDialogListTable = {} globalProfileSaveListenerListTable = {} globalCloseListTables = [ globalRepositoryDialogListTable, globalProfileSaveListenerListTable ] globalSpreadsheetSeparator = '\t' def addAcceleratorCommand( acceleratorBinding, commandFunction, master, menu, text ): "Add accelerator command." acceleratorText = acceleratorBinding[ 1 : - 1 ] lastIndexOfMinus = acceleratorText.rfind( '-' ) if lastIndexOfMinus > - 1: acceleratorText = acceleratorText[ : lastIndexOfMinus + 1 ] + acceleratorText[ lastIndexOfMinus + 1 : ].capitalize() acceleratorText = acceleratorText.replace( 'KeyPress-', '' ) acceleratorText = acceleratorText.replace( '-', '+' ) acceleratorText = acceleratorText.replace( 'Control', 'Ctrl' ) acceleratorBinding = acceleratorBinding.replace( 'KeyPress', '' ) menu.add_command( accelerator = acceleratorText, label = text, underline = 0, command = commandFunction ) master.bind( acceleratorBinding, commandFunction ) def addElementToListTableIfNotThere( element, key, listTable ): "Add the value to the lists." if key in listTable: elements = listTable[ key ] if element not in elements: elements.append( element ) else: listTable[ key ] = [ element ] def addEmptyRow( gridPosition ): "Add an empty row." gridPosition.increment() Tkinter.Label( gridPosition.master ).grid( row = gridPosition.row, column = gridPosition.column ) def addListsSetCraftProfileArchive( craftSequence, defaultProfile, repository, fileNameHelp ): "Set the craft profile archive." addListsToRepository( fileNameHelp, '', repository ) repository.craftSequenceLabel = LabelDisplay().getFromName( 'Craft Sequence: ', repository ) craftToolStrings = [] for craftTool in craftSequence[ : - 1 ]: craftToolStrings.append( getEachWordCapitalized( craftTool ) + '->' ) craftToolStrings.append( getEachWordCapitalized( craftSequence[ - 1 ] ) ) for craftToolStringIndex in xrange( 0, len( craftToolStrings ), 5 ): craftLine = ' '.join( craftToolStrings[ craftToolStringIndex : craftToolStringIndex + 5 ] ) LabelDisplay().getFromName( craftLine, repository ) LabelDisplay().getFromName( '', repository ) repository.profileList = ProfileList().getFromName( 'Profile List:', repository ) repository.profileListbox = ProfileListboxSetting().getFromListSetting( repository.profileList, 'Profile Selection:', repository, defaultProfile ) repository.addListboxSelection = AddProfile().getFromProfileListboxSettingRepository( repository.profileListbox, repository ) repository.deleteListboxSelection = DeleteProfile().getFromProfileListboxSettingRepository( repository.profileListbox, repository ) directoryName = getProfilesDirectoryPath() makeDirectory( directoryName ) repository.windowPosition.value = '0+400' def addListsToRepository( fileNameHelp, profileDirectory, repository ): "Add the value to the lists." repository.archive = [] repository.displayEntities = [] repository.executeTitle = None repository.fileNameHelp = fileNameHelp repository.fileNameInput = None repository.lowerName = fileNameHelp.split( '.' )[ - 2 ] repository.baseName = os.path.join( profileDirectory, repository.lowerName + '.csv' ) repository.capitalizedName = getEachWordCapitalized( repository.lowerName ) repository.openLocalHelpPage = HelpPage().getOpenFromDocumentationSubName( repository.fileNameHelp ) repository.openWikiManualHelpPage = None repository.repositoryDialog = None repository.saveListenerTable = {} repository.title = repository.capitalizedName + ' Settings' repository.menuEntities = [] repository.saveCloseTitle = 'Save and Close' repository.windowPosition = WindowPosition().getFromValue( repository, '0+0' ) WindowVisibilities().getFromRepository( repository ) for setting in repository.archive: setting.repository = repository def addMenuEntitiesToMenu( menu, menuEntities ): "Add the menu entities to the menu." for menuEntity in menuEntities: menuEntity.addToMenu( menu ) def addMenuEntitiesToMenuFrameable( menu, menuEntities ): "Add the menu entities to the menu." for menuEntity in menuEntities: menuEntity.addToMenuFrameable( menu ) def addPluginsParentToMenu( directoryPath, menu, parentPath, pluginFileNames ): "Add plugins and the parent to the menu." ToolDialog().addPluginToMenu( menu, parentPath[ : parentPath.rfind( '.' ) ] ) menu.add_separator() addPluginsToMenu( directoryPath, menu, pluginFileNames ) def addPluginsToMenu( directoryPath, menu, pluginFileNames ): "Add plugins to the menu." for pluginFileName in pluginFileNames: ToolDialog().addPluginToMenu( menu, os.path.join( directoryPath, pluginFileName ) ) def cancelRepository( repository ): "Read the repository then set all the entities to the read archive values." getReadRepository( repository ) for setting in repository.displayEntities: if setting in repository.archive: setting.setStateToValue() def deleteDirectory( directory, subfolderName ): "Delete the directory if it exists." subDirectory = os.path.join( directory, subfolderName ) if os.path.isdir( subDirectory ): shutil.rmtree( subDirectory ) def deleteMenuItems( menu ): "Delete the menu items." try: lastMenuIndex = menu.index( Tkinter.END ) if lastMenuIndex != None: menu.delete( 0, lastMenuIndex ) except: print( 'this should never happen, the lastMenuIndex in deleteMenuItems in settings could not be determined.' ) def getAlongWayHexadecimalColor( beginBrightness, colorWidth, difference, endColorTuple, wayLength ): "Get a color along the way from begin brightness to the end color." alongWay = 1.0 if wayLength != 0.0: alongWay = min( 1.0, float( difference ) / float( wayLength ) ) hexadecimalColor = '#' oneMinusAlongWay = 1.0 - alongWay for primaryIndex in xrange( 3 ): hexadecimalColor += getAlongWayHexadecimalPrimary( beginBrightness, oneMinusAlongWay, colorWidth, endColorTuple[ primaryIndex ], alongWay ) return hexadecimalColor def getAlongWayHexadecimalPrimary( beginBrightness, beginRatio, colorWidth, endBrightness, endRatio ): "Get a primary color along the way from grey to the end color." brightness = beginRatio * float( beginBrightness ) + endRatio * float( endBrightness ) return getWidthHex( int( round( brightness ) ), colorWidth ) def getArchiveText( repository ): "Get the text representation of the archive." archiveWriter = cStringIO.StringIO() archiveWriter.write( 'Format is tab separated %s.\n' % repository.title.lower() ) archiveWriter.write( 'Name %sValue\n' % globalSpreadsheetSeparator ) for setting in repository.archive: setting.writeToArchiveWriter( archiveWriter ) return archiveWriter.getvalue() def getDirectoryInAboveDirectory( directory ): "Get the directory in the above directory." aboveDirectory = os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) return os.path.join( aboveDirectory, directory ) def getDisplayedDialogFromConstructor( repository ): "Display the repository dialog." getReadRepository( repository ) return RepositoryDialog( repository, Tkinter.Tk() ) try: getReadRepository( repository ) return RepositoryDialog( repository, Tkinter.Tk() ) except: print( 'this should never happen, getDisplayedDialogFromConstructor in settings could not open' ) print( repository ) return None def getDisplayedDialogFromPath( path ): "Display the repository dialog." pluginModule = gcodec.getModuleWithPath( path ) if pluginModule == None: return None return getDisplayedDialogFromConstructor( pluginModule.getNewRepository() ) def getDisplayToolButtonsRepository( directoryPath, importantFileNames, names, repository ): "Get the display tool buttons." displayToolButtons = [] for name in names: displayToolButton = DisplayToolButton().getFromPath( name in importantFileNames, name, os.path.join( directoryPath, name ), repository ) displayToolButtons.append( displayToolButton ) return displayToolButtons def getDocumentationPath( subName = '' ): "Get the documentation file path." numberOfLevelsDeepInPackageHierarchy = 2 packageFilePath = os.path.abspath( __file__ ) for level in xrange( numberOfLevelsDeepInPackageHierarchy + 1 ): packageFilePath = os.path.dirname( packageFilePath ) documentationIndexPath = os.path.join( packageFilePath, 'documentation' ) return os.path.join( documentationIndexPath, subName ) def getEachWordCapitalized( name ): "Get the capitalized name." withSpaces = name.lower().replace( '_', ' ' ) words = withSpaces.split( ' ' ) capitalizedStrings = [] for word in words: capitalizedStrings.append( word.capitalize() ) return ' '.join( capitalizedStrings ) def getFileInAlterationsOrGivenDirectory( directory, fileName ): "Get the file from the fileName or the lowercase fileName in the alterations directories, if there is no file look in the given directory." settingsAlterationsDirectory = getSettingsDirectoryPath( 'alterations' ) makeDirectory( settingsAlterationsDirectory ) fileInSettingsAlterationsDirectory = getFileInGivenDirectory( settingsAlterationsDirectory, fileName ) if fileInSettingsAlterationsDirectory != '': return fileInSettingsAlterationsDirectory alterationsDirectory = getDirectoryInAboveDirectory( 'alterations' ) fileInAlterationsDirectory = getFileInGivenDirectory( alterationsDirectory, fileName ) if fileInAlterationsDirectory != '': return fileInAlterationsDirectory if directory == '': directory = os.getcwd() return getFileInGivenDirectory( directory, fileName ) def getFileInGivenDirectory( directory, fileName ): "Get the file from the fileName or the lowercase fileName in the given directory." directoryListing = os.listdir( directory ) lowerFileName = fileName.lower() for directoryFile in directoryListing: if directoryFile.lower() == lowerFileName: return getFileTextGivenDirectoryFileName( directory, directoryFile ) return '' def getFileTextGivenDirectoryFileName( directory, fileName ): "Get the entire text of a file with the given file name in the given directory." absoluteFilePath = os.path.join( directory, fileName ) return gcodec.getFileText( absoluteFilePath ) def getFolders( directory ): "Get the folder list in a directory." makeDirectory( directory ) directoryListing = [] try: directoryListing = os.listdir( directory ) except OSError: print( 'Skeinforge can not list the directory:' ) print( directory ) print( 'so give it read/write permission for that directory.' ) folders = [] for fileName in directoryListing: if os.path.isdir( os.path.join( directory, fileName ) ): folders.append( fileName ) return folders def getPathFromFileNameHelp( fileNameHelp ): "Get the directory path from file name help." skeinforgePath = getSkeinforgeDirectoryPath() splitFileNameHelps = fileNameHelp.split( '.' ) splitFileNameDirectoryNames = splitFileNameHelps[ : - 1 ] for splitFileNameDirectoryName in splitFileNameDirectoryNames: skeinforgePath = os.path.join( skeinforgePath, splitFileNameDirectoryName ) return skeinforgePath def getRadioPluginsAddPluginFrame( directoryPath, importantFileNames, names, repository ): "Get the radio plugins and add the plugin frame." repository.pluginFrame = PluginFrame() radioPlugins = [] for name in names: radioPlugin = RadioPlugin().getFromRadio( name in importantFileNames, repository.pluginFrame.latentStringVar, name, repository, name == importantFileNames[ 0 ] ) radioPlugin.updateFunction = repository.pluginFrame.update radioPlugins.append( radioPlugin ) defaultRadioButton = getSelectedRadioPlugin( importantFileNames + [ radioPlugins[ 0 ].name ], radioPlugins ) repository.pluginFrame.getFromPath( defaultRadioButton, directoryPath, repository ) return radioPlugins def getProfilesDirectoryPath( subfolder = '' ): "Get the profiles directory path, which is the settings directory joined with profiles." profilesDirectory = getSettingsDirectoryPath( 'profiles' ) if subfolder == '': return profilesDirectory return os.path.join( profilesDirectory, subfolder ) def getProfilesDirectoryInAboveDirectory( subName = '' ): "Get the profiles directory path in the above directory." aboveProfilesDirectory = getDirectoryInAboveDirectory( 'profiles' ) if subName == '': return aboveProfilesDirectory return os.path.join( aboveProfilesDirectory, subName ) def getReadRepository( repository ): "Read and return settings from a file." text = gcodec.getFileText( getProfilesDirectoryPath( repository.baseName ), 'r', False ) if text == '': print( 'The default %s will be written in the .skeinforge folder in the home directory.' % repository.title.lower() ) text = gcodec.getFileText( getProfilesDirectoryInAboveDirectory( repository.baseName ), 'r', False ) if text != '': readSettingsFromText( repository, text ) writeSettings( repository ) return repository readSettingsFromText( repository, text ) return repository def getSelectedPluginModuleFromPath( filePath, plugins ): "Get the selected plugin module." for plugin in plugins: if plugin.value: return gcodec.getModuleFromPath( plugin.name, filePath ) return None def getSelectedPluginName( plugins ): "Get the selected plugin name." for plugin in plugins: if plugin.value: return plugin.name return '' def getSelectedRadioPlugin( names, radioPlugins ): "Get the selected radio button if it exists, None otherwise." for radioPlugin in radioPlugins: if radioPlugin.value: return radioPlugin for name in names: for radioPlugin in radioPlugins: if radioPlugin.name == name: radioPlugin.value = True return radioPlugin print( 'this should never happen, no getSelectedRadioPlugin in settings' ) print( names ) return radioPlugin[ 0 ] def getSettingsDirectoryPath( subfolder = '' ): "Get the settings directory path, which is the home directory joined with .skeinforge." settingsDirectory = os.path.join( os.path.expanduser( '~' ), '.skeinforge' ) if subfolder == '': return settingsDirectory return os.path.join( settingsDirectory, subfolder ) def getSkeinforgeToolsDirectoryPath(): "Get the skeinforge tools directory path." return os.path.dirname( os.path.dirname( os.path.abspath( __file__ ) ) ) def getSkeinforgeDirectoryPath(): "Get the skeinforge directory path." return os.path.dirname( getSkeinforgeToolsDirectoryPath() ) def getSubfolderWithBasename( basename, directory ): "Get the subfolder in the directory with the basename." makeDirectory( directory ) directoryListing = os.listdir( directory ) for fileName in directoryListing: joinedFileName = os.path.join( directory, fileName ) if os.path.isdir( joinedFileName ): if basename == fileName: return joinedFileName return None def getTitleFromName( title ): "Get the title of this setting." if title[ - 1 ] == ':': title = title[ : - 1 ] spaceBracketIndex = title.find( ' (' ) if spaceBracketIndex > - 1: return title[ : spaceBracketIndex ] return title def getWidthHex( number, width ): "Get the first width hexadecimal digits." return ( '0000%s' % hex( number )[ 2 : ] )[ - width : ] def liftRepositoryDialogs( repositoryDialogs ): "Lift the repository dialogs." for repositoryDialog in repositoryDialogs: repositoryDialog.root.withdraw() # the withdraw & deiconify trick is here because lift does not work properly on my linux computer repositoryDialog.root.lift() # probably not necessary, here in case the withdraw & deiconify trick does not work on some other computer repositoryDialog.root.deiconify() repositoryDialog.root.lift() # probably not necessary, here in case the withdraw & deiconify trick does not work on some other computer repositoryDialog.root.update_idletasks() def makeDirectory( directory ): "Make a directory if it does not already exist." if os.path.isdir( directory ): return try: os.makedirs( directory ) except OSError: print( 'Skeinforge can not make the directory %s so give it read/write permission for that directory and the containing directory.' % directory ) def openWebPage( webPagePath ): "Open a web page in a browser." if webPagePath.find( '#' ) != - 1: # to get around # encode bug redirectionText = '\n\n\n' redirectionText += '\n\n' % webPagePath webPagePath = getDocumentationPath( 'redirect.html' ) gcodec.writeFileText( webPagePath, redirectionText ) webPagePath = '"%s"' % webPagePath # " to get around space in url bug try: os.startfile( webPagePath )#this is available on some python environments, but not all return except: pass webbrowserName = webbrowser.get().name if webbrowserName == '': print( 'Skeinforge was not able to open the documentation file in a web browser. To see the documentation, open the following file in a web browser:' ) print( webPagePath ) return os.system( webbrowserName + ' ' + webPagePath )#used this instead of webbrowser.open() to workaround webbrowser open() bug def quitWindow( root ): "Quit a window." try: root.destroy() except: pass def quitWindows( event = None ): "Quit all windows." global globalRepositoryDialogListTable globalRepositoryDialogValues = euclidean.getListTableElements( globalRepositoryDialogListTable ) for globalRepositoryDialogValue in globalRepositoryDialogValues: quitWindow( globalRepositoryDialogValue.root ) def readSettingsFromText( repository, text ): "Read settings from a text." lines = gcodec.getTextLines( text ) settingTable = {} for setting in repository.archive: settingTable[ setting.name ] = setting for lineIndex in xrange( len( lines ) ): setArchiveToLine( lineIndex, lines, settingTable ) def saveRepository( repository ): "Set the entities to the dialog then write them." for setting in repository.archive: setting.setToDisplay() writeSettingsPrintMessage( repository ) for saveListener in repository.saveListenerTable.values(): saveListener() def setArchiveToLine( lineIndex, lines, settingTable ): "Set an archive to a setting line." line = lines[ lineIndex ] splitLine = line.split( globalSpreadsheetSeparator ) if len( splitLine ) < 2: return fileSettingName = splitLine[ 0 ] if fileSettingName in settingTable: settingTable[ fileSettingName ].setValueToSplitLine( lineIndex, lines, splitLine ) def setButtonFontWeightString( button, isBold ): "Set button font weight given isBold." try: weightString = 'normal' if isBold: weightString = 'bold' splitFont = button[ 'font' ].split() button[ 'font' ] = ( splitFont[ 0 ], splitFont[ 1 ], weightString ) except: pass def setEntryText( entry, value ): "Set the entry text." if entry == None: return entry.delete( 0, Tkinter.END ) entry.insert( 0, str( value ) ) def setIntegerValueToString( integerSetting, valueString ): "Set the integer to the string." dotIndex = valueString.find( '.' ) if dotIndex > - 1: valueString = valueString[ : dotIndex ] try: integerSetting.value = int( valueString ) return except: print( 'Warning, can not read integer ' + integerSetting.name + ' ' + valueString ) print( 'Will try reading as a boolean, which might be a mistake.' ) integerSetting.value = 0 if valueString.lower() == 'true': integerSetting.value = 1 def setSpinColor( setting ): "Set the spin box color to the value, yellow if it is lower than the default and blue if it is higher." if setting.entry == None: return if setting.backgroundColor == None: setting.backgroundColor = setting.entry[ 'background' ] if setting.backgroundColor[ 0 ] != '#': setting.backgroundColor = '#ffffff' setting.colorWidth = len( setting.backgroundColor ) / 3 setting.grey = int( setting.backgroundColor[ 1 : 1 + setting.colorWidth ], 16 ) setting.white = int( 'f' * setting.colorWidth, 16 ) if abs( setting.value - setting.defaultValue ) < 0.02 * setting.width: setting.entry[ 'background' ] = setting.backgroundColor return difference = setting.value - setting.defaultValue if difference > 0.0: wayLength = setting.to - setting.defaultValue setting.entry[ 'background' ] = getAlongWayHexadecimalColor( setting.grey, setting.colorWidth, difference, ( 0, setting.white, setting.white ), wayLength ) return wayLength = setting.from_ - setting.defaultValue setting.entry[ 'background' ] = getAlongWayHexadecimalColor( setting.grey, setting.colorWidth, difference, ( setting.white, setting.white, 0 ), wayLength ) def startMainLoopFromConstructor( repository ): "Display the repository dialog and start the main loop." getDisplayedDialogFromConstructor( repository ).root.mainloop() def updateProfileSaveListeners(): "Call the save function of all the update profile save listeners." global globalProfileSaveListenerListTable for globalProfileSaveListener in euclidean.getListTableElements( globalProfileSaveListenerListTable ): globalProfileSaveListener.save() def writeValueListToArchiveWriter( archiveWriter, setting ): "Write tab separated name and list to the archive writer." archiveWriter.write( setting.name ) for item in setting.value: if item != '[]': archiveWriter.write( globalSpreadsheetSeparator ) archiveWriter.write( item ) archiveWriter.write( '\n' ) def writeSettings( repository ): "Write the settings to a file." profilesDirectoryPath = getProfilesDirectoryPath( repository.baseName ) makeDirectory( os.path.dirname( profilesDirectoryPath ) ) gcodec.writeFileText( profilesDirectoryPath, getArchiveText( repository ) ) def writeSettingsPrintMessage( repository ): "Set the settings to the dialog then write them." writeSettings( repository ) print( repository.title.lower().capitalize() + ' have been saved.' ) class AddProfile: "A class to add a profile." def addToDialog( self, gridPosition ): "Add this to the dialog." gridPosition.increment() self.entry = Tkinter.Entry( gridPosition.master ) self.entry.bind( '', self.addSelectionWithEvent ) self.entry.grid( row = gridPosition.row, column = 1, columnspan = 3, sticky = Tkinter.W ) self.addButton = Tkinter.Button( gridPosition.master, activebackground = 'black', activeforeground = 'white', text = 'Add Profile', command = self.addSelection ) self.addButton.grid( row = gridPosition.row, column = 0 ) def addSelection( self ): "Add the selection of a listbox setting." entryText = self.entry.get() if entryText == '': print( 'To add to the profiles, enter the material name.' ) return self.profileListboxSetting.listSetting.setValueToFolders() if entryText in self.profileListboxSetting.listSetting.value: print( 'There is already a profile by the name of %s, so no profile will be added.' % entryText ) return self.entry.delete( 0, Tkinter.END ) craftTypeProfileDirectory = getProfilesDirectoryPath( self.profileListboxSetting.listSetting.craftTypeName ) destinationDirectory = os.path.join( craftTypeProfileDirectory, entryText ) shutil.copytree( self.profileListboxSetting.getSelectedFolder(), destinationDirectory ) self.profileListboxSetting.listSetting.setValueToFolders() self.profileListboxSetting.value = entryText self.profileListboxSetting.setStateToValue() def addSelectionWithEvent( self, event ): "Add the selection of a listbox setting, given an event." self.addSelection() def getFromProfileListboxSettingRepository( self, profileListboxSetting, repository ): "Initialize." self.profileListboxSetting = profileListboxSetting self.repository = repository repository.displayEntities.append( self ) return self class StringSetting: "A class to display, read & write a string." def __init__( self ): "Set the update function to none." self.entry = None self.updateFunction = None def addToDialog( self, gridPosition ): "Add this to the dialog." gridPosition.increment() self.label = Tkinter.Label( gridPosition.master, text = self.name ) self.label.grid( row = gridPosition.row, column = 0, columnspan = 3, sticky = Tkinter.W ) self.createEntry( gridPosition.master ) self.setStateToValue() self.entry.grid( row = gridPosition.row, column = 3, columnspan = 2, sticky = Tkinter.W ) self.bindEntry() LabelHelp( self.repository.fileNameHelp, gridPosition.master, self.name, self.label ) def addToMenu( self, repositoryMenu ): "Do nothing because this should only be added to a frameable repository menu." pass def addToMenuFrameable( self, repositoryMenu ): "Add this to the frameable repository menu." titleFromName = getTitleFromName( self.name ) helpWindowMenu = Tkinter.Menu( repositoryMenu, tearoff = 0 ) repositoryMenu.add_cascade( label = titleFromName, menu = helpWindowMenu, underline = 0 ) if self.name in self.repository.frameList.value: helpWindowMenu.add_command( label = 'Remove from Window', command = self.removeFromWindow ) else: helpWindowMenu.add_command( label = 'Add to Window', command = self.addToWindow ) helpWindowMenu.add_separator() helpWindowMenu.add_command( label = 'Help', command = HelpPage().getOpenFromDocumentationSubName( self.repository.fileNameHelp + '#' + titleFromName ) ) def addToWindow( self ): "Add this to the repository frame list." self.repository.frameList.addToList( self.name ) def bindEntry( self ): "Bind the entry to the update function." if self.updateFunction != None: self.entry.bind( '', self.updateFunction ) def createEntry( self, root ): "Create the entry." self.entry = Tkinter.Entry( root ) def getFromValue( self, name, repository, value ): "Initialize." return self.getFromValueOnlyAddToRepository( name, repository, value ) def getFromValueOnly( self, name, repository, value ): "Initialize." self.defaultValue = value self.name = name self.repository = repository self.value = value return self def getFromValueOnlyAddToRepository( self, name, repository, value ): "Initialize." repository.archive.append( self ) repository.displayEntities.append( self ) repository.menuEntities.append( self ) return self.getFromValueOnly( name, repository, value ) def removeFromWindow( self ): "Remove this from the repository frame list." self.repository.frameList.removeFromList( self.name ) def setStateToValue( self ): "Set the entry to the value." setEntryText( self.entry, self.value ) def setToDisplay( self ): "Set the string to the entry field." try: valueString = self.entry.get() self.setValueToString( valueString ) except: pass def setUpdateFunction( self, updateFunction ): "Set the update function." self.updateFunction = updateFunction def setValueToSplitLine( self, lineIndex, lines, splitLine ): "Set the value to the second word of a split line." self.setValueToString( splitLine[ 1 ] ) def setValueToString( self, valueString ): "Set the value to the value string." self.value = valueString def writeToArchiveWriter( self, archiveWriter ): "Write tab separated name and value to the archive writer." archiveWriter.write( '%s%s%s\n' % ( self.name, globalSpreadsheetSeparator, self.value ) ) class BooleanSetting( StringSetting ): "A class to display, read & write a boolean." def addToDialog( self, gridPosition ): "Add this to the dialog." gridPosition.increment() self.checkbutton = Tkinter.Checkbutton( gridPosition.master, command = self.toggleCheckbutton, text = self.name ) #toggleCheckbutton is being used instead of a Tkinter IntVar because there is a weird bug where it doesn't work properly if this setting is not on the first window. self.checkbutton.grid( row = gridPosition.row, columnspan = 5, sticky = Tkinter.W ) self.setStateToValue() LabelHelp( self.repository.fileNameHelp, gridPosition.master, self.name, self.checkbutton ) def addToMenu( self, repositoryMenu ): "Add this to the repository menu." self.activateToggleMenuCheckbutton = False #activateToggleMenuCheckbutton is being used instead of setting command after because add_checkbutton does not return a checkbutton. repositoryMenu.add_checkbutton( label = getTitleFromName( self.name ), command = self.toggleMenuCheckbutton ) if self.value: repositoryMenu.invoke( repositoryMenu.index( Tkinter.END ) ) self.activateToggleMenuCheckbutton = True def addToMenuFrameable( self, repositoryMenu ): "Add this to the frameable repository menu." titleFromName = getTitleFromName( self.name ) helpWindowMenu = Tkinter.Menu( repositoryMenu, tearoff = 0 ) repositoryMenu.add_cascade( label = titleFromName, menu = helpWindowMenu, underline = 0 ) self.addToMenu( helpWindowMenu ) helpWindowMenu.add_separator() helpWindowMenu.add_command( label = 'Help', command = HelpPage().getOpenFromDocumentationSubName( self.repository.fileNameHelp + '#' + titleFromName ) ) def setStateToValue( self ): "Set the checkbutton to the boolean." try: if self.value: self.checkbutton.select() else: self.checkbutton.deselect() except: pass def setToDisplay( self ): "Do nothing because toggleCheckbutton is handling the value." pass def setValueToString( self, valueString ): "Set the boolean to the string." self.value = ( valueString.lower() == 'true' ) def toggleCheckbutton( self ): "Workaround for Tkinter bug, toggle the value." self.value = not self.value self.setStateToValue() if self.updateFunction != None: self.updateFunction() def toggleMenuCheckbutton( self ): "Workaround for Tkinter bug, toggle the value." if self.activateToggleMenuCheckbutton: self.value = not self.value if self.updateFunction != None: self.updateFunction() class CloseListener: "A class to listen to link a window to the global repository dialog list table." def __init__( self, window, closeFunction = None ): "Add the window to the global repository dialog list table." self.closeFunction = closeFunction self.window = window self.shouldWasClosedBeBound = True global globalRepositoryDialogListTable addElementToListTableIfNotThere( window, window, globalRepositoryDialogListTable ) def listenToWidget( self, widget ): "Listen to the destroy message of the widget." if self.shouldWasClosedBeBound: self.shouldWasClosedBeBound = False widget.bind( '', self.wasClosed ) def wasClosed( self, event ): "The dialog was closed." global globalCloseListTables for globalCloseListTable in globalCloseListTables: if self.window in globalCloseListTable: del globalCloseListTable[ self.window ] if self.closeFunction != None: self.closeFunction() class DeleteProfile( AddProfile ): "A class to delete the selection of a listbox profile." def addToDialog( self, gridPosition ): "Add this to the dialog." gridPosition.increment() self.deleteButton = Tkinter.Button( gridPosition.master, activebackground = 'black', activeforeground = 'white', text = "Delete Profile", command = self.deleteSelection ) self.deleteButton.grid( row = gridPosition.row, column = 0 ) def deleteSelection( self ): "Delete the selection of a listbox setting." DeleteProfileDialog( self.profileListboxSetting, Tkinter.Tk() ) class DeleteProfileDialog: def __init__( self, profileListboxSetting, root ): "Display a delete dialog." self.profileListboxSetting = profileListboxSetting self.root = root self.row = 0 root.title( 'Delete Warning' ) self.gridPosition.increment() self.label = Tkinter.Label( self.root, text = 'Do you want to delete the profile?' ) self.label.grid( row = self.row, column = 0, columnspan = 3, sticky = Tkinter.W ) columnIndex = 1 deleteButton = Tkinter.Button( root, activebackground = 'black', activeforeground = 'red', command = self.delete, fg = 'red', text = 'Delete' ) deleteButton.grid( row = self.row, column = columnIndex ) columnIndex += 1 noButton = Tkinter.Button( root, activebackground = 'black', activeforeground = 'darkgreen', command = self.no, fg = 'darkgreen', text = 'Do Nothing' ) noButton.grid( row = self.row, column = columnIndex ) def delete( self ): "Delete the selection of a listbox setting." self.profileListboxSetting.setToDisplay() self.profileListboxSetting.listSetting.setValueToFolders() if self.profileListboxSetting.value not in self.profileListboxSetting.listSetting.value: return lastSelectionIndex = 0 currentSelectionTuple = self.profileListboxSetting.listbox.curselection() if len( currentSelectionTuple ) > 0: lastSelectionIndex = int( currentSelectionTuple[ 0 ] ) else: print( 'No profile is selected, so no profile will be deleted.' ) return deleteDirectory( getProfilesDirectoryPath( self.profileListboxSetting.listSetting.craftTypeName ), self.profileListboxSetting.value ) deleteDirectory( getProfilesDirectoryInAboveDirectory( self.profileListboxSetting.listSetting.craftTypeName ), self.profileListboxSetting.value ) self.profileListboxSetting.listSetting.setValueToFolders() if len( self.profileListboxSetting.listSetting.value ) < 1: defaultSettingsDirectory = getProfilesDirectoryPath( os.path.join( self.profileListboxSetting.listSetting.craftTypeName, self.profileListboxSetting.defaultValue ) ) makeDirectory( defaultSettingsDirectory ) self.profileListboxSetting.listSetting.setValueToFolders() lastSelectionIndex = min( lastSelectionIndex, len( self.profileListboxSetting.listSetting.value ) - 1 ) self.profileListboxSetting.value = self.profileListboxSetting.listSetting.value[ lastSelectionIndex ] self.profileListboxSetting.setStateToValue() self.no() def no( self ): "The dialog was closed." self.root.destroy() class DisplayToolButton: "A class to display the tool dialog button, in a two column wide table." def addToDialog( self, gridPosition ): "Add this to the dialog." self.displayButton = Tkinter.Button( gridPosition.master, activebackground = 'black', activeforeground = 'white', text = getEachWordCapitalized( self.name ), command = self.displayDialog ) setButtonFontWeightString( self.displayButton, self.important ) gridPosition.incrementGivenNumberOfColumns( 2 ) self.displayButton.grid( row = gridPosition.row, column = gridPosition.column, columnspan = 2 ) def displayDialog( self ): "Display function." ToolDialog().getFromPath( self.path ).display() def getFromPath( self, important, name, path, repository ): "Initialize." self.important = important self.name = name self.path = path self.repository = repository repository.displayEntities.append( self ) return self class FileHelpMenuBar: def __init__( self, root ): "Create a menu bar with a file and help menu." self.underlineLetters = [] self.menuBar = Tkinter.Menu( root ) self.root = root root.config( menu = self.menuBar ) self.fileMenu = Tkinter.Menu( self.menuBar, tearoff = 0 ) self.menuBar.add_cascade( label = "File", menu = self.fileMenu, underline = 0 ) self.underlineLetters.append( 'f' ) def addMenuToMenuBar( self, labelText, menu ): "Add a menu to the menu bar." lowerLabelText = labelText.lower() for underlineLetterIndex in xrange( len( lowerLabelText ) ): underlineLetter = lowerLabelText[ underlineLetterIndex ] if underlineLetter not in self.underlineLetters: self.underlineLetters.append( underlineLetter ) self.menuBar.add_cascade( label = labelText, menu = menu, underline = underlineLetterIndex ) return self.menuBar.add_cascade( label = labelText, menu = menu ) def addPluginToMenuBar( self, modulePath, repository, window ): "Add a menu to the menu bar from a tool." pluginModule = gcodec.getModuleWithPath( modulePath ) if pluginModule == None: print( 'this should never happen, pluginModule in addMenuToMenuBar in settings is None.' ) return None repositoryMenu = Tkinter.Menu( self.menuBar, tearoff = 0 ) labelText = getEachWordCapitalized( os.path.basename( modulePath ) ) self.addMenuToMenuBar( labelText, repositoryMenu ) pluginModule.addToMenu( self.root, repositoryMenu, repository, window ) def completeMenu( self, closeFunction, repository, saveFunction, window ): "Complete the menu." self.closeFunction = closeFunction self.saveFunction = saveFunction addAcceleratorCommand( '', saveFunction, self.root, self.fileMenu, 'Save' ) self.fileMenu.add_command( label = "Save and Close", command = self.saveClose ) addAcceleratorCommand( '', closeFunction, self.root, self.fileMenu, 'Close' ) self.fileMenu.add_separator() addAcceleratorCommand( '', quitWindows, self.root, self.fileMenu, 'Quit' ) skeinforgeToolsDirectoryPath = getSkeinforgeToolsDirectoryPath() pluginFileNames = gcodec.getPluginFileNamesFromDirectoryPath( skeinforgeToolsDirectoryPath ) for pluginFileName in pluginFileNames: self.addPluginToMenuBar( os.path.join( skeinforgeToolsDirectoryPath, pluginFileName ), repository, window ) def saveClose( self ): "Call the save function then the close function." self.saveFunction() self.closeFunction() class FileNameInput( StringSetting ): "A class to display, read & write a fileName." def addToDialog( self, gridPosition ): "Add this to the dialog." self.gridPosition = gridPosition gridPosition.executables.append( self ) def execute( self ): "Open the file picker." self.wasCancelled = False parent = self.gridPosition.master try: import tkFileDialog summarized = gcodec.getSummarizedFileName( self.value ) initialDirectory = os.path.dirname( summarized ) if len( initialDirectory ) > 0: initialDirectory += os.sep else: initialDirectory = "." fileName = tkFileDialog.askopenfilename( filetypes = self.getFileNameFirstTypes(), initialdir = initialDirectory, initialfile = os.path.basename( summarized ), parent = parent, title = self.name ) self.setCancelledValue( fileName ) return except: print( 'Could not get the old directory in settings, so the file picker will be opened in the default directory.' ) try: fileName = tkFileDialog.askopenfilename( filetypes = self.getFileNameFirstTypes(), initialdir = '.', initialfile = '', parent = parent, title = self.name ) self.setCancelledValue( fileName ) except: print( 'Error in execute in FileName in settings, ' + self.name ) def getFileNameFirstTypes( self ): "Get the file types with the file type of the fileName moved to the front of the list." try: basename = os.path.basename( self.value ) splitFile = basename.split( '.' ) allFiles = [ ( 'All', '*.*' ) ] allReadables = [] if len( self.fileTypes ) > 1: for fileType in self.fileTypes: allReadable = ( ( 'All Readable', fileType[ 1 ] ) ) allReadables.append( allReadable ) if len( splitFile ) < 1: return self.fileTypes + allReadables + allFiles baseExtension = splitFile[ - 1 ] for fileType in self.fileTypes: fileExtension = fileType[ 1 ].split( '.' )[ - 1 ] if fileExtension == baseExtension: fileNameFirstTypes = self.fileTypes[ : ] fileNameFirstTypes.remove( fileType ) return [ fileType ] + fileNameFirstTypes + allReadables + allFiles return self.fileTypes + allReadables + allFiles except: return allFiles def getFromFileName( self, fileTypes, name, repository, value ): "Initialize." self.getFromValueOnly( name, repository, value ) self.fileTypes = fileTypes repository.archive.append( self ) repository.displayEntities.append( self ) return self def setCancelledValue( self, fileName ): "Set the value to the file name and wasCancelled true if a file was not picked." if ( str( fileName ) == '()' or str( fileName ) == '' ): self.wasCancelled = True else: self.value = fileName def setToDisplay( self ): "Do nothing because the file dialog is handling the value." pass class FloatSetting( StringSetting ): "A class to display, read & write a float." def setValueToString( self, valueString ): "Set the float to the string." try: self.value = float( valueString ) except: print( 'Oops, can not read float' + self.name + ' ' + valueString ) class FloatSpin( FloatSetting ): "A class to display, read & write an float in a spin box." def addToMenuFrameable( self, repositoryMenu ): "Add this to the frameable repository menu." titleFromName = getTitleFromName( self.name ) helpWindowMenu = Tkinter.Menu( repositoryMenu, tearoff = 0 ) repositoryMenu.add_cascade( label = titleFromName, menu = helpWindowMenu, underline = 0 ) if self.name in self.repository.frameList.value: helpWindowMenu.add_command( label = 'Remove from Window', command = self.removeFromWindow ) else: helpWindowMenu.add_command( label = 'Add to Window', command = self.addToWindow ) helpWindowMenu.add_separator() changeString = ' by %s' % self.increment helpWindowMenu.add_command( label = 'Increase' + changeString, command = self.increase ) helpWindowMenu.add_command( label = 'Decrease' + changeString, command = self.decrease ) helpWindowMenu.add_separator() helpWindowMenu.add_command( label = 'Help', command = HelpPage().getOpenFromDocumentationSubName( self.repository.fileNameHelp + '#' + titleFromName ) ) def bindEntry( self ): "Bind the entry to the update function." self.entry.bind( '', self.entryUpdated ) self.setColor() def createEntry( self, root ): "Create the entry." self.entry = Tkinter.Spinbox( root, command = self.setColorToDisplay, from_ = self.from_, increment = self.increment, to = self.to ) def decrease( self ): "Decrease the value then set the state and color to the value." self.value -= self.increment self.setStateUpdateColor() def entryUpdated( self, event = None ): "Create the entry." self.setColorToDisplay() if self.updateFunction != None: self.updateFunction( event ) def getFromValue( self, from_, name, repository, to, value ): "Initialize." self.backgroundColor = None self.from_ = from_ self.width = to - from_ rank = euclidean.getRank( 0.05 * self.width ) self.increment = euclidean.getIncrementFromRank( rank ) self.to = to return self.getFromValueOnlyAddToRepository( name, repository, value ) def increase( self ): "Increase the value then set the state and color to the value." self.value += self.increment self.setStateUpdateColor() def setColor( self, event = None ): "Set the color to the value, yellow if it is lower than the default and blue if it is higher." setSpinColor( self ) def setColorToDisplay( self, event = None ): "Set the color to the value, yellow if it is lower than the default and blue if it is higher." self.setToDisplay() self.setColor() def setStateToValue( self ): "Set the entry to the value." setEntryText( self.entry, self.value ) self.setColor() def setStateUpdateColor( self ): "Set the state to the value, call the update function, then set the color." self.setStateToValue() if self.updateFunction != None: self.updateFunction() class FloatSpinNotOnMenu( FloatSpin ): "A class to display, read & write an float in a spin box, which is not to be added to a menu." def getFromValueOnlyAddToRepository( self, name, repository, value ): "Initialize." repository.archive.append( self ) repository.displayEntities.append( self ) return self.getFromValueOnly( name, repository, value ) class FloatSpinUpdate( FloatSpin ): "A class to display, read, update & write an float in a spin box." def createEntry( self, root ): "Create the entry." self.entry = Tkinter.Spinbox( root, command = self.entryUpdated, from_ = self.from_, increment = self.increment, to = self.to ) class FrameList: "A class to list the frames." def addToList( self, word ): "Add the word to the sorted list." self.value.append( word ) self.value.sort() self.repository.window.redisplayWindowUpdate() def getFromValue( self, name, repository, value ): "Initialize." repository.archive.append( self ) self.name = name self.repository = repository self.value = value return self def removeFromList( self, word ): "Remove the word from the sorted list." self.value.remove( word ) self.value.sort() self.repository.window.redisplayWindowUpdate() def setToDisplay( self ): "Do nothing because frame list does not have a display." pass def setValueToSplitLine( self, lineIndex, lines, splitLine ): "Set the value to the second and later words of a split line." self.value = splitLine[ 1 : ] def writeToArchiveWriter( self, archiveWriter ): "Write tab separated name and list to the archive writer." writeValueListToArchiveWriter( archiveWriter, self ) class GridHorizontal: "A class to place elements horizontally on a grid." def __init__( self, column, row ): "Initialize the column and row." self.column = column self.columnStart = column self.row = row def getCopy( self ): "Get a copy." copy = GridHorizontal( self.column, self.row ) copy.columnStart = self.columnStart return copy def increment( self ): "Increment the position horizontally." self.column += 1 class GridVertical: "A class to place elements vertically on a grid." def __init__( self, column, row ): "Initialize the column and row." self.column = column self.columnOffset = column self.columnStart = column self.row = row self.rowStart = row def execute( self ): "The execute button was clicked." for executable in self.executables: executable.execute() saveRepository( self.repository ) self.repository.execute() def getCopy( self ): "Get a copy." copy = GridVertical( self.column, self.row ) copy.columnOffset = self.columnOffset copy.columnStart = self.columnStart copy.rowStart = self.rowStart return copy def increment( self ): "Increment the position vertically." self.column = self.columnStart self.columnOffset = self.columnStart self.row += 1 def incrementGivenNumberOfColumns( self, numberOfColumns ): "Increment the position vertically and offset it horizontally by the given number of columns." self.column = self.columnOffset if self.columnOffset == self.columnStart: self.columnOffset = self.columnStart + 1 self.row += 1 return if self.columnOffset < self.columnStart + numberOfColumns - 1: self.columnOffset += 1 return self.columnOffset = self.columnStart def setExecutablesRepository( self, repository ): "Set the executables to an empty list and set the repository." self.executables = [] self.repository = repository class HelpPage: "A class to open a help page." def addToDialog( self, gridPosition ): "Add this to the dialog." self.displayButton = Tkinter.Button( gridPosition.master, activebackground = 'black', activeforeground = 'white', text = getEachWordCapitalized( self.name ), command = self.openPage ) self.displayButton.grid( row = gridPosition.row, column = 3, columnspan = 2 ) def addToMenu( self, repositoryMenu ): "Add this to the repository menu." repositoryMenu.add_command( label = getTitleFromName( self.name ), command = self.openPage ) def addToMenuFrameable( self, repositoryMenu ): "Add this to the frameable repository menu." self.addToMenu( repositoryMenu ) def getFromNameAfterHTTP( self, afterHTTP, name, repository ): "Initialize." self.setToNameRepository( name, repository ) self.hypertextAddress = 'http://' + afterHTTP return self def getFromNameAfterWWW( self, afterWWW, name, repository ): "Initialize." self.setToNameRepository( name, repository ) self.hypertextAddress = 'http://www.' + afterWWW return self def getFromNameSubName( self, name, repository, subName = '' ): "Initialize." self.setToNameRepository( name, repository ) self.hypertextAddress = getDocumentationPath( subName ) return self def getOpenFromAbsolute( self, hypertextAddress ): "Get the open help page function from the hypertext address." self.hypertextAddress = hypertextAddress return self.openPage def getOpenFromAfterHTTP( self, afterHTTP ): "Get the open help page function from the part of the address after the HTTP." self.hypertextAddress = 'http://' + afterHTTP return self.openPage def getOpenFromAfterWWW( self, afterWWW ): "Get the open help page function from the afterWWW of the address after the www." self.hypertextAddress = 'http://www.' + afterWWW return self.openPage def getOpenFromDocumentationSubName( self, subName = '' ): "Get the open help page function from the afterWWW of the address after the www." self.hypertextAddress = getDocumentationPath( subName ) return self.openPage def openPage( self, event = None ): "Open the browser to the hypertext address." openWebPage( self.hypertextAddress ) def setToNameRepository( self, name, repository ): "Set to the name and repository." self.name = name self.repository = repository repository.displayEntities.append( self ) repository.menuEntities.append( self ) class HelpPageRepository: "A class to open a repository help page." def __init__( self, repository ): "Add this to the dialog." self.repository = repository def openPage( self, event = None ): "Open the browser to the repository help page." if self.repository.openWikiManualHelpPage == None: self.repository.openLocalHelpPage() return from skeinforge_tools import help helpRepository = getReadRepository( help.HelpRepository() ) if helpRepository.wikiManualPrimary.value: self.repository.openWikiManualHelpPage() return self.repository.openLocalHelpPage() class HiddenScrollbar( Tkinter.Scrollbar ): "A class to hide the scrollbar if it is not needed." def set( self, lo, hi ): "Add to grid is needed, remove if not." if float( lo ) <= 0.0 and float( hi ) >= 1.0: self.tk.call( 'grid', 'remove', self ) else: self.grid() Tkinter.Scrollbar.set( self, lo, hi ) class IntSetting( FloatSetting ): "A class to display, read & write an int." def setValueToString( self, valueString ): "Set the integer to the string." setIntegerValueToString( self, valueString ) class IntSpin( FloatSpin ): "A class to display, read & write an int in a spin box." def getFromValue( self, from_, name, repository, to, value ): "Initialize." self.backgroundColor = None self.from_ = from_ self.width = to - from_ rank = euclidean.getRank( 0.05 * self.width ) self.increment = max( 1, int( euclidean.getIncrementFromRank( rank ) ) ) self.to = to return self.getFromValueOnlyAddToRepository( name, repository, value ) def getSingleIncrementFromValue( self, from_, name, repository, to, value ): "Initialize." self.backgroundColor = None self.from_ = from_ self.width = to - from_ self.increment = 1 self.to = to return self.getFromValueOnlyAddToRepository( name, repository, value ) def setValueToString( self, valueString ): "Set the integer to the string." setIntegerValueToString( self, valueString ) class IntSpinNotOnMenu( IntSpin ): "A class to display, read & write an integer in a spin box, which is not to be added to a menu." def getFromValueOnlyAddToRepository( self, name, repository, value ): "Initialize." repository.archive.append( self ) repository.displayEntities.append( self ) return self.getFromValueOnly( name, repository, value ) class IntSpinUpdate( IntSpin ): "A class to display, read, update & write an int in a spin box." def createEntry( self, root ): "Create the entry." self.entry = Tkinter.Spinbox( root, command = self.entryUpdated, from_ = self.from_, increment = self.increment, to = self.to ) class LabelDisplay: "A class to add a label." def addToDialog( self, gridPosition ): "Add this to the dialog." gridPosition.increment() self.label = Tkinter.Label( gridPosition.master, text = self.name ) self.label.grid( row = gridPosition.row, column = 0, columnspan = 3, sticky = Tkinter.W ) LabelHelp( self.repository.fileNameHelp, gridPosition.master, self.name, self.label ) def getFromName( self, name, repository ): "Initialize." self.name = name self.repository = repository repository.displayEntities.append( self ) return self class LabelHelp: "A class to add help to a widget." def __init__( self, fileNameHelp, master, name, widget ): "Add menu to the widget." if len( name ) < 1: return self.popupMenu = Tkinter.Menu( master, tearoff = 0 ) titleFromName = getTitleFromName( name.replace( '- ', '' ).replace( ' -', '' ) ) self.popupMenu.add_command( label = 'Help', command = HelpPage().getOpenFromDocumentationSubName( fileNameHelp + '#' + titleFromName ) ) widget.bind( '', self.unpostPopupMenu ) widget.bind( '', self.unpostPopupMenu ) widget.bind( '', self.displayPopupMenu ) def unpostPopupMenu( self, event = None ): 'Unpost the popup menu.' self.popupMenu.unpost() def displayPopupMenu( self, event = None ): 'Display the popup menu when the button is right clicked.' try: self.popupMenu.tk_popup( event.x_root + 30, event.y_root, 0 ) finally: self.popupMenu.grab_release() class LabelSeparator: "A class to add a label and menu separator." def addToDialog( self, gridPosition ): "Add this to the dialog." gridPosition.increment() self.label = Tkinter.Label( gridPosition.master, text = '' ) self.label.grid( row = gridPosition.row, column = 0, columnspan = 3, sticky = Tkinter.W ) def addToMenu( self, repositoryMenu ): "Add this to the repository menu." repositoryMenu.add_separator() def addToMenuFrameable( self, repositoryMenu ): "Add this to the frameable repository menu." self.addToMenu( repositoryMenu ) def getFromRepository( self, repository ): "Initialize." self.repository = repository repository.displayEntities.append( self ) repository.menuEntities.append( self ) return self class LatentStringVar: "A class to provide a StringVar when needed." def __init__( self ): "Set the string var." self.stringVar = None def getVar( self ): "Get the string var." if self.stringVar == None: self.stringVar = Tkinter.StringVar() return self.stringVar def getString( self ): "Get the string." return self.getVar().get() def setString( self, word ): "Set the string." self.getVar().set( word ) class MenuButtonDisplay: "A class to add a menu button." def addRadiosToDialog( self, gridPosition ): "Add the menu radios to the dialog." for menuRadio in self.menuRadios: menuRadio.addToDialog( gridPosition ) def addToMenu( self, repositoryMenu ): "Add this to the repository menu." if len( self.menuRadios ) < 1: print( 'The MenuButtonDisplay in settings should have menu items.' ) print( self.name ) return self.menu = Tkinter.Menu( repositoryMenu, tearoff = 0 ) repositoryMenu.add_cascade( label = getTitleFromName( self.name ), menu = self.menu ) self.setRadioVarToName( self.menuRadios[ 0 ].name ) def addToMenuFrameable( self, repositoryMenu ): "Add this to the frameable repository menu." titleFromName = getTitleFromName( self.name ) self.addToMenu( repositoryMenu ) self.menu.add_command( label = 'Help', command = HelpPage().getOpenFromDocumentationSubName( self.repository.fileNameHelp + '#' + titleFromName ) ) self.menu.add_separator() def getFromName( self, name, repository ): "Initialize." self.menuRadios = [] self.name = name self.radioVar = None self.repository = repository repository.menuEntities.append( self ) return self def removeMenus( self ): "Remove all menus." deleteMenuItems( self.menu ) self.menuRadios = [] def setRadioVarToName( self, name ): "Get the menu button." self.optionList = [ name ] self.radioVar = Tkinter.StringVar() self.radioVar.set( self.optionList[ 0 ] ) def setToNameAddToDialog( self, name, gridPosition ): "Get the menu button." if self.radioVar != None: return gridPosition.increment() self.setRadioVarToName( name ) self.label = Tkinter.Label( gridPosition.master, text = self.name ) self.label.grid( row = gridPosition.row, column = 0, columnspan = 3, sticky = Tkinter.W ) self.menuButton = Tkinter.OptionMenu( gridPosition.master, self.radioVar, self.optionList ) self.menuButton.grid( row = gridPosition.row, column = 3, columnspan = 2, sticky = Tkinter.W ) self.menuButton.menu = Tkinter.Menu( self.menuButton, tearoff = 0 ) self.menu = self.menuButton.menu self.menuButton[ 'menu' ] = self.menu LabelHelp( self.repository.fileNameHelp, gridPosition.master, self.name, self.label ) class MenuRadio( BooleanSetting ): "A class to display, read & write a boolean with associated menu radio button." def addToDialog( self, gridPosition ): "Add this to the dialog." self.menuButtonDisplay.setToNameAddToDialog( self.name, gridPosition ) self.addToSubmenu() def addToMenu( self, repositoryMenu ): "Add this to the submenu set by MenuButtonDisplay, the repository menu is ignored" self.addToSubmenu() def addToMenuFrameable( self, repositoryMenu ): "Add this to the frameable repository menu." self.addToMenu( repositoryMenu ) def addToSubmenu( self ): "Add this to the submenu." self.activate = False menu = self.menuButtonDisplay.menu menu.add_radiobutton( label = self.name, command = self.clickRadio, value = self.name, variable = self.menuButtonDisplay.radioVar ) self.menuLength = menu.index( Tkinter.END ) if self.value: self.menuButtonDisplay.radioVar.set( self.name ) self.invoke() self.activate = True def clickRadio( self ): "Workaround for Tkinter bug, invoke and set the value when clicked." if not self.activate: return self.menuButtonDisplay.radioVar.set( self.name ) if self.updateFunction != None: self.updateFunction() def getFromMenuButtonDisplay( self, menuButtonDisplay, name, repository, value ): "Initialize." self.getFromValueOnlyAddToRepository( name, repository, value ) self.menuButtonDisplay = menuButtonDisplay self.menuButtonDisplay.menuRadios.append( self ) return self def invoke( self ): "Workaround for Tkinter bug, invoke to set the value when changed." self.menuButtonDisplay.menu.invoke( self.menuLength ) def setStateToValue( self ): "Set the checkbutton to the boolean." try: if self.value: self.invoke() except: pass def setToDisplay( self ): "Set the boolean to the checkbutton." if self.menuButtonDisplay.radioVar != None: self.value = ( self.menuButtonDisplay.radioVar.get() == self.name ) class PluginFrame: "A class to list the profiles." def __init__( self ): "Set the radio." self.gridTable = {} self.latentStringVar = LatentStringVar() self.oldLatentString = '' def addToDialog( self, gridPosition ): "Add this to the dialog." gridPosition.increment() self.gridPosition = gridPosition.getCopy() self.gridPosition.master = gridPosition.master self.createFrame( gridPosition ) def createFrame( self, gridPosition ): "Create the frame." gridVertical = GridVertical( 0, 0 ) gridVertical.master = Tkinter.LabelFrame( gridPosition.master, borderwidth = 3, relief = 'raised' ) gridVertical.master.grid( row = gridPosition.row, column = gridPosition.column, columnspan = 10, sticky = Tkinter.E + Tkinter.W + Tkinter.N + Tkinter.S ) gridPosition.master.grid_rowconfigure( gridPosition.row, weight = 1 ) gridPosition.master.grid_columnconfigure( gridPosition.column + 9, weight = 1 ) if self.latentStringVar.getString() == '': self.defaultRadioButton.setSelect() self.gridTable[ self.latentStringVar.getString() ] = gridVertical path = os.path.join( self.directoryPath, self.latentStringVar.getString() ) pluginModule = gcodec.getModuleWithPath( path ) if pluginModule == None: print( 'this should never happen, pluginModule in addToDialog in PluginFrame in settings is None' ) print( path ) return gridVertical.repository = getReadRepository( pluginModule.getNewRepository() ) gridVertical.frameGridVertical = GridVertical( 0, 0 ) gridVertical.frameGridVertical.setExecutablesRepository( gridVertical.repository ) executeTitle = gridVertical.repository.executeTitle if executeTitle != None: executeButton = Tkinter.Button( gridVertical.master, activebackground = 'black', activeforeground = 'blue', text = executeTitle, command = gridVertical.frameGridVertical.execute ) executeButton.grid( row = gridVertical.row, column = gridVertical.column ) gridVertical.column += 1 self.helpButton = Tkinter.Button( gridVertical.master, activebackground = 'black', activeforeground = 'white', text = "?", command = HelpPageRepository( gridVertical.repository ).openPage ) self.helpButton.grid( row = gridVertical.row, column = gridVertical.column ) addEmptyRow( gridVertical ) gridVertical.increment() gridVertical.xScrollbar = HiddenScrollbar( gridVertical.master, orient = Tkinter.HORIZONTAL ) gridVertical.xScrollbar.grid( row = gridVertical.row + 1, column = gridVertical.column, columnspan = 10, sticky = Tkinter.E + Tkinter.W ) gridVertical.yScrollbar = HiddenScrollbar( gridVertical.master ) gridVertical.yScrollbar.grid( row = gridVertical.row, column = gridVertical.column + 11, sticky = Tkinter.N + Tkinter.S ) canvasHeight = min( 1000, gridPosition.master.winfo_screenheight() - 400 ) - 6 - int( gridVertical.xScrollbar[ 'width' ] ) canvasWidth = min( 650, gridPosition.master.winfo_screenwidth() - 100 ) - 6 - int( gridVertical.yScrollbar[ 'width' ] ) gridVertical.canvas = Tkinter.Canvas( gridVertical.master, height = canvasHeight, highlightthickness = 0, width = canvasWidth ) gridVertical.frameGridVertical.master = Tkinter.Frame( gridVertical.canvas ) for setting in gridVertical.repository.displayEntities: setting.addToDialog( gridVertical.frameGridVertical ) gridVertical.frameGridVertical.master.update_idletasks() gridVertical.xScrollbar.config( command = gridVertical.canvas.xview ) gridVertical.canvas[ 'xscrollcommand' ] = gridVertical.xScrollbar.set gridVertical.yScrollbar.config( command = gridVertical.canvas.yview ) gridVertical.canvas[ 'yscrollcommand' ] = gridVertical.yScrollbar.set gridVertical.canvas.create_window( 0, 0, anchor = Tkinter.NW, window = gridVertical.frameGridVertical.master ) gridVertical.canvas[ 'scrollregion' ] = gridVertical.frameGridVertical.master.grid_bbox() gridVertical.canvas.grid( row = gridVertical.row, column = gridVertical.column, columnspan = 10, sticky = Tkinter.E + Tkinter.W + Tkinter.N + Tkinter.S ) gridVertical.master.grid_rowconfigure( gridVertical.row, weight = 1 ) gridVertical.master.grid_columnconfigure( gridVertical.column + 9, weight = 1 ) gridVertical.frameGridVertical.master.lift() self.oldLatentString = self.latentStringVar.getString() def getFromPath( self, defaultRadioButton, directoryPath, repository ): "Initialize." self.defaultRadioButton = defaultRadioButton self.directoryPath = directoryPath self.name = 'PluginFrame' self.repository = repository repository.archive.append( self ) repository.displayEntities.append( self ) return self def setStateToValue( self ): "Set the state of all the plugins to the value." for gridTableValue in self.gridTable.values(): cancelRepository( gridTableValue.repository ) def setToDisplay( self ): "Set the plugins to the display." pass def update( self ): "Update the frame." if self.oldLatentString == self.latentStringVar.getString(): return self.oldLatentString = self.latentStringVar.getString() self.repository.archive.remove( self ) for setting in self.repository.archive: setting.setToDisplay() writeSettingsPrintMessage( self.repository ) self.repository.archive.append( self ) if self.latentStringVar.getString() in self.gridTable: gridPosition = self.gridTable[ self.latentStringVar.getString() ] gridPosition.master.lift() gridPosition.frameGridVertical.master.focus_set() return self.createFrame( self.gridPosition ) def writeToArchiveWriter( self, archiveWriter ): "Write tab separated name and value to the archive writer." gridTableKeys = self.gridTable.keys() gridTableKeys.sort() for gridTableKey in gridTableKeys: saveRepository( self.gridTable[ gridTableKey ].repository ) class ProfileList: "A class to list the profiles." def getFromName( self, name, repository ): "Initialize." self.craftTypeName = repository.lowerName self.name = name self.repository = repository self.setValueToFolders() return self def setValueToFolders( self ): "Set the value to the folders in the profiles directories." self.value = getFolders( getProfilesDirectoryPath( self.craftTypeName ) ) defaultFolders = getFolders( getProfilesDirectoryInAboveDirectory( self.craftTypeName ) ) for defaultFolder in defaultFolders: if defaultFolder not in self.value: self.value.append( defaultFolder ) self.value.sort() class ProfileListboxSetting( StringSetting ): "A class to handle the profile listbox." def addToDialog( self, gridPosition ): "Add this to the dialog." #http://www.pythonware.com/library/tkinter/introduction/x5453-patterns.htm self.root = gridPosition.master gridPosition.increment() scrollbar = HiddenScrollbar( gridPosition.master ) self.listbox = Tkinter.Listbox( gridPosition.master, selectmode = Tkinter.SINGLE, yscrollcommand = scrollbar.set ) self.listbox.bind( '', self.buttonReleaseOne ) gridPosition.master.bind( '', self.focusIn ) scrollbar.config( command = self.listbox.yview ) self.listbox.grid( row = gridPosition.row, column = 0, sticky = Tkinter.N + Tkinter.S ) scrollbar.grid( row = gridPosition.row, column = 1, sticky = Tkinter.N + Tkinter.S ) self.setStateToValue() self.repository.saveListenerTable[ 'updateProfileSaveListeners' ] = updateProfileSaveListeners def buttonReleaseOne( self, event ): "Button one released." self.setValueToIndex( self.listbox.nearest( event.y ) ) def focusIn( self, event ): "The root has gained focus." getReadRepository( self.repository ) self.setStateToValue() def getFromListSetting( self, listSetting, name, repository, value ): "Initialize." self.getFromValueOnly( name, repository, value ) self.listSetting = listSetting repository.archive.append( self ) repository.displayEntities.append( self ) return self def getSelectedFolder( self ): "Get the selected folder." settingProfileSubfolder = getSubfolderWithBasename( self.value, getProfilesDirectoryPath( self.listSetting.craftTypeName ) ) if settingProfileSubfolder != None: return settingProfileSubfolder toolProfileSubfolder = getSubfolderWithBasename( self.value, getProfilesDirectoryInAboveDirectory( self.listSetting.craftTypeName ) ) return toolProfileSubfolder def setStateToValue( self ): "Set the listbox items to the list setting." self.listbox.delete( 0, Tkinter.END ) for item in self.listSetting.value: self.listbox.insert( Tkinter.END, item ) if self.value == item: self.listbox.select_set( Tkinter.END ) def setToDisplay( self ): "Set the selection value to the listbox selection." currentSelectionTuple = self.listbox.curselection() if len( currentSelectionTuple ) > 0: self.setValueToIndex( int( currentSelectionTuple[ 0 ] ) ) def setValueToIndex( self, index ): "Set the selection value to the index." valueString = self.listbox.get( index ) self.setValueToString( valueString ) def setValueToString( self, valueString ): "Set the value to the value string." self.value = valueString if self.getSelectedFolder() == None: self.value = self.defaultValue if self.getSelectedFolder() == None: if len( self.listSetting.value ) > 0: self.value = self.listSetting.value[ 0 ] class Radio( BooleanSetting ): "A class to display, read & write a boolean with associated radio button." def addToDialog( self, gridPosition ): "Add this to the dialog." gridPosition.increment() self.createRadioButton( gridPosition ) self.radiobutton.grid( row = gridPosition.row, column = 0, columnspan = 3, sticky = Tkinter.W ) self.setStateToValue() def clickRadio( self ): "Workaround for Tkinter bug, set the value." self.latentStringVar.setString( self.radiobutton[ 'value' ] ) if self.updateFunction != None: self.updateFunction() def createRadioButton( self, gridPosition ): "Create the radio button." self.radiobutton = Tkinter.Radiobutton( gridPosition.master, command = self.clickRadio, text = self.name, value = self.name, variable = self.latentStringVar.getVar() ) LabelHelp( self.repository.fileNameHelp, gridPosition.master, self.name, self.radiobutton ) def getFromRadio( self, latentStringVar, name, repository, value ): "Initialize." self.getFromValueOnly( name, repository, value ) self.latentStringVar = latentStringVar repository.archive.append( self ) repository.displayEntities.append( self ) #when addToMenu is added to this entity, the line below should be uncommented # repository.menuEntities.append( self ) return self def setToDisplay( self ): "Set the boolean to the checkbutton." self.value = ( self.latentStringVar.getString() == self.radiobutton[ 'value' ] ) def setSelect( self ): "Set the int var and select the radio button." self.latentStringVar.setString( self.radiobutton[ 'value' ] ) self.radiobutton.select() def setStateToValue( self ): "Set the checkbutton to the boolean." if self.value: self.setSelect() class RadioCapitalized( Radio ): "A class to display, read & write a boolean with associated radio button." def createRadioButton( self, gridPosition ): "Create the radio button." capitalizedName = getEachWordCapitalized( self.name ) self.radiobutton = Tkinter.Radiobutton( gridPosition.master, command = self.clickRadio, text = capitalizedName, value = self.name, variable = self.latentStringVar.getVar() ) class RadioCapitalizedButton( Radio ): "A class to display, read & write a boolean with associated radio button." def createRadioButton( self, gridPosition ): "Create the radio button." capitalizedName = getEachWordCapitalized( self.name ) self.radiobutton = Tkinter.Radiobutton( gridPosition.master, command = self.clickRadio, text = capitalizedName, value = self.name, variable = self.latentStringVar.getVar() ) self.displayButton = Tkinter.Button( gridPosition.master, activebackground = 'black', activeforeground = 'white', text = capitalizedName, command = self.displayDialog ) self.displayButton.grid( row = gridPosition.row, column = 3, columnspan = 2 ) def displayDialog( self ): "Display function." ToolDialog().getFromPath( self.path ).display() self.setSelect() def getFromPath( self, latentStringVar, name, path, repository, value ): "Initialize." self.getFromRadio( latentStringVar, name, repository, value ) self.path = path return self class RadioPlugin( RadioCapitalized ): "A class to display, read & write a boolean with associated radio button." def addToDialog( self, gridPosition ): "Add this to the dialog." self.createRadioButton( gridPosition ) self.radiobutton[ 'activebackground' ] = 'black' self.radiobutton[ 'activeforeground' ] = 'white' self.radiobutton[ 'selectcolor' ] = 'white' self.radiobutton[ 'borderwidth' ] = 3 self.radiobutton[ 'indicatoron' ] = 0 setButtonFontWeightString( self.radiobutton, self.important ) self.incrementGridPosition( gridPosition ) self.setStateToValue() def getFromRadio( self, important, latentStringVar, name, repository, value ): "Initialize." self.important = important return RadioCapitalized.getFromRadio( self, latentStringVar, name, repository, value ) def incrementGridPosition( self, gridPosition ): "Increment the grid position." gridPosition.incrementGivenNumberOfColumns( 8 ) self.radiobutton.grid( row = gridPosition.row, column = gridPosition.column, sticky = Tkinter.W ) class TextSetting( StringSetting ): "A class to display, read & write a text." def __init__( self ): "Set the update function to none." self.tokenConversions = [ TokenConversion(), TokenConversion( 'carriageReturn', '\r' ), TokenConversion( 'doubleQuote', '"' ), TokenConversion( 'newline', '\n' ), TokenConversion( 'semicolon', ';' ), TokenConversion( 'singleQuote', "'" ), TokenConversion( 'tab', '\t' ) ] self.updateFunction = None def addToDialog( self, gridPosition ): "Add this to the dialog." gridPosition.increment() self.label = Tkinter.Label( gridPosition.master, text = self.name ) self.label.grid( row = gridPosition.row, column = 0, columnspan = 3, sticky = Tkinter.W ) gridPosition.increment() self.entry = Tkinter.Text( gridPosition.master ) self.setStateToValue() self.entry.grid( row = gridPosition.row, column = 0, columnspan = 5, sticky = Tkinter.W ) LabelHelp( self.repository.fileNameHelp, gridPosition.master, self.name, self.label ) def getFromValue( self, name, repository, value ): "Initialize." self.getFromValueOnly( name, repository, value ) repository.archive.append( self ) repository.displayEntities.append( self ) return self def setToDisplay( self ): "Set the string to the entry field." valueString = self.entry.get( 1.0, Tkinter.END ) self.setValueToString( valueString ) def setStateToValue( self ): "Set the entry to the value." try: self.entry.delete( 1.0, Tkinter.END ) self.entry.insert( Tkinter.INSERT, self.value ) except: pass def setValueToSplitLine( self, lineIndex, lines, splitLine ): "Set the value to the second word of a split line." replacedValue = splitLine[ 1 ] for tokenConversion in reversed( self.tokenConversions ): replacedValue = tokenConversion.getTokenizedString( replacedValue ) self.setValueToString( replacedValue ) def writeToArchiveWriter( self, archiveWriter ): "Write tab separated name and value to the archive writer." replacedValue = self.value for tokenConversion in self.tokenConversions: replacedValue = tokenConversion.getNamedString( replacedValue ) archiveWriter.write( '%s%s%s\n' % ( self.name, globalSpreadsheetSeparator, replacedValue ) ) class TokenConversion: "A class to convert tokens in a string." def __init__( self, name = 'replaceToken', token = '___replaced___' ): "Set the name and token." self.replacedName = '___replaced___' + name self.token = token def getNamedString( self, text ): "Get a string with the tokens changed to names." return text.replace( self.token, self.replacedName ) def getTokenizedString( self, text ): "Get a string with the names changed to tokens." return text.replace( self.replacedName, self.token ) class ToolDialog: "A class to display the tool repository dialog." def addPluginToMenu( self, menu, path ): "Add the display command to the menu." name = os.path.basename( path ) self.path = path menu.add_command( label = getEachWordCapitalized( name ) + '...', command = self.display ) def display( self ): "Display the tool repository dialog." global globalRepositoryDialogListTable for repositoryDialog in globalRepositoryDialogListTable: if getPathFromFileNameHelp( repositoryDialog.repository.fileNameHelp ) == self.path: liftRepositoryDialogs( globalRepositoryDialogListTable[ repositoryDialog ] ) return self.repositoryDialog = getDisplayedDialogFromPath( self.path ) def getFromPath( self, path ): "Initialize and return display function." self.path = path return self class WindowPosition( StringSetting ): "A class to display, read & write a window position." def addToDialog( self, gridPosition ): "Set the root to later get the geometry." self.root = gridPosition.master self.setToDisplay() def getFromValue( self, repository, value ): "Initialize." self.getFromValueOnly( 'WindowPosition', repository, value ) repository.archive.append( self ) repository.displayEntities.append( self ) return self def setToDisplay( self ): "Set the string to the window position." try: geometryString = self.root.geometry() except: return if geometryString == '1x1+0+0': return firstPlusIndexPlusOne = geometryString.find( '+' ) + 1 self.value = geometryString[ firstPlusIndexPlusOne : ] def setWindowPosition( self ): "Set the window position." movedGeometryString = '%sx%s+%s' % ( self.root.winfo_reqwidth(), self.root.winfo_reqheight(), self.value ) self.root.geometry( movedGeometryString ) class WindowVisibilities: "A class to read & write window visibilities and display them." def addToDialog( self, gridPosition ): "Add this to the dialog." if self.repository.repositoryDialog == None: self.isActive = False return self.isActive = self.repository.repositoryDialog.isFirst if self.isActive: self.repository.repositoryDialog.openDialogListeners.append( self ) def getFromRepository( self, repository ): "Initialize." self.isActive = False self.name = 'WindowVisibilities' self.repository = repository repository.archive.append( self ) repository.displayEntities.append( self ) self.value = [] return self def openDialog( self ): "Create the display button." for item in self.value: getDisplayedDialogFromPath( item ) def setToDisplay( self ): "Set the string to the window position." if not self.isActive: return self.value = [] ownPath = getPathFromFileNameHelp( self.repository.fileNameHelp ) for repositoryDialog in globalRepositoryDialogListTable.keys(): keyPath = getPathFromFileNameHelp( repositoryDialog.repository.fileNameHelp ) if keyPath != ownPath: if keyPath not in self.value: self.value.append( keyPath ) def setStateToValue( self ): "Do nothing because the window visibility is not to be cancelled." pass def setValueToSplitLine( self, lineIndex, lines, splitLine ): "Set the value to the second and later words of a split line." self.value = splitLine[ 1 : ] def writeToArchiveWriter( self, archiveWriter ): "Write tab separated name and list to the archive writer." writeValueListToArchiveWriter( archiveWriter, self ) class RepositoryDialog: def __init__( self, repository, root ): "Add entities to the dialog." self.isFirst = ( len( globalRepositoryDialogListTable.keys() ) == 0 ) self.closeListener = CloseListener( self ) self.repository = repository self.gridPosition = GridVertical( 0, - 1 ) self.gridPosition.setExecutablesRepository( repository ) self.gridPosition.master = root self.root = root self.openDialogListeners = [] repository.repositoryDialog = self root.withdraw() title = repository.title if repository.fileNameInput != None: title = os.path.basename( repository.fileNameInput.value ) + ' - ' + title root.title( title ) fileHelpMenuBar = FileHelpMenuBar( root ) fileHelpMenuBar.completeMenu( self.close, repository, self.save, self ) for setting in repository.displayEntities: setting.addToDialog( self.gridPosition ) if self.gridPosition.row < 20: addEmptyRow( self.gridPosition ) self.addButtons( repository, root ) root.update_idletasks() self.setWindowPositionDeiconify() root.deiconify() for openDialogListener in self.openDialogListeners: openDialogListener.openDialog() def __repr__( self ): "Get the string representation of this RepositoryDialog." return self.repository.title def addButtons( self, repository, root ): "Add buttons to the dialog." columnIndex = 0 self.gridPosition.increment() saveCommand = self.save saveText = 'Save' if self.isFirst: saveCommand = self.saveAll saveText = 'Save All' if repository.executeTitle != None: executeButton = Tkinter.Button( root, activebackground = 'black', activeforeground = 'blue', text = repository.executeTitle, command = self.gridPosition.execute ) executeButton.grid( row = self.gridPosition.row, column = columnIndex ) columnIndex += 1 self.helpButton = Tkinter.Button( root, activebackground = 'black', activeforeground = 'white', text = "?", command = HelpPageRepository( self.repository ).openPage ) self.helpButton.grid( row = self.gridPosition.row, column = columnIndex ) self.closeListener.listenToWidget( self.helpButton ) columnIndex += 5 cancelButton = Tkinter.Button( root, activebackground = 'black', activeforeground = 'orange', command = self.cancel, fg = 'orange', text = 'Cancel' ) cancelButton.grid( row = self.gridPosition.row, column = columnIndex ) columnIndex += 1 self.saveButton = Tkinter.Button( root, activebackground = 'black', activeforeground = 'darkgreen', command = saveCommand, fg = 'darkgreen', text = saveText ) self.saveButton.grid( row = self.gridPosition.row, column = columnIndex ) def cancel( self, event = None ): "Set all entities to their saved state." cancelRepository( self.repository ) def close( self, event = None ): "The dialog was closed." try: self.root.destroy() except: pass def save( self, event = None ): "Set the entities to the dialog then write them." saveRepository( self.repository ) def saveAll( self ): "Save all the dialogs." global globalRepositoryDialogListTable globalRepositoryDialogValues = euclidean.getListTableElements( globalRepositoryDialogListTable ) for globalRepositoryDialogValue in globalRepositoryDialogValues: globalRepositoryDialogValue.save() def setWindowPositionDeiconify( self ): "Set the window position if that setting exists." for setting in self.repository.archive: if setting.name == 'WindowPosition': setting.setWindowPosition() return