Concurrent Modification exception!

Found another Nifty issue…



My chat is working now, but the word wrap crashes with an java.lang.StringIndexOutOfBoundsException exception.



stack trace:


SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
   at java.lang.String.substring(String.java:1937)
   at de.lessvoid.nifty.elements.tools.TextBreak.processWords(TextBreak.java:60)
   at de.lessvoid.nifty.elements.tools.TextBreak.split(TextBreak.java:23)
   at de.lessvoid.nifty.elements.render.TextRenderer.wrapText(TextRenderer.java:398)
   at de.lessvoid.nifty.elements.render.TextRenderer.setWidthConstraint(TextRenderer.java:411)
   at de.lessvoid.nifty.elements.Element.processLayoutInternal(Element.java:584)
   at de.lessvoid.nifty.elements.Element.processL(Element.java:590)
   at de.lessvoid.nifty.elements.Element.processL(Element.java:604)
   at de.lessvoid.nifty.elements.Element.processL(Element.java:604)
   at de.lessvoid.nifty.elements.Element.processL(Element.java:604)
   at de.lessvoid.nifty.elements.Element.processL(Element.java:604)
   at de.lessvoid.nifty.elements.Element.processL(Element.java:604)
   at de.lessvoid.nifty.elements.Element.processL(Element.java:604)
   at de.lessvoid.nifty.elements.Element.processL(Element.java:604)
   at de.lessvoid.nifty.elements.Element.processL(Element.java:604)
   at de.lessvoid.nifty.elements.Element.layoutElements(Element.java:618)
   at de.lessvoid.nifty.screen.Screen.layoutLayers(Screen.java:185)
   at de.lessvoid.nifty.screen.Screen.startScreen(Screen.java:159)
   at de.lessvoid.nifty.Nifty.gotoScreenInternal(Nifty.java:494)
   at de.lessvoid.nifty.Nifty.gotoScreen(Nifty.java:462)
   at de.lessvoid.nifty.Nifty.fromXml(Nifty.java:310)
   at com.ractoc.opengamefinder.client.plugins.NiftyPlugin.processMessage(NiftyPlugin.java:52)
   at com.ractoc.pffj.core.PluginController.processMessage(PluginController.java:169)
   at com.ractoc.pffj.core.PluginController.processMessage(PluginController.java:114)
   at com.ractoc.opengamefinder.client.OGFClientStartup.simpleInitApp(OGFClientStartup.java:76)
   at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:158)
   at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:102)
   at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:147)
   at java.lang.Thread.run(Thread.java:619)

Hmm, I didn't anticipate that.

It means there is a word of length 0 that doesn't fit in the current row. :stuck_out_tongue:

Anyway, I've committed a fix so hopefully you won't get this error again.

Just out of curiosity - what width did you set your text element to?

Thanks, does it work well now?

Well, yes and no. I no longer get a stacktrace, but now the text pops in there for a fraction of a second and then dissapears…

I see now in your xml that you have set width="" for the label.

That currently doesn't work with wrapping, I'm afraid. I'm not yet sure how to make it work as I think only void knows how it's implemented.

The problem is that when you use width="
" the wrapping method gets the width as -1 and that's not much width to wrap around. :wink:



Try it with a fixed or percentage width instead.

Do you add new chat-line-controls dynamically to the xml and then change the size of the containing panel or relayout the screen?

Ok, so if I reset the width to for instance 5px, and resize it correctly in the bind method of the control, that should work better.

In the control I can calculate the correct width to fill out the textfield by takin gthe unknown width of the surrounding panel and the known width of the button.



I will test this when I get home tonight.

Hey there, I found a fix. First I implemented it just in my own code, but then I figured that, with a few tweaks, it might also work in the actual Nifty code…



I ended up changing the following method on the Element class:



private void processLayoutInternal() {
        for (Element w : elements) {
            TextRenderer textRenderer = w.getRenderer(TextRenderer.class);
            if (textRenderer != null) {
                if (w.getConstraintWidth().getValue(100f) < 0f) {
                    if (layoutManager instanceof HorizontalLayout) {
                        float totalWidth = this.getWidth();
                        float otherElementsWidth = 0;
                        for (Element e : elements) {
                            if (!e.equals(w)) {
                                otherElementsWidth += e.getWidth();
                            }
                        }
                        w.setConstraintWidth(new SizeValue((int)(totalWidth - otherElementsWidth) + "px"));
                    }
                }
                System.out.println(w.getId() + ": constraintwidth = " + w.getConstraintWidth());
                textRenderer.setWidthConstraint(w, w.getConstraintWidth(), getWidth(), nifty.getRenderEngine());
            }
        }
    }



What I changed is that I put in a test to see if the element is using a * as width:


if (w.getConstraintWidth().getValue(100f) < 0f) {



Then, when we are also using a HorizontalLayout, I calculate the actual width (in pixels) for the element by taking the width of the parent element and the combined width of all the other elements on the same level as the current one.
When I finished with that, I put that calculated width as the actual constraintWidth, which makes sure the element does NOT use the * for width anymore.