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

Source Code for Module Gnumed.wxpython.gmAddressWidgets

   1  """GNUmed generic address related widgets.""" 
   2  #================================================================ 
   3  __author__ = 'karsten.hilbert@gmx.net' 
   4  __license__ = 'GPL v2 or later (details at http://www.gnu.org)' 
   5   
   6  # stdlib 
   7  import logging, sys 
   8   
   9   
  10  # 3rd party 
  11  import wx 
  12   
  13   
  14  # GNUmed 
  15  if __name__ == '__main__': 
  16          sys.path.insert(0, '../../') 
  17   
  18  from Gnumed.pycommon import gmTools 
  19  from Gnumed.pycommon import gmMatchProvider 
  20  from Gnumed.business import gmDemographicRecord 
  21   
  22  from Gnumed.wxpython import gmCfgWidgets 
  23  from Gnumed.wxpython import gmPhraseWheel 
  24  from Gnumed.wxpython import gmListWidgets 
  25  from Gnumed.wxpython import gmEditArea 
  26  from Gnumed.wxpython import gmGuiHelpers 
  27   
  28   
  29  _log = logging.getLogger('gm.ui') 
  30  #============================================================ 
  31  # country related widgets / functions 
  32  #============================================================ 
33 -def configure_default_country(parent=None):
34 35 if parent is None: 36 parent = wx.GetApp().GetTopWindow() 37 38 countries = gmDemographicRecord.get_countries() 39 40 gmCfgWidgets.configure_string_from_list_option ( 41 parent = parent, 42 message = _('Select the default country for new persons.\n'), 43 option = 'person.create.default_country', 44 bias = 'user', 45 choices = [ (c['l10n_country'], c['code']) for c in countries ], 46 columns = [_('Country'), _('Code')], 47 data = [ c['code'] for c in countries ] 48 )
49 #============================================================
50 -class cCountryPhraseWheel(gmPhraseWheel.cPhraseWheel):
51
52 - def __init__(self, *args, **kwargs):
53 54 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 55 56 context = { 57 u'ctxt_zip': { 58 u'where_part': u'and zip ilike %(zip)s', 59 u'placeholder': u'zip' 60 } 61 } 62 query = u""" 63 SELECT 64 data, 65 field_label, 66 list_label 67 FROM ( 68 SELECT DISTINCT ON (data) 69 data, 70 field_label, 71 list_label, 72 rank 73 FROM ( 74 75 -- localized to user 76 SELECT 77 code_country AS data, 78 l10n_country AS field_label, 79 l10n_country || ' (' || code_country || '): ' || country AS list_label, 80 1 AS rank 81 FROM dem.v_zip2data 82 WHERE 83 l10n_country %(fragment_condition)s 84 %(ctxt_zip)s 85 UNION ALL 86 SELECT 87 code AS data, 88 _(name) AS field_label, 89 _(name) || ' (' || code || '): ' || name AS list_label, 90 2 AS rank 91 FROM dem.country 92 WHERE 93 _(name) %(fragment_condition)s 94 95 UNION ALL 96 97 -- non-localized 98 SELECT 99 code_country AS data, 100 l10n_country AS field_label, 101 country || ' (' || code_country || '): ' || l10n_country AS list_label, 102 3 AS rank 103 FROM dem.v_zip2data 104 WHERE 105 country %(fragment_condition)s 106 %(ctxt_zip)s 107 UNION ALL 108 SELECT 109 code AS data, 110 _(name) AS field_label, 111 name || ' (' || code || '): ' || _(name) AS list_label, 112 4 AS rank 113 FROM dem.country 114 WHERE 115 name %(fragment_condition)s 116 117 UNION ALL 118 119 -- abbreviation 120 SELECT 121 code AS data, 122 _(name) AS field_label, 123 code || ': ' || _(name) || ' (' || name || ')' AS list_label, 124 5 AS rank 125 FROM dem.country 126 WHERE 127 code %(fragment_condition)s 128 129 ) AS candidates 130 ) AS distint_candidates 131 ORDER BY rank, list_label 132 LIMIT 25""" 133 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=context) 134 mp._SQL_data2match = u""" 135 SELECT 136 code AS data, 137 _(name) AS field_label, 138 code || ': ' || _(name) || ' (' || name || ')' AS list_label, 139 5 AS rank 140 FROM dem.country 141 WHERE 142 code = %(pk)s 143 """ 144 mp.setThresholds(2, 5, 9) 145 self.matcher = mp 146 147 self.unset_context(context = u'zip') 148 self.SetToolTipString(_('Type or select a country.')) 149 self.capitalisation_mode = gmTools.CAPS_FIRST 150 self.selection_only = True
151 152 #============================================================ 153 # province/state related widgets / functions 154 #============================================================
155 -def configure_default_region(parent=None):
156 157 if parent is None: 158 parent = wx.GetApp().GetTopWindow() 159 160 provs = gmDemographicRecord.get_provinces() 161 162 gmCfgWidgets.configure_string_from_list_option ( 163 parent = parent, 164 message = _('Select the default region/province/state/territory for new persons.\n'), 165 option = 'person.create.default_region', 166 bias = 'user', 167 choices = [ (p['l10n_country'], p['l10n_state'], p['code_state']) for p in provs ], 168 columns = [_('Country'), _('Region'), _('Code')], 169 data = [ p['state'] for p in provs ] 170 )
171 #============================================================
172 -def edit_province(parent=None, province=None):
173 ea = cProvinceEAPnl(parent = parent, id = -1, province = province) 174 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (province is not None)) 175 dlg.SetTitle(gmTools.coalesce(province, _('Adding province'), _('Editing province'))) 176 result = dlg.ShowModal() 177 dlg.Destroy() 178 return (result == wx.ID_OK)
179 #============================================================
180 -def delete_province(parent=None, province=None):
181 182 msg = _( 183 'Are you sure you want to delete this province ?\n' 184 '\n' 185 'Deletion will only work if this province is not\n' 186 'yet in use in any patient addresses.' 187 ) 188 189 tt = _( 190 'Also delete any towns/cities/villages known\n' 191 'to be situated in this state as long as\n' 192 'no patients are recorded to live there.' 193 ) 194 195 dlg = gmGuiHelpers.c2ButtonQuestionDlg ( 196 parent, 197 -1, 198 caption = _('Deleting province'), 199 question = msg, 200 show_checkbox = True, 201 checkbox_msg = _('delete related townships'), 202 checkbox_tooltip = tt, 203 button_defs = [ 204 {'label': _('Yes, delete'), 'tooltip': _('Delete province and possibly related townships.'), 'default': False}, 205 {'label': _('No'), 'tooltip': _('No, do NOT delete anything.'), 'default': True} 206 ] 207 ) 208 209 decision = dlg.ShowModal() 210 if decision != wx.ID_YES: 211 dlg.Destroy() 212 return False 213 214 include_urbs = dlg.checkbox_is_checked() 215 dlg.Destroy() 216 217 return gmDemographicRecord.delete_province(province = province, delete_urbs = include_urbs)
218 #============================================================
219 -def manage_provinces(parent=None):
220 221 if parent is None: 222 parent = wx.GetApp().GetTopWindow() 223 224 #------------------------------------------------------------ 225 def delete(province=None): 226 return delete_province(parent = parent, province = province['pk_state'])
227 #------------------------------------------------------------ 228 def edit(province=None): 229 return edit_province(parent = parent, province = province) 230 #------------------------------------------------------------ 231 def refresh(lctrl): 232 wx.BeginBusyCursor() 233 provinces = gmDemographicRecord.get_provinces() 234 lctrl.set_string_items([ (p['l10n_country'], p['l10n_state']) for p in provinces ]) 235 lctrl.set_data(provinces) 236 wx.EndBusyCursor() 237 #------------------------------------------------------------ 238 msg = _( 239 '\n' 240 'This list shows the provinces known to GNUmed.\n' 241 '\n' 242 'In your jurisdiction "province" may correspond to either of "state",\n' 243 '"county", "region", "territory", or some such term.\n' 244 '\n' 245 'Select the province you want to edit !\n' 246 ) 247 248 gmListWidgets.get_choices_from_list ( 249 parent = parent, 250 msg = msg, 251 caption = _('Editing provinces ...'), 252 columns = [_('Country'), _('Province')], 253 single_selection = True, 254 new_callback = edit, 255 #edit_callback = edit, 256 delete_callback = delete, 257 refresh_callback = refresh 258 ) 259 #============================================================
260 -class cStateSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
261
262 - def __init__(self, *args, **kwargs):
263 264 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 265 266 context = { 267 u'ctxt_country_name': { 268 u'where_part': u'AND l10n_country ILIKE %(country_name)s OR country ILIKE %(country_name)s', 269 u'placeholder': u'country_name' 270 }, 271 u'ctxt_zip': { 272 u'where_part': u'AND zip ilike %(zip)s', 273 u'placeholder': u'zip' 274 }, 275 u'ctxt_country_code': { 276 u'where_part': u'AND country IN (SELECT code FROM dem.country WHERE _(name) ILIKE %(country_name)s OR name ILIKE %(country_name)s)', 277 u'placeholder': u'country_name' 278 } 279 } 280 281 query = u""" 282 SELECT 283 data, 284 field_label, 285 list_label 286 FROM ( 287 SELECT DISTINCT ON (field_label) 288 data, 289 field_label, 290 list_label, 291 rank 292 FROM ( 293 -- 1: find states based on name, context: zip and country name 294 SELECT 295 code_state AS data, 296 state AS field_label, 297 state || ' (' || code_state || '), ' || l10n_country || ' (' || code_country || ')' AS list_label, 298 1 AS rank 299 FROM dem.v_zip2data 300 WHERE 301 state %(fragment_condition)s 302 %(ctxt_country_name)s 303 %(ctxt_zip)s 304 305 UNION ALL 306 307 -- 2: find states based on code, context: zip and country name 308 SELECT 309 code_state AS data, 310 state AS field_label, 311 code_state || ': ' || state || ' (' || l10n_country || ', ' || code_country || ')' AS list_label, 312 2 AS rank 313 FROM dem.v_zip2data 314 WHERE 315 code_state %(fragment_condition)s 316 %(ctxt_country_name)s 317 %(ctxt_zip)s 318 319 UNION ALL 320 321 -- 3: find states based on name, context: country 322 SELECT 323 code AS data, 324 name AS field_label, 325 name || ' (' || code || '), ' || country AS list_label, 326 3 AS rank 327 FROM dem.state 328 WHERE 329 name %(fragment_condition)s 330 %(ctxt_country_code)s 331 332 UNION ALL 333 334 -- 4: find states based on code, context: country 335 SELECT 336 code AS data, 337 name AS field_label, 338 code || ': ' || name || ', ' || country AS list_label, 339 3 AS rank 340 FROM dem.state 341 WHERE 342 code %(fragment_condition)s 343 %(ctxt_country_code)s 344 345 ) AS candidate_states 346 ) AS distinct_matches 347 ORDER BY rank, list_label 348 LIMIT 50""" 349 350 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=context) 351 mp.setThresholds(2, 5, 6) 352 mp.word_separators = u'[ \t]+' 353 self.matcher = mp 354 355 self.unset_context(context = u'zip') 356 self.unset_context(context = u'country_name') 357 self.SetToolTipString(_('Type or select a state/region/province/territory.')) 358 self.capitalisation_mode = gmTools.CAPS_FIRST 359 self.selection_only = True
360 #==================================================================== 361 from Gnumed.wxGladeWidgets import wxgProvinceEAPnl 362
363 -class cProvinceEAPnl(wxgProvinceEAPnl.wxgProvinceEAPnl, gmEditArea.cGenericEditAreaMixin):
364
365 - def __init__(self, *args, **kwargs):
366 367 try: 368 data = kwargs['province'] 369 del kwargs['province'] 370 except KeyError: 371 data = None 372 373 wxgProvinceEAPnl.wxgProvinceEAPnl.__init__(self, *args, **kwargs) 374 gmEditArea.cGenericEditAreaMixin.__init__(self) 375 376 self.mode = 'new' 377 self.data = data 378 if data is not None: 379 self.mode = 'edit' 380 381 self.__init_ui()
382 #----------------------------------------------------------------
383 - def __init_ui(self):
384 self._PRW_province.selection_only = False
385 #---------------------------------------------------------------- 386 # generic Edit Area mixin API 387 #----------------------------------------------------------------
388 - def _valid_for_save(self):
389 390 validity = True 391 392 if self._PRW_province.GetData() is None: 393 if self._PRW_province.GetValue().strip() == u'': 394 validity = False 395 self._PRW_province.display_as_valid(False) 396 else: 397 self._PRW_province.display_as_valid(True) 398 else: 399 self._PRW_province.display_as_valid(True) 400 401 if self._PRW_province.GetData() is None: 402 if self._TCTRL_code.GetValue().strip() == u'': 403 validity = False 404 self._TCTRL_code.SetBackgroundColour(gmPhraseWheel.color_prw_invalid) 405 else: 406 self._TCTRL_code.SetBackgroundColour(gmPhraseWheel.color_prw_valid) 407 408 if self._PRW_country.GetData() is None: 409 validity = False 410 self._PRW_country.display_as_valid(False) 411 else: 412 self._PRW_country.display_as_valid(True) 413 414 return validity
415 #----------------------------------------------------------------
416 - def _save_as_new(self):
417 gmDemographicRecord.create_province ( 418 name = self._PRW_province.GetValue().strip(), 419 code = self._TCTRL_code.GetValue().strip(), 420 country = self._PRW_country.GetData() 421 ) 422 423 # EA is refreshed automatically after save, so need this ... 424 self.data = { 425 'l10n_state' : self._PRW_province.GetValue().strip(), 426 'code_state' : self._TCTRL_code.GetValue().strip(), 427 'l10n_country' : self._PRW_country.GetValue().strip(), 428 'code_country' : self._PRW_country.GetData().strip() 429 } 430 431 return True
432 #----------------------------------------------------------------
433 - def _save_as_update(self):
434 # update self.data and save the changes 435 #self.data[''] = 436 #self.data[''] = 437 #self.data[''] = 438 #self.data.save() 439 440 # do nothing for now (IOW, don't support updates) 441 return True
442 #----------------------------------------------------------------
443 - def _refresh_as_new(self):
444 self._PRW_province.SetText() 445 self._TCTRL_code.SetValue(u'') 446 self._PRW_country.SetText() 447 448 self._PRW_province.SetFocus()
449 #----------------------------------------------------------------
450 - def _refresh_from_existing(self):
451 self._PRW_province.SetText(self.data['l10n_state'], self.data['code_state']) 452 self._TCTRL_code.SetValue(self.data['code_state']) 453 self._PRW_country.SetText(self.data['l10n_country'], self.data['code_country']) 454 455 self._PRW_province.SetFocus()
456 #----------------------------------------------------------------
458 self._PRW_province.SetText() 459 self._TCTRL_code.SetValue(u'') 460 self._PRW_country.SetText(self.data['l10n_country'], self.data['code_country']) 461 462 self._PRW_province.SetFocus()
463 464 #============================================================ 465 # other address parts phrasewheels and widgets 466 #============================================================
467 -class cZipcodePhraseWheel(gmPhraseWheel.cPhraseWheel):
468
469 - def __init__(self, *args, **kwargs):
470 # FIXME: add possible context 471 query = u"""( 472 SELECT DISTINCT ON (list_label) 473 postcode AS data, 474 postcode || ' (' || name || ')' AS list_label, 475 postcode AS field_label 476 FROM dem.street 477 WHERE 478 postcode %(fragment_condition)s 479 ORDER BY list_label 480 LIMIT 20 481 482 ) UNION ( 483 484 SELECT DISTINCT ON (list_label) 485 postcode AS data, 486 postcode || ' (' || name || ')' AS list_label, 487 postcode AS field_label 488 FROM dem.urb 489 WHERE 490 postcode %(fragment_condition)s 491 ORDER BY list_label 492 LIMIT 20 493 )""" 494 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 495 mp.setThresholds(2, 3, 15) 496 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 497 self.SetToolTipString(_("Type or select a zip code (postcode).\n\nUse e.g. '?' if unknown.")) 498 self.matcher = mp
499 #============================================================
500 -class cStreetPhraseWheel(gmPhraseWheel.cPhraseWheel):
501
502 - def __init__(self, *args, **kwargs):
503 context = { 504 u'ctxt_zip': { 505 u'where_part': u'AND zip ILIKE %(zip)s', 506 u'placeholder': u'zip' 507 } 508 } 509 query = u""" 510 SELECT 511 data, 512 field_label, 513 list_label 514 FROM ( 515 516 SELECT DISTINCT ON (data) 517 street AS data, 518 street AS field_label, 519 street || ' (' || zip || ', ' || urb || coalesce(', ' || suburb, '') || ', ' || l10n_country || ')' AS list_label, 520 1 AS rank 521 FROM dem.v_zip2data 522 WHERE 523 street %(fragment_condition)s 524 %(ctxt_zip)s 525 526 UNION ALL 527 528 SELECT DISTINCT ON (data) 529 name AS data, 530 name AS field_label, 531 name || ' (' || postcode || coalesce(', ' || suburb, '') || ')' AS list_label, 532 2 AS rank 533 FROM dem.street 534 WHERE 535 name %(fragment_condition)s 536 537 ) AS matching_streets 538 ORDER BY rank, field_label 539 LIMIT 50""" 540 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=context) 541 mp.setThresholds(3, 5, 8) 542 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 543 self.unset_context(context = u'zip') 544 545 self.SetToolTipString(_('Type or select a street.')) 546 self.capitalisation_mode = gmTools.CAPS_FIRST 547 self.matcher = mp
548 #============================================================
549 -class cSuburbPhraseWheel(gmPhraseWheel.cPhraseWheel):
550
551 - def __init__(self, *args, **kwargs):
552 553 query = """ 554 SELECT DISTINCT ON (suburb) suburb, suburb 555 FROM dem.street 556 WHERE suburb %(fragment_condition)s 557 ORDER BY suburb 558 LIMIT 50 559 """ 560 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 561 mp.setThresholds(2, 3, 6) 562 gmPhraseWheel.cPhraseWheel.__init__ ( 563 self, 564 *args, 565 **kwargs 566 ) 567 568 self.SetToolTipString(_('Type or select the suburb.')) 569 self.capitalisation_mode = gmTools.CAPS_FIRST 570 self.matcher = mp
571 #============================================================
572 -class cUrbPhraseWheel(gmPhraseWheel.cPhraseWheel):
573
574 - def __init__(self, *args, **kwargs):
575 context = { 576 u'ctxt_zip': { 577 u'where_part': u'and zip ilike %(zip)s', 578 u'placeholder': u'zip' 579 } 580 } 581 query = u""" 582 SELECT DISTINCT ON (rank, data) 583 data, 584 field_label, 585 list_label 586 FROM ( 587 588 SELECT 589 urb AS data, 590 urb AS field_label, 591 urb || ' (' || zip || ', ' || state || ', ' || l10n_country || ')' AS list_label, 592 1 AS rank 593 FROM dem.v_zip2data 594 WHERE 595 urb %(fragment_condition)s 596 %(ctxt_zip)s 597 598 UNION ALL 599 600 SELECT 601 name AS data, 602 name AS field_label, 603 name || ' (' || postcode ||')' AS list_label, 604 2 AS rank 605 FROM dem.urb 606 WHERE 607 name %(fragment_condition)s 608 609 ) AS matching_urbs 610 ORDER BY rank, data 611 LIMIT 50""" 612 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=context) 613 mp.setThresholds(3, 5, 7) 614 gmPhraseWheel.cPhraseWheel.__init__ ( 615 self, 616 *args, 617 **kwargs 618 ) 619 self.unset_context(context = u'zip') 620 621 self.SetToolTipString(_('Type or select a city/town/village/dwelling.')) 622 self.capitalisation_mode = gmTools.CAPS_FIRST 623 self.matcher = mp
624 #============================================================ 625 # address type related widgets 626 #============================================================
627 -class cAddressTypePhraseWheel(gmPhraseWheel.cPhraseWheel):
628
629 - def __init__(self, *args, **kwargs):
630 631 query = u""" 632 SELECT id, type FROM (( 633 SELECT id, _(name) AS type, 1 AS rank 634 FROM dem.address_type 635 WHERE _(name) %(fragment_condition)s 636 ) UNION ( 637 SELECT id, name AS type, 2 AS rank 638 FROM dem.address_type 639 WHERE name %(fragment_condition)s 640 )) AS ur 641 order by 642 ur.rank, ur.type 643 """ 644 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 645 mp.setThresholds(1, 2, 4) 646 mp.word_separators = u'[ \t]+' 647 gmPhraseWheel.cPhraseWheel.__init__ ( 648 self, 649 *args, 650 **kwargs 651 ) 652 self.matcher = mp 653 self.SetToolTipString(_('Select the type of address.')) 654 # self.capitalisation_mode = gmTools.CAPS_FIRST 655 self.selection_only = True
656 #-------------------------------------------------------- 657 # def GetData(self, can_create=False): 658 # if self.data is None: 659 # if can_create: 660 # self.data = gmDocuments.create_document_type(self.GetValue().strip())['pk_doc_type'] # FIXME: error handling 661 # return self.data 662 663 #============================================================ 664 # address phrasewheels and widgets 665 #============================================================
666 -def manage_addresses(parent=None):
667 668 if parent is None: 669 parent = wx.GetApp().GetTopWindow() 670 671 #------------------------------------------------------------ 672 def calculate_tooltip(address): 673 return u'\n'.join(address.format())
674 #------------------------------------------------------------ 675 def delete(address): 676 return gmDemographicRecord.delete_address(pk_address = address['pk_address']) 677 #------------------------------------------------------------ 678 def refresh(lctrl): 679 adrs = gmDemographicRecord.get_addresses(order_by = u'l10n_country, urb, street, number, subunit') 680 items = [ [ 681 a['street'], 682 gmTools.coalesce(a['notes_street'], u''), 683 a['number'], 684 gmTools.coalesce(a['subunit'], u''), 685 a['postcode'], 686 a['urb'], 687 gmTools.coalesce(a['suburb'], u''), 688 a['l10n_state'], 689 a['l10n_country'], 690 gmTools.coalesce(a['notes_subunit'], u'') 691 ] for a in adrs 692 ] 693 lctrl.set_string_items(items) 694 lctrl.set_data(adrs) 695 696 #------------------------------------------------------------ 697 cols = [ 698 _('Street'), 699 _('Street info'), 700 _('Number'), 701 _('Subunit'), 702 _('Postal code'), 703 _('Community'), 704 _('Suburb'), 705 _('Region'), 706 _('Country'), 707 _('Comment') 708 ] 709 return gmListWidgets.get_choices_from_list ( 710 parent = parent, 711 caption = _('Showing addresses registered in GNUmed.'), 712 columns = cols, 713 single_selection = True, 714 refresh_callback = refresh, 715 delete_callback = delete, 716 list_tooltip_callback = calculate_tooltip 717 ) 718 #============================================================ 719 from Gnumed.wxGladeWidgets import wxgGenericAddressEditAreaPnl 720
721 -class cAddressEditAreaPnl(wxgGenericAddressEditAreaPnl.wxgGenericAddressEditAreaPnl):
722 """An edit area for editing/creating an address.""" 723
724 - def __init__(self, *args, **kwargs):
725 try: 726 self.__address = kwargs['address'] 727 del kwargs['address'] 728 except KeyError: 729 self.__address = None 730 731 wxgGenericAddressEditAreaPnl.wxgGenericAddressEditAreaPnl.__init__(self, *args, **kwargs) 732 733 self.address_holder = None 734 self.type_is_editable = True 735 self.address_is_searchable = False 736 737 self.__register_interests() 738 self.refresh()
739 #-------------------------------------------------------- 740 # external API 741 #--------------------------------------------------------
742 - def refresh(self, address = None):
743 if address is not None: 744 self.__address = address 745 746 if self.__address is None: 747 self._PRW_type.SetText(u'', None) 748 self._PRW_zip.SetText(u'', None) 749 self._PRW_street.SetText(u'', None) 750 self._TCTRL_notes_street.SetValue(u'') 751 self._TCTRL_number.SetValue(u'') 752 self._TCTRL_subunit.SetValue(u'') 753 self._PRW_suburb.SetText(u'', None) 754 self._PRW_urb.SetText(u'', None) 755 self._PRW_state.SetText(u'', None) 756 self._PRW_country.SetText(u'', None) 757 self._TCTRL_notes_subunit.SetValue(u'') 758 if self.__type_is_editable: 759 self._PRW_type.SetFocus() 760 else: 761 self._PRW_zip.SetFocus() 762 return 763 764 if self.__type_is_editable: 765 self._PRW_type.SetText(self.address['l10n_address_type']) 766 else: 767 self._PRW_type.SetText(u'', None) 768 self._PRW_zip.SetText(self.address['postcode']) 769 self._PRW_street.SetText(self.address['street'], data = self.address['street']) 770 self._TCTRL_notes_street.SetValue(gmTools.coalesce(self.address['notes_street'], '')) 771 self._TCTRL_number.SetValue(self.address['number']) 772 self._TCTRL_subunit.SetValue(gmTools.coalesce(self.address['subunit'], '')) 773 self._PRW_suburb.SetText(gmTools.coalesce(self.address['suburb'], '')) 774 self._PRW_urb.SetText(self.address['urb'], data = self.address['urb']) 775 self._PRW_state.SetText(self.address['l10n_state'], data = self.address['code_state']) 776 self._PRW_country.SetText(self.address['l10n_country'], data = self.address['code_country']) 777 self._TCTRL_notes_subunit.SetValue(gmTools.coalesce(self.address['notes_subunit'], '')) 778 779 if self.__type_is_editable: 780 self._PRW_type.SetFocus() 781 else: 782 self._PRW_zip.SetFocus() 783 return
784 #--------------------------------------------------------
785 - def save(self):
786 """Links address to patient or org, creating new address if necessary""" 787 788 if not self.__valid_for_save(): 789 return False 790 791 try: 792 address = gmDemographicRecord.create_address ( 793 country = self._PRW_country.GetData(), 794 state = self._PRW_state.GetData(), 795 urb = self._PRW_urb.GetValue().strip(), 796 suburb = gmTools.none_if(self._PRW_suburb.GetValue().strip(), u''), 797 postcode = self._PRW_zip.GetValue().strip(), 798 street = self._PRW_street.GetValue().strip(), 799 number = self._TCTRL_number.GetValue().strip(), 800 subunit = gmTools.none_if(self._TCTRL_subunit.GetValue().strip(), u'') 801 ) 802 except: 803 _log.exception('cannot save address') 804 gmGuiHelpers.gm_show_error ( 805 _('Cannot save address.\n\n' 806 'Does the state [%s]\n' 807 'exist in country [%s] ?' 808 ) % ( 809 self._PRW_state.GetValue().strip(), 810 self._PRW_country.GetValue().strip() 811 ), 812 _('Saving address') 813 ) 814 return False 815 816 # link address to owner 817 a = self.address_holder.link_address(id_type = self._PRW_type.GetData(), address = address) 818 if a['pk_address'] != address['pk_address']: 819 raise ValueError('problem linking address to person or org') 820 821 address['notes_street'] = gmTools.none_if(self._TCTRL_notes_street.GetValue().strip(), u'') 822 address['notes_subunit'] = gmTools.none_if(self._TCTRL_notes_subunit.GetValue().strip(), u'') 823 address.save_payload() 824 825 self.__address = address 826 827 return True
828 #-------------------------------------------------------- 829 # event handling 830 #--------------------------------------------------------
831 - def __register_interests(self):
832 self._PRW_zip.add_callback_on_lose_focus(self._on_zip_set) 833 self._PRW_country.add_callback_on_lose_focus(self._on_country_set)
834 #--------------------------------------------------------
835 - def _on_zip_set(self):
836 """Set the street, town, state and country according to entered zip code.""" 837 zip_code = self._PRW_zip.GetValue() 838 if zip_code.strip() == u'': 839 self._PRW_street.unset_context(context = u'zip') 840 self._PRW_urb.unset_context(context = u'zip') 841 self._PRW_state.unset_context(context = u'zip') 842 self._PRW_country.unset_context(context = u'zip') 843 else: 844 self._PRW_street.set_context(context = u'zip', val = zip_code) 845 self._PRW_urb.set_context(context = u'zip', val = zip_code) 846 self._PRW_state.set_context(context = u'zip', val = zip_code) 847 self._PRW_country.set_context(context = u'zip', val = zip_code)
848 #--------------------------------------------------------
849 - def _on_country_set(self):
850 """Set the states according to entered country.""" 851 country = self._PRW_country.GetData() 852 if country is None: 853 self._PRW_state.unset_context(context = 'country') 854 else: 855 self._PRW_state.set_context(context = 'country', val = country)
856 #-------------------------------------------------------- 857 # internal helpers 858 #--------------------------------------------------------
859 - def __valid_for_save(self):
860 861 # validate required fields 862 is_any_field_filled = False 863 864 required_fields = [ 865 self._PRW_zip, 866 self._PRW_street, 867 self._TCTRL_number, 868 self._PRW_urb 869 ] 870 if self.__type_is_editable: 871 required_fields.insert(0, self._PRW_type) 872 873 for field in required_fields: 874 if len(field.GetValue().strip()) == 0: 875 if is_any_field_filled: 876 field.SetBackgroundColour('pink') 877 field.SetFocus() 878 field.Refresh() 879 gmGuiHelpers.gm_show_error ( 880 _('Address details must be filled in completely or not at all.'), 881 _('Saving contact data') 882 ) 883 return False 884 else: 885 is_any_field_filled = True 886 field.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 887 field.Refresh() 888 889 required_fields = ( 890 self._PRW_state, 891 self._PRW_country 892 ) 893 for field in required_fields: 894 if field.GetData() is None: 895 if is_any_field_filled: 896 field.SetBackgroundColour('pink') 897 field.SetFocus() 898 field.Refresh() 899 gmGuiHelpers.gm_show_error ( 900 _('Address details must be filled in completely or not at all.'), 901 _('Saving contact data') 902 ) 903 return False 904 else: 905 is_any_field_filled = True 906 field.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 907 field.Refresh() 908 909 return True
910 #-------------------------------------------------------- 911 # properties 912 #--------------------------------------------------------
913 - def _get_type_is_editable(self):
914 return self.__type_is_editable
915
916 - def _set_type_is_editable(self, type_is_editable):
917 self.__type_is_editable = type_is_editable 918 self._PRW_type.Enable(type_is_editable) 919 self._PRW_type.Show(type_is_editable) 920 self._LBL_type.Show(type_is_editable)
921 922 type_is_editable = property(_get_type_is_editable, _set_type_is_editable) 923 #--------------------------------------------------------
924 - def _get_address_is_searchable(self):
925 return self.__address_is_searchable
926
927 - def _set_address_is_searchable(self, address_is_searchable):
928 # always set tot FALSE when self.mode == 'new' 929 self.__address_is_searchable = address_is_searchable 930 self._PRW_address_searcher.Enable(address_is_searchable) 931 self._PRW_address_searcher.Show(address_is_searchable) 932 self._LBL_search.Show(address_is_searchable)
933 934 address_is_searchable = property(_get_address_is_searchable, _set_address_is_searchable) 935 #--------------------------------------------------------
936 - def _get_address(self):
937 return self.__address
938
939 - def _set_address(self, address):
940 self.__address = address 941 self.refresh()
942 943 address = property(_get_address, _set_address)
944 945 #============================================================
946 -class cAddressMatchProvider(gmMatchProvider.cMatchProvider_SQL2):
947
948 - def __init__(self):
949 950 query = u""" 951 SELECT * FROM ( 952 (SELECT 953 pk_address AS data, 954 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 955 || urb || coalesce(' (' || suburb || ')', '') || ', ' 956 || postcode || ', ' 957 || code_country 958 ) AS field_label, 959 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 960 || urb || coalesce(' (' || suburb || ')', '') || ', ' 961 || postcode || ', ' 962 || l10n_state || ', ' 963 || l10n_country 964 || coalesce(', ' || notes_street, '') 965 || coalesce(', ' || notes_subunit, '') 966 ) AS list_label 967 FROM 968 dem.v_address 969 WHERE 970 street %(fragment_condition)s 971 972 ) UNION ( 973 974 SELECT 975 pk_address AS data, 976 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 977 || urb || coalesce(' (' || suburb || ')', '') || ', ' 978 || postcode || ', ' 979 || code_country 980 ) AS field_label, 981 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 982 || urb || coalesce(' (' || suburb || ')', '') || ', ' 983 || postcode || ', ' 984 || l10n_state || ', ' 985 || l10n_country 986 || coalesce(', ' || notes_street, '') 987 || coalesce(', ' || notes_subunit, '') 988 ) AS list_label 989 FROM 990 dem.v_address 991 WHERE 992 postcode_street %(fragment_condition)s 993 994 ) UNION ( 995 996 SELECT 997 pk_address AS data, 998 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 999 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1000 || postcode || ', ' 1001 || code_country 1002 ) AS field_label, 1003 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1004 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1005 || postcode || ', ' 1006 || l10n_state || ', ' 1007 || l10n_country 1008 || coalesce(', ' || notes_street, '') 1009 || coalesce(', ' || notes_subunit, '') 1010 ) AS list_label 1011 FROM 1012 dem.v_address 1013 WHERE 1014 postcode_urb %(fragment_condition)s 1015 ) 1016 ) AS matching_addresses 1017 ORDER BY list_label 1018 LIMIT 50""" 1019 1020 gmMatchProvider.cMatchProvider_SQL2.__init__(self, queries = query) 1021 1022 self.setThresholds(2, 4, 6) 1023 # self.word_separators = u'[ \t]+' 1024 1025 self._SQL_data2match = u""" 1026 SELECT 1027 pk_address AS data, 1028 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1029 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1030 || postcode || ', ' 1031 || code_country 1032 ) AS field_label, 1033 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1034 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1035 || postcode || ', ' 1036 || l10n_state || ', ' 1037 || l10n_country 1038 || coalesce(', ' || notes_street, '') 1039 || coalesce(', ' || notes_subunit, '') 1040 ) AS list_label 1041 FROM 1042 dem.v_address 1043 WHERE 1044 pk_address = %(pk)s 1045 """
1046 1047 #============================================================
1048 -class cAddressPhraseWheel(gmPhraseWheel.cPhraseWheel):
1049
1050 - def __init__(self, *args, **kwargs):
1051 1052 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1053 self.matcher = cAddressMatchProvider() 1054 self.SetToolTipString(_('Select an address by postcode or street name.')) 1055 self.selection_only = True 1056 self.__address = None 1057 self.__old_pk = None
1058 #--------------------------------------------------------
1059 - def _get_data_tooltip(self):
1060 adr = self.address 1061 if adr is None: 1062 return None 1063 return u'\n'.join(adr.format())
1064 #--------------------------------------------------------
1065 - def _data2instance(self):
1066 return gmDemographicRecord.cAddress(aPK_obj = self.GetData())
1067 #-------------------------------------------------------- 1068 # properties 1069 #--------------------------------------------------------
1070 - def __get_address(self):
1071 pk = self.GetData() 1072 if pk is None: 1073 self.__address = None 1074 return None 1075 if self.__address is None: 1076 self.__old_pk = pk 1077 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1078 else: 1079 if pk != self.__old_pk: 1080 self.__old_pk = pk 1081 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1082 return self.__address
1083
1084 - def __set_address(self, address):
1085 if address is None: 1086 self.__old_pk = None 1087 self.__address = None 1088 self.SetText(u'', None) 1089 return 1090 if isinstance(address, gmDemographicRecord.cAddress): 1091 self.__old_pk = address['pk_address'] 1092 self.__address = address 1093 pk = self.__old_pk 1094 else: 1095 self.__old_pk = None 1096 self.__address = None 1097 pk = address 1098 match = self.matcher.get_match_by_data(data = pk) 1099 if match is None: 1100 raise ValueError(u'[%s]: cannot match address [#%s]' % (self.__class__.__name__, pk)) 1101 self.SetText(match['field_label'], pk)
1102 1103 address = property(__get_address, __set_address) 1104 #--------------------------------------------------------
1105 - def __get_person_address(self):
1106 pk = self.GetData() 1107 if pk is None: 1108 self.__address = None 1109 return None 1110 if self.__address is None: 1111 self.__old_pk = pk 1112 self.__address = gmDemographicRecord.cPatientAddress(aPK_obj = pk) 1113 else: 1114 if pk != self.__old_pk: 1115 self.__old_pk = pk 1116 self.__address = gmDemographicRecord.cPatientAddress(aPK_obj = pk) 1117 return self.__address
1118 1119 person_address = property(__get_person_address, lambda x:x)
1120 #================================================================ 1121 # main 1122 #---------------------------------------------------------------- 1123 if __name__ == '__main__': 1124 1125 if len(sys.argv) < 2: 1126 sys.exit() 1127 1128 if sys.argv[1] != 'test': 1129 sys.exit() 1130 1131 from Gnumed.pycommon import gmI18N 1132 gmI18N.activate_locale() 1133 gmI18N.install_domain() 1134 from Gnumed.business import gmPersonSearch 1135 1136 #--------------------------------------------------------
1137 - def test_country_prw():
1138 app = wx.PyWidgetTester(size = (200, 50)) 1139 pw = cCountryPhraseWheel(app.frame, -1) 1140 app.frame.Show(True) 1141 app.MainLoop()
1142 #--------------------------------------------------------
1143 - def test_state_prw():
1144 app = wx.PyWidgetTester(size = (200, 50)) 1145 pw = cStateSelectionPhraseWheel(app.frame, -1) 1146 pw.set_context(context = u'zip', val = u'04318') 1147 pw.set_context(context = u'country', val = u'Deutschland') 1148 app.frame.Show(True) 1149 app.MainLoop()
1150 #--------------------------------------------------------
1151 - def test_zipcode_prw():
1152 app = wx.PyWidgetTester(size = (200, 50)) 1153 pw = cZipcodePhraseWheel(app.frame, -1) 1154 app.frame.Show(True) 1155 app.MainLoop()
1156 #--------------------------------------------------------
1157 - def test_street_prw():
1158 app = wx.PyWidgetTester(size = (200, 50)) 1159 pw = cStreetPhraseWheel(app.frame, -1) 1160 # pw.set_context(context = u'zip', val = u'04318') 1161 app.frame.Show(True) 1162 app.MainLoop()
1163 #--------------------------------------------------------
1164 - def test_suburb_prw():
1165 app = wx.PyWidgetTester(size = (200, 50)) 1166 pw = cSuburbPhraseWheel(app.frame, -1) 1167 app.frame.Show(True) 1168 app.MainLoop()
1169 #--------------------------------------------------------
1170 - def test_urb_prw():
1171 app = wx.PyWidgetTester(size = (200, 50)) 1172 pw = cUrbPhraseWheel(app.frame, -1) 1173 app.frame.Show(True) 1174 pw.set_context(context = u'zip', val = u'04317') 1175 app.MainLoop()
1176 #--------------------------------------------------------
1177 - def test_address_type_prw():
1178 app = wx.PyWidgetTester(size = (200, 50)) 1179 pw = cAddressTypePhraseWheel(app.frame, -1) 1180 app.frame.Show(True) 1181 app.MainLoop()
1182 #--------------------------------------------------------
1183 - def test_address_prw():
1184 app = wx.PyWidgetTester(size = (200, 50)) 1185 pw = cAddressPhraseWheel(app.frame, -1) 1186 app.frame.Show(True) 1187 app.MainLoop()
1188 #--------------------------------------------------------
1189 - def test_address_ea_pnl():
1190 app = wx.PyWidgetTester(size = (600, 400)) 1191 app.SetWidget(cAddressEditAreaPnl, address = gmDemographicRecord.cAddress(aPK_obj = 1)) 1192 app.MainLoop()
1193 #-------------------------------------------------------- 1194 #test_address_type_prw() 1195 #test_zipcode_prw() 1196 #test_state_prw() 1197 #test_street_prw() 1198 #test_suburb_prw() 1199 #test_country_prw() 1200 #test_urb_prw() 1201 #test_address_ea_pnl() 1202 test_address_prw() 1203 1204 #================================================================ 1205