http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/ParagraphPropertyMarkerSkin.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/ParagraphPropertyMarkerSkin.as
 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/ParagraphPropertyMarkerSkin.as
new file mode 100644
index 0000000..930f1c7
--- /dev/null
+++ 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/ParagraphPropertyMarkerSkin.as
@@ -0,0 +1,103 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package flashx.textLayout.ui.rulers
+{
+       import mx.skins.RectangularBorder;
+
+       public class ParagraphPropertyMarkerSkin extends RectangularBorder
+       {
+               public function ParagraphPropertyMarkerSkin()
+               {
+                       super();
+               }
+               
+               override protected function updateDisplayList(w:Number, 
h:Number):void
+               {
+                   super.updateDisplayList(w, h);
+                   
+                   var propKind:String = getStyle("propkind");
+                   var rightToLeftPar:Boolean = getStyle("rightToLeftPar");
+                   
+                   var t:Number = 0;
+                   var b:Number = h;
+                   
+                       graphics.clear();
+
+                       graphics.beginFill(0x000000);
+                       if (rightToLeftPar)
+                       {
+                               switch(propKind) {
+                               case "textIndent":
+                                       b = (h - 1) / 2;
+                                       graphics.moveTo(w, 0);
+                                       graphics.lineTo(w, b);
+                                       graphics.lineTo(0, b);
+                                       graphics.lineTo(w, 0);
+                                       break;
+                               case "paragraphStartIndent":
+                                       graphics.moveTo(0, 0);
+                                       graphics.lineTo(0, h);
+                                       graphics.lineTo(w, h / 2);
+                                       graphics.lineTo(0, 0);
+                                       break;
+                               case "paragraphEndIndent":
+                                       t = h - (h - 1) / 2;
+                                       graphics.moveTo(w, h);
+                                       graphics.lineTo(0, t);
+                                       graphics.lineTo(w, t);
+                                       graphics.lineTo(w, h);
+                                       break;
+                               }
+                       }
+                       else
+                       {
+                               switch(propKind) {
+                               case "textIndent":
+                                       b = (h - 1) / 2;
+                                       graphics.moveTo(0, 0);
+                                       graphics.lineTo(w, b);
+                                       graphics.lineTo(0, b);
+                                       graphics.lineTo(0, 0);
+                                       break;
+                               case "paragraphStartIndent":
+                                       t = h - (h - 1) / 2;
+                                       graphics.moveTo(0, h);
+                                       graphics.lineTo(0, t);
+                                       graphics.lineTo(w, t);
+                                       graphics.lineTo(0, h);
+                                       break;
+                               case "paragraphEndIndent":
+                                       graphics.moveTo(w, 0);
+                                       graphics.lineTo(w, h);
+                                       graphics.lineTo(0, h / 2);
+                                       graphics.lineTo(w, 0);
+                                       break;
+                               }
+                       }
+                       graphics.endFill();
+                       
+                       // this makes the whole rect hittable
+                       graphics.lineStyle();
+               graphics.beginFill(0x0000ff, 0);
+               graphics.drawRect(0, t, w, b);
+               graphics.endFill();
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerBar.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerBar.as 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerBar.as
new file mode 100644
index 0000000..73817f2
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerBar.as
@@ -0,0 +1,672 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package flashx.textLayout.ui.rulers
+{
+       import bxf.ui.inspectors.DynamicPropertyEditorBase;
+       
+       import flash.display.DisplayObject;
+       import flash.display.GradientType;
+       import flash.events.MouseEvent;
+       import flash.geom.Matrix;
+       import flash.geom.Point;
+       import flash.geom.Rectangle;
+       import flash.text.engine.TabAlignment;
+       
+       import flashx.textLayout.container.ContainerController;
+       import flashx.textLayout.edit.EditManager;
+       import flashx.textLayout.edit.ElementRange;
+       import flashx.textLayout.edit.SelectionState;
+       import flashx.textLayout.elements.ContainerFormattedElement;
+       import flashx.textLayout.elements.ParagraphElement;
+       import flashx.textLayout.elements.TextFlow;
+       import flashx.textLayout.compose.TextFlowLine;
+       import flashx.textLayout.events.SelectionEvent;
+       import flashx.textLayout.formats.ITextLayoutFormat;
+       import flashx.textLayout.formats.ITabStopFormat;
+       import flashx.textLayout.formats.TextLayoutFormat;
+       import flashx.textLayout.formats.TabStopFormat;
+       import flashx.textLayout.formats.BlockProgression;
+       import flashx.textLayout.tlf_internal;
+       import flashx.textLayout.ui.inspectors.TabPropertyEditor;
+       import flashx.textLayout.ui.inspectors.TextInspectorController;
+       
+       import mx.containers.Canvas;
+       import mx.core.ScrollPolicy;
+       import mx.core.UIComponent;
+       import mx.events.PropertyChangeEvent;
+       import mx.events.ResizeEvent;
+       use namespace tlf_internal;
+       
+       public class RulerBar extends Canvas
+       {
+               public static const RULER_HORIZONTAL:String = "horizontal";
+               public static const RULER_VERTICAL:String = "vertical";
+               
+               public function RulerBar()
+               {
+                       super();
+                       horizontalScrollPolicy = ScrollPolicy.OFF;
+                       verticalScrollPolicy = ScrollPolicy.OFF;
+                       mDefaultTabStop = new 
TabStopFormat(TabStopFormat.defaultFormat);
+                       addEventListener(MouseEvent.MOUSE_DOWN, 
onRulerMouseDown);
+                       selectMarker(null);
+                       TextInspectorController.Instance().AddRuler(this);
+                       curParagraphFormat = null;
+               }
+               
+               override public function initialize():void
+               {
+                       super.initialize();
+                       adjustForActive();
+               }
+               
+               public function creationComplete():void
+               {
+                       if (mSyncToPanel)
+                       {
+                               
mSyncToPanel.addEventListener(ResizeEvent.RESIZE, onSyncPanelResize);
+                       }
+                       SyncRulerToPanel();
+                       mIndentMarker = 
addParagraphPropertyMarker(TextLayoutFormat.textIndentProperty.name);
+                       mLeftMarginMarker = 
addParagraphPropertyMarker(TextLayoutFormat.paragraphStartIndentProperty.name);
+                       mRightMarginMarker = 
addParagraphPropertyMarker(TextLayoutFormat.paragraphEndIndentProperty.name);
+               }
+               
+               public function set activeFlow(inFlow:TextFlow):void
+               {
+                       if (inFlow && !inFlow.interactionManager is EditManager)
+                               throw new Error("Can't set the active flow to a 
flow without an EditManager.");
+                       if (mActiveFlow)
+                       {
+                               
mActiveFlow.removeEventListener(SelectionEvent.SELECTION_CHANGE, 
onTextSelectionChanged);
+                               mEditManager = null;
+                       }
+                       mActiveFlow = inFlow;
+                       mLastSelActiveIdx = -1;
+                       mLastSelAnchorIdx = -1;
+                       mTabSet = null;
+                       RemoveTabMarkers();
+                       selectMarker(null);
+                       
+                       if (mActiveFlow)
+                       {
+                               mEditManager = mActiveFlow.interactionManager 
as EditManager;
+                               
mActiveFlow.addEventListener(SelectionEvent.SELECTION_CHANGE, 
onTextSelectionChanged);
+                       }
+                       else
+                               onTextSelectionChanged(null);
+               }
+               
+               public function get activeFlow():TextFlow
+               {
+                       return mActiveFlow;
+               }
+               
+               public function set active(inActive:Boolean):void
+               {
+                       mActive = inActive;
+                       selectMarker(null);
+                       adjustForActive();
+               }
+               
+               public function get active():Boolean
+               {
+                       return mActive;
+               }
+
+               private function set rightRuler(inActive:Boolean):void
+               {
+                       mRightRuler = inActive;
+                       adjustForActive();
+               }
+               
+               private function get rightRuler():Boolean
+               {
+                       return mRightRuler;
+               }
+               
+               private function adjustForActive():void
+               {
+                       if (parent)
+                       {
+                               if (mActive && mRightRuler)
+                               {
+                                       parent.visible = true;
+                                       if (parent is Canvas)
+                                               (parent as 
Canvas).includeInLayout = true;
+                               }
+                               else
+                               {
+                                       parent.visible = false;
+                                       if (parent is Canvas)
+                                               (parent as 
Canvas).includeInLayout = false;
+                               }
+                       }
+               }
+               
+               public function set orientation(inOrientation:String):void
+               {
+                       if (inOrientation != mOrientation && (inOrientation == 
RULER_HORIZONTAL || inOrientation == RULER_VERTICAL))
+                       {
+                               mOrientation = inOrientation;
+                       }
+               }
+               
+               public function set syncToPanel(inPanel:UIComponent):void
+               {
+                       mSyncToPanel = inPanel;
+               }
+               
+               public function set 
tabPropertyEditor(inEditor:TabPropertyEditor):void
+               {
+                       mPropertyEditor = inEditor;
+                       
mPropertyEditor.addEventListener(DynamicPropertyEditorBase.MODELCHANGED_EVENT, 
onFormatValueChanged, false, 0, true);
+                       
mPropertyEditor.addEventListener(DynamicPropertyEditorBase.MODELEDITED_EVENT, 
onFormatValueChanged, false, 0, true);
+                       selectMarker(mSelectedMarker);
+               }
+               
+               private function onSyncPanelResize(evt:ResizeEvent):void
+               {
+                       RedrawRuler();
+               }
+               
+               public function RedrawRuler():void
+               {
+                       SyncRulerToPanel();
+                       if (curParagraphFormat != null) {
+                               ShowTabs(curParagraphFormat);
+                       }                       
+               }
+
+               private function SyncRulerToPanel():void
+               {
+                       if (mActiveFlow && mActiveFlow.flowComposer && 
rightRuler)
+                       {
+                               var selStart:int = 
Math.min(mActiveFlow.interactionManager.activePosition, 
mActiveFlow.interactionManager.anchorPosition);
+                               var line:TextFlowLine = selStart != -1 ? 
mActiveFlow.flowComposer.findLineAtPosition(selStart) : null;
+                               if (line)
+                               {
+                                       var controller:ContainerController;
+                                       var containerDO:DisplayObject;
+                                       if (line.controller)
+                                       {
+                                               controller = line.controller;
+                                               containerDO = 
controller.container as DisplayObject;
+                                       }
+                                       else
+                                       {
+                                               // get the last container
+                                               controller = 
mActiveFlow.flowComposer.getControllerAt(mActiveFlow.flowComposer.numControllers-1);
+                                               containerDO = 
controller.container as DisplayObject;
+                                       }
+                                       var localOrigin:Point = 
parent.globalToLocal(containerDO.parent.localToGlobal(new Point(containerDO.x, 
containerDO.y)));
+                                       var columnBounds:Rectangle;
+                                       var columnIndex:int = line.columnIndex;
+                                       if (columnIndex == -1)
+                                               columnBounds = 
controller.columnState.getColumnAt(controller.columnState.columnCount - 1);
+                                       else
+                                       {
+                                               // columnIndex is an index into 
all the columns in the flow, so to get the actual
+                                               // column bounds 
+                                               var idx:int = 0;
+                                               var ch:ContainerController = 
mActiveFlow.flowComposer.getControllerAt(idx);
+                                               while (ch && ch != controller)
+                                               {
+                                                       columnIndex -= 
ch.columnState.columnCount;
+                                                       idx++;
+                                                       ch = idx == 
mActiveFlow.flowComposer.numControllers ? null : 
mActiveFlow.flowComposer.getControllerAt(idx);
+                                               }
+                                               // Pin the column number to the 
actual range of column indices. I have found this
+                                               // is needed when the insertion 
point is inside a table (because the line's container
+                                               // is not in the flow's list of 
containers) or when the insertion point is in regular
+                                               // text after a table (the 
column number doesn't make sense, and I think it's a bug, which
+                                               // I have written to Robin 
about.
+                                               columnIndex = Math.max(0, 
Math.min(line.columnIndex, controller.columnState.columnCount - 1));
+                                               columnBounds = 
controller.columnState.getColumnAt(columnIndex);
+                                       }
+                                       
+                                       if (columnBounds)
+                                       {
+                                               if (mOrientation == 
RULER_HORIZONTAL)
+                                               {
+                                                       x = localOrigin.x + 
columnBounds.x;
+                                                       y = 0;
+                                                       height = parent.height;
+                                                       width = 
columnBounds.width;
+                                               }
+                                               else
+                                               {
+                                                       x = parent.width;
+                                                       y = localOrigin.y + 
columnBounds.y;
+                                                       rotation = 90;
+                                                       height = parent.width;
+                                                       width = 
columnBounds.height;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               private function onTextSelectionChanged(e:SelectionEvent):void
+               {
+                       curParagraphFormat = null;
+                       if (mEditManager && (mEditManager.activePosition != 
mLastSelActiveIdx || mEditManager.anchorPosition != mLastSelAnchorIdx))
+                       {
+                               mLastSelActiveIdx = 
mActiveFlow.interactionManager.activePosition;
+                               mLastSelAnchorIdx = 
mActiveFlow.interactionManager.anchorPosition;
+                               selectMarker(null);
+                       }
+                       if (e)
+                       {
+                               var selState:SelectionState = e.selectionState;
+                               var selectedElementRange:ElementRange =  
selState ? ElementRange.createElementRange(selState.textFlow, 
selState.absoluteStart, selState.absoluteEnd) : null;
+                               if (selectedElementRange)
+                               {
+                                       var 
rootElement:ContainerFormattedElement = 
selectedElementRange.firstLeaf.getAncestorWithContainer();
+                                       if 
((rootElement.computedFormat.blockProgression == BlockProgression.RL) == 
(mOrientation == RULER_VERTICAL))
+                                       {
+                                               // should be active
+                                               if (rightRuler != true)
+                                               {
+                                                       mTabSet = null;
+                                               }
+                                               if (!rightRuler)
+                                                       rightRuler = true;
+                                       }
+                                       else
+                                       {
+                                               // should be inactive
+                                               if (rightRuler != false)
+                                               {
+                                                       mTabSet = null;
+                                               }
+                                               if (rightRuler)
+                                                       rightRuler = false;
+                                       }
+                                       
+                                       curParagraphFormat = new 
TextLayoutFormat(selectedElementRange.firstParagraph.computedFormat);
+                                       
setRightToLeft(curParagraphFormat.direction == 
flashx.textLayout.formats.Direction.RTL);                                       
 
+                                       ShowTabs(curParagraphFormat);
+                               }
+                               else
+                                       ShowTabs(null);
+                       }
+                       else
+                               ShowTabs(null);
+               }
+               
+               
+               private function RemoveTabMarkers():void
+               {
+                       var markers:Array = getChildren();
+                       for each (var marker:UIComponent in markers)
+                               if (marker is TabMarker)
+                                       this.removeChild(marker);
+               }
+               
+               
+               private function ShowTabs(inFormat:ITextLayoutFormat):void
+               {
+                       SyncRulerToPanel();
+                       var tabs:Array = inFormat ? ((inFormat.tabStops && 
(inFormat.tabStops.length > 0)) ? inFormat.tabStops as Array : null) : null;
+                       if (isNewTabSet(tabs))
+                       {
+                               mTabSet = tabs;
+                               if (mUpdateFromSelection)
+                               {
+                                       RemoveTabMarkers();
+                                       var oldSel:RulerMarker = 
mSelectedMarker;
+                                       selectMarker(null);
+                                       if (mTabSet)
+                                               for each(var tab:TabStopFormat 
in mTabSet)
+                                               {
+                                                       var tabMarker:TabMarker 
= addTabMarker(tab);
+                                                       if (oldSel && 
oldSel.pos == tabMarker.pos)
+                                                               
selectMarker(tabMarker);
+                                               }
+                               }
+                       }
+                       if (inFormat)
+                       {
+                               if(mIndentMarker)
+                               {
+                                       mIndentMarker.rightToLeftPar = 
mRightToLeft;
+                                       mIndentMarker.pos = 
Number(inFormat.textIndent);
+                                       mIndentMarker.relativeToPosition = 
inFormat.paragraphStartIndent;
+                               }
+                               
+                               if(mLeftMarginMarker)
+                               {
+                                       mLeftMarginMarker.rightToLeftPar = 
mRightToLeft;
+                                       mLeftMarginMarker.pos = rightToLeft ? 
Number(inFormat.paragraphEndIndent): Number(inFormat.paragraphStartIndent);
+                               }
+                               
+                               if(mRightMarginMarker)
+                               {
+                                       mRightMarginMarker.rightToLeftPar = 
mRightToLeft;
+                                       mRightMarginMarker.pos = rightToLeft ? 
Number(inFormat.paragraphStartIndent): Number(inFormat.paragraphEndIndent);
+                               }
+                       }
+               }
+               
+               
+               private function addTabMarker(tabAttrs:ITabStopFormat):TabMarker
+               {
+                       var tabMarker:TabMarker = new TabMarker(this, tabAttrs);
+                       tabMarker.addEventListener(MouseEvent.MOUSE_DOWN, 
onMarkerMouseDown);
+                       addChild(tabMarker);
+                       return tabMarker;
+               }
+               
+               
+               private function 
addParagraphPropertyMarker(inProperty:String):ParagraphPropertyMarker
+               {
+                       var propMarker:ParagraphPropertyMarker = new 
ParagraphPropertyMarker(this, inProperty);
+                       propMarker.addEventListener(MouseEvent.MOUSE_DOWN, 
onMarkerMouseDown);
+                       addChild(propMarker);
+                       return propMarker;
+               }
+               
+               
+               private function isNewTabSet(inTabs:Array):Boolean
+               {
+                       if (inTabs == mTabSet)
+                               return false;
+                       if ((inTabs == null) != (mTabSet == null))
+                               return true;
+                       if (inTabs)
+                       {
+                               if (inTabs.length == mTabSet.length)
+                               {
+                                       var n:int = inTabs.length;
+                                       for (var i:int = 0; i < n; ++i)
+                                       {
+                                               if (inTabs[i] != mTabSet[i])
+                                                       return true;
+                                       }
+                                       return false;
+                               }
+                               else
+                                       return true;
+                       }
+                       return false;
+               }
+
+
+               override protected function updateDisplayList(w:Number, 
h:Number):void
+               {
+                   super.updateDisplayList(w, h);
+                   
+                       graphics.clear();
+                       var m:Matrix = new Matrix();
+                       m.createGradientBox(height, height, Math.PI / 2);
+                       graphics.beginGradientFill(GradientType.LINEAR, 
[0xffffff, 0xe0e0e0], [1, 1], [0, 255], m);
+                       graphics.drawRect(0, 0, w, h);
+                       graphics.endFill();
+                       
+                       graphics.lineStyle(1, 0x404040, 1.0, true);
+                       for (var x:int = 0; x < w; x += 10)
+                       {
+                               var rulerX:Number = rightToLeft ? w - x - 1 : x;
+                               if (x % 100 == 0)
+                                       graphics.moveTo(rulerX, 12);
+                               else if (x % 50 == 0)
+                                       graphics.moveTo(rulerX, 9);
+                               else
+                                       graphics.moveTo(rulerX, 5);
+                               graphics.lineTo(rulerX, 0);
+                       }
+               }
+               
+               private function onMarkerMouseDown(e:MouseEvent):void
+               {
+                       if (mEditManager)
+                       {
+                               var cookie:Object;
+                               if (e.target is TabMarker)
+                               {
+                                       var tabMarker:TabMarker = e.target as 
TabMarker;
+                                       selectMarker(tabMarker);
+                                       e.stopPropagation();
+                                       cookie = new Object();
+                                       cookie["marker"] = tabMarker;
+                                       cookie["offset"] = e.localX;
+                                       cookie["onRuler"] = true;
+                                       mUpdateFromSelection = false;
+                                       new 
RulerDragTracker(this.parentApplication as UIComponent, this, 
cookie).BeginTracking(e, false);
+                               }
+                               else if (e.target is ParagraphPropertyMarker)
+                               {
+                                       var propMarker:ParagraphPropertyMarker 
= e.target as ParagraphPropertyMarker;
+                                       selectMarker(null);
+                                       e.stopPropagation();
+                                       cookie = new Object();
+                                       cookie["marker"] = propMarker;
+                                       cookie["offset"] = e.localX;
+                                       new 
RulerDragTracker(this.parentApplication as UIComponent, this, 
cookie).BeginTracking(e, false);
+                               }
+                       }
+               }
+               
+               private function onRulerMouseDown(e:MouseEvent):void
+               {
+                       if (e.target is RulerBar && mEditManager)
+                       {
+                               var tabMarker:TabMarker = 
addTabMarker(mDefaultTabStop);
+                               tabMarker.markerLeft = e.localX + 
tabMarker.hOffset;
+                               selectMarker(tabMarker);
+                               mUpdateFromSelection = false;
+                               setFormatFromRuler();
+                               e.stopPropagation();
+                               var cookie:Object = new Object();
+                               cookie["marker"] = tabMarker;
+                               cookie["offset"] = -tabMarker.hOffset;
+                               cookie["onRuler"] = true;
+                               new RulerDragTracker(this.parentApplication as 
UIComponent, this, cookie, 0).BeginTracking(e, false);
+                       }
+               }
+               
+               public function TrackDrag(inCurPos:Point, inCookie:Object, 
inCommit:Boolean):void
+               {
+                       if (inCookie)
+                       {
+                               if (inCookie["marker"] is TabMarker)
+                               {
+                                       var tabMarker:TabMarker = 
inCookie["marker"] as TabMarker;
+                                       var wasOnRuler:Boolean = 
inCookie["onRuler"];
+                                       if (inCookie["onRuler"] && inCurPos.y > 
height + 16)
+                                       {
+                                               inCookie["onRuler"] = false;
+                                               removeChild(tabMarker);
+                                               selectMarker(null);
+                                       }
+                                       else if (!inCookie["onRuler"] && 
inCurPos.y <= height + 16)
+                                       {
+                                               inCookie["onRuler"] = true;
+                                               addChild(tabMarker);
+                                               selectMarker(tabMarker);
+                                       }
+                                       
+                                       tabMarker.markerLeft = inCurPos.x - 
inCookie["offset"];
+                                       if (wasOnRuler || inCookie["onRuler"])
+                                               setFormatFromRuler();
+                               }
+                               else if (inCookie["marker"] is 
ParagraphPropertyMarker)
+                               {
+                                       var propMarker:ParagraphPropertyMarker 
= inCookie["marker"] as ParagraphPropertyMarker;
+                                       propMarker.markerLeft = inCurPos.x - 
inCookie["offset"];
+                                       var pa:TextLayoutFormat = new 
TextLayoutFormat();
+                                       pa[propMarker.property] = 
propMarker.pos;
+                                       mEditManager.applyParagraphFormat(pa);
+                               }
+                       }
+                       if (inCommit)
+                               mUpdateFromSelection = true;
+               }
+               
+               public function DragCancelled():void
+               {
+                       mUpdateFromSelection = true;
+               }
+
+               private function selectMarker(inMarker:RulerMarker):void
+               {
+                       if (mSelectedMarker)
+                               mSelectedMarker.setStyle("selected", false);
+                       mSelectedMarker = inMarker;
+                       if (mSelectedMarker)
+                               mSelectedMarker.setStyle("selected", true);
+                       updatePropertyEditor();
+               }
+               
+               private function updatePropertyEditor():void
+               {
+                       if (mRightRuler && mPropertyEditor && mTabPanelActive)
+                       {
+                               mPropertyEditor.reset();
+                               mPropertyEditor.properties["rulervisible"] = 
TextInspectorController.Instance().rulerVisible;
+                               if 
(TextInspectorController.Instance().rulerVisible)
+                               {
+                                       var tab:ITabStopFormat = 
mSelectedMarker as ITabStopFormat;
+                                       if (!tab)
+                                               tab = mDefaultTabStop as 
ITabStopFormat;
+                                       if (tab)
+                                       {
+                                               
mPropertyEditor.properties["alignment"] = tab.alignment;
+                                               if (tab != mDefaultTabStop)
+                                                       
mPropertyEditor.properties["position"] = tab.position;
+                                               if (tab.alignment == 
flash.text.engine.TabAlignment.DECIMAL)
+                                                       
mPropertyEditor.properties["decimalAlignmentToken"] = tab.decimalAlignmentToken;
+                                       }
+                               }
+                               mPropertyEditor.rebuildUI();
+                       }
+               }
+               
+               private function 
onFormatValueChanged(e:PropertyChangeEvent):void
+               {
+                       if (mRightRuler)
+                       {
+                               var property:String = e.property as String;
+                               if (property == "rulervisible")
+                                       
TextInspectorController.Instance().rulerVisible = (e.newValue == "true" ? true 
: false);
+                               else
+                               {
+                                       if (e.type == 
DynamicPropertyEditorBase.MODELEDITED_EVENT)
+                                               mUpdateFromSelection = false;
+                                       var tab:Object = mSelectedMarker;
+                                       if (!tab)
+                                               tab = mDefaultTabStop;
+                                       var newValue:Object = e.newValue;
+                                       if (property == "position")
+                                               newValue = Number(newValue);
+                                       tab[property] = newValue;
+                                       if (property == "alignment" && newValue 
== flash.text.engine.TabAlignment.DECIMAL && tab["decimalAlignmentToken"] == 
null)
+                                               tab["decimalAlignmentToken"] = 
"";
+                                       if (mSelectedMarker)
+                                               setFormatFromRuler();
+                                       if (e.type == 
DynamicPropertyEditorBase.MODELCHANGED_EVENT)
+                                               mUpdateFromSelection = true;
+                                       updatePropertyEditor();
+                               }
+                       }
+               }
+
+               private function setFormatFromRuler():void
+               {
+                       var newTabs:Array = [];
+                       if (mSelectedMarker && mSelectedMarker.parent)
+                               newTabs.push(new TabStopFormat(mSelectedMarker 
as ITabStopFormat));
+                       var markers:Array = getChildren();
+                       for each (var marker:UIComponent in markers)
+                               if (marker is TabMarker)
+                               {
+                                       var tab:TabMarker = marker as TabMarker;
+                                       if (isUniquePosition(newTabs, tab.pos))
+                                               newTabs.push(new 
TabStopFormat(tab));
+                                       
+                               }
+                       newTabs.sortOn("position", Array.NUMERIC);
+                       var pa:TextLayoutFormat = new TextLayoutFormat();
+                       pa.tabStops = newTabs;
+                       mEditManager.applyParagraphFormat(pa);
+                       updatePropertyEditor();
+               }
+               
+               private static function isUniquePosition(inTabFormat:Array, 
inNewPosition:Number):Boolean
+               {
+                       for each (var tab:TabStopFormat in inTabFormat)
+                               if (tab.position == inNewPosition)
+                                       return false;
+                       return true;
+               }
+
+               public function set tabPanelActive(inActive:Boolean):void
+               {
+                       if (mTabPanelActive != inActive)
+                       {
+                               mTabPanelActive = inActive;
+                               if (mTabPanelActive)
+                                       updatePropertyEditor();
+                       }
+               }
+               
+               public function get tabPanelActive():Boolean
+               {
+                       return mTabPanelActive;
+               }
+               
+               public function get rightToLeft():Boolean
+               {
+                       return mRightToLeft;
+               }
+               
+               private function setRightToLeft(inRTL:Boolean):void
+               {
+                       if (inRTL != mRightToLeft)
+                       {
+                               mTabSet = null;
+                               mRightToLeft = inRTL;
+                               invalidateDisplayList();
+                       }
+               }
+               
+               private var mActive:Boolean = true;
+               private var mActiveFlow:TextFlow = null;
+               private var mEditManager:EditManager = null;
+               private var mTabSet:Array = null;
+               private var mSelectedMarker:RulerMarker = null;
+               private var mUpdateFromSelection:Boolean = true;
+               private var mDefaultTabStop:TabStopFormat;
+               private var mPropertyEditor:TabPropertyEditor = null;
+               private var mOrientation:String = RULER_HORIZONTAL;
+               private var mSyncToPanel:UIComponent = null;
+               private var mRightRuler:Boolean = true;
+               private var mLastSelAnchorIdx:int = -1;
+               private var mLastSelActiveIdx:int = -1;
+               private var mIndentMarker:ParagraphPropertyMarker = null;
+               private var mLeftMarginMarker:ParagraphPropertyMarker = null;
+               private var mRightMarginMarker:ParagraphPropertyMarker = null;
+               private var mTabPanelActive:Boolean = false;
+               private var mRightToLeft:Boolean = false;
+               private var curParagraphFormat:TextLayoutFormat = null;
+               
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerDragTracker.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerDragTracker.as
 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerDragTracker.as
new file mode 100644
index 0000000..042a92c
--- /dev/null
+++ 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerDragTracker.as
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package flashx.textLayout.ui.rulers
+{
+       import flash.events.MouseEvent;
+       import flash.geom.Point;
+       
+       import mx.core.UIComponent;
+       
+       import bxf.ui.toolkit.Tracker;
+
+       public class RulerDragTracker extends Tracker
+       {
+               public function RulerDragTracker(inPeerToTrackTo:UIComponent, 
inController:RulerBar, inCookie:Object, inDragThreshold:Number = 2)
+               {
+                       super(inPeerToTrackTo, 0, 0);
+                       mController = inController;
+                       mDragCookie = inCookie;
+                       mDragThreshold = inDragThreshold;
+               }
+               
+               /**     Override to get cursor adjust hook and mouse down. 
+                * @param inMouseEvent mouse info.
+                * @param inCursorAdjust true if this is a mouse up track.*/
+               override public function BeginTracking(inMouseEvent:MouseEvent, 
inCursorAdjust:Boolean):void
+               {
+                       super.BeginTracking(inMouseEvent, inCursorAdjust);
+               }
+               
+               /**     Override to get mouse move. 
+                * @param inMouseEvent mouse info.*/
+               override public function 
ContinueTracking(inMouseEvent:MouseEvent):void
+               {
+                       super.ContinueTracking(inMouseEvent);
+                       if (!mDragThresholdReached)
+                       {
+                               if (Point.distance(mAnchorPt, mTrackPt) >= 
mDragThreshold)
+                                       mDragThresholdReached = true;
+                       }
+                       if (mDragThresholdReached)
+                               mController.TrackDrag(mTrackPt, mDragCookie, 
false);
+                       inMouseEvent.stopPropagation();
+               }
+               
+               /**     Override to get mouse up. 
+                * @param inMouseEvent mouse info.*/
+               override public function 
EndTracking(inMouseEvent:MouseEvent):void
+               {
+                       super.EndTracking(inMouseEvent);
+                       if (mDragThresholdReached)
+                               mController.TrackDrag(mTrackPt, mDragCookie, 
true);
+                       else
+                               mController.DragCancelled();
+                       inMouseEvent.stopPropagation();
+               }
+               
+               override protected function TrackPoint(inMouseEvent:MouseEvent, 
inAlsoSetAnchor:Boolean): void
+               {
+                       mTrackPt.x = inMouseEvent.stageX;
+                       mTrackPt.y = inMouseEvent.stageY;
+                       mTrackPt = mController.globalToLocal(mTrackPt);
+                       if (inAlsoSetAnchor)
+                               mAnchorPt = mTrackPt.clone();
+               }
+
+               private var mController:RulerBar = null;
+               private var mDragCookie:Object = null;
+               private var mDragThreshold:Number;
+               private var mDragThresholdReached:Boolean = false;
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerMarker.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerMarker.as 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerMarker.as
new file mode 100644
index 0000000..7cc2848
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/RulerMarker.as
@@ -0,0 +1,124 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package flashx.textLayout.ui.rulers
+{
+       import mx.containers.Canvas;
+
+       public class RulerMarker extends Canvas
+       {
+               public function RulerMarker(inRuler:RulerBar, inWidth:Number, 
inHeight:Number, inHOffset:Number, inVOffset:Number, inPos:Number)
+               {
+                       super();
+                       width = inWidth;
+                       height = inHeight;
+                       mHOffset = inHOffset;
+                       mVOffset = inVOffset;
+                       mPos = inPos;
+                       mRuler = inRuler;
+               }
+               
+               override public function initialize():void
+               {
+                       super.initialize();
+                       positionMarker();
+               }
+               
+               protected function positionMarker():void
+               {
+                       if (parent)
+                       {
+                               if (alignToRight)
+                               {
+                                       x = parent.width - originPosition - pos 
+ hOffset;
+                                       y = parent.height - height + vOffset;
+                               }
+                               else
+                               {
+                                       x = originPosition + pos + hOffset;
+                                       y = parent.height - height + vOffset;
+                               }
+                       }
+               }
+               
+               protected function get alignToRight():Boolean
+               {
+                       return ruler.rightToLeft;
+               }
+               
+               protected function get originPosition():Number
+               {
+                       return 0;
+               }
+
+               public function set pos(inPos:Number):void
+               {
+                       mPos = inPos;
+                       positionMarker();
+               }
+               
+               public function get pos():Number
+               {
+                       return mPos;
+               }
+               
+               public function set hOffset(inOffset:Number):void
+               {
+                       mHOffset = inOffset;
+                       positionMarker();
+               }
+               
+               public function get hOffset():Number
+               {
+                       return mHOffset;
+               }
+               
+               public function set vOffset(inOffset:Number):void
+               {
+                       mVOffset = inOffset;
+                       positionMarker();
+               }
+               
+               public function get vOffset():Number
+               {
+                       return mVOffset;
+               }
+               
+               public function get ruler():RulerBar
+               {
+                       return mRuler;
+               }
+               
+               public function set markerLeft(inNewLeft:Number):void
+               {
+                       if (parent)
+                       {
+                               if (alignToRight)
+                                       pos = parent.width - (inNewLeft + 
hOffset > parent.width ? parent.width : inNewLeft + hOffset)  - originPosition;
+                               else
+                                       pos = (inNewLeft < 0 ? 0 : inNewLeft) - 
originPosition - hOffset;
+                       }
+               }
+
+               private var mPos:Number;
+               private var mHOffset:Number;
+               private var mVOffset:Number;
+               private var mRuler:RulerBar = null;
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/TabMarker.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/TabMarker.as 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/TabMarker.as
new file mode 100644
index 0000000..9b6a31e
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/TabMarker.as
@@ -0,0 +1,86 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package flashx.textLayout.ui.rulers
+{
+       import mx.messaging.management.Attribute;
+       
+       import flashx.textLayout.formats.ITabStopFormat;
+       
+       public class TabMarker extends RulerMarker implements ITabStopFormat
+       {
+               public function TabMarker(inRuler:RulerBar, 
tabAttrs:ITabStopFormat)
+               {
+                       super(inRuler, 9, 10, -4, 0, Number(tabAttrs.position));
+                       mTabKind = tabAttrs.alignment;
+                       mAlignmentToken = tabAttrs.decimalAlignmentToken;
+                       setStyle("tabkind", mTabKind);
+               }
+               
+               public function get alignment():*
+               {
+                       return mTabKind;
+               }
+               
+               public function set alignment(inAlignment:String):void
+               {
+                       mTabKind = inAlignment;
+                       setStyle("tabkind", mTabKind);
+               }
+               
+               public function get decimalAlignmentToken():*
+               {
+                       return mAlignmentToken;
+               }
+               
+               public function set decimalAlignmenyToken(inToken:String):void
+               {
+                       mAlignmentToken = inToken;
+               }
+               
+               public function set decimalAlignmentToken(inToken:String):void
+               {
+                       mAlignmentToken = inToken;
+               }
+               
+               public function get position():*
+               {
+                       return pos;
+               }
+               
+               public function set position(inPosition:Object):void
+               {
+                       pos = inPosition as Number;
+               }
+               
+               
+               public function isDifferentPosition(element:*, index:int, 
arr:Array):Boolean
+               {
+                       var other:TabMarker = element as TabMarker;
+                       if (other)
+                               return other.position != position;
+                       else
+                               return true;
+               }
+               
+
+               private var mTabKind:String;
+               private var mAlignmentToken:String = null;
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/TabMarkerSkin.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/TabMarkerSkin.as 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/TabMarkerSkin.as
new file mode 100644
index 0000000..a6c4aaf
--- /dev/null
+++ 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/rulers/TabMarkerSkin.as
@@ -0,0 +1,94 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package flashx.textLayout.ui.rulers
+{
+       import flash.text.engine.TabAlignment;
+       
+       import mx.skins.RectangularBorder;
+
+       public class TabMarkerSkin extends RectangularBorder
+       {
+               public function TabMarkerSkin()
+               {
+                       super();
+               }
+               
+               override protected function updateDisplayList(w:Number, 
h:Number):void
+               {
+                   super.updateDisplayList(w, h);
+                   
+                   var tabKind:String = getStyle("tabkind");
+                   
+                       graphics.clear();
+
+                   graphics.lineStyle(3, 0xffffff);
+                   drawOrnament(tabKind, w, h);
+                   graphics.lineStyle(1, 0x000000);
+                   drawOrnament(tabKind, w, h);
+                   
+                   if (tabKind == flash.text.engine.TabAlignment.DECIMAL)
+                   {
+                               graphics.beginFill(0x000000);
+                               graphics.drawCircle(w / 2 + 3, (h - w / 2) / 2, 
.75);
+                               graphics.endFill();
+                   }
+                   
+                       graphics.beginFill(0x000000);
+                       graphics.moveTo(0, h - w / 2);
+                       graphics.lineTo(w / 2, h);
+                       graphics.lineTo(w, h - w / 2);
+                       graphics.lineTo(0, h - w / 2);
+                       graphics.endFill();
+                       
+                   var selected:Boolean = getStyle("selected");
+                       graphics.lineStyle();
+               graphics.beginFill(0x0000ff, selected ? .3 : 0);
+               graphics.drawRect(0, 0, w, h);
+               graphics.endFill();
+               }
+
+               private function drawOrnament(inKind:String, w:Number, 
h:Number):void
+               {
+                       switch (inKind)
+                       {
+                       case flash.text.engine.TabAlignment.START:
+                               graphics.moveTo(w / 2, h - w / 2);
+                               graphics.lineTo(w / 2, 1);
+                               graphics.lineTo(w, 1);
+                               break;
+                       case flash.text.engine.TabAlignment.CENTER:
+                               graphics.moveTo(w / 2, h - w / 2);
+                               graphics.lineTo(w / 2, 0);
+                               break;
+                       case flash.text.engine.TabAlignment.END:
+                               graphics.moveTo(w / 2, h - w / 2);
+                               graphics.lineTo(w / 2, 1);
+                               graphics.lineTo(0, 1);
+                               break;
+                       case flash.text.engine.TabAlignment.DECIMAL:
+                               graphics.moveTo(w / 2, h - w / 2);
+                               graphics.lineTo(w / 2, 0);
+                               break;
+                       }
+               }
+               
+
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/PopupMenuSkin.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/PopupMenuSkin.as 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/PopupMenuSkin.as
new file mode 100644
index 0000000..78b3ccb
--- /dev/null
+++ 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/PopupMenuSkin.as
@@ -0,0 +1,70 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package flashx.textLayout.ui.styles
+{
+       import flash.filters.DropShadowFilter;
+       
+       import mx.skins.RectangularBorder;
+
+       public class PopupMenuSkin extends RectangularBorder
+       {
+               public function PopupMenuSkin()
+               {
+                       super();
+                       filters = [new DropShadowFilter(2, 90, 0x000000, .45, 
2, 2)];
+               }
+
+               override protected function 
updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void 
+               {
+                       super.updateDisplayList(unscaledWidth, unscaledHeight);
+                       
+                       if (getStyle("cornerRadius") != undefined)
+                               mCornerRadius = getStyle("cornerRadius");
+                       if (getStyle("backColor") != undefined)
+                               mBackColor = getStyle("backColor");
+                       if (getStyle("backAlpha") != undefined)
+                               mBackAlpha = getStyle("backAlpha");
+                       if (getStyle("lineColor") != undefined)
+                               mLineColor = getStyle("lineColor");
+                       if (getStyle("lineAlpha") != undefined)
+                               mLineAlpha = getStyle("lineAlpha");
+                       if (getStyle("lineWidth") != undefined)
+                               mLineWidth = getStyle("lineWidth");
+       
+                       graphics.clear();
+                       graphics.lineStyle(mLineWidth, mLineColor, mLineAlpha);
+                       graphics.beginFill(mBackColor, mBackAlpha);
+                       graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
+                       graphics.endFill();
+                               
+               }
+       
+               private var mCornerRadius:Number = 0;
+               private var mLineWidth:Number = 1;
+               private var mBackColor:uint = 0x1a1a1a;
+               private var mBackAlpha:Number = 0.9;
+               private var mLineColor:uint = 0xffffff;
+               private var mLineAlpha:Number = 0.15;
+
+
+       }
+       
+       
+}

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarDownArrowUpSkin.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarDownArrowUpSkin.as
 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarDownArrowUpSkin.as
new file mode 100644
index 0000000..f2c4e5e
--- /dev/null
+++ 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarDownArrowUpSkin.as
@@ -0,0 +1,45 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package flashx.textLayout.ui.styles
+{
+       import mx.skins.RectangularBorder;
+
+       public class ScrollbarDownArrowUpSkin extends RectangularBorder
+       {
+               public function ScrollbarDownArrowUpSkin()
+               {
+                       super();
+               }
+               
+               override public function get measuredWidth():Number
+               {
+                       return 13;
+               }
+               
+               override public function get measuredHeight():Number
+               {
+                       return 14;
+               }
+               
+               override protected function updateDisplayList(w:Number, 
h:Number):void
+               {
+                       super.updateDisplayList(w, h);
+               }
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarThumbOverSkin.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarThumbOverSkin.as
 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarThumbOverSkin.as
new file mode 100644
index 0000000..48aa83a
--- /dev/null
+++ 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarThumbOverSkin.as
@@ -0,0 +1,89 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package flashx.textLayout.ui.styles
+{
+       import mx.skins.RectangularBorder;
+       import mx.utils.GraphicsUtil;
+       import flash.display.LineScaleMode;
+       import flash.display.CapsStyle;
+       
+       public class ScrollbarThumbOverSkin extends RectangularBorder
+       {
+               public function ScrollbarThumbOverSkin()
+               {
+                       super();
+               }
+               
+               override public function get measuredWidth():Number
+               {
+                       return 11;
+               }
+               
+               override public function get measuredHeight():Number
+               {
+                       return 10;
+               }
+               
+               override protected function updateDisplayList(w:Number, 
h:Number):void
+               {
+                       super.updateDisplayList(w, h);
+                       
+                       var thumbFill:uint = 0x222222;
+                       var thumbFillAlpha:Number = 1.0;
+                       var thumbStroke:uint = 0x2A2A2A;
+                       var thumbStrokeAlpha:Number = 1.0;
+
+                       var trackStroke:uint = 0x2A2A2A;
+                       var trackStrokeAlpha:Number = 1.0;
+                                               
+                       if (getStyle("thumbOverFill") != undefined)
+                               thumbFill = getStyle("thumbOverFill");
+                       if (getStyle("thumbOverFillAlpha") != undefined)
+                               thumbFillAlpha = getStyle("thumbOverFillAlpha");
+                       if (getStyle("thumbOverStroke") != undefined)
+                               thumbStroke = getStyle("thumbOverStroke");
+                       if (getStyle("thumbOverStrokeAlpha") != undefined)
+                               thumbStrokeAlpha = 
getStyle("thumbOverStrokeAlpha");
+                       if (getStyle("trackStroke") != undefined)
+                               trackStroke = getStyle("trackStroke");
+                       if (getStyle("trackStrokeAlpha") != undefined)
+                               trackStrokeAlpha = getStyle("trackStrokeAlpha");
+
+                       graphics.clear();
+                       // draw the top line of the thumb to match the track
+                       graphics.lineStyle(1, trackStroke, trackStrokeAlpha);
+                       graphics.moveTo(0, 0);
+                       graphics.lineTo(w-1, 0);
+
+                       // fill in the thumb
+                       graphics.beginFill(thumbFill, thumbFillAlpha);
+                       graphics.drawRect(0, 0, w-1, h-2);
+                       graphics.endFill();
+                       
+                       // draw the border of the thumb
+                       graphics.lineStyle(1, thumbStroke, thumbStrokeAlpha);
+                       graphics.drawRect(0, 1, w-1, h-3);
+                       
+                       // draw the bottom line of the thumb to match the track
+                       graphics.lineStyle(1, trackStroke, trackStrokeAlpha);
+                       graphics.moveTo(0, h-1);
+                       graphics.lineTo(w, h-1);
+                       
+               }
+       }}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarThumbUpSkin.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarThumbUpSkin.as
 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarThumbUpSkin.as
new file mode 100644
index 0000000..450fd3a
--- /dev/null
+++ 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarThumbUpSkin.as
@@ -0,0 +1,89 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package flashx.textLayout.ui.styles
+{
+       import mx.skins.RectangularBorder;
+       import mx.utils.GraphicsUtil;
+       import flash.display.LineScaleMode;
+       import flash.display.CapsStyle;
+       
+       public class ScrollbarThumbUpSkin extends RectangularBorder
+       {
+               public function ScrollbarThumbUpSkin()
+               {
+                       super();
+               }
+               
+               override public function get measuredWidth():Number
+               {
+                       return 11;
+               }
+               
+               override public function get measuredHeight():Number
+               {
+                       return 10;
+               }
+               
+               override protected function updateDisplayList(w:Number, 
h:Number):void
+               {
+                       super.updateDisplayList(w, h);
+                       
+                       var thumbFill:uint = 0x222222;
+                       var thumbFillAlpha:Number = 1.0;
+                       var thumbStroke:uint = 0x2A2A2A;
+                       var thumbStrokeAlpha:Number = 1.0;
+
+                       var trackStroke:uint = 0x2A2A2A;
+                       var trackStrokeAlpha:Number = 1.0;
+                                               
+                       if (getStyle("thumbFill") != undefined)
+                               thumbFill = getStyle("thumbFill");
+                       if (getStyle("thumbFillAlpha") != undefined)
+                               thumbFillAlpha = getStyle("thumbFillAlpha");
+                       if (getStyle("thumbStroke") != undefined)
+                               thumbStroke = getStyle("thumbStroke");
+                       if (getStyle("thumbStrokeAlpha") != undefined)
+                               thumbStrokeAlpha = getStyle("thumbStrokeAlpha");
+                       if (getStyle("trackStroke") != undefined)
+                               trackStroke = getStyle("trackStroke");
+                       if (getStyle("trackStrokeAlpha") != undefined)
+                               trackStrokeAlpha = getStyle("trackStrokeAlpha");
+
+                       graphics.clear();
+                       // draw the top line of the thumb to match the track
+                       graphics.lineStyle(1, trackStroke, trackStrokeAlpha);
+                       graphics.moveTo(0, 0);
+                       graphics.lineTo(w-1, 0);
+
+                       // fill in the thumb
+                       graphics.beginFill(thumbFill, thumbFillAlpha);
+                       graphics.drawRect(0, 0, w-1, h-2);
+                       graphics.endFill();
+                       
+                       // draw the border of the thumb
+                       graphics.lineStyle(1, thumbStroke, thumbStrokeAlpha);
+                       graphics.drawRect(0, 1, w-1, h-3);
+                       
+                       // draw the bottom line of the thumb to match the track
+                       graphics.lineStyle(1, trackStroke, trackStrokeAlpha);
+                       graphics.moveTo(0, h-1);
+                       graphics.lineTo(w, h-1);
+                       
+               }
+       }}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarTrackSkin.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarTrackSkin.as
 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarTrackSkin.as
new file mode 100644
index 0000000..d822b91
--- /dev/null
+++ 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarTrackSkin.as
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package flashx.textLayout.ui.styles
+{
+       import flash.display.CapsStyle;
+       import flash.display.LineScaleMode;
+       
+       import mx.skins.RectangularBorder;
+
+       public class ScrollbarTrackSkin extends RectangularBorder
+       {
+               public function ScrollbarTrackSkin()
+               {
+                       super();
+               }
+               
+               override public function get measuredWidth():Number
+               {
+                       return 13;
+               }
+               
+               override public function get measuredHeight():Number
+               {
+                       return 10;
+               }
+               
+               override protected function updateDisplayList(w:Number, 
h:Number):void
+               {
+                       super.updateDisplayList(w, h);
+                       
+                       var trackFill:uint = 0x000000;
+                       var trackFillAlpha:Number = 1.0;
+                       var trackStroke:uint = 0x2A2A2A;
+                       var trackStrokeAlpha:Number = 1.0;
+                       
+                       if (getStyle("trackFill") != undefined)
+                               trackFill = getStyle("trackFill");
+                       if (getStyle("trackFillAlpha") != undefined)
+                               trackFillAlpha = getStyle("trackFillAlpha");
+                       if (getStyle("trackStroke") != undefined)
+                               trackStroke = getStyle("trackStroke");
+                       if (getStyle("trackStrokeInnerAlpha") != undefined)
+                               trackStrokeAlpha = getStyle("trackStrokeAlpha");
+
+                       graphics.clear();
+                       graphics.beginFill(trackFill, trackFillAlpha);
+                       graphics.drawRect(0, 0, w-1, h);
+                       graphics.endFill();
+                       graphics.lineStyle(1, trackStroke, trackStrokeAlpha, 
true, LineScaleMode.NONE, CapsStyle.SQUARE);
+                       graphics.drawRect(0, 0, w-1, h);
+               }
+       }}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarUpArrowUpSkin.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarUpArrowUpSkin.as
 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarUpArrowUpSkin.as
new file mode 100644
index 0000000..f9b66bc
--- /dev/null
+++ 
b/tourdeflexmodules/src/spark/tlf/flashx/textLayout/ui/styles/ScrollbarUpArrowUpSkin.as
@@ -0,0 +1,45 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package flashx.textLayout.ui.styles
+{
+       import mx.skins.RectangularBorder;
+
+       public class ScrollbarUpArrowUpSkin extends RectangularBorder
+       {
+               public function ScrollbarUpArrowUpSkin()
+               {
+                       super();
+               }
+               
+               override public function get measuredWidth():Number
+               {
+                       return 13;
+               }
+               
+               override public function get measuredHeight():Number
+               {
+                       return 14;
+               }
+               
+               override protected function updateDisplayList(w:Number, 
h:Number):void
+               {
+                       super.updateDisplayList(w, h);
+               }
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/textEditBar/FeatureSetChangeEvent.as
----------------------------------------------------------------------
diff --git 
a/tourdeflexmodules/src/spark/tlf/textEditBar/FeatureSetChangeEvent.as 
b/tourdeflexmodules/src/spark/tlf/textEditBar/FeatureSetChangeEvent.as
new file mode 100644
index 0000000..811dd37
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/textEditBar/FeatureSetChangeEvent.as
@@ -0,0 +1,42 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 textEditBar
+{
+import flash.events.Event;
+import flashx.textLayout.elements.TextFlow;
+
+public class FeatureSetChangeEvent extends Event
+{
+       public const FEATURE_SET:String = "featureSet";
+       
+       public var featureSet:String;
+
+       public function FeatureSetChangeEvent(newFeatureSet:String, type:String 
= FEATURE_SET,
+                                                         bubbles:Boolean = 
false,
+                                                         cancelable:Boolean = 
false)
+       {
+               super(type, bubbles, cancelable);
+               featureSet = newFeatureSet;
+       }
+       override public function clone():Event
+       {
+               return new FeatureSetChangeEvent(featureSet, type, bubbles, 
cancelable);
+       }
+}              // end class
+}

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/textEditBar/FileEvent.as
----------------------------------------------------------------------
diff --git a/tourdeflexmodules/src/spark/tlf/textEditBar/FileEvent.as 
b/tourdeflexmodules/src/spark/tlf/textEditBar/FileEvent.as
new file mode 100644
index 0000000..4832d1f
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/textEditBar/FileEvent.as
@@ -0,0 +1,43 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 textEditBar
+{
+import flash.events.Event;
+import flash.net.FileReference;
+
+public class FileEvent extends Event
+{
+       public var fileName:FileReference;
+       
+       public const FILE_CHOOSE:String = "fileChoose";
+
+       public function FileEvent(newFileName:FileReference, type:String = 
FILE_CHOOSE,
+                                                         bubbles:Boolean = 
false,
+                                                         cancelable:Boolean = 
false)
+       {
+               super(type, bubbles, cancelable);
+               fileName = newFileName;
+       }
+       
+       override public function clone():Event
+       {
+               return new FileEvent(fileName, type, bubbles, cancelable);
+       }
+}              // end class
+}              // end package
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/textEditBar/FileIOHelper.as
----------------------------------------------------------------------
diff --git a/tourdeflexmodules/src/spark/tlf/textEditBar/FileIOHelper.as 
b/tourdeflexmodules/src/spark/tlf/textEditBar/FileIOHelper.as
new file mode 100644
index 0000000..1d239bc
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/textEditBar/FileIOHelper.as
@@ -0,0 +1,268 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 textEditBar
+{
+       import flash.display.DisplayObject;
+       import flash.events.Event;
+       import flash.events.IOErrorEvent;
+       import flash.net.FileReference;
+       
+       import flashx.textLayout.conversion.ConversionType;
+       import flashx.textLayout.conversion.ITextExporter;
+       import flashx.textLayout.conversion.ITextImporter;
+       import flashx.textLayout.conversion.TextConverter;
+       import flashx.textLayout.debug.assert;
+       import flashx.textLayout.elements.TextFlow;
+       
+       import mx.managers.CursorManager;
+       import mx.managers.PopUpManager;
+       import mx.rpc.events.ResultEvent;
+       import mx.rpc.http.mxml.HTTPService;
+       
+       import textEditBar.StatusPopup;
+       
+       public class FileIOHelper
+       {
+               static public var parentWindow:DisplayObject;
+               static public var changeContent:Function;
+
+               static private var _openedFile:String;
+               
+               // called when the app has a specific file it wants to read (at 
startup)
+               static public function fileOpen(fileName:String):void
+               {
+                       var localHTTP:HTTPService = new HTTPService();
+                       localHTTP.url = fileName;
+                       _openedFile = fileName;
+                       localHTTP.method = "GET";
+                       localHTTP.resultFormat="text"
+                       localHTTP.showBusyCursor=true;
+                       
localHTTP.addEventListener(ResultEvent.RESULT,parseIntoFlowFromHTTP,false,0,true);
+                       
localHTTP.addEventListener(IOErrorEvent.IO_ERROR,errorOnReadFromHTTP,false,0,true);
+                       localHTTP.send();
+               }
+
+               // called when user picks a file
+               static public function fileChoose(fileName:FileReference) : void
+               {
+                       
fileName.addEventListener(Event.COMPLETE,onFileReferenceLoadComplete,false,0,true);
+                       
fileName.addEventListener(IOErrorEvent.IO_ERROR,errorOnReadFromFileReference,false,0,true);
+                       fileName.load();
+               }
+               
+               static private function 
onFileReferenceLoadComplete(event:Event):void
+               {
+                       var fileReference:FileReference = 
FileReference(event.target);
+                       _extension= 
getExtension(fileReference.name).toLowerCase();
+                       _fileData = String(fileReference.data);
+                       parseCurrentDataWithExtension();
+               }
+
+               static private function 
errorOnReadFromFileReference(event:IOErrorEvent):void
+        {
+               var curFileReference:FileReference = 
FileReference(event.target);
+               // Text content will be an error string
+                       var errorString:String = "Error reading file " + 
curFileReference.name;
+                       errorString += "\n";
+                       errorString += event.toString();
+                       _extension = "txt";
+                       _fileData = errorString;
+                       parseCurrentDataWithExtension();
+                       //CursorManager.removeBusyCursor(); //get rid of 
hourglass cursor.                      
+               }
+               
+               static private function 
parseIntoFlowFromHTTP(event:ResultEvent):void 
+               {
+                       _fileData = String(event.result);
+                       _extension = getExtension(_openedFile).toLowerCase();
+                       parseCurrentDataWithExtension();
+                       _openedFile = null;
+               }
+               
+               static private function errorOnReadFromHTTP(event:Object):void
+               {
+                       // Text content will be an error string
+                       var errorString:String = "Error reading file " + 
_openedFile;
+                       errorString += "\n";
+                       errorString += event.fault;
+                       _extension = "txt";
+                       _fileData = errorString;
+                       parseCurrentDataWithExtension();
+                       CursorManager.removeBusyCursor(); //get rid of 
hourglass cursor. 
+                       _openedFile = null;
+               }
+               
+               static private function getExtension(fileName:String):String
+               {
+                       var dotPos:int = fileName.lastIndexOf(".");
+                       if (dotPos >= 0)
+                               return fileName.substring(dotPos + 1);
+                       return fileName;
+               }
+               
+               // hold onto these two in case we need to recreate textFlow
+               static private var _extension:String;
+               static private var _fileData:String;
+               
+               static public function parseCurrentDataWithExtension():void
+               {
+                       switch (_extension)
+                       {
+                               case "xml":             // use Vellum markup
+                                       parseStringIntoFlow(_fileData, 
TextConverter.TEXT_LAYOUT_FORMAT);
+                                       break;
+                               case "txt":
+                                       parseStringIntoFlow(_fileData, 
TextConverter.PLAIN_TEXT_FORMAT);
+                                       break;
+                               case "html":
+                                       parseStringIntoFlow(_fileData, 
TextConverter.TEXT_FIELD_HTML_FORMAT);
+                                       break;
+
+                       }
+               }
+                               
+               static private function parseStringIntoFlow(source:String, 
format:String):void
+               {
+                       var textImporter:ITextImporter = 
TextConverter.getImporter(format);
+                       var newFlow:TextFlow = 
textImporter.importToFlow(source);
+                       reportImportErrors(textImporter.errors);
+                       // no TextFlow found - Flow will display an empty 
TextFlow by design 
+                       // - alternative is to do some kind of error string
+                       changeContent(newFlow ? newFlow : new TextFlow());
+               } 
+               
+               static private function 
reportImportErrors(errors:Vector.<String>):void
+               {
+                       if (errors)
+                       {
+                               var errorText:String = "ERRORS REPORTED ON 
IMPORT";
+                               for each(var e:String in errors)
+                                       errorText += "\n" + e;
+                                       
+                               var dlg:StatusPopup = new StatusPopup();
+                               dlg.closeFunction = closeStatusPopup;
+
+                               PopUpManager.addPopUp(dlg, parentWindow, true);
+                               PopUpManager.centerPopUp(dlg);
+                               // stick it in the upper left
+                               dlg.x = 0;
+                               dlg.y = 0;
+                       
+                               dlg.textArea.text = errorText;
+                       }
+               }
+               static private function closeStatusPopup(dlg:StatusPopup):void
+               {
+                       PopUpManager.removePopUp(dlg);
+               }
+                       
+               static private function 
importStatusPopupContent(dlg:StatusPopup):void
+               {
+                       switch(dlg.textFormat)
+                       {
+                               case TextConverter.TEXT_LAYOUT_FORMAT:
+                                       _extension = "xml";
+                                       break;
+                               case TextConverter.TEXT_FIELD_HTML_FORMAT:
+                                       _extension = "html";
+                                       break;
+                       }
+                       _fileData = dlg.textArea.text;
+                       parseCurrentDataWithExtension();
+                       PopUpManager.removePopUp(dlg);
+               }
+               
+               static private function 
saveStatusPopupContent(dlg:StatusPopup):void
+               {
+                       var extension:String;
+                       switch(dlg.textFormat)
+                       {
+                               case TextConverter.TEXT_LAYOUT_FORMAT:
+                                       extension = "xml";
+                                       break;
+                               case TextConverter.TEXT_FIELD_HTML_FORMAT:
+                                       extension = "html";
+                                       break;
+                       }
+                       
+                       var fileReference:FileReference = new FileReference();
+                       fileReference.save(dlg.textArea.text,extension == null 
? null : "NewFile."+extension);
+               }
+               
+
+
+               // Export related code
+               static public function textLayoutExport(activeFlow:TextFlow) : 
void
+               {               
+                       export(activeFlow, TextConverter.TEXT_LAYOUT_FORMAT);
+               }
+
+
+               static public function htmlExport(activeFlow:TextFlow) : void
+               {
+                       export(activeFlow, 
TextConverter.TEXT_FIELD_HTML_FORMAT);
+               }
+
+               static private const xmlBoilerPlate:String = '<?xml 
version="1.0" encoding="utf-8"?>\n';
+                                                                               
+               static public function export(activeFlow:TextFlow, 
format:String) : void
+               {
+                       //CONFIG::debug
+                       {       
+                               var originalSettings:Object = XML.settings();
+                               try
+                               {
+                                       XML.ignoreProcessingInstructions = 
false;               
+                                       XML.ignoreWhitespace = false;
+                                       XML.prettyPrinting = false;
+                                       
+                                       
+                                       var exporter:ITextExporter = 
TextConverter.getExporter(format);
+                                       var xmlExport:XML = 
exporter.export(activeFlow, ConversionType.XML_TYPE) as XML;
+                                       var result:String = xmlBoilerPlate + 
xmlExport;                                 
+                                       XML.setSettings(originalSettings);
+                               }
+                               
+                               catch(e:Error)
+                               {
+                                       XML.setSettings(originalSettings);
+                                       throw(e);
+                               }
+                       }
+                       
+                       // show it in the pop-up dialog
+                       var dlg:StatusPopup = new StatusPopup();
+                       dlg.closeFunction = closeStatusPopup;
+                       dlg.importFunction = importStatusPopupContent;
+                       dlg.saveFunction   = saveStatusPopupContent;
+                       dlg.textFormat = format;
+                       
+                       PopUpManager.addPopUp(dlg, parentWindow, true);
+                       PopUpManager.centerPopUp(dlg);
+                       // stick it in the upper left
+                       dlg.x = 0;
+                       dlg.y = 0;
+       
+                       dlg.textArea.text = result.replace(/\u000D\u000A/g, 
"\r"); // workaround for TextArea bug SDK-14797
+               }
+               
+
+
+       }
+}

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/textEditBar/FileServices.mxml
----------------------------------------------------------------------
diff --git a/tourdeflexmodules/src/spark/tlf/textEditBar/FileServices.mxml 
b/tourdeflexmodules/src/spark/tlf/textEditBar/FileServices.mxml
new file mode 100644
index 0000000..58e740b
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/textEditBar/FileServices.mxml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+
+<!--This widget allows the user to enter a file name and when the "ReadFile" 
button is pressed, it 
+reads the file, and passes through the file contents as a ContentEvent. It 
expects an XML file in
+TextLayout format.-->
+
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"; xmlns="*" 
creationComplete="handleCreationComplete()" >
+       <mx:Metadata>
+       [Event(name="fileChoose", type="textEditBar.FileEvent")]
+       [Event(name="textLayoutExport", type="flash.events.Event")]
+       [Event(name="htmlExport", type="flash.events.Event")]
+       </mx:Metadata>
+
+  <mx:Script>
+               <![CDATA[
+                       import flash.events.Event;
+                       import flash.system.Capabilities;
+                       import flashx.textLayout.elements.TextFlow;
+                       import mx.events.MenuEvent;
+                       import mx.controls.Alert;
+                       import flashx.textLayout.edit.EditingMode;
+                       import flashx.textLayout.edit.ElementRange;
+                       import flashx.textLayout.edit.ISelectionManager;
+                       import flashx.textLayout.edit.IEditManager;
+                       import flashx.textLayout.BuildInfo;
+                       
+                       public var activeFlow:TextFlow;
+                       
+                       [Bindable]
+                       public var buildString:String = "Build: " + 
BuildInfo.kBuildNumber + "(" + Capabilities.version + ")";
+
+                       internal function handleCreationComplete():void
+                       {
+                               buildLabel.left = (this.x + this.width - 20) - 
buildLabel.width;
+                       }
+                       // Update UI panel in response to change in selection
+                       public function update(range:ElementRange):void
+                       {
+                               if (!activeFlow)
+                                       return;
+                                       
+                       }
+                       
+                       private var fileReference:FileReference;
+                       
+                       public function currentFileName():String
+                       {
+                               return fileReference != null ? 
fileReference.name : null;
+                       }
+                       
+                       public function openDialog():void
+                       {
+                               var markupFilter:FileFilter = new 
FileFilter("Documents","*.xml;*.fxg;*.html");
+                               fileReference = new FileReference();
+                               fileReference.browse([markupFilter]);
+                               
fileReference.addEventListener(Event.SELECT,onFileSelect);
+                       }
+                       
+                       private function onFileSelect(event:Event):void 
+                       {
+                               try {
+                                       dispatchEvent(new 
FileEvent(fileReference));
+                                       //fileReference.load();
+                               } catch (err:Event) {
+                                       Alert.show(err.toString());
+                               }
+                       }
+                  
+           ]]>
+    </mx:Script>
+
+       <mx:Button label="Open..." click="openDialog()"/>
+               
+       <mx:Button id="textLayoutExportButton" label="Markup..." 
click="dispatchEvent(new Event('textLayoutExport'))"/>
+       <mx:Button id="htmlExportButton" label="HTML Markup..." 
click="dispatchEvent(new Event('htmlExport'))"/>
+
+       <mx:Label id="buildLabel" text="{buildString}" fontWeight="bold" 
paddingTop="3" paddingBottom="1"/>
+</mx:HBox>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/textEditBar/GraphicBar.mxml
----------------------------------------------------------------------
diff --git a/tourdeflexmodules/src/spark/tlf/textEditBar/GraphicBar.mxml 
b/tourdeflexmodules/src/spark/tlf/textEditBar/GraphicBar.mxml
new file mode 100644
index 0000000..9d5d2fb
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/textEditBar/GraphicBar.mxml
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"; 
xmlns:textEditBar="textEditBar.*" 
+       addedToStage="onAddedToStage()" removedFromStage="onRemovedFromStage()" 
horizontalScrollPolicy="off" verticalScrollPolicy="off">
+       
+       <mx:Script>
+               <![CDATA[
+                       import flashx.textLayout.edit.ElementRange;
+                       import flashx.textLayout.edit.IEditManager;
+                       import flashx.textLayout.elements.InlineGraphicElement;
+                       import flashx.textLayout.elements.TextFlow;
+                       import flashx.textLayout.formats.FormatValue;
+                       import flashx.textLayout.tlf_internal;
+                       
+                       use namespace tlf_internal;
+                       
+                       public var activeFlow:TextFlow;
+                       
+                       protected function applyChange():void
+                       {
+                               changeForeignElement(imageURL.text, 
imageWidth.text, imageHeight.text, "none", doChangeImage);                      
    
+                       }
+                       
+                       protected function 
changeForeignElement(foreignElementUrl:String, width:String, height:String, 
float:String, changeCurrent:Boolean):void
+                       {
+                               if (activeFlow && activeFlow.interactionManager 
is IEditManager)
+                               {
+                                       if (changeCurrent)
+                                               
IEditManager(activeFlow.interactionManager).modifyInlineGraphic(foreignElementUrl,
 width, height, float);
+                                       else
+                                               
IEditManager(activeFlow.interactionManager).insertInlineGraphic(foreignElementUrl,
 width, height, float);
+                                       
activeFlow.interactionManager.setFocus();
+                               }
+                       }
+               
+                       protected var doChangeImage:Boolean = false;
+                       
+                       public function update(range:ElementRange):void
+                       {
+                               if (onStage)
+                               {
+                                       if (range ==  null)
+                                               visible = false;
+                                       else
+                                       {
+                                               if (!visible)
+                                                       visible = true;
+
+                                               var 
makeItTheChangeButton:Boolean = false;
+                                               
+                                               // this logic is a complicated 
by the fact that we extend the end of the selection because the FE is at the 
end of the paragraph
+                                               if (range && range.firstLeaf is 
InlineGraphicElement && range.absoluteStart == 
range.firstLeaf.getAbsoluteStart())
+                                               {
+                                                       // two cases just the 
FE and just the FE plus the paragraph terminator
+                                                       if (range.absoluteEnd 
== range.absoluteStart+1 || (range.firstParagraph == range.lastParagraph && 
range.absoluteEnd == range.absoluteStart+2 && range.absoluteEnd == 
range.lastParagraph.getAbsoluteStart() + range.lastParagraph.textLength))
+                                                               
makeItTheChangeButton = true; 
+                                               }
+                                               
+                                               // block selection of just the 
FE
+                                               if (makeItTheChangeButton)
+                                                       
updateForChange(InlineGraphicElement(range.firstLeaf));
+                                               else
+                                                       updateForInsert(range)
+                                       }
+                               }
+                               lastRange = range;      
+                       }
+                       
+                       protected function 
updateForChange(inlineElement:InlineGraphicElement):void
+                       {
+                               var sourceString:String = 
inlineElement.source.toString()
+                               var widthString:String = inlineElement.width 
=== undefined ? FormatValue.AUTO : inlineElement.width.toString();
+                               var heightString:String = inlineElement.height 
=== undefined ? FormatValue.AUTO : inlineElement.height.toString();
+                               doUpdate(sourceString, widthString, 
heightString, true, true);
+                       }
+                       
+                       protected function 
updateForInsert(range:ElementRange):void
+                       {
+                               doUpdate("", 
+                                       
InlineGraphicElement.tlf_internal::widthPropertyDefinition.defaultValue.toString(),
+                                       
InlineGraphicElement.tlf_internal::heightPropertyDefinition.defaultValue.toString(),
+                                       false, range && range.firstLeaf);
+                       }
+                       
+                       private function doUpdate(url:String, width:String, 
height:String, modify:Boolean, enableImage:Boolean):void
+                       {
+                               imageURL.text = url;
+                               imageWidth.text = width;
+                               imageHeight.text = height;
+                               imageButton.label = modify ? "Change" : 
"Insert";
+                               doChangeImage = modify;
+                               imageButton.enabled = enableImage;              
        
+                       }
+
+                       private var onStage:Boolean = false;
+                       private var addedFrameEventListener:Boolean = false;
+                       protected var lastRange:ElementRange = null;
+                       private function onAddedToStage():void
+                       {
+                               // the dataProviders aren't set up yet - delay 
to the frame
+                               onStage = true;
+                               if (!addedFrameEventListener)
+                               {
+                                       addedFrameEventListener = true;
+                                       
addEventListener("enterFrame",onEnterFrame);
+                               }
+                       }
+                               
+                       private function onEnterFrame(p:Event):void
+                       {
+                               
this.removeEventListener("enterFrame",onEnterFrame);
+                               addedFrameEventListener = false;        
+                               
+                               var temp:ElementRange = lastRange;
+                               lastRange = null;
+                               update(temp);
+                                       
+                       }
+                       
+                       private function onRemovedFromStage():void
+                       {
+                               onStage = false;
+                       }
+               ]]>
+       </mx:Script>
+
+       <mx:Label text="Image URL:" fontWeight="bold"/>
+       <mx:TextInput id="imageURL" width="140"/>
+       <mx:Label text="Width:" fontWeight="bold"/>
+       <mx:TextInput id="imageWidth" width="60"/>
+       <mx:Label text="Height:" fontWeight="bold"/>
+       <mx:TextInput id="imageHeight" width="60"/>                     
+       <mx:Button id="imageButton" label="Insert Image" 
+               click="applyChange()" />
+</mx:HBox>

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/textEditBar/GraphicChangeEvent.as
----------------------------------------------------------------------
diff --git a/tourdeflexmodules/src/spark/tlf/textEditBar/GraphicChangeEvent.as 
b/tourdeflexmodules/src/spark/tlf/textEditBar/GraphicChangeEvent.as
new file mode 100644
index 0000000..0128881
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/textEditBar/GraphicChangeEvent.as
@@ -0,0 +1,61 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 textEditBar
+{
+       import flash.events.Event;
+       
+       public class GraphicChangeEvent extends Event
+       {
+               private var _imageLink:String;
+               private var _imageWidth:Object;
+               private var _imageHeight:Object;
+               private var _float:String;
+               private var _replaceCurrent:Boolean;    
+               
+               public function GraphicChangeEvent(type:String, 
imageLink:String, imageWidth:Object, imageHeight:Object, float:String, 
replaceCurrent:Boolean = false, bubbles:Boolean=false, cancelable:Boolean=false)
+               {
+                       _imageLink = imageLink;
+                       _imageWidth = imageWidth;
+                       _imageHeight = imageHeight;
+                       _replaceCurrent = replaceCurrent;
+                       _float = float;
+                       super(type, bubbles, cancelable);
+               }
+               
+               override public function clone():Event
+               {
+                       return new GraphicChangeEvent(type, _imageLink, 
_imageWidth, _imageHeight, _float, _replaceCurrent, bubbles, cancelable);
+               }
+               
+               public function get imageLink():String
+               { return _imageLink; }          
+               
+               public function get imageWidth():Object
+               { return _imageWidth; }
+               
+               public function get imageHeight():Object
+               { return _imageHeight; }
+               
+               public function get float():String
+               { return _float; }
+               
+               public function get replaceCurrent():Boolean
+               { return _replaceCurrent; }
+       }
+}

http://git-wip-us.apache.org/repos/asf/flex-examples/blob/9343d391/tourdeflexmodules/src/spark/tlf/textEditBar/LinkBar.mxml
----------------------------------------------------------------------
diff --git a/tourdeflexmodules/src/spark/tlf/textEditBar/LinkBar.mxml 
b/tourdeflexmodules/src/spark/tlf/textEditBar/LinkBar.mxml
new file mode 100644
index 0000000..bdcbcd8
--- /dev/null
+++ b/tourdeflexmodules/src/spark/tlf/textEditBar/LinkBar.mxml
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+
+<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml"; 
xmlns:textEditBar="textEditBar.*"
+               addedToStage="onAddedToStage()" 
removedFromStage="onRemovedFromStage()">
+       
+       <mx:Array id="targetArray"> 
+               <mx:String>_blank</mx:String>
+               <mx:String>_self</mx:String>
+               <mx:String>_parent</mx:String>
+               <mx:String>_top</mx:String>
+       </mx:Array>     
+       
+       <mx:Script>
+               <![CDATA[
+                   import mx.controls.Alert;
+                       import flashx.textLayout.edit.ElementRange;
+                       import flashx.textLayout.edit.IEditManager;
+                       import flashx.textLayout.elements.LinkElement;
+                       import flashx.textLayout.elements.FlowElement;
+                       import flashx.textLayout.elements.ParagraphElement;
+                       import flashx.textLayout.events.FlowElementMouseEvent;
+                       import flashx.textLayout.elements.TextFlow;
+                       
+                       public var activeFlow:TextFlow;
+                       
+                       private function changeLink(urlText:String, 
targetText:String, extendToOverlappingLinks:Boolean):void
+                       {
+                               if (activeFlow && activeFlow.interactionManager 
is IEditManager)
+                               {
+                                       
IEditManager(activeFlow.interactionManager).applyLink(urlText, targetText, 
extendToOverlappingLinks);                   
+                                       
activeFlow.interactionManager.setFocus();
+                               }
+                       }
+               
+                   private var onStage:Boolean = false;
+               private var addedFrameEventListener:Boolean = false;
+               private var lastRange:ElementRange;
+               
+                       private function onAddedToStage():void
+                       {
+                               // the dataProviders aren't set up yet - delay 
to the frame
+                               onStage = true;
+                               if (!addedFrameEventListener)
+                               {
+                                       addedFrameEventListener = true;
+                                       
addEventListener("enterFrame",onEnterFrame);
+                               }
+                       }
+               
+                       private function onEnterFrame(p:Event):void
+                       {
+                               
this.removeEventListener("enterFrame",onEnterFrame);
+                               addedFrameEventListener = false;
+                       
+                               update(lastRange);
+                       }
+       
+                       private function onRemovedFromStage():void
+                       {
+                               onStage = false;
+                       }               
+
+                       protected function setTargetCombo(val:String):void
+                       {
+                               var length:uint = 
linkTargetCombo.dataProvider.length;
+               
+                               for (var i:uint = 0; i < length; i++)
+                               {
+                                       if 
(linkTargetCombo.dataProvider.getItemAt(i).toLowerCase() == val.toLowerCase())
+                                       {
+                                               linkTargetCombo.selectedIndex = 
i;
+                                               return;
+                                       }
+                               }
+                               linkTargetCombo.selectedIndex = -1;
+                               linkTargetCombo.validateNow();
+                               linkTargetCombo.text = val;
+                       }
+                                       
+                       public function update(range:ElementRange):void
+                       {
+                               if (!range)
+                               {
+                                       if (onStage)
+                                               visible = false;
+                                       lastRange = null;
+                                       return;
+                               }
+                               
+                               var linkString:String = "";
+                               var linkTarget:String = "";
+                               var linkEl:LinkElement = 
range.firstLeaf.getParentByType(LinkElement) as LinkElement;
+                               if (linkEl != null)
+                               {
+                                       var linkElStart:int = 
linkEl.getAbsoluteStart();
+                                       var linkElEnd:int = linkElStart + 
linkEl.textLength;
+                                       if (linkElEnd < linkElStart)
+                                       {
+                                               var temp:int = linkElStart;
+                                               linkElStart = linkElEnd;
+                                               linkElEnd = temp;
+                                       }
+                                       
+                                       var beginRange:int = 
range.absoluteStart;
+                                       var endRange:int = range.absoluteEnd;
+                                       
+                                       var beginPara:ParagraphElement = 
range.firstParagraph;
+                                       if (endRange == 
(beginPara.getAbsoluteStart() + beginPara.textLength))
+                                       {
+                                               endRange--;
+                                       }
+                                       
+                                       if ((beginRange == endRange) || 
(endRange <= linkElEnd))
+                                       {
+                                               linkString = 
LinkElement(linkEl).href;
+                                               linkTarget = 
LinkElement(linkEl).target;
+                                       }
+                               }
+                               
+                               if (onStage)
+                               {
+                                       if (!visible)
+                                               visible = true;
+                                       linkTextInput.text = linkString ? 
linkString : "";
+                                       setTargetCombo(linkTarget ? linkTarget 
: "");
+                               }
+                               lastRange = range;
+                       }                       
+               ]]>
+       </mx:Script>
+
+       <mx:Label text="Link Url:" fontWeight="bold"/>
+       <mx:TextInput id="linkTextInput" width="140"/>
+       <mx:Label text="Link Target:" fontWeight="bold"/>
+       <mx:ComboBox id="linkTargetCombo" editable="true"
+               selectedIndex="0" dataProvider = "{targetArray}"/>
+       <mx:CheckBox id = "linkExtendCheckBox" label="Extend"/>
+       <mx:Button label="Apply Link" 
+               click="changeLink(linkTextInput.text, linkTargetCombo.text, 
linkExtendCheckBox.selected)" />
+</mx:HBox>

Reply via email to