Skip to content

Add C++ ScriptConstructor to replace QML filter/computed-column drag-and-drop constructors - #6306

Draft
JorisGoosen wants to merge 19 commits into
jasp-stats:developmentfrom
JorisGoosen:filterConstructorCPP
Draft

Add C++ ScriptConstructor to replace QML filter/computed-column drag-and-drop constructors#6306
JorisGoosen wants to merge 19 commits into
jasp-stats:developmentfrom
JorisGoosen:filterConstructorCPP

Conversation

@JorisGoosen

Copy link
Copy Markdown
Contributor

Introduces a UI-agnostic model layer and a C++ QQuickItem view that together
replace the JSON/QML/JS FilterConstructor and ComputedColumnsConstructor.

Model (CommonData):

  • ScriptNode tree with JSON round-trip and R code generation matching the old
    QML output byte-for-byte (operators, functions, row-functions, columns,
    literals), including na.rm handling and ifelse return types.
  • ScriptConstructorRegistry as the single source of truth for available
    operators/functions per mode (filter / computed column / computed dataset).
  • ScriptConstructorModel owning the formula tree with drop-target resolution
    (including the gobble-left behaviour), completeness/boolean checks and
    snapshot-based undo.

View (Desktop/qquick):

  • ScriptConstructorView (registered as ScriptConstructor) orchestrates layout,
    drag-and-drop, palettes, operator bar, inline literal editing and column type
    changes; leaf visuals are incubated QML (Text/Image/TextInput/CheckBox).

Integration:

  • FilterWindow.qml now uses ScriptConstructor for the drag-and-drop filter.

Tests:

  • Golden-R parity, 300-seed JSON round-trip fuzz, completeness, undo and
    DEFAULT_FILTER_JSON regression tests in testall.cpp.

Virtuoos Automatisch added 13 commits August 26, 2026 08:58
…and-drop constructors

Introduces a UI-agnostic model layer and a C++ QQuickItem view that together
replace the JSON/QML/JS FilterConstructor and ComputedColumnsConstructor.

Model (CommonData):
- ScriptNode tree with JSON round-trip and R code generation matching the old
  QML output byte-for-byte (operators, functions, row-functions, columns,
  literals), including na.rm handling and ifelse return types.
- ScriptConstructorRegistry as the single source of truth for available
  operators/functions per mode (filter / computed column / computed dataset).
- ScriptConstructorModel owning the formula tree with drop-target resolution
  (including the gobble-left behaviour), completeness/boolean checks and
  snapshot-based undo.

View (Desktop/qquick):
- ScriptConstructorView (registered as ScriptConstructor) orchestrates layout,
  drag-and-drop, palettes, operator bar, inline literal editing and column type
  changes; leaf visuals are incubated QML (Text/Image/TextInput/CheckBox).

Integration:
- FilterWindow.qml now uses ScriptConstructor for the drag-and-drop filter.

Tests:
- Golden-R parity, 300-seed JSON round-trip fuzz, completeness, undo and
  DEFAULT_FILTER_JSON regression tests in testall.cpp.
- Column palette now falls back to ColumnsModel::singleton() (the
  columnsModel Q_PROPERTY shadowed the QML context property, so the
  palette was empty).
- Add ScriptPalette with mouse-wheel and drag-to-scroll for the column
  and function palettes.
- Drop spots accept inline typing: clicking an empty slot focuses a
  TextInput that parses number -> string -> boolean on edit-finish.
- rebuild() now recursively renders child nodes into filled drop spots,
  and drop spots/leaves get explicit sizes so they are visible/clickable.
- View implements ScriptColumnTypeProvider, resolving real column types
  from the columns model for R generation (previously always fell back
  to scale); columnTypeDrop is resolved on drop and re-resolved when the
  user changes a column's type while it sits in a slot.
- Drag/drop hardening: scene->local coordinate mapping, skip filled and
  own-subtree drop spots, prefer deepest spot, clean up the dragged item.
- Add hint text area, error markers on incomplete slots, trash icon, and
  filterErrorMsg property.
- Add headless QML smoke test (tst_scriptconstructor.qml) verifying the
  view instantiates and the JSON->R/apply flow works.
- Wire the generated-R code display for computed columns (reserve bottom
  space, show/update on edit, hide in filter mode).
- Add sqrt and ! to the operator bar as operator-bar-only functions.
- Render function math symbols (sum/prod/sd/var and row variants) as images.
- Wrap nested operator/function args in parentheses.
- Fix operator "gobble left" on drop into empty space.
- Integrate ScriptConstructor into ComputeColumnWindow.
- Add engine-execution fuzz test that runs generated R through the engine.
- Right-clicking an element now rebuilds the view after removing the node,
  preventing a crash from dangling ScriptNode pointers in stale items.
- Cycling a column's type now refreshes the whole view so the icon and parent
  layout update to the newly selected type.
- Column icons use the "transformed" variant (asterisk) when the column's
  effective type differs from its dataset type.
- Clicking a column icon in a restrictive drop slot shows the allowed types
  instead of silently cycling to a type that would be reverted.
- Row functions lay out their "row" text + symbol image correctly, and always
  keep a trailing free drop slot so more columns can be added.
