forked from onp/gmcr-py
-
Notifications
You must be signed in to change notification settings - Fork 0
/
widgets_f05_01_PrefRank.py
154 lines (121 loc) · 5.79 KB
/
widgets_f05_01_PrefRank.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# Copyright: (c) Oskar Petersons 2013
"""Widgets used for validating and manually entering state rankings.
Loaded by the frame_05_preferenceRanking module.
"""
from tkinter import StringVar, N, S, E, W, Text
from tkinter import ttk
from ast import literal_eval
import data_03_gmcrUtilities as gmcrUtil
NSEW = (N, S, E, W)
class RankingEditor(ttk.Frame):
"""Display and edit the state ranking for a single Decision Maker."""
def __init__(self, master, conflict, dm):
"""Initialize a RankingEditor widget for a decision maker."""
ttk.Frame.__init__(self, master, borderwidth=2)
self.master = master
self.conflict = conflict
self.dm = dm
self.columnconfigure(1, weight=1)
self.dmText = StringVar(value=dm.name + ': ')
self.dmLabel = ttk.Label(self, textvariable=self.dmText, width=20)
self.dmLabel.grid(row=0, column=0, sticky=NSEW)
self.prefRankVar = StringVar(value=str(dm.perceivedRanking))
self.prefRankEntry = ttk.Entry(self, textvariable=self.prefRankVar)
self.prefRankEntry.grid(row=0, column=1, sticky=NSEW)
self.errorDetails = None
self.prefRankEntry.bind("<FocusOut>", self.onFocusOut)
def onFocusOut(self, event):
"""Validate the preference ranking when focus leaves the widget."""
try:
perceivedRank = literal_eval(self.prefRankVar.get())
except SyntaxError:
self.errorDetails = ("DM {}'s preference ranking is "
"invalid.").format(self.dm.name)
self.master.event_generate("<<errorChange>>")
return
except NameError:
self.errorDetails = ("DM {}'s preference ranking is "
"invalid.").format(self.dm.name)
self.master.event_generate("<<errorChange>>")
return
prefRank = perceivedRank + self.dm.misperceived
self.errorDetails = gmcrUtil.validatePreferenceRanking(
prefRank, self.conflict.feasibles)
if self.errorDetails:
self.errorDetails += (" Check DM {}'s preference "
"ranking.").format(self.dm.name)
self.master.event_generate("<<errorChange>>")
return
self.dm.preferenceRanking = prefRank
self.dm.calculatePreferences()
self.master.event_generate("<<errorChange>>")
def enableWidget(self):
"""Enable editting of the ranking."""
self.prefRankEntry['state'] = 'normal'
def disableWidget(self):
"""Disable editting of the ranking."""
self.prefRankEntry['state'] = 'disabled'
class PRankEditMaster(ttk.Frame):
"""Contains a RankingEditor for each DM, plus an error box."""
def __init__(self, master, conflict):
"""Initialize a preference ranking master widget for the conflict."""
ttk.Frame.__init__(self, master, borderwidth=2)
self.conflict = conflict
self.columnconfigure(0, weight=1)
self.activateButton = ttk.Button(
self,
text="Press to enable manual preference ranking changes",
command=self.enableEditing)
self.activateButton.grid(row=0, column=0, sticky=NSEW)
self.editorFrame = ttk.Frame(self)
self.editorFrame.grid(row=2, column=0, sticky=NSEW)
self.editorFrame.columnconfigure(0, weight=1)
self.errorDisplay = Text(self, height=6)
self.errorDisplay['state'] = 'disabled'
self.errorDisplay.grid(row=3, column=0, sticky=(N, E, W))
self.editorFrame.bind('<<errorChange>>', self.updateErrors)
def refresh(self):
"""Refresh the widget and all children."""
for child in self.editorFrame.winfo_children():
child.destroy()
self.rankingEditors = []
for idx, dm in enumerate(self.conflict.decisionMakers):
newEditor = RankingEditor(self.editorFrame, self.conflict, dm)
self.rankingEditors.append(newEditor)
newEditor.grid(row=idx, column=0, sticky=NSEW)
self.updateErrors()
if not self.conflict.useManualPreferenceRanking:
self.activateButton['text'] = ("Click to enable manual preference "
"ranking changes")
self.activateButton['state'] = 'normal'
for editor in self.rankingEditors:
editor.disableWidget()
else:
self.activateButton['text'] = ("Preference rankings entered below "
"will be used in analysis.")
self.activateButton['state'] = 'disabled'
def enableEditing(self):
"""Switch on manual editing of the preference rankings."""
self.activateButton['text'] = ("Preference rankings entered below "
"will be used in analysis.")
self.activateButton['state'] = 'disabled'
for editor in self.rankingEditors:
editor.enableWidget()
self.conflict.useManualPreferenceRanking = True
def updateErrors(self, event=None):
"""Update the messages in the error box."""
messages = [editor.errorDetails for editor in self.rankingEditors
if editor.errorDetails]
self.conflict.preferenceErrors = len(messages)
self.errorDisplay['state'] = 'normal'
self.errorDisplay.delete('1.0', 'end')
if len(messages) > 0:
text = '\n'.join(messages)
self.errorDisplay.insert('1.0', text)
self.errorDisplay['foreground'] = 'red'
else:
self.errorDisplay.insert(
'1.0', "No Errors. Preference rankings are valid.")
self.errorDisplay['foreground'] = 'black'
self.event_generate("<<PreferenceRankingChange>>")
self.errorDisplay['state'] = 'disabled'