/*---------------- 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.config.Colors; import nl.idgis.giclient.gis.ActiveLayerListener; import nl.idgis.giclient.gis.Layer; import nl.idgis.giclient.gis.GILayer; import nl.idgis.giclient.gis.LayerExpandedListener; import nl.idgis.giclient.gis.LayerFilteredFeaturesListener; import nl.idgis.giclient.gis.LayerVisibleListener; import nl.idgis.giclient.gis.SelectionListener; import nl.idgis.giclient.gui.mapviewer.MapLayerLoadListener; import nl.idgis.giclient.Ruler; import mx.controls.CheckBox; import nl.idgis.giclient.gis.LayerRefreshListener; import mx.utils.Delegate; import nl.idgis.giclient.gis.SelectableLayer; import nl.idgis.giclient.event.StateEvent; import nl.idgis.giclient.event.StateEventListener; import nl.idgis.giclient.geoma.Envelope; import nl.idgis.giclient.gis.WMLayer; import nl.idgis.giclient.webserviceconnector.wmsconnector.WMSConnector; import nl.idgis.giclient.gis.GIS; class nl.idgis.giclient.gui.legendviewer.LegendLayer extends MovieClip implements ActiveLayerListener, LayerVisibleListener, LayerExpandedListener, LayerRefreshListener, LayerFilteredFeaturesListener, SelectionListener, MapLayerLoadListener, StateEventListener { private var ruler:Ruler = null; // Set by init object. private var layer:Layer = null; // Set by init object. private var viewerWidth:Number = 0; // Set by init object. private var depth:Number = 0; private var normalColor:Number = 0x000000; private var lightColor:Number = 0xFFFFFF; private var darkColor:Number = 0x404040; private var checkBox:CheckBox = null; private var graphic:MovieClip = null; private var expander:MovieClip = null; private var textField:TextField = null; private var cross:MovieClip = null; private var zoom:MovieClip = null; private var xPosZoom:Number = 40; private var xPosCross:Number = 20; private var xPosCheckBox:Number = 20; private var xPosSelectionIndicator = 20; private var xPosLoadProgressIndicator = 37; private var xPosGraphic:Number = 46; private var xPosExpander:Number = 5; private var yPos:Number = 7; private var tabWidth:Number = 18; private var checkBoxSize:Number = 10; private var limitedGraphicHeight = 0; private var arrowLength:Number = 4; private var rightArrowMargin:Number = 10; private var verticalArrowMargin:Number = 3; private var intervalID = null; // For some reason intervalID cannot be given a type, not even Object. private var pressed:Boolean = false; private var dragging:Boolean = false; private var startedDragging:Boolean = false; private var layerEnabled:Boolean; private var textFormat:TextFormat; private var disabledTextFormat:TextFormat; private var lastHeight:Number = -1; function onLoad():Void { normalColor = _parent.frame.getBackGroundColor(); textFormat = new TextFormat(); textFormat.font = "_sans"; textFormat.size = 11; disabledTextFormat = new TextFormat(); disabledTextFormat.font = "_sans"; disabledTextFormat.size = 11; disabledTextFormat.color = 0x808080; ruler.getGIS().gisEventDispatcher.addActiveLayerListener(this); layer.layerEventDispatcher.addLayerVisibleListener(this); layer.layerEventDispatcher.addLayerExpandedListener(this); layer.layerEventDispatcher.addLayerRefreshListener(this); layer.layerEventDispatcher.addLayerFilteredFeaturesListener(this); layer.layerEventDispatcher.addSelectionListener(this); layer.layerEventDispatcher.addMapLayerLoadListener(this); layer.addEventListener(this, "Layer", StateEvent.CHANGE, "currentScale"); layerEnabled = true; drawAll(); } function onChangeActiveLayer():Void { drawBackGround(); } function onChangeLayerVisible(layer:Layer):Void { checkBox.selected = layer.isVisible(); } function onChangeLayerExpanded():Void { plusOrMinusExpander(); if(graphic != null) { graphic._visible = layer.isExpanded(); completeLegend(true); } else { setGraphic(); } } function onLayerRefresh(layer:Layer):Void { setGraphic(); } function onChangeLayerFilteredFeatures(layer:Layer):Void { setFilterIndicatorVisible(); } function onChangeLayerSelectedFeatures(layer:Layer, selected:Boolean, subSelected:Boolean, current:Boolean):Void { if (selected) { setSelectionIndicatorVisible(); } } function onMapLayerLoadProgress(layer:Layer, percentage:Number):Void { updateLoadProgressIndicator(percentage); } function onStateEvent(stateEvent:StateEvent):Void { var sourceClassName:String = stateEvent.getSourceClassName(); var actionType:Number = stateEvent.getActionType(); var propertyName:String = stateEvent.getPropertyName(); if (sourceClassName + "_" + actionType + "_" + propertyName == "Layer_" + StateEvent.CHANGE + "_currentScale") { setGraphic(); } } private function drawAll():Void { addCheckBox(); addCross(); addZoom(); addFilterIndicator(); addSelectionIndicator(); addLoadProgressIndicator(); setGraphic(); setCross(); } private function addZoom():Void { zoom = createEmptyMovieClip("zoom", depth + 11); zoom.attachMovie("Zoom", "icon", 0); zoom._width = zoom._width / 3; zoom._height = zoom._height / 3; zoom._x = xPosZoom + layer.getLevel() * tabWidth;; zoom._y = yPos + 4; zoom._visible = false; } private function addCross():Void { cross = createEmptyMovieClip("cross", depth + 10); cross.lineStyle(2 ,0xFF0000, 100); cross.lineTo(10, 10); cross.moveTo(10, 0); cross.lineTo(0, 10); cross._x = xPosCross; cross._y = yPos; } private function addCheckBox():Void { var initObject:Object = new Object(); initObject["_x"] = xPosCheckBox + layer.getLevel() * tabWidth;// + 20; initObject["_y"] = yPos; initObject["_width"] = checkBoxSize; initObject["_height"] = checkBoxSize; initObject["selected"] = layer.isVisible(); checkBox = CheckBox(attachMovie("CheckBox", "checkBox_mc", depth + 6, initObject)); checkBox.addEventListener("click", Delegate.create(this, onClickCheckBox)); } function onClickCheckBox(eventObject:Object):Void { var visible:Boolean = checkBox.selected; layer.setVisible(visible); } private function addFilterIndicator():Void { createEmptyMovieClip("filterIndicator", depth + 1); var tempX:Number = xPosLoadProgressIndicator + layer.getLevel() * tabWidth - 3; var tempY:Number = yPos; this["filterIndicator"]._alpha = 0; this["filterIndicator"].beginFill(Colors.filterColor, 70); this["filterIndicator"].moveTo(2, 2); this["filterIndicator"].lineTo(viewerWidth - 2, 2); this["filterIndicator"].lineTo(viewerWidth - 2, tempY + 16); this["filterIndicator"].lineTo(2, tempY + 16); this["filterIndicator"].endFill(); this["filterIndicator"].attachMovie("Filter","filter", 1, {_width:16, _height:16}); this["filterIndicator"]["filter"]._x = tempX + 6; this["filterIndicator"]["filter"]._y = tempY + 6; this["filterIndicator"]["filter"]._alpha = 80; setFilterIndicatorVisible(); } private function setFilterIndicatorVisible():Void { if ((layer instanceof SelectableLayer) && (SelectableLayer(layer).isFiltered())) { this["filterIndicator"]._visible = true; } else { this["filterIndicator"]._visible = false; } } private function addSelectionIndicator():Void { createEmptyMovieClip("selectionIndicator", depth + 3); this["selectionIndicator"]._visible = false; this["selectionIndicator"]._x = xPosSelectionIndicator + layer.getLevel() * tabWidth; this["selectionIndicator"]._y = yPos; this["selectionIndicator"].beginFill(Colors.selectionColor, 70); this["selectionIndicator"].moveTo(-2, -2); this["selectionIndicator"].lineTo(14, -2); this["selectionIndicator"].lineTo(14, 14); this["selectionIndicator"].lineTo(-2, 14); this["selectionIndicator"].endFill(); setSelectionIndicatorVisible(); } private function setSelectionIndicatorVisible():Void { if ((layer instanceof SelectableLayer) && (SelectableLayer(layer).getSelectedFeatures().length > 0)) { this["selectionIndicator"]._visible = true; } else { this["selectionIndicator"]._visible = false; } } private function addLoadProgressIndicator():Void { createEmptyMovieClip("loadProgressIndicator", depth + 9); this["loadProgressIndicator"]._x = xPosLoadProgressIndicator + layer.getLevel() * tabWidth + 2; this["loadProgressIndicator"]._y = yPos + 1; this["loadProgressIndicator"].fade = function() { this._alpha -= 20; if (this._alpha < 20) { this._parent.clearLoadProgressIndicator(); } }; } private function updateLoadProgressIndicator(percentage : Number) : Void { if (percentage == 100) { if (intervalID == null) { intervalID = setInterval(this["loadProgressIndicator"], "fade", 100); } if(this["filterIndicator"] != null) { this["filterIndicator"]._alpha = 70; } } else { this["filterIndicator"]._alpha = 0; clearLoadProgressIndicator(); } this["loadProgressIndicator"].lineStyle(3, lightColor, 100); this["loadProgressIndicator"].moveTo(0, 0); this["loadProgressIndicator"].lineTo(0, checkBoxSize); this["loadProgressIndicator"].lineStyle(3, darkColor, 100); this["loadProgressIndicator"].moveTo(0, checkBoxSize); this["loadProgressIndicator"].lineTo(0, checkBoxSize - (percentage / checkBoxSize)); } function clearLoadProgressIndicator():Void { this["loadProgressIndicator"].clear(); this["loadProgressIndicator"]._alpha = 100; if (intervalID != null) { clearInterval(intervalID); intervalID = null; } } private function hasExpandedParent():Boolean { var currentParent:Layer = layer.getSuperLayer(); while(currentParent != null) { if(!currentParent.isExpanded()) { return false; } currentParent = currentParent.getSuperLayer(); } return true; } private function setGraphic():Void { if (graphic != null) { graphic.removeMovieClip(); graphic = null; } if (layer.getLayers().length == 0 && hasExpandedParent()) { // If the layer has no sublayers; layers with sublayers don't have legend graphics of their own. graphic = createEmptyMovieClip("graphic_mc", depth + 5); var url:String = layer.getMapConnector().getLegendGraphic( layer, ruler.getGIS().getCurrentCentreScale().getScale()); if(url != null) { var mcl:MovieClipLoader = new MovieClipLoader(); mcl.addListener(this); mcl.loadClip(url, graphic); } else onLoadInit(null); } else { onLoadInit(null); } } function onLoadError(target_mc:MovieClip, errorCode:String, httpStatus:Number) { graphic = null; completeLegend(); } function onLoadInit(mc:MovieClip) { graphic = mc; completeLegend(); }; private function completeLegend(disableOnChangeLegendLayerHeight:Boolean):Void { if (graphic != null) { if(graphic._height == 0) { // Wait until graphic is fully loaded _global["setTimeout"](this, "completeLegend", 1); return; } graphic._visible = !hasLargeGraphic() || layer.isExpanded(); graphic._x = xPosGraphic + layer.getLevel() * tabWidth; graphic._y = yPos; if(!graphic["symbolsMoved"]) { for(var mc:String in graphic) { if (typeof(graphic[mc]) == "movieclip" && graphic[mc]._parent == graphic) { for(var mc2:String in graphic[mc]) { graphic[mc][mc2]["_x"] += graphic[mc][mc2]["_width"] / 2; } } } graphic["symbolsMoved"] = true; } if(!layerEnabled) { graphic._alpha = 50; } if (hasLargeGraphic()) { graphic._x -= tabWidth; graphic._y += checkBoxSize + yPos; } } setExpander(); setTextField(); drawBackGround(); drawTabLines(); drawOrMoveArrows(); var currentGraphic = this._height; if(currentGraphic != lastHeight && !disableOnChangeLegendLayerHeight) { lastHeight = currentGraphic; this._parent.onChangeLegendLayerHeight(this); } } function onReady() { //Called by the GI legend graphics. Not used any more. } private function setExpander():Void { if (hasLargeGraphic() || layer.getLayers().length > 0) { addExpander(); } else { removeExpander(); } } private function addExpander():Void { if (expander == null) { expander = createEmptyMovieClip("expander_mc", depth + 7); expander._x = xPosExpander + layer.getLevel() * tabWidth; expander._y = yPos; expander.beginFill(0xFFFFFF, 100); expander.lineStyle(1, darkColor, 80); expander.moveTo(0, 0); expander.lineTo(8, 0); expander.lineTo(8, 8); expander.lineTo(0, 8); expander.lineTo(0, 0); expander.endFill(); expander.createEmptyMovieClip("plus", 0); expander["plus"]._visible = false; expander["plus"].lineStyle(1, darkColor, 80); expander["plus"].moveTo(2, 4); expander["plus"].lineTo(7, 4); expander["plus"].moveTo(4, 2); expander["plus"].lineTo(4, 7); expander.createEmptyMovieClip("minus", 1); expander["minus"]._visible = false; expander["minus"].lineStyle(1, darkColor, 80); expander["minus"].moveTo(2, 4); expander["minus"].lineTo(7, 4); expander.onRelease = function() { this._parent.onClickExpander(); }; } plusOrMinusExpander(); } function onClickExpander():Void { layer.setExpanded(!layer.isExpanded()); } private function plusOrMinusExpander():Void { if (expander == null) { return; } if (layer.isExpanded()) { expander["plus"]._visible = false; expander["minus"]._visible = true; } else { expander["plus"]._visible = true; expander["minus"]._visible = false; } } private function removeExpander():Void { if (expander == null) { return; } expander.removeMovieClip(); expander = null; } private function setTextField():Void { addTextField(); } private function addTextField():Void { if (textField != null) { textField.removeTextField(); } var layerTitle:String = layer.getTitle(); var metrics:Object = textFormat.getTextExtent(layerTitle); var textFieldWidth:Number = metrics.textFieldWidth + 11; var textFieldHeight:Number = metrics.textFieldHeight + 3; var xpos:Number = xPosGraphic + layer.getLevel() * tabWidth; if (graphic != null && !hasLargeGraphic() && layer.getLayers().length == 0) { xpos += 26; } createTextField("textField_mc", depth + 8, xpos , yPos - 3, textFieldWidth, textFieldHeight); textField = this["textField_mc"]; textField.setNewTextFormat(textFormat); textField.html = true; textField.htmlText = getTitleHtml(); } private function getTitleHtml():String { var metaUrl:String = layer.getMetaUrl(); /*if (layer.getMapConnector() instanceof WMSConnector && ( metaUrl == null || metaUrl.length == 0) && graphic != null) { return ""; } else*/ if(metaUrl == null || metaUrl.length == 0) { return "" + layer.getTitle() + ""; } else { return "" + layer.getTitle() + ""; } } private function removeTextField():Void { if (textField == null) { return; } textField.removeTextField(); textField = null; } private function drawBackGround() { var active:Boolean = false; if (layer == ruler.getGIS().getActiveLayer()) { active = true; } var upLeftColor:Number; var downRightColor:Number; if (active) { upLeftColor = darkColor; downRightColor = lightColor; } else { upLeftColor = lightColor; downRightColor = darkColor; } var height:Number = getHeight(); clear(); beginFill(normalColor, 100); lineStyle(1, upLeftColor, 100); moveTo(0, height - 1); lineTo(0, 0); lineTo(viewerWidth - 1, 0); lineStyle(1, downRightColor, 100); lineTo(viewerWidth - 1, height - 1); lineTo(0, height - 1); endFill(); } private function drawTabLines():Void { createEmptyMovieClip("tabLine", depth + 0); this["tabLine"]._x = xPosExpander; this["tabLine"]._y = 0; this["tabLine"].lineStyle(1, darkColor, 20); for (var i:Number = 0; i < layer.getLevel() + 1; i++) { this["tabLine"].moveTo(i * tabWidth + xPosExpander - 1, 0); this["tabLine"].lineTo(i * tabWidth + xPosExpander - 1, getHeight() - 1); if (i == layer.getLevel()) { this["tabLine"].moveTo(i * tabWidth + xPosExpander - 1, yPos + 5); this["tabLine"].lineTo((i + 1) * tabWidth + xPosExpander - 1 /*+20 */, yPos + 5); } } } private function drawOrMoveArrows() { if (this["upArrow"] == null) { createEmptyMovieClip("upArrow", depth + 4 ); this["upArrow"]._x = this.viewerWidth - this.rightArrowMargin; this["upArrow"]._y = verticalArrowMargin; this["upArrow"].beginFill(darkColor, 80); this["upArrow"].lineStyle(1,darkColor, 80); this["upArrow"].moveTo(0,arrowLength); this["upArrow"].lineTo(arrowLength,arrowLength); this["upArrow"].lineTo(arrowLength/2,0); this["upArrow"].lineTo(0,arrowLength); this["upArrow"].endFill(); this["upArrow"].onRelease = function() { this._parent._parent.onClickLegendLayerArrow(this._parent.layer, "Frontward"); }; } else { this["upArrow"]._x = this.viewerWidth - this.rightArrowMargin; this["upArrow"]._y = verticalArrowMargin; } if (this["downArrow"] == null) { this["downArrow"] = this["upArrow"].duplicateMovieClip("downArrow", depth + 2); this["downArrow"]._x = this.viewerWidth - rightArrowMargin + arrowLength; this["downArrow"]._y = getHeight() - verticalArrowMargin - arrowLength/2; this["downArrow"]._rotation = 180; this["downArrow"].onRelease = function() { this._parent._parent.onClickLegendLayerArrow(this._parent.layer, "Backward"); }; } else { this["downArrow"]._x = this.viewerWidth - rightArrowMargin + arrowLength; this["downArrow"]._y = getHeight() - verticalArrowMargin - arrowLength/2; } } private function hasLargeGraphic():Boolean { if(layer.getMapConnector() instanceof WMSConnector) { return true; } else { if((GILayer(layer).legendIsDynamic() || graphic._height > 15)) { return true; } } return false; } public function getHeight():Number { var height:Number = yPos + checkBoxSize + yPos; if ((graphic != null) && (graphic._height > 0)) { if (hasLargeGraphic() && layer.isExpanded()) { height += graphic._height + yPos; } } return height; } /** * Is called when the nl.idgis.giclient.gui.legendviewer.LegendLayer is pressed. This may mean that this nl.idgis.giclient.gui.legendviewer.LegendLayer needs to be set active, but also * that the nl.idgis.giclient.gui.legendviewer.LegendLayer will have to be shuffled. */ function onSmartPress(Void):Void { pressed = true; } /** * Is called when the nl.idgis.giclient.gui.legendviewer.LegendLayer is released. This may mean that the nl.idgis.giclient.gui.legendviewer.LegendLayer is to be set active, but if the mouse has been * moved after pressing it may also mean that some shuffling needs to be done. */ function onSmartRelease(Void):Void { try { if (pressed && !dragging && layerEnabled) { //only change active layer if not dragging if (layer == ruler.getGIS().getActiveLayer()) { ruler.getGIS().setActiveLayer(null); } else { ruler.getGIS().setActiveLayer(layer); } } } catch (e:Error) { throw new Error("LegendLayer.onSmartRelease() error: " + e.toString()); } // Resets the mouse properties. pressed = false; dragging = false; startedDragging = false; } /** * Used to decide if the mouse has been moved after pressing a nl.idgis.giclient.gui.legendviewer.LegendLayer whether the nl.idgis.giclient.gui.legendviewer.LegendLayer has to be set * active. */ function onMouseMove() { if (pressed) { if (dragging == false) { dragging = true; startedDragging = true; } else { startedDragging = false; } } if (startedDragging) { this._parent.onStartDraggingLegendLayer(layer); // if(_visible); } if(layer.getMetaUrl() != null && layer.getMetaUrl().length > 0) { this.useHandCursor =_xmouse >= textField._x && _xmouse <= textField._x + textField._width && _ymouse >= textField._y && _ymouse <= textField._y + textField._height; } } /** * This method is used to reset the mouse properties. The method onMouseUp cannot do this, because it * is called before onSmartRelease, which will need these mouse properties. */ function onMouseDown() { pressed = false; dragging = false; startedDragging = false; } function setCross() : Void { var available:Boolean = layer.isAvailable(); cross._visible = !available; this["checkBox_mc"]._visible = available; this["loadProgressIndicator"]._visible = available; } function disable():Void { if(layerEnabled) { layerEnabled = false; checkBox.enabled = false; if(graphic != null) { graphic._alpha = 50; } textField.setTextFormat(disabledTextFormat); cross._alpha = 50; zoom._alpha = 50; } } function enable():Void { if(!layerEnabled) { layerEnabled = true; checkBox.enabled = true; if(graphic != null) { graphic._alpha = 100; } textField.setTextFormat(textFormat); textField.htmlText = getTitleHtml(); cross._alpha = 100; zoom._alpha = 100; } } function onPress():Void { if(layerEnabled && checkBox.hitTest(_root._xmouse, _root._ymouse, true)) { checkBox.onPress(); } else if(expander.hitTest(_root._xmouse, _root._ymouse, true)) { expander.onPress(); } else if(zoom._visible && zoom.hitTest(_root._xmouse, _root._ymouse, false)) { } else if(layer.getMetaUrl() != null && layer.getMetaUrl().length > 0 && _xmouse >= textField._x && _xmouse <= textField._x + textField._width && _ymouse >= textField._y && _ymouse <= textField._y + textField._height) { getURL(layer.getMetaUrl(), "_blank"); } else { onSmartPress(); } } function onRelease():Void { if(layerEnabled && checkBox.hitTest(_root._xmouse, _root._ymouse, true)) { checkBox.onRelease(); } else if(expander.hitTest(_root._xmouse, _root._ymouse, true)) { expander.onRelease(); } else if(zoom._visible && zoom.hitTest(_root._xmouse, _root._ymouse, false)) { zoomClicked(); } else { onSmartRelease(); } } private var zoomVisibleInterval:Number; function onRollOver():Void { this.useHandCursor = false; zoomVisibleInterval = setInterval(this, "setZoomVisible", 750); } function onRollOut():Void { zoom._visible = false; clearInterval(zoomVisibleInterval); } function setZoomVisible():Void { clearInterval(zoomVisibleInterval); zoom._visible = true; } private function zoomClicked() { var gism:GIS = ruler.getGIS(); var envelope:Envelope = layer.getEnvelope(); if(layer.isExtentZoomable()) { if(envelope != null) { gism.zoomToEnvelope(envelope); } } else { var maxExtent:Envelope = gism.getActiveMap().getEnvelope(); if (maxExtent == null) { maxExtent = gism.getActiveMap().getInitEnvelope(); } if (envelope != null && maxExtent.contains(envelope)) { gism.setCurrentCentreScale(envelope.getCenterPoint().getX(), envelope.getCenterPoint().getY(), layer.getMaxScale()); } else { gism.setCurrentScale(layer.getMaxScale()); } } } public function display() { if(graphic == null) { setGraphic(); } _visible = true; } }