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 'ctxt_zip': { 58 'where_part': 'and zip ilike %(zip)s', 59 'placeholder': 'zip' 60 } 61 } 62 query = """ 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 = """ 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 = 'zip') 148 self.SetToolTip(_('Type or select a country.')) 149 self.capitalisation_mode = gmTools.CAPS_FIRST 150 self.selection_only = True
151 152 #============================================================ 153 # region related widgets / functions 154 #============================================================
155 -def configure_default_region(parent=None):
156 157 if parent is None: 158 parent = wx.GetApp().GetTopWindow() 159 160 regs = gmDemographicRecord.get_regions() 161 162 gmCfgWidgets.configure_string_from_list_option ( 163 parent = parent, 164 message = _('Select the default region (state/province/county/territory/arrondissement/prefecture/department/kanton/...) for new persons.\n'), 165 option = 'person.create.default_region', 166 bias = 'user', 167 choices = [ (r['l10n_country'], r['l10n_region'], r['code_region']) for r in regs ], 168 columns = [_('Country'), _('Region'), _('Code')], 169 data = [ r['region'] for r in regs ] 170 )
171 #============================================================
172 -def edit_region(parent=None, region=None):
173 ea = cProvinceEAPnl(parent, -1, region = region) 174 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = (region is not None)) 175 dlg.SetTitle(gmTools.coalesce(region, _('Adding region'), _('Editing region'))) 176 result = dlg.ShowModal() 177 dlg.DestroyLater() 178 return (result == wx.ID_OK)
179 #============================================================
180 -def delete_region(parent=None, region=None):
181 182 msg = _( 183 'Are you sure you want to delete this region ?\n' 184 '\n' 185 'Deletion will only work if this region 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 region'), 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 region 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.DestroyLater() 212 return False 213 214 include_urbs = dlg.checkbox_is_checked() 215 dlg.DestroyLater() 216 217 return gmDemographicRecord.delete_region(region = region, delete_urbs = include_urbs)
218 #============================================================
219 -def manage_regions(parent=None):
220 221 if parent is None: 222 parent = wx.GetApp().GetTopWindow() 223 224 #------------------------------------------------------------ 225 def delete(region=None): 226 return delete_region(parent = parent, region = region['pk_region'])
227 #------------------------------------------------------------ 228 def edit(region=None): 229 return edit_region(parent = parent, region = region) 230 #------------------------------------------------------------ 231 def refresh(lctrl): 232 wx.BeginBusyCursor() 233 provinces = gmDemographicRecord.get_regions() 234 lctrl.set_string_items([ (p['l10n_country'], p['l10n_region']) for p in provinces ]) 235 lctrl.set_data(provinces) 236 wx.EndBusyCursor() 237 #------------------------------------------------------------ 238 msg = _( 239 'This list shows the regions known to GNUmed.\n' 240 '\n' 241 'In your jurisdiction "region" may correspond to either of "state",\n' 242 '"county", "province", "territory", "arrondissement", "department,"\n' 243 '"prefecture", "kanton", or some such term.\n' 244 ) 245 246 gmListWidgets.get_choices_from_list ( 247 parent = parent, 248 msg = msg, 249 caption = _('Editing regions ...'), 250 columns = [_('Country'), _('Region')], 251 single_selection = True, 252 new_callback = edit, 253 #edit_callback = edit, 254 delete_callback = delete, 255 refresh_callback = refresh 256 ) 257 #============================================================
258 -class cStateSelectionPhraseWheel(gmPhraseWheel.cPhraseWheel):
259
260 - def __init__(self, *args, **kwargs):
261 262 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 263 264 context = { 265 'ctxt_country_name': { 266 'where_part': 'AND l10n_country ILIKE %(country_name)s OR country ILIKE %(country_name)s', 267 'placeholder': 'country_name' 268 }, 269 'ctxt_zip': { 270 'where_part': 'AND zip ilike %(zip)s', 271 'placeholder': 'zip' 272 }, 273 'ctxt_country_code': { 274 'where_part': 'AND country IN (SELECT code FROM dem.country WHERE _(name) ILIKE %(country_name)s OR name ILIKE %(country_name)s)', 275 'placeholder': 'country_name' 276 } 277 } 278 279 query = """ 280 SELECT 281 data, 282 field_label, 283 list_label 284 FROM ( 285 SELECT DISTINCT ON (field_label) 286 data, 287 field_label, 288 list_label, 289 rank 290 FROM ( 291 -- 1: find regions based on name, context: zip and country name 292 SELECT 293 code_region AS data, 294 region AS field_label, 295 region || ' (' || code_region || '), ' || l10n_country || ' (' || code_country || ')' AS list_label, 296 1 AS rank 297 FROM dem.v_zip2data 298 WHERE 299 region %(fragment_condition)s 300 %(ctxt_country_name)s 301 %(ctxt_zip)s 302 303 UNION ALL 304 305 -- 2: find regions based on code, context: zip and country name 306 SELECT 307 code_region AS data, 308 region AS field_label, 309 code_region || ': ' || region || ' (' || l10n_country || ', ' || code_country || ')' AS list_label, 310 2 AS rank 311 FROM dem.v_zip2data 312 WHERE 313 code_region %(fragment_condition)s 314 %(ctxt_country_name)s 315 %(ctxt_zip)s 316 317 UNION ALL 318 319 -- 3: find regions based on name, context: country 320 SELECT 321 code AS data, 322 name AS field_label, 323 name || ' (' || code || '), ' || country AS list_label, 324 3 AS rank 325 FROM dem.region 326 WHERE 327 name %(fragment_condition)s 328 %(ctxt_country_code)s 329 330 UNION ALL 331 332 -- 4: find regions based on code, context: country 333 SELECT 334 code AS data, 335 name AS field_label, 336 code || ': ' || name || ', ' || country AS list_label, 337 3 AS rank 338 FROM dem.region 339 WHERE 340 code %(fragment_condition)s 341 %(ctxt_country_code)s 342 343 ) AS candidate_regions 344 ) AS distinct_matches 345 ORDER BY rank, list_label 346 LIMIT 50""" 347 348 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=context) 349 mp.setThresholds(2, 5, 6) 350 mp.word_separators = '[ \t]+' 351 self.matcher = mp 352 353 self.unset_context(context = 'zip') 354 self.unset_context(context = 'country_name') 355 self.SetToolTip(_('Type or select a region (state/province/county/territory/arrondissement/prefecture/department/kanton/...).')) 356 self.capitalisation_mode = gmTools.CAPS_FIRST 357 self.selection_only = True
358 #==================================================================== 359 from Gnumed.wxGladeWidgets import wxgProvinceEAPnl 360
361 -class cProvinceEAPnl(wxgProvinceEAPnl.wxgProvinceEAPnl, gmEditArea.cGenericEditAreaMixin):
362
363 - def __init__(self, *args, **kwargs):
364 365 try: 366 data = kwargs['region'] 367 del kwargs['region'] 368 except KeyError: 369 data = None 370 371 wxgProvinceEAPnl.wxgProvinceEAPnl.__init__(self, *args, **kwargs) 372 gmEditArea.cGenericEditAreaMixin.__init__(self) 373 374 self.mode = 'new' 375 self.data = data 376 if data is not None: 377 self.mode = 'edit' 378 379 self.__init_ui()
380 #----------------------------------------------------------------
381 - def __init_ui(self):
382 self._PRW_region.selection_only = False
383 #---------------------------------------------------------------- 384 # generic Edit Area mixin API 385 #----------------------------------------------------------------
386 - def _valid_for_save(self):
387 388 validity = True 389 390 if self._PRW_region.GetData() is None: 391 if self._PRW_region.GetValue().strip() == '': 392 validity = False 393 self._PRW_region.display_as_valid(False) 394 else: 395 self._PRW_region.display_as_valid(True) 396 else: 397 self._PRW_region.display_as_valid(True) 398 399 if self._PRW_region.GetData() is None: 400 if self._TCTRL_code.GetValue().strip() == '': 401 validity = False 402 self._TCTRL_code.SetBackgroundColour(gmPhraseWheel.color_prw_invalid) 403 else: 404 self._TCTRL_code.SetBackgroundColour(gmPhraseWheel.color_prw_valid) 405 406 if self._PRW_country.GetData() is None: 407 validity = False 408 self._PRW_country.display_as_valid(False) 409 else: 410 self._PRW_country.display_as_valid(True) 411 412 return validity
413 #----------------------------------------------------------------
414 - def _save_as_new(self):
415 gmDemographicRecord.create_region ( 416 name = self._PRW_region.GetValue().strip(), 417 code = self._TCTRL_code.GetValue().strip(), 418 country = self._PRW_country.GetData() 419 ) 420 421 # EA is refreshed automatically after save, so need this ... 422 self.data = { 423 'l10n_region' : self._PRW_region.GetValue().strip(), 424 'code_region' : self._TCTRL_code.GetValue().strip(), 425 'l10n_country' : self._PRW_country.GetValue().strip(), 426 'code_country' : self._PRW_country.GetData().strip() 427 } 428 429 return True
430 #----------------------------------------------------------------
431 - def _save_as_update(self):
432 # update self.data and save the changes 433 #self.data[''] = 434 #self.data[''] = 435 #self.data[''] = 436 #self.data.save() 437 438 # do nothing for now (IOW, don't support updates) 439 return True
440 #----------------------------------------------------------------
441 - def _refresh_as_new(self):
442 self._PRW_region.SetText() 443 self._TCTRL_code.SetValue('') 444 self._PRW_country.SetText() 445 446 self._PRW_region.SetFocus()
447 #----------------------------------------------------------------
448 - def _refresh_from_existing(self):
449 self._PRW_region.SetText(self.data['l10n_region'], self.data['code_region']) 450 self._TCTRL_code.SetValue(self.data['code_region']) 451 self._PRW_country.SetText(self.data['l10n_country'], self.data['code_country']) 452 453 self._PRW_region.SetFocus()
454 #----------------------------------------------------------------
456 self._PRW_region.SetText() 457 self._TCTRL_code.SetValue('') 458 self._PRW_country.SetText(self.data['l10n_country'], self.data['code_country']) 459 460 self._PRW_region.SetFocus()
461 462 #============================================================ 463 # other address parts phrasewheels and widgets 464 #============================================================
465 -class cZipcodePhraseWheel(gmPhraseWheel.cPhraseWheel):
466
467 - def __init__(self, *args, **kwargs):
468 # FIXME: add possible context 469 query = """( 470 SELECT DISTINCT ON (list_label) 471 postcode AS data, 472 postcode || ' (' || name || ')' AS list_label, 473 postcode AS field_label 474 FROM dem.street 475 WHERE 476 postcode %(fragment_condition)s 477 ORDER BY list_label 478 LIMIT 20 479 480 ) UNION ( 481 482 SELECT DISTINCT ON (list_label) 483 postcode AS data, 484 postcode || ' (' || name || ')' AS list_label, 485 postcode AS field_label 486 FROM dem.urb 487 WHERE 488 postcode %(fragment_condition)s 489 ORDER BY list_label 490 LIMIT 20 491 )""" 492 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 493 mp.setThresholds(2, 3, 15) 494 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 495 self.SetToolTip(_("Type or select a zip code (postcode).\n\nUse e.g. '?' if unknown.")) 496 self.matcher = mp
497 #============================================================
498 -class cStreetPhraseWheel(gmPhraseWheel.cPhraseWheel):
499
500 - def __init__(self, *args, **kwargs):
501 context = { 502 'ctxt_zip': { 503 'where_part': 'AND zip ILIKE %(zip)s', 504 'placeholder': 'zip' 505 } 506 } 507 query = """ 508 SELECT 509 data, 510 field_label, 511 list_label 512 FROM ( 513 514 SELECT DISTINCT ON (data) 515 street AS data, 516 street AS field_label, 517 street || ' (' || zip || ', ' || urb || coalesce(', ' || suburb, '') || ', ' || l10n_country || ')' AS list_label, 518 1 AS rank 519 FROM dem.v_zip2data 520 WHERE 521 street %(fragment_condition)s 522 %(ctxt_zip)s 523 524 UNION ALL 525 526 SELECT DISTINCT ON (data) 527 name AS data, 528 name AS field_label, 529 name || ' (' || coalesce(postcode, '') || coalesce(', ' || suburb, '') || ')' AS list_label, 530 2 AS rank 531 FROM dem.street 532 WHERE 533 name %(fragment_condition)s 534 535 ) AS matching_streets 536 ORDER BY rank, field_label 537 LIMIT 50""" 538 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=context) 539 mp.setThresholds(3, 5, 8) 540 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 541 self.unset_context(context = 'zip') 542 543 self.SetToolTip(_('Type or select a street.')) 544 self.capitalisation_mode = gmTools.CAPS_FIRST 545 self.matcher = mp
546 #============================================================
547 -class cSuburbPhraseWheel(gmPhraseWheel.cPhraseWheel):
548
549 - def __init__(self, *args, **kwargs):
550 551 query = """ 552 SELECT DISTINCT ON (suburb) suburb, suburb 553 FROM dem.street 554 WHERE suburb %(fragment_condition)s 555 ORDER BY suburb 556 LIMIT 50 557 """ 558 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 559 mp.setThresholds(2, 3, 6) 560 gmPhraseWheel.cPhraseWheel.__init__ ( 561 self, 562 *args, 563 **kwargs 564 ) 565 566 self.SetToolTip(_('Type or select the suburb.')) 567 self.capitalisation_mode = gmTools.CAPS_FIRST 568 self.matcher = mp
569 #============================================================
570 -class cUrbPhraseWheel(gmPhraseWheel.cPhraseWheel):
571
572 - def __init__(self, *args, **kwargs):
573 context = { 574 'ctxt_zip': { 575 'where_part': 'and zip ilike %(zip)s', 576 'placeholder': 'zip' 577 } 578 } 579 query = """ 580 SELECT DISTINCT ON (rank, data) 581 data, 582 field_label, 583 list_label 584 FROM ( 585 586 SELECT 587 urb AS data, 588 urb AS field_label, 589 urb || ' (' || zip || ', ' || region || ', ' || l10n_country || ')' AS list_label, 590 1 AS rank 591 FROM dem.v_zip2data 592 WHERE 593 urb %(fragment_condition)s 594 %(ctxt_zip)s 595 596 UNION ALL 597 598 SELECT 599 name AS data, 600 name AS field_label, 601 name || ' (' || postcode ||')' AS list_label, 602 2 AS rank 603 FROM dem.urb 604 WHERE 605 name %(fragment_condition)s 606 607 ) AS matching_urbs 608 ORDER BY rank, data 609 LIMIT 50""" 610 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query, context=context) 611 mp.setThresholds(3, 5, 7) 612 gmPhraseWheel.cPhraseWheel.__init__ ( 613 self, 614 *args, 615 **kwargs 616 ) 617 self.unset_context(context = 'zip') 618 619 self.SetToolTip(_('Type or select a city/town/village/dwelling.')) 620 self.capitalisation_mode = gmTools.CAPS_FIRST 621 self.matcher = mp
622 #============================================================ 623 # address type related widgets 624 #============================================================
625 -class cAddressTypePhraseWheel(gmPhraseWheel.cPhraseWheel):
626
627 - def __init__(self, *args, **kwargs):
628 629 query = """ 630 SELECT id, type FROM (( 631 SELECT id, _(name) AS type, 1 AS rank 632 FROM dem.address_type 633 WHERE _(name) %(fragment_condition)s 634 ) UNION ( 635 SELECT id, name AS type, 2 AS rank 636 FROM dem.address_type 637 WHERE name %(fragment_condition)s 638 )) AS ur 639 order by 640 ur.rank, ur.type 641 """ 642 mp = gmMatchProvider.cMatchProvider_SQL2(queries=query) 643 mp.setThresholds(1, 2, 4) 644 mp.word_separators = '[ \t]+' 645 gmPhraseWheel.cPhraseWheel.__init__ ( 646 self, 647 *args, 648 **kwargs 649 ) 650 self.matcher = mp 651 self.SetToolTip(_('Select the type of address.')) 652 # self.capitalisation_mode = gmTools.CAPS_FIRST 653 self.selection_only = True
654 #-------------------------------------------------------- 655 # def GetData(self, can_create=False): 656 # if self.data is None: 657 # if can_create: 658 # self.data = gmDocuments.create_document_type(self.GetValue().strip())['pk_doc_type'] # FIXME: error handling 659 # return self.data 660 661 #============================================================ 662 # address phrasewheels and widgets 663 #============================================================
664 -def manage_addresses(parent=None):
665 666 if parent is None: 667 parent = wx.GetApp().GetTopWindow() 668 669 #------------------------------------------------------------ 670 def calculate_tooltip(address): 671 return '\n'.join(address.format())
672 #------------------------------------------------------------ 673 def delete(address): 674 return gmDemographicRecord.delete_address(pk_address = address['pk_address']) 675 #------------------------------------------------------------ 676 def refresh(lctrl): 677 adrs = gmDemographicRecord.get_addresses(order_by = 'l10n_country, urb, street, number, subunit') 678 items = [ [ 679 a['street'], 680 gmTools.coalesce(a['notes_street'], ''), 681 a['number'], 682 gmTools.coalesce(a['subunit'], ''), 683 a['postcode'], 684 a['urb'], 685 gmTools.coalesce(a['suburb'], ''), 686 a['l10n_region'], 687 a['l10n_country'], 688 gmTools.coalesce(a['notes_subunit'], '') 689 ] for a in adrs 690 ] 691 lctrl.set_string_items(items) 692 lctrl.set_data(adrs) 693 694 #------------------------------------------------------------ 695 cols = [ 696 _('Street'), 697 _('Street info'), 698 _('Number'), 699 _('Subunit'), 700 _('Postal code'), 701 _('Community'), 702 _('Suburb'), 703 _('Region'), 704 _('Country'), 705 _('Comment') 706 ] 707 return gmListWidgets.get_choices_from_list ( 708 parent = parent, 709 caption = _('Showing addresses registered in GNUmed.'), 710 columns = cols, 711 single_selection = True, 712 refresh_callback = refresh, 713 delete_callback = delete, 714 list_tooltip_callback = calculate_tooltip 715 ) 716 717 #============================================================ 718 from Gnumed.wxGladeWidgets import wxgGenericAddressEditAreaPnl 719
720 -class cAddressEAPnl(wxgGenericAddressEditAreaPnl.wxgGenericAddressEditAreaPnl, gmEditArea.cGenericEditAreaMixin):
721
722 - def __init__(self, *args, **kwargs):
723 724 try: 725 data = kwargs['address'] 726 del kwargs['address'] 727 except KeyError: 728 data = None 729 730 self.address_holder = None 731 self.__type_is_editable = True 732 self.__address_is_searchable = False 733 734 wxgGenericAddressEditAreaPnl.wxgGenericAddressEditAreaPnl.__init__(self, *args, **kwargs) 735 gmEditArea.cGenericEditAreaMixin.__init__(self) 736 737 self.type_is_editable = True 738 self.address_is_searchable = False 739 740 # Code using this mixin should set mode and data 741 # after instantiating the class: 742 self.mode = 'new' 743 self.data = data 744 if data is not None: 745 self.mode = 'edit' 746 747 self.__init_ui()
748 #----------------------------------------------------------------
749 - def __init_ui(self):
750 self._PRW_zip.add_callback_on_lose_focus(self._on_zip_set) 751 self._PRW_country.add_callback_on_lose_focus(self._on_country_set)
752 #---------------------------------------------------------------- 753 # generic Edit Area mixin API 754 #----------------------------------------------------------------
755 - def _valid_for_save(self):
756 757 validity = True 758 759 # if any field is filled, all must be filled, so track that 760 is_any_field_filled = False 761 762 # check by string 763 required_fields = [ 764 self._PRW_urb, 765 self._TCTRL_number, 766 self._PRW_street, 767 self._PRW_zip 768 ] 769 if self.__type_is_editable: 770 required_fields.insert(0, self._PRW_type) 771 for field in required_fields: 772 if len(field.GetValue().strip()) == 0: 773 if is_any_field_filled: 774 self.display_ctrl_as_valid(field, False) 775 field.SetFocus() 776 gmGuiHelpers.gm_show_error ( 777 _('Address details must be filled in completely or not at all.'), 778 _('Saving contact data') 779 ) 780 validity = False 781 else: 782 is_any_field_filled = True 783 self.display_ctrl_as_valid(field, True) 784 785 # check by data 786 required_fields = ( 787 self._PRW_country, 788 self._PRW_state 789 ) 790 for field in required_fields: 791 if field.GetData() is None: 792 if is_any_field_filled: 793 self.display_ctrl_as_valid(field, False) 794 field.SetFocus() 795 gmGuiHelpers.gm_show_error ( 796 _('Address details must be filled in completely or not at all.'), 797 _('Saving contact data') 798 ) 799 validity = False 800 else: 801 is_any_field_filled = True 802 self.display_ctrl_as_valid(field, True) 803 804 return validity
805 #----------------------------------------------------------------
806 - def _save_as_new(self):
807 try: 808 # will create or return address 809 address = gmDemographicRecord.create_address ( 810 country_code = self._PRW_country.GetData(), 811 region_code = self._PRW_state.GetData(), 812 urb = self._PRW_urb.GetValue().strip(), 813 suburb = gmTools.none_if(self._PRW_suburb.GetValue().strip(), ''), 814 postcode = self._PRW_zip.GetValue().strip(), 815 street = self._PRW_street.GetValue().strip(), 816 number = self._TCTRL_number.GetValue().strip(), 817 subunit = gmTools.none_if(self._TCTRL_subunit.GetValue().strip(), '') 818 ) 819 except Exception: 820 _log.exception('cannot save address') 821 gmGuiHelpers.gm_show_error ( 822 _('Cannot save address.\n\n' 823 'Does the region [%s]\n' 824 'exist in country [%s] ?' 825 ) % ( 826 self._PRW_state.GetValue().strip(), 827 self._PRW_country.GetValue().strip() 828 ), 829 _('Saving address') 830 ) 831 return False 832 833 # link address to holder (there better be one) 834 linked_address = self.address_holder.link_address(id_type = self._PRW_type.GetData(), address = address) 835 if linked_address['pk_address'] != address['pk_address']: 836 raise ValueError('problem linking address to person or org') 837 838 address['notes_street'] = gmTools.none_if(self._TCTRL_notes_street.GetValue().strip(), '') 839 address['notes_subunit'] = gmTools.none_if(self._TCTRL_notes_subunit.GetValue().strip(), '') 840 address.save() 841 842 linked_address.refetch_payload() 843 self.data = linked_address 844 845 return True
846 #----------------------------------------------------------------
847 - def _save_as_update(self):
848 # do not update existing address, rather 849 # create new one or get corresponding 850 # address should it exist 851 try: 852 created_or_loaded_address = gmDemographicRecord.create_address ( 853 country_code = self._PRW_country.GetData(), 854 region_code = self._PRW_state.GetData(), 855 urb = self._PRW_urb.GetValue().strip(), 856 suburb = gmTools.none_if(self._PRW_suburb.GetValue().strip(), ''), 857 postcode = self._PRW_zip.GetValue().strip(), 858 street = self._PRW_street.GetValue().strip(), 859 number = self._TCTRL_number.GetValue().strip(), 860 subunit = gmTools.none_if(self._TCTRL_subunit.GetValue().strip(), '') 861 ) 862 except Exception: 863 _log.exception('cannot save address') 864 gmGuiHelpers.gm_show_error ( 865 _('Cannot save address.\n\n' 866 'Does the region [%s]\n' 867 'exist in country [%s] ?' 868 ) % ( 869 self._PRW_state.GetValue().strip(), 870 self._PRW_country.GetValue().strip() 871 ), 872 _('Saving address') 873 ) 874 return False 875 876 # link address to holder (there better be one) 877 linked_address = self.address_holder.link_address(id_type = self._PRW_type.GetData(), address = created_or_loaded_address) 878 if linked_address['pk_address'] != created_or_loaded_address['pk_address']: 879 raise ValueError('problem linking address to person or org') 880 881 created_or_loaded_address['notes_street'] = gmTools.none_if(self._TCTRL_notes_street.GetValue().strip(), '') 882 created_or_loaded_address['notes_subunit'] = gmTools.none_if(self._TCTRL_notes_subunit.GetValue().strip(), '') 883 created_or_loaded_address.save_payload() 884 linked_address.refetch_payload() 885 self.data = linked_address 886 887 return True
888 #----------------------------------------------------------------
889 - def _refresh_as_new(self):
890 self._PRW_type.SetText('', None) 891 self._PRW_zip.SetText('', None) 892 self._PRW_street.SetText('', None) 893 self._TCTRL_notes_street.SetValue('') 894 self._TCTRL_number.SetValue('') 895 self._TCTRL_subunit.SetValue('') 896 self._PRW_suburb.SetText('', None) 897 self._PRW_urb.SetText('', None) 898 self._PRW_state.SetText('', None) 899 self._PRW_country.SetText('', None) 900 self._TCTRL_notes_subunit.SetValue('') 901 902 if self.__type_is_editable: 903 self._PRW_type.SetFocus() 904 else: 905 self._PRW_zip.SetFocus()
906 #----------------------------------------------------------------
908 self._refresh_as_new() 909 910 self._PRW_zip.SetText(self.data['postcode']) 911 self._PRW_street.SetText(self.data['street'], data = self.data['street']) 912 self._PRW_suburb.SetText(gmTools.coalesce(self.data['suburb'], '')) 913 self._PRW_urb.SetText(self.data['urb'], data = self.data['urb']) 914 self._PRW_state.SetText(self.data['l10n_region'], data = self.data['code_region']) 915 self._PRW_country.SetText(self.data['l10n_country'], data = self.data['code_country']) 916 917 if self.__type_is_editable: 918 self._PRW_type.SetFocus() 919 else: 920 self._TCTRL_number.SetFocus()
921 #----------------------------------------------------------------
922 - def _refresh_from_existing(self):
923 if self.__type_is_editable: 924 self._PRW_type.SetText(self.data['l10n_address_type']) 925 else: 926 self._PRW_type.SetText('', None) 927 self._PRW_zip.SetText(self.data['postcode']) 928 self._PRW_street.SetText(self.data['street'], data = self.data['street']) 929 self._TCTRL_notes_street.SetValue(gmTools.coalesce(self.data['notes_street'], '')) 930 self._TCTRL_number.SetValue(self.data['number']) 931 self._TCTRL_subunit.SetValue(gmTools.coalesce(self.data['subunit'], '')) 932 self._PRW_suburb.SetText(gmTools.coalesce(self.data['suburb'], '')) 933 self._PRW_urb.SetText(self.data['urb'], data = self.data['urb']) 934 self._PRW_state.SetText(self.data['l10n_region'], data = self.data['code_region']) 935 self._PRW_country.SetText(self.data['l10n_country'], data = self.data['code_country']) 936 self._TCTRL_notes_subunit.SetValue(gmTools.coalesce(self.data['notes_subunit'], '')) 937 938 if self.__type_is_editable: 939 self._PRW_type.SetFocus() 940 else: 941 self._PRW_zip.SetFocus()
942 #---------------------------------------------------------------- 943 # event handling 944 #----------------------------------------------------------------
945 - def _on_zip_set(self):
946 """Set the street, town, region and country according to entered zip code.""" 947 zip_code = self._PRW_zip.GetValue() 948 if zip_code.strip() == '': 949 self._PRW_street.unset_context(context = 'zip') 950 self._PRW_urb.unset_context(context = 'zip') 951 self._PRW_state.unset_context(context = 'zip') 952 self._PRW_country.unset_context(context = 'zip') 953 else: 954 self._PRW_street.set_context(context = 'zip', val = zip_code) 955 self._PRW_urb.set_context(context = 'zip', val = zip_code) 956 self._PRW_state.set_context(context = 'zip', val = zip_code) 957 self._PRW_country.set_context(context = 'zip', val = zip_code)
958 #----------------------------------------------------------------
959 - def _on_country_set(self):
960 """Set the regions according to entered country.""" 961 country = self._PRW_country.GetData() 962 if country is None: 963 self._PRW_state.unset_context(context = 'country') 964 else: 965 self._PRW_state.set_context(context = 'country', val = country)
966 #---------------------------------------------------------------- 967 # properties 968 #----------------------------------------------------------------
969 - def _get_type_is_editable(self):
970 return self.__type_is_editable
971
972 - def _set_type_is_editable(self, type_is_editable):
973 self.__type_is_editable = type_is_editable 974 self._PRW_type.Enable(type_is_editable) 975 self._PRW_type.Show(type_is_editable) 976 self._LBL_type.Show(type_is_editable)
977 978 type_is_editable = property(_get_type_is_editable, _set_type_is_editable) 979 #----------------------------------------------------------------
980 - def _get_address_is_searchable(self):
981 return self.__address_is_searchable
982
983 - def _set_address_is_searchable(self, address_is_searchable):
984 # FIXME: always set to FALSE when self.mode == 'new' ? 985 self.__address_is_searchable = address_is_searchable 986 self._PRW_address_searcher.Enable(address_is_searchable) 987 self._PRW_address_searcher.Show(address_is_searchable) 988 self._LBL_search.Show(address_is_searchable)
989 990 address_is_searchable = property(_get_address_is_searchable, _set_address_is_searchable) 991 #----------------------------------------------------------------
992 - def _get_address(self):
993 return self.data
994
995 - def _set_address(self, address):
996 self.data = address
997 998 address = property(_get_address, _set_address)
999 1000 #============================================================
1001 -class cAddressMatchProvider(gmMatchProvider.cMatchProvider_SQL2):
1002
1003 - def __init__(self):
1004 1005 query = """ 1006 SELECT * FROM ( 1007 (SELECT 1008 pk_address AS data, 1009 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1010 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1011 || postcode || ', ' 1012 || code_country 1013 ) AS field_label, 1014 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1015 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1016 || postcode || ', ' 1017 || l10n_region || ', ' 1018 || l10n_country 1019 || coalesce(', ' || notes_street, '') 1020 || coalesce(', ' || notes_subunit, '') 1021 ) AS list_label 1022 FROM 1023 dem.v_address 1024 WHERE 1025 street %(fragment_condition)s 1026 1027 ) UNION ( 1028 1029 SELECT 1030 pk_address AS data, 1031 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1032 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1033 || postcode || ', ' 1034 || code_country 1035 ) AS field_label, 1036 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1037 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1038 || postcode || ', ' 1039 || l10n_region || ', ' 1040 || l10n_country 1041 || coalesce(', ' || notes_street, '') 1042 || coalesce(', ' || notes_subunit, '') 1043 ) AS list_label 1044 FROM 1045 dem.v_address 1046 WHERE 1047 postcode_street %(fragment_condition)s 1048 1049 ) UNION ( 1050 1051 SELECT 1052 pk_address AS data, 1053 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1054 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1055 || postcode || ', ' 1056 || code_country 1057 ) AS field_label, 1058 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1059 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1060 || postcode || ', ' 1061 || l10n_region || ', ' 1062 || l10n_country 1063 || coalesce(', ' || notes_street, '') 1064 || coalesce(', ' || notes_subunit, '') 1065 ) AS list_label 1066 FROM 1067 dem.v_address 1068 WHERE 1069 postcode_urb %(fragment_condition)s 1070 ) 1071 ) AS matching_addresses 1072 ORDER BY list_label 1073 LIMIT 50""" 1074 1075 gmMatchProvider.cMatchProvider_SQL2.__init__(self, queries = query) 1076 1077 self.setThresholds(2, 4, 6) 1078 # self.word_separators = u'[ \t]+' 1079 1080 self._SQL_data2match = """ 1081 SELECT 1082 pk_address AS data, 1083 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1084 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1085 || postcode || ', ' 1086 || code_country 1087 ) AS field_label, 1088 (street || ' ' || number || coalesce(' (' || subunit || ')', '') || ', ' 1089 || urb || coalesce(' (' || suburb || ')', '') || ', ' 1090 || postcode || ', ' 1091 || l10n_region || ', ' 1092 || l10n_country 1093 || coalesce(', ' || notes_street, '') 1094 || coalesce(', ' || notes_subunit, '') 1095 ) AS list_label 1096 FROM 1097 dem.v_address 1098 WHERE 1099 pk_address = %(pk)s 1100 """
1101 1102 #============================================================
1103 -class cAddressPhraseWheel(gmPhraseWheel.cPhraseWheel):
1104
1105 - def __init__(self, *args, **kwargs):
1106 1107 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1108 self.matcher = cAddressMatchProvider() 1109 self.SetToolTip(_('Select an address by postcode or street name.')) 1110 self.selection_only = True 1111 self.__address = None 1112 self.__old_pk = None
1113 #--------------------------------------------------------
1114 - def _get_data_tooltip(self):
1115 adr = self.address 1116 if adr is None: 1117 return None 1118 return '\n'.join(adr.format())
1119 #--------------------------------------------------------
1120 - def _data2instance(self):
1121 return gmDemographicRecord.cAddress(aPK_obj = self.GetData())
1122 #-------------------------------------------------------- 1123 # properties 1124 #--------------------------------------------------------
1125 - def __get_address(self):
1126 pk = self.GetData() 1127 if pk is None: 1128 self.__address = None 1129 return None 1130 if self.__address is None: 1131 self.__old_pk = pk 1132 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1133 else: 1134 if pk != self.__old_pk: 1135 self.__old_pk = pk 1136 self.__address = gmDemographicRecord.cAddress(aPK_obj = pk) 1137 return self.__address
1138
1139 - def __set_address(self, address):
1140 if address is None: 1141 self.__old_pk = None 1142 self.__address = None 1143 self.SetText('', None) 1144 return 1145 if isinstance(address, (gmDemographicRecord.cAddress, gmDemographicRecord.cPatientAddress)): 1146 self.__old_pk = address['pk_address'] 1147 self.__address = address 1148 pk = self.__old_pk 1149 else: 1150 self.__old_pk = None 1151 self.__address = None 1152 pk = address 1153 match = self.matcher.get_match_by_data(data = pk) 1154 if match is None: 1155 raise ValueError('[%s]: cannot match address [#%s]' % (self.__class__.__name__, pk)) 1156 self.SetText(match['field_label'], pk)
1157 1158 address = property(__get_address, __set_address)
1159 1160 #-------------------------------------------------------- 1161 # def __get_person_address(self): 1162 # pk = self.GetData() 1163 # if pk is None: 1164 # self.__address = None 1165 # return None 1166 # if self.__address is None: 1167 # self.__old_pk = pk 1168 # self.__address = gmDemographicRecord.cPatientAddress(aPK_obj = pk xxxxxxxxx) 1169 # else: 1170 # if pk != self.__old_pk: 1171 # self.__old_pk = pk 1172 # self.__address = gmDemographicRecord.cPatientAddress(aPK_obj = pk xxxxxxxxxxx) 1173 # return self.__address 1174 # 1175 # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 1176 # must have access to pk_identity 1177 # person_address = property(__get_person_address, lambda x:x) 1178 1179 #============================================================ 1180 from Gnumed.wxGladeWidgets import wxgAddressSelectionDlg 1181
1182 -class cAddressSelectionDlg(wxgAddressSelectionDlg.wxgAddressSelectionDlg):
1183
1184 - def __init__(self, *args, **kwargs):
1185 wxgAddressSelectionDlg.wxgAddressSelectionDlg.__init__(self, *args, **kwargs) 1186 self._PRW_address_searcher.SetFocus()
1187 #--------------------------------------------------------
1188 - def _get_address(self):
1189 return self._PRW_address_searcher.address
1190 1191 address = property(_get_address, lambda x:x) 1192 #--------------------------------------------------------
1193 - def _set_message(self, msg):
1194 self._LBL_msg.SetLabel(msg)
1195 1196 message = property(lambda x:x, _set_message) 1197 #--------------------------------------------------------
1198 - def _on_manage_addresses_button_pressed(self, event):
1199 event.Skip() 1200 manage_addresses(parent = self)
1201 1202 #================================================================ 1203 # main 1204 #---------------------------------------------------------------- 1205 if __name__ == '__main__': 1206 1207 if len(sys.argv) < 2: 1208 sys.exit() 1209 1210 if sys.argv[1] != 'test': 1211 sys.exit() 1212 1213 from Gnumed.pycommon import gmI18N 1214 gmI18N.activate_locale() 1215 gmI18N.install_domain() 1216 from Gnumed.business import gmPersonSearch 1217 1218 #--------------------------------------------------------
1219 - def test_country_prw():
1220 app = wx.PyWidgetTester(size = (200, 50)) 1221 pw = cCountryPhraseWheel(app.frame, -1) 1222 app.frame.Show(True) 1223 app.MainLoop()
1224 #--------------------------------------------------------
1225 - def test_region_prw():
1226 app = wx.PyWidgetTester(size = (200, 50)) 1227 pw = cStateSelectionPhraseWheel(app.frame, -1) 1228 pw.set_context(context = 'zip', val = '04318') 1229 pw.set_context(context = 'country', val = 'Deutschland') 1230 app.frame.Show(True) 1231 app.MainLoop()
1232 #--------------------------------------------------------
1233 - def test_zipcode_prw():
1234 app = wx.PyWidgetTester(size = (200, 50)) 1235 pw = cZipcodePhraseWheel(app.frame, -1) 1236 app.frame.Show(True) 1237 app.MainLoop()
1238 #--------------------------------------------------------
1239 - def test_street_prw():
1240 app = wx.PyWidgetTester(size = (200, 50)) 1241 pw = cStreetPhraseWheel(app.frame, -1) 1242 # pw.set_context(context = u'zip', val = u'04318') 1243 app.frame.Show(True) 1244 app.MainLoop()
1245 #--------------------------------------------------------
1246 - def test_suburb_prw():
1247 app = wx.PyWidgetTester(size = (200, 50)) 1248 pw = cSuburbPhraseWheel(app.frame, -1) 1249 app.frame.Show(True) 1250 app.MainLoop()
1251 #--------------------------------------------------------
1252 - def test_urb_prw():
1253 app = wx.PyWidgetTester(size = (200, 50)) 1254 pw = cUrbPhraseWheel(app.frame, -1) 1255 app.frame.Show(True) 1256 pw.set_context(context = 'zip', val = '04317') 1257 app.MainLoop()
1258 #--------------------------------------------------------
1259 - def test_address_type_prw():
1260 app = wx.PyWidgetTester(size = (200, 50)) 1261 pw = cAddressTypePhraseWheel(app.frame, -1) 1262 app.frame.Show(True) 1263 app.MainLoop()
1264 #--------------------------------------------------------
1265 - def test_address_prw():
1266 app = wx.PyWidgetTester(size = (200, 50)) 1267 pw = cAddressPhraseWheel(app.frame, -1) 1268 app.frame.Show(True) 1269 app.MainLoop()
1270 #--------------------------------------------------------
1271 - def test_address_ea_pnl():
1272 app = wx.PyWidgetTester(size = (600, 400)) 1273 app.SetWidget(cAddressEditAreaPnl, address = gmDemographicRecord.cAddress(aPK_obj = 1)) 1274 app.MainLoop()
1275 #-------------------------------------------------------- 1276 #test_address_type_prw() 1277 #test_zipcode_prw() 1278 #test_region_prw() 1279 #test_street_prw() 1280 #test_suburb_prw() 1281 #test_country_prw() 1282 #test_urb_prw() 1283 #test_address_ea_pnl() 1284 test_address_prw() 1285 1286 #================================================================ 1287