Package Gnumed :: Package wxpython :: Module gmGuiHelpers
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmGuiHelpers

  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  This source code is protected by the GPL licensing scheme. 
  8  Details regarding the GPL are available at http://www.gnu.org 
  9  You may use and share it as long as you don't deny this right 
 10  to anybody else. 
 11  """ 
 12  # ======================================================================== 
 13  __version__ = "$Revision: 1.106 $" 
 14  __author__  = "K. Hilbert <Karsten.Hilbert@gmx.net>" 
 15  __license__ = "GPL (details at http://www.gnu.org)" 
 16   
 17  import os 
 18  import logging 
 19  import sys 
 20   
 21   
 22  import wx 
 23   
 24   
 25  if __name__ == '__main__': 
 26          sys.path.insert(0, '../../') 
 27   
 28  from Gnumed.pycommon import gmPG2 
 29  from Gnumed.pycommon import gmTools 
 30  from Gnumed.pycommon import gmI18N 
 31   
 32   
 33  _log = logging.getLogger('gm.main') 
 34  # ======================================================================== 
 35  from Gnumed.wxGladeWidgets import wxg2ButtonQuestionDlg 
 36   
37 -class c2ButtonQuestionDlg(wxg2ButtonQuestionDlg.wxg2ButtonQuestionDlg):
38
39 - def __init__(self, *args, **kwargs):
40 41 caption = kwargs['caption'] 42 question = kwargs['question'] 43 button_defs = kwargs['button_defs'][:2] 44 del kwargs['caption'] 45 del kwargs['question'] 46 del kwargs['button_defs'] 47 48 try: 49 show_checkbox = kwargs['show_checkbox'] 50 del kwargs['show_checkbox'] 51 except KeyError: 52 show_checkbox = False 53 54 try: 55 checkbox_msg = kwargs['checkbox_msg'] 56 del kwargs['checkbox_msg'] 57 except KeyError: 58 checkbox_msg = None 59 60 try: 61 checkbox_tooltip = kwargs['checkbox_tooltip'] 62 del kwargs['checkbox_tooltip'] 63 except KeyError: 64 checkbox_tooltip = None 65 66 wxg2ButtonQuestionDlg.wxg2ButtonQuestionDlg.__init__(self, *args, **kwargs) 67 68 self.SetTitle(title = caption) 69 self._LBL_question.SetLabel(label = question) 70 71 if not show_checkbox: 72 self._CHBOX_dont_ask_again.Hide() 73 else: 74 if checkbox_msg is not None: 75 self._CHBOX_dont_ask_again.SetLabel(checkbox_msg) 76 if checkbox_tooltip is not None: 77 self._CHBOX_dont_ask_again.SetToolTipString(checkbox_tooltip) 78 79 buttons = [self._BTN_1, self._BTN_2] 80 for idx in range(len(button_defs)): 81 buttons[idx].SetLabel(label = button_defs[idx]['label']) 82 buttons[idx].SetToolTipString(button_defs[idx]['tooltip']) 83 try: 84 if button_defs[idx]['default'] is True: 85 buttons[idx].SetDefault() 86 buttons[idx].SetFocus() 87 except KeyError: 88 pass 89 90 self.Fit()
91 #--------------------------------------------------------
92 - def checkbox_is_checked(self):
93 return self._CHBOX_dont_ask_again.IsChecked()
94 #-------------------------------------------------------- 95 # event handlers 96 #--------------------------------------------------------
97 - def _on_BTN_1_pressed(self, evt):
98 if self.IsModal(): 99 self.EndModal(wx.ID_YES) 100 else: 101 self.Close()
102 #--------------------------------------------------------
103 - def _on_BTN_2_pressed(self, evt):
104 if self.IsModal(): 105 self.EndModal(wx.ID_NO) 106 else: 107 self.Close()
108 # ======================================================================== 109 from Gnumed.wxGladeWidgets import wxg3ButtonQuestionDlg 110
111 -class c3ButtonQuestionDlg(wxg3ButtonQuestionDlg.wxg3ButtonQuestionDlg):
112
113 - def __init__(self, *args, **kwargs):
114 115 caption = kwargs['caption'] 116 question = kwargs['question'] 117 button_defs = kwargs['button_defs'][:3] 118 119 del kwargs['caption'] 120 del kwargs['question'] 121 del kwargs['button_defs'] 122 123 wxg3ButtonQuestionDlg.wxg3ButtonQuestionDlg.__init__(self, *args, **kwargs) 124 125 self.SetTitle(title = caption) 126 self._LBL_question.SetLabel(label = question) 127 128 buttons = [self._BTN_1, self._BTN_2, self._BTN_3] 129 for idx in range(len(button_defs)): 130 buttons[idx].SetLabel(label = button_defs[idx]['label']) 131 buttons[idx].SetToolTipString(button_defs[idx]['tooltip']) 132 try: 133 if button_defs[idx]['default'] is True: 134 buttons[idx].SetDefault() 135 buttons[idx].SetFocus() 136 except KeyError: 137 pass 138 139 self.Fit()
140 #-------------------------------------------------------- 141 # event handlers 142 #--------------------------------------------------------
143 - def _on_BTN_1_pressed(self, evt):
144 if self.IsModal(): 145 self.EndModal(wx.ID_YES) 146 else: 147 self.Close()
148 #--------------------------------------------------------
149 - def _on_BTN_2_pressed(self, evt):
150 if self.IsModal(): 151 self.EndModal(wx.ID_NO) 152 else: 153 self.Close()
154 # ======================================================================== 155 from Gnumed.wxGladeWidgets import wxgMultilineTextEntryDlg 156
157 -class cMultilineTextEntryDlg(wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg):
158 """Editor for a bit of text.""" 159
160 - def __init__(self, *args, **kwargs):
161 162 try: 163 title = kwargs['title'] 164 del kwargs['title'] 165 except KeyError: 166 title = None 167 168 try: 169 msg = kwargs['msg'] 170 del kwargs['msg'] 171 except KeyError: 172 msg = None 173 174 try: 175 data = kwargs['data'] 176 del kwargs['data'] 177 except KeyError: 178 data = None 179 180 try: 181 self.original_text = kwargs['text'] 182 del kwargs['text'] 183 except KeyError: 184 self.original_text = None 185 186 wxgMultilineTextEntryDlg.wxgMultilineTextEntryDlg.__init__(self, *args, **kwargs) 187 188 if title is not None: 189 self.SetTitle(title) 190 191 if self.original_text is not None: 192 self._TCTRL_text.SetValue(self.original_text) 193 self._BTN_restore.Enable(True) 194 195 if msg is None: 196 self._LBL_msg.Hide() 197 else: 198 self._LBL_msg.SetLabel(msg) 199 self.Layout() 200 self.Refresh() 201 202 if data is None: 203 self._TCTRL_data.Hide() 204 else: 205 self._TCTRL_data.SetValue(data) 206 self.Layout() 207 self.Refresh()
208 #-------------------------------------------------------- 209 # properties 210 #--------------------------------------------------------
211 - def _get_value(self):
212 return self._TCTRL_text.GetValue()
213 214 value = property(_get_value, lambda x:x) 215 #--------------------------------------------------------
216 - def _get_is_user_formatted(self):
217 return self._CHBOX_is_already_formatted.IsChecked()
218 219 is_user_formatted = property(_get_is_user_formatted, lambda x:x) 220 #--------------------------------------------------------
221 - def _set_enable_user_formatting(self, value):
222 self._CHBOX_is_already_formatted.Enable(value)
223 224 enable_user_formatting = property(lambda x:x, _set_enable_user_formatting) 225 #-------------------------------------------------------- 226 # event handlers 227 #--------------------------------------------------------
228 - def _on_save_button_pressed(self, evt):
229 230 if self.IsModal(): 231 self.EndModal(wx.ID_SAVE) 232 else: 233 self.Close()
234 #--------------------------------------------------------
235 - def _on_clear_button_pressed(self, evt):
236 self._TCTRL_text.SetValue(u'')
237 #--------------------------------------------------------
238 - def _on_restore_button_pressed(self, evt):
239 if self.original_text is not None: 240 self._TCTRL_text.SetValue(self.original_text)
241 # ======================================================================== 242 from Gnumed.business import gmSurgery 243 from Gnumed.wxGladeWidgets import wxgGreetingEditorDlg 244
245 -class cGreetingEditorDlg(wxgGreetingEditorDlg.wxgGreetingEditorDlg):
246
247 - def __init__(self, *args, **kwargs):
248 wxgGreetingEditorDlg.wxgGreetingEditorDlg.__init__(self, *args, **kwargs) 249 250 self.surgery = gmSurgery.gmCurrentPractice() 251 self._TCTRL_message.SetValue(self.surgery.db_logon_banner)
252 #-------------------------------------------------------- 253 # event handlers 254 #--------------------------------------------------------
255 - def _on_save_button_pressed(self, evt):
256 self.surgery.db_logon_banner = self._TCTRL_message.GetValue().strip() 257 if self.IsModal(): 258 self.EndModal(wx.ID_SAVE) 259 else: 260 self.Close()
261 # ========================================================================
262 -class cTreeExpansionHistoryMixin:
263 """TreeCtrl mixin class to record expansion history."""
264 - def __init__(self):
265 if not isinstance(self, wx.TreeCtrl): 266 raise TypeError('[%s]: mixin can only be applied to wx.TreeCtrl, not [%s]' % (cTreeExpansionHistoryMixin, self.__class__.__name__)) 267 self.expansion_state = {}
268 #-------------------------------------------------------- 269 # public API 270 #--------------------------------------------------------
271 - def snapshot_expansion(self):
272 self.__record_subtree_expansion(start_node_id = self.GetRootItem())
273 #--------------------------------------------------------
274 - def restore_expansion(self):
275 if len(self.expansion_state) == 0: 276 return True 277 self.__restore_subtree_expansion(start_node_id = self.GetRootItem())
278 #--------------------------------------------------------
279 - def print_expansion(self):
280 if len(self.expansion_state) == 0: 281 print "currently no expansion snapshot available" 282 return True 283 print "last snapshot of state of expansion" 284 print "-----------------------------------" 285 print "listing expanded nodes:" 286 for node_id in self.expansion_state.keys(): 287 print "node ID:", node_id 288 print " selected:", self.expansion_state[node_id]
289 #-------------------------------------------------------- 290 # internal API 291 #--------------------------------------------------------
292 - def __record_subtree_expansion(self, start_node_id=None):
293 """This records node expansion states based on the item label. 294 295 A side effect of this is that identically named items can 296 become unduly synchronized in their expand state after a 297 snapshot/restore cycle. 298 299 Better choices might be 300 301 id(item.GetPyData()) or 302 item.GetPyData().get_tree_uid() 303 304 where get_tree_uid(): 305 306 '[%s:%s]' % (self.__class__.__name__, id(self)) 307 308 or some such. This would survive renaming of the item. 309 310 For database items it may be useful to include the 311 primary key which would - contrary to id() - survive 312 reloads from the database. 313 """ 314 # protect against empty tree where not even 315 # a root node exists 316 if not start_node_id.IsOk(): 317 return True 318 319 if not self.IsExpanded(start_node_id): 320 return True 321 322 self.expansion_state[self.GetItemText(start_node_id)] = self.IsSelected(start_node_id) 323 324 child_id, cookie = self.GetFirstChild(start_node_id) 325 while child_id.IsOk(): 326 self.__record_subtree_expansion(start_node_id = child_id) 327 child_id, cookie = self.GetNextChild(start_node_id, cookie) 328 329 return
330 #--------------------------------------------------------
331 - def __restore_subtree_expansion(self, start_node_id=None):
332 start_node_label = self.GetItemText(start_node_id) 333 try: 334 node_selected = self.expansion_state[start_node_label] 335 except KeyError: 336 return 337 338 self.Expand(start_node_id) 339 if node_selected: 340 self.SelectItem(start_node_id) 341 342 child_id, cookie = self.GetFirstChild(start_node_id) 343 while child_id.IsOk(): 344 self.__restore_subtree_expansion(start_node_id = child_id) 345 child_id, cookie = self.GetNextChild(start_node_id, cookie) 346 347 return
348 # ========================================================================
349 -class cFileDropTarget(wx.FileDropTarget):
350 """Generic file drop target class. 351 352 Protocol: 353 Widgets being declared file drop targets 354 must provide the method: 355 356 add_filenames(filenames) 357 """ 358 #-----------------------------------------------
359 - def __init__(self, target):
360 wx.FileDropTarget.__init__(self) 361 self.target = target
362 #-----------------------------------------------
363 - def OnDropFiles(self, x, y, filenames):
364 self.target.add_filenames(filenames)
365 # ========================================================================
366 -def file2scaled_image(filename=None, height=100):
367 img_data = None 368 bitmap = None 369 rescaled_height = height 370 try: 371 img_data = wx.Image(filename, wx.BITMAP_TYPE_ANY) 372 current_width = img_data.GetWidth() 373 current_height = img_data.GetHeight() 374 # if current_width == 0: 375 # current_width = 1 376 # if current_height == 0: 377 # current_height = 1 378 rescaled_width = (current_width / current_height) * rescaled_height 379 img_data.Rescale(rescaled_width, rescaled_height, quality = wx.IMAGE_QUALITY_HIGH) # w, h 380 bitmap = wx.BitmapFromImage(img_data) 381 del img_data 382 except StandardError: 383 _log.exception('cannot load image from [%s]', filename) 384 del img_data 385 del bitmap 386 return None 387 388 return bitmap
389 # ========================================================================
390 -def gm_show_error(aMessage = None, aTitle = None):
391 if aMessage is None: 392 aMessage = _('programmer forgot to specify error message') 393 394 aMessage += _("\n\nPlease consult the error log for all the gory details !") 395 396 if aTitle is None: 397 aTitle = _('generic error message') 398 399 dlg = wx.MessageDialog ( 400 parent = None, 401 message = aMessage, 402 caption = aTitle, 403 style = wx.OK | wx.ICON_ERROR | wx.STAY_ON_TOP 404 ) 405 dlg.ShowModal() 406 dlg.Destroy() 407 return True
408 #-------------------------------------------------------------------------
409 -def gm_show_info(aMessage = None, aTitle = None):
410 if aMessage is None: 411 aMessage = _('programmer forgot to specify info message') 412 413 if aTitle is None: 414 aTitle = _('generic info message') 415 416 dlg = wx.MessageDialog ( 417 parent = None, 418 message = aMessage, 419 caption = aTitle, 420 style = wx.OK | wx.ICON_INFORMATION | wx.STAY_ON_TOP 421 ) 422 dlg.ShowModal() 423 dlg.Destroy() 424 return True
425 #-------------------------------------------------------------------------
426 -def gm_show_warning(aMessage=None, aTitle=None):
427 if aMessage is None: 428 aMessage = _('programmer forgot to specify warning') 429 430 if aTitle is None: 431 aTitle = _('generic warning message') 432 433 dlg = wx.MessageDialog ( 434 parent = None, 435 message = aMessage, 436 caption = aTitle, 437 style = wx.OK | wx.ICON_EXCLAMATION | wx.STAY_ON_TOP 438 ) 439 dlg.ShowModal() 440 dlg.Destroy() 441 return True
442 #-------------------------------------------------------------------------
443 -def gm_show_question(aMessage='programmer forgot to specify question', aTitle='generic user question dialog', cancel_button=False):
444 if cancel_button: 445 style = wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION | wx.STAY_ON_TOP 446 else: 447 style = wx.YES_NO | wx.ICON_QUESTION | wx.STAY_ON_TOP 448 449 dlg = wx.MessageDialog ( 450 None, 451 aMessage, 452 aTitle, 453 style 454 ) 455 btn_pressed = dlg.ShowModal() 456 dlg.Destroy() 457 458 if btn_pressed == wx.ID_YES: 459 return True 460 elif btn_pressed == wx.ID_NO: 461 return False 462 else: 463 return None
464 #====================================================================== 465 466 if __name__ == '__main__': 467 468 if len(sys.argv) < 2: 469 sys.exit() 470 471 if sys.argv[1] != 'test': 472 sys.exit() 473 474 app = wx.App() 475 img = file2scaled_image(filename = sys.argv[2]) 476 print img 477 print img.Height 478 print img.Width 479