Updated build script to create win32/linux/macos versions. Fixed the defaults to they work with PLA. Fixed the temperature plugin default "ON" problem. Removed all profiles except for PLA.
2046 lines
77 KiB
Python
2046 lines
77 KiB
Python
"""
|
|
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 fabmetheus_utilities import archive
|
|
from fabmetheus_utilities import euclidean
|
|
from fabmetheus_utilities import gcodec
|
|
import cStringIO
|
|
import math
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import traceback
|
|
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__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
|
|
|
|
|
|
globalRepositoryDialogListTable = {}
|
|
globalProfileSaveListenerListTable = {}
|
|
globalCloseListTables = [globalRepositoryDialogListTable, globalProfileSaveListenerListTable]
|
|
globalSettingReplacements = {
|
|
'Perimeter Width over Thickness (ratio):' : 'Edge Width over Height (ratio):',
|
|
'Layer Thickness (mm):' : 'Layer Height (mm):',
|
|
'Location Arrival X (mm):' : 'Arrival X (mm):',
|
|
'Location Arrival Y (mm):' : 'Arrival Y (mm):',
|
|
'Location Arrival Z (mm):' : 'Arrival Z (mm):',
|
|
'Location Departure X (mm):' : 'Departure X (mm):',
|
|
'Location Departure Y (mm):' : 'Departure Y (mm):',
|
|
'Location Departure Z (mm):' : 'Departure Z (mm):',
|
|
'Location Wipe X (mm):' : 'Wipe X (mm):',
|
|
'Location Wipe Y (mm):' : 'Wipe Y (mm):',
|
|
'Location Wipe Z (mm):' : 'Wipe Z (mm):'
|
|
}
|
|
globalSpreadsheetSeparator = '\t'
|
|
globalTemporaryOverrides = {}
|
|
|
|
|
|
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 addEmptyRow( gridPosition ):
|
|
"Add an empty row."
|
|
gridPosition.increment()
|
|
Tkinter.Label( gridPosition.master ).grid( row = gridPosition.row, column = gridPosition.column )
|
|
|
|
def addListsToRepository(fileNameHelp, repository):
|
|
'Add the value to the lists.'
|
|
addListsToRepositoryByFunction(fileNameHelp, None, repository)
|
|
|
|
def addListsToRepositoryByFunction(fileNameHelp, getProfileDirectory, repository):
|
|
'Add the value to the lists.'
|
|
repository.displayEntities = []
|
|
repository.executeTitle = None
|
|
repository.fileNameHelp = fileNameHelp
|
|
repository.fileNameInput = None
|
|
repository.lowerName = fileNameHelp.split('.')[-2]
|
|
repository.baseName = repository.lowerName + '.csv'
|
|
repository.baseNameSynonym = None
|
|
repository.baseNameSynonymDictionary = None
|
|
repository.capitalizedName = getEachWordCapitalized( repository.lowerName )
|
|
repository.getProfileDirectory = getProfileDirectory
|
|
repository.openLocalHelpPage = HelpPage().getOpenFromDocumentationSubName( repository.fileNameHelp )
|
|
repository.openWikiManualHelpPage = None
|
|
repository.preferences = []
|
|
repository.repositoryDialog = None
|
|
repository.saveListenerTable = {}
|
|
repository.title = repository.capitalizedName + ' Settings'
|
|
repository.menuEntities = []
|
|
repository.saveCloseTitle = 'Save and Close'
|
|
repository.windowPosition = WindowPosition().getFromValue( repository, '0+0')
|
|
for setting in repository.preferences:
|
|
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 repository values."
|
|
getReadRepository(repository)
|
|
for setting in repository.displayEntities:
|
|
if setting in repository.preferences:
|
|
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 = 0.4 + 0.6 * min( 1.0, abs( 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 getAlterationFile(fileName):
|
|
"Get the file from the fileName or the lowercase fileName in the alterations directories."
|
|
settingsAlterationsDirectory = archive.getSettingsPath('alterations')
|
|
archive.makeDirectory(settingsAlterationsDirectory)
|
|
fileInSettingsAlterationsDirectory = getFileInGivenDirectory(settingsAlterationsDirectory, fileName)
|
|
if fileInSettingsAlterationsDirectory != '':
|
|
return fileInSettingsAlterationsDirectory
|
|
alterationsDirectory = archive.getSkeinforgePath('alterations')
|
|
return getFileInGivenDirectory(alterationsDirectory, fileName)
|
|
|
|
def getAlterationFileLine(fileName):
|
|
"Get the alteration file line from the fileName."
|
|
lines = getAlterationLines(fileName)
|
|
if len(lines) == 0:
|
|
return []
|
|
return getAlterationFileLineBlindly(fileName)
|
|
|
|
def getAlterationFileLineBlindly(fileName):
|
|
"Get the alteration file line from the fileName."
|
|
return '(<alterationFile>) %s (</alterationFile>)' % fileName
|
|
|
|
def getAlterationFileLines(fileName):
|
|
'Get the alteration file line and the text lines from the fileName in the alterations directories.'
|
|
lines = getAlterationLines(fileName)
|
|
if len(lines) == 0:
|
|
return []
|
|
return [getAlterationFileLineBlindly(fileName)] + lines
|
|
|
|
def getAlterationLines(fileName):
|
|
"Get the text lines from the fileName in the alterations directories."
|
|
return archive.getTextLines(getAlterationFile(fileName))
|
|
|
|
def getDisplayedDialogFromConstructor(repository):
|
|
"Display the repository dialog."
|
|
try:
|
|
getReadRepository(repository)
|
|
return RepositoryDialog( repository, Tkinter.Tk() )
|
|
except:
|
|
print('this should never happen, getDisplayedDialogFromConstructor in settings could not open')
|
|
print(repository)
|
|
traceback.print_exc(file=sys.stdout)
|
|
return None
|
|
|
|
def getDisplayedDialogFromPath(path):
|
|
"Display the repository dialog."
|
|
pluginModule = archive.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 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 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 archive.getFileText( absoluteFilePath )
|
|
|
|
def getFolders(directory):
|
|
"Get the folder list in a directory."
|
|
archive.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 getGlobalRepositoryDialogValues():
|
|
"Get the global repository dialog values."
|
|
global globalRepositoryDialogListTable
|
|
return euclidean.getListTableElements(globalRepositoryDialogListTable)
|
|
|
|
def getPathInFabmetheusFromFileNameHelp( fileNameHelp ):
|
|
"Get the directory path from file name help."
|
|
fabmetheusPath = archive.getFabmetheusPath()
|
|
splitFileNameHelps = fileNameHelp.split('.')
|
|
splitFileNameDirectoryNames = splitFileNameHelps[ : - 1 ]
|
|
for splitFileNameDirectoryName in splitFileNameDirectoryNames:
|
|
fabmetheusPath = os.path.join( fabmetheusPath, splitFileNameDirectoryName )
|
|
return fabmetheusPath
|
|
|
|
def getProfileBaseName(repository):
|
|
"Get the profile base file name."
|
|
return getProfileName(repository.baseName, repository)
|
|
|
|
def getProfilesDirectoryInAboveDirectory(subName=''):
|
|
"Get the profiles directory path in the above directory."
|
|
aboveProfilesDirectory = archive.getSkeinforgePath('profiles')
|
|
if subName == '':
|
|
return aboveProfilesDirectory
|
|
return os.path.join( aboveProfilesDirectory, subName )
|
|
|
|
def getProfileName(name, repository):
|
|
"Get the name, joined with the profile directory if there is one."
|
|
if repository.getProfileDirectory == None:
|
|
return name
|
|
return os.path.join(repository.getProfileDirectory(), name)
|
|
|
|
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 getReadRepository(repository):
|
|
"Read and return settings from a file."
|
|
text = archive.getFileText(archive.getProfilesPath(getProfileBaseName(repository)), False)
|
|
if text == '':
|
|
if repository.baseNameSynonym != None:
|
|
text = archive.getFileText(archive.getProfilesPath(getProfileName(repository.baseNameSynonym, repository)), False)
|
|
if text == '':
|
|
print('The default %s will be written in the .skeinforge_pypy folder in the home directory.' % repository.title.lower() )
|
|
text = archive.getFileText(getProfilesDirectoryInAboveDirectory(getProfileBaseName(repository)), False)
|
|
if text != '':
|
|
readSettingsFromText(repository, text)
|
|
writeSettings(repository)
|
|
temporaryApplyOverrides(repository)
|
|
return repository
|
|
readSettingsFromText(repository, text)
|
|
temporaryApplyOverrides(repository)
|
|
return repository
|
|
|
|
def getRepositoryText(repository):
|
|
"Get the text representation of the repository."
|
|
repositoryWriter = getRepositoryWriter(repository.title.lower())
|
|
for setting in repository.preferences:
|
|
setting.writeToRepositoryWriter(repositoryWriter)
|
|
return repositoryWriter.getvalue()
|
|
|
|
def getRepositoryWriter(title):
|
|
"Get the repository writer for the title."
|
|
repositoryWriter = cStringIO.StringIO()
|
|
repositoryWriter.write('Format is tab separated %s.\n' % title)
|
|
repositoryWriter.write('_Name %sValue\n' % globalSpreadsheetSeparator)
|
|
return repositoryWriter
|
|
|
|
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 getShortestUniqueSettingName(settingName, settings):
|
|
"Get the shortest unique name in the settings."
|
|
for length in xrange(3, len(settingName)):
|
|
numberOfEquals = 0
|
|
shortName = settingName[: length]
|
|
for setting in settings:
|
|
if setting.name[: length] == shortName:
|
|
numberOfEquals += 1
|
|
if numberOfEquals < 2:
|
|
return shortName.lower()
|
|
return settingName.lower()
|
|
|
|
def getSubfolderWithBasename( basename, directory ):
|
|
"Get the subfolder in the directory with the basename."
|
|
archive.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 getUntilFirstBracket(text):
|
|
'Get the text until the first bracket, if any.'
|
|
dotIndex = text.find('(')
|
|
if dotIndex < 0:
|
|
return text
|
|
return text[: dotIndex]
|
|
|
|
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 openSVGPage( fileName, svgViewer ):
|
|
"Open svg page with an svg program."
|
|
if svgViewer == '':
|
|
return
|
|
if svgViewer == 'webbrowser':
|
|
openWebPage(fileName)
|
|
return
|
|
filePath = '"' + os.path.normpath(fileName) + '"' # " to send in file name with spaces
|
|
shellCommand = svgViewer + ' ' + filePath
|
|
commandResult = os.system(shellCommand)
|
|
if commandResult != 0:
|
|
print('It may be that the system could not find the %s program.' % svgViewer )
|
|
print('If so, try installing the %s program or look for another svg viewer, like Netscape which can be found at:' % svgViewer )
|
|
print('http://www.netscape.org/')
|
|
print('')
|
|
|
|
def openWebPage( webPagePath ):
|
|
"Open a web page in a browser."
|
|
if webPagePath.find('#') != - 1: # to get around # encode bug
|
|
redirectionText = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">\n<html>\n<head>\n'
|
|
redirectionText += '<meta http-equiv="REFRESH" content="0;url=%s"></head>\n</HTML>\n' % webPagePath
|
|
webPagePath = archive.getDocumentationPath('redirect.html')
|
|
archive.writeFileText( webPagePath, redirectionText )
|
|
webPagePath = '"%s"' % webPagePath # " to get around space in url bug
|
|
try: # " to get around using gnome-open or internet explorer for webbrowser default
|
|
webbrowserController = webbrowser.get('firefox')
|
|
except:
|
|
webbrowserController = webbrowser.get()
|
|
webbrowserName = webbrowserController.name
|
|
if webbrowserName == '':
|
|
try:
|
|
os.startfile( webPagePath )#this is available on some python environments, but not all
|
|
return
|
|
except:
|
|
pass
|
|
print('Skeinforge was not able to open the file in a web browser. To see the documentation, open the following file in a web browser:')
|
|
print(webPagePath)
|
|
return
|
|
else:
|
|
os.system(webbrowserName + ' ' + webPagePath)#used this instead of webbrowser.open() to workaround webbrowser open() bug
|
|
|
|
def printProgress(layerIndex, procedureName):
|
|
"Print layerIndex followed by a carriage return."
|
|
printProgressByString('%s layer count %s...' % (procedureName.capitalize(), layerIndex + 1))
|
|
|
|
def printProgressByNumber(layerIndex, numberOfLayers, procedureName):
|
|
"Print layerIndex and numberOfLayers followed by a carriage return."
|
|
printProgressByString('%s layer count %s of %s...' % (procedureName.capitalize(), layerIndex + 1, numberOfLayers))
|
|
|
|
def printProgressByString(progressString):
|
|
"Print progress string."
|
|
sys.stdout.write(progressString)
|
|
sys.stdout.write(chr(27) + '\r')
|
|
sys.stdout.flush()
|
|
|
|
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."
|
|
text = text.replace(('\nName %sValue\n' % globalSpreadsheetSeparator), ('\n_Name %sValue\n' % globalSpreadsheetSeparator))
|
|
lines = archive.getTextLines(text)
|
|
shortDictionary = {}
|
|
for setting in repository.preferences:
|
|
shortDictionary[getShortestUniqueSettingName(setting.name, repository.preferences)] = setting
|
|
if repository.baseNameSynonymDictionary != None:
|
|
synonymDictionaryCopy = repository.baseNameSynonymDictionary.copy()
|
|
for line in lines:
|
|
splitLine = line.split(globalSpreadsheetSeparator)
|
|
if len(splitLine) > 1:
|
|
if splitLine[0] in synonymDictionaryCopy:
|
|
del synonymDictionaryCopy[splitLine[0]]
|
|
for synonymDictionaryCopyKey in synonymDictionaryCopy.keys():
|
|
text = archive.getFileText(archive.getProfilesPath(getProfileName(synonymDictionaryCopy[synonymDictionaryCopyKey], repository)), False)
|
|
synonymLines = archive.getTextLines(text)
|
|
for synonymLine in synonymLines:
|
|
splitLine = synonymLine.split(globalSpreadsheetSeparator)
|
|
if len(splitLine) > 1:
|
|
if splitLine[0] == synonymDictionaryCopyKey:
|
|
lines.append(synonymLine)
|
|
for lineIndex in xrange(len(lines)):
|
|
setRepositoryToLine(lineIndex, lines, shortDictionary)
|
|
|
|
def saveAll():
|
|
"Save all the dialogs."
|
|
for globalRepositoryDialogValue in getGlobalRepositoryDialogValues():
|
|
globalRepositoryDialogValue.save()
|
|
|
|
def saveRepository(repository):
|
|
"Set the entities to the dialog then write them."
|
|
for setting in repository.preferences:
|
|
setting.setToDisplay()
|
|
writeSettingsPrintMessage(repository)
|
|
for saveListener in repository.saveListenerTable.values():
|
|
saveListener()
|
|
|
|
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 setRepositoryToLine(lineIndex, lines, shortDictionary):
|
|
"Set setting dictionary to a setting line.globalSettingReplacements"
|
|
line = lines[lineIndex]
|
|
splitLine = line.split(globalSpreadsheetSeparator)
|
|
if len(splitLine) < 2:
|
|
return
|
|
fileSettingName = splitLine[0]
|
|
if fileSettingName in globalSettingReplacements:
|
|
fileSettingName = globalSettingReplacements[fileSettingName]
|
|
shortDictionaryKeys = shortDictionary.keys()
|
|
shortDictionaryKeys.sort(key=len, reverse=True) # so that a short word like fill is not overidden by a longer word like fillet
|
|
for shortDictionaryKey in shortDictionaryKeys:
|
|
if fileSettingName[: len(shortDictionaryKey)].lower() == shortDictionaryKey:
|
|
shortDictionary[shortDictionaryKey].setValueToSplitLine(lineIndex, lines, splitLine)
|
|
return
|
|
|
|
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.75 * setting.increment:
|
|
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."
|
|
try:
|
|
import Tkinter
|
|
except:
|
|
return
|
|
displayedDialogFromConstructor = getDisplayedDialogFromConstructor(repository)
|
|
if displayedDialogFromConstructor == None:
|
|
print('Warning, displayedDialogFromConstructor in settings is none, so the window will not be displayed.')
|
|
else:
|
|
displayedDialogFromConstructor.root.mainloop()
|
|
|
|
def startMainLoopFromWindow(window):
|
|
'Display the tableau window and start the main loop.'
|
|
if window == None:
|
|
return
|
|
if window.root == None:
|
|
print('Warning, window.root in startMainLoopFromWindow in settings is none, so the window will not be displayed.')
|
|
return
|
|
window.root.mainloop()
|
|
|
|
def temporaryAddPreferenceOverride(module, name, value):
|
|
global globalTemporaryOverrides
|
|
if not module in globalTemporaryOverrides:
|
|
globalTemporaryOverrides[module] = {}
|
|
globalTemporaryOverrides[module][name] = value
|
|
print('OVERRIDE %s %s %s' % (module,name,value))
|
|
print(globalTemporaryOverrides[module])
|
|
|
|
def temporaryApplyOverrides(repository):
|
|
'Apply any overrides that have been set at the command line.'
|
|
# The override dictionary is a mapping of repository names to
|
|
# key-value mappings.
|
|
global globalTemporaryOverrides
|
|
if repository.baseName in globalTemporaryOverrides:
|
|
settingTable = {}
|
|
for setting in repository.preferences:
|
|
settingTable[ setting.name ] = setting
|
|
for (name, value) in overrides[repository.baseName].items():
|
|
if name in settingTable:
|
|
settingTable[name].setValueToString(value)
|
|
else:
|
|
print('Override not applied for: %s, %s' % (name,value))
|
|
|
|
def writeSettings(repository):
|
|
"Write the settings to a file."
|
|
profilesDirectoryPath = archive.getProfilesPath(getProfileBaseName(repository))
|
|
archive.makeDirectory(os.path.dirname(profilesDirectoryPath))
|
|
archive.writeFileText(profilesDirectoryPath, getRepositoryText(repository))
|
|
for setting in repository.preferences:
|
|
setting.updateSaveListeners()
|
|
|
|
def writeSettingsPrintMessage(repository):
|
|
"Set the settings to the dialog then write them."
|
|
writeSettings(repository)
|
|
print(repository.title.lower().capitalize() + ' have been saved.')
|
|
|
|
def writeValueListToRepositoryWriter( repositoryWriter, setting ):
|
|
"Write tab separated name and list to the repository writer."
|
|
repositoryWriter.write( setting.name )
|
|
for item in setting.value:
|
|
if item != '[]':
|
|
repositoryWriter.write(globalSpreadsheetSeparator)
|
|
repositoryWriter.write( item )
|
|
repositoryWriter.write('\n')
|
|
|
|
|
|
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 __repr__(self):
|
|
"Get the string representation of this StringSetting."
|
|
return str(self.__dict__)
|
|
|
|
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('<Return>', 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.displayEntities.append(self)
|
|
repository.menuEntities.append(self)
|
|
repository.preferences.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 updateSaveListeners(self):
|
|
"Update save listeners if any."
|
|
pass
|
|
|
|
def writeToRepositoryWriter( self, repositoryWriter ):
|
|
"Write tab separated name and value to the repository writer."
|
|
repositoryWriter.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
|
|
euclidean.addElementToListDictionaryIfNotThere( window, window, globalRepositoryDialogListTable )
|
|
|
|
def listenToWidget( self, widget ):
|
|
"Listen to the destroy message of the widget."
|
|
if self.shouldWasClosedBeBound:
|
|
self.shouldWasClosedBeBound = False
|
|
widget.bind('<Destroy>', 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 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 = archive.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('<Control-KeyPress-s>', saveFunction, self.root, self.fileMenu, 'Save')
|
|
self.fileMenu.add_command(label = "Save and Close", command = self.saveClose)
|
|
addAcceleratorCommand('<Control-KeyPress-w>', closeFunction, self.root, self.fileMenu, 'Close')
|
|
self.fileMenu.add_separator()
|
|
addAcceleratorCommand('<Control-KeyPress-q>', quitWindows, self.root, self.fileMenu, 'Quit')
|
|
skeinforgePluginsPath = archive.getSkeinforgePath('skeinforge_plugins')
|
|
pluginFileNames = archive.getPluginFileNamesFromDirectoryPath(skeinforgePluginsPath)
|
|
for pluginFileName in pluginFileNames:
|
|
self.addPluginToMenuBar(os.path.join(skeinforgePluginsPath, 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 = archive.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."
|
|
allFiles = [ ('All', '*.*') ]
|
|
try:
|
|
basename = os.path.basename(self.value)
|
|
splitFile = basename.split('.')
|
|
allReadables = []
|
|
if len( self.fileTypes ) > 1:
|
|
for fileType in self.fileTypes:
|
|
allReadable = ( ('All Readable', fileType[1] ) )
|
|
allReadables.append( allReadable )
|
|
if len( splitFile ) < 1:
|
|
return allReadables + allFiles + self.fileTypes
|
|
baseExtension = splitFile[-1]
|
|
for fileType in self.fileTypes:
|
|
fileExtension = fileType[1].split('.')[-1]
|
|
if fileExtension == baseExtension:
|
|
fileNameFirstTypes = self.fileTypes[:]
|
|
fileNameFirstTypes.remove( fileType )
|
|
return [ fileType ] + allReadables + allFiles + fileNameFirstTypes
|
|
return allReadables + allFiles + self.fileTypes
|
|
except:
|
|
return allFiles
|
|
|
|
def getFromFileName( self, fileTypes, name, repository, value ):
|
|
"Initialize."
|
|
self.getFromValueOnly( name, repository, value )
|
|
self.fileTypes = fileTypes
|
|
self.wasCancelled = False
|
|
repository.displayEntities.append(self)
|
|
repository.preferences.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('<Return>', 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.minimumWidth = min(value - from_, to - value)
|
|
rank = euclidean.getRank(0.05 * (to - from_))
|
|
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.displayEntities.append(self)
|
|
repository.preferences.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.preferences.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 updateSaveListeners(self):
|
|
"Update save listeners if any."
|
|
pass
|
|
|
|
def writeToRepositoryWriter( self, repositoryWriter ):
|
|
"Write tab separated name and list to the repository writer."
|
|
writeValueListToRepositoryWriter( repositoryWriter, 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()
|
|
saveAll()
|
|
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 __init__(self):
|
|
"Initialize column."
|
|
self.column = 3
|
|
|
|
def addToDialog( self, gridPosition ):
|
|
"Add this to the dialog."
|
|
capitalizedName = getEachWordCapitalized( self.name )
|
|
self.displayButton = Tkinter.Button( gridPosition.master, activebackground = 'black', activeforeground = 'white', command = self.openPage, text = capitalizedName )
|
|
if len( capitalizedName ) < 12:
|
|
self.displayButton['width'] = 10
|
|
self.displayButton.grid( row = gridPosition.row, column = self.column, 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 = archive.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 = archive.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_application.skeinforge_utilities import skeinforge_help
|
|
helpRepository = getReadRepository( skeinforge_help.HelpRepository() )
|
|
if helpRepository.wikiManualPrimary.value:
|
|
self.repository.openWikiManualHelpPage()
|
|
return
|
|
self.repository.openLocalHelpPage()
|
|
|
|
|
|
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_
|
|
rank = euclidean.getRank(0.05 * (to - from_))
|
|
self.increment = max(1, int(euclidean.getIncrementFromRank(rank)))
|
|
self.minimumWidth = min(value - from_, to - value)
|
|
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.increment = 1
|
|
self.minimumWidth = min(value - from_, to - value)
|
|
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.displayEntities.append(self)
|
|
repository.preferences.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 = self.columnspan, sticky = Tkinter.W )
|
|
LabelHelp( self.repository.fileNameHelp, gridPosition.master, self.name, self.label )
|
|
|
|
def getFromName( self, name, repository ):
|
|
"Initialize."
|
|
self.columnspan = 3
|
|
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('<Button-1>', self.unpostPopupMenu )
|
|
widget.bind('<Button-2>', self.unpostPopupMenu )
|
|
widget.bind('<Button-3>', self.displayPopupMenu )
|
|
|
|
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()
|
|
|
|
def unpostPopupMenu(self, event=None):
|
|
'Unpost the popup menu.'
|
|
self.popupMenu.unpost()
|
|
|
|
|
|
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.name = ''
|
|
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 getString(self):
|
|
"Get the string."
|
|
return self.getVar().get()
|
|
|
|
def getVar(self):
|
|
"Get the string var."
|
|
if self.stringVar == None:
|
|
self.stringVar = Tkinter.StringVar()
|
|
return self.stringVar
|
|
|
|
def setString(self, word):
|
|
"Set the string."
|
|
self.getVar().set(word)
|
|
|
|
|
|
class LayerCount:
|
|
'A class to handle the layerIndex.'
|
|
def __init__(self):
|
|
'Initialize.'
|
|
self.layerIndex = -1
|
|
|
|
def __repr__(self):
|
|
'Get the string representation of this LayerCount.'
|
|
return str(self.layerIndex)
|
|
|
|
def printProgressIncrement(self, procedureName):
|
|
'Print progress then increment layerIndex.'
|
|
self.layerIndex += 1
|
|
printProgress(self.layerIndex, procedureName)
|
|
|
|
|
|
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.columnspan = 2
|
|
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 = self.columnspan, 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 display the plugins in a frame."
|
|
def __init__(self):
|
|
"Initialize."
|
|
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 = 12, sticky = Tkinter.E + Tkinter.W + Tkinter.N + Tkinter.S )
|
|
gridPosition.master.grid_rowconfigure( gridPosition.row, weight = 1 )
|
|
gridPosition.master.grid_columnconfigure( gridPosition.column + 11, 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 = archive.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, sticky = Tkinter.W )
|
|
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, sticky = Tkinter.W )
|
|
addEmptyRow( gridVertical )
|
|
gridVertical.increment()
|
|
from fabmetheus_utilities.hidden_scrollbar import HiddenScrollbar
|
|
gridVertical.xScrollbar = HiddenScrollbar( gridVertical.master, orient = Tkinter.HORIZONTAL )
|
|
gridVertical.xScrollbar.grid( row = gridVertical.row + 1, column = gridVertical.column, columnspan = 11, sticky = Tkinter.E + Tkinter.W )
|
|
gridVertical.yScrollbar = HiddenScrollbar( gridVertical.master )
|
|
gridVertical.yScrollbar.grid( row = gridVertical.row, column = gridVertical.column + 12, sticky = Tkinter.N + Tkinter.S )
|
|
canvasHeight = min( 1000, gridPosition.master.winfo_screenheight() - 540 ) - 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 )
|
|
addEmptyRow( 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 = 12, sticky = Tkinter.E + Tkinter.W + Tkinter.N + Tkinter.S )
|
|
gridVertical.master.grid_rowconfigure( gridVertical.row, weight = 1 )
|
|
gridVertical.master.grid_columnconfigure( gridVertical.column + 11, weight = 1 )
|
|
gridVertical.frameGridVertical.master.lift()
|
|
self.oldLatentString = self.latentStringVar.getString()
|
|
|
|
def focusSetMaster( self, gridPosition ):
|
|
"Set the focus to the plugin master."
|
|
gridPosition.frameGridVertical.master.focus_set()
|
|
|
|
def getFromPath( self, defaultRadioButton, directoryPath, repository ):
|
|
"Initialize."
|
|
self.defaultRadioButton = defaultRadioButton
|
|
self.directoryPath = directoryPath
|
|
self.name = 'PluginFrame'
|
|
self.repository = repository
|
|
repository.displayEntities.append(self)
|
|
repository.preferences.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 len(self.gridTable) < 1:
|
|
return
|
|
if self.oldLatentString == self.latentStringVar.getString():
|
|
return
|
|
self.oldLatentString = self.latentStringVar.getString()
|
|
self.repository.preferences.remove(self)
|
|
for setting in self.repository.preferences:
|
|
setting.setToDisplay()
|
|
writeSettingsPrintMessage(self.repository)
|
|
self.repository.preferences.append(self)
|
|
if self.latentStringVar.getString() in self.gridTable:
|
|
gridPosition = self.gridTable[self.latentStringVar.getString()]
|
|
gridPosition.master.lift()
|
|
self.focusSetMaster(gridPosition)
|
|
return
|
|
self.createFrame(self.gridPosition)
|
|
|
|
def updateSaveListeners(self):
|
|
"Update save listeners if any."
|
|
gridTableKeys = self.gridTable.keys()
|
|
gridTableKeys.sort()
|
|
for gridTableKey in gridTableKeys:
|
|
saveRepository( self.gridTable[ gridTableKey ].repository )
|
|
|
|
def writeToRepositoryWriter( self, repositoryWriter ):
|
|
"Write tab separated name and value to the repository writer."
|
|
pass
|
|
|
|
|
|
class PluginGroupFrame( PluginFrame ):
|
|
"A class to display the plugin groups in a frame."
|
|
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 = 11, sticky = Tkinter.E + Tkinter.W + Tkinter.N + Tkinter.S )
|
|
gridPosition.master.grid_rowconfigure( gridPosition.row, weight = 1 )
|
|
gridPosition.master.grid_columnconfigure( gridPosition.column + 10, 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 = archive.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.setExecutablesRepository( gridVertical.repository )
|
|
executeTitle = gridVertical.repository.executeTitle
|
|
if executeTitle != None:
|
|
executeButton = Tkinter.Button( gridVertical.master, activebackground = 'black', activeforeground = 'blue', text = executeTitle, command = gridVertical.execute )
|
|
executeButton.grid( row = gridVertical.row, column = gridVertical.column, sticky = Tkinter.W )
|
|
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, sticky = Tkinter.W )
|
|
addEmptyRow( gridVertical )
|
|
gridVertical.increment()
|
|
for setting in gridVertical.repository.displayEntities:
|
|
setting.addToDialog( gridVertical )
|
|
gridVertical.master.update_idletasks()
|
|
gridVertical.master.lift()
|
|
self.oldLatentString = self.latentStringVar.getString()
|
|
|
|
def focusSetMaster( self, gridPosition ):
|
|
"Set the focus to the plugin master."
|
|
gridPosition.master.focus_set()
|
|
|
|
|
|
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.displayEntities.append(self)
|
|
repository.preferences.append(self)
|
|
#when addToMenu is added to this entity, the line below should be uncommented
|
|
# repository.menuEntities.append(self)
|
|
return self
|
|
|
|
def setSelect(self):
|
|
"Set the int var and select the radio button."
|
|
oldLatentStringValue = self.latentStringVar.getString()
|
|
self.latentStringVar.setString( self.radiobutton['value'] )
|
|
self.radiobutton.select()
|
|
if oldLatentStringValue == '':
|
|
return False
|
|
return oldLatentStringValue != self.latentStringVar.getString()
|
|
|
|
def setStateToValue(self):
|
|
"Set the checkbutton to the boolean."
|
|
if self.value:
|
|
if self.setSelect():
|
|
if self.updateFunction != None:
|
|
self.updateFunction()
|
|
|
|
def setToDisplay(self):
|
|
"Set the boolean to the checkbutton."
|
|
self.value = ( self.latentStringVar.getString() == self.radiobutton['value'] )
|
|
|
|
|
|
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['activeforeground'] = 'magenta'
|
|
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( 10 )
|
|
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.displayEntities.append(self)
|
|
repository.preferences.append(self)
|
|
return self
|
|
|
|
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 setToDisplay(self):
|
|
"Set the string to the entry field."
|
|
valueString = self.entry.get( 1.0, Tkinter.END )
|
|
self.setValueToString( valueString )
|
|
|
|
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 writeToRepositoryWriter( self, repositoryWriter ):
|
|
"Write tab separated name and value to the repository writer."
|
|
replacedValue = self.value
|
|
for tokenConversion in self.tokenConversions:
|
|
replacedValue = tokenConversion.getNamedString( replacedValue )
|
|
repositoryWriter.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 getPathInFabmetheusFromFileNameHelp( 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.displayEntities.append(self)
|
|
repository.preferences.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 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 = 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, columnspan = 2, sticky = Tkinter.W )
|
|
columnIndex += 2
|
|
self.helpButton = Tkinter.Button( root, activebackground = 'black', activeforeground = 'white', text = "?", command = HelpPageRepository(self.repository).openPage )
|
|
self.helpButton.grid( row = self.gridPosition.row, column = columnIndex, sticky = Tkinter.W )
|
|
self.closeListener.listenToWidget( self.helpButton )
|
|
columnIndex += 6
|
|
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 setWindowPositionDeiconify(self):
|
|
"Set the window position if that setting exists."
|
|
for setting in self.repository.preferences:
|
|
if setting.name == 'WindowPosition':
|
|
setting.setWindowPosition()
|
|
return
|