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 #============================================================ 720 from Gnumed.wxGladeWidgets import wxgGenericAddressEditAreaPnl 721
722 -class cAddressEAPnl(wxgGenericAddressEditAreaPnl.wxgGenericAddressEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
723
724 - def __init__(self, *args, **kwargs):
725 726 try: 727 data = kwargs['address'] 728 del kwargs['address'] 729 except KeyError: 730 data = None 731 732 self.address_holder = None 733 self.__type_is_editable = True 734 self.__address_is_searchable = False 735 736 wxgGenericAddressEditAreaPnl.wxgGenericAddressEditAreaPnl.__init__(self, *args, **kwargs) 737 gmEditArea.cGenericEditAreaMixin.__init__(self) 738 739 self.type_is_editable = True 740 self.address_is_searchable = False 741 742 # Code using this mixin should set mode and data 743 # after instantiating the class: 744 self.mode = 'new' 745 self.data = data 746 if data is not None: 747 self.mode = 'edit' 748 749 self.__init_ui()
750 #----------------------------------------------------------------
751 - def __init_ui(self):
752 self._PRW_zip.add_callback_on_lose_focus(self._on_zip_set) 753 self._PRW_country.add_callback_on_lose_focus(self._on_country_set)
754 #---------------------------------------------------------------- 755 # generic Edit Area mixin API 756 #----------------------------------------------------------------
757 - def _valid_for_save(self):
758 759 validity = True 760 761 # if any field is filled, all must be filled, so track that 762 is_any_field_filled = False 763 764 # check by string 765 required_fields = [ 766 self._PRW_urb, 767 self._TCTRL_number, 768 self._PRW_street, 769 self._PRW_zip 770 ] 771 if self.__type_is_editable: 772 required_fields.insert(0, self._PRW_type) 773 for field in required_fields: 774 if len(field.GetValue().strip()) == 0: 775 if is_any_field_filled: 776 self.display_ctrl_as_valid(field, False) 777 field.SetFocus() 778 gmGuiHelpers.gm_show_error ( 779 _('Address details must be filled in completely or not at all.'), 780 _('Saving contact data') 781 ) 782 validity = False 783 else: 784 is_any_field_filled = True 785 self.display_ctrl_as_valid(field, True) 786 787 # check by data 788 required_fields = ( 789 self._PRW_country, 790 self._PRW_state 791 ) 792 for field in required_fields: 793 if field.GetData() is None: 794 if is_any_field_filled: 795 self.display_ctrl_as_valid(field, False) 796 field.SetFocus() 797 gmGuiHelpers.gm_show_error ( 798 _('Address details must be filled in completely or not at all.'), 799 _('Saving contact data') 800 ) 801 validity = False 802 else: 803 is_any_field_filled = True 804 self.display_ctrl_as_valid(field, True) 805 806 return validity
807 #----------------------------------------------------------------
808 - def _save_as_new(self):
809 try: 810 # will create or return address 811 address = gmDemographicRecord.create_address ( 812 country = self._PRW_country.GetData(), 813 state = self._PRW_state.GetData(), 814 urb = self._PRW_urb.GetValue().strip(), 815 suburb = gmTools.none_if(self._PRW_suburb.GetValue().strip(), u''), 816 postcode = self._PRW_zip.GetValue().strip(), 817 street = self._PRW_street.GetValue().strip(), 818 number = self._TCTRL_number.GetValue().strip(), 819 subunit = gmTools.none_if(self._TCTRL_subunit.GetValue().strip(), u'') 820 ) 821 except: 822 _log.exception('cannot save address') 823 gmGuiHelpers.gm_show_error ( 824 _('Cannot save address.\n\n' 825 'Does the state [%s]\n' 826 'exist in country [%s] ?' 827 ) % ( 828 self._PRW_state.GetValue().strip(), 829 self._PRW_country.GetValue().strip() 830 ), 831 _('Saving address') 832 ) 833 return False 834 835 # link address to holder (there better be one) 836 linked_address = self.address_holder.link_address(id_type = self._PRW_type.GetData(), address = address) 837 if linked_address['pk_address'] != address['pk_address']: 838 raise ValueError('problem linking address to person or org') 839 840 address['notes_street'] = gmTools.none_if(self._TCTRL_notes_street.GetValue().strip(), u'') 841 address['notes_subunit'] = gmTools.none_if(self._TCTRL_notes_subunit.GetValue().strip(), u'') 842 address.save() 843 844 linked_address.refetch_payload() 845 self.data = linked_address 846 847 return True
848 #----------------------------------------------------------------
849 - def _save_as_update(self):
850 # do not update existing address, rather 851 # create new one or get corresponding 852 # address should it exist 853 try: 854 address = gmDemographicRecord.create_address ( 855 country = self._PRW_country.GetData(), 856 state = self._PRW_state.GetData(), 857 urb = self._PRW_urb.GetValue().strip(), 858 suburb = gmTools.none_if(self._PRW_suburb.GetValue().strip(), u''), 859 postcode = self._PRW_zip.GetValue().strip(), 860 street = self._PRW_street.GetValue().strip(), 861 number = self._TCTRL_number.GetValue().strip(), 862 subunit = gmTools.none_if(self._TCTRL_subunit.GetValue().strip(), u'') 863 ) 864 except: 865 _log.exception('cannot save address') 866 gmGuiHelpers.gm_show_error ( 867 _('Cannot save address.\n\n' 868 'Does the state [%s]\n' 869 'exist in country [%s] ?' 870 ) % ( 871 self._PRW_state.GetValue().strip(), 872 self._PRW_country.GetValue().strip() 873 ), 874 _('Saving address') 875 ) 876 return False 877 878 # link address to holder (there better be one) 879 linked_address = self.address_holder.link_address(id_type = self._PRW_type.GetData(), address = address) 880 if linked_address['pk_address'] != address['pk_address']: 881 raise ValueError('problem linking address to person or org') 882 883 address['notes_street'] = gmTools.none_if(self._TCTRL_notes_street.GetValue().strip(), u'') 884 address['notes_subunit'] = gmTools.none_if(self._TCTRL_notes_subunit.GetValue().strip(), u'') 885 address.save() 886 887 linked_address.refetch_payload() 888 self.data = linked_address 889 890 return True
891 #----------------------------------------------------------------
892 - def _refresh_as_new(self):
893 self._PRW_type.SetText(u'', None) 894 self._PRW_zip.SetText(u'', None) 895 self._PRW_street.SetText(u'', None) 896 self._TCTRL_notes_street.SetValue(u'') 897 self._TCTRL_number.SetValue(u'') 898 self._TCTRL_subunit.SetValue(u'') 899 self._PRW_suburb.SetText(u'', None) 900 self._PRW_urb.SetText(u'', None) 901 self._PRW_state.SetText(u'', None) 902 self._PRW_country.SetText(u'', None) 903 self._TCTRL_notes_subunit.SetValue(u'') 904 905 if self.__type_is_editable: 906 self._PRW_type.SetFocus() 907 else: 908 self._PRW_zip.SetFocus()
909 #----------------------------------------------------------------
911 self._refresh_as_new() 912 913 self._PRW_zip.SetText(self.data['postcode']) 914 self._PRW_street.SetText(self.data['street'], data = self.data['street']) 915 self._PRW_suburb.SetText(gmTools.coalesce(self.data['suburb'], '')) 916 self._PRW_urb.SetText(self.data['urb'], data = self.data['urb']) 917 self._PRW_state.SetText(self.data['l10n_state'], data = self.data['code_state']) 918 self._PRW_country.SetText(self.data['l10n_country'], data = self.data['code_country']) 919 920 if self.__type_is_editable: 921 self._PRW_type.SetFocus() 922 else: 923 self._TCTRL_number.SetFocus()
924 #----------------------------------------------------------------
925 - def _refresh_from_existing(self):
926 if self.__type_is_editable: 927 self._PRW_type.SetText(self.data['l10n_address_type']) 928 else: 929 self._PRW_type.SetText(u'', None) 930 self._PRW_zip.SetText(self.data['postcode']) 931 self._PRW_street.SetText(self.data['street'], data = self.data['street']) 932 self._TCTRL_notes_street.SetValue(gmTools.coalesce(self.data['notes_street'], '')) 933 self._TCTRL_number.SetValue(self.data['number']) 934 self._TCTRL_subunit.SetValue(gmTools.coalesce(self.data['subunit'], '')) 935 self._PRW_suburb.SetText(gmTools.coalesce(self.data['suburb'], '')) 936 self._PRW_urb.SetText(self.data['urb'], data = self.data['urb']) 937 self._PRW_state.SetText(self.data['l10n_state'], data = self.data['code_state']) 938 self._PRW_country.SetText(self.data['l10n_country'], data = self.data['code_country']) 939 self._TCTRL_notes_subunit.SetValue(gmTools.coalesce(self.data['notes_subunit'], '')) 940 941 if self.__type_is_editable: 942 self._PRW_type.SetFocus() 943 else: 944 self._PRW_zip.SetFocus()
945 #---------------------------------------------------------------- 946 # event handling 947 #----------------------------------------------------------------
948 - def _on_zip_set(self):
949 """Set the street, town, state and country according to entered zip code.""" 950 zip_code = self._PRW_zip.GetValue() 951 if zip_code.strip() == u'': 952 self._PRW_street.unset_context(context = u'zip') 953 self._PRW_urb.unset_context(context = u'zip') 954 self._PRW_state.unset_context(context = u'zip') 955 self._PRW_country.unset_context(context = u'zip') 956 else: 957 self._PRW_street.set_context(context = u'zip', val = zip_code) 958 self._PRW_urb.set_context(context = u'zip', val = zip_code) 959 self._PRW_state.set_context(context = u'zip', val = zip_code) 960 self._PRW_country.set_context(context = u'zip', val = zip_code)
961 #----------------------------------------------------------------
962 - def _on_country_set(self):
963 """Set the states according to entered country.""" 964 country = self._PRW_country.GetData() 965 if country is None: 966 self._PRW_state.unset_context(context = 'country') 967 else: 968 self._PRW_state.set_context(context = 'country', val = country)
969 #---------------------------------------------------------------- 970 # properties 971 #----------------------------------------------------------------
972 - def _get_type_is_editable(self):
973 return self.__type_is_editable
974
975 - def _set_type_is_editable(self, type_is_editable):
976 self.__type_is_editable = type_is_editable 977 self._PRW_type.Enable(type_is_editable) 978 self._PRW_type.Show(type_is_editable) 979 self._LBL_type.Show(type_is_editable)
980 981 type_is_editable = property(_get_type_is_editable, _set_type_is_editable) 982 #----------------------------------------------------------------
983 - def _get_address_is_searchable(self):
984 return self.__address_is_searchable
985
986 - def _set_address_is_searchable(self, address_is_searchable):
987 # FIXME: always set to FALSE when self.mode == 'new' ? 988 self.__address_is_searchable = address_is_searchable 989 self._PRW_address_searcher.Enable(address_is_searchable) 990 self._PRW_address_searcher.Show(address_is_searchable) 991 self._LBL_search.Show(address_is_searchable)
992 993 address_is_searchable = property(_get_address_is_searchable, _set_address_is_searchable) 994 #----------------------------------------------------------------
995 - def _get_address(self):
996 return self.data
997
998 - def _set_address(self, address):
999 self.data = address
1000 1001 address = property(_get_address, _set_address)
1002 1003 #============================================================
1004 -class cAddressMatchProvider(gmMatchProvider.cMatchProvider_SQL2):
1005
1006 - def __init__(self):
1007 1008 query = u""" 1009 SELECT * FROM ( 1010 (SELECT 1011 pk_address AS data, 1012 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1013 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1014 || postcode || ', ' 1015 || code_country 1016 ) AS field_label, 1017 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1018 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1019 || postcode || ', ' 1020 || l10n_state || ', ' 1021 || l10n_country 1022 || coalesce(', ' || notes_street, '') 1023 || coalesce(', ' || notes_subunit, '') 1024 ) AS list_label 1025 FROM 1026 dem.v_address 1027 WHERE 1028 street %(fragment_condition)s 1029 1030 ) UNION ( 1031 1032 SELECT 1033 pk_address AS data, 1034 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1035 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1036 || postcode || ', ' 1037 || code_country 1038 ) AS field_label, 1039 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1040 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1041 || postcode || ', ' 1042 || l10n_state || ', ' 1043 || l10n_country 1044 || coalesce(', ' || notes_street, '') 1045 || coalesce(', ' || notes_subunit, '') 1046 ) AS list_label 1047 FROM 1048 dem.v_address 1049 WHERE 1050 postcode_street %(fragment_condition)s 1051 1052 ) UNION ( 1053 1054 SELECT 1055 pk_address AS data, 1056 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1057 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1058 || postcode || ', ' 1059 || code_country 1060 ) AS field_label, 1061 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1062 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1063 || postcode || ', ' 1064 || l10n_state || ', ' 1065 || l10n_country 1066 || coalesce(', ' || notes_street, '') 1067 || coalesce(', ' || notes_subunit, '') 1068 ) AS list_label 1069 FROM 1070 dem.v_address 1071 WHERE 1072 postcode_urb %(fragment_condition)s 1073 ) 1074 ) AS matching_addresses 1075 ORDER BY list_label 1076 LIMIT 50""" 1077 1078 gmMatchProvider.cMatchProvider_SQL2.__init__(self, queries = query) 1079 1080 self.setThresholds(2, 4, 6) 1081 # self.word_separators = u'[ \t]+' 1082 1083 self._SQL_data2match = u""" 1084 SELECT 1085 pk_address AS data, 1086 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1087 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1088 || postcode || ', ' 1089 || code_country 1090 ) AS field_label, 1091 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1092 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1093 || postcode || ', ' 1094 || l10n_state || ', ' 1095 || l10n_country 1096 || coalesce(', ' || notes_street, '') 1097 || coalesce(', ' || notes_subunit, '') 1098 ) AS list_label 1099 FROM 1100 dem.v_address 1101 WHERE 1102 pk_address = %(pk)s 1103 """
1104 1105 #============================================================
1106 -class cAddressPhraseWheel(gmPhraseWheel.cPhraseWheel):
1107
1108 - def __init__(self, *args, **kwargs):
1109 1110 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1111 self.matcher = cAddressMatchProvider() 1112 self.SetToolTipString(_('Select an address by postcode or street name.')) 1113 self.selection_only = True 1114 self.__address = None 1115 self.__old_pk = None
1116 #--------------------------------------------------------
1117 - def _get_data_tooltip(self):
1118 adr = self.address 1119 if adr is None: 1120 return None 1121 return u'\n'.join(adr.format())
1122 #--------------------------------------------------------
1123 - def _data2instance(self):
1124 return gmDemographicRecord.cAddress(aPK_obj = self.GetData())
1125 #-------------------------------------------------------- 1126 # properties 1127 #--------------------------------------------------------
1128 - def __get_address(self):
1129 pk = self.GetData() 1130 if pk is None: 1131 self.__address = None 1132 return None 1133 if self.__address is None: 1134 self.__old_pk = pk 1135 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1136 else: 1137 if pk != self.__old_pk: 1138 self.__old_pk = pk 1139 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1140 return self.__address
1141
1142 - def __set_address(self, address):
1143 if address is None: 1144 self.__old_pk = None 1145 self.__address = None 1146 self.SetText(u'', None) 1147 return 1148 if isinstance(address, gmDemographicRecord.cAddress): 1149 self.__old_pk = address['pk_address'] 1150 self.__address = address 1151 pk = self.__old_pk 1152 else: 1153 self.__old_pk = None 1154 self.__address = None 1155 pk = address 1156 match = self.matcher.get_match_by_data(data = pk) 1157 if match is None: 1158 raise ValueError(u'[%s]: cannot match address [#%s]' % (self.__class__.__name__, pk)) 1159 self.SetText(match['field_label'], pk)
1160 1161 address = property(__get_address, __set_address) 1162 #--------------------------------------------------------
1163 - def __get_person_address(self):
1164 pk = self.GetData() 1165 if pk is None: 1166 self.__address = None 1167 return None 1168 if self.__address is None: 1169 self.__old_pk = pk 1170 self.__address = gmDemographicRecord.cPatientAddress(aPK_obj = pk) 1171 else: 1172 if pk != self.__old_pk: 1173 self.__old_pk = pk 1174 self.__address = gmDemographicRecord.cPatientAddress(aPK_obj = pk) 1175 return self.__address
1176 1177 person_address = property(__get_person_address, lambda x:x)
1178 #================================================================ 1179 # main 1180 #---------------------------------------------------------------- 1181 if __name__ == '__main__': 1182 1183 if len(sys.argv) < 2: 1184 sys.exit() 1185 1186 if sys.argv[1] != 'test': 1187 sys.exit() 1188 1189 from Gnumed.pycommon import gmI18N 1190 gmI18N.activate_locale() 1191 gmI18N.install_domain() 1192 from Gnumed.business import gmPersonSearch 1193 1194 #--------------------------------------------------------
1195 - def test_country_prw():
1196 app = wx.PyWidgetTester(size = (200, 50)) 1197 pw = cCountryPhraseWheel(app.frame, -1) 1198 app.frame.Show(True) 1199 app.MainLoop()
1200 #--------------------------------------------------------
1201 - def test_state_prw():
1202 app = wx.PyWidgetTester(size = (200, 50)) 1203 pw = cStateSelectionPhraseWheel(app.frame, -1) 1204 pw.set_context(context = u'zip', val = u'04318') 1205 pw.set_context(context = u'country', val = u'Deutschland') 1206 app.frame.Show(True) 1207 app.MainLoop()
1208 #--------------------------------------------------------
1209 - def test_zipcode_prw():
1210 app = wx.PyWidgetTester(size = (200, 50)) 1211 pw = cZipcodePhraseWheel(app.frame, -1) 1212 app.frame.Show(True) 1213 app.MainLoop()
1214 #--------------------------------------------------------
1215 - def test_street_prw():
1216 app = wx.PyWidgetTester(size = (200, 50)) 1217 pw = cStreetPhraseWheel(app.frame, -1) 1218 # pw.set_context(context = u'zip', val = u'04318') 1219 app.frame.Show(True) 1220 app.MainLoop()
1221 #--------------------------------------------------------
1222 - def test_suburb_prw():
1223 app = wx.PyWidgetTester(size = (200, 50)) 1224 pw = cSuburbPhraseWheel(app.frame, -1) 1225 app.frame.Show(True) 1226 app.MainLoop()
1227 #--------------------------------------------------------
1228 - def test_urb_prw():
1229 app = wx.PyWidgetTester(size = (200, 50)) 1230 pw = cUrbPhraseWheel(app.frame, -1) 1231 app.frame.Show(True) 1232 pw.set_context(context = u'zip', val = u'04317') 1233 app.MainLoop()
1234 #--------------------------------------------------------
1235 - def test_address_type_prw():
1236 app = wx.PyWidgetTester(size = (200, 50)) 1237 pw = cAddressTypePhraseWheel(app.frame, -1) 1238 app.frame.Show(True) 1239 app.MainLoop()
1240 #--------------------------------------------------------
1241 - def test_address_prw():
1242 app = wx.PyWidgetTester(size = (200, 50)) 1243 pw = cAddressPhraseWheel(app.frame, -1) 1244 app.frame.Show(True) 1245 app.MainLoop()
1246 #--------------------------------------------------------
1247 - def test_address_ea_pnl():
1248 app = wx.PyWidgetTester(size = (600, 400)) 1249 app.SetWidget(cAddressEditAreaPnl, address = gmDemographicRecord.cAddress(aPK_obj = 1)) 1250 app.MainLoop()
1251 #-------------------------------------------------------- 1252 #test_address_type_prw() 1253 #test_zipcode_prw() 1254 #test_state_prw() 1255 #test_street_prw() 1256 #test_suburb_prw() 1257 #test_country_prw() 1258 #test_urb_prw() 1259 #test_address_ea_pnl() 1260 test_address_prw() 1261 1262 #================================================================ 1263