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 } 429 430 return True
431 #----------------------------------------------------------------
432 - def _save_as_update(self):
433 # update self.data and save the changes 434 #self.data[''] = 435 #self.data[''] = 436 #self.data[''] = 437 #self.data.save() 438 439 # do nothing for now (IOW, don't support updates) 440 return True
441 #----------------------------------------------------------------
442 - def _refresh_as_new(self):
443 self._PRW_province.SetText() 444 self._TCTRL_code.SetValue(u'') 445 self._PRW_country.SetText() 446 447 self._PRW_province.SetFocus()
448 #----------------------------------------------------------------
449 - def _refresh_from_existing(self):
450 self._PRW_province.SetText(self.data['l10n_state'], self.data['code_state']) 451 self._TCTRL_code.SetValue(self.data['code_state']) 452 self._PRW_country.SetText(self.data['l10n_country'], self.data['code_country']) 453 454 self._PRW_province.SetFocus()
455 #----------------------------------------------------------------
457 self._PRW_province.SetText() 458 self._TCTRL_code.SetValue(u'') 459 self._PRW_country.SetText(self.data['l10n_country'], self.data['code_country']) 460 461 self._PRW_province.SetFocus()
462 463 #============================================================ 464 # other address parts phrasewheels and widgets 465 #============================================================
466 -class cZipcodePhraseWheel(gmPhraseWheel.cPhraseWheel):
467
468 - def __init__(self, *args, **kwargs):
469 # FIXME: add possible context 470 query = u""" 471 (SELECT distinct postcode, postcode FROM dem.street WHERE postcode %(fragment_condition)s limit 20) 472 UNION 473 (SELECT distinct postcode, postcode FROM dem.urb WHERE postcode %(fragment_condition)s limit 20)""" 474 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 475 mp.setThresholds(2, 3, 15) 476 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 477 self.SetToolTipString(_("Type or select a zip code (postcode).\n\nUse e.g. '?' if unknown.")) 478 self.matcher = mp
479 #============================================================
480 -class cStreetPhraseWheel(gmPhraseWheel.cPhraseWheel):
481
482 - def __init__(self, *args, **kwargs):
483 context = { 484 u'ctxt_zip': { 485 u'where_part': u'AND zip ILIKE %(zip)s', 486 u'placeholder': u'zip' 487 } 488 } 489 query = u""" 490 SELECT 491 data, 492 field_label, 493 list_label 494 FROM ( 495 496 SELECT DISTINCT ON (data) 497 street AS data, 498 street AS field_label, 499 street || ' (' || zip || ', ' || urb || coalesce(', ' || suburb, '') || ', ' || l10n_country || ')' AS list_label, 500 1 AS rank 501 FROM dem.v_zip2data 502 WHERE 503 street %(fragment_condition)s 504 %(ctxt_zip)s 505 506 UNION ALL 507 508 SELECT DISTINCT ON (data) 509 name AS data, 510 name AS field_label, 511 name || ' (' || postcode || coalesce(', ' || suburb, '') || ')' AS list_label, 512 2 AS rank 513 FROM dem.street 514 WHERE 515 name %(fragment_condition)s 516 517 ) AS matching_streets 518 ORDER BY rank, field_label 519 LIMIT 50""" 520 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=context) 521 mp.setThresholds(3, 5, 8) 522 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 523 self.unset_context(context = u'zip') 524 525 self.SetToolTipString(_('Type or select a street.')) 526 self.capitalisation_mode = gmTools.CAPS_FIRST 527 self.matcher = mp
528 #============================================================
529 -class cSuburbPhraseWheel(gmPhraseWheel.cPhraseWheel):
530
531 - def __init__(self, *args, **kwargs):
532 533 query = """ 534 SELECT DISTINCT ON (suburb) suburb, suburb 535 FROM dem.street 536 WHERE suburb %(fragment_condition)s 537 ORDER BY suburb 538 LIMIT 50 539 """ 540 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 541 mp.setThresholds(2, 3, 6) 542 gmPhraseWheel.cPhraseWheel.__init__ ( 543 self, 544 *args, 545 **kwargs 546 ) 547 548 self.SetToolTipString(_('Type or select the suburb.')) 549 self.capitalisation_mode = gmTools.CAPS_FIRST 550 self.matcher = mp
551 #============================================================
552 -class cUrbPhraseWheel(gmPhraseWheel.cPhraseWheel):
553
554 - def __init__(self, *args, **kwargs):
555 context = { 556 u'ctxt_zip': { 557 u'where_part': u'and zip ilike %(zip)s', 558 u'placeholder': u'zip' 559 } 560 } 561 query = u""" 562 SELECT DISTINCT ON (rank, data) 563 data, 564 field_label, 565 list_label 566 FROM ( 567 568 SELECT 569 urb AS data, 570 urb AS field_label, 571 urb || ' (' || zip || ', ' || state || ', ' || l10n_country || ')' AS list_label, 572 1 AS rank 573 FROM dem.v_zip2data 574 WHERE 575 urb %(fragment_condition)s 576 %(ctxt_zip)s 577 578 UNION ALL 579 580 SELECT 581 name AS data, 582 name AS field_label, 583 name || ' (' || postcode ||')' AS list_label, 584 2 AS rank 585 FROM dem.urb 586 WHERE 587 name %(fragment_condition)s 588 589 ) AS matching_urbs 590 ORDER BY rank, data 591 LIMIT 50""" 592 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=context) 593 mp.setThresholds(3, 5, 7) 594 gmPhraseWheel.cPhraseWheel.__init__ ( 595 self, 596 *args, 597 **kwargs 598 ) 599 self.unset_context(context = u'zip') 600 601 self.SetToolTipString(_('Type or select a city/town/village/dwelling.')) 602 self.capitalisation_mode = gmTools.CAPS_FIRST 603 self.matcher = mp
604 605 #============================================================ 606 # address phrasewheels and widgets 607 #============================================================
608 -def manage_addresses(parent=None):
609 610 if parent is None: 611 parent = wx.GetApp().GetTopWindow() 612 613 #------------------------------------------------------------ 614 def calculate_tooltip(address): 615 return u'\n'.join(address.format())
616 #------------------------------------------------------------ 617 def delete(address): 618 return gmDemographicRecord.delete_address(pk_address = address['pk_address']) 619 #------------------------------------------------------------ 620 def refresh(lctrl): 621 adrs = gmDemographicRecord.get_addresses(order_by = u'l10n_country, urb, street, number, subunit') 622 items = [ [ 623 a['street'], 624 gmTools.coalesce(a['notes_street'], u''), 625 a['number'], 626 gmTools.coalesce(a['subunit'], u''), 627 a['postcode'], 628 a['urb'], 629 gmTools.coalesce(a['suburb'], u''), 630 a['l10n_state'], 631 a['l10n_country'], 632 gmTools.coalesce(a['notes_subunit'], u'') 633 ] for a in adrs 634 ] 635 lctrl.set_string_items(items) 636 lctrl.set_data(adrs) 637 638 #------------------------------------------------------------ 639 cols = [ 640 _('Street'), 641 _('Street info'), 642 _('Number'), 643 _('Subunit'), 644 _('Postal code'), 645 _('Community'), 646 _('Suburb'), 647 _('Region'), 648 _('Country'), 649 _('Comment') 650 ] 651 return gmListWidgets.get_choices_from_list ( 652 parent = parent, 653 caption = _('Showing addresses registered in GNUmed.'), 654 columns = cols, 655 single_selection = True, 656 refresh_callback = refresh, 657 delete_callback = delete, 658 list_tooltip_callback = calculate_tooltip 659 ) 660 #============================================================ 661 from Gnumed.wxGladeWidgets import wxgGenericAddressEditAreaPnl 662
663 -class cAddressEditAreaPnl(wxgGenericAddressEditAreaPnl.wxgGenericAddressEditAreaPnl):
664 """An edit area for editing/creating an address.""" 665
666 - def __init__(self, *args, **kwargs):
667 try: 668 self.__address = kwargs['address'] 669 del kwargs['address'] 670 except KeyError: 671 self.__address = None 672 673 wxgGenericAddressEditAreaPnl.wxgGenericAddressEditAreaPnl.__init__(self, *args, **kwargs) 674 675 self.address_holder = None 676 self.type_is_editable = True 677 self.address_is_searchable = False 678 679 self.__register_interests() 680 self.refresh()
681 #-------------------------------------------------------- 682 # external API 683 #--------------------------------------------------------
684 - def refresh(self, address = None):
685 if address is not None: 686 self.__address = address 687 688 if self.__address is None: 689 self._PRW_type.SetText(u'', None) 690 self._PRW_zip.SetText(u'', None) 691 self._PRW_street.SetText(u'', None) 692 self._TCTRL_notes_street.SetValue(u'') 693 self._TCTRL_number.SetValue(u'') 694 self._TCTRL_subunit.SetValue(u'') 695 self._PRW_suburb.SetText(u'', None) 696 self._PRW_urb.SetText(u'', None) 697 self._PRW_state.SetText(u'', None) 698 self._PRW_country.SetText(u'', None) 699 self._TCTRL_notes_subunit.SetValue(u'') 700 if self.__type_is_editable: 701 self._PRW_type.SetFocus() 702 else: 703 self._PRW_zip.SetFocus() 704 return 705 706 if self.__type_is_editable: 707 self._PRW_type.SetText(self.address['l10n_address_type']) 708 else: 709 self._PRW_type.SetText(u'', None) 710 self._PRW_zip.SetText(self.address['postcode']) 711 self._PRW_street.SetText(self.address['street'], data = self.address['street']) 712 self._TCTRL_notes_street.SetValue(gmTools.coalesce(self.address['notes_street'], '')) 713 self._TCTRL_number.SetValue(self.address['number']) 714 self._TCTRL_subunit.SetValue(gmTools.coalesce(self.address['subunit'], '')) 715 self._PRW_suburb.SetText(gmTools.coalesce(self.address['suburb'], '')) 716 self._PRW_urb.SetText(self.address['urb'], data = self.address['urb']) 717 self._PRW_state.SetText(self.address['l10n_state'], data = self.address['code_state']) 718 self._PRW_country.SetText(self.address['l10n_country'], data = self.address['code_country']) 719 self._TCTRL_notes_subunit.SetValue(gmTools.coalesce(self.address['notes_subunit'], '')) 720 721 if self.__type_is_editable: 722 self._PRW_type.SetFocus() 723 else: 724 self._PRW_zip.SetFocus() 725 return
726 #--------------------------------------------------------
727 - def save(self):
728 """Links address to patient or org, creating new address if necessary""" 729 730 if not self.__valid_for_save(): 731 return False 732 733 try: 734 address = gmDemographicRecord.create_address ( 735 country = self._PRW_country.GetData(), 736 state = self._PRW_state.GetData(), 737 urb = self._PRW_urb.GetValue().strip(), 738 suburb = gmTools.none_if(self._PRW_suburb.GetValue().strip(), u''), 739 postcode = self._PRW_zip.GetValue().strip(), 740 street = self._PRW_street.GetValue().strip(), 741 number = self._TCTRL_number.GetValue().strip(), 742 subunit = gmTools.none_if(self._TCTRL_subunit.GetValue().strip(), u'') 743 ) 744 except: 745 _log.exception('cannot save address') 746 gmGuiHelpers.gm_show_error ( 747 _('Cannot save address.\n\n' 748 'Does the state [%s]\n' 749 'exist in country [%s] ?' 750 ) % ( 751 self._PRW_state.GetValue().strip(), 752 self._PRW_country.GetValue().strip() 753 ), 754 _('Saving address') 755 ) 756 return False 757 758 # link address to owner 759 a = self.address_holder.link_address(id_type = self._PRW_type.GetData(), address = address) 760 if a['pk_address'] != address['pk_address']: 761 raise ValueError('problem linking address to person or org') 762 763 notes = self._TCTRL_notes_street.GetValue().strip() 764 if notes != u'': 765 address['notes_street'] = notes 766 notes = self._TCTRL_notes_subunit.GetValue().strip() 767 if notes != u'': 768 address['notes_subunit'] = notes 769 address.save_payload() 770 771 self.__address = address 772 773 return True
774 #-------------------------------------------------------- 775 # event handling 776 #--------------------------------------------------------
777 - def __register_interests(self):
778 self._PRW_zip.add_callback_on_lose_focus(self._on_zip_set) 779 self._PRW_country.add_callback_on_lose_focus(self._on_country_set)
780 #--------------------------------------------------------
781 - def _on_zip_set(self):
782 """Set the street, town, state and country according to entered zip code.""" 783 zip_code = self._PRW_zip.GetValue() 784 if zip_code.strip() == u'': 785 self._PRW_street.unset_context(context = u'zip') 786 self._PRW_urb.unset_context(context = u'zip') 787 self._PRW_state.unset_context(context = u'zip') 788 self._PRW_country.unset_context(context = u'zip') 789 else: 790 self._PRW_street.set_context(context = u'zip', val = zip_code) 791 self._PRW_urb.set_context(context = u'zip', val = zip_code) 792 self._PRW_state.set_context(context = u'zip', val = zip_code) 793 self._PRW_country.set_context(context = u'zip', val = zip_code)
794 #--------------------------------------------------------
795 - def _on_country_set(self):
796 """Set the states according to entered country.""" 797 country = self._PRW_country.GetData() 798 if country is None: 799 self._PRW_state.unset_context(context = 'country') 800 else: 801 self._PRW_state.set_context(context = 'country', val = country)
802 #-------------------------------------------------------- 803 # internal helpers 804 #--------------------------------------------------------
805 - def __valid_for_save(self):
806 807 # validate required fields 808 is_any_field_filled = False 809 810 required_fields = [ 811 self._PRW_zip, 812 self._PRW_street, 813 self._TCTRL_number, 814 self._PRW_urb 815 ] 816 if self.__type_is_editable: 817 required_fields.insert(0, self._PRW_type) 818 819 for field in required_fields: 820 if len(field.GetValue().strip()) == 0: 821 if is_any_field_filled: 822 field.SetBackgroundColour('pink') 823 field.SetFocus() 824 field.Refresh() 825 gmGuiHelpers.gm_show_error ( 826 _('Address details must be filled in completely or not at all.'), 827 _('Saving contact data') 828 ) 829 return False 830 else: 831 is_any_field_filled = True 832 field.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 833 field.Refresh() 834 835 required_fields = ( 836 self._PRW_state, 837 self._PRW_country 838 ) 839 for field in required_fields: 840 if field.GetData() is None: 841 if is_any_field_filled: 842 field.SetBackgroundColour('pink') 843 field.SetFocus() 844 field.Refresh() 845 gmGuiHelpers.gm_show_error ( 846 _('Address details must be filled in completely or not at all.'), 847 _('Saving contact data') 848 ) 849 return False 850 else: 851 is_any_field_filled = True 852 field.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) 853 field.Refresh() 854 855 return True
856 #-------------------------------------------------------- 857 # properties 858 #--------------------------------------------------------
859 - def _get_type_is_editable(self):
860 return self.__type_is_editable
861
862 - def _set_type_is_editable(self, type_is_editable):
863 self.__type_is_editable = type_is_editable 864 self._PRW_type.Enable(type_is_editable) 865 self._PRW_type.Show(type_is_editable) 866 self._LBL_type.Show(type_is_editable)
867 868 type_is_editable = property(_get_type_is_editable, _set_type_is_editable) 869 #--------------------------------------------------------
870 - def _get_address_is_searchable(self):
871 return self.__address_is_searchable
872
873 - def _set_address_is_searchable(self, address_is_searchable):
874 # always set tot FALSE when self.mode == 'new' 875 self.__address_is_searchable = address_is_searchable 876 self._PRW_address_searcher.Enable(address_is_searchable) 877 self._PRW_address_searcher.Show(address_is_searchable) 878 self._LBL_search.Show(address_is_searchable)
879 880 address_is_searchable = property(_get_address_is_searchable, _set_address_is_searchable) 881 #--------------------------------------------------------
882 - def _get_address(self):
883 return self.__address
884
885 - def _set_address(self, address):
886 self.__address = address 887 self.refresh()
888 889 address = property(_get_address, _set_address)
890 891 #============================================================
892 -class cAddressTypePhraseWheel(gmPhraseWheel.cPhraseWheel):
893
894 - def __init__(self, *args, **kwargs):
895 896 query = u""" 897 SELECT id, type FROM (( 898 SELECT id, _(name) AS type, 1 AS rank 899 FROM dem.address_type 900 WHERE _(name) %(fragment_condition)s 901 ) UNION ( 902 SELECT id, name AS type, 2 AS rank 903 FROM dem.address_type 904 WHERE name %(fragment_condition)s 905 )) AS ur 906 order by 907 ur.rank, ur.type 908 """ 909 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 910 mp.setThresholds(1, 2, 4) 911 mp.word_separators = u'[ \t]+' 912 gmPhraseWheel.cPhraseWheel.__init__ ( 913 self, 914 *args, 915 **kwargs 916 ) 917 self.matcher = mp 918 self.SetToolTipString(_('Select the type of address.')) 919 # self.capitalisation_mode = gmTools.CAPS_FIRST 920 self.selection_only = True
921 #-------------------------------------------------------- 922 # def GetData(self, can_create=False): 923 # if self.data is None: 924 # if can_create: 925 # self.data = gmDocuments.create_document_type(self.GetValue().strip())['pk_doc_type'] # FIXME: error handling 926 # return self.data 927 928 #============================================================
929 -class cAddressMatchProvider(gmMatchProvider.cMatchProvider_SQL2):
930
931 - def __init__(self):
932 933 query = u""" 934 SELECT * FROM ( 935 (SELECT 936 pk_address AS data, 937 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 938 || urb || coalesce(' (' || suburb || ')', '') || ', ' 939 || postcode || ', ' 940 || code_country 941 ) AS field_label, 942 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 943 || urb || coalesce(' (' || suburb || ')', '') || ', ' 944 || postcode || ', ' 945 || l10n_state || ', ' 946 || l10n_country 947 || coalesce(', ' || notes_street, '') 948 || coalesce(', ' || notes_subunit, '') 949 ) AS list_label 950 FROM 951 dem.v_address 952 WHERE 953 street %(fragment_condition)s 954 955 ) UNION ( 956 957 SELECT 958 pk_address AS data, 959 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 960 || urb || coalesce(' (' || suburb || ')', '') || ', ' 961 || postcode || ', ' 962 || code_country 963 ) AS field_label, 964 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 965 || urb || coalesce(' (' || suburb || ')', '') || ', ' 966 || postcode || ', ' 967 || l10n_state || ', ' 968 || l10n_country 969 || coalesce(', ' || notes_street, '') 970 || coalesce(', ' || notes_subunit, '') 971 ) AS list_label 972 FROM 973 dem.v_address 974 WHERE 975 postcode_street %(fragment_condition)s 976 977 ) UNION ( 978 979 SELECT 980 pk_address AS data, 981 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 982 || urb || coalesce(' (' || suburb || ')', '') || ', ' 983 || postcode || ', ' 984 || code_country 985 ) AS field_label, 986 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 987 || urb || coalesce(' (' || suburb || ')', '') || ', ' 988 || postcode || ', ' 989 || l10n_state || ', ' 990 || l10n_country 991 || coalesce(', ' || notes_street, '') 992 || coalesce(', ' || notes_subunit, '') 993 ) AS list_label 994 FROM 995 dem.v_address 996 WHERE 997 postcode_urb %(fragment_condition)s 998 ) 999 ) AS matching_addresses 1000 ORDER BY list_label 1001 LIMIT 50""" 1002 1003 gmMatchProvider.cMatchProvider_SQL2.__init__(self, queries = query) 1004 1005 self.setThresholds(2, 4, 6) 1006 # self.word_separators = u'[ \t]+' 1007 1008 self._SQL_data2match = u""" 1009 SELECT 1010 pk_address AS data, 1011 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1012 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1013 || postcode || ', ' 1014 || code_country 1015 ) AS field_label, 1016 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1017 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1018 || postcode || ', ' 1019 || l10n_state || ', ' 1020 || l10n_country 1021 || coalesce(', ' || notes_street, '') 1022 || coalesce(', ' || notes_subunit, '') 1023 ) AS list_label 1024 FROM 1025 dem.v_address 1026 WHERE 1027 pk_address = %(pk)s 1028 """
1029 1030 #============================================================
1031 -class cAddressPhraseWheel(gmPhraseWheel.cPhraseWheel):
1032
1033 - def __init__(self, *args, **kwargs):
1034 1035 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1036 self.matcher = cAddressMatchProvider() 1037 self.SetToolTipString(_('Select an address by postcode or street name.')) 1038 self.selection_only = True 1039 self.__address = None 1040 self.__old_pk = None
1041 #--------------------------------------------------------
1042 - def _get_data_tooltip(self):
1043 adr = self.address 1044 if adr is None: 1045 return None 1046 return u'\n'.join(adr.format())
1047 #--------------------------------------------------------
1048 - def _data2instance(self):
1049 return gmDemographicRecord.cAddress(aPK_obj = self.GetData())
1050 #-------------------------------------------------------- 1051 # properties 1052 #--------------------------------------------------------
1053 - def __get_address(self):
1054 pk = self.GetData() 1055 if pk is None: 1056 self.__address = None 1057 return None 1058 if self.__address is None: 1059 self.__old_pk = pk 1060 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1061 else: 1062 if pk != self.__old_pk: 1063 self.__old_pk = pk 1064 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1065 return self.__address
1066
1067 - def __set_address(self, address):
1068 if address is None: 1069 self.__old_pk = None 1070 self.__address = None 1071 self.SetText(u'', None) 1072 return 1073 if isinstance(address, gmDemographicRecord.cAddress): 1074 self.__old_pk = address['pk_address'] 1075 self.__address = address 1076 pk = self.__old_pk 1077 else: 1078 self.__old_pk = None 1079 self.__address = None 1080 pk = address 1081 match = self.matcher.get_match_by_data(data = pk) 1082 if match is None: 1083 raise ValueError(u'[%s]: cannot match address [#%s]' % (self.__class__.__name__, pk)) 1084 self.SetText(match['field_label'], pk)
1085 1086 address = property(__get_address, __set_address)
1087 1088 #================================================================ 1089 # main 1090 #---------------------------------------------------------------- 1091 if __name__ == '__main__': 1092 1093 if len(sys.argv) < 2: 1094 sys.exit() 1095 1096 if sys.argv[1] != 'test': 1097 sys.exit() 1098 1099 from Gnumed.pycommon import gmI18N 1100 gmI18N.activate_locale() 1101 gmI18N.install_domain() 1102 from Gnumed.business import gmPersonSearch 1103 1104 #--------------------------------------------------------
1105 - def test_country_prw():
1106 app = wx.PyWidgetTester(size = (200, 50)) 1107 pw = cCountryPhraseWheel(app.frame, -1) 1108 app.frame.Show(True) 1109 app.MainLoop()
1110 #--------------------------------------------------------
1111 - def test_state_prw():
1112 app = wx.PyWidgetTester(size = (200, 50)) 1113 pw = cStateSelectionPhraseWheel(app.frame, -1) 1114 pw.set_context(context = u'zip', val = u'04318') 1115 pw.set_context(context = u'country', val = u'Deutschland') 1116 app.frame.Show(True) 1117 app.MainLoop()
1118 #--------------------------------------------------------
1119 - def test_zipcode_prw():
1120 app = wx.PyWidgetTester(size = (200, 50)) 1121 pw = cZipcodePhraseWheel(app.frame, -1) 1122 app.frame.Show(True) 1123 app.MainLoop()
1124 #--------------------------------------------------------
1125 - def test_street_prw():
1126 app = wx.PyWidgetTester(size = (200, 50)) 1127 pw = cStreetPhraseWheel(app.frame, -1) 1128 # pw.set_context(context = u'zip', val = u'04318') 1129 app.frame.Show(True) 1130 app.MainLoop()
1131 #--------------------------------------------------------
1132 - def test_suburb_prw():
1133 app = wx.PyWidgetTester(size = (200, 50)) 1134 pw = cSuburbPhraseWheel(app.frame, -1) 1135 app.frame.Show(True) 1136 app.MainLoop()
1137 #--------------------------------------------------------
1138 - def test_urb_prw():
1139 app = wx.PyWidgetTester(size = (200, 50)) 1140 pw = cUrbPhraseWheel(app.frame, -1) 1141 app.frame.Show(True) 1142 pw.set_context(context = u'zip', val = u'04317') 1143 app.MainLoop()
1144 #--------------------------------------------------------
1145 - def test_address_type_prw():
1146 app = wx.PyWidgetTester(size = (200, 50)) 1147 pw = cAddressTypePhraseWheel(app.frame, -1) 1148 app.frame.Show(True) 1149 app.MainLoop()
1150 #--------------------------------------------------------
1151 - def test_address_prw():
1152 app = wx.PyWidgetTester(size = (200, 50)) 1153 pw = cAddressPhraseWheel(app.frame, -1) 1154 app.frame.Show(True) 1155 app.MainLoop()
1156 #--------------------------------------------------------
1157 - def test_address_ea_pnl():
1158 app = wx.PyWidgetTester(size = (600, 400)) 1159 app.SetWidget(cAddressEditAreaPnl, address = gmDemographicRecord.cAddress(aPK_obj = 1)) 1160 app.MainLoop()
1161 #-------------------------------------------------------- 1162 #test_address_type_prw() 1163 #test_zipcode_prw() 1164 #test_state_prw() 1165 #test_street_prw() 1166 #test_suburb_prw() 1167 #test_country_prw() 1168 #test_urb_prw() 1169 #test_address_ea_pnl() 1170 test_address_prw() 1171 1172 #================================================================ 1173