Home | Trees | Indices | Help |
|
---|
|
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 __version__ = "$Revision: 1.66 $" 10 __author__ = "K. Hilbert <Karsten.Hilbert@gmx.net>" 11 __licence__ = "GPL v2 or later (details at http://www.gnu.org)" 12 13 # standard libary 14 import re, string, sys, time, datetime as pyDT, logging 15 16 17 # 3rd party 18 import mx.DateTime as mxDT 19 import wx 20 import wx.calendar 21 22 23 # GNUmed specific 24 if __name__ == '__main__': 25 sys.path.insert(0, '../../') 26 from Gnumed.pycommon import gmMatchProvider 27 from Gnumed.pycommon import gmDateTime 28 from Gnumed.pycommon import gmI18N 29 from Gnumed.wxpython import gmPhraseWheel 30 from Gnumed.wxpython import gmGuiHelpers 31 32 _log = logging.getLogger('gm.ui') 33 34 #============================================================ 35 #class cIntervalMatchProvider(gmMatchProvider.cMatchProvider): 36 # """Turns strings into candidate intervals.""" 37 # def __init__(self): 38 # 39 # gmMatchProvider.cMatchProvider.__init__(self) 40 # 41 # self.setThresholds(aPhrase = 1, aWord = 998, aSubstring = 999) 42 # self.word_separators = None 43 ## self.ignored_chars("""[?!."'\\(){}\[\]<>~#*$%^_]+""") 44 # #-------------------------------------------------------- 45 # # external API 46 # #-------------------------------------------------------- 47 # #-------------------------------------------------------- 48 # # base class API 49 # #-------------------------------------------------------- 50 # def getMatchesByPhrase(self, aFragment): 51 # intv = gmDateTime.str2interval(str_interval = aFragment) 52 # 53 # if intv is None: 54 # return (False, []) 55 # 56 # items = [{ 57 # 'data': intv, 58 # 'field_label': gmDateTime.format_interval(intv, gmDateTime.acc_minutes), 59 # 'list_label': gmDateTime.format_interval(intv, gmDateTime.acc_minutes) 60 # }] 61 # 62 # return (True, items) 63 # #-------------------------------------------------------- 64 # def getMatchesByWord(self, aFragment): 65 # return self.getMatchesByPhrase(aFragment) 66 # #-------------------------------------------------------- 67 # def getMatchesBySubstr(self, aFragment): 68 # return self.getMatchesByPhrase(aFragment) 69 # #-------------------------------------------------------- 70 # def getAllMatches(self): 71 # matches = (False, []) 72 # return matches 73 #============================================================75163 #============================================================77 78 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 79 self.phrase_separators = None 80 self.display_accuracy = None81 #-------------------------------------------------------- 82 # phrasewheel internal API 83 #--------------------------------------------------------85 intv = gmDateTime.str2interval(str_interval = val) 86 if intv is None: 87 self._current_match_candidates = [] 88 else: 89 self._current_match_candidates = [{ 90 'data': intv, 91 'field_label': gmDateTime.format_interval(intv, gmDateTime.acc_minutes), 92 'list_label': gmDateTime.format_interval(intv, gmDateTime.acc_minutes) 93 }] 94 self._picklist.SetItems(self._current_match_candidates)95 #--------------------------------------------------------- 96 # def _on_lose_focus(self, event): 97 # # are we valid ? 98 # if len(self._data) == 0: 99 # self._set_data_to_first_match() 100 # 101 # # let the base class do its thing 102 # super(cIntervalPhraseWheel, self)._on_lose_focus(event) 103 #--------------------------------------------------------105 intv = item['data'] 106 if intv is not None: 107 return gmDateTime.format_interval ( 108 interval = intv, 109 accuracy_wanted = self.display_accuracy 110 ) 111 return item['field_label']112 #--------------------------------------------------------114 intv = self.GetData() 115 print intv 116 if intv is None: 117 return u'' 118 return gmDateTime.format_interval ( 119 interval = intv, 120 accuracy_wanted = self.display_accuracy 121 )122 #-------------------------------------------------------- 123 # external API 124 #--------------------------------------------------------126 127 if isinstance(value, pyDT.timedelta): 128 self.SetText(data = value, suppress_smarts = True) 129 return 130 131 if value is None: 132 value = u'' 133 134 super(cIntervalPhraseWheel, self).SetValue(value)135 #--------------------------------------------------------137 138 if data is not None: 139 if value.strip() == u'': 140 value = gmDateTime.format_interval ( 141 interval = data, 142 accuracy_wanted = self.display_accuracy 143 ) 144 145 super(cIntervalPhraseWheel, self).SetText(value = value, data = data, suppress_smarts = suppress_smarts)146 #--------------------------------------------------------148 if data is None: 149 super(cIntervalPhraseWheel, self).SetText(u'', None) 150 return 151 152 value = gmDateTime.format_interval ( 153 interval = data, 154 accuracy_wanted = self.display_accuracy 155 ) 156 super(cIntervalPhraseWheel, self).SetText(value = value, data = data)157 #--------------------------------------------------------159 if len(self._data) == 0: 160 self._set_data_to_first_match() 161 162 return super(cIntervalPhraseWheel, self).GetData()165 """Shows a calendar control from which the user can pick a date."""211 212 #============================================================167 168 wx.Dialog.__init__(self, parent, title = _('Pick a date ...')) 169 panel = wx.Panel(self, -1) 170 171 sizer = wx.BoxSizer(wx.VERTICAL) 172 panel.SetSizer(sizer) 173 174 cal = wx.calendar.CalendarCtrl(panel) 175 176 if sys.platform != 'win32': 177 # gtk truncates the year - this fixes it 178 w, h = cal.Size 179 cal.Size = (w+25, h) 180 cal.MinSize = cal.Size 181 182 sizer.Add(cal, 0) 183 184 button_sizer = wx.BoxSizer(wx.HORIZONTAL) 185 button_sizer.Add((0, 0), 1) 186 btn_ok = wx.Button(panel, wx.ID_OK) 187 btn_ok.SetDefault() 188 button_sizer.Add(btn_ok, 0, wx.ALL, 2) 189 button_sizer.Add((0, 0), 1) 190 btn_can = wx.Button(panel, wx.ID_CANCEL) 191 button_sizer.Add(btn_can, 0, wx.ALL, 2) 192 button_sizer.Add((0, 0), 1) 193 sizer.Add(button_sizer, 1, wx.EXPAND | wx.ALL, 10) 194 sizer.Fit(panel) 195 self.ClientSize = panel.Size 196 197 cal.Bind(wx.EVT_KEY_DOWN, self.__on_key_down) 198 cal.SetFocus() 199 self.cal = cal200 #-----------------------------------------------------------214 """Turns strings into candidate dates. 215 216 Matching on "all" (*, '') will pop up a calendar :-) 217 """283 284 # # consider this: 285 # dlg = cCalendarDatePickerDlg(None) 286 # # FIXME: show below parent 287 # dlg.CentreOnScreen() 288 # 289 # if dlg.ShowModal() == wx.ID_OK: 290 # date = dlg.cal.Date 291 # if date is not None: 292 # if date.IsValid(): 293 # date = gmDateTime.wxDate2py_dt(wxDate = date).replace ( 294 # hour = 11, 295 # minute = 11, 296 # second = 11, 297 # microsecond = 111111 298 # ) 299 # lbl = gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 300 # matches = (True, [{'data': date, 'label': lbl}]) 301 # dlg.Destroy() 302 # 303 # return matches 304 #============================================================219 220 gmMatchProvider.cMatchProvider.__init__(self) 221 222 self.setThresholds(aPhrase = 1, aWord = 998, aSubstring = 999) 223 self.word_separators = None224 # self.ignored_chars("""[?!."'\\(){}\[\]<>~#*$%^_]+""") 225 #-------------------------------------------------------- 226 # external API 227 #-------------------------------------------------------- 228 #-------------------------------------------------------- 229 # base class API 230 #-------------------------------------------------------- 231 # internal matching algorithms 232 # 233 # if we end up here: 234 # - aFragment will not be "None" 235 # - aFragment will be lower case 236 # - we _do_ deliver matches (whether we find any is a different story) 237 #--------------------------------------------------------239 """Return matches for aFragment at start of phrases.""" 240 matches = gmDateTime.str2pydt_matches(str2parse = aFragment.strip()) 241 242 if len(matches) == 0: 243 return (False, []) 244 245 items = [] 246 for match in matches: 247 if match['data'] is None: 248 list_label = match['label'] 249 data = None 250 else: 251 data = match['data'].replace ( 252 hour = 11, 253 minute = 11, 254 second = 11, 255 microsecond = 111111 256 ) 257 list_label = gmDateTime.pydt_strftime ( 258 data, 259 format = '%A, %d. %B %Y (%x)', 260 accuracy = gmDateTime.acc_days 261 ) 262 items.append ({ 263 'data': data, 264 'field_label': match['label'], 265 'list_label': list_label 266 }) 267 268 return (True, items)269 #--------------------------------------------------------271 """Return matches for aFragment at start of words inside phrases.""" 272 return self.getMatchesByPhrase(aFragment)273 #--------------------------------------------------------275 """Return matches for aFragment as a true substring.""" 276 return self.getMatchesByPhrase(aFragment)277 #--------------------------------------------------------306492 #============================================================308 309 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 310 311 self.matcher = cDateMatchProvider() 312 self.phrase_separators = None 313 314 self.static_tooltip_extra = _('<ALT-C/K>: pick from (c/k)alendar')315 #-------------------------------------------------------- 316 # internal helpers 317 #-------------------------------------------------------- 318 # def __text2timestamp(self): 319 # 320 # self._update_candidates_in_picklist(val = self.GetValue().strip()) 321 # 322 # if len(self._current_match_candidates) == 1: 323 # return self._current_match_candidates[0]['data'] 324 # 325 # return None 326 #--------------------------------------------------------328 dlg = cCalendarDatePickerDlg(self) 329 # FIXME: show below parent 330 dlg.CentreOnScreen() 331 decision = dlg.ShowModal() 332 date = dlg.cal.Date 333 dlg.Destroy() 334 335 if decision != wx.ID_OK: 336 return 337 338 if date is None: 339 return 340 341 if not date.IsValid(): 342 return 343 344 date = gmDateTime.wxDate2py_dt(wxDate = date).replace ( 345 hour = 11, 346 minute = 11, 347 second = 11, 348 microsecond = 111111 349 ) 350 val = gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 351 self.SetText(value = val, data = date, suppress_smarts = True)352 #-------------------------------------------------------- 353 # phrasewheel internal API 354 #--------------------------------------------------------356 # are we valid ? 357 if len(self._data) == 0: 358 self._set_data_to_first_match() 359 360 # let the base class do its thing 361 super(cDateInputPhraseWheel, self)._on_lose_focus(event)362 #--------------------------------------------------------364 data = item['data'] 365 if data is not None: 366 return gmDateTime.pydt_strftime(data, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 367 return item['field_label']368 #--------------------------------------------------------370 371 # <ALT-C> / <ALT-K> -> calendar 372 if event.AltDown() is True: 373 char = unichr(event.GetUnicodeKey()) 374 if char in u'ckCK': 375 self.__pick_from_calendar() 376 return 377 378 super(cDateInputPhraseWheel, self)._on_key_down(event)379 #--------------------------------------------------------381 if len(self._data) == 0: 382 return u'' 383 384 date = self.GetData() 385 # if match provider only provided completions 386 # but not a full date with it 387 if date is None: 388 return u'' 389 390 return gmDateTime.pydt_strftime ( 391 date, 392 format = '%A, %d. %B %Y (%x)', 393 accuracy = gmDateTime.acc_days 394 )395 #-------------------------------------------------------- 396 # external API 397 #--------------------------------------------------------399 400 if isinstance(value, pyDT.datetime): 401 date = value.replace ( 402 hour = 11, 403 minute = 11, 404 second = 11, 405 microsecond = 111111 406 ) 407 self.SetText(data = date, suppress_smarts = True) 408 return 409 410 if value is None: 411 value = u'' 412 413 super(self.__class__, self).SetValue(value)414 #--------------------------------------------------------416 417 if data is not None: 418 if isinstance(data, gmDateTime.cFuzzyTimestamp): 419 data = data.timestamp.replace ( 420 hour = 11, 421 minute = 11, 422 second = 11, 423 microsecond = 111111 424 ) 425 if value.strip() == u'': 426 value = gmDateTime.pydt_strftime(data, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 427 428 super(self.__class__, self).SetText(value = value, data = data, suppress_smarts = suppress_smarts)429 #--------------------------------------------------------431 if data is None: 432 gmPhraseWheel.cPhraseWheel.SetText(self, u'', None) 433 else: 434 if isinstance(data, gmDateTime.cFuzzyTimestamp): 435 data = data.timestamp.replace ( 436 hour = 11, 437 minute = 11, 438 second = 11, 439 microsecond = 111111 440 ) 441 val = gmDateTime.pydt_strftime(data, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 442 super(self.__class__, self).SetText(value = val, data = data)443 #--------------------------------------------------------445 if len(self._data) == 0: 446 self._set_data_to_first_match() 447 448 return super(self.__class__, self).GetData()449 #--------------------------------------------------------451 if len(self._data) > 0: 452 self.display_as_valid(True) 453 return True 454 455 if self.GetValue().strip() == u'': 456 if allow_empty: 457 self.display_as_valid(True) 458 return True 459 else: 460 self.display_as_valid(False) 461 return False 462 463 # skip showing calendar on '*' from here 464 if self.GetValue().strip() == u'*': 465 self.display_as_valid(False) 466 return False 467 468 self._set_data_to_first_match() 469 if len(self._data) == 0: 470 self.display_as_valid(False) 471 return False 472 473 self.display_as_valid(True) 474 return True475 #-------------------------------------------------------- 476 # properties 477 #--------------------------------------------------------479 return self.GetData()480 483 # val = gmDateTime.pydt_strftime(date, format = '%Y-%m-%d', accuracy = gmDateTime.acc_days) 484 # self.data = date.replace ( 485 # hour = 11, 486 # minute = 11, 487 # second = 11, 488 # microsecond = 111111 489 # ) 490 491 date = property(_get_date, _set_date)553 #==================================================495 self.__allow_past = 1 496 self.__shifting_base = None 497 498 gmMatchProvider.cMatchProvider.__init__(self) 499 500 self.setThresholds(aPhrase = 1, aWord = 998, aSubstring = 999) 501 self.word_separators = None502 # self.ignored_chars("""[?!."'\\(){}\[\]<>~#*$%^_]+""") 503 #-------------------------------------------------------- 504 # external API 505 #-------------------------------------------------------- 506 #-------------------------------------------------------- 507 # base class API 508 #-------------------------------------------------------- 509 # internal matching algorithms 510 # 511 # if we end up here: 512 # - aFragment will not be "None" 513 # - aFragment will be lower case 514 # - we _do_ deliver matches (whether we find any is a different story) 515 #--------------------------------------------------------517 """Return matches for aFragment at start of phrases.""" 518 # self.__now = mxDT.now() 519 matches = gmDateTime.str2fuzzy_timestamp_matches(aFragment.strip()) 520 521 if len(matches) == 0: 522 return (False, []) 523 524 items = [] 525 for match in matches: 526 # if match['data'] is None: 527 # list_label = match['label'] 528 # else: 529 # list_label = gmDateTime.pydt_strftime ( 530 # match['data'].timestamp.format_accurately(), 531 # format = '%A, %d. %B %Y (%x)', 532 # accuracy = gmDateTime.acc_days 533 # ) 534 items.append ({ 535 'data': match['data'], 536 'field_label': match['label'], 537 'list_label': match['label'] 538 }) 539 540 return (True, items)541 #--------------------------------------------------------543 """Return matches for aFragment at start of words inside phrases.""" 544 return self.getMatchesByPhrase(aFragment)545 #--------------------------------------------------------547 """Return matches for aFragment as a true substring.""" 548 return self.getMatchesByPhrase(aFragment)549 #--------------------------------------------------------555628 #================================================== 629 # main 630 #-------------------------------------------------- 631 if __name__ == '__main__': 632 633 if len(sys.argv) < 2: 634 sys.exit() 635 636 if sys.argv[1] != 'test': 637 sys.exit() 638 639 gmI18N.activate_locale() 640 gmI18N.install_domain(domain='gnumed') 641 gmDateTime.init() 642 643 #----------------------------------------------------557 558 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 559 560 self.matcher = cMatchProvider_FuzzyTimestamp() 561 self.phrase_separators = None 562 self.selection_only = True 563 self.selection_only_error_msg = _('Cannot interpret input as timestamp.')564 #-------------------------------------------------------- 565 # internal helpers 566 #--------------------------------------------------------568 569 if val is None: 570 val = self.GetValue().strip() 571 572 success, matches = self.matcher.getMatchesByPhrase(val) 573 if len(matches) == 1: 574 return matches[0]['data'] 575 576 return None577 #-------------------------------------------------------- 578 # phrasewheel internal API 579 #--------------------------------------------------------581 # are we valid ? 582 if self.data is None: 583 # no, so try 584 self.data = self.__text2timestamp() 585 586 # let the base class do its thing 587 gmPhraseWheel.cPhraseWheel._on_lose_focus(self, event)588 #--------------------------------------------------------590 data = item['data'] 591 if data is not None: 592 return data.format_accurately() 593 return item['field_label']594 #-------------------------------------------------------- 595 # external API 596 #--------------------------------------------------------598 599 if data is not None: 600 if isinstance(data, pyDT.datetime): 601 data = gmDateTime.cFuzzyTimestamp(timestamp=data) 602 if value.strip() == u'': 603 value = data.format_accurately() 604 605 gmPhraseWheel.cPhraseWheel.SetText(self, value = value, data = data, suppress_smarts = suppress_smarts)606 #--------------------------------------------------------608 if data is None: 609 gmPhraseWheel.cPhraseWheel.SetText(self, u'', None) 610 else: 611 if isinstance(data, pyDT.datetime): 612 data = gmDateTime.cFuzzyTimestamp(timestamp=data) 613 gmPhraseWheel.cPhraseWheel.SetText(self, value = data.format_accurately(), data = data)614 #--------------------------------------------------------645 mp = cMatchProvider_FuzzyTimestamp() 646 mp.word_separators = None 647 mp.setThresholds(aWord = 998, aSubstring = 999) 648 val = None 649 while val != 'exit': 650 print "************************************" 651 val = raw_input('Enter date fragment ("exit" to quit): ') 652 found, matches = mp.getMatches(aFragment=val) 653 for match in matches: 654 #print match 655 print match['label'] 656 print match['data'] 657 print "---------------"658 #--------------------------------------------------------660 app = wx.PyWidgetTester(size = (300, 40)) 661 app.SetWidget(cFuzzyTimestampInput, id=-1, size=(180,20), pos=(10,20)) 662 app.MainLoop()663 #--------------------------------------------------------665 app = wx.PyWidgetTester(size = (300, 40)) 666 app.SetWidget(cDateInputPhraseWheel, id=-1, size=(180,20), pos=(10,20)) 667 app.MainLoop()668 #-------------------------------------------------------- 669 #test_cli() 670 test_fuzzy_picker() 671 #test_picker() 672 673 #================================================== 674
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Thu Jul 28 03:57:26 2011 | http://epydoc.sourceforge.net |