/*---------------- FILE HEADER --------------------------------------- This file is part of Geoide. Copyright (C) 2005-2006 by: IDgis B.V. http://www.idgis.nl This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact: Herman Assink IDgis bv P.O. Box 15 7450 AA Holten The Netherlands E-Mail: herman.assink@idgis.nl * @version 1.4.0 * @author IDgis team * ------------------------------------------------------------------------*/ import nl.idgis.giclient.gis.Layer; import nl.idgis.giclient.gis.GILayer; import nl.idgis.giclient.io.XMLServer; import nl.idgis.giclient.gis.Feature; import nl.idgis.giclient.webserviceconnector.giconnector.GIConnector; import nl.idgis.giclient.webserviceconnector.wfsconnector.WFSConnector; import nl.idgis.giclient.webserviceconnector.wfsconnector.Property; import nl.idgis.giclient.webserviceconnector.wfsconnector.FeatureType; import nl.idgis.giclient.synch.SynchSocket; import nl.idgis.giclient.geoma.Geometry; import nl.idgis.giclient.geoma.GMLFactory; import nl.idgis.giclient.filterencoding.SpatialOperation; import nl.idgis.giclient.filterencoding.ComplexFilter; import nl.idgis.giclient.filterencoding.OperationDefines; import nl.idgis.giclient.io.XMLResponse; import nl.idgis.giclient.geoma.Envelope; import nl.idgis.giclient.util.XMLTools; import nl.idgis.giclient.geoma.NullGeometry; import nl.idgis.giclient.util.SynchListener; import nl.idgis.giclient.util.ArrayTools; import nl.idgis.giclient.gis.LayerSession; import nl.idgis.giclient.io.XMLResponseListener; import nl.idgis.giclient.event.StateEventDispatcher; import nl.idgis.giclient.event.StateEventListener; import nl.idgis.giclient.event.StateEvent; import nl.idgis.giclient.event.ChangeEvent; import nl.idgis.giclient.gis.Column; import nl.idgis.giclient.util.Strings; class nl.idgis.giclient.gis.SelectableLayer extends GILayer implements XMLResponseListener { static var FILTER:Number = 0; static var SELECT:Number = 1; static var SUB_SELECT:Number = 2; static var CURRENT:Number = 3; static var NEARBY:Number = 4; static var SELECT_AND_CURRENT:Number = 5; static var VERIFICATION:Number = 0; static var PROPERTIES:Number = 1; static var READY:Number = 0; static var WAITING:Number = 1; var wfsConnector:WFSConnector = null; private var undoStack:Array = null; private var filteredFeatures:Array = null; private var selectedFeatures:Array = null; private var currentFeature:Feature = null; private var templateFeature:Feature = null; private var nearbyFeatures:Array = null; private var layerSessions:Array = null; private var loadedFeatures:Array = null; private var addedFeatureIDIndex:Number = 1; private var currentFeatureIDIndex:Number = -1; private var featureType:FeatureType = null; private var currentFilter:ComplexFilter = null; private var editing:Number = -1; private var editingMessage:String = null; private var columns:Array = null; private var geometryType:String = null; private var columnValues:Object = null; private var stateEventDispatcher:StateEventDispatcher = null; private var hyperlinkColumn:String = null; private var annotationColumn:String = null; private var ownerRoles:Array = null; private var objectOwnerProperty:String = null; function SelectableLayer(connector:GIConnector, name:String, title:String, visible:Boolean, expanded:Boolean, scales:Array, printLayerName:String, printStyle:String, superLayer:Layer, editable:Boolean, wfsURL:String, featureTypeName:String, geometryType:String, extentZoom:Boolean, dynamicLegend:Boolean) { super(connector, name, title, visible, expanded, scales, printLayerName, printStyle, superLayer, editable, featureTypeName, extentZoom, dynamicLegend); //trace(name); if(name!=null){ //super(connector, name, title, visible, expanded, printLayerName, printStyle, superLayer, editable, featureTypeName); if(wfsURL != null) { wfsConnector = WFSConnector.getInstance(wfsURL); wfsConnector.performDescribeFeatureType(featureTypeName, new SynchSocket(this, onLoadFeatureType, null)); } undoStack = new Array(); filteredFeatures = new Array(); selectedFeatures = new Array(); nearbyFeatures = new Array(); layerSessions = new Array(); columns = new Array(); this.geometryType = geometryType; columnValues = new Object(); stateEventDispatcher = new StateEventDispatcher(); } } function onLoadFeatureType(synchObject:Object):Void { featureType = FeatureType(synchObject["featureType"]); var properties:Array = featureType.getProperties(); for(var i:Number = 0; i < properties.length; i++) { var property:Property = properties[i]; var name:String = property.getName(); var column:Column = new Column(name); if(property.getType() != "gml:GeometryPropertyType") { var index:Number = name.indexOf(":"); if(index != - 1) { column.setAlias(String(name.charAt(index + 1)).toUpperCase() + name.substr(index + 2)); } else { column.setAlias(name); } column.setMandatory(property.isMandatory()); column.setType(property.getType()); columns.push(column); var obj:Object = this.getColumnItem(name); var prefix:String = obj["urlprefix"]; if(prefix != null) { column.setURLPrefix(prefix); } } } } function getFeatureType():FeatureType { return featureType; } function isSelectable():Boolean { return true; } function checkMandatoryColumns(): Boolean { var mandatoryColumns:Array = new Array(); for(var i:Number = 0; i < columns.length; i++) { var column:Column = Column(columns[i]); if(column.isMandatory()) { mandatoryColumns.push(column); } } var editingFeatures:Array = getSubSelectedFeatures(); for (var i:Number = 0; i < editingFeatures.length; i++) { var feature:Feature = Feature(editingFeatures[i]); var editingStatus:Number = feature.getEditingStatus(); if(editingStatus == Feature.ADDED || editingStatus == Feature.CHANGED || editingStatus == Feature.WAITING) { for(var j:Number = 0; j < mandatoryColumns.length; j++) { var value:String = feature.getColumnValue(Column(mandatoryColumns[j]).getPath()); if(value == null || value == "") { //editingMessage = "Mandatory column: " + this.getColumnItem(Column(mandatoryColumns[j]).getPath())["title"]; editingMessage = Strings.getFile("Geoide").getString("MandatoryColumn", {column: getColumnItem(Column(mandatoryColumns[j]).getPath())["title"]}); var current:Array = new Array(); current.push(feature.getID()); this.setCurrentFeature(current, false); stateEventDispatcher.dispatchEvent(new StateEvent(this, "SelectableLayer", StateEvent.CHANGE, "editingMessage")); return false; } } } } if(editingMessage != null) { editingMessage = null; stateEventDispatcher.dispatchEvent(new StateEvent(this, "SelectableLayer", StateEvent.CHANGE, "editingMessage")); } return true; } function setEditing(editing:Boolean, save:Boolean, selectSaved:Boolean):Void { if (isEditing() == editing) { return; } if ((!editing) && (this.editing == WAITING)) { // EXCEPTION return; } if (editing) { // From disabled to enabled. this.editing = READY; if (currentFeature != null) { currentFeature.setEditing(true); layerEventDispatcher.changeSelectedFeatures(this, false, true, false); } stateEventDispatcher.dispatchEvent(new ChangeEvent(this, "SelectableLayer", "editingStatus", null)); } else { // From enabled to disabled. if(save ? checkMandatoryColumns() : true) { currentFeatureIDIndex = -1; var currentFeatureIDIndexCounter:Number = -1; var editingFeatures:Array = getSubSelectedFeatures(); var feature:Feature = null; var editingStatus:Number = -1; var waitingFeatures:Array = new Array(); for (var i:Number = 0; i < editingFeatures.length; i++) { feature = Feature(editingFeatures[i]); editingStatus = feature.getEditingStatus(); if ((editingStatus == Feature.ADDED) || (editingStatus == Feature.CHANGED) || (editingStatus == Feature.REMOVED)) { feature.setWaiting(true); waitingFeatures.push(feature); } if(editingStatus == Feature.ADDED) { currentFeatureIDIndexCounter++; if(feature == currentFeature) { currentFeatureIDIndex = currentFeatureIDIndexCounter; } } } if (waitingFeatures.length > 0) { this.editing = WAITING; stateEventDispatcher.dispatchEvent(new ChangeEvent(this, "SelectableLayer", "editingStatus", null)); var layer:SelectableLayer = this; var synchSocket:SynchSocket = new SynchSocket(this, onLoadTransactionResponse, null); synchSocket.setSynchObjectValue("selectSaved", selectSaved != undefined ? selectSaved : true); wfsConnector.performTransaction(waitingFeatures, save, synchSocket, this, "checkMandatoryColumns"); } else { setEditingFalse(false); } } } } function onLoadTransactionResponse(synchObject:Object):Void { var selectSaved:Boolean = synchObject["selectSaved"]; var editingFeatures:Array = getSubSelectedFeatures(); for (var i:String in editingFeatures) { Feature(editingFeatures[i]).setWaiting(false); } var responseCode:String = synchObject["responseCode"]; if (responseCode == "SUCCEEDED") { setEditingFalse(true); var ids:Array = synchObject["ids"]; if(selectSaved) { setSelectedFeatures(ids, true, null); } if(currentFeatureIDIndex >= 0) { var newArray:Array = new Array(); newArray.push(ids[currentFeatureIDIndex]); setCurrentFeature(newArray, false); } refresh(); } else if (responseCode == "CANCELED") { setEditingFalse(false); } else if (responseCode == "CHECKFAILED") { editing = READY; }else { // FAILED editing = READY; stateEventDispatcher.dispatchEvent(new ChangeEvent(this, "SelectableLayer", "editingStatus", null)); } } private function setEditingFalse(succeeded:Boolean):Void { _root.apiInterpreter.beforeStopEditSession(); setFeaturesEditingFalse(getSubSelectedFeatures(), succeeded); editing = -1; editingMessage = null; stateEventDispatcher.dispatchEvent(new ChangeEvent(this, "SelectableLayer", "editingStatus", null)); stateEventDispatcher.dispatchEvent(new ChangeEvent(this, "SelectableLayer", "editingMessage", null)); undoStack = new Array(); } function isEditing():Boolean { if ((editing == READY) || (editing == WAITING)) { return true; } return false; } function addFeature(geometry:Geometry, id:String):Feature { if (editing != READY) { // EXCEPTION return null; } var feature:Feature; if (objectOwnerProperty != null && objectOwnerProperty.length > 0) { var templFeat:Feature = getTemplateFeature(); templFeat.setColumnValue(objectOwnerProperty, this.connector.getUsername()); } if(templateFeature != null) { feature = templateFeature.clone(); } else { var fId:String = id; if(fId == null) { fId = "NW_" + String(addedFeatureIDIndex++); } feature = new Feature(fId, this, featureType, false, true); } feature.setGeometry(geometry); feature.setEditing(true); selectedFeatures.push(feature); currentFeature = feature; layerEventDispatcher.changeSelectedFeatures(this, true, true, true); return feature; } function removeFeature(feature:Feature):Void { if (editing != READY) { // EXCEPTION return; } if (feature.getEditingStatus() == Feature.ADDED) { setFeaturesEditingFalse(new Array(feature), false); } else { feature.remove(); } } private function setFeaturesEditingFalse(features:Array, succeeded:Boolean):Void { var selectedChanged:Boolean = false; var editingChanged:Boolean = false; var currentChanged:Boolean = false; var feature:Feature = null; for (var i:String in features) { feature = Feature(features[i]); if (feature.isEditing()) { var editingStatus:Number = feature.getEditingStatus(); if ((editingStatus == Feature.ADDED) || (editingStatus == Feature.REMOVED) || ((!succeeded) && (editingStatus == Feature.CHANGED))) { selectedChanged = true; if (feature == currentFeature) { currentChanged = true; } doRemoveFeature(feature); // setFeatures(SELECT, new Array(welke id), true, true, null); } editingChanged = true; feature.setEditing(false); } } if (editingChanged) { layerEventDispatcher.changeSelectedFeatures(this, selectedChanged, true, currentChanged); } } function setCurrentFilter(filter:ComplexFilter):Void { this.currentFilter = filter; } function getCurrentFilter():ComplexFilter { return currentFilter; } function isFiltered():Boolean { if (currentFilter == null) { return false; } else { return false; } } function setFilteredFeatures(ids:Array, cumulatively:Boolean):Void { if(ids.length == 0){ currentFilter = null; } setFeatures(FILTER, ids, cumulatively, VERIFICATION, null); } function setSelectedFeaturesByGeometry(geometry:Geometry):Void { var gml:XML = new XML(); gml.docTypeDecl = ""; var geometryPropertyName:String = featureType.getDefaultGeometryProperty().getName(); var geometryNode:XMLNode = GMLFactory.createGeometryNode(geometryPropertyName, geometry, getSRS()); geometryNode = geometryNode.firstChild; // Removes the enclosing node. gml.appendChild(geometryNode); geometryNode.attributes["xmlns:gml"] = "http://www.opengis.net/gml"; var spOp:SpatialOperation = new SpatialOperation(OperationDefines.INTERSECTS, geometryPropertyName, gml); var complexFilter:ComplexFilter = null; var filter:ComplexFilter = new ComplexFilter(spOp,null,null,null); setSelectedFeaturesByFilter(filter); } function setSelectedFeaturesByFilter(filter:ComplexFilter):Void { var serverParams:Object = new Object(); serverParams["featureAction"] = SELECT; serverParams["responseAction"] = "SETFEATURES"; getConnector().getFeaturesByFilterForLayer(this, serverParams, this, filter); } function setFilteredFeaturesByFilter(filter:ComplexFilter):Void { var serverParams:Object = new Object(); serverParams["featureAction"] = FILTER; serverParams["responseAction"] = "SETFEATURES"; currentFilter = filter; //getConnector().getFeaturesByFilter(this, serverParams, this, filter); } /* function getFeaturesByFilter(serverParams:Object, responseHandler:Object, filter:ComplexFilter):Void{ //voeg responseHandler toe aan de serverParams if(serverParams==null){ serverParams = new Object(); } serverParams["responseHandler"] = responseHandler; //Ook rekening houden met bestaande filter op een laag var complexFilter:ComplexFilter = null; if (currentFilter!=null && currentFilter!=filter) { complexFilter = new ComplexFilter(null,currentFilter,filter,OperationDefines.AND); } else { complexFilter = filter; } var serverRequest:String = "request=GetFeature&layer=" + name; serverRequest += "&filtered=true"; var xml:XML = complexFilter.toXML("ftFiltering"); xml.docTypeDecl = ""; var xmlServer:XMLServer = new XMLServer(this.getServerURL()); xmlServer.postAndLoad(xml, this, serverRequest, serverParams); } */ /* function onLoadXMLResponse(xmlResponse:XMLResponse):Void { //Bouw een features Array op, mbv de XMLResponse var id:String = ""; var feature:Feature = null; var envelopeNode:XMLNode = null; var minNode:XMLNode = null; var maxNode:XMLNode = null; var minX:Number = -1; var minY:Number = -1; var maxX:Number = -1; var maxY:Number = -1; var envelope:Envelope = null; var featureGeometryNode:XMLNode = null; var geometryNode:XMLNode = null; var geometry:Geometry = null; loadedFeatures = new Array(); var featureNodes:Array = XMLTools.getChildNodes(name, xmlResponse.firstChild); var features:Array = this.getFeatures(); for (var i:Number = 0; i < featureNodes.length; i++) { id = XMLTools.getStringValue("fid", featureNodes[i]); //loop through the features to see if already exists feature = null; for(var j:Number = 0; j < features.length; j++) { if(id==features[j].getID()){ //feature exists feature = features[j]; } } if(feature == null){ feature = new Feature(id, this, featureType, false, true); } //parse the Envelope envelopeNode = XMLTools.getChild("ENVELOPE", featureNodes[i]); if (envelopeNode.childNodes.length == 0) { envelope = new NullGeometry(); } else { minNode = XMLTools.getChild("MIN", envelopeNode); maxNode = XMLTools.getChild("MAX", envelopeNode); minX = XMLTools.getNumberValue("X", minNode); minY = XMLTools.getNumberValue("Y", minNode); maxX = XMLTools.getNumberValue("X", maxNode); maxY = XMLTools.getNumberValue("Y", maxNode); envelope = new Envelope(minX, minY, maxX, maxY); } feature.setEnvelope(envelope, 2); //Do not parse the geometry at this point, only needed for editing??? //if(feature.getGeometry()==null){ //parse the geometry //featureGeometryNode = XMLTools.getChild(geometryColumn, featureNodes[i]); //geometryNode = featureGeometryNode.firstChild; //if (geometryNode == null) { //geometry = new NullGeometry(); //} else { //geometry = GMLFactory.parseGML(geometryNode); //} //feature.setLoadedGeometry(geometry); //} loadedFeatures.push(feature); } //geef de features terug aan de responseHandler var responseHandler:Object = Object(xmlResponse.getProperties()["responseHandler"]); var responseObject:Object = new Object(); responseObject["featureAction"] = xmlResponse.getProperties()["featureAction"]; responseObject["responseAction"] = xmlResponse.getProperties()["responseAction"]; responseObject["actionLayer"] = this; layerEventDispatcher.changeLoadedFeatures(this); responseHandler.handleResponse(loadedFeatures,responseObject); } */ function getLoadedFeatures():Array{ return loadedFeatures; } function handleResponse(features:Array,responseObject:Object):Void { var responseAction:String = String(responseObject["responseAction"]); var featureAction:Number = Number(responseObject["featureAction"]); switch(responseAction){ case "SETFEATURES": var ids:Array = new Array(); for (var i:Number = 0; i < features.length; i++) { ids.push(features[i].getID()); } setFeatures(featureAction, ids, false, -1, null);//verified:true, feature ids is result of serverrequest default: } } function setSelectedFeatures(ids:Array, cumulatively:Boolean, synchListener:SynchListener):Void { setFeatures(SELECT, ids, cumulatively, VERIFICATION, synchListener); } function setCurrentFeature(ids:Array, cumulatively:Boolean):Void { setFeatures(CURRENT, ids, cumulatively, PROPERTIES, null); } function setNearbyFeatures(ids:Array):Void { setFeatures(NEARBY, ids, false, -1, null); } private function setFeatures(action:Number, whereFeaturesIDs:Array, cumulatively:Boolean, request:Number, synchListener:SynchListener):Void { if (editing == WAITING) { return; } if ((action != FILTER) && (action != SELECT) && (action != CURRENT) && (action != NEARBY)) { // EXCEPTION return; } if (whereFeaturesIDs == null) { whereFeaturesIDs = new Array(); } if ((whereFeaturesIDs.length == 0) && (cumulatively)) { // Not much to do in that case... return; // TODO synchlistener??? } if ((request != -1) && (request != VERIFICATION) && (request != PROPERTIES)) { // EXCEPTION return; } ArrayTools.makeUnique(whereFeaturesIDs); var allFeaturesIDs:Array = getFeatureIDs(getFeatures()); var featureIDs:Array = null; if (action == FILTER) { featureIDs = getFeatureIDs(filteredFeatures); } else if (action == SELECT) { featureIDs = getFeatureIDs(selectedFeatures); } else if (action == CURRENT) { featureIDs = new Array(); if (currentFeature != null) { featureIDs.push(currentFeature.getID()); } } else { // NEARBY nearbyFeatures = new Array(); featureIDs = new Array(); } var toBeRemovedIDs:Array = null; if (cumulatively) { toBeRemovedIDs = ArrayTools.intersect(whereFeaturesIDs, featureIDs); } else { toBeRemovedIDs = ArrayTools.getLeftOver(featureIDs, whereFeaturesIDs); } var toBeCopiedIDs:Array = ArrayTools.getLeftOver(ArrayTools.intersect( whereFeaturesIDs, allFeaturesIDs), featureIDs); var toBeCreatedIDs:Array = ArrayTools.getLeftOver(whereFeaturesIDs, allFeaturesIDs); if (action != NEARBY) { _root["frameWork"].state("Layer name: " + name + ", action: " + action + ".", 2); _root["frameWork"].state("Number of features to be removed: " + toBeRemovedIDs.length + ", to be copied: " + toBeCopiedIDs.length + ", to be created: " + toBeCreatedIDs.length + ".", 2); _root["frameWork"].state("", 2); } var layerSession:LayerSession = new LayerSession(this, synchListener); // It is not strictly necessary to always have a session, notably with actions that don't need to broadcast events. And yet a session is made everytime, in order to handle all actions in the same manner. for (var i:Number = 0; i < toBeRemovedIDs.length; i++) { var toBeRemovedFeature:Feature = getFeature(toBeRemovedIDs[i]); if (action == FILTER) { for (var j:Number = 0; j < filteredFeatures.length; j++) { if (filteredFeatures[j] == toBeRemovedFeature) { filteredFeatures.splice(j, 1); layerSession.setFilteredChanged(true); break; } } } else if (action == SELECT) { if (toBeRemovedFeature.isEditing()) { if (toBeRemovedFeature.getEditingStatus() == Feature.UNCHANGED) { toBeRemovedFeature.setEditing(false); layerSession.setSubSelectedChanged(true); } else { continue; } } if (toBeRemovedFeature == currentFeature) { currentFeature = null; layerSession.setCurrentChanged(true); } for (var j:Number = 0; j < selectedFeatures.length; j++) { if (selectedFeatures[j] == toBeRemovedFeature) { selectedFeatures.splice(j, 1); layerSession.setSelectedChanged(true); break; } } } else if (action == CURRENT) { if (currentFeature == toBeRemovedFeature) { currentFeature = null; layerSession.setCurrentChanged(true); } } else { // NEARBY // It is impossible to remove from the nearby features, because the nearby features is an empty collection at this point. } } for (var i:Number = 0; i < toBeCopiedIDs.length; i++) { var toBeCopiedFeature:Feature = getFeature(toBeCopiedIDs[i]); if ((request == VERIFICATION) && (!toBeCopiedFeature.isIDVerified())) { layerSession.addRequestingFeature(toBeCopiedFeature); // A verification request does NOT need to be given here, because "idVerified == false" is a guarantee that verification is being requested. And also, the verification of a feature's id can never be undone. } else if ((request == PROPERTIES) && (toBeCopiedFeature.getGeometry() == null)) { layerSession.addRequestingFeature(toBeCopiedFeature); toBeCopiedFeature.requestProperties(); // A properties request DOES need to be given here, because having no geometry is no guarantee that properties are being requested. And also, the feature's geometry can be set back to null. If a properties request is going on already, the feature itself will make sure a second request will not be started. } if (action == FILTER) { filteredFeatures.push(toBeCopiedFeature); layerSession.setFilteredChanged(true); } else if (action == SELECT) { selectedFeatures.push(toBeCopiedFeature); layerSession.setSelectedChanged(true); } else if (action == CURRENT) { if (ArrayTools.posInArray(selectedFeatures, toBeCopiedFeature) == -1) { continue; } if ((editing == READY) && (!toBeCopiedFeature.isEditing())) { toBeCopiedFeature.setEditing(true); layerSession.setSubSelectedChanged(true); } currentFeature = toBeCopiedFeature; layerSession.setCurrentChanged(true); } else { // NEARBY nearbyFeatures.push(toBeCopiedFeature); } } for (var i:Number = 0; i < toBeCreatedIDs.length; i++) { var toBeCreatedFeature:Feature = null; if ((request == VERIFICATION) || (request == PROPERTIES)) { toBeCreatedFeature = new Feature(toBeCreatedIDs[i], this, featureType, true, false); // If only properties are needed and the id is already verified, then yet "idVerified == false" is assumed. This is not a problem, because during the properties request the newly created feature can not yet be used in the "outside world" anyways. layerSession.addRequestingFeature(toBeCreatedFeature); toBeCreatedFeature.requestProperties(); // If only verification is needed, then yet all properties are requested. This costs no performance, because verification and properties use the same server request. } else { //controleer of dit feature niet toevallig al in de loadedFeatures Array bestaat TODO for (var j:Number = 0; j < loadedFeatures.length; j++) { if(loadedFeatures[j].getID() == toBeCreatedIDs[i]){ toBeCreatedFeature = loadedFeatures[j]; } } if(toBeCreatedFeature==null){ toBeCreatedFeature = new Feature(toBeCreatedIDs[i], this, featureType, true, true); } } if (action == FILTER) { filteredFeatures.push(toBeCreatedFeature); layerSession.setFilteredChanged(true); } else if (action == SELECT) { selectedFeatures.push(toBeCreatedFeature); layerSession.setSelectedChanged(true); } else if (action == CURRENT) { if (ArrayTools.posInArray(selectedFeatures, toBeCreatedFeature) == -1) { continue; } if ((editing == READY) && (!toBeCreatedFeature.isEditing())) { toBeCreatedFeature.setEditing(true); layerSession.setSubSelectedChanged(true); } currentFeature = toBeCreatedFeature; layerSession.setCurrentChanged(true); } else { // NEARBY if (nearbyFeatures.length < 550) { // Keeping track of nearby features is no use if their number is too great. Above this number filtering, selecting and setting the current feature are faster if loaded from the server. nearbyFeatures.push(toBeCreatedFeature); } } } if (layerSession.getNumRequestingFeatures() == 0) { layerSession.flush(); } else { layerSessions.push(layerSession); // Waits for features to verify their ids. } } function onFeatureResponse(feature:Feature, verified:Boolean, synchListener:SynchListener):Void { if (!verified) { doRemoveFeature(feature); } var layerSession:LayerSession = null; for (var i:Number = 0; i < layerSessions.length; i++) { layerSession = LayerSession(layerSessions[i]); layerSession.removeRequestingFeature(feature); if (layerSession.getNumRequestingFeatures() == 0) { layerSession.flush(); layerSessions.splice(i--, 1); } } synchListener.onSynch(this, "PROPERTIES"); } private function doRemoveFeature(feature:Feature):Void { for (var i:Number = 0; i < filteredFeatures.length; i++) { if (filteredFeatures[i] == feature) { filteredFeatures.splice(i, 1); break; } } for (var i:Number = 0; i < selectedFeatures.length; i++) { if (selectedFeatures[i] == feature) { selectedFeatures.splice(i, 1); break; } } if (currentFeature == feature) { currentFeature = null; } for (var i:Number = 0; i < nearbyFeatures.length; i++) { if (nearbyFeatures[i] == feature) { nearbyFeatures.splice(i, 1); break; } } } public function getFeatures():Array { // Retrieves all features that exist in one of the feature collections, NO MATTER verified or not. var features:Array = new Array(); features = features.concat(filteredFeatures); features = features.concat(selectedFeatures); // Includes subselected and current as well. features = features.concat(nearbyFeatures); ArrayTools.makeUnique(features); return features; } public function getFeature(id:String):Feature { // Retrieves the feature with the given id, if it exists in one of the feature collections, NO MATTER verified or not. var feature:Feature = null; for (var i:String in filteredFeatures) { feature = Feature(filteredFeatures[i]); if (feature.getID() == id) { return feature; } } for (var i:String in selectedFeatures) { // Includes subselected and current as well. feature = Feature(selectedFeatures[i]); if (feature.getID() == id) { return feature; } } for (var i:String in nearbyFeatures) { feature = Feature(nearbyFeatures[i]); if (feature.getID() == id) { return feature; } } return null; } function getFilteredFeatures():Array { var filteredFeatures:Array = new Array(); var feature:Feature = null; for (var i:Number = 0; i < this.filteredFeatures.length; i++) { feature = Feature(this.filteredFeatures[i]); if (feature.isIDVerified()) { filteredFeatures.push(feature); } } return filteredFeatures; } function getFilteredFeature(id:String):Feature { var feature:Feature = null; for (var i:String in filteredFeatures) { feature = Feature(filteredFeatures[i]); if ((feature.getID() == id) && (feature.isIDVerified())) { return feature; } } return null; } function getSelectedFeatures():Array { var selectedFeatures:Array = new Array(); var feature:Feature = null; for (var i:Number = 0; i < this.selectedFeatures.length; i++) { feature = Feature(this.selectedFeatures[i]); if (feature.isIDVerified()) { selectedFeatures.push(feature); } } return selectedFeatures; } function getSelectedFeature(id:String):Feature { var feature:Feature = null; for (var i:String in selectedFeatures) { feature = Feature(selectedFeatures[i]); if ((feature.getID() == id) && (feature.isIDVerified())) { return feature; } } return null; } function getSubSelectedFeatures():Array { var editingFeatures:Array = new Array(); var feature:Feature = null; for (var i:Number = 0; i < selectedFeatures.length; i++) { feature = Feature(selectedFeatures[i]); if ((feature.isEditing()) && (feature.isIDVerified())) { editingFeatures.push(feature); } } return editingFeatures; } function getSubSelectedFeature(id:String):Feature { var feature:Feature = null; for (var i:String in selectedFeatures) { feature = Feature(selectedFeatures[i]); if ((feature.isEditing()) && (feature.getID() == id) && (feature.isIDVerified())) { return feature; } } return null; } function getCurrentFeature():Feature { if (currentFeature.isIDVerified()) { return currentFeature; } return null; } function getNearbyFeatures():Array { // No need to check whether verified, because nearby features are always verified. return nearbyFeatures; } function getNearbyFeature(id:String):Feature { // No need to check whether verified, because nearby features are always verified. var feature:Feature = null; for (var i:String in nearbyFeatures) { feature = Feature(nearbyFeatures[i]); if (feature.getID() == id) { return feature; } } return null; } function pushUndo(featureToSave:Feature):Void { undoStack.push(featureToSave); //trace("layer.pushUndo, stack.length = " + undoStack.length); } function undo():Void { //trace("layer.undo, stack.length = " + undoStack.length); if (undoStack.length > 1) { undoStack.pop(); //remove currentFeature version from stack var undoFeature:Feature = Feature(undoStack.pop()); if ((undoFeature.getID() != currentFeature.getID()) ) { setSelectedFeatures(new Array(undoFeature.getID()), false, null); setCurrentFeature(new Array(undoFeature.getID()), false); pushUndo(undoFeature); } else { undoFeature.undo(undoFeature); //new current will be pushed through onChangeGeometry } } } function addEventListener(stateEventListener:StateEventListener, sourceClassName:String, actionType:Number, propertyName:String):Void { if (sourceClassName + "_" + actionType + "_" + propertyName != "SelectableLayer_" + StateEvent.CHANGE + "_editingStatus" && (sourceClassName + "_" + actionType + "_" + propertyName != "SelectableLayer_" + StateEvent.CHANGE + "_editingMessage") ) { // EXCEPTION return; } stateEventDispatcher.addEventListener(stateEventListener, sourceClassName, actionType, propertyName); } function removeEventListener(stateEventListener:StateEventListener, sourceClassName:String, actionType:Number, propertyName:String):Void { if (sourceClassName + "_" + actionType + "_" + propertyName != "SelectableLayer_" + StateEvent.CHANGE + "_editingStatus") { // EXCEPTION return; } stateEventDispatcher.removeEventListener(stateEventListener, sourceClassName, actionType, propertyName); } function getColumns():Array { return columns; } function getAttrInfoColumns():Array { return columns; } function getContextColumns():Array { var cc:Array = new Array(); for(var i:Number = 0; i < columns.length; i++) { var columnItem:Object = getColumnItem(columns[i].getPath()); if(columnItem != null) { cc[Number(columnItem["position"])] = columns[i]; } } return cc; } function columnItemCount():Number { var retval:Number = 0; for(var i:Number = 0; i < columns.length; i++) { if(getColumnItem(columns[i].getPath()) != null) { retval++; } } return retval; } function setTemplateFeature(templateFeature:Feature):Void { this.templateFeature = templateFeature; } function getTemplateFeature():Feature { if(templateFeature == null) { templateFeature = new Feature("NW_" + String(addedFeatureIDIndex++), this, featureType, false, true); } return templateFeature; } function clearTemplateFeature():Void { templateFeature = null; } function getGeometryType():String { if(geometryType != null) return geometryType; else return super.getGeometryType(); } function onLoadXMLResponse(xmlResponse:XMLResponse):Void { //Bouw een features Array op, mbv de XMLResponse var id:String = ""; var feature:Feature = null; var envelopeNode:XMLNode = null; var minNode:XMLNode = null; var maxNode:XMLNode = null; var minX:Number = -1; var minY:Number = -1; var maxX:Number = -1; var maxY:Number = -1; var envelope:Envelope = null; var featureGeometryNode:XMLNode = null; var geometryNode:XMLNode = null; var geometry:Geometry = null; loadedFeatures = new Array(); var featureNodes:Array = XMLTools.getChildNodes(name, xmlResponse.firstChild); var features:Array = this.getFeatures(); for (var i:Number = 0; i < featureNodes.length; i++) { id = XMLTools.getStringValue("fid", featureNodes[i]); //loop through the features to see if already exists feature = null; for(var j:Number = 0; j < features.length; j++) { if(id==features[j].getID()){ //feature exists feature = features[j]; } } if(feature == null){ feature = new Feature(id, this, featureType, false, true); } //parse the Envelope envelopeNode = XMLTools.getChild("ENVELOPE", featureNodes[i]); if (envelopeNode.childNodes.length == 0) { envelope = new NullGeometry(); } else { minNode = XMLTools.getChild("MIN", envelopeNode); maxNode = XMLTools.getChild("MAX", envelopeNode); minX = XMLTools.getNumberValue("X", minNode); minY = XMLTools.getNumberValue("Y", minNode); maxX = XMLTools.getNumberValue("X", maxNode); maxY = XMLTools.getNumberValue("Y", maxNode); envelope = new Envelope(getSRS(), minX, minY, maxX, maxY); } feature.setEnvelope(envelope, 2); //Do not parse the geometry at this point, only needed for editing??? //if(feature.getGeometry()==null){ //parse the geometry //featureGeometryNode = XMLTools.getChild(geometryColumn, featureNodes[i]); //geometryNode = featureGeometryNode.firstChild; //if (geometryNode == null) { //geometry = new NullGeometry(); //} else { //geometry = GMLFactory.parseGML(geometryNode); //} //feature.setLoadedGeometry(geometry); //} loadedFeatures.push(feature); } //geef de features terug aan de responseHandler var responseHandler:Object = Object(xmlResponse.getProperties()["responseHandler"]); var responseObject:Object = new Object(); responseObject["featureAction"] = xmlResponse.getProperties()["featureAction"]; responseObject["responseAction"] = xmlResponse.getProperties()["responseAction"]; responseObject["actionLayer"] = this; layerEventDispatcher.changeLoadedFeatures(this); responseHandler.handleResponse(loadedFeatures,responseObject); } function addColumnItem(columnName:String, columnTitle:String, columnFeatureTypeName:String, columnLabel:String, columnData:String, columnUrlprefix:String, position:Number) { var obj:Object = columnValues[columnName]; if(obj == null) { obj = new Object(); columnValues[columnName] = obj; } obj["title"] = columnTitle; obj["featureTypeName"] = columnFeatureTypeName; obj["label"] = columnLabel; obj["data"] = columnData; obj["urlprefix"] = columnUrlprefix; obj["position"] = position; } function getColumnItem(columnName:String) { return columnValues[columnName]; } function getWfsConnector() { return wfsConnector; } function getEditingMessage() { return this.editingMessage; } function setHyperlinkColumn(columnName:String):Void { this.hyperlinkColumn = columnName; } function getHyperlinkColumn():Column { if(this.hyperlinkColumn != null) { var column:Column = getColumn(hyperlinkColumn); if(column != null) { return column; } else { column = new Column(hyperlinkColumn); column.setURLPrefix(getColumnItem(hyperlinkColumn)["urlprefix"]); return column; } } else { return getColumn(connector.getHyperlinkColumnName(name)); } } function hasAnnotations():Boolean { return this.annotationColumn != null; } function getAnnotationColumn():String { return this.annotationColumn; } function setAnnotationColumn(column:String):Void { this.annotationColumn = column; } function getOwnerRoles():Array { return this.ownerRoles; } function setOwnerRoles(ownerRoles:String):Void { this.ownerRoles = ownerRoles.split(","); //trace("setOwnerRoles, ownerRoles = " + this.ownerRoles); } function getObjectOwnerProperty():String { return this.objectOwnerProperty; } function setObjectOwnerProperty(objectOwnerProperty:String):Void { this.objectOwnerProperty = objectOwnerProperty; //trace("setObjectOwnerProperty = " + objectOwnerProperty); } function authorized():Boolean { if (ownerRoles == null || ownerRoles.length == 0) { return true; } var assignedRoles:Array = this.connector.getAssignedRoles(); //trace("authorized, assignedRoles = " + assignedRoles); for(var i:Number = 0; i < ownerRoles.length; i++) { for(var j:Number = 0; j < assignedRoles.length; j++) { //trace("ownerRoles[i] = " + ownerRoles[i] + " assignedRoles[j] = " + assignedRoles[j]); if (ownerRoles[i] == assignedRoles[j]) { return true; } } } return false; } }