blob: 8ff9eabeedf91a1317eaee7e0f6766442efb94f4 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package 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;
}
}
}