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

Source Code for Module Gnumed.wxpython.gmDateTimeInput

  1  """GNUmed date input widget 
  2   
  3  All GNUmed date input should happen via classes in 
  4  this module. 
  5   
  6  @copyright: author(s) 
  7  """ 
  8  #============================================================================== 
  9  __author__  = "K. Hilbert <Karsten.Hilbert@gmx.net>" 
 10  __licence__ = "GPL v2 or later (details at http://www.gnu.org)" 
 11   
 12  # standard libary 
 13  import re, string, sys, time, datetime as pyDT, logging 
 14   
 15   
 16  # 3rd party 
 17  import wx 
 18  try: 
 19          import wx.calendar as wxcal 
 20  except ImportError: 
 21          # Phoenix 
 22          import wx.adv as wxcal 
 23   
 24   
 25  # GNUmed specific 
 26  if __name__ == '__main__': 
 27          sys.path.insert(0, '../../') 
 28  from Gnumed.pycommon import gmMatchProvider 
 29  from Gnumed.pycommon import gmDateTime 
 30  from Gnumed.pycommon import gmI18N 
 31  from Gnumed.wxpython import gmPhraseWheel 
 32  from Gnumed.wxpython import gmGuiHelpers 
 33   
 34  _log = logging.getLogger('gm.ui') 
 35   
 36  #============================================================ 
 37  #class cIntervalMatchProvider(gmMatchProvider.cMatchProvider): 
 38  #       """Turns strings into candidate intervals.""" 
 39  #       def __init__(self): 
 40  # 
 41  #               gmMatchProvider.cMatchProvider.__init__(self) 
 42  # 
 43  #               self.setThresholds(aPhrase = 1, aWord = 998, aSubstring = 999) 
 44  #               self.word_separators = None 
 45  ##              self.ignored_chars("""[?!."'\\(){}\[\]<>~#*$%^_]+""") 
 46  #       #-------------------------------------------------------- 
 47  #       # external API 
 48  #       #-------------------------------------------------------- 
 49  #       #-------------------------------------------------------- 
 50  #       # base class API 
 51  #       #-------------------------------------------------------- 
 52  #       def getMatchesByPhrase(self, aFragment): 
 53  #               intv = gmDateTime.str2interval(str_interval = aFragment) 
 54  # 
 55  #               if intv is None: 
 56  #                       return (False, []) 
 57  # 
 58  #               items = [{ 
 59  #                       'data': intv, 
 60  #                       'field_label': gmDateTime.format_interval(intv, gmDateTime.acc_minutes), 
 61  #                       'list_label': gmDateTime.format_interval(intv, gmDateTime.acc_minutes) 
 62  #               }] 
 63  # 
 64  #               return (True, items) 
 65  #       #-------------------------------------------------------- 
 66  #       def getMatchesByWord(self, aFragment): 
 67  #               return self.getMatchesByPhrase(aFragment) 
 68  #       #-------------------------------------------------------- 
 69  #       def getMatchesBySubstr(self, aFragment): 
 70  #               return self.getMatchesByPhrase(aFragment) 
 71  #       #-------------------------------------------------------- 
 72  #       def getAllMatches(self): 
 73  #               matches = (False, []) 
 74  #               return matches 
 75   
 76  #============================================================ 
