1 import sys
2 import types
3 import textwrap
4 import traceback
5
8 self.menus = {}
9 self.width = 80
10 self.onException = "ASK"
11 self.auto = False
12 self.closingMessage = ""
13
15 nextMenu = mainMenu
16 prevMenu = None
17 while nextMenu != None:
18 currentMenu = self.menus[nextMenu]
19 nextMenu = currentMenu.show(prevMenu)
20 if type(nextMenu) == types.ListType:
21 for next in nextMenu:
22 self.run(next)
23 nextMenu = None
24 prevMenu = currentMenu
25
27 if self.closingMessage != None:
28 print >> sys.stderr
29 print >> sys.stderr, self.closingMessage
30
32 if not hasattr(self, attrName):
33 setattr(self, attrName, value)
34
36 system = MenuSystem()
37
39 if name == "SPACE":
40 return Option(None, None)
41
43 if addToSystem:
44 assert title not in Menu.system.menus
45 Menu.system.menus[title] = self
46
47 self.title = title
48 self.text = text
49 self.options = options
50 self.optDict = {}
51 for i in range(len(options)):
52 option = options[i]
53
54 if type(option) in types.StringTypes:
55 option = self.getDefaultOption(option)
56 options[i] = option
57
58 if option.key != None:
59 option.menu = self
60 assert option.key not in self.optDict
61 self.optDict[option.key] = option
62 if option.dataInput != None:
63 self.setAttr(option.dataInput)
64 self.prevChoice = None
65 self.initializer = initializer
66 self.doAlignText = True
67
69 for option in self.options:
70 option.isDefault = False
71 self.optDict[key].isDefault = True
72
74 if not hasattr(self, attrName) or getattr(self, attrName) == None:
75 return ""
76 else:
77 return getattr(self, attrName)
78
80
81 setattr(self, attrName, value)
82
84 if self.doAlignText:
85 print >> sys.stderr, self.alignText(self.text)
86 else:
87 print >> sys.stderr, self.text
88
90 if title != None:
91 border = ((self.system.width - len(title) - 2) / 2) * style
92 titleBar = border + " " + title + " " + border
93 titleBar += (len(titleBar) - self.system.width) * style
94 print >> sys.stderr, titleBar
95 else:
96 print >> sys.stderr, self.system.width * style
97
99 for option in self.options:
100 option.show()
101
118
120 choice = None
121 default = None
122 for item in items:
123 if item.isDefault:
124 default = item
125 break
126 while choice == None:
127 choice = raw_input(">")
128
129 if choice.strip() == "" and default != None:
130 choice = default.key
131 print >> sys.stderr
132 if choice.lower() in self.optDict.keys():
133 choiceLower = choice.lower()
134 opt = self.optDict[choiceLower]
135 self.prevChoice = choiceLower
136 if opt.toggle != None:
137 opt.toggle = not opt.toggle
138 return self.title
139 elif opt.dataInput != None:
140 setattr(self, opt.dataInput, self.getDataInput(opt.dataInput))
141 return self.title
142 else:
143 opt.do()
144 return opt.nextMenu
145 else:
146 print >> sys.stderr, "Unknown option", choice
147 choice == None
148 return self.title
149
151 lines = text.split("\n")
152 paragraphs = [""]
153 for line in lines:
154 if line.strip() == "":
155 paragraphs.append("")
156 else:
157 paragraphs[-1] += line.strip() + " "
158 paragraphsToKeep = []
159 for paragraph in paragraphs:
160 paragraph = "\n".join(textwrap.wrap(paragraph, width=self.system.width))
161 if paragraph.strip() != "":
162 paragraphsToKeep.append(paragraph)
163 return "\n\n".join(paragraphsToKeep)
164
166
167
168 if self.initializer != None:
169 self.initializer(self, prevMenu)
170 print >> sys.stderr
171 self.printBorder(self.title)
172 self.printText()
173 self.printBorder(style="-")
174 assert self.options != None and len(self.options) >= 1
175 self.printOptions()
176 self.printBorder()
177 return self.getChoice(self.options)
178
180 SPACE = "SPACE"
181 QUIT = "QUIT"
182
183 - def __init__(self, key, text, nextMenu=None, handler=None, isDefault=False, toggle=None, dataInput=None, handlerArgs=[]):
184 self.key = key
185 self.text = text
186 self.toggle = toggle
187 self.dataInput = dataInput
188 self.isDefault = isDefault
189 self.menu = None
190 self.handler = handler
191 self.handlerArgs = handlerArgs
192 self.nextMenu = nextMenu
193
194 - def show(self, alignText=True):
195 if self.key == None:
196 print >> sys.stderr
197 return
198
199 if self.isDefault:
200 print >> sys.stderr, " * ",
201 elif self.toggle != None:
202 if self.toggle:
203 print >> sys.stderr, "[X]",
204 else:
205 print >> sys.stderr, "[ ]",
206 else:
207 print >> sys.stderr, " ",
208 print >> sys.stderr, self.key + ")",
209
210 if self.dataInput != None:
211 print >> sys.stderr, self.text, "(" + self.menu.getAttrString(self.dataInput) + ")"
212 else:
213 print >> sys.stderr, self.text
214
216 if self.handler == None:
217 return
218 elif type(self.handler) == types.ListType:
219 for i in range(len(self.handler)):
220 if len(self.handlerArgs) > i:
221 self._runHandler(self.handler[i], self.handlerArgs[i])
222 else:
223 self._runHandler(self.handler[i])
224 else:
225 self._runHandler(self.handler, self.handlerArgs)
226
228 try:
229 handler(*handlerArgs)
230 except Exception, e:
231 print >> sys.stderr
232 print >> sys.stderr, "***", "Exception processing menu '" + self.menu.title + "' option '" + self.key + " (" + self.text + ")", "***"
233 print >> sys.stderr, "Exception:", e
234 traceback.print_exc(file=sys.stderr)
235 assert self.menu.system.onException in ["EXIT", "IGNORE", "ASK"]
236 if self.menu.system.onException == "EXIT":
237 print >> sys.stderr, "Exiting"
238 sys.exit(1)
239 elif self.menu.system.onException == "IGNORE":
240 print >> sys.stderr, "Ignoring error and continuing"
241 else:
242 Option.exceptionMenu.show()
243 print >> sys.stderr, "Ignoring error and continuing"
244
245 Option.exceptionMenu = Menu("Error", "There was an error processing the menu option. Please choose whether to quit or continue",
246 [Option("i", "Ignore and continue"),
247 Option("q", "Quit", isDefault=True, handler=sys.exit, handlerArgs=[1])],
248 addToSystem=False)
249
250
251
252
253
254
255
256
257
258 if __name__=="__main__":
259
260 try:
261 import psyco
262 psyco.full()
263 print >> sys.stderr, "Found Psyco, using"
264 except ImportError:
265 print >> sys.stderr, "Psyco not installed"
266
267 m = Menu("Main menu",
268 "Some Text."
269 [Option("Y", "Yes", None, True), Option("N", "No")])
270 m.show()
271