| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.operations |
| { |
| |
| import flashx.textLayout.debug.assert; |
| import flashx.textLayout.edit.ElementRange; |
| import flashx.textLayout.edit.ParaEdit; |
| import flashx.textLayout.edit.PointFormat; |
| import flashx.textLayout.edit.SelectionState; |
| import flashx.textLayout.elements.ParagraphElement; |
| import flashx.textLayout.elements.TextFlow; |
| import flashx.textLayout.formats.Category; |
| import flashx.textLayout.formats.ITextLayoutFormat; |
| import flashx.textLayout.formats.TextLayoutFormat; |
| import flashx.textLayout.property.Property; |
| import flashx.textLayout.tlf_internal; |
| |
| use namespace tlf_internal; |
| |
| /** |
| * The ApplyFormatOperation class encapsulates a style change. |
| * |
| * <p>An ApplyFormatOperation applies the leaf format to the text in the |
| * specified range (no change is made if the specified range is a single point). |
| * It applies the paragraph format to any paragraphs at least partially within the range |
| * (or a single paragraph if the range is a single point). |
| * And it applies the container format to any containers at least partially within the range |
| * (or a single container if the range is a single point).</p> |
| * |
| * @see flashx.textLayout.edit.EditManager |
| * @see flashx.textLayout.events.FlowOperationEvent |
| * |
| * @includeExample examples\ApplyFormatOperation_example.as -noswf |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public class ApplyFormatOperation extends FlowTextOperation |
| { |
| private var applyLeafFormat:ITextLayoutFormat; |
| private var applyParagraphFormat:ITextLayoutFormat; |
| private var applyContainerFormat:ITextLayoutFormat; |
| |
| // helper array of styles to revert |
| // each entry has a begIdx, endIdx, ContainerFormat |
| private var undoLeafArray:Array; |
| private var undoParagraphArray:Array; |
| private var undoContainerArray:Array; |
| |
| /** |
| * Creates an ApplyFormatOperation object. |
| * |
| * @param operationState Defines the text range to which the format is applied. |
| * @param leafFormat The format to apply to LeafFlowElement objects in the selected range. |
| * @param paragraphFormat The format to apply to ParagraphElement objects in the selected range. |
| * @param containerFormat The format to apply to containers in the selected range. |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function ApplyFormatOperation(operationState:SelectionState, leafFormat:ITextLayoutFormat, paragraphFormat:ITextLayoutFormat, containerFormat:ITextLayoutFormat = null) |
| { |
| super(operationState); |
| this.leafFormat = leafFormat; |
| this.paragraphFormat = paragraphFormat; |
| this.containerFormat = containerFormat; |
| } |
| |
| /** |
| * The format properties to apply to the leaf elements in the range. |
| * |
| * <p>If the range of this operation is a point, or if <code>leafFormat</code> is <code>null</code>, |
| * then no leaf element formats are changed.</p> |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function get leafFormat():ITextLayoutFormat |
| { |
| return applyLeafFormat; |
| } |
| public function set leafFormat(value:ITextLayoutFormat):void |
| { |
| applyLeafFormat = value ? new TextLayoutFormat(value) : null; |
| } |
| |
| /** |
| * The format properties to apply to the paragraphs in the range. |
| * |
| * <p>The formats of any paragraphs at least partially within the range are updated. |
| * If the range of this operation is a point, then a single paragraph is updated. |
| * If <code>paragraphFormat</code> is <code>null</code>, then no paragraph formats are changed.</p> |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function get paragraphFormat():ITextLayoutFormat |
| { |
| return applyParagraphFormat; |
| } |
| public function set paragraphFormat(value:ITextLayoutFormat):void |
| { |
| applyParagraphFormat = value ? new TextLayoutFormat(value) : null; |
| } |
| |
| /** |
| * The format properties to apply to the containers in the range. |
| * |
| * <p>The formats of any containers at least partially within the range are updated. |
| * If the range of this operation is a point, then a single container is updated. |
| * If <code>containerFormat</code> is <code>null</code>, then no container formats are changed.</p> |
| * |
| * @playerversion Flash 10 |
| * @playerversion AIR 1.5 |
| * @langversion 3.0 |
| */ |
| public function get containerFormat():ITextLayoutFormat |
| { |
| return applyContainerFormat; |
| } |
| public function set containerFormat(value:ITextLayoutFormat):void |
| { |
| applyContainerFormat = value ? new TextLayoutFormat(value) : null; |
| } |
| |
| private function doInternal():SelectionState |
| { |
| var anyNewSelectionState:SelectionState; |
| |
| // Apply character format |
| if (applyLeafFormat) |
| { |
| var begSel:int = absoluteStart; |
| var endSel:int = absoluteEnd; |
| |
| if (absoluteStart == absoluteEnd) |
| { |
| // On a caret selection, apply the leaf format to the SelectionManager's pointFormat, so it will be applied to the next insert. |
| // But if the paragraph is empty, go ahead and apply it now to the paragraph terminator. |
| var paragraph:ParagraphElement = textFlow.findLeaf(absoluteStart).getParagraph(); |
| if (paragraph.textLength <= 1) |
| { |
| endSel++; |
| anyNewSelectionState = originalSelectionState.clone(); |
| anyNewSelectionState.pointFormat = null; |
| } |
| else if (originalSelectionState.selectionManagerOperationState && textFlow.interactionManager) |
| { |
| // on point selection remember pendling leaf formats for next char typed |
| |
| anyNewSelectionState = originalSelectionState.clone(); |
| var newFormat:PointFormat = new PointFormat(anyNewSelectionState.pointFormat); |
| newFormat.apply(applyLeafFormat); |
| anyNewSelectionState.pointFormat = newFormat; |
| } |
| } |
| if (begSel != endSel) |
| { |
| var range:ElementRange = ElementRange.createElementRange(textFlow, begSel,endSel); |
| |
| begSel = range.absoluteStart; |
| endSel = range.absoluteEnd; |
| if(endSel == textFlow.textLength - 1) |
| ++endSel; |
| |
| // CONFIG::debug { if (begSel != absoluteStart || endSel != absoluteEnd) trace("found mismatch ApplyFormatOperation"); } |
| if (!undoLeafArray) |
| { |
| undoLeafArray = new Array(); |
| ParaEdit.cacheStyleInformation(textFlow,begSel,endSel,undoLeafArray); |
| } |
| ParaEdit.applyTextStyleChange(textFlow,begSel,endSel,applyLeafFormat,null); |
| } |
| } |
| |
| if (applyParagraphFormat) |
| { |
| if (!undoParagraphArray) |
| { |
| undoParagraphArray = new Array(); |
| ParaEdit.cacheParagraphStyleInformation(textFlow,absoluteStart, absoluteEnd,undoParagraphArray); |
| } |
| ParaEdit.applyParagraphStyleChange(textFlow,absoluteStart, absoluteEnd,applyParagraphFormat,null); |
| } |
| if (applyContainerFormat) |
| { |
| if (!undoContainerArray) |
| { |
| undoContainerArray = new Array(); |
| ParaEdit.cacheContainerStyleInformation(textFlow,absoluteStart,absoluteEnd,undoContainerArray); |
| } |
| ParaEdit.applyContainerStyleChange(textFlow,absoluteStart,absoluteEnd,applyContainerFormat,null); |
| } |
| return anyNewSelectionState; |
| } |
| |
| /** @private */ |
| public override function doOperation():Boolean |
| { |
| var newSelectionState:SelectionState = doInternal(); |
| if (newSelectionState && textFlow.interactionManager) |
| textFlow.interactionManager.setSelectionState(newSelectionState); |
| return true; |
| } |
| |
| /** @private */ |
| override public function redo():SelectionState |
| { |
| var newSelectionState:SelectionState = doInternal(); |
| return newSelectionState? newSelectionState : originalSelectionState; |
| } |
| |
| /** @private */ |
| public override function undo():SelectionState |
| { |
| var obj:Object; |
| |
| // Undo character format changes |
| for each (obj in undoLeafArray) |
| ParaEdit.setTextStyleChange(textFlow,obj.begIdx,obj.endIdx,obj.style); |
| |
| // Undo paragraph format changes |
| for each (obj in undoParagraphArray) |
| ParaEdit.setParagraphStyleChange(textFlow,obj.begIdx,obj.endIdx,obj.attributes); |
| |
| // Undo container format changes |
| for each (obj in undoContainerArray) |
| ParaEdit.setContainerStyleChange(obj); |
| |
| return originalSelectionState; |
| } |
| |
| } |
| } |