908 lines
38 KiB
Python
Executable File
908 lines
38 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
The main code. This code will look at the command line arguments. If
|
|
an invalid number of arguments are given, it will return an error.
|
|
Otherwise, it will read the commandline arguments. If one argument
|
|
is given, the code will assume the class name is the same as the
|
|
module name, and try to import the class. Otherwise, it will import
|
|
the given class from the given module and try to make an instance
|
|
of it.
|
|
This code will first try to run ._parameters and ._facilities
|
|
method of the instance. Then, it will check the dictionaryOfVariables
|
|
of the Insar class to see what components may be required. If it is
|
|
not empty, it will make a GUI with the following components:
|
|
- Label to indicate the component name, and whether or not its optional
|
|
- An entry box for the user to input the value for the component
|
|
- Buttons for each facility to allow user to
|
|
change the component of each one
|
|
- A Save button to save the component values, as well as the components
|
|
of the facilities that the user has saved
|
|
- A button to switch between saving a single xml file or saving
|
|
the xml file using multiple xml files
|
|
- A Reset all button, which resets all the inputted data in program
|
|
- A button to allow the user to use an existing xml file to change
|
|
data
|
|
- A quit button to quit the GUI
|
|
|
|
Global Variables Used: parameters, dictionaryOfFacilities, facilityButtons,
|
|
facilityDirs, classInstance, description, allParams,
|
|
singleFile, directory, facilityParams
|
|
|
|
"""
|
|
import sys
|
|
import os
|
|
from StringIO import StringIO
|
|
import Tkinter as tk
|
|
import tkFileDialog, tkMessageBox, tkFont
|
|
import xml.etree.ElementTree as ElementTree
|
|
|
|
import isce
|
|
from iscesys.Compatibility import Compatibility
|
|
Compatibility.checkPythonVersion()
|
|
#from insarApp import Insar
|
|
import traceback
|
|
from xml.parsers.expat import ExpatError
|
|
|
|
"""
|
|
Global Definitions:
|
|
|
|
classInstance - The instance of Insar that is created. This is the instance
|
|
which has the dictionaryOfVariables and dictionaryOfFacilities
|
|
attributes.
|
|
|
|
allParams - A dictionary of dictionaries containing all the parameters that
|
|
have been set so far.
|
|
|
|
parameters - a list containing class instances of class parameter, used to
|
|
access the user entry and the name and whether or not it is
|
|
optional in a clean manner.
|
|
|
|
description - a description of variables for parameters
|
|
|
|
|
|
facilityParams - a list containing instances of class parameter, used
|
|
to access the user entry for the facility's parameter
|
|
more easily, similar to global variable parameters.
|
|
|
|
dictionaryOfFaciliites - the dictionaryOfFacilities, contains the names
|
|
of all the facilities, as well as its factorymodule,
|
|
which is the path to the module containing its
|
|
factoryname, which creates an instance of the
|
|
facility
|
|
|
|
facilitiyButtons - The buttons, which causes a GUI for the facility to pop up
|
|
when pressed. They are disabled when a facility GUI is
|
|
already present.
|
|
|
|
facilityDirs - A dictionary containing the locations that the
|
|
user saved the xml file for each key, which is the
|
|
facility name.
|
|
|
|
root2 - The Tk instance for the second GUI, whcih should be the
|
|
GUI for the facility's parameters.
|
|
|
|
rootName - The name that the component in the xml is saved under.
|
|
This value is either the name of a facility or 'insarApp'.
|
|
|
|
directory - The directory at which the most recent file was saved.
|
|
|
|
singleFile - A boolean which indicates whether or not to save
|
|
the final XML file as a single file or multiple XML in
|
|
catalog format.
|
|
"""
|
|
|
|
class RefactorWarning(DeprecationWarning):
|
|
"""put in to alert uses that the code needs to be refactored.
|
|
Take out the raising if you don't like it"""
|
|
pass
|
|
|
|
class parameter:
|
|
"""Class parameter used to keep track of a parameter and its related objects
|
|
|
|
Class Members:
|
|
key: The name of the parameter
|
|
text: The text widget used for inputting data of this parameter
|
|
optional: Indicates whether or not this parameter is optional
|
|
attrib: The name this parameter has as an Insar class attribute
|
|
"""
|
|
def __init__(self, key=None, text=None, optional=None, attrib = None):
|
|
self.key = key
|
|
self.text = text
|
|
self.optional = optional
|
|
self.attrib = attrib
|
|
|
|
def indent(elem, level=0):
|
|
"""Indent an XML ElementTree"""
|
|
i = "\n" + level*" "
|
|
if len(elem):
|
|
if not elem.text or not elem.text.strip():
|
|
elem.text = i + " "
|
|
if not elem.tail or not elem.tail.strip():
|
|
elem.tail = i
|
|
for elem in elem:
|
|
indent(elem, level+1)
|
|
if not elem.tail or not elem.tail.strip():
|
|
elem.tail = i
|
|
else:
|
|
if level and (not elem.tail or not elem.tail.strip()):
|
|
elem.tail = i
|
|
|
|
|
|
## Creates the Input XML file given the user's inputs.
|
|
## If the user has missed a mandatory field in the current level GUI,
|
|
## this will cause a pop-up box to appear and tell the user to
|
|
## fill in the mandatory fields. Otherwise, it will ask the
|
|
## user for a directory to save the xml file in and create the
|
|
## xml file given their inputs. If making the final xml file,
|
|
## i.e the input file for the insarApp, it will also add any
|
|
## directories created by using a catalog.
|
|
##
|
|
## global variables used - directory, facilityDirs, facilityButtons,
|
|
## singleFile, allParams
|
|
def createInputXML(parameters, rootName):
|
|
"""Creates the Input XML File given the user inputs
|
|
Arguments:
|
|
parameters - A list of parameters to be inputted into the xml file
|
|
rootName - The name of the root
|
|
"""
|
|
# Get necessary global variables
|
|
global directory
|
|
global facilityDirs
|
|
global facilityButtons
|
|
global facilityRequired
|
|
global singleFile
|
|
global allParams
|
|
# Checks if any of the manadatory fields are blank.
|
|
for param in parameters:
|
|
if(not(param.optional) and param.text.get()==''):
|
|
tkMessageBox.showerror('ERROR!', 'Mandatory Field(s) is blank!')
|
|
return False
|
|
# If rootName is insarApp, and it is in multi file XML mode,
|
|
# then the user should have, by either loading an XML which is
|
|
# in that form or creating multiple files, a file for each facility.
|
|
if(rootName == 'insarApp' and not singleFile):
|
|
for x in zip(facilityButtons,facilityRequired):
|
|
button = x[0]
|
|
req = x[1]
|
|
try:
|
|
if(facilityDirs[button.cget('text')]=='' and req):
|
|
raise KeyError
|
|
except KeyError:
|
|
tkMessageBox.showerror('ERROR!',
|
|
'Facility parameters not saved in a file for:\n' +
|
|
button.cget('text'))
|
|
return False
|
|
# If rootName is insarApp and it is in single file XML mode,
|
|
# then the user should have, by either loading an XML file or
|
|
# by inputting and saving, have data for each facility.
|
|
elif(rootName == 'insarApp' and singleFile):
|
|
for x in zip(facilityButtons,facilityRequired):
|
|
button = x[0]
|
|
req = x[1]
|
|
try:
|
|
if(allParams[button.cget('text')] == {} and req):
|
|
raise KeyError
|
|
except KeyError:
|
|
tkMessageBox.showerror('ERROR!',
|
|
'Facility parameters not set in:\n' +
|
|
button.cget('text'))
|
|
return False
|
|
# Get a directory from the user to save in if we are in multi file XML
|
|
# mode and/or is saving the insarApp input file.
|
|
if(not singleFile or rootName == 'insarApp'):
|
|
directory = tkFileDialog.asksaveasfilename(initialfile=rootName+'.xml',
|
|
title="Choose where to save:",
|
|
defaultextension='.xml',
|
|
filetypes=[('xml files', '.xml')])
|
|
if(not directory):
|
|
return False
|
|
else:
|
|
# Create the input xml file using ElementTree.
|
|
top = ElementTree.Element(rootName)
|
|
top.text='\n'
|
|
root = ElementTree.SubElement(top,'component', {'name':rootName})
|
|
for param in parameters:
|
|
if(param.text.get()!=''):
|
|
property = ElementTree.SubElement(root,'property', {'name':param.key})
|
|
value = ElementTree.SubElement(property,'value')
|
|
value.text = param.text.get()
|
|
# If this is the insarApp input file, we must put the
|
|
# directory of all the input xml files for the facilities
|
|
if(rootName == 'insarApp'):
|
|
# If we are in sigleFile mode, write all the parameters
|
|
# into the file that we were writing to.
|
|
if singleFile:
|
|
for key in allParams.keys():
|
|
if allParams[key]:
|
|
facility = ElementTree.SubElement(root, 'component', {'name':key})
|
|
for paramKey in allParams[key].keys():
|
|
if allParams[key][paramKey]:
|
|
param = ElementTree.SubElement(facility, 'property',
|
|
{'name':paramKey})
|
|
value = ElementTree.SubElement(param, 'value')
|
|
value.text = allParams[key][paramKey]
|
|
# Otherwise, write the directory of each facility into
|
|
# the file that we were writing to.
|
|
else:
|
|
for key in facilityDirs.keys():
|
|
if facilityDirs[key]:
|
|
property = ElementTree.SubElement(root, 'component', {'name':key})
|
|
catalog = ElementTree.SubElement(property, 'catalog')
|
|
catalog.text = facilityDirs[key]
|
|
# Write the file using ElementTree
|
|
# If the file we are saving is the insarApp input file,
|
|
# we want insarApp tag on top of it. Otherwise, just
|
|
# put the data in to the xml file
|
|
if(rootName == 'insarApp'):
|
|
tempTree = ElementTree.ElementTree(root)
|
|
indent(tempTree.getroot())
|
|
tree = ElementTree.ElementTree(top)
|
|
else:
|
|
tree = ElementTree.ElementTree(root)
|
|
indent(tree.getroot())
|
|
tree.write(directory)
|
|
# Since the user is saving a facility in the single file XML mode,
|
|
# save the values in the global variable allParams
|
|
else:
|
|
allParams[rootName] = {}
|
|
for param in parameters:
|
|
allParams[rootName][param.key] = param.text.get()
|
|
return True
|
|
|
|
|
|
## Creates the input XML for a toplevel GUI, which
|
|
## should be for the facility's components. After
|
|
## saving the XML file, it will exit the toplevel
|
|
## GUI and save the directory that it was saved to
|
|
## in a dictionary with the key as the name of the
|
|
## facility.
|
|
##
|
|
## global variables used - facilityComponents, dir, rootName, facilityDirs
|
|
def facilityInputXML():
|
|
"""Creates an XML file for a facility's parameters"""
|
|
global facilityParams
|
|
global directory
|
|
global rootName
|
|
global facilityDirs
|
|
# Create the XML using the facilityParameters
|
|
# and the rootName, which was set as the facility name
|
|
# when the facility GUI was made
|
|
if(createInputXML(facilityParams, rootName)):
|
|
facilityQuit()
|
|
if(directory):
|
|
facilityDirs[rootName] = directory
|
|
return
|
|
|
|
|
|
## Creates the input XML for insarApp, which is
|
|
## at the root.
|
|
def componentInputXML():
|
|
"""Creates an XML file for the InsarApp"""
|
|
global parameters
|
|
global facilityDirs
|
|
createInputXML(parameters, 'insarApp')
|
|
|
|
###The event that is called when a facilityButton is
|
|
## pressed by the user. When the button is pressed,
|
|
## the code will first try to create an instance of
|
|
## the class using the argument given in the
|
|
## dictionaryOfFacilities and the method given in it.
|
|
## If it fails, it will return an error
|
|
## message, indicating a matching argument for the method
|
|
## was not found. If it succeeds, it will disable the facility
|
|
## buttons, since we can only have one other GUI open at once.
|
|
## Then, it will also disable the inputs to the components,
|
|
## since those should not be changed, since the facility could
|
|
## depend on the values. It will then proceed to make
|
|
## a GUI with entries for each component found in the
|
|
## attribute dictionaryOfVariables of the instance.
|
|
def facilityEvent(event):
|
|
"""Creates a pop-up GUI for inputting facility parameters"""
|
|
# Load all the global variables used in this function
|
|
global parameters
|
|
global dictionaryOfFacilities
|
|
global facilityButtons
|
|
global facilityParams
|
|
global rootName
|
|
global root2
|
|
global classInstance
|
|
global singleFile
|
|
global allParams
|
|
global facilityDocs
|
|
# Find which facility button the user pressed
|
|
# through its text, and set it as the rootName
|
|
text = event.widget.cget('text')
|
|
rootName = text
|
|
# Initiate instance as None
|
|
instance = None
|
|
# Initiate a StringIO and set it as stdout to
|
|
# catch any error messages the factory
|
|
# method produces
|
|
temp = sys.stdout
|
|
errorStr = StringIO('')
|
|
sys.stdout = errorStr
|
|
# Call the parameters method to restore the
|
|
# default value of facilities
|
|
try:
|
|
classInstance._parameters()
|
|
except:
|
|
pass
|
|
for param in parameters:
|
|
if param.text.get():
|
|
# exec 'classInstance.' + param.attrib + '= \'' + param.text.get() + '\''
|
|
setattr(classInstance, param.attrib, eval('\'' + param.text.get() + '\''))
|
|
|
|
pass
|
|
pass
|
|
try:
|
|
classInstance._facilities()
|
|
except:
|
|
pass
|
|
# Try to use the arguments in the dictionaryOfFacilities
|
|
# to instantiate an instance of the facility
|
|
try:
|
|
args = dictionaryOfFacilities[text]['args']
|
|
kwargs = dictionaryOfFacilities[text]['kwargs']
|
|
# May need to be modified if a factory takes
|
|
# the None argument
|
|
modified = ['']*len(args)
|
|
for i in range(0, len(args)):
|
|
if(args[i] == None):
|
|
modified[i] = 'None'
|
|
else:
|
|
modified[i] = args[i]
|
|
pass
|
|
pass
|
|
modified = tuple(modified)
|
|
# raise RefactorWarning("refactor with appy built-in")
|
|
instance = eval(
|
|
dictionaryOfFacilities[text]['factoryname']+'(*' + modified.__str__() + ', **' +
|
|
kwargs.__str__() + ')'
|
|
)
|
|
except Exception as e:
|
|
traceback.print_exc(file=sys.stdout)
|
|
tkMessageBox.showerror('ERROR!', 'Unknown error occurred:\n'+errorStr.getvalue()+'\n%s' %e)
|
|
return None
|
|
# If the instance is still none, this means
|
|
# that an error message was produced, and
|
|
# that it failed to make an instance.
|
|
# Print out the error message
|
|
# produced, which is contained in the StringIO
|
|
sys.stdout = temp
|
|
if instance is None:
|
|
tkMessageBox.showerror('ERROR!', 'Bad argument for: ' +
|
|
dictionaryOfFacilities[text]['factoryname'] +
|
|
'\n' + errorStr.getvalue())
|
|
return
|
|
# Try to run the ._parameters() and ._facilities()
|
|
# methods of the instance, and then get its
|
|
# dictionaryOfVariables
|
|
try:
|
|
instance._parameters()
|
|
except:
|
|
pass
|
|
try:
|
|
instance._facilities()
|
|
except:
|
|
pass
|
|
dictionaryOfVariables = None
|
|
try:
|
|
dictionaryOfVariables = instance.dictionaryOfVariables
|
|
except:
|
|
pass
|
|
# Check if the dictionaryOfVariables is empty or does not exist
|
|
if (dictionaryOfVariables is None or dictionaryOfVariables == {}):
|
|
# Create a Popup Error message
|
|
sys.stdout = sys.stderr
|
|
tkMessageBox.showerror('ERROR!', 'DictionaryOfVariables for ' +
|
|
text + ' is empty! Nothing to do...')
|
|
return
|
|
# Disable all the facilityButtons b/c multiple facility
|
|
# GUI's are not supported
|
|
for button in facilityButtons:
|
|
button.config(state='disabled')
|
|
for param in parameters:
|
|
param.text.config(state='disabled')
|
|
XMLButton.config(state='disabled')
|
|
# Create the new facility GUI
|
|
root2 = tk.Toplevel()
|
|
root2.protocol("WM_DELETE_WINDOW",facilityQuit)
|
|
root2.title('Facility '+text+ ' Component Editor')
|
|
tempFont = ('Times New Roman', 14)
|
|
# Create a font with underlines
|
|
uFont = tkFont.Font(family='Times New Roman', size=14, underline=True)
|
|
# First column gives the name
|
|
nameLabel = tk.Label(root2, text='Name (Click a name for help)', font=uFont)
|
|
# Second column allows user to input values for each attribute
|
|
valueLabel = tk.Label(root2, text='Value', font=uFont)
|
|
# The third column is for units
|
|
unitsLabel = tk.Label(root2, text='Units', font=uFont)
|
|
# The fourth column indicates to users whether or not an
|
|
# attribute is optional or mandatory.
|
|
requiredLabel = tk.Label(root2, text='Optional/Mandatory', font=uFont)
|
|
# Put each label in respective locations
|
|
nameLabel.grid(row=0, column=0)
|
|
valueLabel.grid(row=0, column=1)
|
|
unitsLabel.grid(row=0, column=2)
|
|
requiredLabel.grid(row=0, column=3)
|
|
r = 1
|
|
# Reset facilityParams, since we are using a new
|
|
# facility
|
|
facilityParams = []
|
|
try:
|
|
units = instance.unitsOfVariables
|
|
except:
|
|
pass
|
|
try:
|
|
facilityDocs = instance.descriptionOfVariables
|
|
except:
|
|
pass
|
|
for key in dictionaryOfVariables.keys():
|
|
label = tk.Label(root2, text=key)
|
|
label.grid(row=r, column=0)
|
|
if(dictionaryOfVariables[key][2].lower() == 'optional'):
|
|
opt = tk.Label(root2, text='Optional', fg='green')
|
|
facilityParams.append(parameter(key, tk.Entry(root2), True))
|
|
else:
|
|
opt = tk.Label(root2, text='Mandatory', fg='red')
|
|
facilityParams.append(parameter(key, tk.Entry(root2), False))
|
|
try:
|
|
label = tk.Label(root2, text=units[key])
|
|
label.grid(row=r, column=2)
|
|
except:
|
|
pass
|
|
button = tk.Button(root2, text=key, width=25)
|
|
button.bind('<ButtonRelease>', facilityHelp)
|
|
button.grid(row=r, column=0)
|
|
opt.grid(row=r, column=3)
|
|
facilityParams[r-1].text.grid(row=r, column=1)
|
|
r = r + 1
|
|
# Put the known arguments into the entry boxes before outputting
|
|
# them, and also check for any "trash" values inside the dictionary
|
|
# that could occur from loading an xml file with incorrect facility
|
|
# parameters
|
|
temp = {}
|
|
temp[text] = {}
|
|
for param in facilityParams:
|
|
try:
|
|
param.text.insert(0, allParams[text][param.key])
|
|
temp[text][param.key] = allParams[text][param.key]
|
|
except:
|
|
pass
|
|
allParams[text] = temp[text]
|
|
# Create a quit and save button, as well as a dir button so
|
|
# that the user can load a directory and use that as their
|
|
# facility XML file
|
|
quitButton = tk.Button(root2, text='Quit', command=facilityQuit)
|
|
saveButton = tk.Button(root2, text='Save', command=facilityInputXML)
|
|
dirButton = tk.Button(root2, text='Use An Existing\n XML File',
|
|
command=getFacilityDirectory)
|
|
quitButton.grid(row=r, column=2)
|
|
saveButton.grid(row=r, column=1)
|
|
dirButton.grid(row=r, column=0)
|
|
root2.mainloop()
|
|
|
|
def facilityHelp(event):
|
|
"""Creates help documentation for the facility GUI"""
|
|
global facilityDocs
|
|
text = event.widget.cget('text')
|
|
if(text in facilityDocs.keys() and facilityDocs[text] != ''):
|
|
tkMessageBox.showinfo(text+' documentation:', description[text])
|
|
else:
|
|
tkMessageBox.showerror('Documentation Not Found!', 'There is no documentation\nfor this parameter')
|
|
|
|
|
|
## This method is called when the button for using an already existing
|
|
## XML file is clicked on the facility GUI. The method tries to open
|
|
## the xml file given, and stores the data in the global variable
|
|
## allParams, as well as populate them in the GUI's entry boxes.
|
|
##
|
|
## Global Variables Used: rootName, facilityDirs, facilityParams
|
|
def getFacilityDirectory():
|
|
"""Gets the directory for the xml used for the facility's parameter"""
|
|
global rootName
|
|
global facilityDirs
|
|
global facilityParams
|
|
directory = tkFileDialog.askopenfilename(title='Locate Your XML File for '
|
|
+ rootName, defaultextension='.xml',
|
|
filetypes=[('xml files', '.xml')])
|
|
if(directory):
|
|
try:
|
|
tree = ElementTree.parse(directory)
|
|
value = ''
|
|
name = ''
|
|
for property in tree.findall('property'):
|
|
name = property.attrib['name']
|
|
value = property.find('value').text
|
|
for param in facilityParams:
|
|
if param.key == name:
|
|
param.text.delete(0, tk.END)
|
|
param.text.insert(0, value)
|
|
allParams[rootName][param.key] = value
|
|
name = ''
|
|
break
|
|
if name != '':
|
|
tkMessageBox.showerror('Error!', 'Invalid XML for'+
|
|
rootName + ' facility!'
|
|
+ '\nParameter ' + name +
|
|
' does not exist in this facility!')
|
|
return
|
|
except ExpatError:
|
|
tkMessageBox.showerror('Error!', 'Invalid XML error! XML is ill formed!')
|
|
except Exception:
|
|
tkMessageBox.showerror('Error!', 'Invalid XML error! XML is ill formed for ' + rootName + '!')
|
|
facilityDirs[rootName] = directory
|
|
|
|
## This is the quit button event for the facility GUI. This
|
|
## quits out of the for facility and reenables all the
|
|
## buttons for the other facilities and entry boxes for
|
|
## the components.
|
|
##
|
|
## Global Variables Used: facilityButtons, components, root2, XMLButton
|
|
def facilityQuit():
|
|
"""The button event for Quit button on facility GUI. This destroys the
|
|
facility GUI and restores disabled buttons on main GUI."""
|
|
root2.destroy()
|
|
for button in facilityButtons:
|
|
button.config(state='normal')
|
|
for param in parameters:
|
|
param.text.config(state='normal')
|
|
XMLButton.config(state='normal')
|
|
|
|
def showDoc(event):
|
|
"""Shows documentation for the parameter written on the button"""
|
|
text = event.widget.cget('text')
|
|
if(text in description.keys() and description[text] != ''):
|
|
tkMessageBox.showinfo(text+' documentation:', description[text])
|
|
else:
|
|
tkMessageBox.showerror('Documentation Not Found!', 'There is no documentation\nfor this parameter')
|
|
|
|
def changeSave(event):
|
|
"""Changes the save from single file save to multiple and vice versa"""
|
|
global singleFile
|
|
global facilityDirs
|
|
singleFile = not singleFile
|
|
if(singleFile):
|
|
event.widget.configure(text='Currently:\nSingle XML File Mode')
|
|
facilityDirs = {}
|
|
else:
|
|
event.widget.configure(text = 'Currently:\nMultiple XML Mode')
|
|
return
|
|
|
|
def loadXML():
|
|
"""Loads an XML file for the insarApp and stores the data"""
|
|
global parameters
|
|
global allParams
|
|
global facilityDirs
|
|
facilityDirs = {}
|
|
# Get the directory from the user
|
|
directory = ''
|
|
directory = tkFileDialog.askopenfilename(title='Locate Your XML File:',
|
|
defaultextension='.xml',
|
|
filetypes=[('xml files', '.xml')])
|
|
# If the user specified a directory, try loading it
|
|
if directory:
|
|
try:
|
|
# Find the insarApp component which should have all the properties
|
|
# and facilities
|
|
tree = ElementTree.parse(directory).find('component')
|
|
text = ''
|
|
name = ''
|
|
# First find all the parameters listed in the main GUI
|
|
for property in tree.findall('property'):
|
|
name = property.attrib['name']
|
|
value = property.find('value').text
|
|
for param in parameters:
|
|
if param.key == name:
|
|
param.text.delete(0, tk.END)
|
|
param.text.insert(0, value)
|
|
name = ''
|
|
break
|
|
pass
|
|
if name:
|
|
tkMessageBox.showerror('Error!', 'Invalid xml for these parameters!\n'+
|
|
'Parameter ' + name + ' does not exist!')
|
|
pass
|
|
pass
|
|
|
|
# Then find the parameters for the facilities
|
|
for facility in tree.findall('component'):
|
|
exists = False
|
|
facilityName = facility.attrib['name']
|
|
for button in facilityButtons:
|
|
if button.cget('text') == facilityName:
|
|
exists = True
|
|
pass
|
|
pass
|
|
if not exists:
|
|
tkMessageBox.showerror('Error!', 'Invalid xml error! Facility '
|
|
+ facilityName + ' does not exist!')
|
|
return None
|
|
# Check whether or not the xml is in catalog format or all-in-one
|
|
# format
|
|
catalog = None
|
|
catalog = facility.find('catalog')
|
|
allParams[facilityName] = {}
|
|
# If there is a catalog, assume that the first component
|
|
# contains every parameter of the facility
|
|
if catalog is not None:
|
|
catalog = catalog.text
|
|
facilityDirs[facilityName] = catalog
|
|
facilityTree = ElementTree.parse(catalog)
|
|
for property in facilityTree.findall('property'):
|
|
name = property.attrib['name']
|
|
value = property.find('value').text
|
|
allParams[facilityName][name] = value
|
|
pass
|
|
pass
|
|
# Otherwise, go through the facility and get the parameters
|
|
else:
|
|
for property in facility.findall('property'):
|
|
name = property.attrib['name']
|
|
value = property.find('value').text
|
|
allParams[facilityName][name] = value
|
|
except IOError:
|
|
tkMessageBox.showerror('Error!', 'Invalid XML error! One or more XML does not exist!')
|
|
except ExpatError:
|
|
tkMessageBox.showerror('Error!', 'Invalid XML error! XML is ill formed!')
|
|
except Exception:
|
|
tkMessageBox.showerror('Error!', 'Invalid XML error! XML is valid for insarApp!')
|
|
return
|
|
|
|
|
|
|
|
def reset():
|
|
"""After asking the user, resets everything in the code used for writing to an xml"""
|
|
global allParams
|
|
global facilityDirs
|
|
global parameters
|
|
global facilityButtons
|
|
global root2
|
|
# Ask the user if they want to reset everything
|
|
answer = tkMessageBox.askyesno("Are you sure?", "Are you sure you want to reset all data?")
|
|
if answer:
|
|
# Delete all entries in the main GUI
|
|
for param in parameters:
|
|
param.text.delete(0, tk.END)
|
|
# Erase all data stored for writing to XML's
|
|
allParams = {}
|
|
facilityDirs = {}
|
|
# Make sure that all the main GUI buttons are enabled
|
|
for button in facilityButtons:
|
|
button.configure(state='normal')
|
|
facilityDirs[button.cget('text')] = ''
|
|
allParams[button.cget('text')] = {}
|
|
XMLButton.config(state='normal')
|
|
# If there is a facility GUI, get rid of it
|
|
try:
|
|
root2.destroy()
|
|
except:
|
|
pass
|
|
pass
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
"""Builds the main GUI for making an XML input for given class"""
|
|
# Get the global variable
|
|
global parameters
|
|
global dictionaryOfFacilities
|
|
global facilityButtons
|
|
global facilityRequired
|
|
global facilityDirs
|
|
global classInstance
|
|
global description
|
|
global allParams
|
|
global singleFile
|
|
global directory
|
|
global facilityParams
|
|
parameters = []
|
|
facilityParams = []
|
|
dictionaryOfFacilities = {}
|
|
facilityButtons = []
|
|
facilityRequired = []
|
|
facilityDirs = {}
|
|
root2 = None
|
|
rootName = ''
|
|
directory = ''
|
|
allParams = {}
|
|
|
|
# Create an instance of Insar to run the _parameters() and
|
|
# _facilities() function, if they exist, to create the
|
|
# dictionaryOfVariables.
|
|
try:
|
|
if(len(sys.argv) != 2 and len(sys.argv) != 3):
|
|
print("Invalid commandline arguments:")
|
|
print("Usage 1, Module and Class have same names: xmlGenerator Module")
|
|
print("Usage 2, Module and Class names different: xmlGenerator Module Class")
|
|
print("(Module name should not include the '.py')")
|
|
sys.exit()
|
|
elif(len(sys.argv) == 2):
|
|
if 'help' in sys.argv[1]:
|
|
print("'Invalid commandline arguments:\nUsage: xmlGenerator [Module (sans '.py'] [Class]")
|
|
# raise RefactorWarning("refactor with __import__ built-in")
|
|
print("Assuming module name and class name are both, ", sys.argv[1])
|
|
exec('from ' + sys.argv[1] + ' import ' + sys.argv[1])
|
|
classInstance = eval(sys.argv[1] + '()')
|
|
else:
|
|
print("importing class %s from module %s" % (sys.argv[1], sys.argv[2]))
|
|
# raise RefactorWarning("refactor with __import__ built-in")
|
|
exec('from ' + sys.argv[1] + ' import ' + sys.argv[2])
|
|
# print sys.argv[2]
|
|
classInstance = eval(sys.argv[2] + '()')
|
|
pass
|
|
pass
|
|
except ImportError as e:
|
|
print("Invalid arguments!")
|
|
print("Either the given module or the given class does not exist,")
|
|
print("or you have assumed they both have the same name and they do not.")
|
|
sys.exit()
|
|
pass
|
|
try:
|
|
classInstance._parameters()
|
|
classInstance._facilities()
|
|
except:
|
|
pass
|
|
dictionaryOfVariables = classInstance.dictionaryOfVariables
|
|
try:
|
|
dictionaryOfFacilities = classInstance._dictionaryOfFacilities
|
|
except:
|
|
pass
|
|
|
|
# If the dictionaryOfVariables is not empty, create
|
|
# the GUI
|
|
if dictionaryOfVariables:
|
|
|
|
# Since Frame class does not have scrollbars, use a
|
|
# canvas to create a scrollbar in the y direction
|
|
root = tk.Tk()
|
|
root.title(sys.argv[1] + ' Input XML File Generator')
|
|
verticalBar = tk.Scrollbar(root)
|
|
verticalBar.grid(row=0, column=1, sticky='N'+'S')
|
|
|
|
# Create the Canvas, which will have the scroll bar as
|
|
# well as the frame. Change the width here to
|
|
# change the starting width of the screen.
|
|
canvas = tk.Canvas(root,
|
|
yscrollcommand=verticalBar.set,
|
|
width=1100, height=500)
|
|
canvas.grid(row=0, column=0, sticky='N'+'S'+'E'+'W')
|
|
verticalBar.config(command=canvas.yview)
|
|
|
|
root.grid_rowconfigure(0, weight=1)
|
|
root.grid_columnconfigure(0, weight=1)
|
|
|
|
|
|
frame = tk.Frame(canvas)
|
|
frame.rowconfigure(1, weight=1)
|
|
frame.columnconfigure(1, weight=1)
|
|
# Begin creating the GUI involved with input variables
|
|
# Create a font with underlines
|
|
uFont = tkFont.Font(family='Times New Roman', size=14, underline=True)
|
|
# Create a parameters label
|
|
paramLabel = tk.Label(frame, text='Parameters:',
|
|
font=("Times New Roman", 20, "bold"))
|
|
# First column gives the name
|
|
nameLabel = tk.Label(frame, text='Name (Click a name for help)', font=uFont)
|
|
# Second column allows user to input values for each attribute
|
|
valueLabel = tk.Label(frame, text='Value', font=uFont)
|
|
# The third column is for units
|
|
unitsLabel = tk.Label(frame, text='Units', font=uFont)
|
|
# The fourth column indicates to users whether or not an
|
|
# attribute is optional or mandatory.
|
|
requiredLabel = tk.Label(frame, text='Optional/Mandatory', font=uFont)
|
|
# Put each label in respective locations
|
|
paramLabel.grid(row=0, column=0)
|
|
nameLabel.grid(row=1, column=0, columnspan=2)
|
|
valueLabel.grid(row=1, column=2)
|
|
unitsLabel.grid(row=1, column=4)
|
|
requiredLabel.grid(row=1, column=5)
|
|
|
|
# Create a variable for the row
|
|
r = 2
|
|
try:
|
|
description = classInstance.descriptionOfVariables
|
|
except:
|
|
pass
|
|
units = {}
|
|
try:
|
|
units = classInstance.unitsOfVariables
|
|
except:
|
|
pass
|
|
for key in dictionaryOfVariables.keys():
|
|
val = dictionaryOfVariables[key]
|
|
# Make the label from the keys in the dictionary
|
|
# Change the wraplength here for the names if it is too short or long.
|
|
# label = tk.Label(frame, text=key, anchor = tk.W, justify=tk.LEFT, wraplength=100)
|
|
# label.grid(row=r,column=0)
|
|
# Indicate whether the attribute is optional or mandatory
|
|
if(val[2].lower() == ('optional')):
|
|
required = tk.Label(frame, text='Optional', fg='green')
|
|
parameters.append(parameter(key, tk.Entry(frame, width=50), True, val[0]))
|
|
else:
|
|
required = tk.Label(frame, text='Mandatory', fg='red')
|
|
parameters.append(parameter(key, tk.Entry(frame, width=50), False, val[0]))
|
|
pass
|
|
try:
|
|
doc = tk.Button(frame, text=key, anchor = tk.W, justify=tk.LEFT, width=50,
|
|
wraplength=348)
|
|
doc.bind('<ButtonRelease>', showDoc)
|
|
doc.grid(row=r, column=0, columnspan=2)
|
|
except:
|
|
pass
|
|
try:
|
|
unit = tk.Label(frame, text=units[key])
|
|
unit.grid(row=r, column=2)
|
|
except:
|
|
pass
|
|
required.grid(row=r,column=5)
|
|
# Put the Entry in global variable, since it is needed
|
|
# for saving inputted values into xml
|
|
parameters[r-2].text.grid(row=r,column=2, columnspan=2)
|
|
r = r + 1
|
|
pass
|
|
if dictionaryOfFacilities:
|
|
# Add a label indicating that these buttons are facilities
|
|
facilityLabel = tk.Label(frame, text='Facilities:',
|
|
font=("Times New Roman", 20, "bold"),
|
|
justify=tk.LEFT,
|
|
anchor=tk.W)
|
|
facilityLabel.grid(row=r, column=0)
|
|
r = r + 1
|
|
x = 0
|
|
# Make the buttons to edit facility parameters and import
|
|
# the required modules using the factorymodule
|
|
for key in dictionaryOfFacilities.keys():
|
|
facilityButtons.append(tk.Button(frame, text = key, width=50, justify=tk.LEFT,
|
|
anchor=tk.W, wraplength=348))
|
|
facilityButtons[x].grid(row=r, column=0, columnspan=2)
|
|
facilityButtons[x].bind('<ButtonRelease>', facilityEvent)
|
|
facilityDirs[key] = ''
|
|
allParams[key] = {}
|
|
if dictionaryOfFacilities[key]['mandatory']:
|
|
facilityRequired.append(True)
|
|
required = tk.Label(frame, text='Mandatory', fg='red')
|
|
required.grid(row=r,column=5)
|
|
else:
|
|
facilityRequired.append(False)
|
|
required = tk.Label(frame, text='Optional', fg='green')
|
|
required.grid(row=r,column=5)
|
|
|
|
r = r + 1
|
|
x = x + 1
|
|
try:
|
|
exec ('from ' + dictionaryOfFacilities[key]['factorymodule'] +
|
|
' import ' + dictionaryOfFacilities[key]['factoryname'])
|
|
raise RefactorWarning("refactor with __import__ built-in")
|
|
except:
|
|
pass
|
|
pass
|
|
pass
|
|
# Buttons for saving the xml file, using an existing xml file,
|
|
# changing the save settings, and quitting out of the program
|
|
saveButton = tk.Button(frame, text="Save", command=componentInputXML)
|
|
quitButton = tk.Button(frame, text="Quit", command=root.destroy)
|
|
resetButton = tk.Button(frame, text='Reset All', command=reset)
|
|
# The button for switching between multiple xml mode and single
|
|
# mode. The default is multiple XML mode.
|
|
singleFile = False
|
|
singleFileButton = tk.Button(frame, text='Currently:\nMultiple XML Mode')
|
|
singleFileButton.bind('<ButtonRelease>', changeSave)
|
|
# The button used to get an existing XML file
|
|
XMLButton = tk.Button(frame, text='Use an existing XML File', command=loadXML)
|
|
saveButton.grid(row=r+1, column=2)
|
|
quitButton.grid(row=r+1, column=3)
|
|
resetButton.grid(row=r+1, column=4)
|
|
singleFileButton.grid(row=r+1, column=5)
|
|
XMLButton.grid(row=r+1, column=1)
|
|
# Have the canvas create a window in the top left corner,
|
|
# which is the frame with everything on it
|
|
canvas.create_window(0, 0, anchor='nw', window=frame)
|
|
frame.update_idletasks()
|
|
canvas.config(scrollregion=canvas.bbox("all"))
|
|
root.mainloop()
|
|
else:
|
|
tkMessageBox.showerror('ERROR!', 'Dictionary of Variables Empty: Nothing to do')
|
|
pass
|
|
sys.exit()
|