~dongpo-deng/sahana-eden/test

« back to all changes in this revision

Viewing changes to static/scripts/gis/geoext/lib/GeoExt/widgets/VectorLegend.js

  • Committer: Deng Dongpo
  • Date: 2010-08-01 09:29:44 UTC
  • Revision ID: dongpo@dhcp-21193.iis.sinica.edu.tw-20100801092944-8t9obt4xtl7otesb
initial

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * Copyright (c) 2008-2010 The Open Source Geospatial Foundation
 
3
 * 
 
4
 * Published under the BSD license.
 
5
 * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
 
6
 * of the license.
 
7
 */
 
8
 
 
9
/**
 
10
 * @include GeoExt/widgets/FeatureRenderer.js
 
11
 * @requires GeoExt/widgets/LayerLegend.js
 
12
 */
 
13
 
 
14
/** api: (define)
 
15
 *  module = GeoExt
 
16
 *  class = VectorLegend
 
17
 */
 
18
 
 
19
/** api: (extends)
 
20
 * GeoExt/widgets/LayerLegend.js
 
21
 */
 
22
 
 
23
Ext.namespace('GeoExt');
 
24
 
 
25
/** api: constructor
 
26
 *  .. class:: VectorLegend(config)
 
27
 *
 
28
 *      Create a vector legend.
 
29
 */
 
