1 |
# |
# |
|
# Copyright 2001 Free Software Foundation |
|
|
# |
|
2 |
# This file is part of GNU Enterprise. |
# This file is part of GNU Enterprise. |
3 |
# |
# |
4 |
# GNU Enterprise is free software; you can redistribute it |
# GNU Enterprise is free software; you can redistribute it |
16 |
# write to the Free Software Foundation, Inc., 59 Temple Place |
# write to the Free Software Foundation, Inc., 59 Temple Place |
17 |
# - Suite 330, Boston, MA 02111-1307, USA. |
# - Suite 330, Boston, MA 02111-1307, USA. |
18 |
# |
# |
19 |
|
# Copyright 2001-2002 Free Software Foundation |
20 |
|
# |
21 |
# FILE: |
# FILE: |
22 |
# TemplateParser.py |
# TemplateParser.py |
23 |
# |
# |
28 |
|
|
29 |
from wxPython.wx import * |
from wxPython.wx import * |
30 |
from gnue.designer import TemplateBase |
from gnue.designer import TemplateBase |
31 |
|
from gnue.common.FileUtils import dyn_import |
32 |
|
from gnue.common.events import Event |
33 |
|
|
34 |
class TemplateParser: |
class TemplateParser: |
35 |
def __init__(self, instance, rootObject, parent, templateInformation): |
def __init__(self, instance, rootObject, parent, |
36 |
|
templateInformation, currentObject=None): |
37 |
self.parent = parent |
self.parent = parent |
38 |
self.instance = instance |
self.instance = instance |
39 |
self.templateInformation = templateInformation |
self.templateInformation = templateInformation |
40 |
self.rootObject = rootObject |
self.rootObject = rootObject |
41 |
|
self.currentObject = currentObject |
42 |
|
|
43 |
if templateInformation['Product'] == 'forms': |
self.elements = dyn_import('gnue.designer.%s.Incubator'%templateInformation['Product']).elements |
|
from gnue.forms import GFParser |
|
|
self.elements = GFParser.getXMLelements() |
|
|
elif templateInformation['Product'] == 'reports': |
|
|
from gnue.reports import GRParser |
|
|
self.elements = GRParser.getXMLelements() |
|
44 |
|
|
45 |
|
|
46 |
def run(self): |
def run(self, **params): |
47 |
|
|
48 |
self.template = self.templateInformation['BaseClass'](self) |
self.template = self.templateInformation['BaseClass'](self) |
49 |
|
|
50 |
self.template.Start(self.rootObject) |
self.template.Start(self.rootObject, |
51 |
|
self.currentObject or self.rootObject, |
52 |
|
**params) |
53 |
|
|
54 |
# If this is simply a template and not a wizard, |
# If this is simply a template and not a wizard, |
55 |
# generate the results and get out of Dodge. |
# generate the results and get out of Dodge. |
56 |
if self.templateInformation['Behavior'] == TemplateBase.TEMPLATE: |
if self.templateInformation['Behavior'] == TemplateBase.TEMPLATE: |
57 |
return self.template.GetFinal() |
return self.template.Finalize() |
58 |
|
|
59 |
self.wizard = wxDialog(self.parent, -1, self.templateInformation['Name'], |
self.wizard = wxDialog(self.parent, -1, self.templateInformation['Name'], |
60 |
style=wxDEFAULT_DIALOG_STYLE|wxDIALOG_MODAL) |
style=wxDEFAULT_DIALOG_STYLE|wxDIALOG_MODAL) |
64 |
|
|
65 |
self.wizardPage = WizardPage(self, self.panel) |
self.wizardPage = WizardPage(self, self.panel) |
66 |
|
|
67 |
self.prevButton = wxButton(self.panel, -1, '< Back') |
self.prevButton = wxButton(self.panel, -1, _('< Back')) |
68 |
self.nextButton = wxButton(self.panel, -1, 'Continue >') |
self.nextButton = wxButton(self.panel, -1, _('Continue >')) |
69 |
self.cancelButton = wxButton(self.panel, -1, 'Cancel') |
self.cancelButton = wxButton(self.panel, -1, _('Cancel')) |
70 |
|
|
71 |
self.nextButton.SetDefault() |
self.nextButton.SetDefault() |
72 |
|
|
87 |
|
|
88 |
EVT_CLOSE(self.wizard, self.wizardPage.OnCancel) |
EVT_CLOSE(self.wizard, self.wizardPage.OnCancel) |
89 |
|
|
90 |
self.title = wxStaticText(self.panel, -1, "Wizard Header", pos=wxPoint(10,10)) |
self.title = wxStaticText(self.panel, -1, _("Wizard Header"), pos=wxPoint(10,10)) |
91 |
font = self.title.GetFont() |
font = self.title.GetFont() |
92 |
font.SetPointSize(int(self.title.GetFont().GetPointSize()*1.5)) |
font.SetPointSize(int(self.title.GetFont().GetPointSize()*1.5)) |
93 |
font.SetStyle(wxITALIC) |
font.SetStyle(wxITALIC) |
94 |
# font.SetWeight(wxBOLD) |
# font.SetWeight(wxBOLD) |
95 |
self.title.SetForegroundColour(wxColour(255,255,255)) |
self.title.SetForegroundColour(wxColour(255,255,255)) |
96 |
self.title.SetFont(font) |
self.title.SetFont(font) |
97 |
self.title2 = wxStaticText(self.panel, -1, "Wizard Header", pos=wxPoint(11,11)) |
self.title2 = wxStaticText(self.panel, -1, _("Wizard Header"), pos=wxPoint(11,11)) |
98 |
self.title2.SetForegroundColour(wxColour(0,0,102)) |
self.title2.SetForegroundColour(wxColour(0,0,102)) |
99 |
self.title2.SetFont(font) |
self.title2.SetFont(font) |
100 |
|
|
155 |
|
|
156 |
def OnNextStep(self, event): |
def OnNextStep(self, event): |
157 |
|
|
158 |
|
validation = [] |
159 |
|
|
160 |
# Save the variables from current step |
# Save the variables from current step |
161 |
for o in self.editorMappings.keys(): |
for o in self.editorMappings.keys(): |
162 |
self.parser.template.variables[self.editorMappings[o].variable] = o.get() |
value = o.get() |
163 |
|
if o.source.required and (value == None or not o.source.set and |
164 |
|
o.source.typecast == TemplateBase.text and not len(value)): |
165 |
|
validation.append('A required value is missing for "%s"' % o.source.variable) |
166 |
|
|
167 |
|
## TODO: Add the various other validation checks |
168 |
|
|
169 |
validation = self.parser.template.ValidateStep(self.step) |
self.parser.template.variables[self.editorMappings[o].variable] = value |
170 |
if validation != None: |
|
171 |
|
|
172 |
|
if not validation: |
173 |
|
validation = self.parser.template.ValidateStep(self.step) |
174 |
|
|
175 |
|
if validation: |
176 |
# TODO: This should display a dialog box listing problems... |
# TODO: This should display a dialog box listing problems... |
177 |
for mesg in validation: |
for mesg in validation: |
178 |
print "(*) %s" % mesg |
print "(*) %s" % mesg |
|
event.Veto() |
|
179 |
return |
return |
180 |
else: |
else: |
181 |
if self.nextStep == None: |
if self.nextStep == None: |
207 |
nextY = yMargin |
nextY = yMargin |
208 |
|
|
209 |
if self.nextStep == None: |
if self.nextStep == None: |
210 |
self.parser.nextButton.SetLabel('Finished') |
self.parser.nextButton.SetLabel(_('Finished')) |
211 |
else: |
else: |
212 |
self.parser.nextButton.SetLabel('Continue >') |
self.parser.nextButton.SetLabel(_('Continue >')) |
213 |
|
|
214 |
if self.prevStep == None: |
if self.prevStep == None: |
215 |
self.parser.prevButton.Enable(0) |
self.parser.prevButton.Enable(0) |
223 |
nextY = yMargin |
nextY = yMargin |
224 |
|
|
225 |
self.editorMappings = {} |
self.editorMappings = {} |
226 |
|
self.textctrlList = [] |
227 |
|
|
228 |
for object in self.stepInfo['content']: |
for object in self.stepInfo['content']: |
229 |
|
|
234 |
# TODO: perform our own wrapping. Of course, this is |
# TODO: perform our own wrapping. Of course, this is |
235 |
# TODO: not at all portable! |
# TODO: not at all portable! |
236 |
|
|
237 |
o = wxStaticText(self, -1, object.text, pos=wxPoint(xMargin, nextY)) |
width = self.GetSize().x - xMargin * 2 |
238 |
|
|
239 |
|
o = WrappedStaticText(self, -1, object.text, width, |
240 |
|
pos=wxPoint(xMargin, nextY)) |
241 |
|
|
242 |
nextY = nextY + ySpacing + o.GetSize().y |
nextY = nextY + ySpacing + o.GetSize().y |
243 |
|
|
244 |
elif isinstance(object, TemplateBase.WizardInput): |
elif isinstance(object, TemplateBase.WizardInput): |
265 |
|
|
266 |
|
|
267 |
self.editorMappings[o] = object |
self.editorMappings[o] = object |
268 |
|
MyId = len(self.textctrlList) |
269 |
|
self.textctrlList.append(o) |
270 |
|
|
271 |
nextY = nextY + ySpacing + o.GetSize().y |
nextY = nextY + ySpacing + o.GetSize().y |
272 |
|
|
273 |
|
EVT_CHAR(o, FieldHandler(self, MyId).fieldEventTrap) |
274 |
|
|
275 |
if self.parser.template.variables.has_key(object.variable): |
if self.parser.template.variables.has_key(object.variable): |
276 |
o.set(self.parser.template.variables[object.variable]) |
o.set(self.parser.template.variables[object.variable]) |
277 |
|
|
278 |
|
# Add our buttons to the focus list |
279 |
|
if self.prevStep: |
280 |
|
self.textctrlList.append(self.parser.prevButton) |
281 |
|
self.textctrlList.append(self.parser.nextButton) |
282 |
|
self.textctrlList.append(self.parser.cancelButton) |
283 |
|
|
284 |
|
# Set focus to be the first input widget |
285 |
|
self.textctrlList[0].SetFocus() |
286 |
|
|
287 |
|
|
288 |
|
|
289 |
|
|
290 |
class TextField(wxTextCtrl): |
class TextField(wxTextCtrl): |
300 |
if self.forceupper: |
if self.forceupper: |
301 |
EVT_CHAR(wxTextCtrl, self.OnCharUpper) |
EVT_CHAR(wxTextCtrl, self.OnCharUpper) |
302 |
if self.forcelower: |
if self.forcelower: |
303 |
EVT_CHAR(wxTextCtrl, self.OnCharUpper) |
EVT_CHAR(wxTextCtrl, self.OnCharLower) |
304 |
|
|
305 |
|
|
306 |
def get(self): |
def get(self): |
319 |
|
|
320 |
|
|
321 |
|
|
322 |
class ComboField(wxComboBox): |
class ComboField(wxComboBox): |
323 |
def __init__(self, source, parent, pos=wxDefaultPosition, size=wxDefaultSize): |
def __init__(self, source, parent, pos=wxDefaultPosition, size=wxDefaultSize): |
324 |
wxComboBox.__init__(self, parent, -1, pos=pos, size=size) |
wxComboBox.__init__(self, parent, -1, pos=pos, size=size) |
325 |
self.source = source |
self.source = source |
326 |
self.parent = parent |
self.parent = parent |
328 |
self.lookup = [] |
self.lookup = [] |
329 |
|
|
330 |
i = 0 |
i = 0 |
331 |
for choice in source.set: |
for choice in source.set: |
332 |
key, descr = choice |
key, descr = choice |
333 |
self.mapping[key] = i |
self.mapping[key] = i |
334 |
self.lookup.append(key) |
self.lookup.append(key) |
335 |
self.Append(descr) |
self.Append(descr) |
336 |
i = i + 1 |
i = i + 1 |
337 |
|
|
338 |
def get(self): |
def get(self): |
339 |
return self.lookup[self.GetSelection()] |
return self.lookup[self.GetSelection()] |
340 |
|
|
341 |
def set(self, value): |
def set(self, value): |
342 |
self.SetSelection(self.mapping[value]) |
self.SetSelection(self.mapping[value]) |
343 |
|
|
344 |
|
|
345 |
|
|
346 |
class ListField(wxListBox): |
class ListField(wxListBox): |
347 |
def __init__(self, source, parent, pos=wxDefaultPosition, size=wxDefaultSize): |
def __init__(self, source, parent, pos=wxDefaultPosition, size=wxDefaultSize): |
348 |
if source.maxSelections != 1: |
if source.maxSelections != 1: |
349 |
style = wxLB_MULTIPLE |
style = wxLB_MULTIPLE |
350 |
else: |
else: |
351 |
style = wxLB_SINGLE |
style = wxLB_SINGLE |
352 |
|
|
353 |
wxListBox.__init__(self, parent, -1, pos=pos, size=size, \ |
wxListBox.__init__(self, parent, -1, pos=pos, size=size, \ |
361 |
#print source.set |
#print source.set |
362 |
|
|
363 |
i = 0 |
i = 0 |
364 |
for choice in source.set: |
|
365 |
|
# TODO: This [:2000] is a temporary fix since GTK limits to 2000 entries |
366 |
|
for choice in source.set[:500]: |
367 |
key, descr = choice |
key, descr = choice |
368 |
self.mapping[key] = i |
self.mapping[key] = i |
369 |
self.lookup.append(key) |
self.lookup.append(key) |
390 |
|
|
391 |
class SortableListField(wxPanel): |
class SortableListField(wxPanel): |
392 |
def __init__(self, source, parent, pos=wxDefaultPosition, |
def __init__(self, source, parent, pos=wxDefaultPosition, |
393 |
size=wxDefaultSize): |
size=wxDefaultSize): |
394 |
|
|
395 |
wxPanel.__init__(self, parent, -1, pos=pos, size=size, |
wxPanel.__init__(self, parent, -1, pos=pos, size=size, |
396 |
style=wxSIMPLE_BORDER) |
style=wxSIMPLE_BORDER) |
397 |
|
|
398 |
self.source = source |
self.source = source |
399 |
self.parent = parent |
self.parent = parent |
400 |
|
|
401 |
self.addButton = wxButton(self, -1, " Add >") |
self.addButton = wxButton(self, -1, _(" Add >")) |
402 |
self.delButton = wxButton(self, -1, "< Remove ") |
self.delButton = wxButton(self, -1, _("< Remove ")) |
403 |
self.upButton = wxButton(self, -1, "Move Up") |
self.upButton = wxButton(self, -1, _("Move Up")) |
404 |
self.downButton = wxButton(self, -1, "Move Down") |
self.downButton = wxButton(self, -1, _("Move Down")) |
405 |
self.selectAllButton = wxButton(self, -1, "Select All") |
self.selectAllButton = wxButton(self, -1, _("Select All")) |
406 |
|
|
407 |
self.addButton.SetSize(self.downButton.GetSize()) |
self.addButton.SetSize(self.downButton.GetSize()) |
408 |
self.delButton.SetSize(self.downButton.GetSize()) |
self.delButton.SetSize(self.downButton.GetSize()) |
505 |
self.downButton.Enable(0) |
self.downButton.Enable(0) |
506 |
else: |
else: |
507 |
self.downButton.Enable(1) |
self.downButton.Enable(1) |
508 |
else: |
else: |
509 |
self.delButton.Enable(0) |
self.delButton.Enable(0) |
510 |
self.upButton.Enable(0) |
self.upButton.Enable(0) |
511 |
self.downButton.Enable(0) |
self.downButton.Enable(0) |
512 |
|
|
513 |
|
|
514 |
self.addButton.Enable(0) |
self.addButton.Enable(0) |
515 |
for i in self.list1.GetSelections(): |
for i in self.list1.GetSelections(): |
516 |
self.list1.SetSelection(i,0) |
self.list1.SetSelection(i,0) |
517 |
|
|
518 |
def OnSelectAll(self, event): |
def OnSelectAll(self, event): |
552 |
appendages2.insert(0,self.included[i]) |
appendages2.insert(0,self.included[i]) |
553 |
self.included.pop(i) |
self.included.pop(i) |
554 |
self.list2.Delete(i) |
self.list2.Delete(i) |
555 |
|
|
556 |
for a in appendages1: |
for a in appendages1: |
557 |
self.list1.Append(a) |
self.list1.Append(a) |
558 |
|
|
594 |
|
|
595 |
|
|
596 |
|
|
597 |
|
class WizardRunner: |
598 |
|
def __init__(self, template, title, instance): |
599 |
|
self.template = template |
600 |
|
self.instance = instance |
601 |
|
|
602 |
|
self.wxId = wxNewId() |
603 |
|
self.title = title |
604 |
|
self.checkable = 0 |
605 |
|
try: |
606 |
|
self.tooltip = template['Description'] |
607 |
|
except KeyError: |
608 |
|
self.tooltip = "" |
609 |
|
|
610 |
|
def run(self, event): |
611 |
|
self.instance.dispatchEvent(Event('BeginWizard', template=self.template)) |
612 |
|
TemplateParser(self.instance, self.instance.rootObject, |
613 |
|
self.instance, self.template).run() |
614 |
|
self.instance.dispatchEvent(Event('EndWizard', template=self.template)) |
615 |
|
|
616 |
|
def finalize(self): |
617 |
|
pass |
618 |
|
|
619 |
|
|
620 |
|
class WrappedStaticText(wxStaticText): |
621 |
|
def __init__(self, parent, id, label, width, *args, **params): |
622 |
|
wxStaticText.__init__(self, parent, id, "bah!", *args, **params) |
623 |
|
|
624 |
|
|
625 |
|
textSoFar = "" |
626 |
|
thisLine = "" |
627 |
|
for part in string.split(label,'\n'): |
628 |
|
for word in string.split(part): |
629 |
|
self.SetLabel(thisLine + word) |
630 |
|
if self.GetSize().width > width: |
631 |
|
textSoFar += thisLine + " \n" |
632 |
|
thisLine = word + " " |
633 |
|
else: |
634 |
|
thisLine += word + " " |
635 |
|
|
636 |
|
textSoFar += thisLine + " \n" |
637 |
|
thisLine = "" |
638 |
|
|
639 |
|
if len(textSoFar): |
640 |
|
self.SetLabel(string.replace(textSoFar,' \n','\n')[:-1]) |
641 |
|
else: |
642 |
|
self.SetLabel("") |
643 |
|
|
644 |
|
|
645 |
|
# |
646 |
|
# FieldHandler |
647 |
|
# |
648 |
|
# enables the user to press tab/return and have it jump to the next box |
649 |
|
# |
650 |
|
class FieldHandler: |
651 |
|
def __init__(self, app, seq): |
652 |
|
self.app = app |
653 |
|
self.seq = seq |
654 |
|
|
655 |
|
def fieldEventTrap(self, event): |
656 |
|
keycode = event.KeyCode() |
657 |
|
if keycode in (WXK_RETURN, WXK_TAB): |
658 |
|
if self.seq < len(self.app.textctrlList) - 1: |
659 |
|
self.app.textctrlList[self.seq+1].SetFocus() |
660 |
|
else: |
661 |
|
if keycode == WXK_TAB: |
662 |
|
if event.ShiftDown(): |
663 |
|
self.app.textctrlList[self.seq-1].SetFocus() |
664 |
|
elif keycode == WXK_ESCAPE: |
665 |
|
self.app.OnCancel(None) |
666 |
|
else: |
667 |
|
event.Skip() |
668 |
|
|