Replace the modal MessageForwarder dialog with QToolTip::showText so the
"Only <types> allowed" notice appears transiently near the clicked icon and
does not block interaction. The message remains translatable via tr().
- Separate function and row-function arguments with commas.
- Wrap function arguments in parentheses (single-arg math symbols like sum/SD omit them).
- Centre the operator row within the top bar.
- Autosize the column/function palettes to their widest entry (capped at a third of the view).
- Show the column-type restriction tooltip ~10x longer.
- Pin image implicit size to blockDim so icon images no longer blow up the
  layout to their source resolution (this made sqrt extremely wide).
- Render sqrt as a proper radical: a tall √ head plus an overline drawn above
  the argument; the operator bar shows the plain square-root symbol.
- Add the faint centred background decoration (filter vs computed-column).
- Make ScriptConstructorRegistry a QObject and wrap every operator/function/
  row-function tooltip in tr(), restoring the translatable strings.
- Restore the mode-dependent "returns logicals..." suffix for comparison and
  logical operators (and the "!" function) via ScriptOperatorDef::toolTipForMode.
- Add a ToolTip overlay (hover MouseArea, acceptedButtons: NoButton) to each
  ScriptNodeItem, showing the element's tooltip on hover without breaking
  drag & drop.
- Columns show "Click icon to change column type" plus description and
  transformed-type preview; the trash shows its old "Dump unwanted snippets"
  tooltip.
Store the untranslated source strings (via QT_TRANSLATE_NOOP) in the registry
and look them up with QCoreApplication::translate in toolTipForMode(), instead
of freezing them with tr() at singleton-construction time. This makes the
tooltips re-translate correctly after a live language change.
Distinguish the two division operators by making the operator lookup
vertical-aware (operatorDef now resolves via the vertical flag), so the
operator bar shows the fraction (\u00f7) and diagonal (/) distinctly instead
of two identical images. Render vertical division as a stacked fraction
(numerator over a horizontal bar over denominator) in the script area.

Make the constructor background watermark resize reactively once its
source image loads, fixing the filter constructor's missing watermark.
Remove the redundant white paint from ScriptConstructorView's
updatePaintNode so the background watermark (filter/column) is no longer
hidden behind it; both modes now show their image.

Double-clicking the trash zone now clears the constructor (undoable),
mirroring the old DropTrash.qml.

Centre drop-spot placeholder text so the vertical-division dots line up
under the fraction bar.
Comment thread CommonData/scriptconstructormodel.cpp Outdated
Virtuoos Automatisch and others added 2 commits August 27, 2026 13:20
Add local per-step undo to the constructor (own QUndoStack, focus-scoped
Ctrl+Z/Shift+Z, cleared when re-seeded from another filter/column), so
in-progress editing is undoable without touching the dataset stack.

Route computed-column code application through
SetComputedColumnCodeCommand and column creation through
CreateComputedColumnCommand, so the data-mode undo/redo buttons cover
computed columns the same way they already cover filters.

Replace magic 1/2/3 column-type constants with columnType enum values,
and drop the redundant columnTypeString in favour of the
DECLARE_ENUM-generated columnTypeToString.
@JorisGoosen
JorisGoosen force-pushed the filterConstructorCPP branch from a7cde49 to 3d99479 Compare August 27, 2026 11:24
JorisGoosen and others added 4 commits August 27, 2026 13:53
Replace the setProperty("border.*") calls (which silently fail on QML
group properties) with QQmlProperty writes, restoring the green/red hover
outline, the red incomplete-check outline and the trash-zone border.

Cache the watermark image's natural size on load and use it for the
scaling ratio, so the background scales back up after shrinking instead
of staying stuck at its smallest size (the sourceSize = width*2 binding
was making implicitWidth follow width).
…timers

- Fix ScriptConstructorToolTipArea TypeError by guarding null parent in the
  tooltip overlay binding (fired once per node item build)
- Fix FilterWindow tab anchoring: anchor the Flickable content to its grandparent
  was dropped by Qt (parent/sibling only), so the RowLayout instead stretches
  via a width binding; use dataSetModel.columnsLabelFilteredCount instead of
  the stale workspace reference
- Make column palette/tooltip builds O(N): cache column type/index/description
  per view (single pass via new ColumnsModel::provideInfoAt) and coalesce
  model-driven palette rebuilds through a 0ms timer
- Add JASPTIMER scopes across the constructor pipeline (enabled with
  JASP_TIMER_USED=ON) and print all timers on exit
…nd incubation timers

- Replace the per-item QtQuick ToolTip overlay with QToolTip::showText on
  hover (removes one QML incubation per node item and the tooltip-area
  component altogether)
- Add deferUntilVisible so the computed-column constructor only builds its
  chrome/palettes when the tab becomes effectively visible (itemChange +
  requestBuild + singleShot re-check); FilterWindow keeps building eagerly
- Add per-leaf-kind incubation timers (incubate <kind>, createSync <kind>,
  compile <kind>Component) to pinpoint whether first-use compilation or
  instantiation dominates constructor load time
- Add quicktest for deferred build
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant