source: branches/GUIdev/DuchampParameterGUI.py @ 1441

Last change on this file since 1441 was 1331, checked in by KelvinHsu, 11 years ago

Some clean up of code before splitting into files.

  • Property svn:executable set to *
File size: 36.2 KB
Line 
1#!/usr/bin/env python
2
3#-------------------------------------------------------------------------------
4# Name:        DuchampParameterGUI
5# Purpose:
6#
7# Author:      Kelvin
8#
9# Created:     4/12/2013
10#-------------------------------------------------------------------------------
11
12import os
13
14# Python 2 packages
15try:
16    from Tkinter import *
17    import tkFileDialog
18
19# Python 3 packages
20except ImportError:
21    from tkinter import *
22    import tkinter.filedialog as tkFileDialog
23
24
25# Determine the current directory.
26directory = os.getcwd()
27
28# Define the default file path.
29defaultParamFileName = '/InputComplete'
30defaultParamFilePath = directory + defaultParamFileName
31
32
33# This reads parameter files with the specified format.
34def readParamFile(paramFilePath):
35
36    # Create a dictionary that maps parameter names to its value and a list to keep track of its order.
37    parameters = {}
38    orderedParameters = []
39
40    try:
41        # Open the given parameter file.
42        paramFile = open(paramFilePath)
43
44        # Load files for lines of parameter data in the specified format and
45        # store them into the dictionary.
46        for line in paramFile:
47            if line[0] != '#' and len(line.split()) > 1:
48                linebits = line.split()
49                parameters[linebits[0]] = linebits[1]
50                orderedParameters = orderedParameters + [linebits[0]]
51
52        paramFile.close()
53
54    # Note that if the file could not be read, then the dictionary will stay empty.
55    # The GUI window can make use of this fact.
56    except IOError:
57        print("Cannot open file")
58
59    return(parameters, orderedParameters)
60
61
62# This reads the default file for all relevant information of parameter classes, description, type, and format.
63def readParamByClass(paramFilePath):
64
65    # Create a diciontary that maps parameter names to its class and a list to keep track of class orders.
66    classOfParameter = {}
67    classNames = []
68
69    # Create dictionaries that maps parameter names to its description, value type, and value format.
70    description = {}
71    paramType = {}
72    paramFormat = {}
73
74    try:
75        # Open the given parameter file.
76        paramFile = open(paramFilePath)
77
78        # Load files for lines of parameter data in the specified format and
79        # store them into the dictionaries.
80        for line in paramFile:
81
82            if line[0:3] == '###' and len(line.split('###')) > 1:
83                className = line.strip('###').strip()
84                classNames = classNames + [className]
85
86            elif line[0:2] == '#*' and len(line.split()) > 1 and '--' in line:
87                param = line.split()[1].strip()
88                paramType[param] = line.split('[')[1].split(']')[0].strip()
89                paramFormat[param] = line.split('{')[1].split('}')[0].strip()
90                description[param] = '--'.join(line.split('--')[1:len(line.split('--'))]).strip()
91               
92            elif line[0] != '#' and len(line.split()) > 1:
93                linebits = line.split()
94                classOfParameter[linebits[0]] = className
95
96        paramFile.close()
97
98    # Note that if the file could not be read, then the dictionary will stay empty.
99    # The GUI window can make use of this fact.
100    except IOError:
101        print("Cannot open file")
102                 
103    return(classOfParameter, classNames, description, paramType, paramFormat)
104
105
106# Define a function to create a parameter file with the specified format.
107# It will return 0 if the file already exists and will not overwrite the file just yet (unless write = 1)
108#                1 if the file is successfully created (or overwriten)
109#               -1 if the file was not successfully created (or overwriten) due to some error
110def writeParamFile(newParamFilePath, parameters, parameterOrder, write):
111
112    # If we want to make sure if it is okay to write, do the following.
113    if write != 1:
114       
115        # First, try opening the file for reading.
116        # If the file exists for reading, then close it and then return a 0,
117        # which the GUI window use to warn the user that a file with that name already exists.
118        try:
119            newParamFile = open(newParamFilePath)
120            newParamFile.close()
121            return(0)
122
123        # If we have trouble reading the file, then the file doesn't exist and we're safe to write to it.
124        except IOError:
125            write = 1
126
127    # If we are sure we can write to the file, then do it.
128    if write == 1:
129
130        try:
131            newParamFile = open(newParamFilePath, 'w')
132           
133            # Write the editted set of parameters into the new file.
134            for par in parameterOrder:
135                newParamFile.write('%s    %s\n'%(par, parameters[par]))
136
137            newParamFile.close()
138            return(1)
139       
140        except IOError:
141            return(-1)
142
143
144# This function determines the longest key in a dictionary.
145def longestKeyLength(dictionary):
146    return(len(max(dictionary.keys(), key = len)))
147
148# This function determines the longest value in a dictionary.
149def longestValueLength(dictionary):
150    return(len(max(dictionary.values(), key = len)))
151
152# This is the minimum space between the a key and its value in a dictionary when we want to display it.
153minimumSpace = 5
154
155# This appends the appropriate space after a single key in a dictionary.
156# Note: Can this be optimised?
157def tabbedDictionaryLine(dictionary, key, star):
158
159    if key in dictionary:
160
161        # Determine the residual space our word will have compared to the longest word.
162        residualSpace = longestKeyLength(dictionary) - len(key)
163       
164        if star == 0:
165
166            # Add extra space after the word based on the minimum separatio between the word and its definition.
167            space = ' '*(minimumSpace + residualSpace)
168            tabbedKey = key + space
169
170            # Return the word with the appropriate spaces appended.
171            return(tabbedKey)
172        elif star == 1:
173
174            star = ' (*) '
175           
176            # Add extra space after the word based on the minimum separatio between the word and its definition.
177            space = star + ' '*residualSpace + ' '*(minimumSpace - len(star))
178            tabbedKey = key + space
179
180            # Return the word with the appropriate spaces appended.
181            return(tabbedKey)
182
183        else:
184            print("Coding Error: 'Star' is not binary")
185
186    # This exception is not needed, as the function will always be called with a word within the dictionary.
187    else:
188        print(key + "is not in the dictionary")
189        return(' ')
190
191# This determines the longest line that will be printed in a dictionary given the above method.
192def longestLineLength(dictionary):
193
194    maxLineLength = longestKeyLength(dictionary) + longestValueLength(dictionary) + minimumSpace
195    return(maxLineLength)
196
197# Given an array of string, this returns an array of the same strings but in lower cases.
198def lower(stringArray):
199
200    lowerArray = []
201
202    L = len(stringArray)
203   
204    for i in range(L):
205        lowerArray += [stringArray[i].lower()]
206
207    return lowerArray
208
209
210#-------------------------------------------------------------------------------
211# GUI - Tkinter section
212
213class mainInterface:
214
215    def __init__(self, master):
216       
217        # --------------------------------------------------
218        # Initialise the GUI window.
219        self.frame = Frame(master)
220        self.frame.grid()
221        # --------------------------------------------------
222
223
224        # --------------------------------------------------
225        # Menu
226        self.menubar = Menu(master)
227
228        # File Menu
229        self.filemenu = Menu(self.menubar, tearoff = 0)
230        self.filemenu.add_command(label = "Open", command = self.createInputInterface)
231        self.filemenu.add_command(label = "Save specification", command = self.createSpecifiedOutputInterface)
232        self.filemenu.add_command(label = "Save all specification", command = self.createEffectiveOutputInterface)
233        self.filemenu.add_separator()
234        self.filemenu.add_command(label = "Exit", command = self.frame.quit)
235        self.menubar.add_cascade(label = "File", menu = self.filemenu)
236
237
238        # Options Menu
239        self.editmenu = Menu(self.menubar, tearoff = 0)
240        self.editmenu.add_command(label = "Cut", command = self.notImplementedYet)
241        self.editmenu.add_command(label = "Copy", command = self.notImplementedYet)
242        self.editmenu.add_command(label = "Paste", command = self.notImplementedYet)
243        self.menubar.add_cascade(label = "Options", menu = self.editmenu)
244
245        # Help Menu
246        self.helpmenu = Menu(self.menubar, tearoff = 0)
247        self.helpmenu.add_command(label = "About", command = self.notImplementedYet)
248        self.menubar.add_cascade(label = "Help", menu = self.helpmenu)
249        # --------------------------------------------------
250   
251       
252        # Row 1-10 reserved for future extensions
253       
254       
255        # --------------------------------------------------
256        # Parameter name and value entry
257        self.parameterLabel = Label(self.frame, text = "Parameter: ", foreground = "Blue")
258        self.parameterLabel.grid(row = 11, column = 1, columnspan = 2)
259
260        self.valueLabel = Label(self.frame, text = "Value: ", foreground = "Forest Green")
261        self.valueLabel.grid(row = 11, column = 3, columnspan = 2)
262
263        self.parameterEntry = Entry(self.frame, width = 25)
264        self.parameterEntry.bind("<Return>", self.checkParameterEvent)
265        self.parameterEntry.grid(row = 12, column = 1, padx = 10, columnspan = 2)
266
267        self.valueEntry = Entry(self.frame, width = 25)
268        self.valueEntry.bind("<Return>", self.updateParameterEvent)
269        self.valueEntry.grid(row = 12, column = 3, padx = 10, columnspan = 2)
270        # --------------------------------------------------
271
272
273        # --------------------------------------------------
274        # Check, update, and describe parameter buttons
275        self.checkButton = Button(self.frame, text = "Check", command = self.checkParameterWithDescription)
276        self.checkButton.grid(row = 13, column = 1, padx = 10, pady = 10)
277       
278        self.updateButton = Button(self.frame, text = "Update", command = self.updateParameter)
279        self.updateButton.grid(row = 13, column = 2, padx = 10, pady = 10)
280
281        self.revertDefaultButton = Button(self.frame, text = "Revert to default", command = self.revertDefault)
282        self.revertDefaultButton.grid(row = 13, column = 4, padx = 10, pady = 10, columnspan = 2)
283        # --------------------------------------------------
284
285
286        # Row 14-15 reserved for displaying the information queried from above
287
288
289        # --------------------------------------------------
290        # List parameter files buttons (default and specified)
291        self.listDefault = Button(self.frame, text = "List Default Parameters", command = lambda: self.listParameters("Default"))
292        self.listDefault.grid(row = 16, column = 1, padx = 10, pady = 10, columnspan = 2)
293
294        self.listSpecified = Button(self.frame, text = "List User Specified Parameters", command = lambda: self.listParameters("Specified"))
295        self.listSpecified.grid(row = 17, column = 1, padx = 10, pady = 10, columnspan = 2)
296
297        self.listEffective = Button(self.frame, text = "List Effective Parameters", command = lambda: self.listParameters("Effective"))
298        self.listEffective.grid(row = 18, column = 1, padx = 10, pady = 10, columnspan = 2)
299        # --------------------------------------------------
300
301
302        # --------------------------------------------------
303        # Radio Buttons
304
305        # Obtain (parameter: class) dictionary, and a list of the names of classes in order
306        (self.classOfParameter, self.classNames, self.description, self.paramType, self.paramFormat) = readParamByClass(defaultParamFilePath)
307
308        # Initialise the variable containing the name of the class to be displayed
309        self.whichClass = StringVar()
310
311        # Index the buttons
312        i = 0
313
314
315        # Create each radio button in order
316        for name in self.classNames:
317           
318            b = Radiobutton(self.frame, text = name, variable = self.whichClass, value = name, indicatoron = 0, command = lambda: self.listParameters("Class"), width = 30)
319
320            # Place them at appropriate positions
321            r = 19 + int(i/2)
322
323            if (i % 2) == 0:
324                c = 1
325            else:
326                c = 3
327
328            # Make them stick to the left
329            b.grid(row = r, column = c, columnspan = 2)
330            i = i + 1
331        # --------------------------------------------------
332
333
334        # --------------------------------------------------
335        # Variable definitions throughout the window
336       
337        # Firstly, determine the default list of parameters
338        (self.defaultParameters, self.orderedParameters) = readParamFile(defaultParamFilePath)
339
340        # Then, determine the user specified list of parameters
341        self.userSpecifiedParameters = {}
342        self.orderedSpecifiedParameters = []
343
344        # This is the effective parameters
345        self.effectiveParameters = dict(self.defaultParameters)
346
347        # Define the string variables in the parameter name and value entry section
348        self.resultTitle = StringVar()
349        self.result = StringVar()
350        self.notesTitle = StringVar()
351        self.notes = StringVar()
352        self.color = StringVar()
353
354        # Define the string variables for entering file directories, names, and paths   
355        self.userSpecifiedFileDirectory = StringVar()
356        self.userSpecifiedFileName = StringVar()
357        self.userSpecifiedFilePath = StringVar()
358        # --------------------------------------------------
359
360
361        # Give a default name for the user specified file name
362        self.userSpecifiedFileName = 'duchampHIPASS.txt'
363
364        self.frame.bind("<Enter>", self.precaution)
365
366
367       
368    # Define a notice box (one button only)
369    def createNoticeBox1(self, title, message, command, buttonText = "Dismiss"):
370       
371        self.noticeBox = Toplevel(width = 200, borderwidth = 20)
372        self.noticeBox.title(title)
373       
374        self.noticeMsg = Message(self.noticeBox, text = message)
375        self.noticeMsg.grid(row = 1, column = 1, columnspan = 2)
376       
377        self.noticeBoxButton = Button(self.noticeBox, text = buttonText, command = command)
378        self.noticeBoxButton.grid(row = 2, column = 1, pady = 5, columnspan = 2)
379       
380
381    # Define a notice box (two buttons)
382    def createNoticeBox2(self, title, message, command1, command2, buttonText1 = "Yes", buttonText2 = "No"):
383
384        self.noticeBox = Toplevel(width = 200, borderwidth = 20)
385        self.noticeBox.title(title)
386       
387        self.noticeMsg = Message(self.noticeBox, text = message)
388        self.noticeMsg.grid(row = 1, column = 1, columnspan = 2)
389       
390        self.noticeBoxButton1 = Button(self.noticeBox, text = buttonText1, command = command1)
391        self.noticeBoxButton1.grid(row = 2, column = 1, pady = 5)
392       
393        self.noticeBoxButton2 = Button(self.noticeBox, text = buttonText2, command = command2)
394        self.noticeBoxButton2.grid(row = 2, column = 2, pady = 5)
395       
396
397    # This destroys notice box
398    def dismissNotice(self):
399
400        self.noticeBox.destroy()
401       
402       
403    # This checks if file is missing or corrupted or now
404    def precaution(self, event):
405
406        d = [len(self.defaultParameters), len(self.description), len(self.paramType), len(self.paramFormat)]
407        s = ["Default Parameter", "Description", "Type", "Format"]
408       
409        # Firstly, if the default parameter file was not loaded, notify the user
410        if min(d) == 0:
411
412            which = s[d.index(min(d))]
413
414            self.createNoticeBox1(title = "Notice", message = "Input data file missing or corrupted. " + which + " data missing. Close the window and restart.", command = self.frame.quit, buttonText = "Okay")
415            self.frame.bind("<Button-1>", self.quitNow)
416            self.frame.bind("<Button-3>", self.quitNow)
417
418        # Also, check if all of the loaded dictionaries have the same number of elements
419        if max(d) != min(d):
420
421            if d.count(min(d)) == 3:
422                print(1)
423                which = s[d.index(max(d))]
424            elif d.count(max(d)) == 3:
425                print(2)
426                which = s[d.index(min(d))]
427            else:
428                which = "Multiple"
429
430            self.createNoticeBox1(title = "Notice", message = "Input data file corrupted. " + which + " data corrupted. Close the window and restart.", command = self.frame.quit, buttonText = "Okay")
431            self.frame.bind("<Button-1>", self.quitNow)
432            self.frame.bind("<Button-3>", self.quitNow)
433           
434
435    # This quits the frame by events
436    def quitNow(self, event):
437
438        self.frame.quit()
439       
440
441    # A notice for functions being not implemented yet
442    def notImplementedYet(self):
443
444        self.createNoticeBox1(title = "Be Patient!", message = "Wait! This button is still under developement!", command = self.dismissNotice, buttonText = "Alright!")
445       
446
447    # Some commands want both checking and describing parameters to be done
448    def checkParameterWithDescription(self):
449       
450        self.checkParameter()
451        self.showDescription()
452
453
454    # Allow checking and describing parameters to be driven by events
455    def checkParameterEvent(self, event):
456
457        self.checkParameterWithDescription()
458
459
460    # Allow updating parameters to be driven by events
461    def updateParameterEvent(self, event):
462
463        self.updateParameter()
464
465       
466    # This checks the value of the parameter entered in the parameter entry box
467    def checkParameter(self):
468
469        # Determine which parameter the user wants to check
470        par = self.parameterEntry.get()
471
472        # Find which list it is in and determine its value
473        # Note that specified list takes priority
474        if par.lower() in lower(self.orderedSpecifiedParameters):
475            index = lower(self.orderedSpecifiedParameters).index(par.lower())
476            parameter2check = self.orderedSpecifiedParameters[index]
477            value = self.userSpecifiedParameters[parameter2check]
478            paramInfo = par + ': ' + value
479            self.color.set("Forest Green")
480            defaultYN = "Specified Value"
481        elif par.lower() in lower(self.orderedParameters):
482            index = lower(self.orderedParameters).index(par.lower())
483            parameter2check = self.orderedParameters[index]
484            value = self.defaultParameters[parameter2check]
485            paramInfo = parameter2check + ': ' + value
486            self.color.set("Forest Green")
487            defaultYN = "Default Value"
488        else:
489            value = "N/A"
490            paramInfo = '"' + par + '" does not exist'
491            self.color.set("Red")
492            defaultYN = "N/A"
493
494
495        # Store the results from the above
496        self.resultTitle.set("Parameter Information")
497        self.result.set(paramInfo)
498        self.notesTitle.set("Default/Specified")
499        self.notes.set(defaultYN)
500
501        self.valueEntry.delete(0, END)
502        self.valueEntry.insert(0, value)
503
504        # --------------------------------------------------
505        # Windows that correspond to the variables above
506        self.resultLabel = Label(self.frame, textvariable = self.resultTitle)
507        self.resultLabel.grid(row = 14, column = 1, pady = 0, columnspan = 2)
508
509        self.resultValue = Label(self.frame, textvariable = self.result, foreground = self.color.get())
510        self.resultValue.grid(row = 15, column = 1, pady = 10, columnspan = 2)
511
512        self.notesLabel = Label(self.frame, textvariable = self.notesTitle)
513        self.notesLabel.grid(row = 14, column = 3, pady = 0, columnspan = 2)
514
515        self.notesValue = Label(self.frame, textvariable = self.notes)
516        self.notesValue.grid(row = 15, column = 3, pady = 10, columnspan = 2)
517        # --------------------------------------------------
518       
519       
520    # This updates the value of the parameter entered in the parameter entry box
521    def updateParameter(self):
522
523        # Determine which parameter the user wants to update
524        par = self.parameterEntry.get()
525
526        # Update the value and determine if the parameter is being changed or added into the list
527        if par.lower() in lower(self.orderedSpecifiedParameters):
528            value2write = self.valueEntry.get()
529            index = lower(self.orderedSpecifiedParameters).index(par.lower())
530            parameter2update = self.orderedSpecifiedParameters[index]
531            self.userSpecifiedParameters[parameter2update] = value2write
532            paramInfo = parameter2update + ': ' + value2write
533            newParamYN = "Updated specified parameter list"
534            self.color.set("Blue")
535        elif par.lower() in lower(self.orderedParameters):
536            index = lower(self.orderedParameters).index(par.lower())
537            parameter2update = self.orderedParameters[index]
538            value2write = self.valueEntry.get()
539            self.userSpecifiedParameters[parameter2update] = value2write
540            paramInfo = parameter2update + ': ' + value2write
541            newParamYN = "Added in specified parameter list"
542            self.color.set("Blue")
543
544            self.orderedSpecifiedParameters = self.orderedSpecifiedParameters + [parameter2update]
545        else:
546            paramInfo = '"' + par + '" does not exist'
547            newParamYN = "-"
548            self.color.set("Red")
549
550        # Store the results from above
551        self.resultTitle.set("Parameter Information")
552        self.result.set(paramInfo)
553        self.notesTitle.set("Notes")
554        self.notes.set(newParamYN)
555
556        # --------------------------------------------------
557        # Windows that correspond to the variables above
558        self.resultLabel = Label(self.frame, textvariable = self.resultTitle)
559        self.resultLabel.grid(row = 14, column = 1, pady = 0, columnspan = 2)
560
561        self.resultValue = Label(self.frame, textvariable = self.result, foreground = self.color.get())
562        self.resultValue.grid(row = 15, column = 1, pady = 10, columnspan = 2)
563
564        self.notesLabel = Label(self.frame, textvariable = self.notesTitle)
565        self.notesLabel.grid(row = 14, column = 3, pady = 0, columnspan = 2)
566
567        self.notesValue = Label(self.frame, textvariable = self.notes)
568        self.notesValue.grid(row = 15, column = 3, pady = 10, columnspan = 2)
569        # --------------------------------------------------
570
571        # Update the effective parameters
572        self.effectiveParameters.update(self.defaultParameters) # In case default wasn't loaded before
573        self.effectiveParameters.update(self.userSpecifiedParameters)
574
575        # List specified parameters
576        self.listParameters("Specified")
577       
578
579    # This displays a description of the parameter entered in the parameter entry box
580    def showDescription(self):
581
582        # Determine which parameter to describe
583        par = self.parameterEntry.get()
584
585        # Determine if the parameter is within the description file
586        if par.lower() in lower(self.orderedParameters):
587            index = lower(self.orderedParameters).index(par.lower())
588            parameter2describe = self.orderedParameters[index]           
589            description = self.description[parameter2describe]
590        else:
591            parameter2describe = par
592            description = "No description available"
593
594        # Create the description
595        self.descriptionList = Listbox(self.frame, width = longestLineLength(self.defaultParameters) + 5, font = ('courier', (10)))
596        self.descriptionList.grid(row = 30, column = 1, columnspan = 4)
597
598        try:
599            self.descriptionList.insert(END, "Description of '" + parameter2describe + "'")
600            self.descriptionList.insert(END, "Class: " + self.classOfParameter[parameter2describe])
601            self.descriptionList.insert(END, "Type: " + self.paramType[parameter2describe])
602            self.descriptionList.insert(END, "Format: " + self.paramFormat[parameter2describe])
603            self.descriptionList.insert(END, " ")
604           
605        except KeyError:
606            self.descriptionList.delete(0, END)
607            self.descriptionList.insert(END, "Please Enter a parameter")
608            return
609       
610
611        descriptionWords = description.split()
612
613        largestWordLength = 0
614
615        for word in descriptionWords:
616            if len(word) > largestWordLength:
617                largestWordLength = len(word)
618        b = 0
619
620        for i in range(len(descriptionWords)):
621                           
622            phrase = ' '.join(descriptionWords[b:i])
623                           
624            if len(phrase) > longestLineLength(self.defaultParameters) - largestWordLength:
625                line = phrase
626
627                self.descriptionList.insert(END, line) 
628                b = i
629
630        self.descriptionList.insert(END, ' '.join(descriptionWords[b:]))
631
632    # This allows the user to revert a parameter to its default value   
633    def revertDefault(self):
634
635        # Determine which parameter the user wants to revert
636        parameter2revert = self.parameterEntry.get()
637
638        finalValue = self.defaultParameters.get(parameter2revert, "N/A")
639        paramInfo = parameter2revert + ': ' + finalValue
640
641        # Revert the value and determine if the parameter was already default
642        if parameter2revert in self.userSpecifiedParameters:
643
644            del(self.userSpecifiedParameters[parameter2revert])
645            self.orderedSpecifiedParameters.remove(parameter2revert)
646            alreadyDefaultYN = "Reverted back to default"
647            self.color.set("Sky Blue")
648        elif parameter2revert in self.defaultParameters:
649
650            alreadyDefaultYN = "Already default"
651            self.color.set("Sky Blue")
652        else:
653            paramInfo = '"' + parameter2revert + '" does not exist'
654            alreadyDefaultYN = "-"
655            self.color.set("Red")
656
657        # Store the results from above
658        self.resultTitle.set("Parameter Information")
659        self.result.set(paramInfo)
660        self.notesTitle.set("Notes")
661        self.notes.set(alreadyDefaultYN)
662
663        self.valueEntry.delete(0, END)
664        self.valueEntry.insert(0, finalValue)
665
666        # --------------------------------------------------
667        # Windows that correspond to the variables above
668        self.resultLabel = Label(self.frame, textvariable = self.resultTitle)
669        self.resultLabel.grid(row = 14, column = 1, pady = 0, columnspan = 2)
670
671        self.resultValue = Label(self.frame, textvariable = self.result, foreground = self.color.get())
672        self.resultValue.grid(row = 15, column = 1, pady = 10, columnspan = 2)
673
674        self.notesLabel = Label(self.frame, textvariable = self.notesTitle)
675        self.notesLabel.grid(row = 14, column = 3, pady = 0, columnspan = 2)
676
677        self.notesValue = Label(self.frame, textvariable = self.notes)
678        self.notesValue.grid(row = 15, column = 3, pady = 10, columnspan = 2)
679        # --------------------------------------------------
680
681        # Update the effective parameters
682        self.effectiveParameters.update(self.defaultParameters) # In case default wasn't loaded before
683        self.effectiveParameters.update(self.userSpecifiedParameters)
684       
685        # List the specified parameter values
686        self.listParameters("Specified")
687
688       
689    # This displays a list of parameters sets (depending on user command)
690    def listParameters(self, parameterSet):
691
692        paramOrder = self.orderedParameters
693       
694        if parameterSet == "Default":
695            self.parameters = self.defaultParameters
696        elif parameterSet == "Specified":
697            self.parameters = self.userSpecifiedParameters
698            paramOrder = self.orderedSpecifiedParameters
699        elif parameterSet == "Effective":
700            self.parameters = self.effectiveParameters
701        elif parameterSet == "Class":
702            self.effectiveParameters.update(self.defaultParameters) # In case default wasn't loaded before
703            self.effectiveParameters.update(self.userSpecifiedParameters)
704            self.parameters = self.effectiveParameters
705            className = self.whichClass.get()
706        else:
707            print("Coding Error: Used wrong parameter set.")
708            return
709
710        # If the list is empty, it means we haven't loaded it yet
711        if self.parameters == {}:
712           
713            self.createNoticeBox1(title = "Notice", message = "No " + parameterSet + " Parameter File Loaded", command = self.dismissNotice, buttonText = "Okay")
714
715        # Otherwise we can print it using the specified format
716        else:
717
718
719            self.paramListScrollBar = Scrollbar(self.frame)
720            self.paramListScrollBar.grid(row = 30, column = 5, ipady = 65)
721           
722            self.parameterList = Listbox(self.frame, yscrollcommand = self.paramListScrollBar.set, width = longestLineLength(self.defaultParameters) + 5, font = ('courier', (10)))
723            self.parameterList.grid(row = 30, column = 1, columnspan = 4)
724
725            if parameterSet == "Class":
726                self.parameterList.insert(END, className)
727            else:
728                self.parameterList.insert(END, parameterSet + " set of Parameters")
729               
730            self.parameterList.insert(END, " ")
731
732            star = 0
733
734            for par in paramOrder:
735
736                if parameterSet == "Effective":
737                    if par in self.userSpecifiedParameters:
738                        star = 1
739                    else:
740                        star = 0
741                       
742                if parameterSet == "Class":
743
744                    if self.classOfParameter[par] == className:
745
746                        if par in self.userSpecifiedParameters:
747                            star = 1
748                        else:
749                            star = 0
750
751                        tabbedPar = tabbedDictionaryLine(self.parameters, par, star)
752                        self.parameterList.insert(END, tabbedPar + self.parameters[par])
753                   
754                else:
755                    tabbedPar = tabbedDictionaryLine(self.parameters, par, star)
756                    self.parameterList.insert(END, tabbedPar + self.parameters[par])
757
758                   
759
760            self.paramListScrollBar.config(command = self.parameterList.yview)
761
762            self.list2read = self.parameterList
763            self.parameterList.bind("<ButtonRelease-1>", self.checkItem)
764            self.parameterList.bind("<ButtonRelease-3>", self.checkItemDescript)
765            self.parameterList.bind("<Return>", self.checkItemDescript)
766
767
768    # When description is not needed
769    def checkItem(self, event):
770
771        self.doCheckItem(0)
772
773
774    # When description is needed
775    def checkItemDescript(self, event):
776
777        self.doCheckItem(1)
778
779    # When buttons are pressed on the lists, the items will be checked or described.
780    def doCheckItem(self, describeFlag):
781
782        try:
783            if int(self.list2read.curselection()[0]) != 0:
784
785                line = self.list2read.get(self.list2read.curselection())
786                linebits = line.split()
787                parameter = linebits[0]
788
789                self.parameterEntry.delete(0, END)
790                self.parameterEntry.insert(0, parameter)
791
792                if describeFlag == 0:
793                    self.checkParameter()
794                elif describeFlag == 1:
795                    self.checkParameterWithDescription()
796                else:
797                    print("Coding Error: Describe flag not binary")
798                   
799        except IndexError:
800            pass
801       
802
803    # This handles the input interface (loading a file)
804    def createInputInterface(self):
805
806        self.file_opt = options = {}
807        options['defaultextension'] = '.txt'
808        options['filetypes'] = [('text files', '.txt'), ('all files', '.*')]
809        options['initialdir'] = os.getcwd
810        options['initialfile'] = 'duchampHIPASS.txt'
811        options['parent'] = self.frame
812        options['title'] = 'Load Parameter File'
813
814        self.userSpecifiedFilePath = tkFileDialog.askopenfilename(**self.file_opt)
815
816        self.userSpecifiedFileName = self.userSpecifiedFilePath.split('/')[-1]
817        self.loadInputFile()
818       
819
820    # This handles the output interface for specified parameters (saving a file)
821    def createSpecifiedOutputInterface(self):
822       
823        self.file_opt = options = {}
824        options['defaultextension'] = '.txt'
825        options['filetypes'] = [('text files', '.txt'), ('all files', '.*')]
826        options['initialdir'] = os.getcwd
827        options['initialfile'] = self.userSpecifiedFileName.split('.')[0] + 'Edited.' + self.userSpecifiedFileName.split('.')[1]
828        options['parent'] = self.frame
829        options['title'] = 'Save User Specified Parameters'
830
831        self.newFilePath = tkFileDialog.asksaveasfilename(**self.file_opt)
832
833        writeParamFile(self.newFilePath, self.userSpecifiedParameters, self.orderedSpecifiedParameters, 1)
834
835
836    # This handles the output interface for effective parameters (saving a file)
837    def createEffectiveOutputInterface(self):
838       
839        self.file_opt = options = {}
840        options['defaultextension'] = '.txt'
841        options['filetypes'] = [('text files', '.txt'), ('all files', '.*')]
842        options['initialdir'] = os.getcwd
843        options['initialfile'] = self.userSpecifiedFileName.split('.')[0] + 'AllEdited.' + self.userSpecifiedFileName.split('.')[1]
844        options['parent'] = self.frame
845        options['title'] = 'Save List of Effective Parameters'
846
847        self.newFilePath = tkFileDialog.asksaveasfilename(**self.file_opt)
848
849        writeParamFile(self.newFilePath, self.effectiveParameters, self.orderedParameters, 1)
850       
851
852    # This decides whether to load or update the input files for specified parameters
853    def loadInputFile(self):
854
855        try:
856            fin = open(self.userSpecifiedFilePath, 'r')
857            fin.close()
858           
859            # If the list is empty, that means we are loading the file for the first time
860            if self.userSpecifiedParameters == {}:
861
862                self.createNoticeBox1(title = "Notice", message = "Input Files Loaded", command = self.load, buttonText = "Okay")
863
864            # If the list is non-empty, this means we risk rewritting any edits we have made
865            else:
866
867                msg = "Are you sure? Any edits you've made in the previous session will be lost and replaced with the contents of the new files."
868                self.createNoticeBox2(title = "Notice", message = msg, command1 = self.load, command2 = self.dismissNotice, buttonText1 = "Yes", buttonText2 = "No")
869        except IOError:
870            pass
871        except TypeError:
872            pass
873            print("TypeError")
874           
875       
876    # This loads or updates the input files for specified parameters
877    def load(self):
878
879        # The notice box can go away
880        self.noticeBox.destroy()
881
882        # Then we can determine the list of specified and effective parameters
883        (self.userSpecifiedParameters, self.orderedSpecifiedParameters) = readParamFile(self.userSpecifiedFilePath)
884        self.effectiveParameters.update(self.userSpecifiedParameters)
885       
886        messages = []
887       
888        # If the file is empty, let the user know.
889        if self.userSpecifiedParameters == {}:
890
891            messages += ["The file you loaded is empty. Parameter file discarded."]
892           
893        # Otherwise, determine if some parameters are not part of the default set of parameters.
894        else:
895            self.listParameters("Specified")
896
897            for par in self.orderedSpecifiedParameters:
898
899                if par not in self.defaultParameters:
900
901                    messages += ["Some parameters loaded are not part of the default set of parameters."]
902                    break
903
904        fin = open(self.userSpecifiedFilePath)
905
906        # Also, determine if the format was not correct.
907        for line in fin:
908
909            if line[0] != '#' and len(line) > 1 and len(line.split()) > 1:
910
911                if len(line.split()) != 2:
912
913                    messages += ["File loaded has the wrong format. Loaded inputs may be incorrect."]
914                    break
915
916        fin.close()
917
918        # Let the user know of the above detections
919        for msg in messages:
920
921            self.createNoticeBox1(title = "Notice", message = msg, command = self.dismissNotice, buttonText = "Dismiss")
922               
923
924       
925
926
927   
928
929
930
931
932
933
934
935def main():
936   
937    root = Tk()
938    root.wm_title("Duchamp Parameters")
939
940    interface = mainInterface(root)
941    root.config(menu = interface.menubar)
942    root.mainloop()
943
944    try:
945        root.destroy()
946    except TclError:
947        pass
948
949if __name__ == '__main__':
950    main()
Note: See TracBrowser for help on using the repository browser.