Yes, that would definitely explain it.

On Dec 12, 2010, at 9:01 AM, Chris Bartlett wrote:

> I didn't think to look that closely at installSkin(), but it sounds like the
> behaviour you describe would give the same problem due to there not being a
> skin installed when the setText() call occurs, so no there is no listener to
> catch the TextAreaContentListener#paragraphInserted(TextArea, int) event.
> 
> On 12 December 2010 20:03, Greg Brown <[email protected]> wrote:
> 
>> I don't think the problem is that the skin is getting installed twice -
>> installSkin() was written specifically to handle that case. When a more
>> specific component/skin mapping exists, installSkin() is supposed to ignore
>> the first call because it knows a more specific skin will be installed
>> later. So something else is probably going on, most likely related to the
>> call to setText().
>> 
>> On Dec 11, 2010, at 1:48 PM, Chris Bartlett wrote:
>> 
>>> I created a custom skin extended from TerraTextAreaSkin in order to
>> handle these keypresses.
>>> However I had problems after associating my subclass of TextArea with a
>> custom skin.
>>> 
>>> 
>>> TextArea only has one constructor, a public no args one which will always
>> be called when instantiating a subclass.
>>> public TextArea() {
>>>    installSkin(TextArea.class);
>>>    setText("");
>>> }
>>> 
>>> The problem is that org.apache.pivot.wtk.skin.TextAreaSkin is installed
>> immediately, and this skin holds some state.
>>> The setText() call ultimately adds a empty paragraph via
>> TerraTextAreaSkin(TextAreaSkin).paragraphInserted(TextArea, int), and this
>> is tracked within TextAreaSkin.
>>> 
>>> 
>>> Normally I would extends a skin & component as follows
>>> public class MyTextAreaSkin extends TerraTextAreaSkin {
>>>    public MyTextAreaSkin() {
>>>        super();
>>>    }
>>>    // My styles, overrides & supporting code
>>> }
>>> 
>>> public class MyTextArea extends TextArea {
>>>    public MyTextArea() {
>>>        super();
>>>        installSkin(MyTextArea.class);
>>>    }
>>>    // My properties, overrides & supporting code
>>> }
>>> 
>>> And make them known to the Theme
>>> Theme.getTheme().set(MyTextArea.class, MyTextAreaSkin.class);
>>> 
>>> 
>>> This will fail because by the time I get to install my custom skin in the
>> MyTextArea constructor, it superclass has already installed a skin, *and*
>> altered its state.
>>> The installSkin() in MyTextArea runs again, and essentially resets the
>> state by installing a new skin over the old one.
>>> The next call to TextArea.setText(Reader) will fail with the following
>> error
>>> 
>>> Exception in thread "main" java.lang.IndexOutOfBoundsException: index 0
>> out of bounds.
>>> at
>> org.apache.pivot.collections.ArrayList.verifyIndexBounds(ArrayList.java:577)
>>> at org.apache.pivot.collections.ArrayList.get(ArrayList.java:346)
>>> at
>> org.apache.pivot.wtk.skin.TextAreaSkin.paragraphsRemoved(TextAreaSkin.java:1216)
>>> at
>> org.apache.pivot.wtk.TextArea$TextAreaContentListenerList.paragraphsRemoved(TextArea.java:511)
>>> at
>> org.apache.pivot.wtk.TextArea$ParagraphSequence.remove(TextArea.java:420)
>>> at org.apache.pivot.wtk.TextArea.setText(TextArea.java:722)
>>> at org.apache.pivot.wtk.TextArea.setText(TextArea.java:667)
>>> at mytextarea.SimpleTest.test(SimpleTest.java:23)
>>> at mytextarea.SimpleTest.main(SimpleTest.java:27)
>>> 
>>> 
>>> This occurs because the state held in the TextArea component is now out
>> of sync with the state held in the TextAreaSkin.  (The component remembers
>> the first paragraph that was added, but the newly installed skin knows
>> nothing about it, so fails when it tries to remove the paragraph)
>>> 
>>> Hopefully that all makes sense!
>>> 
>>> 
>>> A simple fix would be something like changing the TextArea constructors
>> as follows
>>> // Single constructor to be replaced with 2 new constructors
>>> public TextArea() {
>>>    installSkin(TextArea.class);
>>>    setText("");
>>> }
>>> 
>>> ...becomes...
>>> 
>>> // Default
>>> public TextArea() {
>>>    this(TextArea.class);
>>> }
>>> 
>>> // To be called by any class extending this which wishes to use a custom
>> skin
>>> public TextArea(Class<? extends TextArea> componentClass) {
>>>    installSkin(componentClass);
>>>    setText("");
>>> }
>>> 
>>> 
>>> Then in the constructor for MyTextArea() I can call the 2nd constructor
>> and only install a single skin instance
>>> public MyTextArea() {
>>>    super(MyTextArea.class);
>>> }
>>> 
>>> Zip file (hopefully) attached with some simple test code to demonstrate
>> the issue.
>>> 
>>> Chris
>>> 
>>> On 11 December 2010 17:25, Chris Bartlett <[email protected]> wrote:
>>> I forgot to add that it would be nice to be able to place the caret at
>> the start and end of the file with keystrokes such as CTRL+HOME and
>> CTRL+END.
>>> Holding SHIFT in addition to the other keys would bound the selection
>> from the caret to the start/end point respectively.
>>> 
>>> As I will be following up on the whole component keystroke handling area
>> in PIVOT-638, I will just make a note to include it then.
>>> 
>>> Chris
>>> 
>>> On 11 December 2010 17:12, Chris Bartlett <[email protected]> wrote:
>>> Greg,
>>> 
>>> I finally found a little time to play around with TextArea today, and it
>> looks good.   The only points of note I could find are the following.
>>> 
>>> 
>>> TextAreaSkin fails as follows if when the END key is pressed on the final
>> line of a TextArea (ie, a line without a linebreak)
>>> java.lang.IndexOutOfBoundsException
>>> at org.apache.pivot.wtk.TextArea.getCharacterAt(TextArea.java:870)
>>> at
>> org.apache.pivot.wtk.skin.TextAreaSkin.keyPressed(TextAreaSkin.java:934)
>>> at
>> org.apache.pivot.wtk.Component$ComponentKeyListenerList.keyPressed(Component.java:524)
>>> at org.apache.pivot.wtk.Component.keyPressed(Component.java:2813)
>>> at
>> org.apache.pivot.wtk.ApplicationContext$DisplayHost.processKeyEvent(ApplicationContext.java:1257)
>>> at java.awt.Component.processEvent(Unknown Source)
>>> at
>> org.apache.pivot.wtk.ApplicationContext$DisplayHost.processEvent(ApplicationContext.java:709)
>>> ...
>>> You can see this by simply pressing END with a freshly created TextArea
>> with no content.
>>> If you add a second line, END will work on the first line, but throw on
>> the last one.
>>> 
>>> 
>>> TextAreaSkin.getInsertionPoint(int, int) did not behave as I anticipated
>> in one scenario.
>>> I was expecting it to place the caret at the end of the text (the same
>> placement that would occur if I press the END key) if I left click anywhere
>> within the 'space' following the final character in TextArea.
>>> Clicking in that space currently seems to have no effect.
>>> 
>>> Chris
>>> 
>>> 
>>> <mytextarea.zip>
>> 
>> 

Reply via email to