| Summary: | [Virtual Table] setDataEvent is not always fired during the first LifeCycle | ||
|---|---|---|---|
| Product: | [RT] RAP | Reporter: | Istvan Ballok <Istvan.Ballok> |
| Component: | RWT | Assignee: | Project Inbox <rap-inbox> |
| Status: | RESOLVED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P2 | ||
| Version: | 1.4 | ||
| Target Milestone: | 1.4 M5 | ||
| Hardware: | All | ||
| OS: | All | ||
| Whiteboard: | |||
| Attachments: | |||
Created attachment 182993 [details]
a patch for the current HEAD version in the git mirror to reproduce the problem
Created attachment 182997 [details]
proposed solution for the problem
The approach
============
Execute the RWTLifeCycle#doRedrawFake method after the prepare ui root
phase during the first request. (because there is no process action phase
in this case)
Thanks for the detailed explanation of the problem, Istvan. There is a similar (same) problem with the Tree - see bug 275457, but in Tree, TreeLCA#doRedrawFake fires a resize event to trigger the checkAllData in Tree#resizeListener. BTW, there is an use case (see bug 294709) where we need to fire an event in the first request. That's why in the proposed patch for bug 294709 the PROCESS_ACTION phase has been added to the first request. How about this (just a thought):
We could treat redraw() like a usual "message" that gets processed by Display#readAndDispatch().
The current code in Control#redraw() could basically stay the same in that it puts the control to be redrawn into a list.
RWTLifeCycle#doRedrawFake() wouldn't be called after executing the PROCESS_ACTION phase, instead Display#runPendingMessages() would run the pending redraws if there are no other "messages" to dispatch like so (checks left out for brevity)
private boolean runPendingMessages() {
boolean result = ProcessActionRunner.executeNext();
if( !result ) {
// ...
}
// ...
if( !result ) {
result = runPendingRedraws();
}
return result;
}
This would also allow for a cleaner implementation. The list of Controls that needs to be redrawn (those on which redraw() was called) could be held and managed by the Display/DisplayAdapter.
I am aware that this won't sovle bug 294709
There is another effect of the approach in comment #5: Events that arise during events that are triggered while redrawing (e.g. an event fired from within a SetData event) will still be dispatched. Currently they would be discarded. Created attachment 184808 [details] Bugfix as outlined in comment #5 Istvan would you mind to see if this patch fixes your problem? Created attachment 185616 [details]
Updated patch #3 to HEAD
Created attachment 185627 [details]
Replacees patch #4 (that accidentially contained unrelated changes)
Tested patch #5 with snippets from this bug and bug 275457 - all works fine. Applied patch to CVS HEAD. |
The Problem =========== The SetDataEvent fired by a virtual Table is used to set/update the content of the visible TableItems. Under certain conditions*, this event is not fired, and hence, the Table remains empty. *Preconditions of the problem: ============================== 1) The table is created and updated in the first, initial request, when the application is started. -> it is a feasible requirement. 2) Setting the Table#itemCount is performed after the initial layout. -> this is always the case, when the update of the virtual table (Table#setItemCount / Table#clearAll; Table#redraw methods) is triggered in a Display#asncExec block. If the same snippet is executed in a Button#selectionEvent, it works fine. (because it is not the first, initial request) If the same snippet is executed in a Display#syncExec block, it works fine. (there are other mechanisms, such as the layouting/control size changed, that call the private Table#checkData method directly that triggers the firing of the SetDataEvents) Please check the supplied patch to reproduce the problem in the controls demo. Explanation of the problem ========================== see RWTLifeCycle#execute(): the first request does not run through every phase that is executed in all other subsequent requests. - first request: 1) prepare ui root 2) render - subsequent requests: 1) prepare ui root 2) read data 3) process action 4) render ie., the "process action" phase is missing in the initial request. Note: This makes sense, because there are no events sent from the browser in this case. (=this is the initial request) The Table#redraw method that should fire the the SetDataEvents in the end, performs this task in an indirect way: it calls the RWTLifeCycle#fakeRedraw method to add the control to a set stored in the Request's context; a collection of widgets marked to be redrawn, when the "time comes". RWTLifeCycle#doRedrawFake performs then the redraw action on the controls, that were added to the collection in the previous step. In the case of the Table, this results in calling the Table#checkData(item, index) method, that at last fires the SetDataEvents. This mechanism breaks in the specific case described in this bug. The problem is: The RWTLifeCycle#doRedrawFake is called in RWTLifeCycle#afterPhaseExecution, but only if the current phase was a "process action". Hence, we can now understand the problem: in the initial request, there is no "process action" phase, the widgets, that were marked for redraw, are not 'redrawn' at all, because the RWTLifeCycle#doRedrawFake is not called! Note: ===== after starting the server, the first time you start the application in the browser, it works fine. Later, if you restart the application in the browser, you can reproduce the problem as I described it above. The explanation for that is, that the very first time, the text size determination mechanism kicks in and relayouts the shell with enlarged bounds. (See TextSizeDeterminationHandler#afterPhase(PhaseEvent)) When the size of the table is changed, the Table#checkData method is called directly (without the mechanism above), and that fires the SetDataEvents.