pivot-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Chris Bartlett <cbartlet...@gmail.com>
Subject Re: TextAreaSkin
Date Sat, 11 Dec 2010 18:48:28 GMT
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 <cbartlett.x@gmail.com> 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 <cbartlett.x@gmail.com> 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
>>
>
>

Mime
View raw message