]>
Commit | Line | Data |
---|---|---|
d14a1e28 RD |
1 | # Name: panel.py |
2 | # Purpose: XRC editor, Panel class and related | |
3 | # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be> | |
4 | # Created: 02.12.2002 | |
5 | # RCS-ID: $Id$ | |
1fded56b | 6 | |
d14a1e28 RD |
7 | from xxx import * # xxx imports globals and params |
8 | from undo import * | |
9 | from wxPython.html import wxHtmlWindow | |
10 | ||
11 | # Properties panel containing notebook | |
12 | class Panel(wxNotebook): | |
13 | def __init__(self, parent, id = -1): | |
14 | if wxPlatform != '__WXMAC__': # some problems with this style on macs | |
15 | wxNotebook.__init__(self, parent, id, style=wxNB_BOTTOM) | |
16 | else: | |
17 | wxNotebook.__init__(self, parent, id) | |
18 | global panel | |
19 | g.panel = panel = self | |
20 | self.modified = False | |
21 | ||
22 | # Set common button size for parameter buttons | |
23 | bTmp = wxButton(self, -1, '') | |
24 | import params | |
25 | params.buttonSize = (self.DLG_SZE(buttonSize)[0], bTmp.GetSize()[1]) | |
26 | bTmp.Destroy() | |
27 | del bTmp | |
28 | ||
29 | # List of child windows | |
30 | self.pages = [] | |
31 | # Create scrolled windows for pages | |
32 | self.page1 = wxScrolledWindow(self, -1) | |
33 | sizer = wxBoxSizer() | |
34 | sizer.Add(wxBoxSizer()) # dummy sizer | |
35 | self.page1.SetAutoLayout(True) | |
36 | self.page1.SetSizer(sizer) | |
37 | self.AddPage(self.page1, 'Properties') | |
38 | # Second page | |
39 | self.page2 = wxScrolledWindow(self, -1) | |
2871fade | 40 | self.page2.Hide() |
d14a1e28 RD |
41 | sizer = wxBoxSizer() |
42 | sizer.Add(wxBoxSizer()) # dummy sizer | |
43 | self.page2.SetAutoLayout(True) | |
44 | self.page2.SetSizer(sizer) | |
5cd66f07 RD |
45 | # Cache for already used panels |
46 | self.pageCache = {} # cached property panels | |
47 | self.stylePageCache = {} # cached style panels | |
a78714eb | 48 | |
d14a1e28 RD |
49 | # Delete child windows and recreate page sizer |
50 | def ResetPage(self, page): | |
51 | topSizer = page.GetSizer() | |
52 | sizer = topSizer.GetChildren()[0].GetSizer() | |
53 | for w in page.GetChildren(): | |
5cd66f07 RD |
54 | sizer.Detach(w) |
55 | if isinstance(w, ParamPage): | |
56 | if w.IsShown(): | |
57 | w.Hide() | |
58 | else: | |
59 | w.Destroy() | |
68ae5821 | 60 | topSizer.Remove(sizer) |
d14a1e28 RD |
61 | # Create new windows |
62 | sizer = wxBoxSizer(wxVERTICAL) | |
63 | # Special case - resize html window | |
64 | if g.conf.panic: | |
65 | topSizer.Add(sizer, 1, wxEXPAND) | |
66 | else: | |
67 | topSizer.Add(sizer, 0, wxALL, 5) | |
68 | return sizer | |
a78714eb | 69 | |
d14a1e28 RD |
70 | def SetData(self, xxx): |
71 | self.pages = [] | |
72 | # First page | |
d14a1e28 RD |
73 | # Remove current objects and sizer |
74 | sizer = self.ResetPage(self.page1) | |
64b9ac75 | 75 | if not xxx or (not xxx.allParams and not xxx.hasName and not xxx.hasChild): |
d14a1e28 RD |
76 | if g.tree.selection: |
77 | sizer.Add(wxStaticText(self.page1, -1, 'This item has no properties.')) | |
78 | else: # nothing selected | |
79 | # If first time, show some help | |
80 | if g.conf.panic: | |
81 | html = wxHtmlWindow(self.page1, -1, wxDefaultPosition, | |
82 | wxDefaultSize, wxSUNKEN_BORDER) | |
83 | html.SetPage(g.helpText) | |
84 | sizer.Add(html, 1, wxEXPAND) | |
85 | g.conf.panic = False | |
86 | else: | |
87 | sizer.Add(wxStaticText(self.page1, -1, 'Select a tree item.')) | |
88 | else: | |
89 | g.currentXXX = xxx.treeObject() | |
a4c013b2 RR |
90 | # Normal or SizerItem page |
91 | isGBSizerItem = isinstance(xxx.parent, xxxGridBagSizer) | |
5cd66f07 RD |
92 | cacheID = (xxx.__class__, isGBSizerItem) |
93 | try: | |
94 | page = self.pageCache[cacheID] | |
95 | page.box.SetLabel(xxx.panelName()) | |
96 | page.Show() | |
97 | except KeyError: | |
98 | page = PropPage(self.page1, xxx.panelName(), xxx) | |
99 | self.pageCache[cacheID] = page | |
d14a1e28 RD |
100 | page.SetValues(xxx) |
101 | self.pages.append(page) | |
102 | sizer.Add(page, 1, wxEXPAND) | |
103 | if xxx.hasChild: | |
104 | # Special label for child objects - they may have different GUI | |
5cd66f07 RD |
105 | cacheID = (xxx.child.__class__, xxx.__class__) |
106 | try: | |
107 | page = self.pageCache[cacheID] | |
108 | page.box.SetLabel(xxx.child.panelName()) | |
109 | page.Show() | |
110 | except KeyError: | |
111 | page = PropPage(self.page1, xxx.child.panelName(), xxx.child) | |
112 | self.pageCache[cacheID] = page | |
d14a1e28 RD |
113 | page.SetValues(xxx.child) |
114 | self.pages.append(page) | |
115 | sizer.Add(page, 0, wxEXPAND | wxTOP, 5) | |
116 | self.page1.Layout() | |
117 | size = self.page1.GetSizer().GetMinSize() | |
118 | self.page1.SetScrollbars(1, 1, size.width, size.height, 0, 0, True) | |
119 | ||
120 | # Second page | |
121 | # Create if does not exist | |
122 | if xxx and xxx.treeObject().hasStyle: | |
123 | xxx = xxx.treeObject() | |
124 | # Simplest case: set data if class is the same | |
125 | sizer = self.ResetPage(self.page2) | |
5cd66f07 RD |
126 | try: |
127 | page = self.stylePageCache[xxx.__class__] | |
128 | page.Show() | |
129 | except KeyError: | |
130 | page = StylePage(self.page2, xxx.className + ' style', xxx) | |
131 | self.stylePageCache[xxx.__class__] = page | |
d14a1e28 RD |
132 | page.SetValues(xxx) |
133 | self.pages.append(page) | |
134 | sizer.Add(page, 0, wxEXPAND) | |
135 | # Add page if not exists | |
136 | if not self.GetPageCount() == 2: | |
137 | self.AddPage(self.page2, 'Style') | |
138 | self.page2.Layout() | |
1c7da10e RD |
139 | if 'wxGTK' in wx.PlatformInfo: |
140 | self.page2.Show(True) | |
d14a1e28 RD |
141 | size = self.page2.GetSizer().GetMinSize() |
142 | self.page2.SetScrollbars(1, 1, size.width, size.height, 0, 0, True) | |
143 | else: | |
144 | # Remove page if exists | |
145 | if self.GetPageCount() == 2: | |
146 | self.SetSelection(0) | |
147 | self.page1.Refresh() | |
148 | self.RemovePage(1) | |
149 | self.modified = False | |
5cd66f07 | 150 | |
d14a1e28 RD |
151 | def Clear(self): |
152 | self.SetData(None) | |
153 | self.modified = False | |
5cd66f07 | 154 | |
d14a1e28 RD |
155 | # If some parameter has changed |
156 | def IsModified(self): | |
157 | return self.modified | |
5cd66f07 | 158 | |
d14a1e28 RD |
159 | def SetModified(self, value): |
160 | # Register undo object when modifying first time | |
161 | if not self.modified and value: | |
162 | g.undoMan.RegisterUndo(UndoEdit()) | |
163 | self.modified = value | |
5cd66f07 | 164 | |
d14a1e28 RD |
165 | def Apply(self): |
166 | for p in self.pages: p.Apply() | |
167 | ||
168 | ################################################################################ | |
169 | ||
170 | # General class for notebook pages | |
171 | class ParamPage(wxPanel): | |
172 | def __init__(self, parent, xxx): | |
173 | wxPanel.__init__(self, parent, -1) | |
174 | self.xxx = xxx | |
175 | # Register event handlers | |
176 | for id in paramIDs.values(): | |
177 | EVT_CHECKBOX(self, id, self.OnCheckParams) | |
178 | self.checks = {} | |
179 | self.controls = {} # save python objects | |
180 | self.controlName = None | |
181 | ||
182 | def OnCheckParams(self, evt): | |
183 | xxx = self.xxx | |
184 | param = evt.GetEventObject().GetName() | |
185 | w = self.controls[param] | |
186 | w.Enable(True) | |
187 | objElem = xxx.element | |
188 | if evt.IsChecked(): | |
189 | # Ad new text node in order of allParams | |
190 | w.SetValue('') # set empty (default) value | |
191 | w.SetModified() # mark as changed | |
192 | elem = g.tree.dom.createElement(param) | |
193 | # Some classes are special | |
194 | if param == 'font': | |
195 | xxx.params[param] = xxxParamFont(xxx.element, elem) | |
196 | elif param in xxxObject.bitmapTags: | |
197 | xxx.params[param] = xxxParamBitmap(elem) | |
198 | else: | |
199 | xxx.params[param] = xxxParam(elem) | |
200 | # Find place to put new element: first present element after param | |
201 | found = False | |
a3c8bbc1 RD |
202 | if xxx.hasStyle: |
203 | paramStyles = xxx.allParams + xxx.styles | |
204 | else: | |
205 | paramStyles = xxx.allParams | |
d14a1e28 RD |
206 | for p in paramStyles[paramStyles.index(param) + 1:]: |
207 | # Content params don't have same type | |
208 | if xxx.params.has_key(p) and p != 'content': | |
209 | found = True | |
210 | break | |
211 | if found: | |
212 | nextTextElem = xxx.params[p].node | |
213 | objElem.insertBefore(elem, nextTextElem) | |
214 | else: | |
215 | objElem.appendChild(elem) | |
216 | else: | |
217 | # Remove parameter | |
218 | xxx.params[param].remove() | |
219 | del xxx.params[param] | |
220 | w.SetValue('') | |
221 | w.modified = False # mark as not changed | |
222 | w.Enable(False) | |
223 | # Set modified flag (provokes undo storing is necessary) | |
224 | panel.SetModified(True) | |
225 | def Apply(self): | |
226 | xxx = self.xxx | |
227 | if self.controlName: | |
228 | name = self.controlName.GetValue() | |
229 | if xxx.name != name: | |
230 | xxx.name = name | |
231 | xxx.element.setAttribute('name', name) | |
232 | for param, w in self.controls.items(): | |
233 | if w.modified: | |
234 | paramObj = xxx.params[param] | |
235 | value = w.GetValue() | |
236 | if param in xxx.specials: | |
237 | xxx.setSpecial(param, value) | |
238 | else: | |
239 | paramObj.update(value) | |
240 | # Save current state | |
241 | def SaveState(self): | |
242 | self.origChecks = map(lambda i: (i[0], i[1].GetValue()), self.checks.items()) | |
243 | self.origControls = map(lambda i: (i[0], i[1].GetValue(), i[1].IsEnabled()), | |
244 | self.controls.items()) | |
245 | if self.controlName: | |
246 | self.origName = self.controlName.GetValue() | |
247 | # Return original values | |
248 | def GetState(self): | |
249 | if self.controlName: | |
250 | return (self.origChecks, self.origControls, self.origName) | |
251 | else: | |
252 | return (self.origChecks, self.origControls) | |
253 | # Set values from undo data | |
254 | def SetState(self, state): | |
255 | for k,v in state[0]: | |
256 | self.checks[k].SetValue(v) | |
257 | for k,v,e in state[1]: | |
258 | self.controls[k].SetValue(v) | |
259 | self.controls[k].Enable(e) | |
260 | if e: self.controls[k].modified = True | |
261 | if self.controlName: | |
262 | self.controlName.SetValue(state[2]) | |
263 | ||
264 | ################################################################################ | |
265 | ||
a78714eb RD |
266 | LABEL_WIDTH = 125 |
267 | ||
d14a1e28 RD |
268 | # Panel for displaying properties |
269 | class PropPage(ParamPage): | |
270 | def __init__(self, parent, label, xxx): | |
271 | ParamPage.__init__(self, parent, xxx) | |
2481bf3c | 272 | self.box = wxStaticBox(self, -1, label) |
289128a4 | 273 | self.box.SetFont(g.labelFont()) |
2481bf3c | 274 | topSizer = wxStaticBoxSizer(self.box, wxVERTICAL) |
306b6fe9 | 275 | sizer = wxFlexGridSizer(len(xxx.allParams), 2, 0, 1) |
d14a1e28 RD |
276 | sizer.AddGrowableCol(1) |
277 | if xxx.hasName: | |
a78714eb | 278 | label = wxStaticText(self, -1, 'XML ID:', size=(LABEL_WIDTH,-1)) |
d14a1e28 RD |
279 | control = ParamText(self, 'XML_name', 200) |
280 | sizer.AddMany([ (label, 0, wxALIGN_CENTER_VERTICAL), | |
306b6fe9 | 281 | (control, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM | wxGROW, 10) ]) |
d14a1e28 RD |
282 | self.controlName = control |
283 | for param in xxx.allParams: | |
284 | present = xxx.params.has_key(param) | |
285 | if param in xxx.required: | |
286 | label = wxStaticText(self, paramIDs[param], param + ':', | |
a78714eb | 287 | size = (LABEL_WIDTH,-1), name = param) |
d14a1e28 RD |
288 | else: |
289 | # Notebook has one very loooooong parameter | |
290 | if param == 'usenotebooksizer': sParam = 'usesizer:' | |
291 | else: sParam = param + ':' | |
292 | label = wxCheckBox(self, paramIDs[param], sParam, | |
a78714eb | 293 | size = (LABEL_WIDTH,-1), name = param) |
d14a1e28 RD |
294 | self.checks[param] = label |
295 | try: | |
296 | typeClass = xxx.paramDict[param] | |
297 | except KeyError: | |
298 | try: | |
299 | # Standart type | |
300 | typeClass = paramDict[param] | |
301 | except KeyError: | |
302 | # Default | |
303 | typeClass = ParamText | |
304 | control = typeClass(self, param) | |
305 | control.Enable(present) | |
306 | sizer.AddMany([ (label, 0, wxALIGN_CENTER_VERTICAL), | |
307 | (control, 0, wxALIGN_CENTER_VERTICAL | wxGROW) ]) | |
308 | self.controls[param] = control | |
309 | topSizer.Add(sizer, 1, wxALL | wxEXPAND, 3) | |
310 | self.SetAutoLayout(True) | |
311 | self.SetSizer(topSizer) | |
312 | topSizer.Fit(self) | |
313 | def SetValues(self, xxx): | |
314 | self.xxx = xxx | |
315 | self.origChecks = [] | |
316 | self.origControls = [] | |
317 | # Set values, checkboxes to False, disable defaults | |
318 | if xxx.hasName: | |
319 | self.controlName.SetValue(xxx.name) | |
320 | self.origName = xxx.name | |
321 | for param in xxx.allParams: | |
322 | w = self.controls[param] | |
323 | w.modified = False | |
324 | try: | |
325 | value = xxx.params[param].value() | |
326 | w.Enable(True) | |
327 | w.SetValue(value) | |
328 | if not param in xxx.required: | |
329 | self.checks[param].SetValue(True) | |
330 | self.origChecks.append((param, True)) | |
331 | self.origControls.append((param, value, True)) | |
332 | except KeyError: | |
333 | self.checks[param].SetValue(False) | |
334 | w.SetValue('') | |
335 | w.Enable(False) | |
336 | self.origChecks.append((param, False)) | |
337 | self.origControls.append((param, '', False)) | |
338 | ||
339 | ################################################################################ | |
340 | ||
341 | # Style notebook page | |
342 | class StylePage(ParamPage): | |
343 | def __init__(self, parent, label, xxx): | |
344 | ParamPage.__init__(self, parent, xxx) | |
345 | box = wxStaticBox(self, -1, label) | |
289128a4 | 346 | box.SetFont(g.labelFont()) |
d14a1e28 | 347 | topSizer = wxStaticBoxSizer(box, wxVERTICAL) |
306b6fe9 | 348 | sizer = wxFlexGridSizer(len(xxx.styles), 2, 0, 1) |
d14a1e28 RD |
349 | sizer.AddGrowableCol(1) |
350 | for param in xxx.styles: | |
351 | present = xxx.params.has_key(param) | |
352 | check = wxCheckBox(self, paramIDs[param], | |
a78714eb | 353 | param + ':', size = (LABEL_WIDTH,-1), name = param) |
d14a1e28 RD |
354 | check.SetValue(present) |
355 | control = paramDict[param](self, name = param) | |
356 | control.Enable(present) | |
357 | sizer.AddMany([ (check, 0, wxALIGN_CENTER_VERTICAL), | |
358 | (control, 0, wxALIGN_CENTER_VERTICAL | wxGROW) ]) | |
359 | self.checks[param] = check | |
360 | self.controls[param] = control | |
361 | topSizer.Add(sizer, 1, wxALL | wxEXPAND, 3) | |
362 | self.SetAutoLayout(True) | |
363 | self.SetSizer(topSizer) | |
364 | topSizer.Fit(self) | |
365 | # Set data for a cahced page | |
366 | def SetValues(self, xxx): | |
367 | self.xxx = xxx | |
368 | self.origChecks = [] | |
369 | self.origControls = [] | |
370 | for param in xxx.styles: | |
371 | present = xxx.params.has_key(param) | |
372 | check = self.checks[param] | |
373 | check.SetValue(present) | |
374 | w = self.controls[param] | |
375 | w.modified = False | |
376 | if present: | |
377 | value = xxx.params[param].value() | |
378 | else: | |
379 | value = '' | |
380 | w.SetValue(value) | |
381 | w.Enable(present) | |
382 | self.origChecks.append((param, present)) | |
383 | self.origControls.append((param, value, present)) | |
1fded56b | 384 |