blob: c734010ece7554caca894de457f1934566a1f945 [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 flashx.textLayout.elements
{
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.text.engine.GraphicElement;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flashx.textLayout.compose.FlowDamageType;
import flashx.textLayout.compose.TextFlowLine;
import flashx.textLayout.container.ContainerController;
import flashx.textLayout.edit.EditManager;
import flashx.textLayout.edit.IEditManager;
import flashx.textLayout.edit.ISelectionManager;
import flashx.textLayout.events.DamageEvent;
import flashx.textLayout.events.ModelChange;
import flashx.textLayout.formats.BlockProgression;
import flashx.textLayout.formats.Float;
import flashx.textLayout.tlf_internal;
import flashx.undo.UndoManager;
use namespace tlf_internal;
/**
* TableCellElement is an item in a TableElement. It most commonly contains one or more ParagraphElement objects.
*
*
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
*
*/
public final class TableCellElement extends TableFormattedElement
{
private var _x:Number;
private var _y:Number;
private var _width:Number;
private var _height:Number;
private var _parcelIndex:int;
private var _container:CellContainer;
private var _enableIME:Boolean = true;
private var _damaged:Boolean = true;
private var _controller:ContainerController;
private var _rowSpan:uint = 1;
private var _columnSpan:uint = 1;
private var _rowIndex:int = -1;
private var _colIndex:int = -1;
private var _includeDescentInCellBounds:Boolean;
public function TableCellElement()
{
super();
_controller = new ContainerController(container,NaN,NaN);
}
/** @private */
override protected function get abstract():Boolean
{ return false; }
/** @private */
tlf_internal override function get defaultTypeName():String
{ return "td"; }
/** @private */
tlf_internal override function canOwnFlowElement(elem:FlowElement):Boolean
{// Table cells have no TLF children. Instead it contains its own TextFlow.
return (elem is FlowElement);
}
public function isDamaged():Boolean {
return _damaged || (_textFlow && _textFlow.flowComposer.isPotentiallyDamaged(_textFlow.textLength));
}
private var _savedPaddingTop:Number = 0;
private var _savedPaddingBottom:Number = 0;
private var _savedPaddingLeft:Number = 0;
private var _savedPaddingRight:Number = 0;
public function compose():Boolean {
var pt:Number = getEffectivePaddingTop();
var pb:Number = getEffectivePaddingBottom();
var pl:Number = getEffectivePaddingLeft();
var pr:Number = getEffectivePaddingRight();
if(pt != _savedPaddingTop)
{
_controller.paddingTop = _savedPaddingTop = pt;
}
if(pb != _savedPaddingBottom)
{
_controller.paddingBottom = _savedPaddingBottom = pb;
}
if(pl != _savedPaddingLeft)
{
_controller.paddingLeft = _savedPaddingLeft = pl;
}
if(pr != _savedPaddingRight)
{
_controller.paddingRight = _savedPaddingRight = pr;
}
var table:TableElement = getTable();
_damaged = false;
var compWidth:Number = 0;
for(var i:int=0;i<columnSpan;i++)
{
if (table && table.getColumnAt(colIndex+i)) {
compWidth += table.getColumnAt(colIndex+i).columnWidth;
}
}
width = compWidth;
if (_textFlow && _textFlow.flowComposer) {
return _textFlow.flowComposer.compose();
}
return false;
}
public function update():Boolean
{
if(_textFlow && _textFlow.flowComposer){
return _textFlow.flowComposer.updateAllControllers();
}
return false;
}
public function get parcelIndex():int
{
return _parcelIndex;
}
public function set parcelIndex(value:int):void
{
_parcelIndex = value;
}
public function get rowIndex():int
{
return _rowIndex;
}
public function set rowIndex(value:int):void
{
_rowIndex = value;
}
public function get colIndex():int
{
return _colIndex;
}
public function set colIndex(value:int):void
{
_colIndex = value;
}
protected var _textFlow:TextFlow;
public function get textFlow():TextFlow {
if (_textFlow == null) {
var flow:TextFlow = new TextFlow();
if (table && table.getTextFlow() && table.getTextFlow().interactionManager is IEditManager) {
flow.interactionManager = new EditManager(IEditManager(_textFlow.interactionManager).undoManager);
}
else if(table && table.getTextFlow() && table.getTextFlow().interactionManager) {
var im:Class = getDefinitionByName(getQualifiedClassName(table.getTextFlow().interactionManager)) as Class;
flow.interactionManager = new im();
}
else {
flow.normalize();
}
textFlow = flow;
}
return _textFlow;
}
public function set textFlow(value:TextFlow):void
{
if (_textFlow) {
_textFlow.removeEventListener(DamageEvent.DAMAGE, handleCellDamage);
_textFlow.flowComposer.removeAllControllers();
}
_textFlow = value;
_textFlow.parentElement = this;
_textFlow.flowComposer.addController(_controller);
_textFlow.addEventListener(DamageEvent.DAMAGE, handleCellDamage);
}
public function get controller():ContainerController {
return _controller;
}
private function handleCellDamage(ev:DamageEvent):void{
damage();
}
public function get enableIME():Boolean
{
return _enableIME;
}
public function set enableIME(value:Boolean):void
{
_enableIME = value;
}
public function get container():CellContainer{
if(!_container){
_container = new CellContainer(enableIME);
_container.element = this;
}
return _container;
}
/**
* Gets the width.
**/
public function get width():Number
{
return _width;
}
/**
* @private
**/
public function set width(value:Number):void
{
if(_width != value) {
_damaged = true;
}
_width = value;
_controller.setCompositionSize(_width, _controller.compositionHeight);
}
/**
* Returns the height of the cell.
**/
public function get height():Number
{
//return getRowHeight(); not sure if we should always use row height
return _height;
}
/**
* @private
**/
public function set height(value:Number):void
{
if (_height != value) {
_damaged = true;
}
_height = value;
_controller.setCompositionSize(_controller.compositionWidth, _height);
}
public function getComposedHeight():Number
{
var descent:Number = 0;
if(!includeDescentInCellBounds)
{
if(_textFlow.flowComposer && _textFlow.flowComposer.numLines)
{
var lastLine:TextFlowLine = _textFlow.flowComposer.getLineAt(_textFlow.flowComposer.numLines-1);
if(lastLine)
descent = lastLine.descent;
}
}
return (_controller.getContentBounds().height - descent);
}
public function getRowHeight():Number
{
return getRow() ? getRow().composedHeight : NaN;
}
public function get rowSpan():uint
{
return _rowSpan;
}
public function set rowSpan(value:uint):void
{
if(value >= 1)
_rowSpan = value;
}
public function get columnSpan():uint
{
return _columnSpan;
}
public function set columnSpan(value:uint):void
{
if(value >= 1)
_columnSpan = value;
}
public function updateCompositionShapes():void{
_controller.updateCompositionShapes();
}
/**
* Return the row that this cell is part of or null
* if not part of a row.
**/
public function getRow():TableRowElement
{
return table ? table.getRowAt(rowIndex) : null;
}
/**
* Returns the next cell in the table or null if not part of a
* table or no cells exist after this cell.
**/
public function getNextCell():TableCellElement {
return table ? table.getNextCell(this) : null;
}
/**
* Returns the previous cell in the table or null if not part of a
* table or no cells exist before this cell.
**/
public function getPreviousCell():TableCellElement {
return table ? table.getPreviousCell(this) : null;
}
public function get x():Number
{
return container.x;
}
public function set x(value:Number):void
{
container.x = value;
}
public function get y():Number
{
return container.y;
}
public function set y(value:Number):void
{
container.y = value;
}
public function damage():void
{
if (table) {
table.hasCellDamage = true;
}
_damaged = true;
}
/**
* Adds in the table cell spacing, border stroke width.
* We may be able to set this value when the format changes.
* For now we just want to get it to work.
**/
public function getTotalPaddingWidth():Number {
var paddingAmount:Number = 0;
// no textflow is no padding
if (!textFlow) {
return 0;
}
if (table && table.cellSpacing!=undefined) {
paddingAmount += table.cellSpacing;
}
if (textFlow.computedFormat.blockProgression == BlockProgression.RL) {
paddingAmount += Math.max(getEffectivePaddingTop() + getEffectivePaddingBottom(), getEffectiveBorderTopWidth() + getEffectiveBorderBottomWidth());
}
else {
paddingAmount += Math.max(getEffectivePaddingLeft() + getEffectivePaddingRight(), getEffectiveBorderLeftWidth() + getEffectiveBorderRightWidth());
}
return paddingAmount;
}
/**
* Adds in the table cell spacing, border stroke height.
* We may be able to set this value when the format changes.
**/
public function getTotalPaddingHeight():Number {
var paddingAmount:Number = 0;
// no textflow is no padding
if (!textFlow) {
return 0;
}
if (table && table.cellSpacing!=undefined) {
paddingAmount += table.cellSpacing;
}
if (textFlow.computedFormat.blockProgression == BlockProgression.RL) {
paddingAmount += Math.max(getEffectivePaddingLeft() + getEffectivePaddingRight(), getEffectiveBorderLeftWidth() + getEffectiveBorderRightWidth());
}
else {
paddingAmount += Math.max(getEffectivePaddingTop() + getEffectivePaddingBottom(), getEffectiveBorderTopWidth() + getEffectiveBorderBottomWidth());
}
return paddingAmount;
}
public function get includeDescentInCellBounds():Boolean
{
return _includeDescentInCellBounds;
}
public function set includeDescentInCellBounds(value:Boolean):void
{
_includeDescentInCellBounds = value;
}
}
}