You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by pi...@apache.org on 2014/11/28 01:20:42 UTC
[02/25] git commit: [flex-tlf] [refs/heads/develop] - Commit of table
work
http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/elements/ParagraphElement.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/elements/ParagraphElement.as b/textLayout/src/flashx/textLayout/elements/ParagraphElement.as
index f4579fc..1fec299 100644
--- a/textLayout/src/flashx/textLayout/elements/ParagraphElement.as
+++ b/textLayout/src/flashx/textLayout/elements/ParagraphElement.as
@@ -31,9 +31,9 @@ package flashx.textLayout.elements
import flash.text.engine.TextLine;
import flash.text.engine.TextLineValidity;
import flash.text.engine.TextRotation;
+ import flash.utils.Dictionary;
import flash.utils.getQualifiedClassName;
- import flashx.textLayout.tlf_internal;
import flashx.textLayout.compose.TextFlowLine;
import flashx.textLayout.container.ContainerController;
import flashx.textLayout.debug.Debugging;
@@ -50,6 +50,7 @@ package flashx.textLayout.elements
import flashx.textLayout.formats.TextJustify;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.property.Property;
+ import flashx.textLayout.tlf_internal;
import flashx.textLayout.utils.CharacterUtil;
import flashx.textLayout.utils.LocaleUtil;
@@ -79,7 +80,8 @@ package flashx.textLayout.elements
public final class ParagraphElement extends ParagraphFormattedElement
{
- private var _textBlock:TextBlock;
+ //private var _textBlock:TextBlock;
+ private var _textBlockChildren:Dictionary;
private var _terminatorSpan:SpanElement;
private var _interactiveChildrenCount:int;
@@ -95,6 +97,7 @@ package flashx.textLayout.elements
super();
_terminatorSpan = null;
_interactiveChildrenCount = 0 ;
+ _textBlockChildren = new Dictionary();
}
tlf_internal function get interactiveChildrenCount():int
{
@@ -106,26 +109,83 @@ package flashx.textLayout.elements
{
CONFIG::debug { assert(_textBlock == null,"createTextBlock called when there is already a textblock"); }
computedFormat; // recreate the format BEFORE the _textBlock is created
- _textBlock = new TextBlock();
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ //tbs.length = 0;
+ var tableCount:int = 0;
+ if(tbs.length == 0 && !(getChildAt(0) is TableElement) )
+ tbs.push(new TextBlock());
+ //getTextBlocks()[0] = new TextBlock();
CONFIG::debug { Debugging.traceFTECall(_textBlock,null,"new TextBlock()"); }
for (var i:int = 0; i < numChildren; i++)
{
var child:FlowElement = getChildAt(i);
+ if(child is TableElement)
+ tableCount++;
+// tbs.push(new TextBlock());
+ else
+ {
+ //child.releaseContentElement();
+ //child.createContentElement();
+ }
+ }
+ while(tableCount >= tbs.length)
+ tbs.push(new TextBlock());
+
+ for (i = 0; i < numChildren; i++)
+ {
+ child = getChildAt(i);
child.createContentElement();
}
- updateTextBlock();
+ tbs.length = tableCount + 1;
+ var tb:TextBlock;
+ for each(tb in tbs){
+ updateTextBlock(tb);
+ }
}
-
- /** @private */
-
- tlf_internal function releaseTextBlock():void
+ private function updateTextBlockDict():void
+ {
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ if(tbs.length == 0)
+ return;//nothing to do
+ var tbIdx:int = 0;
+ var tb:TextBlock = tbs[tbIdx];
+ var items:Array = [];
+ var child:FlowElement;
+ for (var i:int = 0; i < numChildren; i++)
+ {
+ child = getChildAt(i);
+ if(child is TableElement)
+ {
+ _textBlockChildren[tb] = items;
+ tb = tbs[++tbIdx];
+ items = [];
+ continue;
+ }
+ items.push(child);
+ }
+ _textBlockChildren[tb] = items;
+ }
+ private function removeTextBlock(tb:TextBlock):void
+ {
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ if(tbs)
+ {
+ var idx:int = getTextBlocks().indexOf(tb);
+ if(idx > -1)
+ {
+ tbs.splice(idx,1);
+ delete _textBlockChildren[tb];
+ }
+ }
+ }
+ private function releaseTextBlockInternal(tb:TextBlock):void
{
- if (!_textBlock)
+ if (!tb)
return;
-
- if (_textBlock.firstLine) // A TextBlock may have no firstLine if it has previously been released.
+
+ if (tb.firstLine) // A TextBlock may have no firstLine if it has previously been released.
{
- for (var textLineTest:TextLine = _textBlock.firstLine; textLineTest != null; textLineTest = textLineTest.nextLine)
+ for (var textLineTest:TextLine = tb.firstLine; textLineTest != null; textLineTest = textLineTest.nextLine)
{
if(textLineTest.numChildren != 0)
{
@@ -138,55 +198,169 @@ package flashx.textLayout.elements
}
}
- CONFIG::debug { Debugging.traceFTECall(null,_textBlock,"releaseLines",_textBlock.firstLine, _textBlock.lastLine); }
- _textBlock.releaseLines(_textBlock.firstLine, _textBlock.lastLine);
+ CONFIG::debug { Debugging.traceFTECall(null,tb,"releaseLines",tb.firstLine, tb.lastLine); }
+ tb.releaseLines(tb.firstLine, tb.lastLine);
}
-
- _textBlock.content = null;
- for (var i:int = 0; i < numChildren; i++)
+ var items:Array = _textBlockChildren[tb];
+ var len:int = items.length;
+ for (var i:int = 0; i < len; i++)
{
- var child:FlowElement = getChildAt(i);
+ var child:FlowElement = items[i];
child.releaseContentElement();
}
- _textBlock = null;
+ items.length = 0;
+ tb.content = null;
+ removeTextBlock(tb);
+ }
+ /** @private */
+ tlf_internal function releaseTextBlock(tb:TextBlock=null):void
+ {
+ updateTextBlockDict();
+ if(tb)
+ {
+ releaseTextBlockInternal(tb);
+ return;
+ }
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ for each(var tb:TextBlock in tbs)
+ {
+ releaseTextBlockInternal(tb);
+ }
+ //_textBlock = null;
if (_computedFormat)
_computedFormat = null;
}
-
+ private var _textBlocks:Vector.<TextBlock>;
+ tlf_internal function getTextBlocks():Vector.<TextBlock>
+ {
+ if(_textBlocks == null)
+ _textBlocks = new Vector.<TextBlock>();
+ return _textBlocks;
+ }
/** TextBlock where the text of the paragraph is kept. @private */
tlf_internal function getTextBlock():TextBlock
- {
- if (!_textBlock)
+ {
+ if (!getTextBlocks().length)
+ createTextBlock();
+
+ return getTextBlocks()[0];
+ }
+ /** Last TextBlock where the text of the paragraph is kept. @private */
+ tlf_internal function getLastTextBlock():TextBlock
+ {
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ if(!tbs.length)
createTextBlock();
- return _textBlock;
+
+ return tbs[tbs.length-1];
+ }
+
+ /** Get TextBlock at specified position. @private */
+ tlf_internal function getTextBlockAtPosition(pos:int):TextBlock
+ {
+ var curPos:int = 0;
+ var posShift:int = 0;
+ var tables:Vector.<TableElement> = getTables();
+ if(!tables.length)
+ return getTextBlock();
+
+ for each(var table:TableElement in tables)
+ {
+ if(table.getElementRelativeStart(this) < pos)
+ posShift++;
+ }
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ for each(var tb:TextBlock in tbs)
+ {
+ if(tb.content == null)
+ return tb;
+ curPos += tb.content.rawText.length;
+ if(curPos + posShift > pos)
+ {
+ if(getTextBlockStart(tb) > pos)
+ return null;
+ return tb;
+ }
+ }
+ return null;
+ }
+
+ tlf_internal function getTextBlockAbsoluteStart(tb:TextBlock):int
+ {
+ var start:int = getTextBlockStart(tb);
+ if(start < 0)
+ start = 0;
+ return getAbsoluteStart() + start;
+ }
+ tlf_internal function getTextBlockStart(tb:TextBlock):int
+ {
+ var i:int;
+ var curPos:int = 0;
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ if(tbs.length == 0)
+ return -1;
+ var tables:Vector.<TableElement> = getTables();
+ for each(var curTB:TextBlock in tbs)
+ {
+ for each(var table:TableElement in tables)
+ {
+ if(table.getElementRelativeStart(this) <= curPos)
+ {
+ curPos++;
+ tables.splice(tables.indexOf(table),1);
+ }
+ }
+ if(tb == curTB)
+ return curPos;
+ if(tb.content)
+ curPos += curTB.content.rawText.length;
+ }
+
+ return -1;
}
+ private function getTables():Vector.<TableElement>
+ {
+ var tables:Vector.<TableElement> = new Vector.<TableElement>();
+ for (var i:int = 0; i < numChildren; i++)
+ {
+ var child:FlowElement = getChildAt(i);
+ if(child is TableElement)
+ tables.push(child as TableElement);
+ }
+ return tables;
+ }
+
/** TextBlock where the text of the paragraph is kept, or null if we currently don't have one. @private */
tlf_internal function peekTextBlock():TextBlock
{
- return _textBlock;
+ return getTextBlocks().length == 0 ? null : getTextBlocks()[0];
}
/** @private */
tlf_internal function releaseLineCreationData():void
{
CONFIG::debug { assert(Configuration.playerEnablesArgoFeatures,"bad call to releaseLineCreationData"); }
- if (_textBlock)
- _textBlock["releaseLineCreationData"]();
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ for each(var tb:TextBlock in tbs)
+ {
+ tb["releaseLineCreationData"]();
+ }
}
/** @private */
- tlf_internal override function createContentAsGroup():GroupElement
- {
- var group:GroupElement = _textBlock.content as GroupElement;
+ tlf_internal override function createContentAsGroup(pos:int=0):GroupElement
+ {
+ var tb:TextBlock = getTextBlockAtPosition(pos);
+ var group:GroupElement = tb.content as GroupElement;
if (!group)
{
- var originalContent:ContentElement = _textBlock.content;
+ var originalContent:ContentElement = tb.content;
group = new GroupElement();
CONFIG::debug { Debugging.traceFTECall(group,null,"new GroupElement()"); }
- _textBlock.content = group;
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"content",group); }
+ tb.content = group;
+ CONFIG::debug { Debugging.traceFTEAssign(tb,"content",group); }
if (originalContent)
{
@@ -199,7 +373,7 @@ package flashx.textLayout.elements
}
// Now we've got to force damage the entire paragraph, because we restructured it in FTE.
- if (_textBlock.firstLine && textLength)
+ if (tb.firstLine && textLength)
{
var textFlow:TextFlow = getTextFlow();
if (textFlow)
@@ -212,7 +386,15 @@ package flashx.textLayout.elements
/** @private */
tlf_internal override function removeBlockElement(child:FlowElement, block:ContentElement):void
{
- if (numChildren == 1)
+ var tb:TextBlock = getTextBlockAtPosition(child.getElementRelativeStart(this));
+ if(!tb)
+ tb = getTextBlock();
+
+ if(tb.content == null)
+ return;
+ var relativeStart:int = child.getElementRelativeStart(this);
+
+ if (getChildrenInTextBlock(relativeStart).length < 2)
{
if (block is GroupElement)
{
@@ -221,18 +403,20 @@ package flashx.textLayout.elements
CONFIG::debug { assert(_textBlock.content is GroupElement,"removeBlockElement: bad content"); }
CONFIG::debug { assert(GroupElement(_textBlock.content).elementCount == 1,"removeBlockElement: bad element count"); }
CONFIG::debug { assert(GroupElement(_textBlock.content).getElementAt(0) == block,"removeBlockElement: bad group content"); }
- GroupElement(_textBlock.content).replaceElements(0,1,null);
+ GroupElement(tb.content).replaceElements(0,1,null);
CONFIG::debug { Debugging.traceFTECall(null,_textBlock.content,"replaceElements",0,1,null); }
}
- _textBlock.content = null;
+ tb.content = null;
CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"content",null); }
}
- else
+ else if(block.groupElement)
{
- var idx:int = this.getChildIndex(child);
- var group:GroupElement = GroupElement(_textBlock.content);
+ var idx:int = getChildIndexInBlock(child);
+ var group:GroupElement = GroupElement(tb.content);
CONFIG::debug { assert(group.elementCount == numChildren,"Mismatched group and elementCount"); }
group.replaceElements(idx,idx+1,null);
+ if(group.elementCount == 0)
+ return;
CONFIG::debug { Debugging.traceFTECall(null,group,"replaceElements",idx,idx+1,null); }
if (numChildren == 2) // its going to be one so ungroup
{
@@ -243,18 +427,22 @@ package flashx.textLayout.elements
{
group.replaceElements(0,1,null);
CONFIG::debug { Debugging.traceFTECall(null,group,"replaceElements",0,1,null); }
- _textBlock.content = elem;
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"content",elem); }
+ tb.content = elem;
+ CONFIG::debug { Debugging.traceFTEAssign(tb,"content",elem); }
}
}
}
+ else {
+ //trace("1");
+ //tb.content = null;
+ }
}
/** @private */
tlf_internal override function hasBlockElement():Boolean
{
- return _textBlock != null;
+ return getTextBlocks().length > 0;
}
/** @private */
@@ -264,9 +452,42 @@ package flashx.textLayout.elements
}
/** @private */
+ private function getChildrenInTextBlock(pos:int):Array
+ {
+ var retVal:Array = [];
+ if(numChildren == 0)
+ return retVal;
+ if(numChildren == 1)
+ {
+ retVal.push(getChildAt(0));
+ return retVal
+ }
+ var chldrn:Array = mxmlChildren.slice();
+ for(var i:int = 0; i<chldrn.length;i++)
+ {
+ if(chldrn[i] is TableElement)
+ {
+ if(chldrn[i].parentRelativeStart == pos)
+ return [chldrn[i]];
+ if(chldrn[i].parentRelativeStart < pos)
+ {
+ retVal.length = 0;
+ continue;
+ }
+ if(chldrn[i].parentRelativeStart > pos)
+ break;
+ }
+ retVal.push(chldrn[i]);
+ }
+ return retVal;
+ }
+
+ /** @private */
tlf_internal override function insertBlockElement(child:FlowElement, block:ContentElement):void
{
- if (_textBlock == null)
+ var relativeStart:int = child.getElementRelativeStart(this);
+ var tb:TextBlock = getTextBlockAtPosition(relativeStart);
+ if (getTextBlocks().length == 0 || !tb)
{
child.releaseContentElement();
createTextBlock(); // does the whole tree
@@ -274,7 +495,7 @@ package flashx.textLayout.elements
}
var gc:Vector.<ContentElement>; // scratch var
var group:GroupElement; // scratch
- if (numChildren == 1)
+ if (getChildrenInTextBlock(relativeStart).length < 2)
{
if (block is GroupElement)
{
@@ -285,19 +506,23 @@ package flashx.textLayout.elements
CONFIG::debug { Debugging.traceFTECall(null,gc,"push",block); }
group = new GroupElement(gc);
CONFIG::debug { Debugging.traceFTECall(group,null,"new GroupElement",gc); }
- _textBlock.content = group;
+ tb.content = group;
CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"content",group); }
}
else
{
- _textBlock.content = block;
+ if(block.groupElement)
+ {
+ block.groupElement.elementCount;
+ }
+ tb.content = block;
CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"content",block); }
}
}
else
{
- group = createContentAsGroup();
- var idx:int = this.getChildIndex(child);
+ group = createContentAsGroup(relativeStart);
+ var idx:int = getChildIndexInBlock(child);
gc = new Vector.<ContentElement>();
CONFIG::debug { Debugging.traceFTECall(gc,null,"new Vector.<ContentElement>") }
gc.push(block);
@@ -307,6 +532,21 @@ package flashx.textLayout.elements
}
}
+ private function getChildIndexInBlock(elem:FlowElement):int
+ {
+ var relIdx:int = 0;
+ for (var i:int = 0; i < numChildren; i++)
+ {
+ var child:FlowElement = getChildAt(i);
+ if(child == elem)
+ return relIdx;
+ relIdx++;
+ if(child is TableElement)
+ relIdx = 0;
+ }
+ return -1;
+ }
+
/** @private */
override protected function get abstract():Boolean
{ return false; }
@@ -315,24 +555,63 @@ package flashx.textLayout.elements
tlf_internal override function get defaultTypeName():String
{ return "p"; }
+ tlf_internal function removeEmptyTerminator():void
+ {
+ if(numChildren == 1 && _terminatorSpan && _terminatorSpan.textLength == 1)
+ {
+ _terminatorSpan.removeParaTerminator();
+ super.replaceChildren(0, 1);
+ this._terminatorSpan = null;
+ }
+ }
/** @private */
public override function replaceChildren(beginChildIndex:int,endChildIndex:int,...rest):void
{
var applyParams:Array;
-
- // makes a measurable difference - rest.length zero and one are the common cases
- if (rest.length == 1)
- applyParams = [beginChildIndex, endChildIndex, rest[0]];
- else
- {
- applyParams = [beginChildIndex, endChildIndex];
- if (rest.length != 0)
- applyParams = applyParams.concat.apply(applyParams, rest);
- }
- super.replaceChildren.apply(this, applyParams);
+ do{
+ if(_terminatorSpan)
+ {
+ var termIdx:int = getChildIndex(_terminatorSpan);
+ if(termIdx !=0 && _terminatorSpan.textLength == 1)
+ {
+ super.replaceChildren(termIdx, termIdx+1);
+ _terminatorSpan = null;
+ if(beginChildIndex >= termIdx)
+ {
+ beginChildIndex--;
+ if(rest.length == 0) // delete of terminator was already done.
+ break;
+ }
+ if(endChildIndex >= termIdx && beginChildIndex != endChildIndex)
+ endChildIndex--;
+ }
+ }
+
+ // makes a measurable difference - rest.length zero and one are the common cases
+ if (rest.length == 1)
+ applyParams = [beginChildIndex, endChildIndex, rest[0]];
+ else
+ {
+ applyParams = [beginChildIndex, endChildIndex];
+ if (rest.length != 0)
+ applyParams = applyParams.concat.apply(applyParams, rest);
+ }
+
+ super.replaceChildren.apply(this, applyParams);
+
+ }while(false);
ensureTerminatorAfterReplace();
+ // ensure correct text blocks
+ createTextBlock();
+ }
+
+ public override function splitAtPosition(relativePosition:int):FlowElement
+ {
+ // need to handle multiple TextBlocks
+ // maybe not. It might be handled in replaceChildren().
+ return super.splitAtPosition(relativePosition);
}
/** @private */
tlf_internal function ensureTerminatorAfterReplace():void
@@ -340,27 +619,43 @@ package flashx.textLayout.elements
var newLastLeaf:FlowLeafElement = getLastLeaf();
if (_terminatorSpan != newLastLeaf)
{
- if (_terminatorSpan)
+ if (newLastLeaf && _terminatorSpan)
{
_terminatorSpan.removeParaTerminator();
+ if(_terminatorSpan.textLength == 0)
+ {
+ var termIdx:int = getChildIndex(_terminatorSpan);
+ super.replaceChildren(termIdx, termIdx+1);
+ }
this._terminatorSpan = null;
}
- if (newLastLeaf)
+ if (newLastLeaf is SpanElement)
{
- if (newLastLeaf is SpanElement)
- {
- (newLastLeaf as SpanElement).addParaTerminator();
- this._terminatorSpan = newLastLeaf as SpanElement;
- }
- else
- {
- var s:SpanElement = new SpanElement();
- super.replaceChildren(numChildren,numChildren,s);
- s.format = newLastLeaf.format;
- s.addParaTerminator();
- this._terminatorSpan = s;
- }
+ (newLastLeaf as SpanElement).addParaTerminator();
+ this._terminatorSpan = newLastLeaf as SpanElement;
+ }
+ else
+ {
+ var s:SpanElement = new SpanElement();
+ super.replaceChildren(numChildren,numChildren,s);
+ s.format = newLastLeaf ? newLastLeaf.format : _terminatorSpan.format;
+ s.addParaTerminator();
+ this._terminatorSpan = s;
+ }
+ }
+ //merge terminator span to previous if possible
+ if(_terminatorSpan.textLength == 1)
+ {
+ var prev:FlowLeafElement = _terminatorSpan.getPreviousLeaf(this);
+ if(prev && prev is SpanElement)
+ {
+ _terminatorSpan.removeParaTerminator();
+ termIdx = getChildIndex(_terminatorSpan);
+ super.replaceChildren(termIdx, termIdx+1);
+ s = prev as SpanElement;
+ s.addParaTerminator();
+ this._terminatorSpan = s;
}
}
}
@@ -387,7 +682,7 @@ package flashx.textLayout.elements
child.bindableElement = true;
// Note: calling super.replaceChildren because we don't want to transfer para terminator each time
- super.replaceChildren(numChildren, numChildren, child as FlowElement);
+ super.replaceChildren(numChildren, numChildren, child as FlowElement);
}
else if (child is String)
{
@@ -404,6 +699,9 @@ package flashx.textLayout.elements
// Now ensure para terminator
ensureTerminatorAfterReplace();
+
+ // recreate text blocks to handle possible TableElement changes
+ createTextBlock();
}
/** @private
@@ -411,17 +709,26 @@ package flashx.textLayout.elements
public override function getText(relativeStart:int=0, relativeEnd:int=-1, paragraphSeparator:String="\n"):String
{
// Optimization for getting text of the entire paragraph
- if (relativeStart == 0 && (relativeEnd == -1 || relativeEnd >= textLength-1) && _textBlock)
+ if (relativeStart == 0 && (relativeEnd == -1 || relativeEnd >= textLength-1) && getTextBlocks().length)
{
- if (_textBlock.content && _textBlock.content.rawText)
+ var tb:TextBlock;
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ var text:String = "";
+ for each(tb in tbs)
{
- var text:String = _textBlock.content.rawText;
- return text.substring(0, text.length - 1);
+ text = text + getTextInBlock(tb);
}
- return ""; // content is null
+ if(tb.content && tb.content.rawText)
+ return text.substring(0, text.length - 1);
+ return text;
}
return super.getText(relativeStart, relativeEnd, paragraphSeparator);
}
+ private function getTextInBlock(tb:TextBlock):String{
+ if(!tb.content || !tb.content.rawText)
+ return "";
+ return tb.content.rawText;
+ }
/** Returns the paragraph that follows this one, or null if there are no more paragraphs.
*
@@ -478,39 +785,46 @@ package flashx.textLayout.elements
public function findPreviousAtomBoundary(relativePosition:int):int
{
+ var tb:TextBlock = getTextBlockAtPosition(relativePosition);
+ var tbStart:int = getTextBlockStart(tb);
+ var textBlockPos:int = relativePosition - tbStart;
if (ContainerController.tlf_internal::usesDiscretionaryHyphens)
{
- var textBlock:TextBlock = getTextBlock();
- var tl:TextLine = textBlock.getTextLineAtCharIndex(relativePosition);
- var currentAtomIndex:int = tl.getAtomIndexAtCharIndex(relativePosition);
+ var tl:TextLine = tb.getTextLineAtCharIndex(textBlockPos);
+ var currentAtomIndex:int = tl.getAtomIndexAtCharIndex(textBlockPos);
//trace("relpos", relativePosition, "atomIndex", currentAtomIndex);
var isRTL:Boolean = tl.getAtomBidiLevel(currentAtomIndex) == 1;
if (isRTL)
{
- var foo:int = getTextBlock().findPreviousAtomBoundary(relativePosition);
+ var foo:int = tb.findPreviousAtomBoundary(textBlockPos);
if (currentAtomIndex == 0)
{
// when cursor is left of all characters (end of line)
// atomIndex is 0, so compensate
if (tl.atomCount > 0)
{
- while (--relativePosition)
+ while (--textBlockPos)
{
- if (tl.getAtomIndexAtCharIndex(relativePosition) != currentAtomIndex)
+ --relativePosition;
+ if (tl.getAtomIndexAtCharIndex(textBlockPos) != currentAtomIndex)
break;
}
}
}
else
{
- while (--relativePosition)
+ while (--relativePosition && --textBlockPos)
{
- if (tl.getAtomIndexAtCharIndex(relativePosition) != currentAtomIndex)
+ if (tl.getAtomIndexAtCharIndex(textBlockPos) != currentAtomIndex)
break;
}
}
if (CharacterUtil.isLowSurrogate(getText(relativePosition, relativePosition + 1).charCodeAt(0)))
- relativePosition--;
+ {
+ relativePosition--;
+ textBlockPos--;
+ }
+
//trace("previous", relativePosition, foo);
}
else
@@ -521,21 +835,26 @@ package flashx.textLayout.elements
if (!tl)
return -1;
// need this when 0x2028 line separator in use
- if (tl.textBlockBeginIndex + tl.rawTextLength == relativePosition)
- return tl.textBlockBeginIndex + tl.rawTextLength - 1;
- return tl.textBlockBeginIndex + tl.rawTextLength;
+ if (tl.textBlockBeginIndex + tl.rawTextLength == textBlockPos)
+ return tl.textBlockBeginIndex + tl.rawTextLength - 1 + tbStart;
+ return tl.textBlockBeginIndex + tl.rawTextLength + tbStart;
}
- while (--relativePosition)
+ while (--relativePosition && --textBlockPos)
{
- if (tl.getAtomIndexAtCharIndex(relativePosition) < currentAtomIndex)
+ if (tl.getAtomIndexAtCharIndex(textBlockPos) < currentAtomIndex)
break;
}
if (CharacterUtil.isLowSurrogate(getText(relativePosition, relativePosition + 1).charCodeAt(0)))
- relativePosition--;
+ {
+ relativePosition--;
+ textBlockPos--;
+ }
}
return relativePosition;
}
- var pos:int = getTextBlock().findPreviousAtomBoundary(relativePosition);
+ var pos:int = tb.findPreviousAtomBoundary(textBlockPos);
+ if(pos >= 0)
+ pos += tbStart;
//trace("previous", relativePosition, pos);
return pos;
}
@@ -560,34 +879,41 @@ package flashx.textLayout.elements
public function findNextAtomBoundary(relativePosition:int):int
{
+ var tb:TextBlock = getTextBlockAtPosition(relativePosition);
+ var tbStart:int = getTextBlockStart(tb);
+ var textBlockPos:int = relativePosition - tbStart;
if (ContainerController.tlf_internal::usesDiscretionaryHyphens)
{
- var textBlock:TextBlock = getTextBlock();
- var tl:TextLine = textBlock.getTextLineAtCharIndex(relativePosition);
- var currentAtomIndex:int = tl.getAtomIndexAtCharIndex(relativePosition);
+ var tl:TextLine = tb.getTextLineAtCharIndex(textBlockPos);
+ var currentAtomIndex:int = tl.getAtomIndexAtCharIndex(textBlockPos);
//trace("relpos", relativePosition, "atomIndex", currentAtomIndex);
var isRTL:Boolean = tl.getAtomBidiLevel(currentAtomIndex) == 1;
if (isRTL)
{
- var foo:int = getTextBlock().findNextAtomBoundary(relativePosition);
+ var foo:int = tb.findNextAtomBoundary(textBlockPos);
if (currentAtomIndex == 0)
{
- while (++relativePosition)
+ while (++textBlockPos)
{
- if (tl.getAtomIndexAtCharIndex(relativePosition) != currentAtomIndex)
+ ++relativePosition;
+ if (tl.getAtomIndexAtCharIndex(textBlockPos) != currentAtomIndex)
break;
}
}
else
{
- while (++relativePosition)
+ while (++textBlockPos)
{
- if (tl.getAtomIndexAtCharIndex(relativePosition) != currentAtomIndex)
+ ++relativePosition;
+ if (tl.getAtomIndexAtCharIndex(textBlockPos) != currentAtomIndex)
break;
}
}
if (CharacterUtil.isHighSurrogate(getText(relativePosition, relativePosition + 1).charCodeAt(0)))
- relativePosition++;
+ {
+ relativePosition++;
+ textBlockPos++;
+ }
//trace("next", relativePosition, foo);
}
else
@@ -597,19 +923,25 @@ package flashx.textLayout.elements
tl = tl.nextLine;
if (!tl)
return -1;
- return tl.textBlockBeginIndex;
+ return tl.textBlockBeginIndex + tbStart;
}
- while (++relativePosition)
+ while (++textBlockPos)
{
- if (tl.getAtomIndexAtCharIndex(relativePosition) > currentAtomIndex)
+ ++relativePosition;
+ if (tl.getAtomIndexAtCharIndex(textBlockPos) > currentAtomIndex)
break;
}
if (CharacterUtil.isHighSurrogate(getText(relativePosition, relativePosition + 1).charCodeAt(0)))
- relativePosition++;
+ {
+ relativePosition++;
+ textBlockPos++;
+ }
}
return relativePosition;
}
- var pos:int = getTextBlock().findNextAtomBoundary(relativePosition);
+ var pos:int = tb.findNextAtomBoundary(textBlockPos);
+ if(pos >= 0)
+ pos += tbStart;
//trace("next", relativePosition, pos);
return pos;
}
@@ -617,7 +949,27 @@ package flashx.textLayout.elements
/** @private */
public override function getCharAtPosition(relativePosition:int):String
{
- return getTextBlock().content.rawText.charAt(relativePosition);
+ var foundTB:TextBlock = getTextBlockAtPosition(relativePosition);
+ if(!foundTB)
+ return "\u0016";
+ var tables:Vector.<TableElement> = getTables();
+ var pos:int = relativePosition;
+ for each(var table:TableElement in tables)
+ {
+ if(table.getElementRelativeStart(this) < pos)
+ relativePosition--;
+ }
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ for each(var tb:TextBlock in tbs)
+ {
+ if(foundTB == tb)
+ break;
+ if(tb)
+ relativePosition -= tb.content.rawText.length;
+ else
+ relativePosition -= 1;this.getText()
+ }
+ return foundTB.content.rawText.charAt(relativePosition);
}
/**
@@ -650,7 +1002,13 @@ package flashx.textLayout.elements
}
return relativePosition;
}
- return getTextBlock().findPreviousWordBoundary(relativePosition);
+ var block:TextBlock = getTextBlockAtPosition(relativePosition);
+ if(block == null)
+ block = getTextBlockAtPosition(--relativePosition);
+ var pos:int = getTextBlockStart(block);
+ if(pos < 0)
+ pos = 0;
+ return relativePosition == pos ? pos : pos + block.findPreviousWordBoundary(relativePosition - pos);
}
/**
@@ -683,7 +1041,13 @@ package flashx.textLayout.elements
}
return relativePosition;
}
- return getTextBlock().findNextWordBoundary(relativePosition);
+ var block:TextBlock = getTextBlockAtPosition(relativePosition);
+ if(block == null)
+ block = getTextBlockAtPosition(--relativePosition);
+ var pos:int = getTextBlockStart(block);
+ if(pos < 0)
+ pos = 0;
+ return pos + block.findNextWordBoundary(relativePosition - pos);
}
static private var _defaultTabStops:Vector.<TabStop>;
@@ -697,8 +1061,10 @@ package flashx.textLayout.elements
_defaultTabStops[i] = new TabStop(TextAlign.START, defaultTabWidth * i);
}
- private function updateTextBlock():void
+ private function updateTextBlock(textBlock:TextBlock=null):void
{
+ if(!textBlock)
+ textBlock = getTextBlock();
// find the ancestor with a container and use its format for various settings
var containerElement:ContainerFormattedElement = getAncestorWithContainer();
if (!containerElement)
@@ -746,10 +1112,10 @@ package flashx.textLayout.elements
}
CONFIG::debug { Debugging.traceFTECall(spaceJustifier,null,"new SpaceJustifier",_computedFormat.locale,lineJust,spaceJustifier.letterSpacing); }
- _textBlock.textJustifier = spaceJustifier;
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"textJustifier",spaceJustifier); }
- _textBlock.baselineZero = getLeadingBasis(this.getEffectiveLeadingModel());
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"baselineZero",_textBlock.baselineZero); }
+ textBlock.textJustifier = spaceJustifier;
+ CONFIG::debug { Debugging.traceFTEAssign(textBlock,"textJustifier",spaceJustifier); }
+ textBlock.baselineZero = getLeadingBasis(this.getEffectiveLeadingModel());
+ CONFIG::debug { Debugging.traceFTEAssign(textBlock,"baselineZero",textBlock.baselineZero); }
}
else
{
@@ -758,21 +1124,21 @@ package flashx.textLayout.elements
eastAsianJustifier.composeTrailingIdeographicSpaces = true;
}
CONFIG::debug { Debugging.traceFTECall(eastAsianJustifier,null,"new EastAsianJustifier",_computedFormat.locale,lineJust,makeJustRuleStyle); }
- _textBlock.textJustifier = eastAsianJustifier as EastAsianJustifier;
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"textJustifier",eastAsianJustifier); }
- _textBlock.baselineZero = getLeadingBasis(this.getEffectiveLeadingModel());
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"baselineZero",_textBlock.baselineZero); }
+ textBlock.textJustifier = eastAsianJustifier as EastAsianJustifier;
+ CONFIG::debug { Debugging.traceFTEAssign(textBlock,"textJustifier",eastAsianJustifier); }
+ textBlock.baselineZero = getLeadingBasis(this.getEffectiveLeadingModel());
+ CONFIG::debug { Debugging.traceFTEAssign(textBlock,"baselineZero",textBlock.baselineZero); }
}
- _textBlock.bidiLevel = _computedFormat.direction == Direction.LTR ? 0 : 1;
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"bidiLevel",_textBlock.bidiLevel); }
+ textBlock.bidiLevel = _computedFormat.direction == Direction.LTR ? 0 : 1;
+ CONFIG::debug { Debugging.traceFTEAssign(textBlock,"bidiLevel",textBlock.bidiLevel); }
- _textBlock.lineRotation = containerElementFormat.blockProgression == BlockProgression.RL ? TextRotation.ROTATE_90 : TextRotation.ROTATE_0;
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"lineRotation",_textBlock.lineRotation); }
+ textBlock.lineRotation = containerElementFormat.blockProgression == BlockProgression.RL ? TextRotation.ROTATE_90 : TextRotation.ROTATE_0;
+ CONFIG::debug { Debugging.traceFTEAssign(textBlock,"lineRotation",textBlock.lineRotation); }
if (_computedFormat.tabStops && _computedFormat.tabStops.length != 0)
{
- //create a vector of TabStops and assign it to tabStops in _textBlock
+ //create a vector of TabStops and assign it to tabStops in textBlock
var tabStops:Vector.<TabStop> = new Vector.<TabStop>();
CONFIG::debug { Debugging.traceFTECall(tabStops,null,"new Vector.<TabStop>()"); }
for each(var tsa:TabStopFormat in _computedFormat.tabStops)
@@ -786,8 +1152,8 @@ package flashx.textLayout.elements
tabStops.push(tabStop);
CONFIG::debug { Debugging.traceFTECall(null,tabStops,"push",tabStop); }
}
- _textBlock.tabStops = tabStops;
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"tabStops",tabStops); }
+ textBlock.tabStops = tabStops;
+ CONFIG::debug { Debugging.traceFTEAssign(textBlock,"tabStops",tabStops); }
}
else if (GlobalSettings.enableDefaultTabStops && !Configuration.playerEnablesArgoFeatures)
{
@@ -795,13 +1161,13 @@ package flashx.textLayout.elements
// is true, TLF will set up default tabStops in the case where there are no tabs defined.
if (_defaultTabStops == null)
initializeDefaultTabStops();
- _textBlock.tabStops = _defaultTabStops;
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"tabStops",_defaultTabStops); }
+ textBlock.tabStops = _defaultTabStops;
+ CONFIG::debug { Debugging.traceFTEAssign(textBlock,"tabStops",_defaultTabStops); }
}
else
{
- _textBlock.tabStops = null;
- CONFIG::debug { Debugging.traceFTEAssign(_textBlock,"tabStops",null); }
+ textBlock.tabStops = null;
+ CONFIG::debug { Debugging.traceFTEAssign(textBlock,"tabStops",null); }
}
}
@@ -811,8 +1177,10 @@ package flashx.textLayout.elements
if (!_computedFormat)
{
super.computedFormat;
- if (_textBlock)
- updateTextBlock();
+ var tbs:Vector.<TextBlock> = getTextBlocks();
+ for each(var tb:TextBlock in tbs)
+ updateTextBlock(tb);
+
}
return _computedFormat;
}
@@ -820,7 +1188,7 @@ package flashx.textLayout.elements
/** @private */
tlf_internal override function canOwnFlowElement(elem:FlowElement):Boolean
{
- return elem is FlowLeafElement || elem is SubParagraphGroupElementBase;
+ return elem is FlowLeafElement || elem is SubParagraphGroupElementBase || elem is TableElement;
}
/** @private */
@@ -884,32 +1252,6 @@ package flashx.textLayout.elements
}
}
- // mjzhang : new API for table feature, to discuss
- public function isInTable():Boolean
- {
- var parent:FlowElement = this.parent;
- while ( parent )
- {
- if ( (parent is TableDataCellElement) )
- return true;
- parent = parent.parent;
- }
-
- return false;
- }
-
- public function getTableDataCellElement():TableDataCellElement
- {
- var parent:FlowElement = this.parent;
- while ( parent )
- {
- if ( (parent is TableDataCellElement) )
- return parent as TableDataCellElement;
- parent = parent.parent;
- }
-
- return null;
- }
/** @private */
tlf_internal function getEffectiveLeadingModel():String
{
@@ -938,19 +1280,20 @@ package flashx.textLayout.elements
/** @private */
CONFIG::debug public override function debugCheckFlowElement(depth:int = 0, extraData:String = ""):int
{
- var rslt:int = super.debugCheckFlowElement(depth," fte:"+getDebugIdentity(_textBlock)+" "+extraData);
+ var tb:TextBlock = getTextBlock();
+ var rslt:int = super.debugCheckFlowElement(depth," fte:"+getDebugIdentity(tb)+" "+extraData);
// now check the character count and then the last character
- if (_textBlock)
+ if (tb)
{
- var contentLength:int = _textBlock.content && _textBlock.content.rawText ? _textBlock.content.rawText.length : 0;
+ var contentLength:int = tb.content && tb.content.rawText ? tb.content.rawText.length : 0;
rslt += assert(contentLength == textLength,"Bad paragraph length mode:"+textLength.toString()+" _textBlock:" + contentLength.toString());
- var groupElement:GroupElement = _textBlock.content as GroupElement;
+ var groupElement:GroupElement = tb.content as GroupElement;
if (groupElement)
assert(groupElement.elementCount == numChildren,"Mismatched group and elementCount");
- else if (_textBlock.content)
+ else if (tb.content)
assert(1 == numChildren,"Mismatched group and elementCount");
else
assert(0 == numChildren,"Mismatched group and elementCount");
@@ -1013,5 +1356,11 @@ package flashx.textLayout.elements
{
return _interactiveChildrenCount != 0 ;
}
+
+ tlf_internal function get terminatorSpan():SpanElement
+ {
+ return _terminatorSpan;
+ }
+
}
}
http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/elements/SpanElement.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/elements/SpanElement.as b/textLayout/src/flashx/textLayout/elements/SpanElement.as
index c16adff..9e37058 100644
--- a/textLayout/src/flashx/textLayout/elements/SpanElement.as
+++ b/textLayout/src/flashx/textLayout/elements/SpanElement.as
@@ -395,6 +395,8 @@ package flashx.textLayout.elements
assert(_blockElement.rawText.charAt(_blockElement.rawText.length-1) != SpanElement.kParagraphTerminator,"adding para terminator twice");
}
+ if(_text && _text.substr(-1) == SpanElement.kParagraphTerminator)// terminator exists. Bail out.
+ return;
replaceTextInternal(textLength,textLength,SpanElement.kParagraphTerminator);
CONFIG::debug
@@ -414,6 +416,9 @@ package flashx.textLayout.elements
assert(_text && _text.length && _text.charAt(_text.length-1) == SpanElement.kParagraphTerminator,
"attempting to remove para terminator when it doesn't exist");
}
+ if(!_text || _text.substr(-1) != SpanElement.kParagraphTerminator)// no terminator exists. Bail out.
+ return;
+
replaceTextInternal(textLength-1,textLength,"");
modelChanged(ModelChange.TEXT_DELETED,this,textLength > 0 ? textLength-1 : 0,1);
}
@@ -464,7 +469,7 @@ package flashx.textLayout.elements
{
// optimized version leverages player APIs
// TODO: Jeff to add split on TextElement so we don't have to go find a group every time
- var group:GroupElement = parent.createContentAsGroup();
+ var group:GroupElement = parent.createContentAsGroup(getElementRelativeStart(parent));
var elementIndex:int = group.getElementIndex(_blockElement);
http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/elements/SubParagraphGroupElementBase.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/elements/SubParagraphGroupElementBase.as b/textLayout/src/flashx/textLayout/elements/SubParagraphGroupElementBase.as
index c65e138..2affda3 100644
--- a/textLayout/src/flashx/textLayout/elements/SubParagraphGroupElementBase.as
+++ b/textLayout/src/flashx/textLayout/elements/SubParagraphGroupElementBase.as
@@ -190,7 +190,7 @@ package flashx.textLayout.elements
}
/** @private */
- tlf_internal override function createContentAsGroup():GroupElement
+ tlf_internal override function createContentAsGroup(pos:int=0):GroupElement
{ return groupElement; }
/** @private */
http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/elements/TableColElement.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/elements/TableColElement.as b/textLayout/src/flashx/textLayout/elements/TableColElement.as
index 85a1d9e..342b9ce 100644
--- a/textLayout/src/flashx/textLayout/elements/TableColElement.as
+++ b/textLayout/src/flashx/textLayout/elements/TableColElement.as
@@ -18,6 +18,7 @@
////////////////////////////////////////////////////////////////////////////////
package flashx.textLayout.elements
{
+ import flashx.textLayout.formats.ITextLayoutFormat;
import flashx.textLayout.tlf_internal;
use namespace tlf_internal;
@@ -36,6 +37,15 @@ package flashx.textLayout.elements
{
//public var height:Number;
public var x:Number;
+ public var colIndex:int;
+
+ public function TableColElement(format:ITextLayoutFormat=null)
+ {
+ super();
+ if(format)
+ this.format = format;
+ }
+
/** @private */
override protected function get abstract():Boolean
@@ -56,6 +66,29 @@ package flashx.textLayout.elements
{
super.modelChanged(changeType,elem,changeStart,changeLen,needNormalize,bumpGeneration);
}
-
+
+ /**
+ * Get a Vector of cells or null if the column contains no cells
+ **/
+ public function get cells():Vector.<TableCellElement> {
+
+ if (!table) {
+ return null;
+ }
+
+ return table.getCellsForColumn(this);
+ }
+
+ /**
+ * Returns the number of cells in this column.
+ **/
+ public function get numCells():int {
+
+ if (!table) {
+ return 0;
+ }
+
+ return table.getCellsForColumn(this).length;
+ }
}
}
http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/elements/TableElement.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/elements/TableElement.as b/textLayout/src/flashx/textLayout/elements/TableElement.as
index 92cefcc..ed82a28 100644
--- a/textLayout/src/flashx/textLayout/elements/TableElement.as
+++ b/textLayout/src/flashx/textLayout/elements/TableElement.as
@@ -18,19 +18,17 @@
////////////////////////////////////////////////////////////////////////////////
package flashx.textLayout.elements
{
- import flash.display.Graphics;
- import flash.events.Event;
- import flash.events.EventDispatcher;
- import flash.events.IEventDispatcher;
- import flash.events.MouseEvent;
- import flash.geom.Point;
- import flash.text.engine.TextBlock;
- import flash.text.engine.TextLine;
+ import flash.display.Sprite;
+ import flash.text.engine.ContentElement;
+ import flash.text.engine.GraphicElement;
+ import flash.utils.Dictionary;
- import flashx.textLayout.events.FlowElementEventDispatcher;
- import flashx.textLayout.events.FlowElementMouseEventManager;
+ import flashx.textLayout.compose.TextFlowTableBlock;
+ import flashx.textLayout.edit.SelectionFormat;
import flashx.textLayout.events.ModelChange;
- import flashx.textLayout.formats.*;
+ import flashx.textLayout.formats.FormatValue;
+ import flashx.textLayout.formats.ITextLayoutFormat;
+ import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.tlf_internal;
use namespace tlf_internal;
@@ -41,7 +39,6 @@ package flashx.textLayout.elements
* A TableElement's children must be of type TableRowElement, TableColElement, TableColGroupElement, TableBodyElement.
*
*
- *
* @playerversion Flash 10
* @playerversion AIR 1.5
* @langversion 3.0
@@ -49,41 +46,38 @@ package flashx.textLayout.elements
*/
public class TableElement extends TableFormattedElement
{
- private var _row:int;
- private var _column:int;
- private var _height:Array = []; // parcel-indexed
- public var computedWidth:Number;
+ private var _computedWidth:Number;
public var x:Number;
public var y:Number;
- //These attributes is from the original loop prototype. Maybe changed later
- public var totalRowDepth:Number = undefined;
- public var originParcelIndex:Number;
- public var numAcrossParcels:int;
- public var curRowIdx:int = 0; // this value should be only used while composing
- public var outOfLastParcel:Boolean = false;
-
- private var arColumn:Array = [];
+ private var columns:Vector.<TableColElement> = new Vector.<TableColElement>();
+ private var rows:Vector.<TableRowElement> = new Vector.<TableRowElement>();
+ private var damagedColumns:Vector.<TableColElement> = new Vector.<TableColElement>();
+ private var damageRows:Vector.<TableRowElement> = new Vector.<TableRowElement>();
+ private var _hasCellDamage:Boolean = true;
+
+ private var _headerRowCount:uint = 0;
+ private var _footerRowCount:uint = 0;
+ private var _tableRowsComputed:Boolean;
+
+ private var _headerRows:Vector.< Vector.<TableCellElement> >;
+ private var _footerRows:Vector.< Vector.<TableCellElement> >;
+ private var _bodyRows:Vector.< Vector.<TableCellElement> >;
+ private var _composedRowIndex:uint = 0;
+
+ private var _tableBlocks:Vector.<TextFlowTableBlock>;
+ private var _tableBlockIndex:uint = 0;
+ private var _tableBlockDict:Dictionary;
+
+ private var _leaf:TableLeafElement;
public function TableElement()
{
super();
}
- public function initTableElement(row:Number, column:Number):void
- {
- _row = row;
- _column = column;
-
- for ( var i:int = 0; i < column; i ++ )
- {
- var col:TableColElement = new TableColElement();
- arColumn[i] = col;
- }
- }
-
/** @private */
override protected function get abstract():Boolean
{ return false; }
@@ -95,35 +89,714 @@ package flashx.textLayout.elements
/** @private */
tlf_internal override function canOwnFlowElement(elem:FlowElement):Boolean
{
- return (elem is TableBodyElement) || (elem is TableRowElement) || (elem is TableColElement) || (elem is TableColGroupElement);
+ return (elem is TableCellElement) || (elem is TableRowElement) || (elem is TableColElement);// || (elem is TableBodyElement) || (elem is TableColGroupElement);
}
/** @private if its in a numbered list expand the damage to all list items - causes the numbers to be regenerated */
tlf_internal override function modelChanged(changeType:String, elem:FlowElement, changeStart:int, changeLen:int, needNormalize:Boolean = true, bumpGeneration:Boolean = true):void
{
+ if (changeType==ModelChange.ELEMENT_ADDED) {
+
+ }
+ else if (changeType==ModelChange.ELEMENT_REMOVAL) {
+ if (headerRowCount > 0 || footerRowCount > 0) {
+
+ }
+ }
+
super.modelChanged(changeType,elem,changeStart,changeLen,needNormalize,bumpGeneration);
}
- public function get row():int
+ override public function set cellSpacing(cellSpacingValue:*):void
+ {
+
+ markCellsDamaged();
+ hasCellDamage = true;
+ normalizeCells();
+
+ super.cellSpacing = cellSpacingValue;
+ }
+
+ public function get numRows():int
+ {
+ return rows.length;
+ }
+
+ public function get numColumns():int
+ {
+ return columns.length;
+ }
+
+ /**
+ * Total number of cells
+ **/
+ public function get numCells():int
{
- return _row;
+ return getCells().length;
}
- public function get column():int
+ /**
+ * Total number of rows in the table. If set to a value lower than
+ * the current number of rows the rows at the end of the table are removed.
+ * If the set to a value greater than the current number of rows additional
+ * rows are added to the table.
+ **/
+ public function set numRows(value:int):void
{
- return _column;
+ while(value < numRows){
+ rows.pop();
+ }
+ var num:int = numRows;
+ for(var i:int = num;i<value;i++) {
+ var row:TableRowElement = createRowElement(i, defaultRowFormat);
+ rows.push(row);
+ }
}
+ /**
+ * Total number of columns in the table. If set to a value lower than
+ * the current number of columns the columns at the end of the table are removed.
+ * If the set to a value greater than the current number of columns additional
+ * columns are added to the table.
+ **/
+ public function set numColumns(value:int):void
+ {
+ while(value < numColumns){
+ columns.pop();
+ }
+ var num:int = numColumns;
+ for(var i:int = num;i<value;i++) {
+ var column:TableColElement = createColumnElement(i, defaultColumnFormat);
+ columns.push(column);
+ }
+ }
+ private var _defaultRowFormat:ITextLayoutFormat;
+
+ /**
+ * Gets the row format for new rows.
+ **/
+ public function get defaultRowFormat():ITextLayoutFormat
+ {
+ if(!_defaultRowFormat)
+ _defaultRowFormat = new TextLayoutFormat(computedFormat);
+ return _defaultRowFormat;
+ }
+
+ public function set defaultRowFormat(value:ITextLayoutFormat):void
+ {
+ _defaultRowFormat = value;
+ }
+
+ private var _defaultColumnFormat:ITextLayoutFormat;
+
+ /**
+ * Gets the column format for new columns.
+ **/
+ public function get defaultColumnFormat():ITextLayoutFormat
+ {
+ if(!_defaultColumnFormat)
+ _defaultColumnFormat = new TextLayoutFormat(computedFormat);
+ return _defaultColumnFormat;
+ }
+
+ public function set defaultColumnFormat(value:ITextLayoutFormat):void
+ {
+ _defaultColumnFormat = value;
+ }
+
+ /**
+ * Adds a table cell element to the table.
+ * @inheritDoc
+ **/
+ override public function addChild(child:FlowElement):FlowElement
+ {
+
+ if (child is TableFormattedElement) {
+ TableFormattedElement(child).table = this;
+ }
+
+ super.addChild(child);
+
+ return child;
+ }
+
+ /**
+ * Removes a table cell element from the table.
+ * @inheritDoc
+ **/
+ override public function removeChild(child:FlowElement):FlowElement
+ {
+ super.removeChild(child);
+
+ if (child is TableFormattedElement) {
+ TableFormattedElement(child).table = null;
+ }
+
+ return child;
+ }
+
+ /**
+ * Add a row at the end of the table. You would use this if you want to add a row
+ * without changing the table cells.
+ * @see addRowAt
+ * @see insertRow
+ * @see insertRowAt
+ **/
+ public function addRow(format:ITextLayoutFormat=null):void{
+ addRowAt(rows.length,format);
+ }
+
+ /**
+ * Add a row at the index specified.
+ * @see addRow
+ * @see insertRow
+ * @see insertRowAt
+ **/
+ public function addRowAt(idx:int, format:ITextLayoutFormat=null):void{
+ if(idx < 0 || idx > rows.length)
+ throw RangeError(GlobalSettings.resourceStringFunction("badPropertyValue"));
+
+ var row:TableRowElement = createRowElement(idx, format);
+ rows.splice(idx, 0, row);
+ row.composedHeight = row.computedFormat.minCellHeight;
+ row.isMaxHeight = row.computedFormat.minCellHeight == row.computedFormat.maxCellHeight;
+ row.setParentAndRelativeStartOnly(this, 1);
+ }
+
+ /**
+ * Adds a column. You would use this if you want to add a column without changing the table cells.
+ * The cells would reflow, so a cell in row 2 might move up to row 1.
+ * @see addColumnAt
+ * @see insertColumn
+ * @see insertColumnAt
+ **/
+ public function addColumn(format:ITextLayoutFormat=null):void{
+ addColumnAt(columns.length,format);
+ }
+
+ /**
+ * Adds a column at the index specified.
+ * @see addColumn
+ * @see insertColumn
+ * @see insertColumnAt
+ **/
+ public function addColumnAt(idx:int, format:ITextLayoutFormat=null):void{
+ if(idx < 0 || idx > columns.length)
+ throw RangeError(GlobalSettings.resourceStringFunction("badPropertyValue"));
+ if(!format) {
+ format = defaultColumnFormat;
+ }
+ var column:TableColElement = createColumnElement(idx, format);
+
+ columns.splice(idx, 0, column);
+ }
+
+ /**
+ * Returns the column at the index specified or null if the index is out of range.
+ **/
public function getColumnAt(columnIndex:int):TableColElement
{
- if ( columnIndex < 0 || columnIndex >= _column )
+ if ( columnIndex < 0 || columnIndex >= numColumns )
+ return null;
+ return columns[columnIndex];
+ }
+
+ /**
+ * Returns the row at the index specified or null if the index is out of range.
+ **/
+ public function getRowAt(rowIndex:int):TableRowElement
+ {
+ if ( rowIndex < 0 || rowIndex >= numRows )
+ return null;
+ return rows[rowIndex];
+ }
+
+ /**
+ * Return the index of the row provided or -1 if the row is not found.
+ **/
+ public function getRowIndex(row:TableRowElement):int
+ {
+ for(var i:int=0;i<rows.length;i++)
+ {
+ if(rows[i] == row)
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns a vector of the cells for the row specified.
+ **/
+ public function getCellsForRow(row:TableRowElement):Vector.<TableCellElement>{
+
+ return getCellsForRowAt(row.rowIndex);
+ }
+
+ /**
+ * Returns a vector of the cells for the row specified.
+ **/
+ public function getCellsForRowArray(row:TableRowElement):Array {
+
+ return getCellsForRowAtArray(row.rowIndex);
+ }
+
+ /**
+ * Returns a vector of the cells for the row at the specified index.
+ **/
+ public function getCellsForRowAt(index:int):Vector.<TableCellElement>{
+ var cells:Vector.<TableCellElement> = new Vector.<TableCellElement>();
+
+ if (index < 0) {
+ return cells;
+ }
+
+ for each(var cell:TableCellElement in mxmlChildren){
+ if (cell.rowIndex == index) {
+ cells.push(cell);
+ }
+ }
+
+ return cells;
+ }
+
+ /**
+ * Returns an array of the cells for the row specified.
+ **/
+ public function getCellsForRowAtArray(index:int):Array {
+ var cells:Array = [];
+
+ if (index < 0) {
+ return cells;
+ }
+
+ for each(var cell:TableCellElement in mxmlChildren){
+ if (cell.rowIndex == index) {
+ cells.push(cell);
+ }
+ }
+
+ return cells;
+ }
+
+ /**
+ * Returns a Vector of the TableCellElements for the column specified.
+ **/
+ public function getCellsForColumn(column:TableColElement):Vector.<TableCellElement> {
+ if(columns.indexOf(column) < 0)
+ return null;
+
+ return getCellsForColumnAt(column.colIndex);
+ }
+
+ /**
+ * Returns a Vector of the TableCellElements for the column at the specified index.
+ **/
+ public function getCellsForColumnAt(index:int):Vector.<TableCellElement> {
+ var cells:Vector.<TableCellElement> = new Vector.<TableCellElement>();
+
+ if (index < 0) {
+ return cells;
+ }
+
+ for each(var cell:TableCellElement in mxmlChildren){
+ if (cell.colIndex == index) {
+ cells.push(cell);
+ }
+ }
+
+ return cells;
+ }
+
+ /**
+ * Inserts a column at the end of the table. If a column is not provided one is created.
+ *
+ * @see addColumn
+ * @see addColumnAt
+ * @see insertColumnAt
+ **/
+ public function insertColumn(column:TableColElement=null,cells:Array = null):Boolean{
+ return insertColumnAt(numColumns,column,cells);
+ }
+
+ /**
+ * Inserts a column at the column specified. If the column is not provided it
+ * creates a new column containing the cells supplied or creates the cells
+ * based on the number of rows in the table.
+ * @see addColumn
+ * @see addColumnAt
+ * @see insertColumn
+ **/
+ public function insertColumnAt(idx:int,column:TableColElement=null,cells:Array = null):Boolean{
+
+ if (idx < 0 || idx > columns.length) {
+ throw RangeError(GlobalSettings.resourceStringFunction("badPropertyValue"));
+ }
+
+ if (!column) {
+ column = createColumnElement(idx, defaultColumnFormat);
+ }
+
+ columns.splice(idx,0,column);
+
+ var blockedCoords:Vector.<CellCoords> = getBlockedCoords(-1,idx);
+ var cellIdx:int = getCellIndex(0,idx);
+ if(cellIdx < 0)
+ cellIdx = numChildren;
+ var rowIdx:int = 0;
+
+ if (cells==null) cells = [];
+
+ while(cells.length < numRows){
+ cells.push(new TableCellElement());
+ }
+
+ for each(var cell:TableCellElement in cells){
+ while(blockedCoords.length && blockedCoords[0].row == rowIdx){
+ rowIdx++;
+ blockedCoords.shift();
+ }
+ cellIdx = getCellIndex(rowIdx,idx);
+ if(cellIdx < 0)
+ cellIdx = numChildren;
+
+ if(rowIdx < numRows){
+ addChildAt(cellIdx,cell);
+ }
+ }
+
+
+ return true;
+ }
+
+ /**
+ * Inserts a row at the end of the table. If a row is not provided one is created.
+ * @see insertRowAt
+ **/
+ public function insertRow(row:TableRowElement=null,cells:Array = null):Boolean{
+ return insertRowAt(numRows,row,cells);
+ }
+
+ /**
+ * Inserts a row at the index specified. If the row is not provided it
+ * creates a new row containing the cells supplied or creates the cells
+ * based on the number of columns in the table.
+ **/
+ public function insertRowAt(idx:int,row:TableRowElement=null,cells:Array = null):Boolean{
+ if (idx < 0 || idx > rows.length) {
+ throw RangeError(GlobalSettings.resourceStringFunction("badPropertyValue"));
+ }
+
+ if (!row) {
+ row = createRowElement(idx, defaultRowFormat);
+ }
+
+ rows.splice(idx,0,row);
+ row.composedHeight = row.computedFormat.minCellHeight;
+ row.isMaxHeight = row.computedFormat.minCellHeight == row.computedFormat.maxCellHeight;
+
+ var blockedCoords:Vector.<CellCoords> = getBlockedCoords(idx);
+ var cellIdx:int = getCellIndex(idx,0);
+ if(cellIdx < 0)
+ cellIdx = numChildren;
+
+ var colIdx:int = 0;
+
+ if (cells==null) cells = [];
+
+ // create more cells
+ while(cells.length < numColumns){
+ cells.push(new TableCellElement());
+ }
+
+ for each(var cell:TableCellElement in cells){
+ while(blockedCoords.length && blockedCoords[0].column == colIdx){
+ colIdx++;
+ blockedCoords.shift();
+ }
+ if(colIdx < numColumns){
+ addChildAt(cellIdx++,cell);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Removes the row
+ **/
+ public function removeRow(row:TableRowElement):TableRowElement {
+ var i:int = rows.indexOf(row);
+ if(i < 0)
+ return null;
+ return removeRowAt(i);
+ }
+
+ /**
+ * Removes the row and the cells it contains.
+ **/
+ public function removeRowWithContent(row:TableRowElement):Array
+ {
+ var i:int = rows.indexOf(row);
+ if(i < 0)
return null;
- return arColumn[columnIndex];
+ return removeRowWithContentAt(i);
+ }
+
+ /**
+ * Removes the row at the index specified.
+ * @see removeRowWithContentAt
+ **/
+ public function removeRowAt(idx:int):TableRowElement {
+ if(idx < 0 || idx > rows.length - 1)
+ return null;
+
+ var row:TableRowElement = TableRowElement(rows.splice(idx,1)[0]);
+ normalizeCells();
+ hasCellDamage = true;
+ return row;
+
+ }
+
+ /**
+ * Removes the row at the index specified and the cells it contains.
+ **/
+ public function removeRowWithContentAt(idx:int):Array
+ {
+
+ var removedCells:Array = [];
+
+ if(mxmlChildren){
+ for (var i:int = mxmlChildren.length-1;i>=0;i--){
+ var child:* = mxmlChildren[i];
+ if(!(child is TableCellElement))
+ continue;
+ var cell:TableCellElement = child as TableCellElement;
+ if(cell.rowIndex == idx){
+ removedCells.unshift(removeChild(cell));
+ }
+ }
+ }
+
+ removeRowAt(idx);
+ return removedCells;
+ }
+
+ /**
+ * Removes all the rows and the cells.
+ **/
+ public function removeAllRowsWithContent():void
+ {
+ var rowCount:int;
+ var cellCount:int;
+
+ if (numRows>-1) {
+ rowCount = numRows-1;
+
+ for (;rowCount>-1;) {
+ removeRowWithContentAt(rowCount--);
+ }
+
+ }
+ }
+
+ /**
+ * Removes all the rows. Does not remove the cells.
+ * @see removeAllRowsWithContent
+ **/
+ public function removeAllRows():void
+ {
+ var rowCount:int;
+ var cellCount:int;
+
+ if (numRows>-1) {
+ rowCount = numRows;
+
+ for (var i:int; i < rowCount; i++) {
+ removeRowAt(i);
+ }
+
+ }
+ }
+
+ /**
+ * Removes the column
+ **/
+ public function removeColumn(column:TableColElement):TableColElement {
+ var i:int = columns.indexOf(column);
+ if(i < 0)
+ return null;
+ return removeColumnAt(i);
+ }
+
+ /**
+ * Removes the column and the cells it contains.
+ **/
+ public function removeColumnWithContent(column:TableColElement):Array
+ {
+ var i:int = columns.indexOf(column);
+ if(i < 0)
+ return null;
+ return removeColumnWithContentAt(i);
+ }
+
+ /**
+ * Removes the column at the index specified
+ **/
+ public function removeColumnAt(idx:int):TableColElement {
+ if(idx < 0 || idx > columns.length - 1)
+ return null;
+
+ var col:TableColElement = columns.splice(idx,1)[0];
+ normalizeCells();
+ hasCellDamage = true;
+ return col;
+ }
+
+ /**
+ * Removes the column at the index specified and the cells it contains.
+ **/
+ public function removeColumnWithContentAt(idx:int):Array
+ {
+
+ var removedCells:Array = [];
+ if(mxmlChildren){
+ for (var i:int = mxmlChildren.length-1;i>=0;i--){
+ var child:* = mxmlChildren[i];
+ if(!(child is TableCellElement))
+ continue;
+ var cell:TableCellElement = child as TableCellElement;
+ if(cell.colIndex == idx){
+ removedCells.unshift(removeChild(cell));
+ }
+ }
+ }
+ removeColumnAt(idx);
+
+ return removedCells;
+ }
+
+ /**
+ * Remove all cells
+ * @inheritDoc
+ **/
+ override tlf_internal function removed():void
+ {
+ hasCellDamage = true;
+ //removeAllRowsWithContent();
+ }
+
+ /**
+ * @private
+ * Gets table coordinates which represents the space occupied by cells spanning rows or columns
+ **/
+ private function getBlockedCoords(inRow:int = -1, inColumn:int = -1):Vector.<CellCoords>{
+ var coords:Vector.<CellCoords> = new Vector.<CellCoords>();
+
+ if(mxmlChildren) {
+ for each(var child:* in mxmlChildren){
+ var cell:TableCellElement = child as TableCellElement;
+ if (cell==null) continue;
+ if(cell.columnSpan == 1 && cell.rowSpan == 1)
+ continue;
+ var curRow:int = cell.rowIndex;
+ if(inRow >= 0 && curRow != inRow)
+ continue;
+ if(inColumn >= 0 && inColumn != curColumn)
+ continue;
+ var curColumn:int = cell.colIndex;
+ var endRow:int = curRow + cell.rowSpan - 1;
+ var endColumn:int = curColumn + cell.columnSpan -1;
+ for(var rowIdx:int = curRow;rowIdx <= endRow;rowIdx++){
+ for(var colIdx:int = curColumn;colIdx <=endColumn;colIdx++){
+ if(rowIdx == curRow && colIdx == curColumn){
+ continue;
+ }
+ coords.push( new CellCoords(colIdx, rowIdx) );
+ }
+ }
+
+ }
+ }
+ return coords;
}
+ /**
+ * Sets the row and column indices of the cells in the table to match their logical position as described by the table columns and rows
+ **/
+ public function normalizeCells():void
+ {
+ this.numColumns;this.numRows;
+ var i:int;
+ var blockedCoords:Vector.<CellCoords> = new Vector.<CellCoords>();
+
+ if (!mxmlChildren) {
+ return;
+ }
+
+ var curRow:int = 0;
+ var curColumn:int = 0;
+
+ for each(var child:* in mxmlChildren) {
+
+ if (!(child is TableCellElement)) {
+ continue;
+ }
+
+ var cell:TableCellElement = child as TableCellElement;
+
+ if (cell.rowIndex != curRow || cell.colIndex != curColumn) {
+ cell.rowIndex = curRow;
+ cell.colIndex = curColumn;
+ cell.damage();
+ }
+
+ // add blocked coords if the cell spans rows or columns
+ var endRow:int = curRow + cell.rowSpan - 1;
+ var endColumn:int = curColumn + cell.columnSpan -1;
+
+ for(var rowIdx:int = curRow;rowIdx <= endRow;rowIdx++){
+ for(var colIdx:int = curColumn;colIdx <=endColumn;colIdx++){
+ if(rowIdx == curRow && colIdx == curColumn){
+ continue;
+ }
+ blockedCoords.push(new CellCoords(colIdx,rowIdx) );
+ }
+ }
+
+ // advance coordinates while checking blocked ones from spans
+ do {
+ curColumn++;
+
+ if (curColumn >= numColumns){
+ curColumn = 0;
+ curRow++;
+ }
+
+ var advanced:Boolean = true;
+
+ for (i=0;i<blockedCoords.length;i++){
+ if(blockedCoords[i].column == curColumn && blockedCoords[i].row == curRow){
+ advanced = false;
+ blockedCoords.splice(i,1);
+ }
+ }
+
+ if (advanced) {
+ break;
+ }
+
+ } while(1);
+
+ }
+
+ }
+
+ /**
+ * Set the width of the specified column. The value can be a number or percent.
+ **/
public function setColumnWidth(columnIndex:int, value:*):Boolean
{
- var tableColElement:TableColElement = getColumnAt(columnIndex) as TableColElement;
+ //TODO: changing the column width probably requires a recompose of all cells in that column. Mark the cells in that row damaged.
+ var tableColElement:TableColElement = getColumnAt(columnIndex);
if ( ! tableColElement )
return false;
@@ -131,6 +804,22 @@ package flashx.textLayout.elements
return true;
}
+ /**
+ * Set the height of the specified row. The value can be a number or percent.
+ **/
+ public function setRowHeight(rowIdx:int, value:*):Boolean{
+ //TODO: setting the row height might change the composition height of the cells. We'll need to do some housekeeping here.
+ // I'm not sure this function makes sense. We need to handle both min and max values to allow for expanding cells.
+ var row:TableRowElement = getRowAt(rowIdx);
+ if(!row)
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Get the width of the column.
+ **/
public function getColumnWidth(columnIndex:int):*
{
var tableColElement:TableColElement = getColumnAt(columnIndex) as TableColElement;
@@ -138,26 +827,712 @@ package flashx.textLayout.elements
return tableColElement.tableColumnWidth;
return 0;
}
-
- public function get height():Number
- {
- return _height[numAcrossParcels];
- }
-
- public function set height(val:*):void
- {
- _height[numAcrossParcels] = val;
- }
-
- public function get heightArray():Array
- {
- return _height;
- }
-
- public function set heightArray(newArray:Array):void
- {
- _height = newArray;
- }
+ /**
+ * Sizes and positions the cells in the table.
+ **/
+ public function composeCells():void{
+ normalizeCells();
+ _composedRowIndex = 0;
+
+ // make sure the height that defines the row height did not change. If it did we might need to change the row height.
+ if(!hasCellDamage)
+ return;
+ var damagedCells:Vector.<TableCellElement> = getDamagedCells();
+ var cell:TableCellElement;
+
+ for each(cell in damagedCells){
+ // recompose the cells while tracking row height if necessary
+ cell.compose();
+ }
+
+ // set row heights to minimum
+ for each (var row:TableRowElement in rows){
+ var minH:Number = row.computedFormat.minCellHeight;
+ var maxH:Number = row.computedFormat.maxCellHeight;
+ row.totalHeight = row.composedHeight = minH;
+ if(maxH > minH)
+ row.isMaxHeight = false;
+ else
+ row.isMaxHeight = true;
+
+ }
+
+ // set column positions...
+ var xPos:Number = 0;
+ for each (var col:TableColElement in columns){
+ col.x = xPos;
+ xPos += col.columnWidth;
+ }
+
+ if (mxmlChildren) {
+ for(var i:int=0;i<mxmlChildren.length;i++){
+ if( !(mxmlChildren[i] is TableCellElement) )
+ continue;
+ cell = mxmlChildren[i] as TableCellElement;
+ while(rows.length < cell.rowIndex+1){
+ addRow(defaultRowFormat);
+ }
+ row = getRowAt(cell.rowIndex);
+ if(!row)
+ throw new Error("this should not happen...");
+ if(row.isMaxHeight) {
+ continue;
+ }
+
+ var cellHeight:Number = cell.getComposedHeight();
+ if(cell.rowSpan > 1)
+ {
+ // figure out the total height taking into account fixed height rows and the total span.
+
+ // for now, we're taking the easy way out assuming the rows are not fixed...
+ row.totalHeight = Math.max(row.totalHeight, cellHeight);
+
+ }
+ else
+ {
+ row.composedHeight = Math.max(row.composedHeight, cellHeight);
+ row.composedHeight = Math.min(row.composedHeight, row.computedFormat.maxCellHeight);
+ row.totalHeight = Math.max(row.composedHeight, row.totalHeight);
+ }
+ if(row.composedHeight == row.computedFormat.maxCellHeight)
+ row.isMaxHeight = true;
+ }
+ }
+
+
+ if(!_tableRowsComputed)
+ {
+ // create arrays or rows to make table composition simpler
+ // For now we're assuming all cells have the correct row and column indices.
+ // For this assumption to remain valid, the interaction manager will have to update all indices when inserting rows and columns.
+ // actually, it probably makes sense for TableElement to handle that when adding rows and columns.
+ // we need to think this through.
+ _bodyRows = new Vector.< Vector.<TableCellElement> >();
+
+ if (mxmlChildren) {
+ for(i=0;i<mxmlChildren.length;i++){
+
+ if ( !(mxmlChildren[i] is TableCellElement) ) {
+ continue;
+ }
+
+ cell = mxmlChildren[i] as TableCellElement;
+
+ while(cell.rowIndex >= _bodyRows.length)
+ _bodyRows.push(new Vector.<TableCellElement>());
+
+ var rowVec:Vector.<TableCellElement> = _bodyRows[cell.rowIndex] as Vector.<TableCellElement>;
+
+ if(!rowVec){
+ rowVec = new Vector.<TableCellElement>();
+ _bodyRows[cell.rowIndex] = rowVec;
+ }
+
+ if(rowVec.length > cell.colIndex && rowVec[cell.colIndex]) {
+ throw new Error("Two cells cannot have the same coordinates");
+ }
+
+ rowVec.push(cell);
+ }
+ }
+
+ if(headerRowCount > 0){
+ _headerRows = _bodyRows.splice(0,headerRowCount);
+ } else {
+ _headerRows = null;
+ }
+
+ if(footerRowCount > 0){
+ _footerRows = _bodyRows.splice(-footerRowCount,Number.MAX_VALUE);
+ } else {
+ _footerRows = null;
+ }
+ }
+ }
+
+ /**
+ * returns the header rows for composition
+ **/
+ public function getHeaderRows():Vector.< Vector.<TableCellElement> >{
+ return _headerRows;
+ }
+
+ /**
+ * returns the footer rows for composition
+ **/
+ public function getFooterRows():Vector.< Vector.<TableCellElement> >{
+ return _footerRows;
+ }
+
+ /**
+ * returns the body rows (sans header and footer cells) for composition
+ **/
+ public function getBodyRows():Vector.< Vector.<TableCellElement> >{
+ return _bodyRows;
+ }
+
+ /**
+ * returns a vector of table cells in the next row during composition
+ **/
+ public function getNextRow():Vector.<TableCellElement>{
+ if(_composedRowIndex >= _bodyRows.length)
+ return null;
+ return _bodyRows[_composedRowIndex++];
+ }
+
+ /**
+ * Returns the next table cell after the supplied table cell
+ **/
+ public function getNextCell(tableCell:TableCellElement):TableCellElement {
+ var cell:TableCellElement;
+
+ for each (var element:FlowElement in mxmlChildren) {
+ cell = element as TableCellElement;
+
+ if (cell) {
+
+ // get next cell in same row
+ if (cell.rowIndex==tableCell.rowIndex && cell.colIndex-1==tableCell.colIndex) {
+ return cell;
+ }
+
+ // get first cell in next row
+ if (cell.rowIndex-1==tableCell.rowIndex && cell.colIndex==0) {
+ return cell;
+ }
+
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the previous table cell after the supplied table cell
+ **/
+ public function getPreviousCell(tableCell:TableCellElement):TableCellElement {
+ var cell:TableCellElement;
+ var highestCellIndex:int = -1;
+ var rowIndex:int = -1;
+
+ for each (var element:FlowElement in mxmlChildren) {
+ cell = element as TableCellElement;
+
+ if (cell) {
+
+ // get previous cell in same row
+ if (cell.rowIndex==tableCell.rowIndex && cell.colIndex+1==tableCell.colIndex) {
+ return cell;
+ }
+
+ // get last cell in previous row
+ if (cell.rowIndex+1==tableCell.rowIndex) {
+ rowIndex = cell.rowIndex;
+
+ if (highestCellIndex<cell.colIndex) {
+ highestCellIndex = cell.colIndex;
+ }
+ }
+
+ }
+ }
+
+ if (rowIndex>-1 && highestCellIndex>-1) {
+ return getCellAt(rowIndex, highestCellIndex);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the table cell at the row and column specified.
+ **/
+ public function getCellAt(rowIndex:int, columnIndex:int):TableCellElement {
+ var cell:TableCellElement;
+
+ for each (var element:FlowElement in mxmlChildren) {
+ cell = element as TableCellElement;
+
+ if (cell && cell.rowIndex==rowIndex && cell.colIndex==columnIndex) {
+ return cell;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Computed height of the header cells
+ **/
+ public function getHeaderHeight():Number{
+ //TODO: compute the header height from the header cells
+ return 0;
+ }
+
+ /**
+ * Computed height of the footer cells
+ **/
+ public function getFooterHeight():Number{
+ //TODO: compute the footer height from the footer cells
+ return 0;
+
+ }
+
+ /**
+ * Accepts a suggested table width and calculates the column widths.
+ **/
+ public function normalizeColumnWidths(suggestedWidth:Number = 600):void{
+ //TODO: before composition make sure all column widths are rational numbers
+ // We feed in a width to use if there's no width otherwise specified.
+
+ // quick and dirty...
+ var setCount:* = computedFormat.columnCount;
+ if(!setCount){
+ // we need to figure this out...
+ } else if(setCount == FormatValue.AUTO){
+ // figure out...
+ } else {
+ var cCount:Number = computedFormat.columnCount;
+ }
+
+ while (cCount > columns.length){
+ addColumn();
+ }
+
+ var w:Number;
+ switch(typeof(computedFormat.tableWidth)){
+ case "number":
+ w = suggestedWidth;
+ break;
+ case "string":
+ if(computedFormat.tableWidth.indexOf("%") > 0){
+ w = suggestedWidth / (parseFloat(computedFormat.tableWidth)/100);
+ break;
+ }
+ default:
+ w = suggestedWidth;
+ break;
+ }
+ if(isNaN(w))
+ w = 600;
+ if(w > 20000)
+ w = 600;
+
+ _computedWidth = w;
+
+ var numNonsetColumns:int = numColumns;
+ var col:TableColElement;
+ for each(col in columns){
+ // simply stomp on the settings. (need to finesse this...)
+ if(typeof(col.columnWidth) == "number")
+ {
+ w-= col.columnWidth;
+ numNonsetColumns--;
+ }
+ }
+
+ for each(col in columns)
+ {
+ // simply stomp on the settings. (need to finesse this...)
+ if(typeof(col.columnWidth) == "number")
+ continue;
+ col.columnWidth = w / numNonsetColumns;
+ }
+ }
+
+ /**
+ * Returns a vector of all the damaged cells in the table.
+ **/
+ private function getDamagedCells():Vector.<TableCellElement>{
+ var cells:Vector.<TableCellElement> = new Vector.<TableCellElement>();
+ for each (var cell:* in this.mxmlChildren){
+ if((cell is TableCellElement) && cell.isDamaged())
+ cells.push(cell as TableCellElement);
+ }
+ return cells;
+ }
+
+ /**
+ * Marks all of the cells in the table as damaged.
+ **/
+ private function markCellsDamaged():void {
+ if (!mxmlChildren) return;
+
+ for each (var cell:* in this.mxmlChildren){
+ if (cell is TableCellElement) {
+ cell.damage();
+ }
+ }
+ }
+
+ /**
+ * Returns a vector of all the table cell elements in the table.
+ **/
+ public function getCells():Vector.<TableCellElement> {
+ var cells:Vector.<TableCellElement> = new Vector.<TableCellElement>();
+
+ for each (var cell:* in mxmlChildren){
+ if (cell is TableCellElement) {
+ cells.push(cell as TableCellElement);
+ }
+ }
+
+ return cells;
+ }
+
+ /**
+ * Returns an array of all the table cells.
+ **/
+ public function getCellsArray():Array {
+ var cells:Array = [];
+
+ for each (var cell:* in mxmlChildren){
+ if (cell is TableCellElement) {
+ cells.push(cell as TableCellElement);
+ }
+ }
+
+ return cells;
+ }
+
+ /**
+ * Returns the table width
+ **/
+ public function get width():Number
+ {
+ return _computedWidth;
+ }
+
+ /**
+ * Sets the table width
+ **/
+ public function set width(value:*):void
+ {
+ normalizeColumnWidths(value);
+ }
+
+
+ /**
+ * Indicates elements in the table have been modified and the table must be recomposed.
+ **/
+ public function get hasCellDamage():Boolean
+ {
+ return _hasCellDamage;
+ }
+
+ public function set hasCellDamage(value:Boolean):void
+ {
+ _hasCellDamage = value;
+ }
+
+ /**
+ * Returns the number of header rows in the table
+ **/
+ public function get headerRowCount():uint
+ {
+ return _headerRowCount;
+ }
+
+ /**
+ * Sets the number of header rows in the table
+ **/
+ public function set headerRowCount(value:uint):void
+ {
+ if(value != _headerRowCount)
+ _tableRowsComputed = false;
+ _headerRowCount = value;
+ }
+
+ /**
+ * Returns the number of footer rows in the table
+ **/
+ public function get footerRowCount():uint
+ {
+ return _footerRowCount;
+ }
+
+ /**
+ * Sets the number of footer rows in the table
+ **/
+ public function set footerRowCount(value:uint):void
+ {
+ if(value != _footerRowCount)
+ _tableRowsComputed = false;
+ _footerRowCount = value;
+ }
+
+ /**
+ * Gets the first TextFlowTableBlock in the table.
+ **/
+ public function getFirstBlock():TextFlowTableBlock{
+ if(_tableBlocks == null)
+ _tableBlocks = new Vector.<TextFlowTableBlock>();
+ if(_tableBlocks.length == 0)
+ _tableBlocks.push(new TextFlowTableBlock(0));
+ _tableBlockIndex = 0;
+ _tableBlocks[0].parentTable = this;
+
+ return _tableBlocks[0];
+ }
+
+ /**
+ * Gets the next TextFlowTableBlock.
+ **/
+ public function getNextBlock():TextFlowTableBlock{
+ if(_tableBlocks == null)
+ _tableBlocks = new Vector.<TextFlowTableBlock>();
+ _tableBlockIndex++;
+ while(_tableBlocks.length <= _tableBlockIndex){
+ _tableBlocks.push( new TextFlowTableBlock(_tableBlocks.length) );
+ }
+ _tableBlocks[_tableBlockIndex].parentTable = this;
+
+ return _tableBlocks[_tableBlockIndex];
+ }
+
+ /**
+ * Gets the total atom length of this flow element in the text flow.
+ *
+ * @inheritDoc
+ **/
+ override public function get textLength():int{
+ return 1;
+ }
+
+ /**
+ * Returns the cell at the specified row and column.
+ **/
+ private function getCellIndex(rowIdx:int,columnIdx:int):int{
+ if(rowIdx == 0 && columnIdx == 0)
+ return 0;
+ for (var i:int=0;i<mxmlChildren.length;i++){
+ var item:* = mxmlChildren[i];
+ if(!(item is TableCellElement))
+ continue;
+ var cell:TableCellElement = item as TableCellElement;
+ if(cell.rowIndex == rowIdx && cell.colIndex == columnIdx)
+ return i;
+ }
+ return -1;
+
+ }
+
+ /**
+ * Returns a vector of table cell elements in the given cell range.
+ **/
+ public function getCellsInRange(anchorCoords:CellCoordinates, activeCoords:CellCoordinates, block:TextFlowTableBlock=null):Vector.<TableCellElement>
+ {
+ var firstCoords:CellCoordinates = anchorCoords.clone();
+ var lastCoords:CellCoordinates = activeCoords.clone();
+ if(
+ lastCoords.row < firstCoords.row ||
+ (lastCoords.row == firstCoords.row && lastCoords.column < firstCoords.column)
+ )
+ {
+ firstCoords = activeCoords.clone();
+ lastCoords = anchorCoords.clone();
+ }
+
+ // make sure the rectangle is not inversed
+ if(lastCoords.column < firstCoords.column)
+ {
+ var col:int = firstCoords.column;
+ firstCoords.column = lastCoords.column;
+ lastCoords.column = col;
+ }
+ var firstCell:TableCellElement = findCell(firstCoords);
+ var cells:Vector.<TableCellElement> = new Vector.<TableCellElement>();
+ if(!block || getCellBlock(firstCell) == block)
+ cells.push(firstCell);
+ var idx:int = mxmlChildren.indexOf(firstCell);
+ while(++idx < mxmlChildren.length)
+ {
+ var nextCell:TableCellElement = mxmlChildren[idx];
+ if(nextCell.rowIndex > lastCoords.row || (nextCell.rowIndex == lastCoords.row && nextCell.colIndex > lastCoords.column))
+ break;
+ // skip cells outside rectangle
+ if(nextCell.colIndex > lastCoords.column || nextCell.colIndex < firstCoords.column)
+ continue;
+ if(!block || getCellBlock(nextCell) == block)
+ cells.push(nextCell);
+ }
+ return cells;
+ }
+
+ /**
+ * Finds the cell at the specified cell coordinates or null if no cell is found.
+ **/
+ public function findCell(coords:CellCoordinates):TableCellElement
+ {
+ // get a guess of the cell location. If there's no holes (such as spans), it should theoretically pinpoint the index.
+ var idx:int = (coords.row+1) * (coords.column+1) -1;
+ if(idx >= numChildren)
+ idx = numChildren-1;
+
+ var cell:TableCellElement = mxmlChildren[idx];
+ // look ahead to see if we're short (not sure if this is needed).
+ do
+ {
+ if(idx == numChildren-1)
+ break;
+ var nextCell:TableCellElement = mxmlChildren[idx+1];
+ if(nextCell.rowIndex > coords.row || (nextCell.rowIndex == coords.row && nextCell.colIndex > coords.column))
+ break;
+
+ cell = nextCell;
+ idx++;
+
+ }while(true);
+ // look behind accounting for spans
+ do
+ {
+ //check if the coords fall within the row and column span
+ if(
+ cell.colIndex <= coords.column && cell.colIndex + cell.columnSpan - 1 >= coords.column &&
+ cell.rowIndex <= coords.row && cell.rowIndex + cell.rowSpan - 1 >= coords.row
+ )
+ break;
+ //oops we hit the first cell without finding anything. At least return that...
+ if(cell.colIndex == 0 && cell.rowIndex == 0)
+ break;
+ if(idx == 0)
+ break;
+ var prevCell:TableCellElement = mxmlChildren[idx-1];
+ cell = prevCell;
+ idx--;
+ }while(true);
+
+ return cell;
+ }
+
+ /**
+ * Adds the table cell container to the table block specified.
+ **/
+ public function addCellToBlock(cell:TableCellElement, block:TextFlowTableBlock):void
+ {
+ block.addCell(cell.container);
+ tableBlockDict[cell] = block;
+ }
+
+ /**
+ * Returns the table block for the given table cell.
+ **/
+ public function getCellBlock(cell:TableCellElement):TextFlowTableBlock
+ {
+ return tableBlockDict[cell];
+ }
+
+ /**
+ * Keeps a reference to all the table blocks belonging to this table.
+ **/
+ private function get tableBlockDict():Dictionary
+ {
+ if(_tableBlockDict == null)
+ _tableBlockDict = new Dictionary();
+ return _tableBlockDict;
+ }
+
+ /**
+ * Returns a vector of the table blocks.
+ **/
+ public function get tableBlocks():Vector.<TextFlowTableBlock>
+ {
+ return _tableBlocks;
+ }
+
+ public function getTableBlocksInRange(start:CellCoordinates,end:CellCoordinates):Vector.<TextFlowTableBlock>
+ {
+ var coords:CellCoordinates = start.clone();
+ if(end.column < start.column)
+ {
+ coords = end.clone();
+ end = start.clone();
+ }
+ var blocks:Vector.<TextFlowTableBlock> = new Vector.<TextFlowTableBlock>();
+ var block:TextFlowTableBlock = getCellBlock(findCell(coords));
+ if(block)
+ blocks.push(block);
+ while(block)
+ {
+ coords.row++;
+ if(coords.row > end.row)
+ break;
+ if(getCellBlock(findCell(coords)) == block)
+ continue;
+ block = getCellBlock(findCell(coords));
+ if(block)
+ blocks.push(block);
+ }
+ return blocks;
+ }
+
+ /** @private */
+ tlf_internal override function getNextLeafHelper(limitElement:FlowGroupElement,child:FlowElement):FlowLeafElement
+ {
+ return parent.getNextLeafHelper(limitElement,this);
+ }
+
+ /** @private */
+ tlf_internal override function getPreviousLeafHelper(limitElement:FlowGroupElement,child:FlowElement):FlowLeafElement
+ {
+ return parent.getPreviousLeafHelper(limitElement,this);
+ }
+
+ private function getLeaf():TableLeafElement
+ {
+ if(_leaf == null)
+ _leaf = new TableLeafElement(this);
+ return _leaf;
+ }
+
+ public override function findLeaf(relativePosition:int):FlowLeafElement
+ {
+ return getLeaf();
+ }
+ public override function getLastLeaf(): FlowLeafElement
+ {
+ return getLeaf();
+ }
+ public override function getFirstLeaf():FlowLeafElement
+ {
+ return getLeaf();
+ }
+
+ tlf_internal override function createContentElement():void{}
+ /** @private
+ * Release the FTE data structure that corresponds to the FlowElement, so it can be gc'ed
+ */
+ tlf_internal override function releaseContentElement():void{}
+
+ /**
+ * Creates and returns a default row
+ **/
+ tlf_internal function createRowElement(index:int, defaultRowFormat:ITextLayoutFormat):TableRowElement {
+ var row:TableRowElement = new TableRowElement(defaultRowFormat);
+ row.rowIndex = index;
+ row.table = this;
+ return row;
+ }
+
+ /**
+ * Creates and returns a default column
+ **/
+ tlf_internal function createColumnElement(index:int, defaultColumnFormat:ITextLayoutFormat):TableColElement {
+ var column:TableColElement = new TableColElement(defaultColumnFormat);
+ column.colIndex = index;
+ column.table = this;
+ return column;
+ }
+ }
+}
+class CellCoords
+{
+ public var column:int;
+ public var row:int;
+ public function CellCoords(colIdx:int,rowIdx:int)
+ {
+ column = colIdx;
+ row = rowIdx;
}
}
http://git-wip-us.apache.org/repos/asf/flex-tlf/blob/33df98ab/textLayout/src/flashx/textLayout/elements/TableFormattedElement.as
----------------------------------------------------------------------
diff --git a/textLayout/src/flashx/textLayout/elements/TableFormattedElement.as b/textLayout/src/flashx/textLayout/elements/TableFormattedElement.as
index 4b5bd0f..edad5e3 100644
--- a/textLayout/src/flashx/textLayout/elements/TableFormattedElement.as
+++ b/textLayout/src/flashx/textLayout/elements/TableFormattedElement.as
@@ -25,6 +25,9 @@ package flashx.textLayout.elements
super();
}
+ /**
+ * Get a reference to the table. We could refactor this since it's accessed multiple times.
+ **/
public function getTable():TableElement
{
// find the root element entry and either return null or the containing textFlow
@@ -32,6 +35,37 @@ package flashx.textLayout.elements
while ((elem.parent) != null && !( elem.parent is TableElement))
elem = elem.parent;
return elem.parent as TableElement;
- }
+ }
+
+
+ private var _table:TableElement;
+
+ /**
+ * Returns a reference to the table. For this to work we need to set the
+ * table to null when it's removed.
+ **/
+ public function get table():TableElement {
+
+ if (_table) return _table;
+
+ // find the root element entry and either return null or the containing textFlow
+ var elem:FlowGroupElement = this;
+
+ while ((elem.parent) != null && !(elem.parent is TableElement)) {
+ elem = elem.parent;
+ }
+
+ _table = elem.parent as TableElement;
+
+ return _table;
+ }
+
+ /**
+ * @private
+ **/
+ public function set table(element:TableElement):void {
+ _table = element;
+ }
}
-}
\ No newline at end of file
+}
+