1 """module 'tpar.py' -- main module for generating the tpar task editor
2
3 tpar is curses based parameter editing similar to epar. Tpar has the
4 primary goal of simplicity similar to IRAF's CL epar and as such is
5 missing many PyRAF epar features. The primary advantage of tpar is
6 that it works in a simple terminal window (rather than requiring full
7 X-11 and Tk); this is an improvement for low bandwidth network
8 contexts or for people who prefer text interfaces to GUIs.
9
10 $Id: tpar.py 1194 2010-05-14 17:57:37Z sontag $
11
12 Todd Miller, 2006 May 30 derived from epar.py and IRAF CL epar.
13 """
14 from __future__ import division
15
16
17
18 import os, sys, string, commands, re
19
20
21
27
33
34
35 URWID_PRE_9P9 = False
36
37 try:
38 import urwid.curses_display
39 import urwid.raw_display
40 import urwid
41 import urwutil
42 import urwfiledlg
43 urwid.set_encoding("ascii")
44 if 0==urwid.__version__.find('0.9.8') or 0==urwid.__version__.find('0.9.7'):
45 URWID_PRE_9P9 = True
46 except Exception, e:
47 urwid = FakeModule()
48 urwid.Edit = FakeClass()
49 urwid.Columns = FakeClass()
50 urwid.AttrWrap = FakeClass()
51 urwid.Pile = FakeClass()
52 urwid.the_error = str(e)
53
54
55 import iraf, irafpar, irafhelp, iraftask, cStringIO, iraffunctions
56
57 TPAR_HELP_EMACS = """ EDIT COMMANDS (emacs)
58
59 DEL_CHAR = DEL MOVE_RIGHT = RIGHT_ARROW
60 DEL_LEFT = ^H_or_BS MOVE_RIGHT = ^F
61 DEL_LINE = ^K MOVE_START = ESC-<
62 DEL_WORD = ESC-D MOVE_UP = UP_ARROW
63 DEL_WORD = ESC-d MOVE_UP = ^P
64 EXIT_NOUPD = ^C NEXT_PAGE = ^V
65 EXIT_UPDAT = ^D NEXT_WORD = ESC-F
66 NEXT_WORD = ESC-f
67 GET_HELP = ESC-? PREV_PAGE = ESC-V
68 MOVE_BOL = ^A PREV_PAGE = ESC-v
69 MOVE_DOWN = DOWN_ARROW PREV_WORD = ESC-B
70 MOVE_DOWN = ^N PREV_WORD = ESC-b
71 MOVE_END = ESC-> REPAINT = ^L
72 MOVE_EOL = ^E UNDEL_CHAR = ESC-^D
73 MOVE_LEFT = LEFT_ARROW UNDEL_LINE = ESC-^K
74 MOVE_LEFT = ^B UNDEL_WORD = ESC-^W
75
76 X-11 Paste: hold down shift and click middle mouse button
77
78 :e[!] [pset] edit pset "!" == no update
79 :q[!] exit tpar "!" == no update
80 :r! unlearn
81 :w[!] [pset] unsupported
82 :g[!] run task
83 """
84
85 TPAR_BINDINGS_EMACS = {
86 "ctrl c" : "quit",
87 "ctrl C" : "quit",
88 "ctrl d" : "exit",
89 "ctrl D" : "exit",
90 "ctrl z" : "exit",
91 "ctrl Z" : "exit",
92
93 "ctrl p" : "up",
94 "ctrl P" : "up",
95 "shift tab": "up",
96
97 "ctrl n" : "down",
98 "ctrl N" : "down",
99
100 "esc v" : "page down",
101 "esc V" : "page down",
102
103 "esc p" : "page up",
104 "esc P" : "page up",
105
106
107
108
109 "ctrl K" : "del_line",
110 "ctrl k" : "del_line",
111
112 "esc d": "del_word",
113 "esc D": "del_word",
114
115 "esc f": "next_word",
116 "esc F": "next_word",
117
118 "esc b": "prev_word",
119 "esc B": "prev_word",
120
121 "ctrl a": "move_bol",
122 "ctrl A": "move_bol",
123
124 "ctrl e": "move_eol",
125 "ctrl E": "move_eol",
126
127 "esc >": "end",
128 "esc <": "home",
129
130 "ctrl f": "right",
131 "ctrl F": "right",
132
133 "ctrl b": "left",
134 "ctrl B": "left",
135
136 "esc ctrl d": "undel_char",
137 "esc ctrl k": "undel_line",
138 "ctrl y": "undel_line",
139 "esc ctrl w": "undel_word",
140
141 "esc ?": "help"
142 }
143
144
145 TPAR_HELP_VI = """ EDIT COMMANDS (vi)
146
147 DEL_CHAR = BACKSPACE MOVE_LEFT = ^H
148 DEL_LEFT = DEL MOVE_RIGHT = RIGHT_ARROW
149 DEL_LINE = ^I^D MOVE_RIGHT = ^L
150 DEL_WORD = ^I^W MOVE_START = ^T^S
151 EXIT_NOUPD = ^C MOVE_UP = UP_ARROW
152 EXIT_UPDAT = ^D MOVE_UP = ^K
153 EXIT_UPDAT = ^Z NEXT_PAGE = ^N
154 GET_HELP = ESC-? NEXT_WORD = ^W
155 MOVE_BOL = ^A PREV_PAGE = ^P
156 MOVE_DOWN = DOWN_ARROW PREV_WORD = ^B
157 MOVE_DOWN = ^J REPAINT = ^R
158 MOVE_END = ^T^E UNDEL_CHAR = ^U^C
159 MOVE_EOL = ^E UNDEL_LINE = ^U^L
160 MOVE_LEFT = LEFT_ARROW UNDEL_WORD = ^U^W
161
162 X-11 Paste: hold down shift and click middle mouse button
163
164 :e[!] [pset] edit pset "!" == no update
165 :q[!] exit tpar "!" == no update
166 :r! unlearn
167 :w[!] [pset] unsupported
168 :g[!] run task
169 """
170
171 TPAR_BINDINGS_VI = {
172 "ctrl c" : "quit",
173 "ctrl d" : "exit",
174 "ctrl C" : "quit",
175 "ctrl D" : "exit",
176
177 "ctrl K" : "up",
178 "ctrl k" : "up",
179
180 "ctrl j" : "down",
181 "ctrl J" : "down",
182
183 "ctrl n" : "page down",
184 "ctrl N" : "page down",
185
186 "ctrl p" : "page up",
187 "ctrl P" : "page up",
188
189
190
191
192 "tab ctrl D" : "del_line",
193 "tab ctrl d" : "del_line",
194
195 "tab ctrl W": "del_word",
196 "tab ctrl w": "del_word",
197
198 "ctrl w": "next_word",
199 "ctrl W": "next_word",
200
201 "ctrl b": "prev_word",
202 "ctrl B": "prev_word",
203
204 "ctrl a": "move_bol",
205 "ctrl A": "move_bol",
206
207 "ctrl e": "move_eol",
208 "ctrl E": "move_eol",
209
210 "ctrl T ctrl E": "end",
211 "ctrl t ctrl e": "end",
212 "ctrl T ctrl S": "home",
213 "ctrl t ctrl s": "home",
214
215 "ctrl L": "right",
216 "ctrl l": "right",
217
218 "ctrl H": "left",
219 "ctrl h": "left",
220
221 "ctrl U ctrl C": "undel_char",
222 "ctrl u ctrl c": "undel_char",
223
224 "ctrl U ctrl L": "undel_line",
225 "ctrl u ctrl l": "undel_line",
226
227 "ctrl U ctrl W": "undel_word",
228 "ctrl u ctrl w": "undel_word",
229
230 "esc ?": "help"
231 }
232
234 """The Binder class manages keypresses for urwid and adds the
235 ability to bind specific inputs to actions.
236 """
237 - def __init__(self, bindings, inform, mode_keys=[]):
238 self.bindings = bindings
239 self.inform = inform
240 self.mode_keys = mode_keys
241 self.chord = []
242
243 - def bind(self, k, f):
245
247 if key is None:
248 return
249 if key is "ready":
250 if self.bindings.has_key("ready"):
251 return self.bindings["ready"]()
252 else:
253 return "ready"
254 self.debug("pos: %s key: %s" % (pos, key))
255 if key in self.mode_keys:
256 self.chord.append(key)
257 return None
258 elif not urwid.is_mouse_event(key):
259 key = " ".join(self.chord + [key])
260 self.chord = []
261 visited = []
262 while self.bindings.has_key(key) and key not in visited:
263 visited.append(key)
264 f = self.bindings[key]
265 if f is None:
266 key = None
267 elif isinstance(f, str):
268 key = f
269 else:
270 key = f()
271 self.debug("pos: %s visited: %s key: %s mapping: %s" % \
272 (pos, " --> ".join(visited), key, f))
273 return key
274
278
280 """PyrafEdit is a text entry widget which has keybindings similar
281 to IRAF's CL epar command.
282 """
284 inform = keys["inform"]
285 del keys["inform"]
286 self.reset_del_buffers()
287 urwid.Edit.__init__(self, *args, **keys)
288 EDIT_BINDINGS = {
289 "delete" : self.DEL_CHAR,
290 "del_line": self.DEL_LINE,
291 "del_word": self.DEL_WORD,
292
293 "undel_char": self.UNDEL_CHAR,
294 "undel_word": self.UNDEL_WORD,
295 "undel_line": self.UNDEL_LINE,
296
297 "next_word": self.NEXT_WORD,
298 "prev_word": self.PREV_WORD,
299
300 "move_bol": self.MOVE_BOL,
301 "move_eol": self.MOVE_EOL,
302
303 "right": self.MOVE_RIGHT,
304 "left": self.MOVE_LEFT,
305 }
306 self._binder = Binder(EDIT_BINDINGS, inform)
307
309 self._del_words = []
310 self._del_lines = []
311 self._del_chars = []
312
314 s = self.get_edit_text()
315 if len(s):
316 n = self.edit_pos
317 if n >= len(s):
318 n -= 1
319 c = s[n]
320 self.set_edit_text(s[:n] + s[n+1:])
321 self._del_chars.append(c)
322
324 s = self.get_edit_text()
325 i = self.edit_pos
326 while i > 0 and not s[i].isspace():
327 i -= 1
328 if s[i].isspace():
329 i += 1
330 word = ""
331 while i < len(s) and not s[i].isspace():
332 word += s[i]
333 i += 1
334 s = s[:i-len(word)] + s[i:]
335 self._del_words.append(word)
336 self.edit_pos = i
337 self.set_edit_text(s)
338
340 s = self.get_edit_text()
341 line = s[self.edit_pos:]
342 self.set_edit_text(s[:self.edit_pos])
343 self.set_edit_pos(len(self.get_edit_text()))
344 self._del_lines.append(line)
345
347 s = self.get_edit_text()
348 i = self.edit_pos
349 while s and i < len(s)-1 and not s[i].isspace():
350 i += 1
351 while s and i < len(s)-1 and s[i].isspace():
352 i += 1
353 self.edit_pos = i
354
356 s = self.get_edit_text()
357 i = self.edit_pos
358 while s and i > 0 and s[i].isspace():
359 i -= 1
360 while s and i > 0 and not s[i].isspace():
361 i -= 1
362 self.edit_pos = i
363
366
368 self.edit_pos = len(self.get_edit_text())
369
371 if self.edit_pos < len(self.get_edit_text()):
372 self.edit_pos += 1
373
375 if self.edit_pos > 0:
376 self.edit_pos -= 1
377
379 try:
380 char = self._del_chars.pop()
381 except:
382 return
383 self.insert_text(char)
384 self.edit_pos -= 1
385
387 try:
388 word = self._del_words.pop()
389 except:
390 return
391 self.insert_text(word)
392
394 try:
395 if len(self._del_lines) > 1:
396 line = self._del_lines.pop()
397 else:
398 line = self._del_lines[0]
399 except:
400 return
401 self.insert_text(line)
402
404 key = Binder.keypress(self._binder, pos, key)
405 if key is not None and not urwid.is_mouse_event(key):
406 key = urwid.Edit.keypress(self, pos, key)
407 return key
408
410 return self.get_edit_text().strip()
411
414
416 - def __init__(self, paramInfo, defaultParamInfo, inform):
417
418 MODE_KEYS = []
419
420 BINDINGS = {
421 "enter" : self.ENTER,
422 "up" : self.MOVE_UP,
423 "down" : self.MOVE_DOWN,
424 "page up" : self.PAGE_UP,
425 "page down" : self.PAGE_DOWN,
426 "undel_line": self.UNDEL_LINE,
427 "ready" : self.READY_LINE,
428 "end" : self.MOVE_END,
429 "home": self.MOVE_START
430 }
431
432 self._binder = Binder(BINDINGS, inform, MODE_KEYS)
433
434 self._mode = "clear"
435 self._newline = True
436 self.inform = inform
437 self.paramInfo = paramInfo
438 self.defaultParamInfo = defaultParamInfo
439
440 name = self.paramInfo.name
441 value = self.paramInfo.get(field = "p_filename", native = 0,
442 prompt = 0)
443 self._previousValue = value
444
445
446 if (self.paramInfo.get(field = "p_mode") == "h"):
447 required=False
448 else:
449 required=True
450
451 help = self.paramInfo.get(field = "p_prompt", native = 0, prompt = 0)
452 self._args = (name, value, help, required)
453 if not required:
454 name = "(" + name
455 help = ") " + help
456 else:
457 help = " " + help
458 self._name = urwid.Text( "%-10s=" % name )
459 self._edit = PyrafEdit("", "", wrap="clip", align="right", inform=inform)
460 self._edit.verify = self.verify
461 self._value = urwid.Text( "%10s" % value, align="right" )
462 self._help = urwid.Text( "%-30s" % help )
463 urwid.Columns.__init__( self, [('weight',0.20, self._name),
464 ('weight',0.20, self._edit),
465 ('weight',0.20, self._value),
466 ('weight',0.40, self._help)],
467 0, 1, 1)
468
470 key = Binder.keypress(self._binder, pos, key)
471 if key:
472 key = self._edit.keypress(pos, key)
473 return key
474
477
479 return self._edit.get_edit_text()
480
482 self._edit.set_edit_text(s)
483 self._edit.edit_pos = len(s)
484
486 """abstract method called to standardize equivalent values
487 when the 'result' is set."""
488 return v
489
491 return self._value.get_text()[0].strip()
492
494 self._value.set_text( self.normalize(str(r)) )
495
498
500 self.inform("")
501 return True
502
504 v = self.get_result()
505 if v:
506 self.set_candidate( self.get_candidate() + v)
507 self.set_result("")
508 else:
509 return "undel_line"
510
513
516
519
521 return self.linechange("page up")
522
523 - def PAGE_DOWN(self):
524 return self.linechange("page down")
525
528
531
533 """Updates this field when changing the field focus,
534 i.e. switching lines."""
535 s = self.get_candidate()
536 if s != "":
537 if self.verify(s):
538 self.set_result(s)
539 self.set_candidate("")
540 else:
541 return None
542 else:
543 self.inform("")
544 self._edit.set_edit_pos(0)
545 self._edit.reset_del_buffers()
546 self._newline = True
547 return rval
548
550 """Prepares this field for editing in the current
551 mode: default clear or default edit."""
552 if not self._newline:
553 return
554 self._newline = False
555 if self._mode == "clear":
556 self.set_candidate("")
557 else:
558 s = self.get_result()
559 self.set_candidate( s )
560 self._edit.set_edit_pos( len(s) )
561
564
565
568 if v in ["INDEF","Indef","indef"]:
569 return "INDEF"
570 else:
571 return v
572
574 try:
575 if v != self._previousValue:
576 self.paramInfo.set(v)
577 self.paramInfo.set(self._previousValue)
578 return True
579 except ValueError, e:
580 self.set_candidate("")
581 self.inform(str(e))
582 return False
583
586
594
600
602 if v in ["n","N"]:
603 return "no"
604 elif v in ["y","Y"]:
605 return "yes"
606 else:
607 return v
608
610 v = self.normalize(v)
611 if v in ["yes","no"]:
612 self.inform("")
613 return True
614 else:
615 self.set_candidate("")
616 self.inform("Not a valid boolean value.")
617 return False
620
628
629 - def adjust(self, delta, wrap):
630 choices = self.paramInfo.choice
631 try:
632 v = choices[ choices.index(self.get_result()) + delta ]
633 except IndexError:
634 v = choices[ wrap ]
635 self.set_result(v)
636
639
641 return self.adjust(-1, -1)
642
643
646
648 if v not in self.paramInfo.choice:
649 self.inform("What? choose: " + "|".join(self.paramInfo.choice))
650 self.set_candidate("")
651 return False
652 return True
653
657
659 banner = """ I R A F
660 Image Reduction and Analysis Facility
661 """
663 top = urwid.Text(("header", self.banner))
664 s = "%8s= %-10s\n" % ("PACKAGE", package)
665 if task is not None:
666 s += "%8s= %-10s" % ("TASK", task)
667 info = urwid.Text(("body", s))
668 urwid.Pile.__init__(self, [top, info])
669
670
672 palette = [
673 ('body','default','default', 'standout'),
674 ('header', 'default', 'default', ('standout', 'underline')),
675 ('help','black','light gray'),
676 ('reverse','light gray','black'),
677 ('important','dark blue','light gray',('standout','underline')),
678 ('editfc','white', 'dark blue', 'bold'),
679 ('editbx','light gray', 'dark blue'),
680 ('editcp','black','light gray', 'standout'),
681 ('bright','dark gray','light gray', ('bold','standout')),
682 ('buttn','black','dark cyan'),
683 ('buttnf','white','dark blue','bold'),
684 ]
685
687
688 MODE_KEYS_EMACS = [ "esc"]
689
690 MODE_KEYS_VI = ["esc", "tab",
691 "ctrl u", "ctrl U",
692 "ctrl t", "ctrl T"]
693
694 TPAR_BINDINGS = {
695 "quit" : self.QUIT,
696 "exit " : self.EXIT,
697 "help" : self.HELP,
698 "end" : self.MOVE_END,
699 "home" : self.MOVE_START,
700 }
701
702
703 if isinstance(taskName, irafpar.IrafParList):
704
705 self.taskObject = taskName
706 else:
707
708 self.taskObject = iraf.getTask(taskName)
709
710
711 self.taskName = self.taskObject.getName()
712 self.pkgName = self.taskObject.getPkgname()
713 self.paramList = self.taskObject.getParList(docopy=1)
714
715
716 self.__areAnyToLoad = irafpar.haveSpecialVersions(self.taskName,
717 self.pkgName)
718
719
720 self.numParams = len(self.paramList) - 1
721
722
723 self.get_default_param_list()
724 self.make_entries()
725
726 self.escape = False
727
728 if URWID_PRE_9P9:
729 self._createButtonsOld()
730 else:
731 self._createButtons()
732
733
734 self.colon_edit = PyrafEdit("", "", wrap="clip", align="left", inform=self.inform)
735 self.listitems = [urwid.Divider(" ")] + self.entryNo + \
736 [urwid.Divider(" "), self.colon_edit,
737 self.buttons]
738 self.listbox = urwid.ListBox( self.listitems )
739
740 self.listbox.set_focus(1)
741 self.footer = urwid.Text("")
742 self.header = TparHeader(self.pkgName, self.taskName)
743
744 self.view = urwid.Frame(
745 self.listbox,
746 header=self.header,
747 footer=self.footer)
748
749 self._editor = iraf.envget("editor")
750 BINDINGS = {}
751 BINDINGS.update(TPAR_BINDINGS)
752 if self._editor == "vi":
753 BINDINGS.update(TPAR_BINDINGS_VI)
754 MODE_KEYS = MODE_KEYS_VI
755 else:
756 BINDINGS.update(TPAR_BINDINGS_EMACS)
757 MODE_KEYS = MODE_KEYS_EMACS
758 Binder.__init__(self, BINDINGS, self.inform, MODE_KEYS)
759
760
810
811
856
857
859
860 dlist = self.taskObject.getDefaultParList()
861 if len(dlist) != len(self.paramList):
862
863 raise ValueError("Mismatch between default, current par lists"
864 " for task %s (try unlearn)" % self.taskName)
865 dict = {}
866 for par in dlist:
867 dict[par.name] = par
868
869
870 try:
871 dsort = []
872 for par in self.paramList:
873 dsort.append(dict[par.name])
874 except KeyError:
875 raise ValueError("Mismatch between default, current par lists"
876 " for task %s (try unlearn)" % self.taskName)
877 self.defaultParamList = dsort
878
879
881
882 self.entryNo = [None] * self.numParams
883 for i in range(self.numParams):
884 self.entryNo[i] = self.tpar_option_factory(
885 self.paramList[i], self.defaultParamList[i])
886
888
889
890
891 if sys.platform == 'darwin' and sys.version_info[0] == 2 and \
892 sys.version_info[1] > 5:
893 self.ui = urwid.raw_display.Screen()
894 else:
895 self.ui = urwid.curses_display.Screen()
896 self.ui.register_palette( self.palette )
897 self.ui.run_wrapper(self.run)
898 self.done()
899
901 keys = []
902 while not keys:
903 try:
904 keys = self.ui.get_input()
905 except KeyboardInterrupt:
906 keys = ["ctrl c"]
907 return keys
908
910 self.ui.set_mouse_tracking()
911 size = self.ui.get_cols_rows()
912 self.done = False
913 self._newline = True
914 while not self.done:
915 self.view.keypress(size, "ready")
916 canvas = self.view.render( size, focus=1 )
917 self.ui.draw_screen( size, canvas )
918 for k in self.get_keys():
919 if k == ":":
920 self.colon_escape()
921 break
922 elif urwid.is_mouse_event(k):
923 event, button, col, row = k
924 self.view.mouse_event(
925 size, event,
926 button, col, row, focus=True )
927 elif k == 'window resize':
928 size = self.ui.get_cols_rows()
929 self.inform("resize %s" % (str(size)))
930 k = self.keypress(size, k)
931 self.view.keypress( size, k )
932
934 """colon_escape switches the focus to the 'mini-buffer' and
935 accepts and executes a one line colon command."""
936 w, pos0 = self.listbox.get_focus()
937 try:
938 default_file = w.get_result()
939 except:
940 default_file = ""
941 self.listbox.set_focus(len(self.listitems)-2)
942 size = self.ui.get_cols_rows()
943 self.colon_edit.set_edit_text("")
944 self.colon_edit.set_edit_pos(0)
945 self.view.keypress(size, ":")
946 done = False
947 while not done:
948 canvas = self.view.render( size, focus=1 )
949 self.ui.draw_screen( size, canvas )
950 for k in self.get_keys():
951 if urwid.is_mouse_event(k) or \
952 k == "ctrl c" or k == "ctrl g":
953 self.colon_edit.set_edit_text("")
954 return
955 elif k == 'window resize':
956 size = self.ui.get_cols_rows()
957 elif k == 'enter':
958 done = True
959 break
960 k = self.keypress(size, k)
961 self.view.keypress( size, k )
962 cmd = self.colon_edit.get_edit_text()
963 self.listbox.set_focus(pos0)
964 self.colon_edit.set_edit_text("")
965 self.process_colon(cmd)
966
968
969 groups = re.match("^:(?P<cmd>[a-z])\s*"
970 "(?P<emph>!?)\s*"
971 "(?P<file>\w*)", cmd)
972 if not groups:
973 self.inform("bad command: " + cmd)
974 else:
975 letter = groups.group("cmd")
976 emph = groups.group("emph") == "!"
977 file = groups.group("file")
978 try:
979 f = { "q" : self.QUIT,
980 "g" : self.go,
981 "r" : self.read_pset,
982 "w" : self.write_pset,
983 "e" : self.edit_pset
984 }[letter]
985 except KeyError:
986 self.inform("unknown command: " + cmd)
987 return
988 try:
989 f(file, emph)
990 except Exception, e:
991 self.inform("command '%s' failed with exception '%s'" % (cmd, e))
992
994 """ Save the parameter settings to a user-specified file. Any
995 changes here must be coordinated with the corresponding epar saveAs
996 function. """
997
998
999 fname = self.select_file(
1000 "Save parameter values to which file?", overwriteCheck=True)
1001
1002
1003 if fname == None:
1004 msg = "Parameters NOT saved to a file."
1005 okdlg = urwutil.DialogDisplay(msg, 8, 0)
1006 okdlg.add_buttons([ ("OK",0) ])
1007 okdlg.main()
1008 return
1009
1010
1011
1012
1013
1014
1015 pars = []
1016 for par in self.paramList:
1017 if par.type == "pset": pars.append(par.name)
1018 if len(pars):
1019 msg = "If you have made any changes to the PSET "+ \
1020 "values for:\n\n"
1021 for p in pars: msg += " "+p+"\n"
1022 msg = msg+"\nthose changes will NOT be explicitly saved to:"+ \
1023 '\n\n"'+fname+'"'
1024
1025 okdlg = urwutil.DialogDisplay(msg, 0, 0)
1026 okdlg.add_buttons([ ("OK",0) ])
1027 okdlg.main()
1028
1029
1030
1031 self.badEntriesList = self.check_set_save_entries(False)
1032
1033
1034 ansOKCANCEL = True
1035 if self.badEntriesList:
1036 ansOKCANCEL = self.process_bad_entries(self.badEntriesList,
1037 self.taskName)
1038 if not ansOKCANCEL:
1039 return
1040
1041
1042
1043
1044 mstr = "TASKMETA: task="+self.taskName+" package="+self.pkgName
1045 if self.check_set_save_entries(doSave=True, filename=fname, \
1046 comment=mstr):
1047 raise Exception("Unexpected bad entries for: "+self.taskName)
1048
1049
1050 msg = 'Saved to: "'+fname+'"'
1051 okdlg = urwutil.DialogDisplay(msg, 8, 0)
1052 okdlg.add_buttons([ ("OK",0) ])
1053 okdlg.main()
1054
1055
1056 irafpar.newSpecialParFile(self.taskName, self.pkgName, fname)
1057
1058
1060 """ Load the parameter settings from a user-specified file. Any
1061 changes here must be coordinated with the corresponding epar pfopen
1062 function. """
1063
1064 flist = irafpar.getSpecialVersionFiles(self.taskName, self.pkgName)
1065 if len(flist) <= 0:
1066 msg = "No special-purpose parameter files found for "+self.taskName
1067 okdlg = urwutil.DialogDisplay(msg, 8, 0)
1068 okdlg.add_buttons([ ("OK",0) ])
1069 okdlg.main()
1070 return
1071
1072 fname = None
1073 if len(flist) == 1:
1074 msg = "One special-purpose parameter file found.\n"+ \
1075 "Load file?\n\n"+flist[0]
1076 yesnodlg = urwutil.DialogDisplay(msg, 12, 0)
1077 yesnodlg.add_buttons([ ("OK", 0), ("Cancel", 1) ])
1078 rv, junk = yesnodlg.main()
1079 if rv == 0: fname = flist[0]
1080 else:
1081 flist.sort()
1082 chcs = []
1083 for i in range(len(flist)):
1084 chcs.append(str(i))
1085 chcs.append(flist[i])
1086 def menuItemConstr(tag, state):
1087 return urwutil.MenuItem(tag)
1088 selectdlg = urwutil.ListDialogDisplay("Select from these:",
1089 len(flist)+7, 75,
1090 menuItemConstr, tuple(chcs), False)
1091 selectdlg.add_buttons([ ("Cancel",1), ])
1092 rv, ans = selectdlg.main()
1093 if rv == 0: fname = flist[int(ans)]
1094
1095
1096 msg = "\n\nPress any key to continue..."
1097
1098 if fname != None:
1099 newParList = irafpar.IrafParList(self.taskName, fname)
1100 self.set_all_entries_from_par_list(newParList)
1101 msg = "\n\nLoaded:\n\n "+fname+msg
1102
1103
1104 try:
1105 self.ui.clear()
1106 except AttributeError:
1107 self.ui._clear()
1108 self.info(msg, None)
1109
1110
1111 - def save(self, emph):
1112
1113
1114 if emph:
1115 return
1116 self.badEntriesList = self.check_set_save_entries(True)
1117
1118
1119 ansOKCANCEL = True
1120 if (self.badEntriesList):
1121 ansOKCANCEL = self.process_bad_entries(
1122 self.badEntriesList,
1123 self.taskName)
1124 return ansOKCANCEL
1125
1127 self.listbox.set_focus(1)
1128 return "home"
1129
1131 self.listbox.set_focus(len(self.entryNo))
1132 return "end"
1133
1134
1135
1136 - def QUIT(self, event=None, emph=True):
1137 self.save(emph)
1138 def quit_continue():
1139 pass
1140 self.done = quit_continue
1141
1142
1143 - def PFOPEN(self, event=None):
1144
1145 """ Open button - load parameters from a user specified file"""
1146 self.pfopen()
1147 self.done = None
1148
1149
1150 - def SAVEAS(self, event=None):
1151
1152 """ SaveAs button - save parameters to a user specified file"""
1153 self.save_as()
1154 def save_as_continue():
1155 iraffunctions.tparam(self.taskObject)
1156 self.done = save_as_continue
1157
1158
1159 - def EXIT(self, event=None):
1160 self.QUIT(event, False)
1161
1162
1163
1164 - def go(self, event=None, emph=False):
1165 """Executes the task."""
1166 self.save(emph)
1167 def go_continue():
1168 print "\nTask %s is running...\n" % self.taskName
1169 self.run_task()
1170 self.done = go_continue
1171
1173 """Edits the pset referred to by the specifiefd file or the current field."""
1174 self.save(emph)
1175 w, pos0 = self.listbox.get_focus()
1176 try:
1177 default_file = w.get_result()
1178 except:
1179 default_file = ""
1180 if file == "":
1181 iraffunctions.tparam(default_file)
1182 else:
1183 def edit_pset_continue():
1184 iraffunctions.tparam(file)
1185 self.done = edit_pset_continue
1186
1188 """Unlearns the current changes *or* reads in the specified file."""
1189 if file == "":
1190 self.unlearn_all_entries()
1191 else:
1192 def new_pset():
1193 self.__init__(file)
1194 self.done = new_pset
1195
1197 if os.path.exists(file) and not overwrite:
1198 self.inform("File '%s' exists and overwrite (!) not used." % (file,))
1199
1200 self.inform("write pset: %s" % (file,))
1201
1203 """ Set all the parameter entry values in the GUI to the values
1204 in the given par list. Note corresponding EditParDialog method. """
1205 for i in range(self.numParams):
1206 par = self.paramList[i]
1207 if par.type == "pset":
1208 continue
1209 gui_entry = self.entryNo[i]
1210 par.set(aParList.getValue(par.name, native=1, prompt=0))
1211
1212 gui_entry.set_result(par.value)
1213
1215 """ Method to "unlearn" all the parameter entry values in the GUI
1216 and set the parameter back to the default value """
1217 for entry in self.entryNo:
1218 entry.unlearn_value()
1219
1220
1222
1223 self.badEntries = []
1224
1225
1226 for i in range(self.numParams):
1227
1228 par = self.paramList[i]
1229 entry = self.entryNo[i]
1230
1231 if par.type == "pset":
1232 continue
1233
1234 value = entry.get_result()
1235
1236
1237
1238
1239
1240
1241 if par.isChanged() or value != entry._previousValue:
1242
1243
1244
1245 if not entry.verify(value):
1246 self.badEntries.append([
1247 entry.paramInfo.name, value,
1248 entry._previousValue])
1249 else:
1250 self.taskObject.setParam(par.name, value)
1251
1252
1253
1254
1255
1256
1257 if doSave and ((not isinstance(self.taskObject, irafpar.IrafParList)) \
1258 or self.taskObject.getFilename()):
1259 self.taskObject.saveParList(filename=filename, comment=comment)
1260
1261 return self.badEntries
1262
1263
1265
1266
1267
1268
1269 self.taskObject.run(mode='h', _save=1)
1270
1272 results = {}
1273 for i in self.items:
1274 results[i.get_name()] = i.get_result()
1275 return results
1276
1278 canvas = self.view.render( size, focus=True )
1279 self.ui.draw_screen( size, canvas )
1280
1284
1285 - def info(self, msg, b):
1286 self.exit_flag = False
1287 size = self.ui.get_cols_rows()
1288 exit_button = urwid.Padding(
1289 urwid.Button("Exit", self.exit_info),
1290 align="center", width=8)
1291 frame = urwid.Frame(urwid.Filler(
1292 urwid.AttrWrap(urwid.Text(msg), "help"),
1293 valign="top"),
1294 header=self.header,
1295 footer=exit_button)
1296 canvas = frame.render( size )
1297 self.ui.draw_screen( size, canvas )
1298 self.get_keys()
1299
1301 self.exit_flag = True
1302
1303 - def HELP(self, event=None):
1308
1310 """ Allow user to input a file - handle whether it is expected
1311 to be new or existing. Returns file name on success, None on error. """
1312
1313
1314
1315 while True:
1316 try:
1317 fname = urwfiledlg.main()
1318 except:
1319 prompt="(File chooser error, enter choice manually.)\n"+prompt
1320 inputdlg = urwutil.InputDialogDisplay(prompt, 9, 0)
1321 inputdlg.add_buttons([ ("OK", 0), ("Cancel", 1) ])
1322 rv, fname = inputdlg.main()
1323 if rv > 0: fname = None
1324
1325 if fname == None: return None
1326 fname = fname.strip()
1327 if len(fname) == 0: return None
1328
1329
1330 if overwriteCheck and os.path.exists(fname):
1331 yesnodlg = urwutil.DialogDisplay(
1332 "File exists! Overwrite?\n\n "+fname, 9, 0)
1333 yesnodlg.add_buttons([ ("Yes", 0), ("No", 1) ])
1334 rv, junk = yesnodlg.main()
1335 if rv == 0: return fname
1336
1337 else:
1338 return fname
1339
1340
1342 self.info(msg, None)
1343 return False
1344
1345
1347
1348 format = "%20s %20s %20s\n"
1349 badEntriesString = "\nTask " + taskname.upper() + \
1350 " -- Invalid values have been entered.\n\n"
1351 badEntriesString += format % \
1352 ("Parameter", "Bad Value", "Reset Value")
1353 for i in range (len(badEntriesList)):
1354 badEntriesString += format % \
1355 (badEntriesList[i][0].strip(), \
1356 badEntriesList[i][1].strip(), \
1357 badEntriesList[i][2].strip())
1358
1359 badEntriesString += "\nOK to continue using"\
1360 " the reset\nvalues or cancel to re-enter\nvalues?\n"
1361
1362
1363 return (self.askokcancel("Notice", badEntriesString))
1364
1365
1366 _tparOptionDict = { "b": BooleanTparOption,
1367 "r": NumberTparOption,
1368 "d": NumberTparOption,
1369 "i": NumberTparOption,
1370 "pset": PsetTparOption,
1371 "ar": NumberTparOption,
1372 "ai": NumberTparOption,
1373 }
1374
1376 """Return TparOption item of appropriate type for the parameter param"""
1377
1378
1379 if (param.choice != None):
1380 tparOption = EnumTparOption
1381 else:
1382
1383 tparOption = self._tparOptionDict.get(param.type, StringTparOption)
1384 return tparOption(param, defaultParam, self.inform)
1385
1386
1387 -def tpar(taskName):
1388 if isinstance(urwid, FakeModule):
1389 print >>sys.stderr, "The urwid package isn't found on your Python system so tpar can't be used."
1390 print >>sys.stderr, ' (the error given: "'+urwid.the_error+'")'
1391 print >>sys.stderr, "Please install urwid version >= 0.9.7 or use epar instead."
1392 return
1393 TparDisplay(taskName).main()
1394
1395 if __name__ == "__main__":
1396 main()
1397