Feature #10451
GUI interaction event logging
100%
History
#1 Updated by Paula Păstrăguș 11 months ago
This task is meant to add logging for key GUI actions so we can reconstruct user flows and reproduce "one-off" issues (e.g., crashes, OOM). When enabled (intended for testing systems, not production), the client will emit structured logs for things like window x opens/close.
In order to achieve this, we can extend an existing log file, or we can create a dedicated one, gui-actions.log to reduce confusion.
A entry can look like this: <time> <session ID> <event> <desc>2025-08-29 000014 WINDOW_OPEN "window title".
#2 Updated by Paula Păstrăguș 11 months ago
Hynek, I’d value your feedback on this and your approval. Thank you!
#3 Updated by Greg Shah 11 months ago
A common log file is useful because then all logging has context about what was happening. To make that work, we would need to ensure that none of the extended debug logging would be present by default.
I also don't want to create a parallel logging infrastructure. Let's use what we already have.
#4 Updated by Paula Păstrăguș 11 months ago
In that case, we can stick with the existing logger levels defined in directory.xml, no need to introduce any new variables, just as you suggested, Greg. I'll review where the logs would fit best and outline what’s useful and where to place it before committing to a solution.
#5 Updated by Paula Păstrăguș 11 months ago
- Assignee set to Paula Păstrăguș
- Status changed from New to WIP
#6 Updated by Paula Păstrăguș 11 months ago
- File 10450wip.patch
added - reviewer Hynek Cihlar added
I’ve attached a patch that adds structured logging for key GUI events, specifically when windows are opened/closed and when buttons are clicked.
Hynek, please take a look.
The idea behind these logs is to make it easier to trace the sequence of user actions leading up to a crash or unexpected behavior. For example:
Window opened/closedlogs help reconstruct the navigation flow (which screen the user was on, and in what order). This is especially useful if issues appear only after entering or leaving certain dialogs.
Button clicklogs capture the specific actions the user performed. When combined with the window context, they show why the application transitioned into a particular state.
With this information, we can replay the user’s journey and reproduce the bug much more reliably. It also helps to distinguish whether a failure was triggered by a particular user action, or whether it occurred 'spontaneously' in the background.
Here’s a sample of how the logs look:
25/08/20 16:16:32.920+0300 | INFO | com.goldencode.p2j.ui.client.widget.TitledWindow | PID:81199, ThreadName:main, Session:00000017, ThreadId:00000001, User:bogus | Window opened: Display customer details 25/08/20 16:16:40.896+0300 | INFO | com.goldencode.p2j.ui.client.gui.ButtonGuiImpl | PID:81199, ThreadName:main, Session:00000017, ThreadId:00000001, User:bogus | User clicked: Next button. 25/08/20 16:16:42.037+0300 | INFO | com.goldencode.p2j.ui.client.gui.ButtonGuiImpl | PID:81199, ThreadName:main, Session:00000017, ThreadId:00000001, User:bogus | User clicked: Previous button. 25/08/20 16:16:43.024+0300 | INFO | com.goldencode.p2j.ui.client.gui.ButtonGuiImpl | PID:81199, ThreadName:main, Session:00000017, ThreadId:00000001, User:bogus | User clicked: Next button.
By default, these logs are suppressed. In directory.xml, the config for the relevant classes will be set to WARNING:
<node class="string" name="com.goldencode.p2j.ui.client.gui.ButtonGuiImpl">
<node-attribute name="value" value="WARNING"/>
</node>
<node class="string" name="com.goldencode.p2j.ui.client.widget.TitledWindow">
<node-attribute name="value" value="WARNING"/>
</node>
If we want these events to be logged, we simply change the level to INFO for the same entries.
#8 Updated by Hynek Cihlar 11 months ago
Paula, I like the idea. Two suggestions.
1. I think it would be even better to extend this to all widgets. I.e. pick the interesting events involved in UI navigation (CHOOSE, MOUSE events, etc.) and log those at a location where they are dispatched to the widgets.
2. Document this in Debugging_GUI.
#9 Updated by Paula Păstrăguș 11 months ago
- % Done changed from 0 to 50
Committed finest level logging for window open/close and mouse click events as rev 16135 / 10451a.
Next, I’ll review which additional events might be useful to log. Not all events will be included, since we want to avoid unnecessary overhead even in a testing system. I’ll focus on those that provide the most value.
#10 Updated by Paula Păstrăguș 11 months ago
- Status changed from WIP to Review
- File example.log
added - % Done changed from 50 to 100
- window open / close
- widget clicks
- TAB / ENTER key input events
This should be sufficient for now, since navigation typically occurs through TAB, ENTER, or mouse clicks. I’ve attached an example log output for reference.
Hynek, please review.
#11 Updated by Hynek Cihlar 11 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Code review 10451a.
The "window closed" log output is a bit misleading. It is logged in the remove method of WindowManage. Close operation simetime means a window is closed/hidden rather than destroyed. Also remove is not very meaningful for the navigation, the method is called when a window widget gets out of scope. This could have different timing than just closing a window.
For the key events logging I think it would make it more useful if more information is included in the output, like widget id/name/type/etc. And rather than posting the event it is better to log the event when it is dispatched as dispatch closer to the related UI actions.
Please make the added toString output more in line with the existing formats of the other widgets.
Some UI navigation actions are triggered on mouse release, for these cases, click doesn't even need to come.
When creating logger with Class resolution (name) it is better to pass the Class and let the logger facility to come up with the name. This ensures consistency.
#12 Updated by Paula Păstrăguș 11 months ago
Hynek Cihlar wrote:
The "window closed" log output is a bit misleading. It is logged in the
removemethod ofWindowManage. Close operation simetime means a window is closed/hidden rather than destroyed. Alsoremoveis not very meaningful for the navigation, the method is called when a window widget gets out of scope. This could have different timing than just closing a window.
Would it make more sense to handle this on show/hide and log based on the window’s visibility?
Some UI navigation actions are triggered on mouse release, for these cases, click doesn't even need to come.
I’m not sure I fully understand what you’re trying to highlight here. If we also add logs on mouse release, it would just duplicate the existing mouse clicked logs in this branch, since a mouse click is already the combination of press + release.
#13 Updated by Paula Păstrăguș 11 months ago
Hynek Cihlar wrote:
For the key events logging I think it would make it more useful if more information is included in the output, like widget id/name/type/etc. And rather than posting the event it is better to log the event when it is dispatched as dispatch closer to the related UI actions.
When you mention dispatch, I assume you’re referring to the code in TC.apply around line 4953:
try
{
doInteractive(() -> applyWorker(event));
}
This is where the event gets applied to the corresponding in focus widget. Do you want me to add the logging there?
#14 Updated by Hynek Cihlar 11 months ago
Paula Păstrăguș wrote:
Would it make more sense to handle this on show/hide and log based on the window’s visibility?
I think so.
I’m not sure I fully understand what you’re trying to highlight here. If we also add logs on mouse release, it would just duplicate the existing mouse clicked logs in this branch, since a mouse click is already the combination of press + release.
Click is a combination of press + relase, but both must happen in a short time frame. If they are further appart no click event is generated. Try button widget for example, press a mouse on it, wait a couple of seconds and then release.
#15 Updated by Hynek Cihlar 11 months ago
Paula Păstrăguș wrote:
Hynek Cihlar wrote:
For the key events logging I think it would make it more useful if more information is included in the output, like widget id/name/type/etc. And rather than posting the event it is better to log the event when it is dispatched as dispatch closer to the related UI actions.
When you mention dispatch, I assume you’re referring to the code in
TC.applyaround line4953:[...]
This is where the event gets applied to the corresponding in focus widget. Do you want me to add the logging there?
I meant the location where events are dequeued from the event queue and processed. TC.processProgressEvent seems like a good fit.
#16 Updated by Paula Păstrăguș 11 months ago
Hynek, if we add the logging directly in ThinClient, the web_gui log will quickly fill up with entries like:
INFO | com.goldencode.p2j.ui.chui.ThinClient | PID:24187, ThreadName:main, Session:00000018, ThreadId:00000001, User:bogus | Drawing with null widget
I’m not convinced ThinClient is the right place for key input events logs, since many of the messages logged there aren’t really intended for debugging. The log file size increases very quickly.
As an alternative, we could make an exception and log these at WARNING (or another higher level), so we don’t end up recording every detail just for debugging purposes.
#17 Updated by Hynek Cihlar 11 months ago
Paula Păstrăguș wrote:
Hynek, if we add the logging directly in ThinClient, the web_gui log will quickly fill up with entries like:
Please post the diff.
#18 Updated by Paula Păstrăguș 11 months ago
- File web_gui_pmp_54066_bogus_0.log
added - File 10451a.patch
added
I attached the patch. (reverted window manager, event manager, logs for show / hide are now handled by TitledWindow and ModalWindow. In TC I've added logs for tab / return / choose key).
What I wanted to highlight in my prev note can be seen in the attached logs.
#19 Updated by Hynek Cihlar 10 months ago
Paula Păstrăguș wrote:
I attached the patch. (reverted window manager, event manager, logs for show / hide are now handled by TitledWindow and ModalWindow. In TC I've added logs for tab / return / choose key).
What I wanted to highlight in my prev note can be seen in the attached logs.
Please puth a break point where "Drawing with null widget" is logged and see what cases cause these. I suppose there will be a small number (if not one) place where null widget is passed to eventDrawingBracket.
#20 Updated by Paula Păstrăguș 10 months ago
It is caused because we're posting COM-EVENTS with a null source:
ServerEvent{ (-1), source=null, id=1850, name=COM-EVENT, resourceId=1619238176, eventDrawing=false}
Those will be treated as follows: TC.waitForEvent -> applyWorker(Event) -> eventDrawingBraket(...).
The server events are emitted from the ps timer ticks.
#21 Updated by Hynek Cihlar 10 months ago
Paula Păstrăguș wrote:
It is caused because we're posting
COM-EVENTSwith a null source:[...]
Those will be treated as follows: TC.waitForEvent -> applyWorker(Event) -> eventDrawingBraket(...).
The server events are emitted from the ps timer ticks.
For these events (ServerEvent with null source) we should not use eventDrawingBracket.
#22 Updated by Paula Păstrăguș 10 months ago
- % Done changed from 90 to 100
- Status changed from WIP to Review
Committed changes as rev 16137.
Hynek, please review.
#23 Updated by Hynek Cihlar 10 months ago
Code review 10451a.
Instead of outputting custom message for evety distinct key code, just make the output generic. A single message, to get the name of the event based on code, call Keyboard.eventName.
Logging the event at the location in processProgressEvent is too early. It is still far to reach the target, there are multiple paths leading to early exit not reaching the target widget. Instead I suggest to log the events in TitledWindow.processEvent.
ButtonListGuiImpl.Item toString output should hold the class name including the enclosed class: ButtonListGuiImp.Item. Also, should textWidget.getText() be protected for null?
If the log output should function as a tool for tracing UI flow then it is better to have a dedicated logger for all of these outputs. Enabling the logger will only bring in the needed set of outputs not spoiling the log with other entries.
#24 Updated by Paula Păstrăguș 10 months ago
- % Done changed from 100 to 80
- Status changed from Review to WIP
Hynek Cihlar wrote:
If the log output should function as a tool for tracing UI flow then it is better to have a dedicated logger for all of these outputs. Enabling the logger will only bring in the needed set of outputs not spoiling the log with other entries.
Hynek, are you suggesting that instead of using the CentralLogger, we should use a custom logger that can be enabled through directory.xml..?
#26 Updated by Hynek Cihlar 10 months ago
Paula, what I meant was using CentralLogger but through a dedicated logger instance. Normally, we have one instance per Java class, retrieved via CentralLogger.get(), but for UI flow logging we would use a single dedicated instance shared across all places that log the UI flow.
This instance could be wrapped in a new class (e.g., UITrace or a similar name) and exposed through a static public method like getLogger.
UI tracing would then be enabled using the existing logging infrastructure and its configuration. No changes to the logging infrastructure itself would be required.
#27 Updated by Paula Păstrăguș 10 months ago
Hynek, thanks for the detailed review!
Quick question: should we log every key input handled in TitledWindow.processEvent, or limit it to these keys: TAB, RETURN, and CHOOSE?
#28 Updated by Hynek Cihlar 10 months ago
Paula Păstrăguș wrote:
Hynek, thanks for the detailed review!
Quick question: should we log every key input handled in TitledWindow.processEvent, or limit it to these keys: TAB, RETURN, and CHOOSE?
I think it will be useful to also log all real keys (KeyInput.isRealKey()) beside the events above.
#29 Updated by Paula Păstrăguș 10 months ago
Hynek Cihlar wrote:
Also, should
textWidget.getText()be protected fornull?
textWidget is never null since it’s initialized in the constructor. getText() can return null, but that doesn’t cause issues. It’s actually useful to log null values in the web client logs to confirm when no text has been set.
#30 Updated by Paula Păstrăguș 10 months ago
- Status changed from WIP to Review
- % Done changed from 80 to 100
Addressed review as rev 16138.
Hynek, please review.
#31 Updated by Hynek Cihlar 3 months ago
- % Done changed from 100 to 90
- Status changed from Review to WIP
Code review 10451a revisions 16134..16138
- [MAJOR] functional
ButtonListGuiImpl.Item.toString:textWidgetcan benullwhentoString()is called. Add a null guard. - [MAJOR] functional
MouseHandler.applyMouseEvent: Mouse release events (MOUSE_RELEASED) are not logged. The issue spec explicitly requires mouse release logging, but onlyMOUSE_CLICKEDhas theUI_LOGGER.finest(...)call added. - [MAJOR] performance
MouseHandler.applyMouseEvent:UI_LOGGER.finest(mouseSource + " was clicked.")performs unconditionalmouseSource.toString()and string concatenation on every mouse-click event, regardless of whether FINEST is enabled. UseUI_LOGGER.log(Level.FINEST, () -> ...)or guard withisLoggable. - [MINOR] performance
TitledWindow.dispatchEvent: The key-dispatch logging block unconditionally callsKeyboard.eventName(action)and builds the concatenated log string even when FINEST is disabled. TheisLoggableKeyguard filters by event kind but not by log level. Wrap the entire block in aUI_LOGGER.isLoggable(Level.FINEST)guard. - [MINOR] performance
TitledWindow.show:UI_LOGGER.finest("Window " + this + " was shown.")performs unconditional string concatenation andtoString()on every invocation regardless of log level. Same applies toTitledWindow.hideandModalWindow.show. UseUI_LOGGER.log(Level.FINEST, () -> ...)or guard withisLoggable. - [MINOR] style
UITracker: The license block uses a leading space before**on every line (** text) instead of the standard** textformat used in the module header. - [MINOR] style
TitledWindow: Two explicit class imports (CentralLoggerandUITracker) from the same packagecom.goldencode.p2j.util.logginginstead of a single wildcard import.
#32 Updated by Paula Păstrăguș 3 months ago
- % Done changed from 90 to 100
- Status changed from WIP to Review
Addressed review as rev 16139.
Next, I'll rebase the branch to retest the behavior.
#33 Updated by Paula Păstrăguș 3 months ago
I rebased 10451a, new rev is 16521. (is should have been 16520, but the last rev contains a small rebase fix).
#34 Updated by Paula Păstrăguș 3 months ago
I performed some initial testing and it appears to work as expected. I'll continue with more extensive testing once it reaches the internal testing phase ( + also document this within the Debugging GUI wiki afterwards).
However, to ensure that the logs are visible in the web client log file, we need to include the following node in the loggers container within directory.xml:
<node class="string" name="com.goldencode.p2j.util.logging.UITracker">
<node-attribute name="value" value="FINEST"/>
</node>
#35 Updated by Hynek Cihlar 3 months ago
Logging the keyboard events (and the types keys) is a potential security issue (consider passwords entered by the end users). Greg, what do you think? Should we deliver code that could be misused for spying on users?
#36 Updated by Paula Păstrăguș 3 months ago
From my POV, this feature is meant strictly for a testing environment, not for production use. Still, you raise a fair point, it could introduce a security concern. However, logging the typed keys is genuinely helpful when a problematic or unexpected character causes the application to behave incorrectly.
#37 Updated by Hynek Cihlar 3 months ago
Paula Păstrăguș wrote:
From my POV, this feature is meant strictly for a testing environment, not for production use. Still, you raise a fair point, it could introduce a security concern. However, logging the typed keys is genuinely helpful when a problematic or unexpected character causes the application to behave incorrectly.
Yes, I agree the feature is useful.
#38 Updated by Paula Păstrăguș 3 months ago
Maybe we can exclude password fill-ins from logging. There is a place in counteract where users actually enter passwords, so filtering those out would avoid exposing sensitive data.
#39 Updated by Greg Shah 3 months ago
I agree this is a potential security risk. It is enabled purely by setting a logging level, right? That is something that could be easily overlooked.
Let's add a one time WARNING entry to the logs when this logging is active. This should be something like "Keylogging is activated on this server. This may cause a SECURITY or PRIVACY breach. It should only ever be enabled in a TEST or DEVELOPMENT environment, this is not suitable for production!".
With this, it should be more likely to catch a mis-configuration.
#40 Updated by Hynek Cihlar 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Code review 10451a revisions 16515..16521
- [MAJOR] performance
TitledWindow.processEvent: In the newKeyInputbranch,keyEvent.actionCode(),Keyboard.eventName(action)(string allocation/lookup), andkeyEvent.isRealKey()are all invoked on every dispatched key event BEFOREUI_LOGGER.isLoggable(Level.FINEST)is checked. Key dispatch is a hot path; this imposes per-keystroke overhead even when FINEST is disabled. The history entry advertises "Guarded finest logging in ... key dispatch processing", but the guard is placed after the expensive computation. Move theisLoggablecheck outer-most so theeventNamecomputation is only performed when logging is enabled. - [MAJOR] functional
TitledWindow.show/hide: The diff addsimport com.goldencode.p2j.ui.client.gui.OverlayWindow;and twoinstanceof OverlayWindowguards intoTitledWindow(packagecom.goldencode.p2j.ui.client.widget), which had no GUI-package dependencies and is the base of CHUI widgets such asOuterFrame. Leaking a concrete GUI subtype reference into a driver-agnostic base inverts the dependency direction. SinceTopLevelWindowalready declares an abstractgetRelativeTo(), either (a) introduce aprotected boolean isTransientCursorRelative()hook onTitledWindow(defaultfalse, overridden byOverlayWindowto returntruewhengetRelativeTo() == RELATIVE_TO_CURSOR), or (b) move the logging intoTopLevelWindow.show/hidewheregetRelativeTo()is already in scope without a cast. - [MINOR] functional
ModalWindow.show: The"Window ... was shown."log is emitted before any of the actual show work -realize(),forceVisibility(true),gd.setWindowVisible(true),WindowManager.modalizeWindow(this),WindowManager.forceActivateWindow(this, true). Any of these can throw, leaving the trace claiming success when the window was never actually shown. Move the log to after those steps, or change wording to"is being shown.". - [MINOR] functional
Item.toString: Hardcodes the class name as the literal"ButtonListGuiImpl.Item"instead of usinggetClass().getSimpleName()or delegating tosuper.toString().AbstractWidget.toString()already emitsgetClass().getSimpleName() + " [id=" + Utils.nonNull(getId(), "<null>") + "]", andMenuItemGuiImpl.toString()correctly follows thesuper.toString() + " title=" + ...pattern.Itemis non-final so hardcoding defeats the existing pattern and breaks on subclass/rename. - [MINOR] functional
Item.toString:textWidget.getText()may itself returnnull(the underlyingTextCell.getText()returns the text field unguarded, andsetText()permits null), yieldingtitle=nullin the output. UseUtils.nonNull(textWidget.getText(), "")for consistency withTitledWindow.toString(). - [MINOR] performance
TitledWindow.hide: Theinstanceof OverlayWindowtest, cast, andgetRelativeTo()call are evaluated on everyhide()before theisLoggableguard. Reorder soUI_LOGGER.isLoggable(Level.FINEST)is checked first to short-circuit when FINEST is off. - [MINOR] performance
TitledWindow.show: Same pattern ashide(); putisLoggablefirst in the outer check so theinstanceof/getRelativeTo()work is skipped when logging is disabled. - [MINOR] style
TitledWindow: Newimport java.util.logging.Level;uses an explicit class import where the project convention is.*unless a conflict requires an explicit import. - [MINOR] style
MouseHandler: Newimport java.util.logging.Level;uses an explicit class import where the project convention is.*. - [MINOR] style
TitledWindow: Newimport com.goldencode.p2j.ui.client.gui.OverlayWindow;is an explicit single-class import; the convention iscom.goldencode.p2j.ui.client.gui.*unless a naming conflict exists. (Note: introducing this import at all is flagged separately as an architectural concern.)
#41 Updated by Paula Păstrăguș 3 months ago
- Status changed from WIP to Review
- % Done changed from 90 to 100
Addressed code review as rev 16522. I also added the one time warning.
Hynek, please review. Thanks!
#42 Updated by Hynek Cihlar 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Code review 10451a revisions 16515..16522
- [MAJOR] security
UITracker.<clinit>: The keylogger warning is emitted only atLevel.FINESTand only inside the class's static initializer. (1) It is logged at the same level as the keystrokes themselves, so an operator who has turned on FINEST forUITrackerbut routes only INFO+ to operator-visible sinks will never see the warning. The Redmine summary explicitly states the warning should be at WARNING level. (2) The warning fires at most once - at class-load time; if FINEST is enabled later viaCentralLogger.setLevels()the warning never fires while keystroke logging starts working. (3) Conversely, if the class loads before FINEST is enabled, the static init guardif (LOG.isLoggable(Level.FINEST))evaluates false and the warning is never emitted.
- [MAJOR] functional
Item.toString:textWidgetitself can be null. The field is initialized lazily increateOrUpdateComponents()/recomputeSize(), which has an early-return path whenwindow() null, leavingtextWidgetuninitialized. The expressiontextWidget.getText()will throw NPE beforeUtils.nonNullever sees the value. The history comment says "Added NPE protection," butUtils.nonNull(...)only protects against a null return fromgetText(), not againsttextWidgetitself being null. With the newMouseHandlerlogging usingmouseSource + " was clicked.", an Item whose layout has not yet completed (or after a window destroy that nulls children) will throw NPE insideapplyMouseEvent, propagating throughhandleMouseEventand corrupting the UI event chain. Add a null guard, e.g.textWidget null ? "" : Utils.nonNull(textWidget.getText(), "").
- [MINOR] performance
TitledWindow.processEvent:Keyboard.eventName(action)is computed before theisLoggableKeycheck. For non-loggable keys (the vast majority of keystrokes - any modifier, function key, etc., that is notTAB/RETURN/CHOOSE/real-key), this produces a wasted String allocation per key event whenever FINEST is enabled. Move theeventNamecomputation inside theif (isLoggableKey)block so it only runs when actually needed.
- [MINOR] functional
TitledWindow.show: The FINEST log fires near the end ofTitledWindow.show()but BEFORE subclass code inOverlayWindow.show()andWindowGuiImpl.show()completes (e.g.,gd.setWindowVisible(true)). The log records that the window "was shown" before the driver-level visibility is actually set. By contrast,ModalWindow.show()logs at the end afterforceActivateWindow()(correct timing). For consistency, consider moving the log to occur after the full subclass-specific show sequence.
- [MINOR] functional
ModalWindow.show: Logging is duplicated logic instead of leveragingsuper.show(). The rest of the subclass hierarchy (OverlayWindow,WindowGuiImpl,FrameOverlay,DialogBoxWindow,AlertBoxGuiImpl) callssuper.show()to inherit logging, butModalWindow.show()does not callsuper.show()(it has its own divergent implementation). The added log message string is hand-copied fromTitledWindow.show(). If the format diverges, the two paths drift. Suggested fix: extract a small helper such aslogShown()onTitledWindowthat both paths invoke.
- [MINOR] functional
ModalWindow.show: The show log lacks the!isTransientCursorRelative()guard used inTitledWindow.show()/hide(). SinceModalWindowis never cursor-relative this is currently harmless, but if a future modal subtype needs to suppress its show log there is no hook. Suggested fix: gate the log with the same guard for design consistency.
- [MINOR] functional
Item.toString: Formatting deviates from the established convention. Other GuiImpltoString()methods (e.g.AbstractWidget,BrowseGuiImpl,TitledWindow) usegetClass().getSimpleName() + " [id=..."with a leading space before the bracket; the new code emitsgetClass().getSimpleName() + "[id=..."with no space, producing output likeItem[id=...]instead ofItem [id=...]. Add the leading space for visual consistency in logs.
- [MINOR] functional
Item.toString: The override returnsgetClass().getSimpleName() + "[id=...]"and entirely drops the parent'ssuper.toString()info. The convention in sibling classes (MenuItemGuiImpl,SubMenuGuiImpl) is to extend it viasuper.toString() + " title=" + .... Not a defect but consider chaining tosuper.toString()to keep any future parent-added fields visible and avoid duplicating the id/class header.
- [MINOR] functional
MouseHandler.applyMouseEvent: The new FINEST log is placed AFTER the call tomouseSource.mouseClicked(evt)/mouseSource.mouseReleased(evt). If the widget's handler throws (or terminates the dispatch via an exception path), the FINEST entry will not be emitted, so the log will not reflect that the event was actually delivered. Additionally, if a click handler causes the widget to be destroyed before the log statement executes,toString()could touch null/disposed state (especially relevant given the newButtonListGuiImpl.Item.toString()override that dereferencestextWidget). Suggested fix: move the log line above the dispatch, or wrap it in try/finally.
- [MINOR] functional
MouseHandler.applyMouseEvent: The chosen pairMOUSE_CLICKED+MOUSE_RELEASED(withoutMOUSE_PRESSED) is asymmetric and likely accidental. The natural mouse interaction sequence is PRESSED -> RELEASED -> CLICKED; logging RELEASED and CLICKED but not PRESSED makes the trace harder to interpret (e.g. drag-then-release-outside scenarios produce a RELEASED log with no preceding PRESSED context). Suggested fix: either also add a FINEST log in theMOUSE_PRESSEDbranch, or document whyMOUSE_PRESSEDis intentionally suppressed.
- [MINOR] functional
MouseHandler.applyMouseEvent: The log messagemouseSource + " was clicked."discards the actualMouseEventpayload (button, click count, modifiers, coordinates).MOUSE_CLICKEDcan fire with click counts > 1 (double-click) and with different buttons (BUTTON1/2/3); the log entry as written cannot distinguish a left-click from a right-click or a single from a double-click on the same widget. Suggested fix: includeevt.getButton(),evt.getClickCount(), and possiblyevt.getX()/evt.getY()in the log message.
- [MINOR] functional
TitledWindow.processEvent: When the innersource.processEvent(event)triggers a focus change or destroys the widget, the subsequentUI_LOGGER.finest("'" + eventName + "' key dispatched for source = " + source)callstoString()on a potentially-disposed widget, which can in turn call user code (configuredtoStringoverrides like the newButtonListGuiImpl.Item.toStringwhich can NPE). Move the log line abovesource.processEvent(event)(with wording adjusted to "dispatching") to keep diagnostics safe and to also capture cases where the dispatch throws. Even if the widget destroy is currently impossible I think it makes sense to harden the code for potential future changes.
- [MINOR] style
ModalWindow: Copyright year in the file header is2015-2025but new history entries are dated20260415. Update the copyright to2015-2026.
- [MINOR] style
TitledWindow: Copyright year is updated only to2010-2025, but new history entries are dated up to20260423. Update copyright to2010-2026.
#43 Updated by Paula Păstrăguș 3 months ago
- Status changed from WIP to Review
- % Done changed from 90 to 100
Addressed code review as rev 16523.
#44 Updated by Hynek Cihlar about 2 months ago
- Status changed from Review to Internal Test
Code review 10451a revisions 16515..16523
The changes look good, please address the following style issue and go ahead with regression testing. Also please update the wiki unless you already did.
- [MAJOR] style
MouseHandler.logMouseEvent: Line 942 is 134 characters, exceeding the 110-character limit. TheUI_LOGGER.finest(mouseSource + " was clicked. Button = " + evt.getButton() + ", click count = " + evt.getClickCount())call must be wrapped across multiple lines.
#45 Updated by Paula Păstrăguș about 2 months ago
Addressed as rev 16524.
I'm starting regression testing.
#46 Updated by Paula Păstrăguș about 2 months ago
The wiki has been updated and is available at Debugging GUI.
Regression testing did not reveal any issues. I smoke tested Counteract and Hotel GUI, both with logging enabled and disabled, and everything looked fine.
Please let me know if there is another large GUI application that should be tested as well, and I will ask Serban to do it. Thanks!
#47 Updated by Hynek Cihlar about 2 months ago
Paula Păstrăguș wrote:
Please let me know if there is another large GUI application that should be tested as well, and I will ask Serban to do it. Thanks!
Please also run ChUI regression tests.
#48 Updated by Paula Păstrăguș about 2 months ago
10451a was rebased, new rev is 16589.
#49 Updated by Paula Păstrăguș about 2 months ago
I started the ChUI regression tests. In the best case scenario, we should have the results by EOD.
#50 Updated by Paula Păstrăguș about 2 months ago
Here are the results from yesterday:
- gso_282 failed: expected.
- gso_320 failed: not expected. However, Teodor also ran the ChUI regression tests and this failed there as well, so it may be a false positive.
- gso_418 failed: expected.
- gso_478 failed: expected.
- tc_inquiry_inventory_009 failed: not expected. However, after seeing the failures, I ran the ChUI regression tests again and this test passed..
- tc_job_matlcron_002 failed: expected.
- tc_ap_vchrs_011 failed: not expected. Same as above, this passed on the second run.
It looks like something in trunk is causing some kind of non-deterministic behavior. Teodor mentioned that he will run the tests using a fresh setup with trunk, so let's wait for those results and see what we can conclude.
From my point of view, these failures should not be caused by 10451a. Most of the changes are guarded by the UITracker logger configuration in directory.xml, if that logger is not enabled, the behavior should remain unchanged. The only change I can think of outside that area is the one from TC, but that is only NPE protection.
#51 Updated by Paula Păstrăguș about 2 months ago
I have Serban's approval for testing with another application and Teodor's approval for the ChUI Regression Testing. If there is nothing else left to test, I think we can proceed with the merge.
#52 Updated by Hynek Cihlar about 2 months ago
- Status changed from Internal Test to Merge Pending
Please merge 10451a to trunk.
#53 Updated by Paula Păstrăguș about 2 months ago
- Status changed from Merge Pending to Test
Branch 10451a was merged into trunk as rev. 16583 and archived.