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.DestroyLater() 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.DestroyLater() 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 if isinstance(date, pyDT.datetime): 423 date = pyDT.date(date.year, date.month, date.day) 424 today = pyDT.date.today() 425 if date > today: 426 intv = date - today 427 return _('%s\n (a %s in %s)') % ( 428 date.strftime(format = '%B %d %Y -- %x'), 429 date.strftime(format = '%A'), 430 gmDateTime.format_interval(interval = intv, accuracy_wanted = gmDateTime.acc_days, verbose = True) 431 ) 432 433 if date < today: 434 intv = today - date 435 return _('%s\n (a %s %s ago)') % ( 436 gmDateTime.pydt_strftime(date, format = '%B %d %Y -- %x'), 437 gmDateTime.pydt_strftime(date, format = '%A'), 438 gmDateTime.format_interval(interval = intv, accuracy_wanted = gmDateTime.acc_days, verbose = True) 439 ) 440 441 return _('today (%s): %s') % ( 442 gmDateTime.pydt_strftime(date, format = '%A'), 443 gmDateTime.pydt_strftime(date, format = '%B %d %Y -- %x') 444 )
445 446 #-------------------------------------------------------- 447 # external API 448 #--------------------------------------------------------
449 - def SetValue(self, value):
450 451 if isinstance(value, pyDT.datetime): 452 date = value.replace ( 453 hour = 11, 454 minute = 11, 455 second = 11, 456 microsecond = 111111 457 ) 458 self.SetText(data = date, suppress_smarts = True) 459 return 460 461 if value is None: 462 value = '' 463 464 super().SetValue(value)
465 466 #--------------------------------------------------------
467 - def SetText(self, value='', data=None, suppress_smarts=False):
468 469 if data is not None: 470 if isinstance(data, gmDateTime.cFuzzyTimestamp): 471 data = data.timestamp.replace ( 472 hour = 11, 473 minute = 11, 474 second = 11, 475 microsecond = 111111 476 ) 477 if value.strip() == '': 478 value = gmDateTime.pydt_strftime(data, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 479 480 super().SetText(value = value, data = data, suppress_smarts = suppress_smarts)
481 482 #--------------------------------------------------------
483 - def SetData(self, data=None):
484 if data is None: 485 gmPhraseWheel.cPhraseWheel.SetText(self, '', None) 486 return 487 self.SetText(data = data)
488 489 #--------------------------------------------------------
490 - def GetData(self):
491 if len(self._data) == 0: 492 self._set_data_to_first_match() 493 494 return super(self.__class__, self).GetData()
495 496 #--------------------------------------------------------
497 - def is_valid_timestamp(self, empty_is_valid=True):
498 if len(self._data) > 0: 499 self.display_as_valid(True) 500 return True 501 502 if self.GetValue().strip() == '': 503 if empty_is_valid: 504 self.display_as_valid(True) 505 return True 506 else: 507 self.display_as_valid(False) 508 return False 509 510 # skip showing calendar on '*' from here 511 if self.GetValue().strip() == '*': 512 self.display_as_valid(False) 513 return False 514 515 # try to auto-snap to first match 516 self._set_data_to_first_match() 517 if len(self._data) == 0: 518 self.display_as_valid(False) 519 return False 520 521 date = self.GetData() 522 self.SetValue(gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days))#, none_str = u'') 523 self.display_as_valid(True) 524 return True
525 526 #-------------------------------------------------------- 527 # properties 528 #--------------------------------------------------------
529 - def _get_date(self):
530 return self.GetData()
531
532 - def _set_date(self, date):
533 raise AttributeError('._set_date not implemented')
534 # val = gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 535 # self.data = date.replace ( 536 # hour = 11, 537 # minute = 11, 538 # second = 11, 539 # microsecond = 111111 540 # ) 541 542 date = property(_get_date, _set_date)
543 544 #============================================================
545 -class cMatchProvider_FuzzyTimestamp(gmMatchProvider.cMatchProvider):
546 - def __init__(self):
547 self.__allow_past = 1 548 self.__shifting_base = None 549 550 gmMatchProvider.cMatchProvider.__init__(self) 551 552 self.setThresholds(aPhrase = 1, aWord = 998, aSubstring = 999) 553 self.word_separators = None
554 # self.ignored_chars("""[?!."'\\(){}\[\]<>~#*$%^_]+""") 555 #-------------------------------------------------------- 556 # external API 557 #-------------------------------------------------------- 558 #-------------------------------------------------------- 559 # base class API 560 #-------------------------------------------------------- 561 # internal matching algorithms 562 # 563 # if we end up here: 564 # - aFragment will not be "None" 565 # - aFragment will be lower case 566 # - we _do_ deliver matches (whether we find any is a different story) 567 #--------------------------------------------------------
568 - def getMatchesByPhrase(self, aFragment):
569 """Return matches for aFragment at start of phrases.""" 570 matches = gmDateTime.str2fuzzy_timestamp_matches(aFragment.strip()) 571 572 if len(matches) == 0: 573 return (False, []) 574 575 items = [] 576 for match in matches: 577 items.append ({ 578 'data': match['data'], 579 'field_label': match['label'], 580 'list_label': match['label'] 581 }) 582 583 return (True, items)
584 #--------------------------------------------------------
585 - def getMatchesByWord(self, aFragment):
586 """Return matches for aFragment at start of words inside phrases.""" 587 return self.getMatchesByPhrase(aFragment)
588 #--------------------------------------------------------
589 - def getMatchesBySubstr(self, aFragment):
590 """Return matches for aFragment as a true substring.""" 591 return self.getMatchesByPhrase(aFragment)
592 #--------------------------------------------------------
593 - def getAllMatches(self):
594 """Return all items.""" 595 return (False, [])
596 597 #==================================================
598 -class cFuzzyTimestampInput(gmPhraseWheel.cPhraseWheel):
599
600 - def __init__(self, *args, **kwargs):
601 602 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 603 604 self.matcher = cMatchProvider_FuzzyTimestamp() 605 self.phrase_separators = None 606 self.selection_only = True 607 self.selection_only_error_msg = _('Cannot interpret input as timestamp.') 608 self.display_accuracy = None 609 610 self.__weekday_keys = [wx.WXK_F1, wx.WXK_F2, wx.WXK_F3, wx.WXK_F4, wx.WXK_F5, wx.WXK_F6, wx.WXK_F7]
611 612 #-------------------------------------------------------- 613 # internal helpers 614 #--------------------------------------------------------
615 - def __text2timestamp(self, val=None):
616 if val is None: 617 val = self.GetValue() 618 val = val.strip() 619 if val == '': 620 return None 621 success, matches = self.matcher.getMatchesByPhrase(val) 622 if len(matches) == 1: 623 return matches[0]['data'] 624 return None
625 626 #--------------------------------------------------------
627 - def __pick_from_weekday(self, weekday):
628 self.is_valid_timestamp(empty_is_valid = True) 629 dt = self.GetData() 630 if dt is not None: 631 dt = dt.timestamp 632 target_date = gmDateTime.get_date_of_weekday_in_week_of_date(weekday, base_dt = dt) 633 self.SetText(data = target_date, suppress_smarts = True)
634 635 #-------------------------------------------------------- 636 # phrasewheel internal API 637 #--------------------------------------------------------
638 - def _on_lose_focus(self, event):
639 # are we valid ? 640 if self.data is None: 641 # no, so try 642 date = self.__text2timestamp() 643 if date is not None: 644 self.SetValue(value = date.format_accurately(accuracy = self.display_accuracy)) 645 self.data = date 646 647 # let the base class do its thing 648 gmPhraseWheel.cPhraseWheel._on_lose_focus(self, event)
649 650 #--------------------------------------------------------
651 - def _picklist_item2display_string(self, item=None):
652 data = item['data'] 653 if data is not None: 654 return data.format_accurately(accuracy = self.display_accuracy) 655 return item['field_label']
656 657 #--------------------------------------------------------
658 - def _on_key_down(self, event):
659 660 if event.GetUnicodeKey() == wx.WXK_NONE: 661 key = event.GetKeyCode() 662 if key in self.__weekday_keys: 663 self.__pick_from_weekday(self.__weekday_keys.index(key)) 664 return 665 666 # # <ALT-C> / <ALT-K> -> calendar 667 # if event.AltDown() is True: 668 # char = chr(event.GetUnicodeKey()) 669 # if char in 'ckCK': 670 # self.__pick_from_calendar() 671 # return 672 673 super()._on_key_down(event)
674 675 #--------------------------------------------------------
676 - def _get_data_tooltip(self):
677 if len(self._data) == 0: 678 return '' 679 680 date = self.GetData() 681 # if match provider only provided completions 682 # but not a full date with it 683 if date is None: 684 return '' 685 ts = date.timestamp 686 now = gmDateTime.pydt_now_here() 687 if ts > now: 688 intv = ts - now 689 template = _('%s\n %s\n in %s') 690 else: 691 intv = now - ts 692 template = _('%s\n%s\n%s ago') 693 txt = template % ( 694 date.format_accurately(self.display_accuracy), 695 gmDateTime.pydt_strftime ( 696 ts, 697 format = '%A, %B-%d %Y (%c)', 698 ), 699 gmDateTime.format_interval ( 700 interval = intv, 701 accuracy_wanted = gmDateTime.acc_days, 702 verbose = True 703 ) 704 ) 705 return txt
706 707 #-------------------------------------------------------- 708 # external API 709 #--------------------------------------------------------
710 - def SetText(self, value='', data=None, suppress_smarts=False):
711 712 if data is not None: 713 if isinstance(data, pyDT.datetime): 714 data = gmDateTime.cFuzzyTimestamp(timestamp = data) 715 if value.strip() == '': 716 value = data.format_accurately(accuracy = self.display_accuracy) 717 718 super().SetText(value = value, data = data, suppress_smarts = suppress_smarts)
719 720 #--------------------------------------------------------
721 - def SetData(self, data=None):
722 if data is None: 723 gmPhraseWheel.cPhraseWheel.SetText(self, '', None) 724 else: 725 if isinstance(data, pyDT.datetime): 726 data = gmDateTime.cFuzzyTimestamp(timestamp=data) 727 gmPhraseWheel.cPhraseWheel.SetText(self, value = data.format_accurately(accuracy = self.display_accuracy), data = data)
728 729 #--------------------------------------------------------
730 - def is_valid_timestamp(self, empty_is_valid=True):
731 if self.GetData() is not None: 732 return True 733 734 # skip empty value 735 if self.GetValue().strip() == '': 736 if empty_is_valid: 737 return True 738 return False 739 740 date = self.__text2timestamp() 741 if date is None: 742 return False 743 744 self.SetText ( 745 value = date.format_accurately(accuracy = self.display_accuracy), 746 data = date, 747 suppress_smarts = True 748 ) 749 750 return True
751 752 #================================================== 753 # main 754 #-------------------------------------------------- 755 if __name__ == '__main__': 756 757 if len(sys.argv) < 2: 758 sys.exit() 759 760 if sys.argv[1] != 'test': 761 sys.exit() 762 763 gmI18N.activate_locale() 764 gmI18N.install_domain(domain='gnumed') 765 gmDateTime.init() 766 767 #----------------------------------------------------
768 - def test_cli():
769 mp = cMatchProvider_FuzzyTimestamp() 770 mp.word_separators = None 771 mp.setThresholds(aWord = 998, aSubstring = 999) 772 val = None 773 while val != 'exit': 774 print("************************************") 775 val = input('Enter date fragment ("exit" to quit): ') 776 found, matches = mp.getMatches(aFragment=val) 777 for match in matches: 778 #print match 779 print(match['label']) 780 print(match['data']) 781 print("---------------")
782 #--------------------------------------------------------
783 - def test_fuzzy_picker():
784 app = wx.PyWidgetTester(size = (300, 40)) 785 app.SetWidget(cFuzzyTimestampInput, id=-1, size=(180,20), pos=(10,20)) 786 app.MainLoop()
787 #--------------------------------------------------------
788 - def test_picker():
789 app = wx.PyWidgetTester(size = (300, 40)) 790 app.SetWidget(cDateInputPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 791 app.MainLoop()
792 #-------------------------------------------------------- 793 #test_cli() 794 #test_fuzzy_picker() 795 test_picker() 796 797 #================================================== 798