how to update Label content in RepaintRequestEvent w/o stack overflow?

How do I update the content of a Label in response to a RepaintRequestEvent w/o causing a stack overflow (setCaption and setValue trigger a RepaintRequestEvent themselves)?

getApplication().getMainWindow().requestRepaintAll();
Label contentPlaceholder = new Label();

contentPlaceholder.addListener(new RepaintRequestListener() {
				
				@Override
				public void repaintRequested(RepaintRequestEvent event) {
					contentPlaceholder.setValue(help());
					
				}
			});

The first thing that comes to mind is to toggle a boolean flag within the repaintRequested() and only set the caption every other time. This way the second repaint request will go through - otherwise the label wouldn’t show the updated caption - but the second repaint wouldn’t trigger a third one.

If I do this:

contentPlaceholder.addListener(new RepaintRequestListener() {

				boolean hasToRefresh = true;

				@Override
				public void repaintRequested(RepaintRequestEvent event) {
					if (hasToRefresh) {
						// contentPlaceholder.setCaption(help());
						contentPlaceholder.setValue(help());
						[b]
hasToRefresh = false;
[/b]
					} else
						hasToRefresh = true;
				}

			});

It fails saying that “Local type field access can’t be used in evaluation expression”;
If I move it up to the method scope, it has to be final, so that won’t do;
If I move it in enclosing class scope, for some reason I can’t understand, it refuses to hit “hasToRefresh = false;” line in debug, and is always true in consequence.

I thought I should either create a thread local event router and register as listeners the controls I want to update, then when I change the locale, trigger the update on the events, or, since I only want to update controls that are visible, I could maintain a thread local collection of AbstractComponents that are visible and update their content whenever I choose.

The short answer is: you cannot. When repainting is actually performed and the related listeners are triggered, it is too late to make updates to UI components. Doing updates there might lead to infinite recursion, updates that only show up on next event from the UI or disappearing updates.

In general, an application should almost never need to use repaint listeners - they are mostly for internal use by the framework and components. Furthermore, I believe it does not do quite what you expect here - e.g. reloading the page in the browser does not necessarily mean all the components on the page would receive such a call.

I was thinking like in JSF, where the response doesn’t return w/o rendering in the response all the changes first.

Perhaps Vaadin should consider patching in all the Paint requests into the response issued from the same request before sending a response back to the client:
(

separating methods that set values from requesting repaint themselves,
or,
some other method like a Tranzactional paint request that gathers all the requests and “commits” them all in one response
)?
)
If it doesn’t create considerable performance overhead.

I was attempting the most dynamic internationalization change possible, but I left it now up to a user click about the required to change locale component. Saves some bandwidth and resources until I have some time to make a system to keep track of elements that I want to update immediately after the user changes locale. I need to think that system with weak references so those objects can die whenever they need to not stay around because of me keeping references to them to update their locale.

The second of your proposals is actually quite close to how Vaadin works, with the paint phase controlled by the CommunicationManager.

The two issues that I believe cause confusion here stem from Vaadin not being a page based framework.

Firstly, many Vaadin component containers only repaint modified sub-components. There is no such concept as “page reload” in Vaadin.

Secondly, a RepaintRequestListener is really for internal use (by AbstractCommunicationManager and component containers) precisely to find what is the scope of what needs to be repainted. Especially for the component containers, it might not get triggered before the paint phase, where you cannot make modifications (outside a very restricted scope) anymore. Its javadoc should be clarified with respect to this (updated
javadoc ticket #4911
).

A simple (incomplete and possibly slightly inaccurate) explanation of how repaints work:

When a setter of a component is called, it sets a flag that the component is dirty and needs to be repainted, and fires the notification. Such notifications may propagate between a component container and its children, but that typically happens in the paint phase. In some cases, component containers such as layouts may choose to only “paint” a placeholder for a sub-component which is cached on the client side and has not been modified, and some components themselves can choose to only paint the modifications, not the whole component.

I see at least two possible enhancements which apply to much more than your use case - and for which there probably are tickets: 1) to support listening to page reloads on the application level and 2) for component paint methods to get information about when they are being painted for a reload of a page rather than an internal change of state.

EDIT: Removed duplicate quoted text.