feat: ModifiedGutter pattern for property editors#6697
Draft
vlsi wants to merge 8 commits intoapache:masterfrom
Draft
feat: ModifiedGutter pattern for property editors#6697vlsi wants to merge 8 commits intoapache:masterfrom
vlsi wants to merge 8 commits intoapache:masterfrom
Conversation
Adds two related improvements to JEditableCheckBox:
* The check-box label, true/false captions, and the "Use Expression"
menu item now go through a ResourceLocalizer so they can be
translated from JMeter resource bundles.
* A small ellipsis button (and a matching popup menu item) lets the
user switch the editor to expression mode, where a free-form text
field accepts ${variable} / ${__P(...)} expressions instead of a
plain boolean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…xpressionMode
Adds a new pair of Kotlin GUI components — JEnumPropertyEditor (for
enum-typed properties) and the underlying JEditableComboBox — together
with the supporting infrastructure for binding them to a TestElement.
The configuration uses two sealed types:
* `UnsetMode` — `Forbid` or `Allow(unsetValue)` — controls whether the
combobox lets the user clear the selection. The unset entry is shown
in italics and the editor reports `null` when it is selected.
* `ExpressionMode` — `Forbid` or `Allow(useExpression, useExpressionTooltip)` —
controls whether the combobox can be switched to a free-form text
field for `${variable}` / `${__P(...)}` expressions.
JEnumPropertyEditor exposes a `JEnumPropertyEditor.create(...)` factory
that picks sensible defaults for `unsetMode` / `expressionMode`, plus a
data-class `Configuration` for callers that need full control.
Refactors EnumEditor / ConstantThroughputTimer / CSVDataSet so that
the schema-based property descriptors are consistent with the new
editor, and tightens GenericTestBeanCustomizer accordingly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a left-side accent strip (ModifiedGutter) that lights up next to a
property editor when its value is explicitly stored on the test
element. Follows the gutter pattern used by IntelliJ IDEA and VS Code,
keeping configuration forms visually quiet.
Key changes:
* New ModifiedGutter wrapper panel with a LaF-aware accent colour
(muted when the wrapped control is disabled) and a public
isModified property that fires PropertyChangeEvents. The gutter
slot is reserved even when transparent, so toggling the state never
causes a layout shift.
* JEditableCheckBox / JEditableComboBox grow a public isModified and
a protected resetToDefault hook; their root layout becomes
BorderLayout (gutter on the left), the original CardLayout moves
into an inner cardPanel.
* New ResetMode sealed type wires a "Reset to default" entry into the
popup menu of the editors. The action is enabled only while the
gutter is lit, and the popup is reachable both from the regular
card and from the expression card.
* Explicit-set semantics: JBooleanPropertyEditor / JEnumPropertyEditor
use a suppress flag so any user-driven value change marks the
editor modified (and stays modified until reset, even if the user
happens to land back on the default value). Loading from a
TestElement marks the editor modified iff the property is actually
stored on the element, and updateElement is gated on isModified —
so the gutter, the test element and a save/reload round-trip all
agree even when the explicit value happens to equal the default.
* Tests:
* ModifiedGutterTest covers layout reservation, property-change
semantics, and accessibility description.
* JEditableCheckBoxModifiedTest guards against regressions in the
value getter/setter after the layout refactor.
* JEditableCheckBoxGutterSemanticsTest exercises the full state
machine via a test-double subclass that mirrors the production
pattern.
* JBooleanPropertyEditorTest and JEnumPropertyEditorTest exercise
the full updateElement → updateUi cycle through a real
AbstractTestElement, including round-trip preservation of
explicit values that equal the default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…-as-reset
Adds a third gutter-aware property editor for plain string properties,
together with a backspace gesture that resets the field to its default
when invoked on an already-empty modified field.
Key changes:
* New JEditableTextField in jorphan.gui — a gutter-wrapped JTextField
with an optional Reset action in the popup menu. There is no
separate expression card: free-form text already accepts
${expressions}, so a card switch would just add chrome.
* "Quick reset" via Backspace / Delete: pressing the delete key on
an empty modified field is interpreted as "undo my custom value",
saving a popup trip. The first backspace clears the last character;
the next backspace on the now-empty field resets to default and
clears the gutter.
* New JStringPropertyEditor in core.gui — binds JEditableTextField to
a StringPropertyDescriptor with the same explicit-set semantics as
JBooleanPropertyEditor / JEnumPropertyEditor (suppress flag,
value-change listener, updateUi marks the editor modified iff the
property is stored on the element). Persistence is symmetric:
updateElement removes the property when not modified and stores the
value verbatim when modified, so explicit empty strings now survive
a save/reload round-trip.
* HttpTestSampleGui: embeddedAllowRE / embeddedExcludeRE are now
JStringPropertyEditor instances and provide the first smoke-test of
the gutter pattern on text inputs. The MigLayout column constraints
on the surrounding panel are tightened so that the two URL labels
share column 0 and their fields line up under the wider checkbox
row above (the original switch dragged the labels far from their
fields).
* JEditableTextFieldGutterSemanticsTest covers the full state machine,
the popup menu wiring, and the backspace / delete gestures.
* JStringPropertyEditorTest exercises updateElement → updateUi through
a real AbstractTestElement, including the round-trip case for an
explicit empty string.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a multi-line counterpart to JEditableTextField — same gutter, same Reset action, same backspace-as-reset gesture (triggered only when the entire text area is empty). * New JEditableTextArea in jorphan.gui. The text area is added directly to the gutter without a JScrollPane so that short comment-style fields render naturally; callers that need scrolling can wrap the editor or its inner JTextArea externally. * AbstractJMeterGuiComponent.commentField is now backed by a JEditableTextArea. The legacy `commentField` JTextArea reference is retained and points at the editor's inner text area so existing setText / getText callers keep working unchanged. The editor uses a simple "non-empty == modified" rule rather than the explicit-set semantics from JStringPropertyEditor — comments have no notion of "default vs absent", just "set vs cleared", so the listener recomputes the modified flag from the live text on every value change. * New JEditableTextAreaGutterSemanticsTest covers the same scenarios as the text-field test plus a check that multi-line content is read back verbatim and that backspace inside multi-line text falls through to the standard JTextArea behaviour (16 scenarios). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "Use Expression" action was previously surfaced both as an entry in the popup menu and as a small ellipsis button glued to the right of the checkbox / combobox. After "Reset to default" was added to the popup, the gutter became the primary visual indicator, and free-form text fields already work without an ellipsis button — keeping the persistent button only on checkboxes and comboboxes is inconsistent and adds visual noise to forms with many fields. Drops the button from JEditableCheckBox and JEditableComboBox. The Use Expression action remains reachable from the popup menu (right click on the control) on every editor type, which is symmetric with the Reset action and matches what JEditableTextField / JEditableTextArea have always done. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a "modified gutter" — a thin coloured strip on the left edge of property
editors that lights up when the field's value is explicitly stored on the test
element. Mirrors the IntelliJ IDEA / VS Code convention so users can tell at a
glance which fields they have overridden vs. which still inherit a default.
The series introduces:
ModifiedGutterwidget +UnsetMode/ExpressionMode/ResetModesealed types.JBooleanPropertyEditor,JEnumPropertyEditor,JStringPropertyEditor(single-line) andJEditableTextArea(multi-line).empty modified text field).
updateUi/updateElementso a save / reload round-trip preservesexplicit values that happen to equal the default.
Test plan
:src:jorphan:testand:src:core:testare greenembedded resources", "URLs must match", "URLs must not match"; Comment
field on any element. Save / reload a
.jmxand confirm explicit valuesare preserved.
🤖 Generated with Claude Code