diff --git a/lib/Styler/widgets/CircleSegment.js b/lib/Styler/widgets/CircleSegment.js new file mode 100644 index 0000000..67dc178 --- /dev/null +++ b/lib/Styler/widgets/CircleSegment.js @@ -0,0 +1,170 @@ +/** + * @requires OpenLayers/Handler/Path.js + */ + +/** + * Class: OpenLayers.Handler.CircleSegment + * Handler to draw a circle while displaying the radius. + * + * Inherits from: + * - + */ +OpenLayers.Handler.CircleSegment = OpenLayers.Class(OpenLayers.Handler.Path, { + + /** + * Property: origin + * {} The origin of the segment, first clicked + * point + */ + origin: null, + + /** + * Property: circle + * {} The drawn circle + */ + circle: null, + + /** + * Property: _drawing + * {Boolean} Indicates if in the process of drawing a segment. + * (We prefix the variable name with an underscore not to + * collide with a "drawing" property of the parent.) + */ + _drawing: false, + + /** + * Constructor: OpenLayers.Handler.CircleSegment + */ + initialize: function(control, callbacks, options) { + options = options || {}; + options.maxVertices = 2; + options.persist = true; + options.freehandToggle = null; + OpenLayers.Handler.Path.prototype.initialize.apply( + this, [control, callbacks, options]); + }, + + /** + * + */ + addPoint: function() { + OpenLayers.Handler.Path.prototype.addPoint.apply(this, arguments); + if (this.line.geometry.components.length == 2) { + var feature = this.origin = new OpenLayers.Feature.Vector( + this.line.geometry.components[0].clone()); + this.layer.addFeatures([feature], {silent: true}); + this._drawing = true; + } + }, + + /** + * + */ + destroyPersistedFeature: function() { + OpenLayers.Handler.Path.prototype.destroyPersistedFeature.apply( + this, arguments); + if (this.layer) { + if (this.origin) { + this.origin.destroy(); + this.origin = null; + } + if (this.circle) { + this.circle.destroy(); + this.circle = null; + } + } + }, + + /** + * + */ + modifyFeature: function() { + OpenLayers.Handler.Path.prototype.modifyFeature.apply(this, arguments); + + if (this._drawing) { + if (this.circle) { + this.layer.removeFeatures([this.circle, this.point]); + } + var geometry = OpenLayers.Geometry.Polygon.createRegularPolygon( + this.origin.geometry, this.line.geometry.getLength(), 40 + ); + + this.circle = new OpenLayers.Feature.Vector(geometry); + if (!this.point.style){ + var style = OpenLayers.Util.applyDefaults( + this.defaultStyle, OpenLayers.Feature.Vector.style["default"]); + this.point.style = style; + } + + /** Display the radius **/ + var curLength = this.line.geometry.getLength(); + var label=""; + if (curLength>1000) { + label = Math.round(curLength / 10) / 100 + " km "; + } else { + label = Math.round(curLength) + " m "; + } + this.layer.addFeatures([this.point], {silent: true}); + this.point.style.label = label; + this.point.style.graphic = false; + this.point.style.labelSelect = true; + + var o = this.origin.geometry, + p = this.point.geometry, + align, + xOffset, + yOffset; + if (o.x < p.x) { + align = 'l'; + xOffset = 10; + } else { + align = 'r'; + xOffset = -10; + } + + if (o.y < p.y) { + align += 'b'; + yOffset = 10; + } else { + align += 't'; + yOffset = -10; + } + this.point.style.labelAlign = align; + this.point.style.labelXOffset = xOffset; + this.point.style.labelYOffset = yOffset; + + this.layer.addFeatures([this.circle], {silent: true}); + } + }, + + /** + * + */ + deactivate: function() { + if (OpenLayers.Handler.Path.prototype.deactivate.call(this)) { + this._drawing = false; + return true; + } + return false; + }, + + /** + * + */ + dblclick: function() { + // we don't want double click + }, + + finalize: function(cancel) { + var key = cancel ? "cancel" : "done"; + this.mouseDown = false; + this.lastDown = null; + this.lastUp = null; + this.lastTouchPx = null; + + if (this.circle && this.circle.geometry) { + this.callback(key, [this.circle.geometry.clone()]); + } + this.destroyFeature(cancel); + } +}); diff --git a/lib/Styler/widgets/FilterBuilder.js b/lib/Styler/widgets/FilterBuilder.js index 3f30847..1cae4bb 100644 --- a/lib/Styler/widgets/FilterBuilder.js +++ b/lib/Styler/widgets/FilterBuilder.js @@ -1,949 +1,950 @@ -/** - * Copyright (c) 2008 The Open Planning Project - */ - -/** - * @include Styler/widgets/FilterPanel.js - * @include Styler/widgets/SpatialFilterPanel.js - * @include GeoExt/widgets/Action.js - * @include OpenLayers/Handler/RegularPolygon.js - */ - -Ext.namespace("Styler"); - -Styler.FilterBuilder = Ext.extend(Ext.Panel, { - - /** - * Property: builderTypeNames - * {Array} A list of labels for that correspond to builder type constants. - * These will be the option names available in the builder type combo. - * Default is ["any", "all", "none", "not all"]. - */ - - /** - * Property: allowedBuilderTypes - * {Array} List of builder type constants. Default is - * [ANY_OF, ALL_OF, NONE_OF]. - */ - allowedBuilderTypes: null, - - /** - * Property: filterPanelOptions - * {Object} Allows customization of attributes comboBox - */ - filterPanelOptions: null, - - rowHeight: 25, - - builderType: null, - - childFiltersPanel: null, - - customizeFilterOnInit: true, - - /** - * Property: preComboText - * {String} text displayed before combo. - */ - - /** - * Property: postComboText - * {String} text displayed after combo. - */ - - /** - * Property: comboConfig - * {Object} Additional config properties for the filter types combo - */ - comboConfig: {}, - - /** - * Property: allowGroups - * {Boolean} Allow groups of conditions to be added. Default is true. - * If false, only individual conditions (non-logical filters) can - * be added. - */ - allowGroups: true, - - /** - * Property: geometryTypes - * {Array} List all possible geometry types to search with. - */ - geometryTypes: [ 'polygon', 'circle', 'line', 'point' ], - - /** - * Property: allowSpatial - * {Boolean} Allow spatial conditions to be added. Default is false. - */ - allowSpatial: false, - - /** - * Property: vectorLayer - * {OpenLayers.Layer.Vector} The vector layer used to draw features - * If none is provided, it will be created. - */ - vectorLayer: null, - - /** - * Property: map - * {OpenLayers.Map} The map object to which we add our vectorLayer - * required if allowSpatial is true. - */ - map: null, - - /** - * Property: cookieProvider - * {Ext.state.CookieProvider} The cookie provider - * Used for storing filters or geometries (if available) ... - */ - cookieProvider: null, - - /** - * Property: deactivable - * {Boolean} - */ - deactivable: false, - - /** - * Property: noConditionOnInit - * {Boolean} - */ - noConditionOnInit: false, - - initComponent: function() { - var defConfig = { - builderTypeNames: [ - OpenLayers.i18n("any"), - OpenLayers.i18n("all"), - OpenLayers.i18n("none"), - OpenLayers.i18n("not all") - ], - preComboText: OpenLayers.i18n("Matching"), - postComboText: OpenLayers.i18n("these conditions:"), - plain: true, - layout: 'column', - defaults: { - columnWidth: 1 - }, - defaultBuilderType: Styler.FilterBuilder.ANY_OF - }; - Ext.applyIf(this, defConfig); - - if(this.customizeFilterOnInit) { - this.filter = this.customizeFilter(this.filter); - if (this.noConditionOnInit) { - var filters = this.filter.filters[0].filters; - filters.remove(filters[0]); - } - } - - this.builderType = this.getBuilderType(); - - this.items = [ - { - xtype: "panel", - height: 30, - layout: 'fit', - border: false, - items: [{ - xtype: "panel", - border: false, - layout: "column", - style: "margin-top: 0.25em;", - defaults: { - border: false - }, - items: [{ - html: this.preComboText, - cls: 'filterbuilder-text' - }, { - height: 25, - width: 85, - items: [this.createBuilderTypeCombo()] - }, { - html: this.postComboText, - cls: 'filterbuilder-text' - }] - }] - }, this.createChildFiltersPanel() - ]; - - this.bbar = this.createToolBar(); - this.addEvents( - /** - * Event: change - * Fires when the filter changes. - * - * Listener arguments: - * builder - {Styler.FilterBuilder} This filter builder. Call - * to get the updated filter. - */ - "change", - /** - * Event: loading - * Fires when loading data from server - */ - "loading", - /** - * Event: loaded - * Fires when finished loading data from server - */ - "loaded" - ); - - Styler.FilterBuilder.superclass.initComponent.call(this); - }, - - deactivateControls: function() { - var controls = this.controls, i; - if (controls) { - for (i=0,l=controls.length; i-1) { - items.push(new Ext.menu.CheckItem(new GeoExt.Action({ - control: createDrawControl.call(this, OpenLayers.Handler.Point, this.controls), - map: this.map, - group: "querier", - text: OpenLayers.i18n("based on a point"), - iconCls: "point" - }))); - } - if (this.geometryTypes.indexOf('line')>-1) { - items.push(new Ext.menu.CheckItem(new GeoExt.Action({ - control: createDrawControl.call(this, OpenLayers.Handler.Path, this.controls), - map: this.map, - group: "querier", - text: OpenLayers.i18n("based on a line"), - iconCls: "linestring" - }))); - } - if (this.geometryTypes.indexOf('circle')>-1) { - items.push(new Ext.menu.CheckItem(new GeoExt.Action({ - control: createDrawControl.call(this, OpenLayers.Handler.RegularPolygon, this.controls), - map: this.map, - group: "querier", - text: OpenLayers.i18n("based on a circle"), - iconCls: "circle" - }))); - } - if (this.geometryTypes.indexOf('polygon')>-1) { - items.push(new Ext.menu.CheckItem(new GeoExt.Action({ - control: createDrawControl.call(this, OpenLayers.Handler.Polygon, this.controls), - map: this.map, - group: "querier", - text: OpenLayers.i18n("based on a polygon"), - iconCls: "polygon" - }))); - } - if (this.cookieProvider) { - var item = new Ext.menu.CheckItem({ - text: OpenLayers.i18n("based on a stored geometry"), - disabled: !this.cookieProvider.get('geometry', false), - handler: function() { - var wkt = this.cookieProvider.decodeValue( - this.cookieProvider.get('geometry') - ); - this.vectorLayer.addFeatures([ - new OpenLayers.Format.WKT().read(wkt) - ]); - }, - scope: this, - iconCls: "database" - }); - this.cookieProvider.on('statechange', function(cp, key, value){ - if (key === 'geometry') { - if (value.length) { - item.enable(); - } else { - item.disable(); - } - } - }, this); - items.push(item); - } - return new Ext.menu.Menu({items: items}); - }, - - /** - * APIMethod: getFilter - * Returns a filter that fits the model in the Filter Encoding - * specification. Use this method instead of directly accessing - * the property. - * - * Returns: - * {OpenLayers.Filter} A filter that can be serialized with the filter - * format. - */ - getFilter: function() { - var filter; - if(this.filter) { - filter = this.removeUnchecked(this.cloneFilter(this.filter)); - if(filter instanceof OpenLayers.Filter.Logical) { - filter = this.cleanFilter(filter); - } - } - return filter; - }, - - /** - * Method: cloneFilter - * A special cloning method which takes care of the "removed" property - * - * Parameters: - * f - {OpenLayers.Filter} A filter. - * - * Returns: - * {OpenLayers.Filter} A filter - */ - cloneFilter: function(f) { - var filter; - if(f instanceof OpenLayers.Filter.Logical) { - var filters = [], i; - for(var i=0, len=f.filters.length; i method to return a - * filter that meets the encoding spec. - * - * Parameters: - * filter - {OpenLayers.Filter} The input filter. This filter will not - * be modified. Register for events to receive an updated filter, or - * call . - * - * Returns: - * {OpenLayers.Filter} A filter that fits the model used by this builder. - */ - customizeFilter: function(filter) { - var child; - if(!filter) { - filter = this.wrapFilter(this.createDefaultFilter()); - } else { // TODO: spatial case ... - filter = this.cleanFilter(filter); - switch(filter.type) { - case OpenLayers.Filter.Logical.AND: - case OpenLayers.Filter.Logical.OR: - if(!filter.filters || filter.filters.length === 0) { - // give the filter children if it has none - filter.filters = [this.createDefaultFilter()]; - } else { - for(var i=0, len=filter.filters.length; i 0) { - filter = this.customizeFilter(child.filters[0]); - } else { - filter = this.wrapFilter(this.createDefaultFilter()); - } - } - } else { - // non-logical child of NOT should be wrapped - var type; - if(this.defaultBuilderType === Styler.FilterBuilder.NOT_ALL_OF) { - type = OpenLayers.Logical.Filter.AND; - } else { - type = OpenLayers.Logical.Filter.OR; - } - filter.filters = [ - new OpenLayers.Filter.Logical({ - type: type, - filters: [child] - }) - ]; - } - } - break; - case OpenLayers.Filter.Comparison.BETWEEN: - filter = new OpenLayers.Filter.Logical({ - type: OpenLayers.Filter.Logical.AND, - filters: [ - new OpenLayers.Filter.Comparison({ - type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, - property: filter.property, - value: filter.lowerBoundary - }), - new OpenLayers.Filter.Comparison({ - type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, - property: filter.property, - value: filter.upperBoundary - }) - ] - }); - filter = this.customizeFilter(filter); - break; - default: - // non-logical filters get wrapped - filter = this.wrapFilter(filter); - } - } - return filter; - }, - - createDefaultFilter: function(feature) { - if(feature instanceof OpenLayers.Feature.Vector) { - return new OpenLayers.Filter.Spatial({ - value: feature.geometry, - projection: this.map.getProjection(), - type: OpenLayers.Filter.Spatial.INTERSECTS - }); - } else { - return new OpenLayers.Filter.Comparison(); - } - }, - - /** - * Method: createVectorLayer - * - * Returns: - * {OpenLayers.Layer.Vector} - */ - createVectorLayer: function() { - var layer = (this.vectorLayer) ? - this.vectorLayer : new OpenLayers.Layer.Vector('filter_builder', { - displayInLayerSwitcher: false - }); - if(OpenLayers.Util.indexOf(this.map.layers, layer) < 0) { - this.map.addLayer(layer); - } - // each time a new feature is added, a new spatial condition is added. - layer.events.on({ - "featureadded": function(options) { - this.addCondition("spatial", options.feature); - this.deactivateControls(); - }, - scope: this - }); - return layer; - }, - - /** - * Method: wrapFilter - * Given a non-logical filter, this creates parent filters depending on - * the . - * - * Parameters: - * filter - {OpenLayers.Filter} A non-logical filter. - * - * Returns: - * {OpenLayers.Filter} A wrapped version of the input filter. - */ - wrapFilter: function(filter) { - var type; - if(this.defaultBuilderType === Styler.FilterBuilder.ALL_OF) { - type = OpenLayers.Filter.Logical.AND; - } else { - type = OpenLayers.Filter.Logical.OR; - } - return new OpenLayers.Filter.Logical({ - type: OpenLayers.Filter.Logical.OR, - filters: [ - new OpenLayers.Filter.Logical({ - type: type, filters: [filter] - }) - ] - }); - }, - - /** - * Method: addCondition - * Add a new condition or group of conditions to the builder. This - * modifies the filter and adds a panel representing the new condition - * or group of conditions. - */ - addCondition: function(conditionType, feature) { - var filter, type; - - var cfg = { - customizeFilterOnInit: (conditionType === "group") && false, - listeners: { - "change": function() { - this.fireEvent("change", this); - }, - "loaded": function() { - this.fireEvent("loaded"); - }, - "loading": function() { - this.fireEvent("loading"); - }, - scope: this - } - }; - - switch (conditionType) { - case "group": - filter = this.wrapFilter(this.createDefaultFilter()); - Ext.apply(cfg, { - xtype: "gx_filterbuilder", - filter: filter, - deactivable: this.deactivable, - filterPanelOptions: Ext.apply({}, this.filterPanelOptions), - attributes: this.attributes - }); - break; - case "spatial": - filter = this.createDefaultFilter(feature); - Ext.apply(cfg, { - xtype: "gx_spatialfilterpanel", - filter: filter, - cookieProvider: this.cookieProvider, - feature: feature, - toggleGroup: "querier", - map: this.map - }); - break; - default: - filter = this.createDefaultFilter(); - Ext.apply(cfg, { - xtype: "gx_filterpanel", - filter: filter, - attributes: this.attributes, - filterPanelOptions: Ext.apply({}, this.filterPanelOptions) - }); - } - var newChild = this.newRow(cfg); - this.childFiltersPanel.add(newChild); - this.filter.filters[0].filters.push(filter); - this.childFiltersPanel.doLayout(); - }, - - /** - * Method: removeCondition - * Remove a condition or group of conditions from the builder. This - * modifies the filter and removes the panel representing the condition - * or group of conditions. - */ - removeCondition: function(panel, filter) { - var parent = this.filter.filters[0].filters; - if(parent.length >= 1) { - parent.remove(filter); - panel.getComponent(1).getComponent(0).tearDown(); - this.childFiltersPanel.remove(panel); - } - this.fireEvent("change", this); - }, - - createBuilderTypeCombo: function() { - var types = this.allowedBuilderTypes || [ - Styler.FilterBuilder.ANY_OF, Styler.FilterBuilder.ALL_OF, - Styler.FilterBuilder.NONE_OF - ]; - var numTypes = types.length; - var data = new Array(numTypes), type; - for(var i=0; i to get the updated filter. + */ + "change", + /** + * Event: loading + * Fires when loading data from server + */ + "loading", + /** + * Event: loaded + * Fires when finished loading data from server + */ + "loaded" + ); + + Styler.FilterBuilder.superclass.initComponent.call(this); + }, + + deactivateControls: function() { + var controls = this.controls, i; + if (controls) { + for (i=0,l=controls.length; i-1) { + items.push(new Ext.menu.CheckItem(new GeoExt.Action({ + control: createDrawControl.call(this, OpenLayers.Handler.Point, this.controls), + map: this.map, + group: "querier", + text: OpenLayers.i18n("based on a point"), + iconCls: "point" + }))); + } + if (this.geometryTypes.indexOf('line')>-1) { + items.push(new Ext.menu.CheckItem(new GeoExt.Action({ + control: createDrawControl.call(this, OpenLayers.Handler.Path, this.controls), + map: this.map, + group: "querier", + text: OpenLayers.i18n("based on a line"), + iconCls: "linestring" + }))); + } + if (this.geometryTypes.indexOf('circle')>-1) { + items.push(new Ext.menu.CheckItem(new GeoExt.Action({ + control: createDrawControl.call(this, OpenLayers.Handler.CircleSegment, this.controls), + map: this.map, + group: "querier", + text: OpenLayers.i18n("based on a circle"), + iconCls: "circle" + }))); + } + if (this.geometryTypes.indexOf('polygon')>-1) { + items.push(new Ext.menu.CheckItem(new GeoExt.Action({ + control: createDrawControl.call(this, OpenLayers.Handler.Polygon, this.controls), + map: this.map, + group: "querier", + text: OpenLayers.i18n("based on a polygon"), + iconCls: "polygon" + }))); + } + if (this.cookieProvider) { + var item = new Ext.menu.CheckItem({ + text: OpenLayers.i18n("based on a stored geometry"), + disabled: !this.cookieProvider.get('geometry', false), + handler: function() { + var wkt = this.cookieProvider.decodeValue( + this.cookieProvider.get('geometry') + ); + this.vectorLayer.addFeatures([ + new OpenLayers.Format.WKT().read(wkt) + ]); + }, + scope: this, + iconCls: "database" + }); + this.cookieProvider.on('statechange', function(cp, key, value){ + if (key === 'geometry') { + if (value.length) { + item.enable(); + } else { + item.disable(); + } + } + }, this); + items.push(item); + } + return new Ext.menu.Menu({items: items}); + }, + + /** + * APIMethod: getFilter + * Returns a filter that fits the model in the Filter Encoding + * specification. Use this method instead of directly accessing + * the property. + * + * Returns: + * {OpenLayers.Filter} A filter that can be serialized with the filter + * format. + */ + getFilter: function() { + var filter; + if(this.filter) { + filter = this.removeUnchecked(this.cloneFilter(this.filter)); + if(filter instanceof OpenLayers.Filter.Logical) { + filter = this.cleanFilter(filter); + } + } + return filter; + }, + + /** + * Method: cloneFilter + * A special cloning method which takes care of the "removed" property + * + * Parameters: + * f - {OpenLayers.Filter} A filter. + * + * Returns: + * {OpenLayers.Filter} A filter + */ + cloneFilter: function(f) { + var filter; + if(f instanceof OpenLayers.Filter.Logical) { + var filters = [], i; + for(var i=0, len=f.filters.length; i method to return a + * filter that meets the encoding spec. + * + * Parameters: + * filter - {OpenLayers.Filter} The input filter. This filter will not + * be modified. Register for events to receive an updated filter, or + * call . + * + * Returns: + * {OpenLayers.Filter} A filter that fits the model used by this builder. + */ + customizeFilter: function(filter) { + var child; + if(!filter) { + filter = this.wrapFilter(this.createDefaultFilter()); + } else { // TODO: spatial case ... + filter = this.cleanFilter(filter); + switch(filter.type) { + case OpenLayers.Filter.Logical.AND: + case OpenLayers.Filter.Logical.OR: + if(!filter.filters || filter.filters.length === 0) { + // give the filter children if it has none + filter.filters = [this.createDefaultFilter()]; + } else { + for(var i=0, len=filter.filters.length; i 0) { + filter = this.customizeFilter(child.filters[0]); + } else { + filter = this.wrapFilter(this.createDefaultFilter()); + } + } + } else { + // non-logical child of NOT should be wrapped + var type; + if(this.defaultBuilderType === Styler.FilterBuilder.NOT_ALL_OF) { + type = OpenLayers.Logical.Filter.AND; + } else { + type = OpenLayers.Logical.Filter.OR; + } + filter.filters = [ + new OpenLayers.Filter.Logical({ + type: type, + filters: [child] + }) + ]; + } + } + break; + case OpenLayers.Filter.Comparison.BETWEEN: + filter = new OpenLayers.Filter.Logical({ + type: OpenLayers.Filter.Logical.AND, + filters: [ + new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO, + property: filter.property, + value: filter.lowerBoundary + }), + new OpenLayers.Filter.Comparison({ + type: OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO, + property: filter.property, + value: filter.upperBoundary + }) + ] + }); + filter = this.customizeFilter(filter); + break; + default: + // non-logical filters get wrapped + filter = this.wrapFilter(filter); + } + } + return filter; + }, + + createDefaultFilter: function(feature) { + if(feature instanceof OpenLayers.Feature.Vector) { + return new OpenLayers.Filter.Spatial({ + value: feature.geometry, + projection: this.map.getProjection(), + type: OpenLayers.Filter.Spatial.INTERSECTS + }); + } else { + return new OpenLayers.Filter.Comparison(); + } + }, + + /** + * Method: createVectorLayer + * + * Returns: + * {OpenLayers.Layer.Vector} + */ + createVectorLayer: function() { + var layer = (this.vectorLayer) ? + this.vectorLayer : new OpenLayers.Layer.Vector('filter_builder', { + displayInLayerSwitcher: false + }); + if(OpenLayers.Util.indexOf(this.map.layers, layer) < 0) { + this.map.addLayer(layer); + } + // each time a new feature is added, a new spatial condition is added. + layer.events.on({ + "featureadded": function(options) { + this.addCondition("spatial", options.feature); + this.deactivateControls(); + }, + scope: this + }); + return layer; + }, + + /** + * Method: wrapFilter + * Given a non-logical filter, this creates parent filters depending on + * the . + * + * Parameters: + * filter - {OpenLayers.Filter} A non-logical filter. + * + * Returns: + * {OpenLayers.Filter} A wrapped version of the input filter. + */ + wrapFilter: function(filter) { + var type; + if(this.defaultBuilderType === Styler.FilterBuilder.ALL_OF) { + type = OpenLayers.Filter.Logical.AND; + } else { + type = OpenLayers.Filter.Logical.OR; + } + return new OpenLayers.Filter.Logical({ + type: OpenLayers.Filter.Logical.OR, + filters: [ + new OpenLayers.Filter.Logical({ + type: type, filters: [filter] + }) + ] + }); + }, + + /** + * Method: addCondition + * Add a new condition or group of conditions to the builder. This + * modifies the filter and adds a panel representing the new condition + * or group of conditions. + */ + addCondition: function(conditionType, feature) { + var filter, type; + + var cfg = { + customizeFilterOnInit: (conditionType === "group") && false, + listeners: { + "change": function() { + this.fireEvent("change", this); + }, + "loaded": function() { + this.fireEvent("loaded"); + }, + "loading": function() { + this.fireEvent("loading"); + }, + scope: this + } + }; + + switch (conditionType) { + case "group": + filter = this.wrapFilter(this.createDefaultFilter()); + Ext.apply(cfg, { + xtype: "gx_filterbuilder", + filter: filter, + deactivable: this.deactivable, + filterPanelOptions: Ext.apply({}, this.filterPanelOptions), + attributes: this.attributes + }); + break; + case "spatial": + filter = this.createDefaultFilter(feature); + Ext.apply(cfg, { + xtype: "gx_spatialfilterpanel", + filter: filter, + cookieProvider: this.cookieProvider, + feature: feature, + toggleGroup: "querier", + map: this.map + }); + break; + default: + filter = this.createDefaultFilter(); + Ext.apply(cfg, { + xtype: "gx_filterpanel", + filter: filter, + attributes: this.attributes, + filterPanelOptions: Ext.apply({}, this.filterPanelOptions) + }); + } + var newChild = this.newRow(cfg); + this.childFiltersPanel.add(newChild); + this.filter.filters[0].filters.push(filter); + this.childFiltersPanel.doLayout(); + }, + + /** + * Method: removeCondition + * Remove a condition or group of conditions from the builder. This + * modifies the filter and removes the panel representing the condition + * or group of conditions. + */ + removeCondition: function(panel, filter) { + var parent = this.filter.filters[0].filters; + if(parent.length >= 1) { + parent.remove(filter); + panel.getComponent(1).getComponent(0).tearDown(); + this.childFiltersPanel.remove(panel); + } + this.fireEvent("change", this); + }, + + createBuilderTypeCombo: function() { + var types = this.allowedBuilderTypes || [ + Styler.FilterBuilder.ANY_OF, Styler.FilterBuilder.ALL_OF, + Styler.FilterBuilder.NONE_OF + ]; + var numTypes = types.length; + var data = new Array(numTypes), type; + for(var i=0; i