1 """GNUmed GUI helper classes and functions.
2
3 This module provides some convenient wxPython GUI
4 helper thingies that are widely used throughout
5 GNUmed.
6 """
7
8 __version__ = "$Revision: 1.106 $"
9 __author__ = "K. Hilbert <Karsten.Hilbert@gmx.net>"
10 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
11
12 import os
13
14
15 import wx
16
17
18 from Gnumed.business import gmPraxis
19 from Gnumed.wxGladeWidgets import wxg3ButtonQuestionDlg, wxg2ButtonQuestionDlg, wxgGreetingEditorDlg
20
21
93
137
138 from Gnumed.wxGladeWidgets import wxgMultilineTextEntryDlg
139
140 -class cMultilineTextEntryDlg(wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg):
141 """Editor for a bit of text."""
142
143 - def __init__(self, *args, **kwargs):
144
145 try:
146 title = kwargs['title']
147 del kwargs['title']
148 except KeyError:
149 title = None
150
151 try:
152 msg = kwargs['msg']
153 del kwargs['msg']
154 except KeyError:
155 msg = None
156
157 try:
158 data = kwargs['data']
159 del kwargs['data']
160 except KeyError:
161 data = None
162
163 try:
164 self.original_text = kwargs['text']
165 del kwargs['text']
166 except KeyError:
167 self.original_text = None
168
169 wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg.__init__(self, *args, **kwargs)
170
171 if title is not None:
172 self.SetTitle(title)
173
174 if self.original_text is not None:
175 self._TCTRL_text.SetValue(self.original_text)
176 self._BTN_restore.Enable(True)
177
178 if msg is None:
179 self._LBL_msg.Hide()
180 else:
181 self._LBL_msg.SetLabel(msg)
182 self.Layout()
183 self.Refresh()
184
185 if data is None:
186 self._TCTRL_data.Hide()
187 else:
188 self._TCTRL_data.SetValue(data)
189 self.Layout()
190 self.Refresh()
191
192 - def _get_value(self):
193 return self._TCTRL_text.GetValue()
194
195 value = property(_get_value, lambda x:x)
196
197
198
200
201 if self.IsModal():
202 self.EndModal(wx.ID_SAVE)
203 else:
204 self.Close()
205
208
210 if self.original_text is not None:
211 self._TCTRL_text.SetValue(self.original_text)
212
229
231 """TreeCtrl mixin class to record expansion history."""
232 - def __init__(self):
233 if not isinstance(self, wx.TreeCtrl):
234 raise TypeError('[%s]: mixin can only be applied to wx.TreeCtrl, not [%s]' % (cTreeExpansionHistoryMixin, self.__class__.__name__))
235 self.expansion_state = {}
236
237
238
240 self.__record_subtree_expansion(start_node_id = self.GetRootItem())
241
243 if len(self.expansion_state) == 0:
244 return True
245 self.__restore_subtree_expansion(start_node_id = self.GetRootItem())
246
247 - def print_expansion(self):
248 if len(self.expansion_state) == 0:
249 print "currently no expansion snapshot available"
250 return True
251 print "last snapshot of state of expansion"
252 print "-----------------------------------"
253 print "listing expanded nodes:"
254 for node_id in self.expansion_state.keys():
255 print "node ID:", node_id
256 print " selected:", self.expansion_state[node_id]
257
258
259
260 - def __record_subtree_expansion(self, start_node_id=None):
261 """This records node expansion states based on the item label.
262
263 A side effect of this is that identically named items can
264 become unduly synchronized in their expand state after a
265 snapshot/restore cycle.
266
267 Better choices might be
268
269 id(item.GetPyData()) or
270 item.GetPyData().get_tree_uid()
271
272 where get_tree_uid():
273
274 '[%s:%s]' % (self.__class__.__name__, id(self))
275
276 or some such. This would survive renaming of the item.
277
278 For database items it may be useful to include the
279 primary key which would - contrary to id() - survive
280 reloads from the database.
281 """
282
283
284 if not start_node_id.IsOk():
285 return True
286
287 if not self.IsExpanded(start_node_id):
288 return True
289
290 self.expansion_state[self.GetItemText(start_node_id)] = self.IsSelected(start_node_id)
291
292 child_id, cookie = self.GetFirstChild(start_node_id)
293 while child_id.IsOk():
294 self.__record_subtree_expansion(start_node_id = child_id)
295 child_id, cookie = self.GetNextChild(start_node_id, cookie)
296
297 return
298
299 - def __restore_subtree_expansion(self, start_node_id=None):
300 start_node_label = self.GetItemText(start_node_id)
301 try:
302 node_selected = self.expansion_state[start_node_label]
303 except KeyError:
304 return
305
306 self.Expand(start_node_id)
307 if node_selected:
308 self.SelectItem(start_node_id)
309
310 child_id, cookie = self.GetFirstChild(start_node_id)
311 while child_id.IsOk():
312 self.__restore_subtree_expansion(start_node_id = child_id)
313 child_id, cookie = self.GetNextChild(start_node_id, cookie)
314
315 return
316
318 """Generic file drop target class.
319
320 Protocol:
321 Widgets being declared file drop targets
322 must provide the method:
323
324 add_filenames(filenames)
325 """
326
328 wx.FileDropTarget.__init__(self)
329 self.target = target
330
333
335 if aMessage is None:
336 aMessage = _('programmer forgot to specify error message')
337
338 aMessage += _("\n\nPlease consult the error log for all the gory details !")
339
340 if aTitle is None:
341 aTitle = _('generic error message')
342
343 message = aMessage
344 print message
345
346
347
348
349
350
351
352
353
354
355
357 if aMessage is None:
358 aMessage = _('programmer forgot to specify info message')
359
360 if aTitle is None:
361 aTitle = _('generic info message')
362
363 dlg = wx.MessageDialog (
364 parent = None,
365 message = aMessage,
366 caption = aTitle,
367 style = wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP
368 )
369 dlg.ShowModal()
370 dlg.Destroy()
371 return True
372
374 if aMessage is None:
375 aMessage = _('programmer forgot to specify warning')
376
377 if aTitle is None:
378 aTitle = _('generic warning message')
379
380 dlg = wx.MessageDialog (
381 parent = None,
382 message = aMessage,
383 caption = aTitle,
384 style = wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP
385 )
386 dlg.ShowModal()
387 dlg.Destroy()
388 return True
389
390 -def gm_show_question(aMessage='programmer forgot to specify question', aTitle='generic user question dialog', cancel_button=False):
391 if cancel_button:
392 style = wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION | wx.STAY_ON_TOP
393 else:
394 style = wx.YES_NO | wx.ICON_QUESTION | wx.STAY_ON_TOP
395
396 dlg = wx.MessageDialog (
397 None,
398 aMessage,
399 aTitle,
400 style
401 )
402 btn_pressed = dlg.ShowModal()
403 dlg.Destroy()
404
405 if btn_pressed == wx.ID_YES:
406 return True
407 elif btn_pressed == wx.ID_NO:
408 return False
409 else:
410 return None
411
412 -def makePageTitle(wizPg, title):
413 """
414 Utility function to create the main sizer of a wizard's page.
415
416 @param wizPg The wizard page widget
417 @type wizPg A wx.WizardPageSimple instance
418 @param title The wizard page's descriptive title
419 @type title A StringType instance
420 """
421 sizer = wx.BoxSizer(wx.VERTICAL)
422 wizPg.SetSizer(sizer)
423 title = wx.StaticText(wizPg, -1, title)
424 title.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD))
425 sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 2)
426 sizer.Add(wx.StaticLine(wizPg, -1), 0, wx.EXPAND|wx.ALL, 2)
427 return sizer
428
429