////////////////////////////////////////////////////////////////////////////////
//
// 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.advancedDataGridClasses
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.TextLineMetrics;
import mx.controls.AdvancedDataGrid;
import mx.controls.listClasses.BaseListData;
import mx.controls.listClasses.IDropInListItemRenderer;
import mx.controls.listClasses.IListItemRenderer;
import mx.core.ClassFactory;
import mx.core.IDataRenderer;
import mx.core.IFactory;
import mx.core.IInvalidating;
import mx.core.IToolTip;
import mx.core.IUITextField;
import mx.core.UIComponent;
import mx.core.UITextField;
import mx.core.mx_internal;
import mx.events.FlexEvent;
import mx.events.ToolTipEvent;
use namespace mx_internal;
//--------------------------------------
// Events
//--------------------------------------
/**
* Dispatched when the data
property changes.
*
*
When you use a component as an item renderer,
* the data
property contains the data to display.
* You can listen for this event and update the component
* when the data
property changes.
"left"
, "center"
,
* and "right"
.
*
* @default "center"
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="horizontalAlign", type="String", enumeration="left,center,right", inherit="no")]
/**
* Vertical alignment of the header text.
* Possible values are "top"
, "middle"
,
* and "bottom"
.
*
* @default "middle"
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
[Style(name="verticalAlign", type="String", enumeration="top,middle,bottom", inherit="no")]
/**
* The AdvancedDataGridHeaderRenderer class defines the default header
* renderer for a AdvancedDataGrid control.
* By default, the header renderer
* draws the text associated with each header in the list, and an optional
* sort arrow (if sorted by that column).
*
* By default, the custom header renderer uses the default
* sort item renderer defined by the AdvancedDataGridSortItemRenderer class.
* The sort item renderer controls the display of the
* sort icon and sort sequence number.
* You can specify a custom sort item renderer by using
* the sortItemRenderer
property.
You can override the default header renderer by creating a custom
* header renderer.
* The only requirement for a custom header renderer is that it
* must include the size of the sortItemRenderer
* in any size calculations performed by an override of the
* measure()
and updateDisplayList()
methods.
You can customize when the sorting gets triggered by
* handling or dispatching the AdvancedDataGridEvent.SORT
event.
data
property
* as defined by the IDataRenderer interface.
* When set, it stores the value and invalidates the component
* to trigger a relayout of the component.
*
* @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;
invalidateProperties();
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
//----------------------------------
// sortItemRenderer
//----------------------------------
private var _sortItemRenderer:IFactory;
[Inspectable(category="Data")]
/**
* Specifies a custom sort item renderer.
* By default, the AdvancedDataGridHeaderRenderer class uses
* AdvancedDataGridSortItemRenderer as the sort item renderer.
*
* Note that the sort item renderer controls the display of the * sort icon and sort sequence number. * A custom header renderer must include code to display the * sort item renderer, regardless of whether it is the default or custom * sort item renderer.
* * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get sortItemRenderer():IFactory { return _sortItemRenderer; } /** * @private */ public function set sortItemRenderer(value:IFactory):void { _sortItemRenderer = value; sortItemRendererChanged = true; invalidateSize(); invalidateDisplayList(); dispatchEvent(new Event("sortItemRendererChanged")); } //---------------------------------- // listData //---------------------------------- /** * @private * Storage for the listData property. */ private var _listData:AdvancedDataGridListData; [Bindable("dataChange")] /** * The implementation of thelistData
property
* as defined by the IDropInListItemRenderer interface.
*
* @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 = AdvancedDataGridListData(value);
grid = AdvancedDataGrid(_listData.owner);
invalidateProperties();
}
//--------------------------------------------------------------------------
//
// Overridden methods: UIComponent
//
//--------------------------------------------------------------------------
/**
* @private
*/
override protected function createChildren():void
{
super.createChildren();
if (!label)
{
label = IUITextField(createInFontContext(UITextField));
addChild(DisplayObject(label));
}
if (!background)
{
background = new UIComponent();
addChild(background);
}
}
/**
* @private
* Apply the data and listData.
* Create an instance of the sort item renderer if specified,
* and set the text into the text field.
*/
override protected function commitProperties():void
{
super.commitProperties();
if (!initialized)
label.styleName = this;
if (!sortItemRendererInstance || sortItemRendererChanged)
{
if (!sortItemRenderer)
sortItemRenderer = ClassFactory(grid.sortItemRenderer);
if (sortItemRenderer)
{
sortItemRendererInstance = sortItemRenderer.newInstance();
// TODO Ideally, we should be doing this, but commenting out
// now because of Bug 204187:
//
// sortItemRendererInstance.owner = grid;
addChild( DisplayObject(sortItemRendererInstance) );
}
sortItemRendererChanged = false;
}
// Handle skin for the separator between the text and icon parts
var oldPartsSeparatorSkinClass:Class = partsSeparatorSkinClass;
if (!partsSeparatorSkinClass
|| partsSeparatorSkinClass != grid.getStyle("headerSortSeparatorSkin"))
{
partsSeparatorSkinClass = grid.getStyle("headerSortSeparatorSkin");
}
if (grid.sortExpertMode || partsSeparatorSkinClass != oldPartsSeparatorSkinClass)
{
if (partsSeparatorSkin)
removeChild(partsSeparatorSkin);
if (!grid.sortExpertMode)
{
partsSeparatorSkin = new partsSeparatorSkinClass();
addChild(partsSeparatorSkin);
}
}
if (partsSeparatorSkin)
partsSeparatorSkin.visible = !(_data is AdvancedDataGridColumnGroup);
if (_data != null)
{
label.text = listData.label ? listData.label : " ";
label.multiline = grid.variableRowHeight;
if( _data is AdvancedDataGridColumn)
label.wordWrap = grid.columnHeaderWordWrap(_data as AdvancedDataGridColumn);
// if (listData.columnIndex > -1)
// label.wordWrap = grid.columnHeaderWordWrap(grid.columns[listData.columnIndex]);
else
label.wordWrap = grid.wordWrap;
if (_data is AdvancedDataGridColumn)
{
var column:AdvancedDataGridColumn =
_data as AdvancedDataGridColumn;
var dataTips:Boolean = grid.showDataTips;
if (column.showDataTips == true)
dataTips = true;
if (column.showDataTips == false)
dataTips = false;
if (dataTips)
{
if (label.textWidth > label.width
|| column.dataTipFunction || column.dataTipField
|| grid.dataTipFunction || grid.dataTipField)
{
toolTip = column.itemToDataTip(_data);
}
else
{
toolTip = null;
}
}
else
{
toolTip = null;
}
}
}
else
{
label.text = " ";
toolTip = null;
}
if (sortItemRendererInstance is IInvalidating)
IInvalidating(sortItemRendererInstance).invalidateProperties();
}
/**
* @private
*/
override protected function measure():void
{
super.measure();
// Cache padding values
var paddingLeft:int = getStyle("paddingLeft");
var paddingRight:int = getStyle("paddingRight");
var paddingTop:int = getStyle("paddingTop");
var paddingBottom:int = getStyle("paddingBottom");
// Measure sortItemRenderer
var sortItemRendererWidth:Number = sortItemRendererInstance ?
sortItemRendererInstance.getExplicitOrMeasuredWidth() : 0;
var sortItemRendererHeight:Number = sortItemRendererInstance ?
sortItemRendererInstance.getExplicitOrMeasuredHeight() : 0;
if (grid.sortExpertMode && getFieldSortInfo() == null)
{
sortItemRendererWidth = 0;
sortItemRendererHeight = 0;
}
var horizontalGap:Number = getStyle("horizontalGap");
if (sortItemRendererWidth == 0)
horizontalGap = 0;
// Measure text
var labelWidth:Number = 0;
var labelHeight:Number = 0;
var w:Number = 0;
var h:Number = 0;
// By default, we already get the column's width
if (!isNaN(explicitWidth))
{
w = explicitWidth;
labelWidth = w - sortItemRendererWidth
- horizontalGap
- (partsSeparatorSkin ? partsSeparatorSkin.width + 10 : 0)
- paddingLeft - paddingRight;
label.width = labelWidth;
// Inspired by mx.controls.Label#measureTextFieldBounds():
// In order to display the text completely,
// a TextField must be 4-5 pixels larger.
labelHeight = label.textHeight + UITextField.TEXT_HEIGHT_PADDING;
}
else
{
var lineMetrics:TextLineMetrics = measureText(label.text);
labelWidth = lineMetrics.width + UITextField.TEXT_WIDTH_PADDING;
labelHeight = lineMetrics.height + UITextField.TEXT_HEIGHT_PADDING;
w = labelWidth + horizontalGap
+ (partsSeparatorSkin ? partsSeparatorSkin.width : 0)
+ sortItemRendererWidth
}
h = Math.max(labelHeight, sortItemRendererHeight);
h = Math.max(h, (partsSeparatorSkin ? partsSeparatorSkin.height : 0));
// Add padding
w += paddingLeft + paddingRight;
h += paddingTop + paddingBottom;
// Set required width and height
measuredMinWidth = measuredWidth = w;
measuredMinHeight = measuredHeight = h;
}
/**
* @private
*/
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (unscaledWidth == 0)
return;
// Cache padding values
var paddingLeft:int = getStyle("paddingLeft");
var paddingRight:int = getStyle("paddingRight");
var paddingTop:int = getStyle("paddingTop");
var paddingBottom:int = getStyle("paddingBottom");
// Size of sortItemRenderer
var sortItemRendererWidth:Number = sortItemRendererInstance ?
sortItemRendererInstance.getExplicitOrMeasuredWidth() : 0;
var sortItemRendererHeight:Number = sortItemRendererInstance ?
sortItemRendererInstance.getExplicitOrMeasuredHeight() : 0;
if (sortItemRendererInstance)
sortItemRendererInstance.setActualSize(sortItemRendererWidth,
sortItemRendererHeight);
if (grid.sortExpertMode && getFieldSortInfo() == null)
{
sortItemRendererWidth = 0;
sortItemRendererHeight = 0;
}
var horizontalGap:Number = getStyle("horizontalGap");
if (sortItemRendererWidth == 0)
horizontalGap = 0;
// Size of label
const MINIMUM_SIZE:TextLineMetrics = measureText("w");
// Adjust to given width
var lineMetrics:TextLineMetrics = measureText(label.text);
var labelWidth:Number = lineMetrics.width + UITextField.TEXT_WIDTH_PADDING;
var maxLabelWidth:int = unscaledWidth - sortItemRendererWidth
- horizontalGap - paddingLeft - paddingRight;
if (maxLabelWidth < 0)
maxLabelWidth = 0; // set the max width to 0, if its < 0
var truncate:Boolean = false;
if (maxLabelWidth < labelWidth)
{
truncate = true;
labelWidth = maxLabelWidth;
}
// Adjust to given height
var labelHeight:Number = label.textHeight + UITextField.TEXT_HEIGHT_PADDING;
var maxLabelHeight:int = unscaledHeight - paddingTop - paddingBottom;
if (maxLabelHeight < labelHeight)
{
truncate = true;
labelHeight = maxLabelHeight;
}
// Size of label
label.setActualSize(labelWidth, labelHeight);
// truncate only if the truncate flag is set
if (truncate && !label.multiline)
label.truncateToFit();
// Calculate position of label, by default center it
var labelX:Number;
var horizontalAlign:String = getStyle("horizontalAlign");
if (horizontalAlign == "left")
{
labelX = paddingLeft;
}
else if (horizontalAlign == "right")
{
labelX = unscaledWidth - paddingRight - sortItemRendererWidth
- horizontalGap - labelWidth;
}
else // if (horizontalAlign == "center")
{
labelX = (unscaledWidth - labelWidth - paddingLeft
- paddingRight - horizontalGap
- sortItemRendererWidth)/2 + paddingLeft;
}
labelX = Math.max(labelX, 0);
var labelY:Number;
var verticalAlign:String = getStyle("verticalAlign");
if (verticalAlign == "top")
{
labelY = paddingTop;
}
else if (verticalAlign == "bottom")
{
labelY = unscaledHeight - labelHeight - paddingBottom + 2; // 2 for gutter
}
else // if (verticalAlign == "middle")
{
labelY = (unscaledHeight - labelHeight - paddingBottom - paddingTop)/2
+ paddingTop;
}
labelY = Math.max(labelY, 0);
// Set positions
label.x = Math.round(labelX);
label.y = Math.round(labelY);
if (sortItemRendererInstance)
{
// Calculate position of sortItemRenderer (to the right of the headerRenderer)
var sortItemRendererX:Number = unscaledWidth
- sortItemRendererWidth
- paddingRight
;
var sortItemRendererY:Number = (unscaledHeight - sortItemRendererHeight
- paddingTop - paddingBottom
) / 2
+ paddingTop;
sortItemRendererInstance.x = Math.round(sortItemRendererX);
sortItemRendererInstance.y = Math.round(sortItemRendererY);
}
// Draw the separator
graphics.clear();
if (sortItemRendererInstance && !grid.sortExpertMode
&& !(_data is AdvancedDataGridColumnGroup))
{
if (!partsSeparatorSkinClass)
{
graphics.lineStyle(1, getStyle("separatorColor") !== undefined
? getStyle("separatorColor") : 0xCCCCCC);
graphics.moveTo(sortItemRendererInstance.x - 1, 1);
graphics.lineTo(sortItemRendererInstance.x - 1, unscaledHeight - 1);
}
else
{
partsSeparatorSkin.x = sortItemRendererInstance.x
- horizontalGap - partsSeparatorSkin.width;
partsSeparatorSkin.y = (unscaledHeight - partsSeparatorSkin.height) / 2;
}
}
// Set text color
var labelColor:Number;
if (data && parent)
{
if (!enabled)
labelColor = getStyle("disabledColor");
else if (grid.isItemHighlighted(listData.uid))
labelColor = getStyle("textRollOverColor");
else if (grid.isItemSelected(listData.uid))
labelColor = getStyle("textSelectedColor");
else
labelColor = getStyle("color");
label.setColor(labelColor);
}
// Set background size, position, color
if (background)
{
background.graphics.clear();
background.graphics.beginFill(0xFFFFFF, 0.0); // transparent
background.graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
background.graphics.endFill();
setChildIndex( DisplayObject(background), 0 );
}
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* Indicates if the mouse pointer was over the text part or icon part
* of the header when the mouse event occurred.
*
* This method has to be implemented in custom header renderers for sorting * to work. Note that this implicitly means you will need to display both * text (which can be displayed any way the custom header renderer * wants; by default, Flex display text) and an icon (which is the * default or custom sort item renderer).
* * @param event The mouse event. * * @returnAdvancedDataGrid.HEADERTEXTPART
if the mouse was over the header text,
* and AdvancedDataGrid.HEADERICONPART
if the mouse was over the header icon.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function mouseEventToHeaderPart(event:MouseEvent):String
{
var point:Point = new Point(event.stageX, event.stageY);
point = globalToLocal(point);
// Needs to be in sync with the logic in measure() and updateDisplayList()
return point.x < sortItemRendererInstance.x
? AdvancedDataGrid.HEADER_TEXT_PART
: AdvancedDataGrid.HEADER_ICON_PART;
}
/**
* Returns the sort information for this column from the AdvancedDataGrid control
* so that the control can display the column's number in the sort sequence,
* and whether the sort is ascending or descending.
* The sorting information is represented by an instance of the SortInfo class,
* where each column in the AdvancedDataGrid control has an associated
* SortInfo instance.
*
* @return A SortInfo instance.
*
* @see mx.controls.advancedDataGridClasses.SortInfo
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
protected function getFieldSortInfo():SortInfo
{
return grid.getFieldSortInfo(grid.columns[listData.columnIndex]);
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* Positions the tooltip in the header.
*
* @param 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;
var xPos:int = DisplayObject(systemManager).mouseX + 11;
var yPos:int = DisplayObject(systemManager).mouseY + 22;
// Calculate global position of label.
var pt:Point = new Point(xPos, yPos);
pt = DisplayObject(systemManager).localToGlobal(pt);
pt = DisplayObject(systemManager.getSandboxRoot()).globalToLocal(pt);
toolTip.move(pt.x, pt.y + (height - toolTip.height) / 2);
var screen:Rectangle = toolTip.screen;
var screenRight:Number = screen.x + screen.width;
if (toolTip.x + toolTip.width > screenRight)
toolTip.move(screenRight - toolTip.width, toolTip.y);
}
/**
* @private
*/
mx_internal function getLabel():IUITextField
{
return label;
}
} // end class
} // end package