blob: 2957558e10e02fb11929be29b476e58e57855e43 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package mx.controls.dataGridClasses
{
import flash.display.DisplayObject;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getQualifiedSuperclassName;
import mx.controls.DataGrid;
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.UIComponent;
import mx.core.UIComponentGlobals;
import mx.core.UITextField;
import mx.core.mx_internal;
import mx.events.FlexEvent;
import mx.events.InterManagerRequest;
import mx.events.ToolTipEvent;
import mx.managers.ILayoutManagerClient;
import mx.managers.ISystemManager;
import mx.styles.CSSStyleDeclaration;
import mx.styles.IStyleClient;
import mx.styles.StyleProtoChain;
import mx.utils.PopUpUtil;
use namespace mx_internal;
/**
* Dispatched when the <code>data</code> property changes.
*
* <p>When you use a component as an item renderer,
* the <code>data</code> property contains the data to display.
* You can listen for this event and update the component
* when the <code>data</code> property changes.</p>
*
* @eventType mx.events.FlexEvent.DATA_CHANGE
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Event(name="dataChange", type="mx.events.FlexEvent")]
/**
* The DataGridItemRenderer class defines the default item renderer for a DataGrid control.
* By default, the item renderer
* draws the text associated with each item in the grid.
*
* <p>You can override the default item renderer by creating a custom item renderer.</p>
*
* @see mx.controls.DataGrid
* @see mx.core.IDataRenderer
* @see mx.controls.listClasses.IDropInListItemRenderer
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class DataGridItemRenderer extends UITextField
implements IDataRenderer,
IDropInListItemRenderer, ILayoutManagerClient,
IListItemRenderer, IStyleClient
{
include "../../core/Version.as";
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function DataGridItemRenderer()
{
super();
tabEnabled = false;
mouseWheelEnabled = false;
ignorePadding = false;
addEventListener(ToolTipEvent.TOOL_TIP_SHOW, toolTipShowHandler);
inheritingStyles = nonInheritingStyles =
StyleProtoChain.STYLE_UNINITIALIZED;
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @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;
UIComponentGlobals.layoutManager.invalidateProperties(this);
invalidatePropertiesFlag = true;
UIComponentGlobals.layoutManager.invalidateSize(this);
invalidateSizeFlag = true;
}
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// data
//----------------------------------
/**
* @private
*/
private var _data:Object;
[Bindable("dataChange")]
/**
* The implementation of the <code>data</code> property as
* defined by the IDataRenderer interface.
*
* The value is ignored. Only the listData property is used.
* @see mx.core.IDataRenderer
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get data():Object
{
return _data;
}
/**
* @private
*/
public function set data(value:Object):void
{
_data = value;
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
//----------------------------------
// listData
//----------------------------------
/**
* @private
*/
private var _listData:DataGridListData;
[Bindable("dataChange")]
/**
* The implementation of the <code>listData</code> property as
* defined by the IDropInListItemRenderer interface.
* The text of the renderer is set to the <code>label</code>
* property of the listData.
*
* @see mx.controls.listClasses.IDropInListItemRenderer
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get listData():BaseListData
{
return _listData;
}
/**
* @private
*/
public function set listData(value:BaseListData):void
{
_listData = DataGridListData(value);
if (nestLevel && !invalidatePropertiesFlag)
{
UIComponentGlobals.layoutManager.invalidateProperties(this);
invalidatePropertiesFlag = true;
UIComponentGlobals.layoutManager.invalidateSize(this);
invalidateSizeFlag = true;
}
}
//----------------------------------
// styleDeclaration
//----------------------------------
/**
* @private
* Storage for the styleDeclaration property.
*/
private var _styleDeclaration:CSSStyleDeclaration;
/**
* Storage for the inline inheriting styles on this object.
* This CSSStyleDeclaration is created the first time that setStyle()
* is called on this component to set an inheriting style.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get styleDeclaration():CSSStyleDeclaration
{
return _styleDeclaration;
}
/**
* @private
*/
public function set styleDeclaration(value:CSSStyleDeclaration):void
{
_styleDeclaration = value;
}
//--------------------------------------------------------------------------
//
// Overridden methods: UITextField
//
//--------------------------------------------------------------------------
/**
* @private
*/
override public function initialize():void
{
regenerateStyleCache(false)
}
/**
* @private
*/
override public function validateNow():void
{
if (data && parent)
{
var newColor:Number;
if (DataGridBase(_listData.owner).isItemHighlighted(_listData.uid))
{
newColor = getStyle("textRollOverColor");
}
else if (DataGridBase(_listData.owner).isItemSelected(_listData.uid))
{
newColor = getStyle("textSelectedColor");
}
else
{
newColor = getStyle("color");
}
if (newColor != explicitColor)
{
styleChangedFlag = true;
explicitColor = newColor;
invalidateDisplayList();
}
}
super.validateNow();
}
/**
* @copy mx.core.UIComponent#getStyle()
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
override public function getStyle(styleProp:String):*
{
return (styleManager.inheritingStyles[styleProp]) ?
inheritingStyles[styleProp] : nonInheritingStyles[styleProp];
}
/**
* @copy mx.core.UIComponent#setStyle()
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
override public function setStyle(styleProp:String, newValue:*):void
{
if (styleProp == "styleName")
{
// Let the setter handle this one, see UIComponent.
styleName = newValue;
// Short circuit, because styleName isn't really a style.
return;
}
/*
if (styleProp == "themeColor")
{
// setThemeColor handles the side effects.
setThemeColor(newValue);
// Do not short circuit, because themeColor is a style.
// It just has side effects, too.
}
*/
// If this UIComponent didn't previously have any inline styles,
// then regenerate the UIComponent's proto chain (and the proto chains
// of this UIComponent's descendants).
var isInheritingStyle:Boolean =
styleManager.isInheritingStyle(styleProp);
var isProtoChainInitialized:Boolean =
inheritingStyles != StyleProtoChain.STYLE_UNINITIALIZED;
if (isInheritingStyle)
{
if (getStyle(styleProp) == newValue && isProtoChainInitialized)
return;
if (!styleDeclaration)
{
styleDeclaration = new CSSStyleDeclaration(null, styleManager);
styleDeclaration.setLocalStyle(styleProp, newValue);
// If inheritingStyles is undefined, then this object is being
// initialized and we haven't yet generated the proto chain. To
// avoid redundant work, don't bother to create the proto chain here.
if (isProtoChainInitialized)
regenerateStyleCache(true);
}
else
{
styleDeclaration.setLocalStyle(styleProp, newValue);
}
}
else
{
if (getStyle(styleProp) == newValue && isProtoChainInitialized)
return;
if (!styleDeclaration)
{
styleDeclaration = new CSSStyleDeclaration(null, styleManager);
styleDeclaration.setLocalStyle(styleProp, newValue);
// If nonInheritingStyles is undefined, then this object is being
// initialized and we haven't yet generated the proto chain. To
// avoid redundant work, don't bother to create the proto chain here.
if (isProtoChainInitialized)
regenerateStyleCache(false);
}
else
{
styleDeclaration.setLocalStyle(styleProp, newValue);
}
}
if (isProtoChainInitialized)
{
styleChanged(styleProp);
notifyStyleChangeInChildren(styleProp, isInheritingStyle);
}
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* If Flex calls the <code>LayoutManager.invalidateProperties()</code>
* method on this ILayoutManagerClient, then
* this function is called when it's time to commit property values.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function validateProperties():void
{
invalidatePropertiesFlag = false;
if (_listData)
{
var dg:DataGrid = DataGrid(_listData.owner);
var column:DataGridColumn =
dg.mx_internal::rawColumns[_listData.columnIndex];
text = _listData.label;
if (_data is DataGridColumn)
wordWrap = dg.columnHeaderWordWrap(column);
else
wordWrap = dg.columnWordWrap(column);
if (dg.variableRowHeight)
multiline = true;
var dataTips:Boolean = dg.showDataTips;
if (column.showDataTips == true)
dataTips = true;
if (column.showDataTips == false)
dataTips = false;
if (dataTips)
{
if (!(_data is DataGridColumn) && (textWidth > width
|| column.dataTipFunction || column.dataTipField
|| dg.dataTipFunction || dg.dataTipField))
{
toolTip = column.itemToDataTip(_data);
}
else
{
toolTip = null;
}
}
else
{
toolTip = null;
}
}
else
{
text = " ";
toolTip = null;
}
}
/**
* If Flex calls the <code>LayoutManager.invalidateSize()</code>
* method on this ILayoutManagerClient, then
* this function is called when it's time to do measurements.
*
* @param recursive If <code>true</code>, call this method
* on the object's children.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function validateSize(recursive:Boolean = false):void
{
invalidateSizeFlag = false;
validateNow();
}
/**
* If Flex calls <code>LayoutManager.invalidateDisplayList()</code>
* method on this ILayoutManagerClient, then
* this function is called when it's time to update the display list.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function validateDisplayList():void
{
validateNow();
}
/**
* @copy mx.core.UIComponent#clearStyle()
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function clearStyle(styleProp:String):void
{
setStyle(styleProp, undefined);
}
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function notifyStyleChangeInChildren(
styleProp:String, recursive:Boolean):void
{
}
/**
* Sets up the <code>inheritingStyles</code>
* and <code>nonInheritingStyles</code> objects
* and their proto chains so that the <code>getStyle()</code> method can work.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function initProtoChain():void
{
styleChangedFlag = true;
var classSelectors:Array = [];
if (styleName)
{
if (styleName is CSSStyleDeclaration)
{
// Get the style sheet referenced by the styleName property
classSelectors.push(CSSStyleDeclaration(styleName));
}
else if (styleName is IFlexDisplayObject)
{
// If the styleName property is a UIComponent, then there's a
// special search path for that case.
StyleProtoChain.initProtoChainForUIComponentStyleName(this);
return;
}
else if (styleName is String)
{
// Get the style sheet referenced by the styleName property
var styleNames:Array = styleName.split(/\s+/);
for (var c:int=0; c < styleNames.length; c++)
{
if (styleNames[c].length) {
classSelectors.push(styleManager.getMergedStyleDeclaration("." +
styleNames[c]));
}
}
}
}
// To build the proto chain, we start at the end and work forward.
// Referring to the list at the top of this function, we'll start by
// getting the tail of the proto chain, which is:
// - for non-inheriting styles, the global style sheet
// - for inheriting styles, my parent's style object
var nonInheritChain:Object = styleManager.stylesRoot;
var p:IStyleClient = parent as IStyleClient;
if (p)
{
var inheritChain:Object = p.inheritingStyles;
if (inheritChain == StyleProtoChain.STYLE_UNINITIALIZED)
inheritChain = nonInheritChain;
}
else
{
inheritChain = styleManager.stylesRoot;
}
// Working backwards up the list, the next element in the
// search path is the type selector
var typeSelectors:Array = getClassStyleDeclarations();
var n:int = typeSelectors.length;
for (var i:int = 0; i < n; i++)
{
var typeSelector:CSSStyleDeclaration = typeSelectors[i];
inheritChain = typeSelector.addStyleToProtoChain(inheritChain, this);
nonInheritChain = typeSelector.addStyleToProtoChain(nonInheritChain, this);
}
// Next are the class selectors
for (i = 0; i < classSelectors.length; i++)
{
var classSelector:CSSStyleDeclaration = classSelectors[i];
if (classSelector)
{
inheritChain = classSelector.addStyleToProtoChain(inheritChain, this);
nonInheritChain = classSelector.addStyleToProtoChain(nonInheritChain, this);
}
}
// Finally, we'll add the in-line styles
// to the head of the proto chain.
inheritingStyles = styleDeclaration ?
styleDeclaration.addStyleToProtoChain(inheritChain, this) :
inheritChain;
nonInheritingStyles = styleDeclaration ?
styleDeclaration.addStyleToProtoChain(nonInheritChain, this) :
nonInheritChain;
}
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function regenerateStyleCache(recursive:Boolean):void
{
initProtoChain();
}
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function registerEffects(effects:Array /* of String */):void
{
}
/**
* @inheritDoc
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function getClassStyleDeclarations():Array
{
var className:String = getQualifiedClassName(this)
className = className.replace("::", ".");
var decls:Array = [];
while (className != null &&
className != "mx.core.UIComponent" &&
className != "mx.core.UITextField")
{
var s:CSSStyleDeclaration =
styleManager.getMergedStyleDeclaration(className);
if (s)
{
decls.unshift(s);
}
try
{
className = getQualifiedSuperclassName(getDefinitionByName(className));
className = className.replace("::", ".");
}
catch(e:ReferenceError)
{
className = null;
}
}
return decls;
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* The event handler to position the tooltip.
*
* @param event The event object.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
protected function toolTipShowHandler(event:ToolTipEvent):void
{
var toolTip:IToolTip = event.toolTip;
// We need to position the tooltip at same x coordinate,
// center vertically and make sure it doesn't overlap the screen.
// Call the helper function to handle this for us.
var pt:Point = PopUpUtil.positionOverComponent(this,
systemManager,
toolTip.width,
toolTip.height,
height / 2);
toolTip.move(pt.x, pt.y);
}
}
}