/* Copyright (c) 2007 FlexLib Contributors. See: http://code.google.com/p/flexlib/wiki/ProjectContributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package flexlib.controls.treeGridClasses { import flash.display.DisplayObject; import flash.display.InteractiveObject; import flash.display.Shape; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; import flash.geom.Rectangle; import flexlib.controls.TreeGrid; import mx.controls.Image; import mx.controls.dataGridClasses.DataGridListData; import mx.controls.listClasses.BaseListData; import mx.controls.listClasses.IDropInListItemRenderer; import mx.controls.listClasses.IListItemRenderer; import mx.core.IDataRenderer; import mx.core.IFlexDisplayObject; import mx.core.IToolTip; import mx.core.SpriteAsset; import mx.core.UIComponent; import mx.core.UITextField; import mx.events.FlexEvent; import mx.events.ToolTipEvent; import mx.events.TreeEvent; import mx.managers.ILayoutManagerClient; import mx.styles.IStyleClient; [Event(name="dataChange", type="mx.events.FlexEvent")] /** * */ public class TreeGridItemRenderer extends UIComponent implements IDataRenderer, IDropInListItemRenderer, ILayoutManagerClient, IListItemRenderer { //---------------------------------- // disclosureIcon //---------------------------------- /** * The internal IFlexDisplayObject that displays the disclosure icon * in this renderer. */ protected var disclosureIcon:IFlexDisplayObject; //---------------------------------- // icon //---------------------------------- /** * The internal IFlexDisplayObject that displays the icon in this renderer. */ protected var icon:IFlexDisplayObject; //---------------------------------- // label //---------------------------------- /** * The internal UITextField that displays the text in this renderer. */ protected var label:UITextField; /** * The internal shape that displays the trunks in this renderer. */ protected var trunk:Sprite; private var listOwner : TreeGrid; /** * Constructor. */ public function TreeGridItemRenderer() { super(); } /** * @private */ override protected function createChildren():void { super.createChildren(); if (!label) { label = new UITextField(); label.styleName = this; addChild(label); } addEventListener(ToolTipEvent.TOOL_TIP_SHOW, toolTipShowHandler); } /** * @private */ override protected function commitProperties():void { super.commitProperties(); if (icon) { removeChild(DisplayObject(icon)); icon = null; } if (disclosureIcon) { disclosureIcon.removeEventListener(MouseEvent.MOUSE_DOWN, disclosureMouseDownHandler); removeChild(DisplayObject(disclosureIcon)); disclosureIcon = null; } if(trunk) { trunk.graphics.clear(); removeChild(DisplayObject(trunk)); trunk = null; } if ( _data ) { listOwner = TreeGrid( _listData.owner ); if (_listData.disclosureIcon) { var disclosureIconClass:Class = _listData.disclosureIcon; var disclosureInstance:* = new disclosureIconClass(); // If not already an interactive object, then we'll wrap // in one so we can dispatch mouse events. if (!(disclosureInstance is InteractiveObject)) { var wrapper:SpriteAsset = new SpriteAsset(); wrapper.addChild(disclosureInstance as DisplayObject); disclosureIcon = wrapper as IFlexDisplayObject; } else { disclosureIcon = disclosureInstance; } addChild(disclosureIcon as DisplayObject); disclosureIcon.addEventListener(MouseEvent.MOUSE_DOWN, disclosureMouseDownHandler); } if(_listData.trunk != "none" ) { trunk = new Sprite(); addChild(trunk); } if (_listData.icon) { var iconClass:Class = _listData.icon; icon = new iconClass(); addChild(DisplayObject(icon)); } label.text = _listData.label; label.multiline = listOwner.variableRowHeight; label.wordWrap = listOwner.wordWrap; if (listOwner.showDataTips) { if (label.textWidth > label.width || listOwner.dataTipFunction != null) { toolTip = listOwner.itemToDataTip(_data); } else { toolTip = null; } } else { toolTip = null; } } else { label.text = " "; toolTip = null; } invalidateDisplayList(); } /** * @private */ override protected function measure():void { super.measure(); var w:Number = _data ? _listData.indent : 5; w = w + 5; if (disclosureIcon) w += disclosureIcon.width; if (icon) w += icon.measuredWidth; // guarantee that label width isn't zero because it messes up ability to measure if (label.width < 4 || label.height < 4) { label.width = 4; label.height = 16; } if (isNaN(explicitWidth)) { w += label.getExplicitOrMeasuredWidth(); measuredWidth = w; measuredHeight = label.getExplicitOrMeasuredHeight(); } else { label.width = Math.max(explicitWidth - w, 4); measuredHeight = label.getExplicitOrMeasuredHeight(); if (icon && icon.measuredHeight > measuredHeight) measuredHeight = icon.measuredHeight; } } /** * @private */ override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void { super.updateDisplayList(unscaledWidth, unscaledHeight); var startx:Number = _data ? _listData.indent : 0; //if( startx == 0 ) startx = startx + 5; if (disclosureIcon) { disclosureIcon.x = startx; startx = disclosureIcon.x + disclosureIcon.width; disclosureIcon.setActualSize(disclosureIcon.width, disclosureIcon.height); disclosureIcon.visible = _data ? _listData.hasChildren : false; } if(trunk) { trunk.graphics.clear(); trunk.graphics.lineStyle( 1, _listData.trunkColor, 0.5 ); for( var i : int = 0; i < _listData.depth - 1; i++ ) { var currentx : Number = 5 + i * _listData.indentationGap; trunk.graphics.moveTo(currentx + (disclosureIcon.width / 2), 0 - _listData.trunkOffsetTop ); trunk.graphics.lineTo(currentx + (disclosureIcon.width / 2), this.height + _listData.trunkOffsetBottom ); } if(disclosureIcon && disclosureIcon.visible) { //vertical item line (separated in 2 part, top of the icon and bottom of the icon) trunk.graphics.moveTo(startx - (disclosureIcon.width / 2), 0 - _listData.trunkOffsetTop ); trunk.graphics.lineTo(startx - (disclosureIcon.width / 2), disclosureIcon.y ); if(_listData.hasSibling) { trunk.graphics.moveTo(startx - (disclosureIcon.width / 2), disclosureIcon.y + disclosureIcon.height ); trunk.graphics.lineTo(startx - (disclosureIcon.width / 2), this.height + _listData.trunkOffsetBottom ); } //horizontal item line trunk.graphics.moveTo(startx, disclosureIcon.y + disclosureIcon.height / 2 ); trunk.graphics.lineTo(startx + (_listData.indentationGap / 3), disclosureIcon.y + disclosureIcon.height / 2 ); startx = startx + (_listData.indentationGap / 3); } else { if(!disclosureIcon.visible) { var endy : Number=0; //vertical item line if(_listData.hasSibling) { endy = this.height + _listData.trunkOffsetBottom; } else { endy = disclosureIcon.y + disclosureIcon.height / 2; } trunk.graphics.moveTo(startx - (disclosureIcon.width / 2), 0 - _listData.trunkOffsetTop ); trunk.graphics.lineTo(startx - (disclosureIcon.width / 2), endy ); //horizontal item line trunk.graphics.moveTo(startx - (disclosureIcon.width / 2) , disclosureIcon.y + disclosureIcon.height / 2 ); trunk.graphics.lineTo(startx + (_listData.indentationGap / 3) , disclosureIcon.y + disclosureIcon.height / 2 ); startx = startx + (_listData.indentationGap / 3); } else { //trunk.graphics.moveTo(startx , 0 - _listData.trunkOffsetTop ); //trunk.graphics.lineTo(startx , this.height + _listData.trunkOffsetBottom ); } } } if (icon) { icon.x = startx; startx = icon.x + icon.measuredWidth; icon.setActualSize(icon.measuredWidth, icon.measuredHeight); } label.x = startx; label.setActualSize(unscaledWidth - startx, measuredHeight); // using truncateToFit to add the 3 dots to labels if the columns are too small if( label.truncateToFit() ) { label.toolTip = _listData.label; } //var verticalAlign:String = getStyle("verticalAlign"); /*if (verticalAlign == "top") { label.y = 0; if (icon) icon.y = 0; if (disclosureIcon) disclosureIcon.y = 0; } else if (verticalAlign == "bottom") { label.y = unscaledHeight - label.height + 2; // 2 for gutter if (icon) icon.y = unscaledHeight - icon.height; if (disclosureIcon) disclosureIcon.y = unscaledHeight - disclosureIcon.height; } else {*/ // TODO //} label.y = (unscaledHeight - label.height) / 2; if (icon) icon.y = (unscaledHeight - icon.height) / 2; if (disclosureIcon) disclosureIcon.y = (unscaledHeight - disclosureIcon.height) / 2; var labelColor:Number; if (data && parent) { if (!enabled) labelColor = getStyle("disabledColor"); else if (listOwner.isItemHighlighted(listData.uid)) labelColor = getStyle("textRollOverColor"); else if (listOwner.isItemSelected(listData.uid)) labelColor = getStyle("textSelectedColor"); else labelColor = getStyle("color"); label.setColor(labelColor); } } /** * @private */ private function toolTipShowHandler(event:ToolTipEvent):void { var toolTip:IToolTip = event.toolTip; // Calculate global position of label. var pt:Point = new Point(0, 0); pt = label.localToGlobal(pt); pt = root.globalToLocal(pt); toolTip.move(pt.x, pt.y + (height - toolTip.height) / 2); var screen:Rectangle = systemManager.screen; var screenRight:Number = screen.x + screen.width; if (toolTip.x + toolTip.width > screenRight) toolTip.move(screenRight - toolTip.width, toolTip.y); } /** * @private */ private function disclosureMouseDownHandler(event:Event):void { event.stopPropagation(); //if (listOwner.isOpening || !listOwner.enabled) // return; var open:Boolean = _listData.open; _listData.open = !open; listOwner.dispatchTreeEvent(TreeEvent.ITEM_OPENING, _listData, //listData this, //renderer event, //trigger !open, //opening true) //dispatch } /** * @private */ private var invalidatePropertiesFlag:Boolean = false; /** * @private */ private var invalidateSizeFlag:Boolean = false; //-------------------------------------------------------------------------- // // Overridden properties: UIComponent // //-------------------------------------------------------------------------- //---------------------------------- // nestLevel //---------------------------------- /** * @private */ override public function set nestLevel(value:int):void { super.nestLevel = value; } /** * @private */ private var _listData:TreeGridListData; [Bindable("dataChange")] public function get listData() : BaseListData { return _listData; } public function set listData( value : BaseListData ) : void { if( !value ) return; _listData = TreeGridListData( value ); } /** * @private */ private var _data:Object; [Bindable("dataChange")] public function get data(): Object { return _data; } public function set data( value : Object ):void { _data = value; invalidateProperties(); dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE)); } } // end class } // end package