77 -class cIntervalPhraseWheel(gmPhraseWheel.cPhraseWheel):
78
79 - def __init__(self, *args, **kwargs):
80 81 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 82 self.phrase_separators = None 83 self.display_accuracy = None
84 #-------------------------------------------------------- 85 # phrasewheel internal API 86 #--------------------------------------------------------
87 - def _update_candidates_in_picklist(self, val):
88 intv = gmDateTime.str2interval(str_interval = val) 89 if intv is None: 90 self._current_match_candidates = [] 91 else: 92 self._current_match_candidates = [{ 93 'data': intv, 94 'field_label': gmDateTime.format_interval(intv, gmDateTime.acc_minutes), 95 'list_label': gmDateTime.format_interval(intv, gmDateTime.acc_minutes) 96 }] 97 self._picklist.SetItems(self._current_match_candidates)
98 #--------------------------------------------------------- 99 # def _on_lose_focus(self, event): 100 # # are we valid ? 101 # if len(self._data) == 0: 102 # self._set_data_to_first_match() 103 # 104 # # let the base class do its thing 105 # super(cIntervalPhraseWheel, self)._on_lose_focus(event) 106 #--------------------------------------------------------
107 - def _picklist_item2display_string(self, item=None):
108 intv = item['data'] 109 if intv is not None: 110 return gmDateTime.format_interval ( 111 interval = intv, 112 accuracy_wanted = self.display_accuracy 113 ) 114 return item['field_label']
115 #--------------------------------------------------------
116 - def _get_data_tooltip(self):
117 intv = self.GetData() 118 if intv is None: 119 return '' 120 return gmDateTime.format_interval ( 121 interval = intv, 122 accuracy_wanted = self.display_accuracy 123 )
124 #-------------------------------------------------------- 125 # external API 126 #--------------------------------------------------------
127 - def SetValue(self, value):
128 129 if isinstance(value, pyDT.timedelta): 130 self.SetText(data = value, suppress_smarts = True) 131 return 132 133 if value is None: 134 value = '' 135 136 super(cIntervalPhraseWheel, self).SetValue(value)
137 #--------------------------------------------------------
138 - def SetText(self, value='', data=None, suppress_smarts=False):
139 140 if data is not None: 141 if value.strip() == '': 142 value = gmDateTime.format_interval ( 143 interval = data, 144 accuracy_wanted = self.display_accuracy 145 ) 146 147 super(cIntervalPhraseWheel, self).SetText(value = value, data = data, suppress_smarts = suppress_smarts)
148 #--------------------------------------------------------
149 - def SetData(self, data=None):
150 if data is None: 151 super(cIntervalPhraseWheel, self).SetText('', None) 152 return 153 154 value = gmDateTime.format_interval ( 155 interval = data, 156 accuracy_wanted = self.display_accuracy 157 ) 158 super(cIntervalPhraseWheel, self).SetText(value = value, data = data)
159 #--------------------------------------------------------
160 - def GetData(self):
161 if len(self._data) == 0: 162 self._set_data_to_first_match() 163 164 return super(cIntervalPhraseWheel, self).GetData()
165 166 #============================================================
167 -class cCalendarDatePickerDlg(wx.Dialog):
168 """Shows a calendar control from which the user can pick a date."""
169 - def __init__(self, parent):
170 171 wx.Dialog.__init__(self, parent, title = _('Pick a date ...')) 172 panel = wx.Panel(self, -1) 173 174 sizer = wx.BoxSizer(wx.VERTICAL) 175 panel.SetSizer(sizer) 176 177 cal = wxcal.CalendarCtrl(panel) 178 179 if sys.platform != 'win32': 180 # gtk truncates the year - this fixes it 181 w, h = cal.Size 182 cal.Size = (w+25, h) 183 cal.MinSize = cal.Size 184 185 sizer.Add(cal, 0) 186 187 button_sizer = wx.BoxSizer(wx.HORIZONTAL) 188 button_sizer.Add((0, 0), 1) 189 btn_ok = wx.Button(panel, wx.ID_OK) 190 btn_ok.SetDefault() 191 button_sizer.Add(btn_ok, 0, wx.ALL, 2) 192 button_sizer.Add((0, 0), 1) 193 btn_can = wx.Button(panel, wx.ID_CANCEL) 194 button_sizer.Add(btn_can, 0, wx.ALL, 2) 195 button_sizer.Add((0, 0), 1) 196 sizer.Add(button_sizer, 1, wx.EXPAND | wx.ALL, 10) 197 sizer.Fit(panel) 198 self.ClientSize = panel.Size 199 200 cal.Bind(wx.EVT_KEY_DOWN, self.__on_key_down) 201 cal.SetFocus() 202 self.cal = cal
203 204 #-----------------------------------------------------------
205 - def __on_key_down(self, evt):
206 code = evt.KeyCode 207 if code == wx.WXK_TAB: 208 self.cal.Navigate() 209 elif code in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER): 210 self.EndModal(wx.ID_OK) 211 elif code == wx.WXK_ESCAPE: 212 self.EndModal(wx.ID_CANCEL) 213 else: 214 evt.Skip()
215 216 #============================================================
217 -class cDateMatchProvider(gmMatchProvider.cMatchProvider):
218 """Turns strings into candidate dates. 219 220 Matching on "all" (*, '') will pop up a calendar :-) 221 """
222 - def __init__(self):
223 224 gmMatchProvider.cMatchProvider.__init__(self) 225 226 self.setThresholds(aPhrase = 1, aWord = 998, aSubstring = 999) 227 self.word_separators = None
228 # self.ignored_chars("""[?!."'\\(){}\[\]<>~#*$%^_]+""") 229 #-------------------------------------------------------- 230 # external API 231 #-------------------------------------------------------- 232 #-------------------------------------------------------- 233 # base class API 234 #-------------------------------------------------------- 235 # internal matching algorithms 236 # 237 # if we end up here: 238 # - aFragment will not be "None" 239 # - aFragment will be lower case 240 # - we _do_ deliver matches (whether we find any is a different story) 241 #--------------------------------------------------------
242 - def getMatchesByPhrase(self, aFragment):
243 """Return matches for aFragment at start of phrases.""" 244 matches = gmDateTime.str2pydt_matches(str2parse = aFragment.strip()) 245 246 if len(matches) == 0: 247 return (False, []) 248 249 items = [] 250 for match in matches: 251 if match['data'] is None: 252 items.append ({ 253 'data': None, 254 'field_label': match['label'], 255 'list_label': match['label'] 256 }) 257 continue 258 259 data = match['data'].replace ( 260 hour = 11, 261 minute = 11, 262 second = 11, 263 microsecond = 111111 264 ) 265 list_label = gmDateTime.pydt_strftime ( 266 data, 267 format = '%A, %d. %B %Y (%x)', 268 accuracy = gmDateTime.acc_days 269 ) 270 items.append ({ 271 'data': data, 272 'field_label': match['label'], 273 'list_label': list_label 274 }) 275 276 return (True, items)
277 #--------------------------------------------------------
278 - def getMatchesByWord(self, aFragment):
279 """Return matches for aFragment at start of words inside phrases.""" 280 return self.getMatchesByPhrase(aFragment)
281 #--------------------------------------------------------
282 - def getMatchesBySubstr(self, aFragment):
283 """Return matches for aFragment as a true substring.""" 284 return self.getMatchesByPhrase(aFragment)
285 #--------------------------------------------------------
286 - def getAllMatches(self):
287 """Return all items.""" 288 289 matches = (False, []) 290 return matches
291 292 # # consider this: 293 # dlg = cCalendarDatePickerDlg(None) 294 # # FIXME: show below parent 295 # dlg.CentreOnScreen() 296 # 297 # if dlg.ShowModal() == wx.ID_OK: 298 # date = dlg.cal.Date 299 # if date is not None: 300 # if date.IsValid(): 301 # date = gmDateTime.wxDate2py_dt(wxDate = date).replace ( 302 # hour = 11, 303 # minute = 11, 304 # second = 11, 305 # microsecond = 111111 306 # ) 307 # lbl = gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 308 # matches = (True, [{'data': date, 'label': lbl}]) 309 # dlg.Destroy() 310 # 311 # return matches 312 313 #============================================================
314 -class cDateInputPhraseWheel(gmPhraseWheel.cPhraseWheel):
315
316 - def __init__(self, *args, **kwargs):
317 318 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 319 320 self.matcher = cDateMatchProvider() 321 self.phrase_separators = None 322 323 self.static_tooltip_extra = _('<ALT-C/K>: pick from (c/k)alendar') 324 325 self.__weekday_keys = [wx.WXK_F1, wx.WXK_F2, wx.WXK_F3, wx.WXK_F4, wx.WXK_F5, wx.WXK_F6, wx.WXK_F7]
326 327 #-------------------------------------------------------- 328 # internal helpers 329 #-------------------------------------------------------- 330 # def __text2timestamp(self): 331 # 332 # self._update_candidates_in_picklist(val = self.GetValue().strip()) 333 # 334 # if len(self._current_match_candidates) == 1: 335 # return self._current_match_candidates[0]['data'] 336 # 337 # return None 338 #--------------------------------------------------------
339 - def __pick_from_calendar(self):
340 dlg = cCalendarDatePickerDlg(self) 341 # FIXME: show below parent 342 dlg.CentreOnScreen() 343 decision = dlg.ShowModal() 344 date = dlg.cal.Date 345 dlg.Destroy() 346 347 if decision != wx.ID_OK: 348 return 349 350 if date is None: 351 return 352 353 if not date.IsValid(): 354 return 355 356 date = gmDateTime.wxDate2py_dt(wxDate = date).replace ( 357 hour = 11, 358 minute = 11, 359 second = 11, 360 microsecond = 111111 361 ) 362 val = gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 363 self.SetText(value = val, data = date, suppress_smarts = True)
364 365 #--------------------------------------------------------
366 - def __pick_from_weekday(self, weekday):
367 self.is_valid_timestamp(empty_is_valid = True) 368 target_date = gmDateTime.get_date_of_weekday_in_week_of_date(weekday, base_dt = self.date) 369 val = gmDateTime.pydt_strftime(target_date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 370 self.SetText(value = val, data = target_date, suppress_smarts = True)
371 372 #-------------------------------------------------------- 373 # phrasewheel internal API 374 #--------------------------------------------------------
375 - def _on_lose_focus(self, event):
376 # no valid date yet ? 377 if len(self._data) == 0: 378 self._set_data_to_first_match() 379 date = self.GetData() 380 if date is not None: 381 self.SetValue(gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days)) 382 383 # let the base class do its thing 384 super(cDateInputPhraseWheel, self)._on_lose_focus(event)
385 386 #--------------------------------------------------------
387 - def _picklist_item2display_string(self, item=None):
388 data = item['data'] 389 if data is not None: 390 return gmDateTime.pydt_strftime(data, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 391 return item['field_label']
392 393 #--------------------------------------------------------
394 - def _on_key_down(self, event):
395 396 if event.GetUnicodeKey() == wx.WXK_NONE: 397 key = event.GetKeyCode() 398 if key in self.__weekday_keys: 399 self.__pick_from_weekday(self.__weekday_keys.index(key)) 400 return 401 402 # <ALT-C> / <ALT-K> -> calendar 403 if event.AltDown() is True: 404 char = chr(event.GetUnicodeKey()) 405 if char in 'ckCK': 406 self.__pick_from_calendar() 407 return 408 409 super()._on_key_down(event)
410 411 #--------------------------------------------------------
412 - def _get_data_tooltip(self):
413 if len(self._data) == 0: 414 return '' 415 416 date = self.GetData() 417 # if match provider only provided completions 418 # but not a full date with it 419 if date is None: 420 return '' 421 422 now = gmDateTime.pydt_now_here() 423 if date > now: 424 intv = date - now 425 template = _('%s\n (a %s in %s)') 426 else: 427 intv = now - date 428 template = _('%s\n (a %s %s ago)') 429 return template % ( 430 gmDateTime.pydt_strftime(date, format = '%B %d %Y -- %c', accuracy = gmDateTime.acc_days), 431 gmDateTime.pydt_strftime(date, format = '%A', accuracy = gmDateTime.acc_days), 432 gmDateTime.format_interval(interval = intv, accuracy_wanted = gmDateTime.acc_days, verbose = True) 433 )
434 435 #-------------------------------------------------------- 436 # external API 437 #--------------------------------------------------------
438 - def SetValue(self, value):
439 440 if isinstance(value, pyDT.datetime): 441 date = value.replace ( 442 hour = 11, 443 minute = 11, 444 second = 11, 445 microsecond = 111111 446 ) 447 self.SetText(data = date, suppress_smarts = True) 448 return 449 450 if value is None: 451 value = '' 452 453 super().SetValue(value)
454 455 #--------------------------------------------------------
456 - def SetText(self, value='', data=None, suppress_smarts=False):
457 458 if data is not None: 459 if isinstance(data, gmDateTime.cFuzzyTimestamp): 460 data = data.timestamp.replace ( 461 hour = 11, 462 minute = 11, 463 second = 11, 464 microsecond = 111111 465 ) 466 if value.strip() == '': 467 value = gmDateTime.pydt_strftime(data, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 468 469 super().SetText(value = value, data = data, suppress_smarts = suppress_smarts)
470 471 #--------------------------------------------------------
472 - def SetData(self, data=None):
473 if data is None: 474 gmPhraseWheel.cPhraseWheel.SetText(self, '', None) 475 return 476 self.SetText(data = data)
477 478 #--------------------------------------------------------
479 - def GetData(self):
480 if len(self._data) == 0: 481 self._set_data_to_first_match() 482 483 return super(self.__class__, self).GetData()
484 485 #--------------------------------------------------------
486 - def is_valid_timestamp(self, empty_is_valid=True):
487 if len(self._data) > 0: 488 self.display_as_valid(True) 489 return True 490 491 if self.GetValue().strip() == '': 492 if empty_is_valid: 493 self.display_as_valid(True) 494 return True 495 else: 496 self.display_as_valid(False) 497 return False 498 499 # skip showing calendar on '*' from here 500 if self.GetValue().strip() == '*': 501 self.display_as_valid(False) 502 return False 503 504 # try to auto-snap to first match 505 self._set_data_to_first_match() 506 if len(self._data) == 0: 507 self.display_as_valid(False) 508 return False 509 510 date = self.GetData() 511 self.SetValue(gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days))#, none_str = u'') 512 self.display_as_valid(True) 513 return True
514 515 #-------------------------------------------------------- 516 # properties 517 #--------------------------------------------------------
518 - def _get_date(self):
519 return self.GetData()
520
521 - def _set_date(self, date):
522 raise AttributeError('._set_date not implemented')
523 # val = gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 524 # self.data = date.replace ( 525 # hour = 11, 526 # minute = 11, 527 # second = 11, 528 # microsecond = 111111 529 # ) 530 531 date = property(_get_date, _set_date)
532 533 #============================================================
534 -class cMatchProvider_FuzzyTimestamp(gmMatchProvider.cMatchProvider):
535 - def __init__(self):
536 self.__allow_past = 1 537 self.__shifting_base = None 538 539 gmMatchProvider.cMatchProvider.__init__(self) 540 541 self.setThresholds(aPhrase = 1, aWord = 998, aSubstring = 999) 542 self.word_separators = None
543 # self.ignored_chars("""[?!."'\\(){}\[\]<>~#*$%^_]+""") 544 #-------------------------------------------------------- 545 # external API 546 #-------------------------------------------------------- 547 #-------------------------------------------------------- 548 # base class API 549 #-------------------------------------------------------- 550 # internal matching algorithms 551 # 552 # if we end up here: 553 # - aFragment will not be "None" 554 # - aFragment will be lower case 555 # - we _do_ deliver matches (whether we find any is a different story) 556 #--------------------------------------------------------
557 - def getMatchesByPhrase(self, aFragment):
558 """Return matches for aFragment at start of phrases.""" 559 matches = gmDateTime.str2fuzzy_timestamp_matches(aFragment.strip()) 560 561 if len(matches) == 0: 562 return (False, []) 563 564 items = [] 565 for match in matches: 566 items.append ({ 567 'data': match['data'], 568 'field_label': match['label'], 569 'list_label': match['label'] 570 }) 571 572 return (True, items)
573 #--------------------------------------------------------
574 - def getMatchesByWord(self, aFragment):
575 """Return matches for aFragment at start of words inside phrases.""" 576 return self.getMatchesByPhrase(aFragment)
577 #--------------------------------------------------------
578 - def getMatchesBySubstr(self, aFragment):
579 """Return matches for aFragment as a true substring.""" 580 return self.getMatchesByPhrase(aFragment)
581 #--------------------------------------------------------
582 - def getAllMatches(self):
583 """Return all items.""" 584 return (False, [])
585 586 #==================================================
587 -class cFuzzyTimestampInput(gmPhraseWheel.cPhraseWheel):
588
589 - def __init__(self, *args, **kwargs):
590 591 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 592 593 self.matcher = cMatchProvider_FuzzyTimestamp() 594 self.phrase_separators = None 595 self.selection_only = True 596 self.selection_only_error_msg = _('Cannot interpret input as timestamp.') 597 self.display_accuracy = None 598 599 self.__weekday_keys = [wx.WXK_F1, wx.WXK_F2, wx.WXK_F3, wx.WXK_F4, wx.WXK_F5, wx.WXK_F6, wx.WXK_F7]
600 601 #-------------------------------------------------------- 602 # internal helpers 603 #--------------------------------------------------------
604 - def __text2timestamp(self, val=None):
605 if val is None: 606 val = self.GetValue() 607 val = val.strip() 608 if val == '': 609 return None 610 success, matches = self.matcher.getMatchesByPhrase(val) 611 if len(matches) == 1: 612 return matches[0]['data'] 613 return None
614 615 #--------------------------------------------------------
616 - def __pick_from_weekday(self, weekday):
617 self.is_valid_timestamp(empty_is_valid = True) 618 dt = self.GetData() 619 if dt is not None: 620 dt = dt.timestamp 621 target_date = gmDateTime.get_date_of_weekday_in_week_of_date(weekday, base_dt = dt) 622 self.SetText(data = target_date, suppress_smarts = True)
623 624 #-------------------------------------------------------- 625 # phrasewheel internal API 626 #--------------------------------------------------------
627 - def _on_lose_focus(self, event):
628 # are we valid ? 629 if self.data is None: 630 # no, so try 631 date = self.__text2timestamp() 632 if date is not None: 633 self.SetValue(value = date.format_accurately(accuracy = self.display_accuracy)) 634 self.data = date 635 636 # let the base class do its thing 637 gmPhraseWheel.cPhraseWheel._on_lose_focus(self, event)
638 639 #--------------------------------------------------------
640 - def _picklist_item2display_string(self, item=None):
641 data = item['data'] 642 if data is not None: 643 return data.format_accurately(accuracy = self.display_accuracy) 644 return item['field_label']
645 646 #--------------------------------------------------------
647 - def _on_key_down(self, event):
648 649 if event.GetUnicodeKey() == wx.WXK_NONE: 650 key = event.GetKeyCode() 651 if key in self.__weekday_keys: 652 self.__pick_from_weekday(self.__weekday_keys.index(key)) 653 return 654 655 # # <ALT-C> / <ALT-K> -> calendar 656 # if event.AltDown() is True: 657 # char = chr(event.GetUnicodeKey()) 658 # if char in 'ckCK': 659 # self.__pick_from_calendar() 660 # return 661 662 super()._on_key_down(event)
663 664 #--------------------------------------------------------
665 - def _get_data_tooltip(self):
666 if len(self._data) == 0: 667 return '' 668 669 date = self.GetData() 670 # if match provider only provided completions 671 # but not a full date with it 672 if date is None: 673 return '' 674 ts = date.timestamp 675 now = gmDateTime.pydt_now_here() 676 if ts > now: 677 intv = ts - now 678 template = _('%s\n %s\n in %s') 679 else: 680 intv = now - ts 681 template = _('%s\n%s\n%s ago') 682 txt = template % ( 683 date.format_accurately(self.display_accuracy), 684 gmDateTime.pydt_strftime ( 685 ts, 686 format = '%A, %B-%d %Y (%c)', 687 ), 688 gmDateTime.format_interval ( 689 interval = intv, 690 accuracy_wanted = gmDateTime.acc_days, 691 verbose = True 692 ) 693 ) 694 return txt
695 696 #-------------------------------------------------------- 697 # external API 698 #--------------------------------------------------------
699 - def SetText(self, value='', data=None, suppress_smarts=False):
700 701 if data is not None: 702 if isinstance(data, pyDT.datetime): 703 data = gmDateTime.cFuzzyTimestamp(timestamp = data) 704 if value.strip() == '': 705 value = data.format_accurately(accuracy = self.display_accuracy) 706 707 super().SetText(value = value, data = data, suppress_smarts = suppress_smarts)
708 709 #--------------------------------------------------------
710 - def SetData(self, data=None):
711 if data is None: 712 gmPhraseWheel.cPhraseWheel.SetText(self, '', None) 713 else: 714 if isinstance(data, pyDT.datetime): 715 data = gmDateTime.cFuzzyTimestamp(timestamp=data) 716 gmPhraseWheel.cPhraseWheel.SetText(self, value = data.format_accurately(accuracy = self.display_accuracy), data = data)
717 718 #--------------------------------------------------------
719 - def is_valid_timestamp(self, empty_is_valid=True):
720 if self.GetData() is not None: 721 return True 722 723 # skip empty value 724 if self.GetValue().strip() == '': 725 if empty_is_valid: 726 return True 727 return False 728 729 date = self.__text2timestamp() 730 if date is None: 731 return False 732 733 self.SetText ( 734 value = date.format_accurately(accuracy = self.display_accuracy), 735 data = date, 736 suppress_smarts = True 737 ) 738 739 return True
740 741 #================================================== 742 # main 743 #-------------------------------------------------- 744 if __name__ == '__main__': 745 746 if len(sys.argv) < 2: 747 sys.exit() 748 749 if sys.argv[1] != 'test': 750 sys.exit() 751 752 gmI18N.activate_locale() 753 gmI18N.install_domain(domain='gnumed') 754 gmDateTime.init() 755 756 #----------------------------------------------------
757 - def test_cli():
758 mp = cMatchProvider_FuzzyTimestamp() 759 mp.word_separators = None 760 mp.setThresholds(aWord = 998, aSubstring = 999) 761 val = None 762 while val != 'exit': 763 print("************************************") 764 val = input('Enter date fragment ("exit" to quit): ') 765 found, matches = mp.getMatches(aFragment=val) 766 for match in matches: 767 #print match 768 print(match['label']) 769 print(match['data']) 770 print("---------------")
771 #--------------------------------------------------------
772 - def test_fuzzy_picker():
773 app = wx.PyWidgetTester(size = (300, 40)) 774 app.SetWidget(cFuzzyTimestampInput, id=-1, size=(180,20), pos=(10,20)) 775 app.MainLoop()
776 #--------------------------------------------------------
777 - def test_picker():
778 app = wx.PyWidgetTester(size = (300, 40)) 779 app.SetWidget(cDateInputPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 780 app.MainLoop()
781 #-------------------------------------------------------- 782 #test_cli() 783 #test_fuzzy_picker() 784 test_picker() 785 786 #================================================== 787