blob: 312e648ea5eb58e677dd6d4e96853d7cae3c7ab3 [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
{
import flash.display.BlendMode;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.MouseEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.events.TimerEvent;
import flash.geom.Rectangle;
import flash.net.FileFilter;
import flash.net.FileReference;
import flash.net.FileReferenceList;
import flash.system.Capabilities;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.ui.ContextMenu;
import flash.utils.Timer;
import flashx.textLayout.TextLayoutVersion;
import flashx.textLayout.container.ContainerController;
import flashx.textLayout.conversion.ConversionType;
import flashx.textLayout.conversion.ITextImporter;
import flashx.textLayout.conversion.TextConverter;
import flashx.textLayout.debug.Debugging;
import flashx.textLayout.debug.assert;
import flashx.textLayout.edit.EditManager;
import flashx.textLayout.edit.IEditManager;
import flashx.textLayout.edit.SelectionFormat;
import flashx.textLayout.elements.FlowGroupElement;
import flashx.textLayout.elements.FlowLeafElement;
import flashx.textLayout.elements.InlineGraphicElementStatus;
import flashx.textLayout.elements.ParagraphElement;
import flashx.textLayout.elements.SpanElement;
import flashx.textLayout.elements.TextFlow;
import flashx.textLayout.events.StatusChangeEvent;
import flashx.textLayout.formats.ITextLayoutFormat;
import flashx.textLayout.formats.ListStyleType;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.tlf_internal;
import flashx.undo.IUndoManager;
import flashx.undo.UndoManager;
use namespace tlf_internal;
[SWF(width="1000", height="800")]
public class OpHammer extends Sprite
{
private var _textFlow:TextFlow;
private var _textFlowMarkup:String;
private var _sprite:Sprite;
private var _results:TextField;
private var _statusField:TextField;
private var _compress:Boolean = true; // automatically make the TextFlow smaller
private var _pointOnly:Boolean = false; // point selections only
private var _redo:Boolean = false; // redo testing
private const spriteX:Number = 10;
private const spriteY:Number = 70;
private const spriteWidth:Number = 980;
private const spriteHeight:Number = 340;
// FileReference requires a reference or it will be garbage collected
private var _activeFileIndex:int;
private var _activeFileReferenceList:FileReferenceList;
private var _activeFileReference:FileReference;
private var _blockedWaitingForNewFile:Boolean;
private function nextX(b:TextField):Number
{ return b.x + b.width + 10; }
public function OpHammer()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.frameRate = 1000;
stage.addEventListener(Event.RESIZE,resizeHandler);
var b:TextField = addButton("Compress:ON",10,10,0,0,toggleCompress);
b = addButton("PointOnly:OFF",nextX(b),10,0,0,togglePointOnly);
b = addButton("Redo:OFF",nextX(b),10,0,0,toggleRedo);
b = addButton("Load..",nextX(b),10,0,0,openDialog);
b = addButton("STOP",nextX(b),10,0,0,stopTest);
b = addButton(TextLayoutVersion.BUILD_NUMBER + " " + Capabilities.version,nextX(b),10,0,0,null);
_statusField = addButton("Ready",nextX(b),10,0,0,null);
b = addButton("DeleteTest",10,40,0,0,runDeleteTest);
b = addButton("SplitTest",nextX(b),40,0,0,runSplitTest);
b = addButton("FormatSpan",nextX(b),40,0,0,runFormatSpanTest);
b = addButton("ApplyLink",nextX(b),40,0,0,runApplyLinkTest);
b = addButton("RemoveLink",nextX(b),40,0,0,runRemoveLinkTest);
b = addButton("InsertText",nextX(b),40,0,0,runInsertTextTest);
b = addButton("FormatThenSplit",nextX(b),40,0,0,runFormatThenSplitTest);
b = addButton("FormatThenLink",nextX(b),40,0,0,runFormatThenLinkTest);
b = addButton("CreateList",nextX(b),40,0,0,runCreateListTest);
b = addButton("SplitElement",nextX(b),40,0,0,runSplitElementTest);
b = addButton("CreateSubParagraphGroup",nextX(b),40,0,0,runcreateSubParagraphGroupTest);
b = addButton("CreateDiv",nextX(b),40,0,0,runCreateDivTest);
_results = new TextField();
_results.x = 10;
_results.y = 420;
_results.width = 980;
_results.height = 350;
_results.backgroundColor = 0xf0f0f0;
_results.background = true;
_results.wordWrap = true;
addChild(_results);
// show the area covered
/*_sprite = new Sprite;
_sprite.x = spriteX;
_sprite.y = spriteY;
_sprite.graphics.beginFill(0xff,0.5);
_sprite.graphics.drawRect(0,0,spriteWidth,spriteHeight);
_sprite.graphics.endFill();
addChild(_sprite);*/
/*Debugging.verbose = true;
Debugging.debugCheckTextFlow = true;*/
loadTextFlowFromString(TextConverter.PLAIN_TEXT_FORMAT, "Hello", false);
CONFIG::debug { Debugging.tlf_internal::throwOnAssert = true; }
}
public function addButton(text:String,x:Number,y:Number,width:Number,height:Number,handler:Function):TextField
{
var f1:TextField = new TextField();
f1.text = text;
f1.x = x; f1.y = y; // f1.height = height; f1.width = width;
f1.autoSize = TextFieldAutoSize.LEFT;
addChild(f1);
if (handler != null)
{
f1.border = true;
f1.borderColor = 0xff;
f1.addEventListener(MouseEvent.CLICK,handler);
}
f1.selectable = false;
return f1;
}
public function toggleCompress(e:Event):void
{
_compress = !_compress;
TextField(e.target).text = _compress ? "Compress:ON" : "Compress:OFF";
}
public function togglePointOnly(e:Event):void
{
_pointOnly = !_pointOnly;
TextField(e.target).text = _pointOnly ? "PointOnly:ON" : "PointOnly:OFF";
}
public function toggleRedo(e:Event):void
{
_redo = !_redo;
TextField(e.target).text = _redo ? "Redo:ON" : "Redo:OFF";
}
// ////////////////////////
// file loading stuff
// ////////////////////////
public function resizeHandler(e:Event):void
{
/*if (_textFlow)
{
var cont:ContainerController = _textFlow.flowComposer.getControllerAt(0);
cont.setCompositionSize(stage.stageWidth-20,spriteHeight);
_textFlow.flowComposer.updateAllControllers();
}*/
}
public function openDialog(e:Event):void
{
stopTest();
_activeFileReferenceList = null;
if (_activeFileReference)
{
_activeFileReference.cancel();
_activeFileReference = null;
}
var markupFilter:FileFilter = new FileFilter("Documents","*.xml;*.fxg;*.html");
_activeFileReferenceList = new FileReferenceList();
_activeFileReferenceList.addEventListener(Event.SELECT,onFileSelect);
_activeFileReferenceList.addEventListener(Event.CANCEL,function (e:Event):void { _activeFileReference = null; },false,0,true);
_activeFileReferenceList.browse([markupFilter]);
}
public function onFileSelect(event:Event):void
{
_activeFileIndex = 0;
loadActiveFileIndex();
}
public function loadActiveFileIndex():void
{
if (_activeFileReferenceList == null)
return;
_activeFileReference = _activeFileReferenceList.fileList[_activeFileIndex];
_activeFileReference.addEventListener(Event.COMPLETE,onFileReferenceLoadComplete,false,0,true);
_activeFileReference.addEventListener(IOErrorEvent.IO_ERROR,errorOnReadFromFileReference,false,0,true);
_activeFileReference.load();
_statusField.text = traceResult("LOADING",_activeFileReference.name);
}
public function onFileReferenceLoadComplete(event:Event):void
{
if (event.currentTarget == _activeFileReference)
{
var format:String = mapExtensionToFormat(getExtension(_activeFileReference.name));
var fileData:String = String(_activeFileReference.data);
loadTextFlowFromString(format, fileData, _compress);
_activeFileReference = null;
}
}
public function errorOnReadFromFileReference(event:IOErrorEvent):void
{
if (event.currentTarget == _activeFileReference)
{
// Text content will be an error string
var errorString:String = "Error reading file " + _activeFileReference.name;
errorString += "\n";
errorString += event.toString();
loadTextFlowFromString(TextConverter.PLAIN_TEXT_FORMAT,errorString, false);
_activeFileReference = null;
}
}
static public function getExtension(fileName:String):String
{
var dotPos:int = fileName.lastIndexOf(".");
if (dotPos >= 0)
return fileName.substring(dotPos + 1);
return fileName;
}
static public function mapExtensionToFormat(extension:String):String
{
switch (extension.toLowerCase())
{
case "xml": // use Vellum markup
return TextConverter.TEXT_LAYOUT_FORMAT;
break;
case "html":
return TextConverter.TEXT_FIELD_HTML_FORMAT;
break;
}
return TextConverter.PLAIN_TEXT_FORMAT;
}
public function loadTextFlowFromString(format:String,stringData:String, applyCompress:Boolean):void
{
if (_textFlow)
{
_textFlow.removeEventListener(StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGE,statusChangeHandler);
_textFlow = null;
_textFlowMarkup = null;
}
var textImporter:ITextImporter = TextConverter.getImporter(format);
_textFlow = textImporter.importToFlow(stringData);
if (textImporter.errors)
{
traceResult("ERRORS REPORTED ON IMPORT");
for each(var e:String in textImporter.errors)
traceResult(e);
}
// lose the old flow
if (_sprite)
{
removeChild(_sprite);
_sprite = null;
}
if (_textFlow)
{
if (applyCompress)
{
// make all the spans 3 characters (4 with terminator)
var leaf:FlowLeafElement = _textFlow.getLastLeaf();
while (leaf)
{
if ((leaf is SpanElement) && leaf.textLength > 3)
(leaf as SpanElement).replaceText(3,leaf.textLength,null);
leaf = leaf.getPreviousLeaf();
}
// make more visible by giving it multiple columns
_textFlow.columnWidth = 150;
}
_sprite = new Sprite();
_sprite.x = spriteX;
_sprite.y = spriteY;
addChild(_sprite);
var cont:ContainerController = new ContainerController(_sprite,spriteWidth,spriteHeight);
_textFlow.flowComposer.addController(cont);
_textFlow.addEventListener(StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGE,statusChangeHandler);
_textFlow.interactionManager = new EditManager(new UndoManager());
_textFlow.interactionManager.focusedSelectionFormat = new SelectionFormat(0xffffff, 1.0, BlendMode.DIFFERENCE);
_textFlow.interactionManager.unfocusedSelectionFormat = new SelectionFormat(0xa8c6ee, 1.0, BlendMode.NORMAL, 0xffffff);
_textFlow.interactionManager.inactiveSelectionFormat = new SelectionFormat(0xe8e8e8, 1.0, BlendMode.NORMAL, 0xffffff);
_textFlow.flowComposer.updateAllControllers();
// resizeHandler(null);
// save the markup for testing
_textFlowMarkup = TextConverter.export(_textFlow,TextConverter.TEXT_LAYOUT_FORMAT,ConversionType.STRING_TYPE) as String;
}
if (_blockedWaitingForNewFile)
{
_runningTest.reset(_textFlow);
_blockedWaitingForNewFile = false;
traceResult(_textFlowMarkup);
if (_activeFileIndex == 0)
_statusField.text = traceResult("BEG TESTING", _runningTest.testName, _textFlow.textLength);
}
else if (_runningTest)
_runningTest.changeTextFlow(_textFlow);
}
private function statusChangeHandler(e:StatusChangeEvent):void
{
// if the graphic has loaded update the display
// set the loaded graphic's height to match text height
if (e.status == InlineGraphicElementStatus.READY || e.status == InlineGraphicElementStatus.SIZE_PENDING)
_textFlow.flowComposer.updateAllControllers();
}
// //////////////////////
// Results logging
// /////////////////////
public function traceResult(s:String, ... args):String
{
for each (var obj:Object in args)
{
s += " " + obj.toString();
}
trace(s);
_results.appendText(s);
_results.appendText("\n");
_results.scrollV = _results.maxScrollV;
return s;
}
private var _runningTest:ITestCase;
private var _testCount:int;
private var _errorCount:int;
// ////////////////
// Test intiating functions
// ///////////////
public function get editManager():IEditManager
{ return _textFlow ? _textFlow.interactionManager as IEditManager : null; }
public function runDeleteTest(e:Event):void
{
runStandardTest("deleteText", function ():void { editManager.deleteText(); });
}
public function runSplitTest(e:Event):void
{
runStandardTest("splitParagraph",function ():void { editManager.splitParagraph(); });
}
public function runFormatSpanTest(e:Event):void
{
runStandardTest("applyFormat to span",function ():void { editManager.applyFormat(TextLayoutFormat.createTextLayoutFormat({color:0xf0}),null,null); });
}
public function runApplyLinkTest(e:Event):void
{
runStandardTest("applyLink",function ():void { editManager.applyLink("http://www.adobe.com"); });
}
public function runRemoveLinkTest(e:Event):void
{
runStandardTest(e.target.text,function ():void { editManager.applyLink(""); });
}
public function runcreateSubParagraphGroupTest(e:Event):void
{
runStandardTest("createSubParagraphGroup",function ():void { var elem:FlowGroupElement = _runningTest.objectMark.findElement(_textFlow) as FlowGroupElement; editManager.createSubParagraphGroup(elem); },true);
}
public function runCreateDivTest(e:Event):void
{
runStandardTest("createDiv",function ():void { editManager.createDiv(); },true);
// runStandardTest("createDiv",function ():void { var elem:FlowGroupElement = _runningTest.objectMark.findElement(_textFlow) as FlowGroupElement; editManager.createDiv(elem); },true);
}
public function runInsertTextTest(e:Event):void
{
runStandardTest("insertText",function ():void { editManager.insertText("A"); (_textFlow.interactionManager as EditManager).flushPendingOperations()});
}
public function runFormatThenSplitTest(e:Event):void
{
var formatFunction:Function = function ():void { editManager.applyFormat(TextLayoutFormat.createTextLayoutFormat({color:0xf0}),null,null); };
var splitFunction:Function = function ():void { editManager.splitParagraph(); };
runTest(new NestedTestCase("formatThenSplit",new StandardTestCase("formatThenSplit",formatFunction,_textFlow,false,false),splitFunction,_textFlow,_pointOnly));
}
public function runFormatThenLinkTest(e:Event):void
{
var formatFunction:Function = function ():void { editManager.applyFormat(TextLayoutFormat.createTextLayoutFormat({color:0xf0}),null,null); };
var linkFunction:Function = function ():void { editManager.applyLink("http://www.adobe.com"); };
runTest(new NestedTestCase("formatThenLink",new StandardTestCase("formatThenLink",formatFunction,_textFlow,false,false),linkFunction,_textFlow,_pointOnly));
}
public function runCreateListTest(e:Event):void
{
var listFormat:TextLayoutFormat = new TextLayoutFormat();
listFormat.paddingLeft=24;
listFormat.paddingRight=24;
listFormat.listStyleType = ListStyleType.DISC;
runStandardTest("createList",function ():void { editManager.createList(null, listFormat); });
}
public function runSplitElementTest(e:Event):void
{
runStandardTest("splitElement",function ():void { var elem:FlowGroupElement = _runningTest.objectMark.findElement(_textFlow) as FlowGroupElement; editManager.splitElement(elem); }, true);
// runStandardTest("splitElement",function ():void { editManager.splitElement(null); }, false);
}
// ////////////////
// Generic Test
// ///////////////
public function runStandardTest(testName:String,f:Function,objectMode:Boolean = false):void
{ runTest(new StandardTestCase(testName,f,_textFlow,_pointOnly,objectMode)); }
public function runTest(testCase:ITestCase):void
{
if (!_textFlow)
return;
stopTest(); // any that are already running
_runningTest = testCase;
_testCount = 0;
_errorCount = 0;
if (_activeFileIndex != 0)
{
_blockedWaitingForNewFile = true;
_activeFileIndex = 0;
loadActiveFileIndex();
}
else
{
_statusField.text = traceResult("BEG TESTING", testCase.testName, _textFlow.textLength);
traceResult(_textFlowMarkup);
}
addEventListener(Event.ENTER_FRAME,singleStepTestFunction);
}
public function stopTest(e:Object = null):void
{
if (_runningTest)
{
removeEventListener(Event.ENTER_FRAME,singleStepTestFunction);
_statusField.text = traceResult("END TESTING", _runningTest.testName, "TESTS", _testCount, "ERRORS", _errorCount);
_runningTest = null;
}
}
public function reportError(errorStage:String):void
{
traceResult("ERROR",errorStage,_testCount,_runningTest.testName,_runningTest.getErrorInfo());
_errorCount++;
}
public function singleStepTestFunction(e:Event):void
{
if (_blockedWaitingForNewFile)
return;
_testCount++;
var testError:Boolean = false;
var firstPerformMarkup:String;
var testStage:String;
try
{
testStage = "PERFORM";
_runningTest.performFunction();
if (_redo)
{
testStage = "EXPORT";
firstPerformMarkup = TextConverter.export(_textFlow,TextConverter.TEXT_LAYOUT_FORMAT,ConversionType.STRING_TYPE) as String;
}
testStage = "UNDO";
_runningTest.undoFunction();
}
catch (e:Error)
{
traceResult("EXCEPTION CAUGHT",e.toString());
testError = true;
reportError(testStage);
}
if (!testError)
{
var afterFirstUndoMarkup:String = TextConverter.export(_textFlow,TextConverter.TEXT_LAYOUT_FORMAT,ConversionType.STRING_TYPE) as String;
if (afterFirstUndoMarkup != _textFlowMarkup)
{
trace(_textFlowMarkup);
trace(afterFirstUndoMarkup);
testError = true;
reportError("UNDO MARKUP");
}
else if (_redo)
{
// redo the operation
var afterRedoMarkup:String;
try
{
testStage = "REDO";
_runningTest.redoFunction();
testStage = "EXPORT";
afterRedoMarkup = TextConverter.export(_textFlow,TextConverter.TEXT_LAYOUT_FORMAT,ConversionType.STRING_TYPE) as String;
testStage = "2ND UNDO";
_runningTest.undoFunction();
}
catch (e:Error)
{
traceResult("EXCEPTION CAUGHT",e.toString());
testError = true;
reportError(testStage);
}
if (!testError)
{
if (firstPerformMarkup != afterRedoMarkup)
{
testError = true;
reportError("REDO MARKUP");
}
else
{
var afterSecondUndoMarkup:String = TextConverter.export(_textFlow,TextConverter.TEXT_LAYOUT_FORMAT,ConversionType.STRING_TYPE) as String;
if (afterSecondUndoMarkup != _textFlowMarkup)
{
testError = true;
reportError("2ND UNDO MARKUP");
}
}
}
}
}
if (testError)
{
// on error need to reset the textFlow to its original markup
loadTextFlowFromString(TextConverter.TEXT_LAYOUT_FORMAT, _textFlowMarkup, false);
_textFlow.interactionManager.selectRange(_runningTest.begSelIdx,_runningTest.endSelIdx);
_textFlow.interactionManager.refreshSelection();
}
if (testError || (_testCount%250) == 0)
_statusField.text = traceResult("TEST",_runningTest.testName ,_runningTest.getErrorInfo(), "TESTS", _testCount, "ERRORS", _errorCount);
// do and undo the operation with the selection range. verify that the textflow is unchanged
if (_runningTest.isTestComplete())
{
if (this._activeFileReferenceList == null || this._activeFileIndex >= this._activeFileReferenceList.fileList.length-1)
stopTest();
else
{
_blockedWaitingForNewFile = true;
_activeFileIndex++;
loadActiveFileIndex();
}
}
else
_runningTest.incrementTest();
}
}
}
import flashx.textLayout.edit.ElementMark;
import flashx.textLayout.edit.IEditManager;
import flashx.textLayout.elements.FlowElement;
import flashx.textLayout.elements.FlowGroupElement;
import flashx.textLayout.elements.TextFlow;
interface ITestCase
{
function get begSelIdx():int;
function get endSelIdx():int;
function get objectMark():ElementMark;
function get testName():String;
function isTestComplete():Boolean;
function incrementTest():void;
function performFunction():void;
function undoFunction():void;
function redoFunction():void;
/** call to reset a test case for reuse */
function reset(textFlow:TextFlow):void;
/** Used when running a test discovers an error to get the TextFlow back to the correct test version. */
function changeTextFlow(newFlow:TextFlow):void;
function getErrorInfo():String;
}
class StandardTestCase implements ITestCase
{
private var _testName:String;
private var _testFunction:Function;
protected var _textFlow:TextFlow;
private var _begSelIdx:int;
private var _endSelIdx:int;
private var _pointOnly:Boolean;
private var _objectMode:Boolean;
// used in _objectMode to track the current object
private var _objectMark:ElementMark;
private var _objectMarkArray:Array;
// don't use original textFlow.length but the maximum length ever seen in performTest - that's because the textFlow may vary in length
protected var _maxTextFlowLength:int;
public function StandardTestCase(testName:String, func:Function,textFlow:TextFlow,pointOnly:Boolean,objectMode:Boolean)
{
_testName = testName;
_testFunction = func;
_pointOnly = pointOnly;
_objectMode = objectMode;
reset(textFlow);
}
public function reset(textFlow:TextFlow):void
{
_begSelIdx = 0;
_endSelIdx = 0;
_textFlow = textFlow;
_maxTextFlowLength = _textFlow.textLength;
if (_objectMode)
{
// just build a list of ElementMarks
_objectMarkArray = [];
buildFlowGroupChildList(_objectMarkArray,_textFlow);
_objectMark = _objectMarkArray.shift();
_begSelIdx = _endSelIdx = _objectMark.findElement(_textFlow).getAbsoluteStart();
}
}
public static function buildFlowGroupChildList(a:Array,elem:FlowGroupElement):void
{
for (var idx:int = 0; idx < elem.numChildren; idx++)
{
var child:FlowElement = elem.getChildAt(idx);
if (child is FlowGroupElement)
{
buildFlowGroupChildList(a,child as FlowGroupElement);
a.push(new ElementMark(child,0));
}
}
}
public function get testName():String
{ return _testName; }
public function get begSelIdx():int
{ return _begSelIdx; }
public function get endSelIdx():int
{ return _endSelIdx; }
public function get objectMark():ElementMark
{ return _objectMark; }
public function get pointOnly():Boolean
{ return _pointOnly; }
public function changeTextFlow(newFlow:TextFlow):void
{
_textFlow = newFlow;
}
public function performFunction():void
{
_maxTextFlowLength = Math.max(_maxTextFlowLength,_textFlow.textLength);
_textFlow.interactionManager.selectRange(_begSelIdx,_endSelIdx);
_textFlow.interactionManager.refreshSelection();
_testFunction();
}
public function undoFunction():void
{
(_textFlow.interactionManager as IEditManager).undo();
}
public function redoFunction():void
{
(_textFlow.interactionManager as IEditManager).redo();
}
public function incrementTest():void
{
if (_objectMode)
{
if (_pointOnly)
{
var elem:FlowGroupElement = _objectMark.findElement(_textFlow) as FlowGroupElement;
var elemStart:int = _objectMark.elemStart;
if (elemStart < elem.textLength)
_objectMark = new ElementMark(elem,elemStart+1);
else
_objectMark = _objectMarkArray.shift();
_begSelIdx = _endSelIdx = _objectMark.findElement(_textFlow).getAbsoluteStart() + _objectMark.elemStart;
}
else
{
var object:FlowElement = _objectMark.findElement(_textFlow);
var objectEnd:int = object.getAbsoluteStart() + object.textLength;
if (_begSelIdx == objectEnd && _endSelIdx == objectEnd)
{
_objectMark = _objectMarkArray.shift();
object = _objectMark.findElement(_textFlow);
_begSelIdx = _endSelIdx = object.getAbsoluteStart();
}
else if (_begSelIdx == _endSelIdx)
{
_begSelIdx = object.getAbsoluteStart();
_endSelIdx++;
}
else
_begSelIdx++;
}
}
else if (_pointOnly)
{
_begSelIdx++;
_endSelIdx = _begSelIdx;
}
else if (_begSelIdx < _endSelIdx)
_begSelIdx++;
else
{
_endSelIdx++;
_begSelIdx = 0;
}
}
public function isTestComplete():Boolean
{
return _begSelIdx >= _textFlow.textLength && _endSelIdx >= _textFlow.textLength && (!_objectMode || _objectMarkArray.length == 0);
}
public function getErrorInfo():String
{
return "(" + begSelIdx + "," + endSelIdx + ")";
}
}
class NestedTestCase extends StandardTestCase
{
private var _firstTest:ITestCase;
public function NestedTestCase(testName:String,firstTest:ITestCase,secondFunction:Function,textFlow:TextFlow,pointOnly:Boolean)
{
super(testName,secondFunction,textFlow,pointOnly,false);
_firstTest = firstTest; // ;
}
public override function changeTextFlow(newFlow:TextFlow):void
{
super.changeTextFlow(newFlow);
_firstTest.changeTextFlow(newFlow);
}
public override function reset(textFlow:TextFlow):void
{
_firstTest.reset(textFlow);
super.reset(textFlow);
}
public override function isTestComplete():Boolean
{
return _firstTest.isTestComplete() && super.isTestComplete();
}
public override function performFunction():void
{
_firstTest.performFunction();
super.performFunction();
}
public override function undoFunction():void
{
super.undoFunction();
_firstTest.undoFunction();
}
public override function redoFunction():void
{
_firstTest.redoFunction();
super.redoFunction();
}
public override function incrementTest():void
{
if (_firstTest.isTestComplete())
{
_firstTest.reset(_textFlow);
super.incrementTest();
}
else
_firstTest.incrementTest();
}
public override function getErrorInfo():String
{
return _firstTest.getErrorInfo() + " " + super.getErrorInfo();
}
}