Greg,

Is there time before the 2.0 vote to put in the constructor work-around I
suggested?  I see there have been a few commits recently and see it as very
low risk.

Either way I will add it to JIRA for 2.0.1.  As a pure fix, or the fix and
removal of the workaround.

Chris

On 12 December 2010 21:08, Greg Brown <gk_br...@verizon.net> wrote:

> 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 <gk_br...@verizon.net> 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 <cbartlet...@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 <cbartlet...@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
> >>>
> >>>
> >>> <mytextarea.zip>
> >>
> >>
>
>

Reply via email to