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 import logging
14 import sys
15
16
17 import wx
18
19
20 if __name__ == '__main__':
21 sys.path.insert(0, '../../')
22 from Gnumed.pycommon import gmMatchProvider
23 from Gnumed.wxpython import gmPhraseWheel
24
25
26 _log = logging.getLogger('gm.main')
27
29
31
32 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
33
34 items = [
35 {'list_label': _('Yes: + / ! / 1'), 'field_label': _('yes'), 'data': True, 'weight': 0},
36 {'list_label': _('No: - / 0'), 'field_label': _('no'), 'data': False, 'weight': 1},
37 {'list_label': _('Unknown: ?'), 'field_label': _('unknown'), 'data': None, 'weight': 2},
38 ]
39 mp = gmMatchProvider.cMatchProvider_FixedList(items)
40 mp.setThresholds(1, 1, 2)
41 mp.word_separators = '[ :/]+'
42 mp.word_separators = None
43 mp.ignored_chars = r"[.'\\(){}\[\]<>~#*$%^_=&@\t23456]+" + r'"'
44
45 self.matcher = mp
46
47 from Gnumed.wxGladeWidgets import wxg2ButtonQuestionDlg
48
120
121 from Gnumed.wxGladeWidgets import wxg3ButtonQuestionDlg
122
194
195 from Gnumed.wxGladeWidgets import wxgMultilineTextEntryDlg
196
197 -class cMultilineTextEntryDlg(wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg):
198 """Editor for a bit of text."""
199
200 - def __init__(self, *args, **kwargs):
201
202 try:
203 title = kwargs['title']
204 del kwargs['title']
205 except KeyError:
206 title = None
207
208 try:
209 msg = kwargs['msg']
210 del kwargs['msg']
211 except KeyError:
212 msg = None
213
214 try:
215 data = kwargs['data']
216 del kwargs['data']
217 except KeyError:
218 data = None
219
220 try:
221 self.original_text = kwargs['text']
222 del kwargs['text']
223 except KeyError:
224 self.original_text = None
225
226 wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg.__init__(self, *args, **kwargs)
227
228 if title is not None:
229 self.SetTitle(title)
230
231 if self.original_text is not None:
232 self._TCTRL_text.SetValue(self.original_text)
233 self._BTN_restore.Enable(True)
234
235 if msg is None:
236 self._LBL_msg.Hide()
237 else:
238 self._LBL_msg.SetLabel(msg)
239 self.Layout()
240 self.Refresh()
241
242 if data is None:
243 self._TCTRL_data.Hide()
244 else:
245 self._TCTRL_data.SetValue(data)
246 self.Layout()
247 self.Refresh()
248
249
250
251 - def _get_value(self):
252 return self._TCTRL_text.GetValue()
253
254 value = property(_get_value, lambda x:x)
255
257 return self._CHBOX_is_already_formatted.IsChecked()
258
259 is_user_formatted = property(_get_is_user_formatted, lambda x:x)
260
262 self._CHBOX_is_already_formatted.Enable(value)
263
264 enable_user_formatting = property(lambda x:x, _set_enable_user_formatting)
265
266
267
269
270 if self.IsModal():
271 self.EndModal(wx.ID_SAVE)
272 else:
273 self.Close()
274
277
279 if self.original_text is not None:
280 self._TCTRL_text.SetValue(self.original_text)
281
282 from Gnumed.business import gmSurgery
283 from Gnumed.wxGladeWidgets import wxgGreetingEditorDlg
284
301
303 """TreeCtrl mixin class to record expansion history."""
304 - def __init__(self):
305 if not isinstance(self, wx.TreeCtrl):
306 raise TypeError('[%s]: mixin can only be applied to wx.TreeCtrl, not [%s]' % (cTreeExpansionHistoryMixin, self.__class__.__name__))
307 self.expansion_state = {}
308
309
310
312 self.__record_subtree_expansion(start_node_id = self.GetRootItem())
313
315 if len(self.expansion_state) == 0:
316 return True
317 self.__restore_subtree_expansion(start_node_id = self.GetRootItem())
318
319 - def print_expansion(self):
320 if len(self.expansion_state) == 0:
321 print "currently no expansion snapshot available"
322 return True
323 print "last snapshot of state of expansion"
324 print "-----------------------------------"
325 print "listing expanded nodes:"
326 for node_id in self.expansion_state.keys():
327 print "node ID:", node_id
328 print " selected:", self.expansion_state[node_id]
329
330
331
332 - def __record_subtree_expansion(self, start_node_id=None):
333 """This records node expansion states based on the item label.
334
335 A side effect of this is that identically named items can
336 become unduly synchronized in their expand state after a
337 snapshot/restore cycle.
338
339 Better choices might be
340
341 id(item.GetPyData()) or
342 item.GetPyData().get_tree_uid()
343
344 where get_tree_uid():
345
346 '[%s:%s]' % (self.__class__.__name__, id(self))
347
348 or some such. This would survive renaming of the item.
349
350 For database items it may be useful to include the
351 primary key which would - contrary to id() - survive
352 reloads from the database.
353 """
354
355
356 if not start_node_id.IsOk():
357 return True
358
359 if not self.IsExpanded(start_node_id):
360 return True
361
362 self.expansion_state[self.GetItemText(start_node_id)] = self.IsSelected(start_node_id)
363
364 child_id, cookie = self.GetFirstChild(start_node_id)
365 while child_id.IsOk():
366 self.__record_subtree_expansion(start_node_id = child_id)
367 child_id, cookie = self.GetNextChild(start_node_id, cookie)
368
369 return
370
371 - def __restore_subtree_expansion(self, start_node_id=None):
372 start_node_label = self.GetItemText(start_node_id)
373 try:
374 node_selected = self.expansion_state[start_node_label]
375 except KeyError:
376 return
377
378 self.Expand(start_node_id)
379 if node_selected:
380 self.SelectItem(start_node_id)
381
382 child_id, cookie = self.GetFirstChild(start_node_id)
383 while child_id.IsOk():
384 self.__restore_subtree_expansion(start_node_id = child_id)
385 child_id, cookie = self.GetNextChild(start_node_id, cookie)
386
387 return
388
390 """Generic file drop target class.
391
392 Protocol:
393 Widgets being declared file drop targets
394 must provide the method:
395
396 add_filenames(filenames)
397 """
398
400 wx.FileDropTarget.__init__(self)
401 self.target = target
402 _log.debug('setting up [%s] as file drop target', target)
403
406
408 img_data = None
409 bitmap = None
410 rescaled_height = height
411 try:
412 img_data = wx.Image(filename, wx.BITMAP_TYPE_ANY)
413 current_width = img_data.GetWidth()
414 current_height = img_data.GetHeight()
415
416
417
418
419 rescaled_width = (float(current_width) / current_height) * rescaled_height
420 img_data.Rescale(rescaled_width, rescaled_height, quality = wx.IMAGE_QUALITY_HIGH)
421 bitmap = wx.BitmapFromImage(img_data)
422 del img_data
423 except StandardError:
424 _log.exception('cannot load image from [%s]', filename)
425 del img_data
426 del bitmap
427 return None
428
429 return bitmap
430
432 if aMessage is None:
433 aMessage = _('programmer forgot to specify error message')
434
435 aMessage += _("\n\nPlease consult the error log for all the gory details !")
436
437 if aTitle is None:
438 aTitle = _('generic error message')
439
440 dlg = wx.MessageDialog (
441 parent = None,
442 message = aMessage,
443 caption = aTitle,
444 style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP
445 )
446 dlg.ShowModal()
447 dlg.Destroy()
448 return True
449
451 if aMessage is None:
452 aMessage = _('programmer forgot to specify info message')
453
454 if aTitle is None:
455 aTitle = _('generic info message')
456
457 dlg = wx.MessageDialog (
458 parent = None,
459 message = aMessage,
460 caption = aTitle,
461 style = wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP
462 )
463 dlg.ShowModal()
464 dlg.Destroy()
465 return True
466
468 if aMessage is None:
469 aMessage = _('programmer forgot to specify warning')
470
471 if aTitle is None:
472 aTitle = _('generic warning message')
473
474 dlg = wx.MessageDialog (
475 parent = None,
476 message = aMessage,
477 caption = aTitle,
478 style = wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP
479 )
480 dlg.ShowModal()
481 dlg.Destroy()
482 return True
483
484 -def gm_show_question(aMessage='programmer forgot to specify question', aTitle='generic user question dialog', cancel_button=False, question=None, title=None):
485 if cancel_button:
486 style = wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION | wx.STAY_ON_TOP
487 else:
488 style = wx.YES_NO | wx.ICON_QUESTION | wx.STAY_ON_TOP
489
490 if question is None:
491 question = aMessage
492 if title is None:
493 title = aTitle
494
495 dlg = wx.MessageDialog(None, question, title, style)
496 btn_pressed = dlg.ShowModal()
497 dlg.Destroy()
498
499 if btn_pressed == wx.ID_YES:
500 return True
501 elif btn_pressed == wx.ID_NO:
502 return False
503 else:
504 return None
505
506 if __name__ == '__main__':
507
508 if len(sys.argv) < 2:
509 sys.exit()
510
511 if sys.argv[1] != 'test':
512 sys.exit()
513
514 from Gnumed.pycommon import gmI18N
515 gmI18N.activate_locale()
516 gmI18N.install_domain(domain='gnumed')
517
518
520 app = wx.App()
521 img = file2scaled_image(filename = sys.argv[2])
522 print img
523 print img.Height
524 print img.Width
525
527 app = wx.PyWidgetTester(size = (200, 50))
528 prw = cThreeValuedLogicPhraseWheel(parent = app.frame, id = -1)
529 app.frame.Show(True)
530 app.MainLoop()
531
532 return True
533
534
535 test_sql_logic_prw()
536
537
538