30
GeoExt.VectorLegend = Ext.extend(GeoExt.LayerLegend, {
 
31
 
 
32
    /** api: config[layerRecord]
 
33
     *  :class:`GeoExt.data.LayerRecord`
 
34
     *  The record containing a vector layer that this legend will be based on.  
 
35
     *  One of ``layerRecord``, ``layer``,  or ``rules`` must be specified in 
 
36
     *  the config.
 
37
     */
 
38
    layerRecord: null,
 
39
    
 
40
    /** api: config[layer]
 
41
     *  ``OpenLayers.Layer.Vector``
 
42
     *  The layer that this legend will be based on.  One of ``layer``, 
 
43
     *  ``rules``, or ``layerRecord`` must be specified in the config.
 
44
     */
 
45
    layer: null,
 
46
 
 
47
    /** api: config[rules]
 
48
     * ``Array(OpenLayers.Rule)``
 
49
     *  List of rules.  One of ``rules``, ``layer``, or ``layerRecord`` must be 
 
50
     *  specified in the config.  The ``symbolType`` property must also be
 
51
     *  provided if only ``rules`` are given in the config.
 
52
     */
 
53
    rules: null,
 
54
    
 
55
    /** api: config[symbolType]
 
56
     *  ``String``
 
57
     *  The symbol type for legend swatches.  Must be one of ``"Point"``, 
 
58
     *  ``"Line"``, or ``"Polygon"``.  If not provided, the ``layer`` or
 
59
     *  ``layerRecord`` config property must be specified, and the geometry type
 
60
     *  of the first feature found on the layer will be used. If a rule does
 
61
     *  not have a symbolizer for ``symbolType``, we look at the symbolizers
 
62
     *  for the rule, and see if it has a ``"Point"``, ``"Line"`` or
 
63
     *  ``"Polygon"`` symbolizer, which we use for rendering a swatch of the
 
64
     *  respective geometry type. 
 
65
     */
 
66
    symbolType: null,
 
67
 
 
68
    /** api: config[untitledPrefix]
 
69
     *  ``String``
 
70
     *  The prefix to use as a title for rules with no title or
 
71
     *  name.  Default is ``"Untitled "``.  Prefix will be appended with a
 
72
     *  number.
 
73
     */
 
74
    untitledPrefix: "Untitled ",
 
75
    
 
76
    /** api: config[clickableSymbol]
 
77
     *  ``Boolean``
 
78
     *  Set cursor style to "pointer" for symbolizers.  Register for
 
79
     *  the ``symbolclick`` event to handle clicks.  Note that click events
 
80
     *  are fired regardless of this value.  If ``false``, no cursor style will
 
81
     *  be set.  Default is ``false``.
 
82
     */
 
83
    clickableSymbol: false,
 
84
    
 
85
    /** api: config[clickableTitle]
 
86
     *  ``Boolean``
 
87
     *  Set cursor style to "pointer" for rule titles.  Register for
 
88
     *  the ``titleclick`` event to handle clicks.  Note that click events
 
89
     *  are fired regardless of this value.  If ``false``, no cursor style will
 
90
     *  be set.  Default is ``false``.
 
91
     */
 
92
    clickableTitle: false,
 
93
    
 
94
    /** api: config[selectOnClick]
 
95
     *  ``Boolean``
 
96
     *  Set to true if a rule should be selected by clicking on the
 
97
     *  symbol or title. Selection will trigger the ruleselected event, and
 
98
     *  a click on a selected rule will unselect it and trigger the
 
99
     *  ``ruleunselected`` event. Default is ``false``.
 
100
     */
 
101
    selectOnClick: false,
 
102
    
 
103
    /** api: config[enableDD]
 
104
     *  ``Boolean``
 
105
     *  Allow drag and drop of rules. Default is ``false``.
 
106
     */
 
107
    enableDD: false,
 
108
    
 
109
    /** api: config[bodyBorder]
 
110
     *  ``Boolean``
 
111
     *  Show a border around the legend panel. Default is ``false``.
 
112
     */
 
113
    bodyBorder: false,
 
114
 
 
115
    /** private: property[feature]
 
116
     *  ``OpenLayers.Feature.Vector``
 
117
     *  Cached feature for rendering.
 
118
     */
 
119
    feature: null,
 
120
    
 
121
    /** private: property[selectedRule]
 
122
     *  ``OpenLayers.Rule``
 
123
     *  The rule that is currently selected.
 
124
     */
 
125
    selectedRule: null,
 
126
 
 
127
    /** private: property[currentScaleDenominator]
 
128
     *  ``Number`` 
 
129
     *  The current scale denominator of any map associated with this
 
130
     *  legend.  Use :meth`setCurrentScaleDenominator` to change this.  If not
 
131
     *  set an entry for each rule will be rendered.  If set, only rules that
 
132
     *  apply for the given scale will be rendered.
 
133
     */
 
134
    currentScaleDenominator: null,
 
135
    
 
136
    /** private: property[untitledCount]
 
137
     *  ``Number``
 
138
     *  Last number used for untitled rule.
 
139
     */
 
140
    untitledCount: 0,
 
141
    
 
142
    /** private: method[initComponent]
 
143
     *  Initializes the Vector legend.
 
144
     */
 
145
    initComponent: function() {
 
146
        GeoExt.VectorLegend.superclass.initComponent.call(this);
 
147
        if (this.layerRecord) {
 
148
            this.layer = this.layerRecord.get("layer");
 
149
            if (this.layer.map) {
 
150
                this.currentScaleDenominator = this.layer.map.getScale();
 
151
                this.layer.map.events.on({
 
152
                    "zoomend": this.onMapZoom,
 
153
                    scope: this
 
154
                });
 
155
            }
 
156
        }
 
157
        
 
158
        // determine symbol type
 
159
        if (!this.symbolType) {
 
160
            if (this.feature) {
 
161
                this.symbolType = this.symbolTypeFromFeature(this.feature);
 
162
            } else if (this.layer) {
 
163
                if (this.layer.features.length > 0) {
 
164
                    var feature = this.layer.features[0].clone();
 
165
                    feature.attributes = {};
 
166
                    this.feature = feature;
 
167
                    this.symbolType = this.symbolTypeFromFeature(this.feature);
 
168
                } else {
 
169
                    this.layer.events.on({
 
170
                        featuresadded: this.onFeaturesAdded,
 
171
                        scope: this
 
172
                    });
 
173
                }
 
174
            }
 
175
        }
 
176
        
 
177
        // set rules if not provided
 
178
        if (this.layer && this.feature && !this.rules) {
 
179
            this.setRules();
 
180
        }
 
181
 
 
182
        this.rulesContainer = new Ext.Container({
 
183
            autoEl: {}
 
184
        });
 
185
        
 
186
        this.add(this.rulesContainer);
 
187
        
 
188
        this.addEvents(
 
189
            /** api: event[titleclick]
 
190
             *  Fires when a rule title is clicked.
 
191
             *
 
192
             *  Listener arguments:
 
193
             *  
 
194
             *  * comp - :class:`GeoExt.VectorLegend`` This component.
 
195
             *  * rule - ``OpenLayers.Rule`` The rule whose title was clicked.
 
196
             */
 
197
            "titleclick", 
 
198
 
 
199
            /** api: event[symbolclick]
 
200
             *  Fires when a rule symbolizer is clicked.
 
201
             *
 
202
             *  Listener arguments:
 
203
             *  
 
204
             *  * comp - :class:`GeoExt.VectorLegend`` This component.
 
205
             *  * rule - ``OpenLayers.Rule`` The rule whose symbol was clicked.
 
206
             */
 
207
            "symbolclick",
 
208
 
 
209
            /** api: event[ruleclick]
 
210
             *  Fires when a rule entry is clicked (fired with symbolizer or
 
211
             *  title click).
 
212
             *
 
213
             *  Listener arguments:
 
214
             *  
 
215
             *  * comp - :class:`GeoExt.VectorLegend`` This component.
 
216
             *  * rule - ``OpenLayers.Rule`` The rule that was clicked.
 
217
             */
 
218
            "ruleclick",
 
219
            
 
220
            /** api: event[ruleselected]
 
221
             *  Fires when a rule is clicked and ``selectOnClick`` is set to 
 
222
             *  ``true``.
 
223
             * 
 
224
             *  Listener arguments:
 
225
             *  
 
226
             *  * comp - :class:`GeoExt.VectorLegend`` This component.
 
227
             *  * rule - ``OpenLayers.Rule`` The rule that was selected.
 
228
             */
 
229
            "ruleselected",
 
230
            
 
231
            /** api: event[ruleunselected]
 
232
             *  Fires when the selected rule is clicked and ``selectOnClick`` 
 
233
             *  is set to ``true``, or when a rule is unselected by selecting a
 
234
             *  different one.
 
235
             * 
 
236
             *  Listener arguments:
 
237
             *  
 
238
             *  * comp - :class:`GeoExt.VectorLegend`` This component.
 
239
             *  * rule - ``OpenLayers.Rule`` The rule that was unselected.
 
240
             */
 
241
            "ruleunselected",
 
242
            
 
243
            /** api: event[rulemoved]
 
244
             *  Fires when a rule is moved.
 
245
             * 
 
246
             *  Listener arguments:
 
247
             *  
 
248
             *  * comp - :class:`GeoExt.VectorLegend`` This component.
 
249
             *  * rule - ``OpenLayers.Rule`` The rule that was moved.
 
250
             */
 
251
            "rulemoved"
 
252
        ); 
 
253
        
 
254
        this.update();
 
255
    },
 
256
    
 
257
    /** private: method[onMapZoom]
 
258
     *  Listener for map zoomend.
 
259
     */
 
260
    onMapZoom: function() {
 
261
        this.setCurrentScaleDenominator(
 
262
            this.layer.map.getScale()
 
263
        );
 
264
    },
 
265
    
 
266
    /** private: method[symbolTypeFromFeature]
 
267
     *  :arg feature:  ``OpenLayers.Feature.Vector``
 
268
     *
 
269
     *  Determine the symbol type given a feature.
 
270
     */
 
271
    symbolTypeFromFeature: function(feature) {
 
272
        var match = feature.geometry.CLASS_NAME.match(/Point|Line|Polygon/);
 
273
        return (match && match[0]) || "Point";
 
274
    },
 
275
    
 
276
    /** private: method[onFeaturesAdded]
 
277
     *  Set as a one time listener for the ``featuresadded`` event on the layer
 
278
     *  if it was provided with no features originally.
 
279
     */
 
280
    onFeaturesAdded: function() {
 
281
        this.layer.events.un({
 
282
            featuresadded: this.onFeaturesAdded,
 
283
            scope: this
 
284
        });
 
285
        var feature = this.layer.features[0].clone();
 
286
        feature.attributes = {};
 
287
        this.feature = feature;
 
288
        this.symbolType = this.symbolTypeFromFeature(this.feature);
 
289
        if (!this.rules) {
 
290
            this.setRules();
 
291
        }
 
292
        this.update();
 
293
    },
 
294
    
 
295
    /** private: method[setRules]
 
296
     *  Sets the ``rules`` property for this.  This is called when the component
 
297
     *  is constructed without rules.  Rules will be derived from the layer's 
 
298
     *  style map if it has one.
 
299
     */
 
300
    setRules: function() {
 
301
        var style = this.layer.styleMap && this.layer.styleMap.styles["default"];
 
302
        if (!style) {
 
303
            style = new OpenLayers.Style();
 
304
        }
 
305
        if (style.rules.length === 0) {
 
306
            this.rules = [
 
307
                new OpenLayers.Rule({
 
308
                    symbolizer: style.createSymbolizer(this.feature)
 
309
                })
 
310
            ];
 
311
        } else {
 
312
            this.rules = style.rules;                
 
313
        }
 
314
    },
 
315
    
 
316
    /** api: method[setCurrentScaleDenominator]
 
317
     *  :arg scale: ``Number`` The scale denominator.
 
318
     *
 
319
     *  Set the current scale denominator.  This will hide entries for any
 
320
     *  rules that don't apply at the current scale.
 
321
     */
 
322
    setCurrentScaleDenominator: function(scale) {
 
323
        if (scale !== this.currentScaleDenominator) {
 
324
            this.currentScaleDenominator = scale;
 
325
            this.update();
 
326
        }
 
327
    },
 
328
 
 
329
    /** private: method[getRuleEntry]
 
330
     *  :arg rule: ``OpenLayers.Rule``
 
331
     *  :returns: ``Ext.Container``
 
332
     *
 
333
     *  Get the item corresponding to the rule.
 
334
     */
 
335
    getRuleEntry: function(rule) {
 
336
        return this.rulesContainer.items.get(this.rules.indexOf(rule));
 
337
    },
 
338
 
 
339
    /** private: method[addRuleEntry]
 
340
     *  :arg rule: ``OpenLayers.Rule``
 
341
     *  :arg noDoLayout: ``Boolean``  Don't call doLayout after adding rule.
 
342
     *      Default is ``false``.
 
343
     *
 
344
     *  Add a new rule entry in the rules container. This
 
345
     *  method does not add the rule to the rules array.
 
346
     */
 
347
    addRuleEntry: function(rule, noDoLayout) {
 
348
        this.rulesContainer.add(this.createRuleEntry(rule));
 
349
        if (!noDoLayout) {
 
350
            this.doLayout();
 
351
        }
 
352
    },
 
353
 
 
354
    /** private: method[removeRuleEntry]
 
355
     *  :arg rule: ``OpenLayers.Rule``
 
356
     *  :arg noDoLayout: ``Boolean``  Don't call doLayout after removing rule.
 
357
     *      Default is ``false``.
 
358
     *
 
359
     *  Remove a rule entry from the rules container, this
 
360
     *  method assumes the rule is in the rules array, and
 
361
     *  it does not remove the rule from the rules array.
 
362
     */
 
363
    removeRuleEntry: function(rule, noDoLayout) {
 
364
        var ruleEntry = this.getRuleEntry(rule);
 
365
        if (ruleEntry) {
 
366
            this.rulesContainer.remove(ruleEntry);
 
367
            if (!noDoLayout) {
 
368
                this.doLayout();
 
369
            }
 
370
        }
 
371
    },
 
372
    
 
373
    /** private: method[selectRuleEntry]
 
374
     */
 
375
    selectRuleEntry: function(rule) {
 
376
        var newSelection = rule != this.selectedRule;
 
377
        if (this.selectedRule) {
 
378
            this.unselect();
 
379
        }
 
380
        if (newSelection) {
 
381
            var ruleEntry = this.getRuleEntry(rule);
 
382
            ruleEntry.body.addClass("x-grid3-row-selected");
 
383
            this.selectedRule = rule;
 
384
            this.fireEvent("ruleselected", this, rule);
 
385
        }
 
386
    },
 
387
    
 
388
    /** private: method[unselect]
 
389
     */
 
390
    unselect: function() {
 
391
        this.rulesContainer.items.each(function(item, i) {
 
392
            if (this.rules[i] == this.selectedRule) {
 
393
                item.body.removeClass("x-grid3-row-selected");
 
394
                this.selectedRule = null;
 
395
                this.fireEvent("ruleunselected", this, this.rules[i]);
 
396
            }
 
397
        }, this);
 
398
    },
 
399
 
 
400
    /** private: method[createRuleEntry]
 
401
     */
 
402
    createRuleEntry: function(rule) {
 
403
        var applies = true;
 
404
        if (this.currentScaleDenominator != null) {
 
405
            if (rule.minScaleDenominator) {
 
406
                applies = applies && (this.currentScaleDenominator >= rule.minScaleDenominator);
 
407
            }
 
408
            if (rule.maxScaleDenominator) {
 
409
                applies = applies && (this.currentScaleDenominator < rule.maxScaleDenominator);
 
410
            }
 
411
        }
 
412
        return {
 
413
            xtype: "panel",
 
414
            layout: "column",
 
415
            border: false,
 
416
            hidden: !applies,
 
417
            bodyStyle: this.selectOnClick ? {cursor: "pointer"} : undefined,
 
418
            defaults: {
 
419
                border: false
 
420
            },
 
421
            items: [
 
422
                this.createRuleRenderer(rule),
 
423
                this.createRuleTitle(rule)
 
424
            ],
 
425
            listeners: {
 
426
                render: function(comp){
 
427
                    this.selectOnClick && comp.getEl().on({
 
428
                        click: function(comp){
 
429
                            this.selectRuleEntry(rule);
 
430
                        },
 
431
                        scope: this
 
432
                    });
 
433
                    if (this.enableDD == true) {
 
434
                        this.addDD(comp);
 
435
                    }
 
436
                },
 
437
                scope: this
 
438
            }
 
439
        };
 
440
    },
 
441
 
 
442
    /** private: method[createRuleRenderer]
 
443
     *  :arg rule: ``OpenLayers.Rule``
 
444
     *  :returns: ``GeoExt.FeatureRenderer``
 
445
     *
 
446
     *  Create a renderer for the rule.
 
447
     */
 
448
    createRuleRenderer: function(rule) {
 
449
        var symbolizer = rule.symbolizer;
 
450
        var types = [this.symbolType, "Point", "Line", "Polygon"];
 
451
        var type, haveType;
 
452
        for(var i=0, len=types.length; i<len; ++i) {
 
453
            type = types[i];
 
454
            if(symbolizer[type]) {
 
455
                symbolizer = symbolizer[type];
 
456
                haveType = true;
 
457
                break;
 
458
            }
 
459
        }
 
460
        return {
 
461
            xtype: "gx_renderer",
 
462
            symbolType: haveType === true ? type : this.symbolType,
 
463
            symbolizers: [symbolizer],
 
464
            style: this.clickableSymbol ? {cursor: "pointer"} : undefined,
 
465
            listeners: {
 
466
                click: function() {
 
467
                    if (this.clickableSymbol) {
 
468
                        this.fireEvent("symbolclick", this, rule);
 
469
                        this.fireEvent("ruleclick", this, rule);
 
470
                    }
 
471
                },
 
472
                scope: this
 
473
            }
 
474
        };
 
475
    },
 
476
 
 
477
    /** private: method[createRuleTitle]
 
478
     *  :arg rule: ``OpenLayers.Rule``
 
479
     *  :returns: ``Ext.Component``
 
480
     *
 
481
     *  Create a title component for the rule.
 
482
     */
 
483
    createRuleTitle: function(rule) {
 
484
        return {
 
485
            cls: "x-form-item",
 
486
            style: "padding: 0.2em 0.5em 0;", // TODO: css
 
487
            bodyStyle: Ext.applyIf({background: "transparent"}, 
 
488
                this.clickableTitle ? {cursor: "pointer"} : undefined),
 
489
            html: this.getRuleTitle(rule),
 
490
            listeners: {
 
491
                render: function(comp) {
 
492
                    this.clickableTitle && comp.getEl().on({
 
493
                        click: function() {
 
494
                            this.fireEvent("titleclick", this, rule);
 
495
                            this.fireEvent("ruleclick", this, rule);
 
496
                        },
 
497
                        scope: this
 
498
                    });
 
499
                },
 
500
                scope: this
 
501
            }
 
502
        };
 
503
    },
 
504
    
 
505
    /** private: method[addDD]
 
506
     *  :arg component: ``Ext.Component``
 
507
     *
 
508
     *  Adds drag & drop functionality to a rule entry.
 
509
     */
 
510
    addDD: function(component) {
 
511
        var ct = component.ownerCt;
 
512
        var panel = this;
 
513
        new Ext.dd.DragSource(component.getEl(), {
 
514
            ddGroup: ct.id,
 
515
            onDragOut: function(e, targetId) {
 
516
                var target = Ext.getCmp(targetId);
 
517
                target.removeClass("gx-ruledrag-insert-above");
 
518
                target.removeClass("gx-ruledrag-insert-below");
 
519
                return Ext.dd.DragZone.prototype.onDragOut.apply(this, arguments);
 
520
            },
 
521
            onDragEnter: function(e, targetId) {
 
522
                var target = Ext.getCmp(targetId);
 
523
                var cls;
 
524
                var sourcePos = ct.items.indexOf(component);
 
525
                var targetPos = ct.items.indexOf(target);
 
526
                if (sourcePos > targetPos) {
 
527
                    cls = "gx-ruledrag-insert-above";
 
528
                } else if (sourcePos < targetPos) {
 
529
                    cls = "gx-ruledrag-insert-below";
 
530
                }                
 
531
                cls && target.addClass(cls);
 
532
                return Ext.dd.DragZone.prototype.onDragEnter.apply(this, arguments);
 
533
            },
 
534
            onDragDrop: function(e, targetId) {
 
535
                panel.moveRule(ct.items.indexOf(component),
 
536
                    ct.items.indexOf(Ext.getCmp(targetId)));
 
537
                return Ext.dd.DragZone.prototype.onDragDrop.apply(this, arguments);
 
538
            },
 
539
            getDragData: function(e) {
 
540
                var sourceEl = e.getTarget(".x-column-inner");
 
541
                if(sourceEl) {
 
542
                    var d = sourceEl.cloneNode(true);
 
543
                    d.id = Ext.id();
 
544
                    return {
 
545
                        sourceEl: sourceEl,
 
546
                        repairXY: Ext.fly(sourceEl).getXY(),
 
547
                        ddel: d
 
548
                    }
 
549
                }
 
550
            }
 
551
        });
 
552
        new Ext.dd.DropTarget(component.getEl(), {
 
553
            ddGroup: ct.id,
 
554
            notifyDrop: function() {
 
555
                return true;
 
556
            }
 
557
        });
 
558
    },
 
559
    
 
560
    /** api: method[update]
 
561
     *  Update rule titles and symbolizers.
 
562
     */
 
563
    update: function() {
 
564
        GeoExt.VectorLegend.superclass.update.apply(this, arguments);
 
565
        if (this.symbolType && this.rules) {
 
566
            if (this.rulesContainer.items) {
 
567
                var comp;
 
568
                for (var i=this.rulesContainer.items.length-1; i>=0; --i) {
 
569
                    comp = this.rulesContainer.getComponent(i);
 
570
                    this.rulesContainer.remove(comp, true);
 
571
                }
 
572
            }
 
573
            for (var i=0, ii=this.rules.length; i<ii; ++i) {
 
574
                this.addRuleEntry(this.rules[i], true);
 
575
            }
 
576
            this.doLayout();
 
577
            if (this.selectedRule) {
 
578
                this.getRuleEntry(this.selectedRule).body.addClass("x-grid3-row-selected");
 
579
            }
 
580
        }
 
581
    },
 
582
 
 
583
    /** private: method[updateRuleEntry]
 
584
     *  :arg rule: ``OpenLayers.Rule``
 
585
     *
 
586
     *  Update the renderer and the title of a rule.
 
587
     */
 
588
    updateRuleEntry: function(rule) {
 
589
        var ruleEntry = this.getRuleEntry(rule);
 
590
        if (ruleEntry) {
 
591
            ruleEntry.removeAll();
 
592
            ruleEntry.add(this.createRuleRenderer(rule));
 
593
            ruleEntry.add(this.createRuleTitle(rule));
 
594
            ruleEntry.doLayout();
 
595
        }
 
596
    },
 
597
    
 
598
    /** private: method[moveRule]
 
599
     */
 
600
    moveRule: function(sourcePos, targetPos) {
 
601
        var srcRule = this.rules[sourcePos];
 
602
        this.rules.splice(sourcePos, 1);
 
603
        this.rules.splice(targetPos, 0, srcRule);
 
604
        this.update();
 
605
        this.fireEvent("rulemoved", this, srcRule);
 
606
    },
 
607
    
 
608
    /** private: method[getRuleTitle]
 
609
     *  :returns: ``String``
 
610
     *
 
611
     *  Get a rule title given a rule.
 
612
     */
 
613
    getRuleTitle: function(rule) {
 
614
        return rule.title || rule.name || (this.untitledPrefix + (++this.untitledCount));
 
615
    },
 
616
 
 
617
    /** private: method[beforeDestroy]
 
618
     *  Override.
 
619
     */
 
620
    beforeDestroy: function() {
 
621
        if (this.layer) {
 
622
            if (this.layer.events) {
 
623
                this.layer.events.un({
 
624
                    featuresadded: this.onFeaturesAdded,
 
625
                    scope: this
 
626
                });
 
627
            }
 
628
            if (this.layer.map && this.layer.map.events) {
 
629
                this.layer.map.events.un({
 
630
                    "zoomend": this.onMapZoom,
 
631
                    scope: this
 
632
                });
 
633
            }
 
634
        }
 
635
        delete this.layer;
 
636
        delete this.rules;
 
637
        GeoExt.VectorLegend.superclass.beforeDestroy.apply(this, arguments);
 
638
    }
 
639
 
 
640
});
 
641
 
 
642
/** private: method[supports]
 
643
 *  Private override
 
644
 */
 
645
GeoExt.VectorLegend.supports = function(layerRecord) {
 
646
    return layerRecord.get("layer") instanceof OpenLayers.Layer.Vector;
 
647
};
 
648
 
 
649
/** api: legendtype = gx_vectorlegend */
 
650
GeoExt.LayerLegend.types["gx_vectorlegend"] = GeoExt.VectorLegend;
 
651
 
 
652
/** api: xtype = gx_vectorlegend */
 
653
Ext.reg("gx_vectorlegend", GeoExt.VectorLegend);