Closed nihavend closed 4 years ago
I did not get an exception. I'm wondering if the popup fix in #596 made a difference here
Actually there is not any exception thrown but the text is not displayed.If you think #596 has an effect on the issue, I am going to check it later today.
OK, it was not clear what "not functioning properly" means. Issue #596 is probably not related. The next step is probably to follow the logic that eventually calls a composer to generate text for display. I think it was working properly for RichEditableText, but may have broken.
Promise, I am going to try to be more clear. If I check the generated XML named textFlow, which is the member of TextArea, see the that contains the text to be displayed do exists in the XML tree. Somehow it is not displayed.
I am going to try to understand how RichEditableText handles and try to fix the issue.
@aharui, according to the discussions on the list I tried but changing spark to mx is not enough for my case. Do you have a plan to fix the issue ?
or may you please give advises for me to fix the issue ?
What feature do you need that you can't use MX?
I will eventually get around to working on this issue if nobody else can. I don't have any particular advice. I will end up digging into the code and seeing what is not working. I think the basic idea is the same as Flex. The TextLayoutFramework composes "TextLines" and displays them.
Not being completely aware, here is the error log when converting to mx:TextArea
`D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(147): col: 20 Error: Access of possibly undefined property textFlow through a reference with static type mx.controls.TextArea.
mainTextField.textFlow = TextConverter.importToFlow(returnTxt, TextConverter.PLAIN_TEXT_FORMAT) as TextFlow;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(162): col: 21 Error: Access of possibly undefined property textFlow through a reference with static type mx.controls.TextArea.
mainTextField.textFlow = TextConverter.importToFlow((XML(result.content).children()[0]).toString(), TextConverter.PLAIN_TEXT_FORMAT) as TextFlow;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(164): col: 21 Error: Access of possibly undefined property textFlow through a reference with static type mx.controls.TextArea.
mainTextField.textFlow = TextConverter.importToFlow(String(XML(result).content), TextConverter.PLAIN_TEXT_FORMAT) as TextFlow;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(187): col: 35 Error: Access of possibly undefined property selectionActivePosition through a reference with static type TextArea.
var pos:int = mainTextField.selectionActivePosition;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(189): col: 20 Error: Call to a possibly undefined method selectRange through a reference with static type TextArea.
mainTextField.selectRange(bIdx, eIdx);
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(191): col: 20 Error: Call to a possibly undefined method scrollToRange through a reference with static type TextArea.
mainTextField.scrollToRange(bIdx, oldSearchResult);
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(203): col: 38 Error: Access of possibly undefined property selectionActivePosition through a reference with static type TextArea.
var caretPos:int = mainTextField.selectionActivePosition;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(219): col: 47 Error: Access of possibly undefined property selectionActivePosition through a reference with static type TextArea.
activePosition.text = "[" + mainTextField.selectionActivePosition + "]";
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(223): col: 82 Error: Access of possibly undefined property textFlow through a reference with static type TextArea.
var flowComposer : StandardFlowComposer = StandardFlowComposer(mainTextField.textFlow.flowComposer);
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(224): col: 45 Error: Access of possibly undefined property selectionActivePosition through a reference with static type TextArea.
var absoluteIndex : int = mainTextField.selectionActivePosition;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(226): col: 60 Error: Access of possibly undefined property textFlow through a reference with static type TextArea.
lineNumbers.text = (lineIdx + 1) + "/" + mainTextField.textFlow.numChildren;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(147): col: 20 Error: Access of possibly undefined property textFlow through a reference with static type mx.controls.TextArea.
mainTextField.textFlow = TextConverter.importToFlow(returnTxt, TextConverter.PLAIN_TEXT_FORMAT) as TextFlow;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(162): col: 21 Error: Access of possibly undefined property textFlow through a reference with static type mx.controls.TextArea.
mainTextField.textFlow = TextConverter.importToFlow((XML(result.content).children()[0]).toString(), TextConverter.PLAIN_TEXT_FORMAT) as TextFlow;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(164): col: 21 Error: Access of possibly undefined property textFlow through a reference with static type mx.controls.TextArea.
mainTextField.textFlow = TextConverter.importToFlow(String(XML(result).content), TextConverter.PLAIN_TEXT_FORMAT) as TextFlow;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(187): col: 35 Error: Access of possibly undefined property selectionActivePosition through a reference with static type TextArea.
var pos:int = mainTextField.selectionActivePosition;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(189): col: 20 Error: Call to a possibly undefined method selectRange through a reference with static type TextArea.
mainTextField.selectRange(bIdx, eIdx);
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(191): col: 20 Error: Call to a possibly undefined method scrollToRange through a reference with static type TextArea.
mainTextField.scrollToRange(bIdx, oldSearchResult);
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(203): col: 38 Error: Access of possibly undefined property selectionActivePosition through a reference with static type TextArea.
var caretPos:int = mainTextField.selectionActivePosition;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(219): col: 47 Error: Access of possibly undefined property selectionActivePosition through a reference with static type TextArea.
activePosition.text = "[" + mainTextField.selectionActivePosition + "]";
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(223): col: 82 Error: Access of possibly undefined property textFlow through a reference with static type TextArea.
var flowComposer : StandardFlowComposer = StandardFlowComposer(mainTextField.textFlow.flowComposer);
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(224): col: 45 Error: Access of possibly undefined property selectionActivePosition through a reference with static type TextArea.
var absoluteIndex : int = mainTextField.selectionActivePosition;
^
D:\dev\royale-emulation-works\github\royale-testing\src\main\mtest\FindBugFileViewPopup.mxml(226): col: 60 Error: Access of possibly undefined property textFlow through a reference with static type TextArea.
lineNumbers.text = (lineIdx + 1) + "/" + mainTextField.textFlow.numChildren;
^
20.6204339 seconds`
Without looking too carefully, it appears that you are rendering plain text but converting to TextFlow first. If you want to use mx:TextArea, you can skip the converting and just set the plain text.
I got Spark TextArea to work, but it is running a ton of code and thus uses up a lot of memory and may have performance issues and will probably have lots of bugs to fix. MX TextArea uses a native Browser TextArea and should be more functional.
I need some features like line numbers, search navigation over text etc. Is it possible with mx ?
Please be more specific about which TLF APIs you are using in your Flex app. I couldn't easily find line numbering support for TLF. MX TextArea probably does not have the APIs that TLF might, but the question is whether you are better off trying to stabilize a ton of code or implementing the specific customizations you need on MX TextArea. IMO, if you are always using plain text, you might be better off using the native Browser underneath
@aharui below is the original flex code and screen capture of the window.
Some of the functionalities are search,find and select scroll. Line numbers comes from skin.
You can see the info on the picture. If you think that mx is ok, than it is ok for me.
<?xml version="1.0"?>
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:s="library://ns.adobe.com/flex/spark"
close="handleCloseEvent()"
keyDown="titleWindow_keyDown(event);"
creationComplete="titlewindow1_creationCompleteHandler(event)"
width="800" height="500">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import com.likya.pinara.utils.BasicAuthenticationHandler;
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
import mx.resources.ResourceManager;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import spark.layouts.HorizontalLayout;
import flashx.textLayout.compose.StandardFlowComposer;
import flashx.textLayout.conversion.TextConverter;
protected var oldSearchResult:int = 0;
protected var vScrollPos:int = 0;
public var isNativeXML:Boolean = false;
public var fileTag:String;
private var titlePrefix:String = ResourceManager.getInstance().getString('messages', 'logViewWindowTitle');
[Bindable]
private var defEndOff:int = 5000;
private var logViewCTX:String = "/logview";
private function titleWindow_keyDown(evt:KeyboardEvent):void {
if (evt.charCode == Keyboard.ESCAPE) {
this.dispatchEvent(new CloseEvent(CloseEvent.CLOSE));
}
}
private function initService(url:String = null):void {
// liveTreeDataService.url = "http://127.0.0.1:3000/logdetail?fname=myraTrace";
// liveTreeDataService.url = "http://127.0.0.1:3000/logdetail" + "?" + "fname=myraTrace" + "&" + "beginoff=0" + "&" + "endoff=5000";
if(url == null) {
// url = "http://127.0.0.1:3000/logdetail" + "?" + "fname=" + fileTag + "&" + "beginoff=0" + "&" + "endoff=" + defEndOff;
url = logViewCTX + "?" + fileTag + "&" + "beginoff=0" + "&" + "endoff=" + defEndOff;
}
liveTreeDataService.url = url;
//liveTreeDataService.send(); // parametresiz.
liveTreeDataService.method = "POST";
BasicAuthenticationHandler.authAndSend(liveTreeDataService);
}
private function refreshService(event:Event):void {
// Alert.show("EndOff : " + endOff.value);
// var url:String = "http://127.0.0.1:3000/logdetail" + "?" + "fname=" + fileTag + "&" + "beginoff=" + beginOff.value + "&" + "endoff=" + endOff.value;
var url:String = logViewCTX + "?" + fileTag + "&" + "beginoff=" + beginOff.value + "&" + "endoff=" + endOff.value;
//Alert.show("service url : " + url);
initService(url);
defEndOff = endOff.value;
}
protected function titlewindow1_creationCompleteHandler(event:FlexEvent):void {
// addEventListener(MouseEvent.CLICK, handleClickEvent);
title = titlePrefix;
initService();
}
private function handleClickEvent(event:Event):void {
// Alert.show("event.type : " + event.type + " Target : " + event.target);
}
private function handleCloseEvent():void {
PopUpManager.removePopUp(this);
}
private function errAlert(eventObj:CloseEvent):void {
handleCloseEvent();
}
protected function xmlService_faultHandler(event:FaultEvent):void {
Alert.show(event.toString(), "Hata oluştu !");
handleCloseEvent();
}
protected function xmlService_resultHandler(event:ResultEvent):void {
var returnXml:XML;
var returnTxt:String = null;
try {
isNativeXML = true;
returnXml = XML(event.result);
} catch(err:Error) {
isNativeXML = false;
returnTxt = String(event.result)
}
/** XML strucuture : Fault
* <return>
* <code></code>
* <message>
* Error description
* </message>
* </return>
*
* XML strucuture : Return
* <return>
* <code></code>
* <message>
* <data>
* <meta>
* meta file info
* <size></size>
* <name></name>
* <path></path>
* </meta>
* <content>
* limited file content
* </content>
* </data>
* </message>
* </return>
**/
if(returnTxt != null) {
Alert.show(resourceManager.getString("messages", "fileViewPopDataFileCorrupted"));
mainTextField.textFlow = TextConverter.importToFlow(returnTxt, TextConverter.PLAIN_TEXT_FORMAT);
callLater(updateEndOff);
} else if(returnXml.code == "-99" || returnXml.code == "-1") {
Alert.show("" + returnXml.message.substr(0, 200) + "...", "Hata oluştu kod[" + returnXml.code + "]", Alert.OK, this, errAlert, null);
} else {
var result:XML = XML(returnXml.message.data);
this.title = titlePrefix + " : " + XML(result).meta.name;
var fSize:int = XML(result).meta.size;
fileSize.text = fSize + "K";
beginOff.maximum = fSize -1;
endOff.maximum = fSize;
if(isNativeXML) {
mainTextField.textFlow = TextConverter.importToFlow((XML(result.content).children()[0]).toString(), TextConverter.PLAIN_TEXT_FORMAT);
} else {
mainTextField.textFlow = TextConverter.importToFlow(String(XML(result).content), TextConverter.PLAIN_TEXT_FORMAT);
}
callLater(setLineNumbers);
callLater(updateEndOff);
}
}
protected function button1_clickHandler(event:MouseEvent):void {
var searchStr : String = searchTxt.text;
var truncatedText : String;
truncatedText = mainTextField.text.substring(oldSearchResult);
var searchResult:int = truncatedText.search(searchStr);
mainTextField.setFocus();
if(searchResult != -1) {
var bIdx:int = oldSearchResult + searchResult;
var eIdx:int = oldSearchResult + searchResult + searchStr.length;
var pos:int = mainTextField.selectionActivePosition;
mainTextField.selectRange(bIdx, eIdx);
oldSearchResult = eIdx;
mainTextField.scrollToRange(bIdx, oldSearchResult);
//scrollBarPosLabel.text = "[" + mainTextField.scroller.verticalScrollBar.value + "]-[" + vScrollPos + "]";
// var dgArray:Array = [{bIdx:bIdx, eIdx:eIdx, pos:pos + "/" + mainTextField.text.length}];
// initDG.addItem(dgArray[0]);
setCaretPos();
setLineNumbers();
} else {
Alert.show(resourceManager.getString("messages", "fileViewPopNoMoreResult"));
}
}
protected function mainTextField_clickHandler(event:MouseEvent):void {
var caretPos:int = mainTextField.selectionActivePosition;
if(event.target is Button) {
if(event.type == MouseEvent.CLICK) {
vScrollPos = mainTextField.scroller.verticalScrollBar.value;
//scrollBarPosLabel.text = "[" + mainTextField.scroller.verticalScrollBar.value + "]-[" + vScrollPos + "]";
}
} else {
oldSearchResult = caretPos;
setCaretPos();
setLineNumbers();
}
}
protected function setCaretPos():void {
activePosition.text = "[" + mainTextField.selectionActivePosition + "]";
}
protected function setLineNumbers():void {
var flowComposer : StandardFlowComposer = StandardFlowComposer(mainTextField.textFlow.flowComposer);
var absoluteIndex : int = mainTextField.selectionActivePosition;
var lineIdx : int = flowComposer.findLineIndexAtPosition(absoluteIndex);
lineNumbers.text = (lineIdx + 1) + "/" + mainTextField.textFlow.numChildren;
//endOff.value = 5000;
}
protected function updateEndOff():void {
endOff.value = defEndOff;
// Alert.show("endOff.value : " + endOff.value);
}
]]>
</fx:Script>
<fx:Declarations>
<s:HTTPService id="liveTreeDataService"
method="POST"
showBusyCursor="true"
resultFormat="text"
result="xmlService_resultHandler(event)"
fault="xmlService_faultHandler(event)"
/>
</fx:Declarations>
<s:VGroup left="5" right="10" top="10" bottom="10" height="100%" width="100%">
<mx:HBox horizontalAlign="center">
<s:FormItem label="{resourceManager.getString('messages', 'initialOffset')}" layout="{new HorizontalLayout()}" width="100%" >
<s:NumericStepper id="beginOff" stepSize="1" width="100" minimum="0" maximum="999999999" />
</s:FormItem>
<s:FormItem label="{resourceManager.getString('messages', 'endOffset')}" layout="{new HorizontalLayout()}" width="100%" >
<s:NumericStepper id="endOff" stepSize="1" width="100" minimum="0" maximum="999999999" value="{defEndOff}"/>
</s:FormItem>
<s:FormItem width="100%" >
<s:Button label="{resourceManager.getString('messages', 'refresh')}" click="refreshService(event)" />
</s:FormItem>
</mx:HBox>
<mx:HRule width="100%" />
<s:FormItem label="{resourceManager.getString('messages', 'searchTextLabel')}" layout="{new HorizontalLayout()}" width="100%" >
<s:TextInput id="searchTxt" text="fname" />
<s:Button label="{resourceManager.getString('messages', 'searchNextButLabel')}" click="button1_clickHandler(event)" />
</s:FormItem>
<s:Line width="100%">
<s:stroke>
<s:SolidColorStroke color="0x000000" weight="1" caps="square"/>
</s:stroke>
</s:Line>
<s:TextArea id="mainTextField" verticalScrollPolicy="on" width="100%" height="100%" click="mainTextField_clickHandler(event)" editable="false" skinClass="com.likya.pinara.skins.TextAreaLineNumbersSkin" />
<s:BorderContainer height="25" width="100%" backgroundColor="0xDCDCDC" borderStyle="solid">
<s:layout>
<s:HorizontalLayout paddingLeft="5" paddingRight="5" paddingTop="5" paddingBottom="5" verticalAlign="middle"/>
</s:layout>
<s:Label text="{resourceManager.getString('messages', 'lineNumbersLabel')}" />
<s:Label id="lineNumbers" />
<s:Spacer width="5%" />
<s:Label text="{resourceManager.getString('messages', 'caretPositionLabel')}" />
<s:Label id="activePosition" text="[0]" />
<s:Spacer width="100%" />
<s:HGroup horizontalAlign="right">
<s:Label text="{resourceManager.getString('messages', 'fileSizeLabel')}" />
<s:Label id="fileSize" right="0" />
</s:HGroup>
</s:BorderContainer>
</s:VGroup>
</s:TitleWindow>
Looks like you are using a custom skin for TextArea. Support for that will need to be implemented or you can probably fake it by putting a list of numbers next to the TextArea
I am not familiar with the functionalities you mentioned. It appears from your sample code that line numbers is something you developed based on information available from the textFlow. I'm pretty sure the information you need can be pulled from the string or MX TextArea. MX TextArea supports selection but I think it has different API names.
The above list is my requirement. If mx version confirms than it is what I expect.
I don't know what "search and highlight" means. Are you highlighting all occurrences or just one?
Is Caret position where the cursor is? That should be selectionBeginIndex for MX TextArea
Is the font fixed-width or not? Is the file size something other than the length of the plain text?
I don't know what begin/end offset means.
I'm at the end of my work day so will check in the morning.
I don't know what "search and highlight" means. Are you highlighting all occurrences or just one?
I guess the first occurrence
Is Caret position where the cursor is? That should be selectionBeginIndex for MX TextArea
Exactly
Is the font fixed-width or not? Is the file size something other than the length of the plain text?
The size of the file
I don't know what begin/end offset means.
means byte offset
I'm at the end of my work day so will check in the morning.
Is the size of the file different from the length of the plain text in the file? (multi-byte character sequences?)
Byte offset from what?
Is the font fixed-width or not?
I am not sure @aharui have to check it but I guess size should correspond to characters. Byte offset from the beginning of the file. Font is fixed I guess, because it is not required to have different fonts. The aim to enable users to find what they are looking for.
By fixed-width font, I mean a font where every character is the same width like Courier so it is easier to calculate line positions.
Here is the skin class that contains the details, I should have share before.
<?xml version="1.0" encoding="utf-8"?>
<!--- A skin class for Spark TextArea component that shows line numbers.
@see spark.components.TextArea
-->
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
creationComplete="created(event)"
alpha.disabled="0.5"
blendMode="normal">
<fx:Metadata>
<![CDATA[
/**
* @copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.TextArea")]
]]>
</fx:Metadata>
<fx:Script fb:purpose="styling">
private var lineBreakChanged:Boolean;
private var paddingChanged:Boolean;
private var verticalAlignChanged:Boolean;
/* Define the skin elements that should not be colorized.
For text area, the skin itself is colorized but the individual parts are not. */
static private const exclusions:Array = ["background", "scroller"];
/**
* @private
*/
override public function get colorizeExclusions():Array {
return exclusions;
}
/* Define the content fill items that should be colored by the "contentBackgroundColor" style. */
static private const contentFill:Array = ["bgFill"];
/**
* @private
*/
override public function get contentItems():Array {
return contentFill
}
;
/**
* @private
*/
override protected function commitProperties():void {
super.commitProperties();
if (lineBreakChanged) {
updateStringStyle("lineBreak");
lineBreakChanged = false;
if (textDisplay != null) {
if (getStyle("lineBreak") == "explicit") {
if (textDisplay.percentWidth == 100) {
textDisplay.width = NaN;
}
} else if (textDisplay.percentWidth != 100) {
textDisplay.percentWidth = 100;
}
}
}
if (paddingChanged) {
updatePadding();
paddingChanged = false;
}
if (verticalAlignChanged) {
updateStringStyle("verticalAlign");
verticalAlignChanged = false;
}
}
/**
* @private
*/
override protected function initializationComplete():void {
useChromeColor = true;
super.initializationComplete();
}
/**
* @private
*/
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
if (getStyle("borderVisible") == true) {
border.visible = true;
shadow.visible = true;
background.left = background.top = background.right = background.bottom = 1;
scroller.left = scroller.top = scroller.right = scroller.bottom = 1;
} else {
border.visible = false;
shadow.visible = false;
background.left = background.top = background.right = background.bottom = 0;
scroller.left = scroller.top = scroller.right = scroller.bottom = 0;
}
borderStroke.color = getStyle("borderColor");
borderStroke.alpha = getStyle("borderAlpha");
super.updateDisplayList(unscaledWidth, unscaledHeight);
}
/**
* @private
*/
private function updatePadding():void {
if (!textDisplay)
return;
// Push padding styles into the textDisplay
var padding:Number;
padding = getStyle("paddingLeft");
if (textDisplay.getStyle("paddingLeft") != padding)
textDisplay.setStyle("paddingLeft", padding);
padding = getStyle("paddingTop");
if (textDisplay.getStyle("paddingTop") != padding)
textDisplay.setStyle("paddingTop", padding);
padding = getStyle("paddingRight");
if (textDisplay.getStyle("paddingRight") != padding)
textDisplay.setStyle("paddingRight", padding);
padding = getStyle("paddingBottom");
if (textDisplay.getStyle("paddingBottom") != padding)
textDisplay.setStyle("paddingBottom", padding);
}
/**
* @private
*/
private function updateStringStyle(styleName:String):void {
if (!textDisplay)
return;
// Push style into the textDisplay
var style:String;
style = getStyle(styleName);
if (textDisplay.getStyle(styleName) != style) {
textDisplay.setStyle(styleName, style);
}
}
/**
* @private
*/
override public function styleChanged(styleProp:String):void {
var allStyles:Boolean = !styleProp || styleProp == "styleName";
super.styleChanged(styleProp);
if (allStyles || styleProp.indexOf("lineBreak") == 0) {
lineBreakChanged = true;
invalidateProperties();
}
if (allStyles || styleProp.indexOf("padding") == 0) {
paddingChanged = true;
invalidateProperties();
}
if (allStyles || styleProp.indexOf("verticalAlign") == 0) {
verticalAlignChanged = true;
invalidateProperties();
}
}
</fx:Script>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
/**
* @private
*/
private static const focusExclusions:Array = ["textDisplay"];
/**
* @private
*/
override public function get focusSkinExclusions():Array {
return focusExclusions;
}
protected function created(event:FlexEvent):void {
updateLineNumbers(event);
hostComponent.addEventListener(FlexEvent.UPDATE_COMPLETE, updateLineNumbers, false, 0, true);
}
private var _lines:int = 0;
private function updateLineNumbers(event:Event):void {
var lines:int = textDisplay.mx_internal::textContainerManager.numLines;
if (lines != _lines) {
var old:int = _lines;
this._lines = lines;
var diff:int = lines - old;
var linesString:String;
var i:int;
if (diff > 0) {
linesString = lineNumbersLabel.text;
for (i = old + 1; i <= _lines; i++) {
if (i > 1) {
linesString += "\n";
}
linesString += i.toString(10);
}
} else {
linesString = "";
for (i = 1; i <= _lines; i++) {
if (i > 1) {
linesString += "\n";
}
linesString += i.toString(10);
}
}
lineNumbersLabel.text = linesString;
}
}
]]>
</fx:Script>
<s:states>
<s:State name="normal" />
<s:State name="collapsed" />
<s:State name="disabled" />
<s:State name="disabledWithControlBar" />
<s:State name="normalWithControlBar" />
<s:State name="normalWithPrompt" />
<s:State name="disabledWithPrompt" />
</s:states>
<!-- border -->
<!--- @private -->
<s:Rect id="border"
bottom="0"
left="0"
right="0"
top="0">
<s:stroke>
<!--- @private -->
<s:SolidColorStroke id="borderStroke"
weight="1"/>
</s:stroke>
</s:Rect>
<!-- fill -->
<!--- Defines the appearance of the TextArea component's background. -->
<s:Rect id="background"
bottom="1"
left="1"
right="1"
top="1">
<s:fill>
<!--- @private Defines the background fill color. -->
<s:SolidColor id="bgFill"
color="0xFFFFFF"/>
</s:fill>
</s:Rect>
<!-- shadow -->
<!--- @private -->
<s:Rect id="shadow"
height="1"
left="1"
right="1"
top="1">
<s:fill>
<s:SolidColor color="0x000000"
alpha="0.12"/>
</s:fill>
</s:Rect>
<!--- Defines the scroller that is used to scroll the TextArea control. -->
<s:HGroup id="textGroup"
bottom="0"
left="0"
right="0"
top="0"
gap="0">
<s:Group height="100%">
<s:Group id="gutter"
minWidth="25"
verticalScrollPosition="{textDisplay.verticalScrollPosition}"
bottom="1"
top="0"
clipAndEnableScrolling="true">
<s:Label id="lineNumbersLabel"
minWidth="24"
color="#999999"
fontFamily="{textDisplay.getStyle('fontFamily')}"
fontSize="{textDisplay.getStyle('fontSize')}"
fontWeight="{textDisplay.getStyle('fontWeight')}"
paddingBottom="5"
paddingLeft="5"
paddingRight="6"
paddingTop="5"
textAlign="right"/>
</s:Group>
<!-- make a gray area the same size as the horizontal scrollbar -->
<s:Rect height="14"
includeInLayout="{scroller.horizontalScrollBar.visible}"
bottom="1"
left="1"
right="1">
<s:fill>
<s:SolidColor color="#EDEDED"/>
</s:fill>
</s:Rect>
<s:Line width="1"
bottom="1"
right="0"
top="1">
<s:stroke>
<s:SolidColorStroke color="#EDEDED"
weight="1"/>
</s:stroke>
</s:Line>
</s:Group>
<s:Scroller id="scroller"
height="100%"
width="100%"
measuredSizeIncludesScrollBars="false"
minViewportInset="1">
<!--- @copy spark.components.supportClasses.SkinnableTextBase#textDisplay -->
<s:RichEditableText id="textDisplay"
change="updateLineNumbers(event)"
valueCommit="updateLineNumbers(event)"/>
</s:Scroller>
</s:HGroup>
</s:SparkSkin>
I'm still not clear on the details of some things like offset but here's a first cut at a MXTextArea- based component that can display line numbers next to some text.
Test.mxml:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.apache.org/royale/spark"
xmlns:mx="library://ns.apache.org/royale/mx"
xmlns:local="*"
creationComplete="loadData()"
height="100%"
width="100%"
>
<fx:Metadata>
</fx:Metadata>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
protected var oldSearchResult:int = 0;
public var returnXML:XML = <return>
<code>0</code>
<message>
<data>
<meta>
<size>461</size>
<name>conf\myraConfig.xml</name>
</meta>
<content>
<myraConfig xmlns="http://www.likyateknoloji.com/myra-config">
<persistent>false</persistent>
<normalize>true</normalize>
<frequency>1</frequency>
<higherThreshold>10</higherThreshold>
<lowerThreshold>3</lowerThreshold>
<logPath>./</logPath>
<usejobnamesforlog>NO</usejobnamesforlog>
<logFileExt>.log</logFileExt>
<globalLogPath>./</globalLogPath>
<logbuffersize>2000</logbuffersize>
<logpagesize>10</logpagesize>
</myraConfig>
</content>
</data>
</message>
</return>;
public function loadData():void
{
var s:String = returnXML.toXMLString();
var fSize:int = returnXML.meta.size;
fileSize.text = Math.round(s.length/1000) + "K";
mainTextField.text = s;
callLater(setLineNumbers);
}
protected function button1_clickHandler(event:MouseEvent):void {
var searchStr : String = searchTxt.text;
var truncatedText : String;
truncatedText = mainTextField.text.substring(oldSearchResult);
var searchResult:int = truncatedText.search(searchStr);
mainTextField.setFocus();
if(searchResult != -1) {
var bIdx:int = oldSearchResult + searchResult;
var eIdx:int = oldSearchResult + searchResult + searchStr.length;
var pos:int = mainTextField.selectionActivePosition;
mainTextField.selectRange(bIdx, eIdx);
oldSearchResult = eIdx;
mainTextField.scrollToRange(bIdx, oldSearchResult);
setCaretPos();
setLineNumbers();
} else {
Alert.show("search text not found");
}
}
protected function setCaretPos():void {
activePosition.text = "[" + mainTextField.selectionActivePosition + "]";
}
protected function setLineNumbers():void {
var absoluteIndex : int = mainTextField.selectionActivePosition;
var lineIdx : int = mainTextField.findLineIndexAtPosition(absoluteIndex);
lineNumbers.text = (lineIdx + 1) + "/" + mainTextField.numLines;
//endOff.value = 5000;
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<s:layout>
<s:VerticalLayout gap="10" paddingRight="10" paddingLeft="10" paddingTop="10" paddingBottom="20" />
</s:layout>
<mx:Panel title="Line Numbered Text Display Example"
paddingBottom="10" paddingTop="10" paddingLeft="10" paddingRight="10"
height="50%" width="50%">
<s:FormItem label="{resourceManager.getString('formatters', 'monthNamesShort')}" layout="{new HorizontalLayout()}" width="100%" >
<mx:TextInput id="searchTxt" text="fname" />
<s:Button label="Search" click="button1_clickHandler(event)" />
</s:FormItem>
<local:LineNumberTextDisplay id="mainTextField" height="100%" width="100%" />
<s:BorderContainer height="25" width="100%" backgroundColor="0xDCDCDC" borderStyle="solid">
<s:layout>
<s:HorizontalLayout paddingLeft="5" paddingRight="5" paddingTop="5" paddingBottom="5" verticalAlign="middle"/>
</s:layout>
<s:Label text="Line Numbers:" />
<s:Label id="lineNumbers" />
<s:Spacer width="5%" />
<s:Label text="Caret Pos:" />
<s:Label id="activePosition" text="[0]" />
<s:Spacer width="100%" />
<s:HGroup horizontalAlign="right">
<s:Label text="File Size:" />
<s:Label id="fileSize" right="0" />
</s:HGroup>
</s:BorderContainer>
</mx:Panel>
</s:Application>
LineNumberTextDisplay.mxml
<?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:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.apache.org/royale/spark"
xmlns:mx="library://ns.apache.org/royale/mx"
horizontalGap="0"
>
<fx:Metadata>
</fx:Metadata>
<fx:Script>
<![CDATA[
public function get text():String
{
return main.text;
}
public function set text(value:String):void
{
main.text = value;
if (parent)
setLineNumbers();
}
public function get selectionActivePosition():int
{
return main.selectionBeginIndex;
}
public function set selectionActivePosition(value:int):void
{
main.selectionBeginIndex = value;
}
public function selectRange(begin:int, end:int):void
{
main.setSelection(begin, end);
}
public function scrollToRange(begin:int, end:int):void
{
}
private var lineHeight:int = 0;
public function get numLines():int
{
COMPILE::JS
{
if (!lineHeight)
{
var lineHeightStyle:String = getComputedStyle(element)["lineHeight"];
lineHeight = parseInt(lineHeightStyle, 10);
}
return Math.floor(main.element.scrollHeight / lineHeight);
}
return 0;
}
public function findLineIndexAtPosition(offset:int):int
{
return 0;
}
override public function addedToParent():void
{
super.addedToParent();
setLineNumbers();
COMPILE::JS
{
main.element.addEventListener("scroll", scrollHandler);
}
}
public function setLineNumbers():void
{
var s:String = "";
var n:int = numLines;
for (var i:int = 1; i <= n; i++)
{
s += i + "\n";
}
numbers.text = s;
}
COMPILE::JS
private function scrollHandler(event:Event):void
{
numbers.element.scrollTop = main.element.scrollTop;
}
]]>
</fx:Script>
<fx:Declarations>
</fx:Declarations>
<mx:TextArea id="numbers" verticalScrollPolicy="off" horizontalScrollPolicy="off" height="100%" width="50"/>
<mx:TextArea id="main" height="100%" width="100%" />
</mx:HBox>
You will need the latest royale-compiler and royale-asjs commits.
Here is the test case for the popup to display xml text.
While debugging the value is in object but not displayed