| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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(); |
| } |
| } |