## PropFinder.sml ## 21 April 2004 ## Tool script that creates a dialog to conduct property searches ## by address and by property owner for the Lincoln property database. ## The tool also provides three alternative left-mouse button actions: ## 1) zoom in to the mouse location, 2) zoom out from the mouse location ## and 3) select property parcel and show that property's page on the ## county assessor's website. ## Results of address or name searches are shown on the Result List ## tabbed panel. If only one match is found the property polygon is ## automatically highlighted and the view window recenters on that ## property polygon. If more than one match is found, the user ## should select an entry from the list and press the View Property button ## to highlight and recenter on the associated parcel polygon. In either ## case, if the highlighted polygon is already in the view, the view is not ## redrawn. The View Assessor's Website Data button on the same panel shows ## the selected property's page on the county assessor's website. ## Randy Smith, MicroImages, Inc. ## Requires TNTmips v 7.0, 14 April 2004 or later # The following symbols are predefined # class GRE_VIEW View {use to access the view the tool script is attached to} # class GRE_GROUP Group {use to access the group being viewed if the script is run from a group view} # class GRE_LAYOUT Layout {use to access the layout being viewed if the script is run from a layout view} # numeric ToolIsActive Will be 0 if tool is inactive or 1 if tool is active # # The following values are also predefined and are valid when the various On...() # functions are called which deal with pointer and keyboard events. # numeric PointerX Pointer X coordinate within view in pixels # numeric PointerY Pointer Y coordinate within view in pixels # numeric ShiftPressed 1 if key being pressed or 0 if not # numeric CtrlPressed 1 if key being pressed or 0 if not # numeric LeftButtonPressed 1 if left pointer button pressed or 0 if not # numeric RightButtonPressed 1 if right pointer button pressed or 0 if not # numeric MiddleButtonPressed 1 if middle pointer button pressed or 0 if not ######################################## ### Global variable declarations ######################################## class GRE_GROUP activeGroup; class GRE_LAYER_VECTOR parcelLayer; class GRE_LAYER_RASTER orthoLayer; class VECTOR parcelVector; class RASTER orthoRaster; class GRE_VECTOR_POLYS parcelPolys; class TRANSPARM pTransparm; ## coordinate transformation parameters from screen to parcel layer class TRANSPARM lvTransparm; ## coordinate transformation parameters from parcel layer to view class RECT polyExtents, viewExtents; ## extents of polygon and view in screen coordinates numeric searchmode; # 1 if address search, 0 if name search numeric prevsearchmode; # mode for last search numeric zoomChanged; # 1 if zoom has changed since last redraw, otherwise 0 numeric i; # element number counter for polygon loop numeric count; # counter for number of property polygons found numeric numPolys; # number of polygons in parcel vector numeric matchRecList[1]; # array to hold record numbers for records matching search numeric propsArray[1]; # array to hold element numbers of polygons found numeric listcount; # number of items in result list in dialog string xmlfile$; class XMLDOC dlgdoc, listdlgdoc; # class instances for XML documents with dialog specifications class XMLNODE dlgnode, listdlgnode; # class instance for node in the XML document corresponding # to the dialog class GUI_DLG dlgwin; # class instance for the GUI dialog numeric errXML; # error value to check ingest of dialog specification numeric prevMulti; # flag for previous search result type: 1 = multiple, 0 = other string prevname$; # string variable to store owner name for comparison before next search string prevaddress$; # string variable to store address for comparison before next search class GUI_FORMDATA settings; # structure to hold values retrieved from main search dialog ## handles for dialog controls, needed to clear/reset values on close class GUI_LAYOUT_BOOK panels; class GUI_CTRL_EDIT_NUMBER editAddNum; class GUI_CTRL_EDIT_STRING editStreet, editLname, editFname, editMid; class GUI_CTRL_COMBOBOX prefixCombo, streetTypeCombo; class GUI_CTRL_EDIT_STRING statusText, searchText; class GUI_FORM_RADIOGROUP zoomSetting, mouseSetting; class GUI_CTRL_LISTBOX propList; class GUI_CTRL_PUSHBUTTON viewProperty, viewData; ################################################################################## # The following script functions will be called (if used in the script) when # the appropriate action or event occurs as described in the comments before each. # To use a function, uncomment the lines containing the 'func' definition # and ending brace '}' by removing the leftmost '#' on the line and add the # function code between the two lines. ################################################################################## ################################################################################## #### procedure called the first time the tool is activated. #### If the tool implements a dialog it should be created (but not displayed) here. ################################################################################## proc OnInitialize () { searchmode = 1; # set default search mode to address search prevMulti = 0; # reinitialize flag for previous search result type ####################################################################################### ### get screen pixel size and compute map scale for 1X view of orthophoto layer ### (ortho cell size = 0.3 m = 3000 mm); scale at 1X = cell size (mm) / pixel size (mm) ####################################################################################### numeric pixelSize = View.PixelSizeMillimeters; # screen pixel size in millimeters numeric scale1X = 300 / pixelSize; ### get handles for the parcel vector layer in the View and its polygon element set #################################################################################### activeGroup = Layout.ActiveGroup; parcelLayer = activeGroup.GetLayerByName("Parcels"); parcelLayer.NoFillWhenHighlight = 1; # don't fill highlighted polygons with highlight color parcelPolys = parcelLayer.Poly; ### get the parcel vector object in parcelLayer so its database can be accessed ############################################################################### DispGetVectorFromLayer(parcelVector, parcelLayer); numPolys = NumVectorPolys(parcelVector); ### get TRANSPARM from parcel layer object coordinates to View coordinates ### to be used with left mouse button zoom function ########################################################################### lvTransparm = View.GetTransLayerToView(parcelLayer); ############################################### #### specification in XML for main query dialog ############################################### local string xml$ = ' Zoom In to Location Zoom Out from Location View Assessor's Website Data Zoom to Property Zoom to Block Zoom to Neighborhood Keep Current Scale Any None E W N S NW SW Any AVE BLVD CIR CT DR LN RD ST BAY BND BYP HOLW HWY MALL PKWY PL PLZ PP TER TRL VAL '; ################################################################ ### parse XML text for main search dialog into memory; ### return an error code (number < 0) if there are syntax errors ################################################################ errXML = dlgdoc.Parse(xml$); if (errXML < 0) { PopupError(errXML); Exit(); } ########################################################## # get the dialog element from the parsed XML document and # show error message if the dialog element can't be found ########################################################## dlgnode = dlgdoc.GetElementByID("pSearch"); if (dlgnode == 0) { PopupMessage("Could not find dialog node in XML document"); Exit(); } ########################################################## # Set the XML dialog element as the source for the GUI_DLG # class instance we are using for the dialog window. ########################################################## dlgwin.SetXMLNode(dlgnode); dlgwin.CreateModeless(View.InfoForm); ### create as modeless dialog with ### View window status line as parent ################################################################################ ### get handles for dialog controls using their ID's in the dialog specification ################################################################################ statusText = dlgwin.GetCtrlByID("statusText"); searchText = dlgwin.GetCtrlByID("searchText"); zoomSetting = dlgwin.GetCtrlByID("zoomSetting"); mouseSetting = dlgwin.GetCtrlByID("mouseSetting"); propList = dlgwin.GetCtrlByID("propList"); panels = dlgwin.GetPaneByID("panels"); viewProperty = dlgwin.GetCtrlByID("viewProperty"); viewData = dlgwin.GetCtrlByID("viewData"); ### address controls editAddNum = dlgwin.GetCtrlByID("addnumfld"); prefixCombo = dlgwin.GetCtrlByID("comboPrefix"); editStreet = dlgwin.GetCtrlByID("streetnamefld"); streetTypeCombo = dlgwin.GetCtrlByID("comboType"); ### name controls editLname = dlgwin.GetCtrlByID("lastnamefld"); editFname = dlgwin.GetCtrlByID("firstnamefld"); editMid = dlgwin.GetCtrlByID("midintfld"); } # end of OnInitialize ############################################################################# ### Called when tool is activated. ### If the tool implements a dialog it should be "managed" (displayed) here. ############################################################################# proc OnActivate () { panels.SetActivePage(0); ### set Settings panel to be active (on top) dlgwin.Open(); zoomChanged = 1; } # end of OnActivate ############################################################################ ### Called when tool is deactivated (usually when switching to another tool). ### If the tool implements a dialog it should be "unmanaged" (hidden) here. ############################################################################ proc OnDeactivate () { ### clear/reset controls on main search dialog to default states statusText.ClearValue(0); editAddNum.ClearValue(0); prefixCombo.SetSelectedItemIndex(0); editStreet.ClearValue(0); streetTypeCombo.SetSelectedItemIndex(0); editLname.ClearValue(0); editFname.ClearValue(0); editMid.ClearValue(0); if (propList.GetCount() > 0) then ### clear property list propList.DeleteAllItems(); dlgwin.Close(0); # close search dialog without notifying, so OnClose() # will not be called (allows user to switch tools without # having OnClose() override by setting the default tool } # end of OnDeactivate ############################################################################# ### procedure called when Help button on dialog is pressed ############################################################################# proc OnHelp () { local string url$; url$ = "file://" + _context.ScriptDir + "/" + "help.htm"; RunAssociatedApplication(url$); } ############################################################## ### procedure called when the Address Search page is activated ############################################################## proc OnAddressActive () { searchmode = 1; statusText.ClearValue(0); editAddNum.SetFocus(); } # end of OnAddressActive ############################################################ ### procedure called when the Name Search page is activated ############################################################ proc OnNameActive () { searchmode = 0; statusText.ClearValue(0); editLname.SetFocus(); } # end of OnNameActive ########################################################### ### Called when user presses 'left' pointer/mouse button. ########################################################### proc OnLeftButtonPress () { local string mouseSetting$; local class POINT2D clickPt; ### coordinates for click position ### get setting for left mouse button mode from dialog mouseSetting$ = mouseSetting.GetValueStr(); ### get cursor position in screen coordinates clickPt.x = PointerX; clickPt.y = PointerY; ### get TRANSPARM from screen coordinates to parcel vector layer coordinates ### for current view position and transform point to layer coordinates ############################################################################ pTransparm = View.GetTransLayerToScreen(parcelLayer, 1); clickPt = pTransparm.ConvertPoint2DFwd(clickPt); if (mouseSetting$ == "navigate") ### select polygon and go to its page on Assesor's website { local numeric polynum; ### element number of the polygon clicked on local string url$; ### string containing the URL to pass to the browser ### find the polygon clicked on and highlight it in the view polynum = FindClosestPoly(parcelVector, clickPt.x, clickPt.y, GetLastUsedGeorefObject(parcelVector) ); parcelPolys.HighlightSingle(polynum); url$ = parcelVector.poly[polynum].ca123103.P_I_D$; RunAssociatedApplication(url$); } else if (mouseSetting$ == "zoomIn") ### zoom in to cursor position { ### convert click point from vector layer to view coordinates ### using TRANSPARM computed when tool is initialized ############################################################# clickPt = lvTransparm.ConvertPoint2DFwd(clickPt); View.DisableRedraw = 1; View.Center = clickPt; ### recenter View on click point View.ZoomIn(2,1); ### zoom in 2X View.DisableRedraw = 0; View.Redraw(); ### redraw view } else if (mouseSetting$ == "zoomOut") ### zoom out from cursor position { ### convert click point from vector layer to view coordinates ### using TRANSPARM computed when tool is initialized ############################################################# clickPt = lvTransparm.ConvertPoint2DFwd(clickPt); View.DisableRedraw = 1; View.Center = clickPt; ### recenter View on click point View.ZoomOut(2,1); ### zoom out 2X View.DisableRedraw = 0; View.Redraw(); ### redraw view } } # end of OnLeftButtonPress ########################################################### ### procedure called when zoom setting is changed in dialog ########################################################### proc OnZoomChanged () { zoomChanged = 1; } # end of OnZoomChanged ########################################################################## ### procedure to highlight, pan, and zoom to the selected property polygon ########################################################################## proc DoZoom (numeric element) { local numeric vwScale; local string zoom$; ####################################################### ### check if highlighted polygon is already in the view ####################################################### ### get extents of highlighted polygon from Internal database table as min and max points local CLASS POINT2D minPt, maxPt; minPt.x = parcelVector.poly[element].Internal.MinX; minPt.y = parcelVector.poly[element].Internal.MinY; maxPt.x = parcelVector.poly[element].Internal.MaxX; maxPt.y = parcelVector.poly[element].Internal.MaxY; ### set up RECT from polygon extents polyExtents.pt1 = minPt; polyExtents.pt2 = maxPt; ### get extents of View in screen coordinates ### upper left corner of view pane = 0,0, so lower right coordinates = width, height local CLASS POINT2D UpLeft, LowRight; LowRight.x = View.Width; LowRight.y = View.Height; ### set up RECT from view extents in screen coordinates viewExtents.pt1 = UpLeft; viewExtents.pt2 = LowRight; if (zoomChanged == 0) ### zoom setting hasn't been changed; don't need to check it { ################################################################################# ### get TRANSPARM from screen coordinates to parcel vector layer coordinates for ### current view position and convert extents RECT to layer coordinates ################################################################################# pTransparm = View.GetTransLayerToScreen(parcelLayer, 1); viewExtents = pTransparm.ConvertRectFwd(viewExtents); ############################################################################### ### check if parcel polygon is in the current view ############################################################### if (viewExtents.ContainsRect(polyExtents) ) ### don't need to redraw view { View.SetMessage(""); ### clear View window message line and status bar View.StatusBarClear(); } else { View.DisableRedraw = 1; ################################################################################# ### if parcel polygon won't fit in view at this scale, then zoom to polygon extents ### before redrawing. ################################################################################# if ( (polyExtents.GetHeight() > viewExtents.GetHeight() ) || (polyExtents.GetWidth() > viewExtents.GetWidth() ) ) { parcelLayer.ZoomToActiveElement(); parcelLayer.UnhighlightAllElements(); ### needed to force redraw zoomChanged = 1; } else # parcel polygon fits in view; pan to polygon and set current map scale { vwScale = View.CurrentMapScale; # get current view scale parcelLayer.ZoomToActiveElement(); # zooms to polygon extents, changing view scale View.CurrentMapScale = vwScale; # reset previous view scale parcelLayer.UnhighlightAllElements(); # needed to force redraw } ################################################################### ### re-enable redraw, redraw the view, and highlight the polygon ################################################################### View.DisableRedraw = 0; ViewRedraw(View); parcelPolys.HighlightSingle(element); } } # end (if zoomChanged == 0) else ### zoom setting has changed { ### get current setting for Zoom radiogroup zoom$ = zoomSetting.GetValueStr(); View.DisableRedraw = 1; if (zoom$ == "property") ## zoom to 1X but don't redraw yet { vwScale = scale1X; } else ### set vwScale value from Zoom radiogroup setting { if (zoom$ == "current") then vwScale = ViewGetMapScale(View); else if (zoom$ == "block") then vwScale = 3200; else if (zoom$ == "neighborhd") then vwScale = 8000; } ### Set View scale, zoom / recenter on active polygon but don't redraw yet parcelLayer.ZoomToActiveElement(); ViewSetMapScale(View, vwScale); parcelLayer.UnhighlightAllElements(); ##################################################################################### ### get TRANSPARM from screen coordinates to parcel vector layer coordinates for the ### new view position and view scale and convert extents RECT to layer coordinates ##################################################################################### pTransparm = View.GetTransLayerToScreen(parcelLayer, 1); viewExtents = pTransparm.ConvertRectFwd(viewExtents); ################################################################################## ### if parcel polygon won't fit in view at new zoom, then zoom to polygon extents ### before redrawing. ################################################################################### if ( (polyExtents.GetHeight() > viewExtents.GetHeight() ) || (polyExtents.GetWidth() > viewExtents.GetWidth() ) ) { parcelPolys.HighlightSingle(element); parcelLayer.ZoomToActiveElement(); parcelLayer.UnhighlightAllElements(); zoomChanged = 1; } else zoomChanged = 0; ################################################################## ### re-enable redraw, redraw the view, and highlight the polygon ################################################################## View.DisableRedraw = 0; ViewRedraw(View); parcelPolys.HighlightSingle(element); } # end else zoom setting has changed } # end of DoZoom ################################################################# ### procedure to get owner name and address string for parcel ################################################################# func string GetPropString (numeric propNum) { local string name$, num$, dir$, stname$, type$, aptnum$, sub$; local string liststr$; name$ = parcelVector.poly[propNum].ca123103.OWNER$; num$ = parcelVector.poly[propNum].ca123103.SIT_ST_NUM$; dir$ = parcelVector.poly[propNum].ca123103.SIT_ST_DIR$; stname$ = parcelVector.poly[propNum].ca123103.SIT_ST_NAM$; type$ = parcelVector.poly[propNum].ca123103.SIT_ST_TYP$; sub$ = parcelVector.poly[propNum].ca123103.SIT_ST_SUB$; aptnum$ = parcelVector.poly[propNum].ca123103.SIT_APT_NU$; liststr$ = sprintf( "%s: %s %s %s %s %s%s", name$, num$, dir$, stname$, type$, sub$, aptnum$ ); return liststr$; } # end of GetPropString ################################################################# ### procedure called when search finds no matching parcel polygon ################################################################# proc OnFoundNone () { View.SetMessage(""); ### clear View window message and status bar (no redraw will occur View.StatusBarClear(); ### to do this automatically) View.NoBlankScreen = 1; ### don't redraw things that don't need to be redrawn parcelLayer.UnhighlightAllElements(); ### unhighlight any currently highlighted parcel polygons View.NoBlankScreen = 0; viewProperty.SetEnabled(0); ### disable the View Property push-button viewData.SetEnabled(0); ### disable the View Assessor's Website Data button ### update Search Result field in dialog statusText.SetValue("No properties found matching these criteria", 0); } # end of OnFoundNone ##################################################################################### ### procedure called when one or more property polygons meet the search criteria. ##################################################################################### proc OnFound (numeric propCount) { if (propList.GetCount() > 0 ) then ### clear property list propList.DeleteAllItems(); local string liststr$; local numeric j, k, propNum; for j = 1 to propCount { liststr$ = GetPropString(propsArray[j]); ### get name / address string for parcel propList.AddItem(liststr$); ### add this string to the list } # end of for j = 1 to propCount if (propCount == 1) ### only one parcel polygon found { statusText.SetValue("One property found.", 0); ### update status field in dialog propList.SetSelectedItemIndex(0); ### set the single list item to be selected viewProperty.SetEnabled(0); ### disable the View Property push-button viewData.SetEnabled(1); ### enable the View Assessor's Website Data button propNum = propsArray[1]; parcelPolys.HighlightSingle(propNum); ### highlight element to make it active in view DoZoom(propNum); ### pan / zoom to highlighted element } else ### more than one polygon found { View.NoBlankScreen = 1; ### don't redraw entire view parcelLayer.UnhighlightAllElements(1); ### unhighlight any currently highlighted parcel polygon View.NoblankScreen = 0; statusText.SetValue( sprintf("%d properties found.", propCount) , 0); ### update status field in dialog View.SetMessage(""); ## blank the View status message and bar View.StatusBarClear(); viewProperty.SetEnabled(0); ### enable the View Property push-button viewData.SetEnabled(0); ### enable the View Assessor's Website Data button } panels.SetActivePage(3); ### set Result List panel to be active (on top) } #################################################################### ### procedure called when a property is selected in the Result List #################################################################### proc OnPropListSelect () { viewData.SetEnabled(1); viewProperty.SetEnabled(1); } ###################################################################################### ### procedure called when the View Polygon button on the Result List panel is pressed. ###################################################################################### proc OnViewPoly () { local numeric propNumber; # polyon element number of property selected from the Property List ### get the value from the property list (string) and convert to number (polygon element number) propNumber = propsArray[propList.GetSelectedItemIndex() + 1]; View.DisableRedraw = 1; parcelPolys.HighlightSingle(propNumber); ### highlight element to make it active in view View.DisableRedraw = 0; DoZoom(propNumber); ### pan / zoom to highlighted element } ############################################################ ### procedure called when View Assessor's Website Data ### button on dialog is pressed ############################################################ proc OnViewData () { local numeric propNumber; # polyon element number of property selected from the Property List local string url$; ### get the value from the property list (string) and convert to number (polygon element number) propNumber = propsArray[propList.GetSelectedItemIndex() + 1]; url$ = parcelVector.poly[propNumber].ca123103.P_I_D$; RunAssociatedApplication(url$); } ####################################################################### ### procedure called to update status on dialog and view for new search ####################################################################### proc OnNewSearch() { statusText.ClearValue(0); ## clear search status field on dialog if (propList.GetCount() > 0) then propList.DeleteAllItems(); ### clear property list ### Set message at bottom of View window View.SetMessage("Searching for properties..."); } ############################################################################# ### procedure to get element numbers of polygons attached to matching records ### and take action depending on whether 0, 1, or >1 elements found ############################################################################# proc GetPolygons () { ###################################################################### ### We now have a list of records. Find the elements that have those ### records attached. ###################################################################### if (searchmode == 1) then count = TableGetRecordListElementList(parcelVector.poly.ParcelAddress, matchRecList, count, propsArray); else if (searchmode == 0) then count = TableGetRecordListElementList(parcelVector.poly.OwnerName, matchRecList, count, propsArray); if (count == 0) ### no properties found { OnFoundNone(); } else ### one or more properties found { OnFound(count); } } # end of GetPolygons ################################################################# # called when Search button on Property Search dialog is pressed ################################################################# proc OnSearch () { ### get control settings (values) from dialog and store in GUI_FORMDATA settings = dlgwin.GetValues(); local numeric possibleRecList[1]; local numeric numRecords, record; ############################################# ### address search; components of address are ### in separate fields in the database ############################################# if (searchmode == 1) { ############################################## ### declare local string variables for address ############################################## local string addnum$; # address number as string local string streetname$; # street name local string prefix$; # street direction prefix (e.g. "S", "W") local string prefixtext$; # text for street prefix in search text shown in dialog local string streettype$; # street type (e.g. "ST", "RD"); local string streettypetext$; # text for street type in search text shown in dialog local string fulladdress$; # full address local numeric streetasnum; # number returned from street name string (0 if not numbered street) ####################################### ### read address values from formdata; ####################################### ### get address number and convert to string (to match database) addnum$ = NumToStr( int( settings.GetValueNum("addnumfld") ) ); if (addnum$ == "0") then addnum$ = ""; ### get street direction prefix prefix$ = settings.GetValueStr("comboPrefix"); if (prefix$ == "NONE") then prefix$ = ""; ### get street name and change to upper case (to match database); ### remove suffixes such as "nd" and "st" following the number ### in name of numbered street; streetname$ = toupper$(settings.GetValueStr("streetnamefld") ); streetasnum = StrToNum(streetname$); # returns number at beginning of string or 0 if none if ( streetasnum > 0) then streetname$ = NumToStr(streetasnum); # convert street number back to string ### get street type setting streettype$ = settings.GetValueStr("comboType"); ########################################################################################### ### concatenate address components to full address string, omitting empty strings ########################################################################################## if (prefix$ == "ANY") then prefixtext$ = "\"Any\""; else prefixtext$ = prefix$; if (streettype$ == "ANY") then streettypetext$ = "\"Any\""; else streettypetext$ = streettype$; if (prefix$ == "") then fulladdress$ = sprintf("%s %s %s", addnum$, streetname$, streettypetext$); else fulladdress$ = sprintf("%s %s %s %s", addnum$, prefixtext$, streetname$, streettypetext$); ######################################################### ### don't search if no number and street name are entered ######################################################### if ( (addnum$ == "") && (streetname$ == "") ) { statusText.SetValue("Please enter an address number and street.", 0); } ################################################################################# ### if full address is same as previous, abort search and reshow previous results ################################################################################# else if ( (fulladdress$ == prevaddress$) && (prevsearchmode == 1) ) if (count == 0) then OnFoundNone(); else OnFound(count); ################################ ### otherwise do address search ################################ else { prevsearchmode = 1; ## record current address for comparison on next search prevaddress$ = fulladdress$; OnNewSearch(); searchText.SetValue(fulladdress$, 0); ################################### ### search through parcel polygons ################################### count = 0; ### reinitialize polygon counter ResizeArrayClear(matchRecList, 0); ### reinitialize array holding numbers of matching records ResizeArrayClear(propsArray, 0); ### reinitialize array holding found polygon numbers ############################################################################## ### Narrow down the search from 99,000 records to just the records that ### match the requested SIT_ST_NUM value using a function that takes advantage ### of an index on the selected field to speed the search ############################################################################## numRecords = TableKeyFieldLookupList(parcelVector.poly.ParcelAddress, "SIT_ST_NUM", addnum$, possibleRecList); ###################################################################### ### search through the returned set of records for those that match all ### components of the requested address ###################################################################### for i = 1 to numRecords { View.SetStatusBar(i, numRecords); ### update View window's status bar record = possibleRecList[i]; if ( (parcelVector.poly.ParcelAddress[@record].SIT_ST_NUM$ == addnum$) && (parcelVector.poly.ParcelAddress[@record].SIT_ST_NAM$ == streetname$) ) { if ((prefix$ == "ANY") || (parcelVector.poly.ParcelAddress[@record].SIT_ST_DIR$ == prefix$) ) { if ((streettype$ == "ANY") || (parcelVector.poly.ParcelAddress[@record].SIT_ST_TYP$ == streettype$)) { count = count + 1; ResizeArrayPreserve(matchRecList, count + 1); ### increase array size for polygon found matchRecList[count] = record; ### add polygon number to array } } } } ### call procedure to get polygons corresponding to matching records GetPolygons(); } # end else [new search] } # end if (searchmode == 1) #################################################################### ### owner name search; entire name(s) is in single field in database #################################################################### else if (searchmode == 0) { # string variables for owner name components from form local string lastname$, firstname$, middle$; local string firstmid$; # concatenation of first name and middle initial local string fullname$; # full name string (last, firstmid) local numeric firstmidlength; # length of concatenated first name / middle initial local numeric numTokens; # number of tokens in owner name (delimited by space) local numeric j; # counter for looping through tokens in name local numeric name_in; # flag indicating entered first name / middle initial begins one of the name tokens local class STRINGLIST tokenList; # stringlist containing tokens from name ############################################################ ### read name values from formdata and set all to upper case ############################################################ lastname$ = toupper$(settings.GetValueStr("lastnamefld") ); firstname$ = toupper$(settings.GetValueStr("firstnamefld") ); middle$ = toupper$(settings.GetValueStr("midintfld") ); ### concatenate middle initial with first name if (middle$ <> "") then firstmid$ = sprintf("%s %s", firstname$, middle$); else firstmid$ = firstname$; firstmidlength = strlen(firstmid$); ### get length of string to use later in search ### concatenate lastname and firstmid to use to display search text fullname$ = sprintf("%s, %s", lastname$, firstmid$); ###################################################### ### don't search if no owner name is entered in dialog ###################################################### if (fullname$ == ", ") { statusText.SetValue("Please enter an owner name.", 0); } ####################################################################### ### if name is same as previous, abort search and show previous results ####################################################################### else if ( (fullname$ == prevname$) && (prevsearchmode == 0) ) if (count == 0) then OnFoundNone(); else OnFound(count); ############################# ### otherwise do new search ############################# else { prevsearchmode = 0; ### record name string for comparison on next search prevname$ = fullname$; searchText.SetValue(fullname$, 0); OnNewSearch(); #################################### ### search through parcel polygons #################################### count = 0; ### reinitialize polygon counter ResizeArrayClear(matchRecList, 0); ### reinitialize array holding numbers of matching records ResizeArrayClear(propsArray, 0); ### reinitialize array holding found polygon numbers; ############################################################################### ### Narrow down the search from 99,000 records to just the records in which ### the OWNER string begins with the requested last name. Uses a function ### that takes advantage of an index on the selected field to speed the search ############################################################################### numRecords = TableKeyFieldLookupList(parcelVector.poly.OwnerName, "OWNER", lastname$, possibleRecList, "StartsWith" ); ########################################################################### ### Now search the returned records for those with a match to the ### requested name ########################################################################### for i = 1 to numRecords { local numeric name_in = 0; View.SetStatusBar(i, numRecords); ### update View window's status bar record = possibleRecList[i]; ### get owner name string from database local string name$ = parcelVector.poly.OwnerName[@record].OWNER$; local class STRING teststr$; if ( GetToken(name$, ",", 1) == lastname$) ### check for exact match with last name (not just starts with) { numTokens = NumberTokens(name$, ",&"); ### number of tokens in owner name with "," and "&" as delimiters for j = 2 to numTokens ### loop through tokens following last name { teststr$ = GetToken(name$, ",&", j); teststr$.remove(0, 0); ### remove leading space from test string if ( left$( teststr$, firstmidlength) == firstmid$) then name_in = 1; } } if (name_in == 1) { count = count + 1; ResizeArrayPreserve(matchRecList, count + 1); ### increase array size for polygon found matchRecList[count] = record; ### add polygon number to array } } ### call procedure to get polygons corresponding to matching records GetPolygons(); } # end else do new search } # end else if (searchmode == 0) } # end OnSearch ################################################################### ### called when the Property Search dialog is closed by the Cancel, ### OK, or X Windows "X" button ################################################################### proc OnClose() { dlgwin.Close(1); View.SetDefaultTool(); # switch to default tool on the View tool bar }