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 notes = self._TCTRL_notes_street.GetValue().strip() 822 if notes != u'': 823 address['notes_street'] = notes 824 notes = self._TCTRL_notes_subunit.GetValue().strip() 825 if notes != u'': 826 address['notes_subunit'] = notes 827 address.save_payload() 828 829 self.__address = address 830 831 return True
832 #-------------------------------------------------------- 833 # event handling 834 #--------------------------------------------------------
835 - def __register_interests(self):
836 self._PRW_zip.add_callback_on_lose_focus(self._on_zip_set) 837 self._PRW_country.add_callback_on_lose_focus(self._on_country_set)
838 #--------------------------------------------------------
839 - def _on_zip_set(self):
840 """Set the street, town, state and country according to entered zip code.""" 841 zip_code = self._PRW_zip.GetValue() 842 if zip_code.strip() == u'': 843 self._PRW_street.unset_context(context = u'zip') 844 self._PRW_urb.unset_context(context = u'zip') 845 self._PRW_state.unset_context(context = u'zip') 846 self._PRW_country.unset_context(context = u'zip') 847 else: 848 self._PRW_street.set_context(context = u'zip', val = zip_code) 849 self._PRW_urb.set_context(context = u'zip', val = zip_code) 850 self._PRW_state.set_context(context = u'zip', val = zip_code) 851 self._PRW_country.set_context(context = u'zip', val = zip_code)
852 #--------------------------------------------------------
853 - def _on_country_set(self):
854 """Set the states according to entered country.""" 855 country = self._PRW_country.GetData() 856 if country is None: 857 self._PRW_state.unset_context(context = 'country') 858 else: 859 self._PRW_state.set_context(context = 'country', val = country)
860 #-------------------------------------------------------- 861 # internal helpers 862 #--------------------------------------------------------
863 - def __valid_for_save(self):
864 865 # validate required fields 866 is_any_field_filled = False 867 868 required_fields = [ 869 self._PRW_zip, 870 self._PRW_street, 871 self._TCTRL_number, 872 self._PRW_urb 873 ] 874 if self.__type_is_editable: 875 required_fields.insert(0, self._PRW_type) 876 877 for field in required_fields: 878 if len(field.GetValue().strip()) == 0: 879 if is_any_field_filled: 880 field.SetBackgroundColour('pink') 881 field.SetFocus() 882 field.Refresh() 883 gmGuiHelpers.gm_show_error ( 884 _('Address details must be filled in completely or not at all.'), 885 _('Saving contact data') 886 ) 887 return False 888 else: 889 is_any_field_filled = True 890 field.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 891 field.Refresh() 892 893 required_fields = ( 894 self._PRW_state, 895 self._PRW_country 896 ) 897 for field in required_fields: 898 if field.GetData() is None: 899 if is_any_field_filled: 900 field.SetBackgroundColour('pink') 901 field.SetFocus() 902 field.Refresh() 903 gmGuiHelpers.gm_show_error ( 904 _('Address details must be filled in completely or not at all.'), 905 _('Saving contact data') 906 ) 907 return False 908 else: 909 is_any_field_filled = True 910 field.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 911 field.Refresh() 912 913 return True
914 #-------------------------------------------------------- 915 # properties 916 #--------------------------------------------------------
917 - def _get_type_is_editable(self):
918 return self.__type_is_editable
919
920 - def _set_type_is_editable(self, type_is_editable):
921 self.__type_is_editable = type_is_editable 922 self._PRW_type.Enable(type_is_editable) 923 self._PRW_type.Show(type_is_editable) 924 self._LBL_type.Show(type_is_editable)
925 926 type_is_editable = property(_get_type_is_editable, _set_type_is_editable) 927 #--------------------------------------------------------
928 - def _get_address_is_searchable(self):
929 return self.__address_is_searchable
930
931 - def _set_address_is_searchable(self, address_is_searchable):
932 # always set tot FALSE when self.mode == 'new' 933 self.__address_is_searchable = address_is_searchable 934 self._PRW_address_searcher.Enable(address_is_searchable) 935 self._PRW_address_searcher.Show(address_is_searchable) 936 self._LBL_search.Show(address_is_searchable)
937 938 address_is_searchable = property(_get_address_is_searchable, _set_address_is_searchable) 939 #--------------------------------------------------------
940 - def _get_address(self):
941 return self.__address
942
943 - def _set_address(self, address):
944 self.__address = address 945 self.refresh()
946 947 address = property(_get_address, _set_address)
948 949 #============================================================
950 -class cAddressMatchProvider(gmMatchProvider.cMatchProvider_SQL2):
951
952 - def __init__(self):
953 954 query = u""" 955 SELECT * FROM ( 956 (SELECT 957 pk_address AS data, 958 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 959 || urb || coalesce(' (' || suburb || ')', '') || ', ' 960 || postcode || ', ' 961 || code_country 962 ) AS field_label, 963 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 964 || urb || coalesce(' (' || suburb || ')', '') || ', ' 965 || postcode || ', ' 966 || l10n_state || ', ' 967 || l10n_country 968 || coalesce(', ' || notes_street, '') 969 || coalesce(', ' || notes_subunit, '') 970 ) AS list_label 971 FROM 972 dem.v_address 973 WHERE 974 street %(fragment_condition)s 975 976 ) UNION ( 977 978 SELECT 979 pk_address AS data, 980 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 981 || urb || coalesce(' (' || suburb || ')', '') || ', ' 982 || postcode || ', ' 983 || code_country 984 ) AS field_label, 985 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 986 || urb || coalesce(' (' || suburb || ')', '') || ', ' 987 || postcode || ', ' 988 || l10n_state || ', ' 989 || l10n_country 990 || coalesce(', ' || notes_street, '') 991 || coalesce(', ' || notes_subunit, '') 992 ) AS list_label 993 FROM 994 dem.v_address 995 WHERE 996 postcode_street %(fragment_condition)s 997 998 ) UNION ( 999 1000 SELECT 1001 pk_address AS data, 1002 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1003 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1004 || postcode || ', ' 1005 || code_country 1006 ) AS field_label, 1007 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1008 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1009 || postcode || ', ' 1010 || l10n_state || ', ' 1011 || l10n_country 1012 || coalesce(', ' || notes_street, '') 1013 || coalesce(', ' || notes_subunit, '') 1014 ) AS list_label 1015 FROM 1016 dem.v_address 1017 WHERE 1018 postcode_urb %(fragment_condition)s 1019 ) 1020 ) AS matching_addresses 1021 ORDER BY list_label 1022 LIMIT 50""" 1023 1024 gmMatchProvider.cMatchProvider_SQL2.__init__(self, queries = query) 1025 1026 self.setThresholds(2, 4, 6) 1027 # self.word_separators = u'[ \t]+' 1028 1029 self._SQL_data2match = u""" 1030 SELECT 1031 pk_address AS data, 1032 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1033 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1034 || postcode || ', ' 1035 || code_country 1036 ) AS field_label, 1037 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1038 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1039 || postcode || ', ' 1040 || l10n_state || ', ' 1041 || l10n_country 1042 || coalesce(', ' || notes_street, '') 1043 || coalesce(', ' || notes_subunit, '') 1044 ) AS list_label 1045 FROM 1046 dem.v_address 1047 WHERE 1048 pk_address = %(pk)s 1049 """
1050 1051 #============================================================
1052 -class cAddressPhraseWheel(gmPhraseWheel.cPhraseWheel):
1053
1054 - def __init__(self, *args, **kwargs):
1055 1056 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1057 self.matcher = cAddressMatchProvider() 1058 self.SetToolTipString(_('Select an address by postcode or street name.')) 1059 self.selection_only = True 1060 self.__address = None 1061 self.__old_pk = None
1062 #--------------------------------------------------------
1063 - def _get_data_tooltip(self):
1064 adr = self.address 1065 if adr is None: 1066 return None 1067 return u'\n'.join(adr.format())
1068 #--------------------------------------------------------
1069 - def _data2instance(self):
1070 return gmDemographicRecord.cAddress(aPK_obj = self.GetData())
1071 #-------------------------------------------------------- 1072 # properties 1073 #--------------------------------------------------------
1074 - def __get_address(self):
1075 pk = self.GetData() 1076 if pk is None: 1077 self.__address = None 1078 return None 1079 if self.__address is None: 1080 self.__old_pk = pk 1081 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1082 else: 1083 if pk != self.__old_pk: 1084 self.__old_pk = pk 1085 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1086 return self.__address
1087
1088 - def __set_address(self, address):
1089 if address is None: 1090 self.__old_pk = None 1091 self.__address = None 1092 self.SetText(u'', None) 1093 return 1094 if isinstance(address, gmDemographicRecord.cAddress): 1095 self.__old_pk = address['pk_address'] 1096 self.__address = address 1097 pk = self.__old_pk 1098 else: 1099 self.__old_pk = None 1100 self.__address = None 1101 pk = address 1102 match = self.matcher.get_match_by_data(data = pk) 1103 if match is None: 1104 raise ValueError(u'[%s]: cannot match address [#%s]' % (self.__class__.__name__, pk)) 1105 self.SetText(match['field_label'], pk)
1106 1107 address = property(__get_address, __set_address) 1108 #--------------------------------------------------------
1109 - def __get_person_address(self):
1110 pk = self.GetData() 1111 if pk is None: 1112 self.__address = None 1113 return None 1114 if self.__address is None: 1115 self.__old_pk = pk 1116 self.__address = gmDemographicRecord.cPatientAddress(aPK_obj = pk) 1117 else: 1118 if pk != self.__old_pk: 1119 self.__old_pk = pk 1120 self.__address = gmDemographicRecord.cPatientAddress(aPK_obj = pk) 1121 return self.__address
1122 1123 person_address = property(__get_person_address, lambda x:x)
1124 #================================================================ 1125 # main 1126 #---------------------------------------------------------------- 1127 if __name__ == '__main__': 1128 1129 if len(sys.argv) < 2: 1130 sys.exit() 1131 1132 if sys.argv[1] != 'test': 1133 sys.exit() 1134 1135 from Gnumed.pycommon import gmI18N 1136 gmI18N.activate_locale() 1137 gmI18N.install_domain() 1138 from Gnumed.business import gmPersonSearch 1139 1140 #--------------------------------------------------------
1141 - def test_country_prw():
1142 app = wx.PyWidgetTester(size = (200, 50)) 1143 pw = cCountryPhraseWheel(app.frame, -1) 1144 app.frame.Show(True) 1145 app.MainLoop()
1146 #--------------------------------------------------------
1147 - def test_state_prw():
1148 app = wx.PyWidgetTester(size = (200, 50)) 1149 pw = cStateSelectionPhraseWheel(app.frame, -1) 1150 pw.set_context(context = u'zip', val = u'04318') 1151 pw.set_context(context = u'country', val = u'Deutschland') 1152 app.frame.Show(True) 1153 app.MainLoop()
1154 #--------------------------------------------------------
1155 - def test_zipcode_prw():
1156 app = wx.PyWidgetTester(size = (200, 50)) 1157 pw = cZipcodePhraseWheel(app.frame, -1) 1158 app.frame.Show(True) 1159 app.MainLoop()
1160 #--------------------------------------------------------
1161 - def test_street_prw():
1162 app = wx.PyWidgetTester(size = (200, 50)) 1163 pw = cStreetPhraseWheel(app.frame, -1) 1164 # pw.set_context(context = u'zip', val = u'04318') 1165 app.frame.Show(True) 1166 app.MainLoop()
1167 #--------------------------------------------------------
1168 - def test_suburb_prw():
1169 app = wx.PyWidgetTester(size = (200, 50)) 1170 pw = cSuburbPhraseWheel(app.frame, -1) 1171 app.frame.Show(True) 1172 app.MainLoop()
1173 #--------------------------------------------------------
1174 - def test_urb_prw():
1175 app = wx.PyWidgetTester(size = (200, 50)) 1176 pw = cUrbPhraseWheel(app.frame, -1) 1177 app.frame.Show(True) 1178 pw.set_context(context = u'zip', val = u'04317') 1179 app.MainLoop()
1180 #--------------------------------------------------------
1181 - def test_address_type_prw():
1182 app = wx.PyWidgetTester(size = (200, 50)) 1183 pw = cAddressTypePhraseWheel(app.frame, -1) 1184 app.frame.Show(True) 1185 app.MainLoop()
1186 #--------------------------------------------------------
1187 - def test_address_prw():
1188 app = wx.PyWidgetTester(size = (200, 50)) 1189 pw = cAddressPhraseWheel(app.frame, -1) 1190 app.frame.Show(True) 1191 app.MainLoop()
1192 #--------------------------------------------------------
1193 - def test_address_ea_pnl():
1194 app = wx.PyWidgetTester(size = (600, 400)) 1195 app.SetWidget(cAddressEditAreaPnl, address = gmDemographicRecord.cAddress(aPK_obj = 1)) 1196 app.MainLoop()
1197 #-------------------------------------------------------- 1198 #test_address_type_prw() 1199 #test_zipcode_prw() 1200 #test_state_prw() 1201 #test_street_prw() 1202 #test_suburb_prw() 1203 #test_country_prw() 1204 #test_urb_prw() 1205 #test_address_ea_pnl() 1206 test_address_prw() 1207 1208 #================================================================ 1209