This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 040cd17fba Add config options for all tooltips on the canvas, fixes
#8478 (#8532)
040cd17fba is described below
commit 040cd17fba626d5e3ce226ed172db40b046f0e76
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Thu Sep 24 09:16:41 2026 +0200
Add config options for all tooltips on the canvas, fixes #8478 (#8532)
* Add config options for all tooltips on the canvas, fixes #8478
* fix remarks
---
.../pages/hop-gui/perspective-configuration.adoc | 13 ++
.../HopGuiPipelineGraphClickContractTest.java | 89 +++++++++++++
.../ConfigGuiOptionsTabCanvasToolTipsTest.java | 146 +++++++++++++++++++++
.../main/java/org/apache/hop/ui/core/PropsUi.java | 14 ++
.../hopgui/file/pipeline/HopGuiPipelineGraph.java | 27 ++--
.../hop/ui/hopgui/file/shared/CanvasToolTip.java | 104 +++++++++++++++
.../ui/hopgui/file/shared/HopGuiAbstractGraph.java | 28 ++++
.../hopgui/file/workflow/HopGuiWorkflowGraph.java | 75 +++++++----
.../configuration/tabs/ConfigGuiOptionsTab.java | 50 +++++++
.../core/dialog/messages/messages_en_US.properties | 18 +++
.../ui/hopgui/file/shared/CanvasToolTipTest.java | 90 +++++++++++++
11 files changed, 616 insertions(+), 38 deletions(-)
diff --git
a/docs/hop-user-manual/modules/ROOT/pages/hop-gui/perspective-configuration.adoc
b/docs/hop-user-manual/modules/ROOT/pages/hop-gui/perspective-configuration.adoc
index 6bcbb1a34a..13b3ee8da5 100644
---
a/docs/hop-user-manual/modules/ROOT/pages/hop-gui/perspective-configuration.adoc
+++
b/docs/hop-user-manual/modules/ROOT/pages/hop-gui/perspective-configuration.adoc
@@ -103,6 +103,19 @@ See xref:hop-gui/canvas-mouse.adoc[Canvas mouse gestures]
for every click in bot
|If this option is enabled, a border will be drawn around the names of
transforms and actions on the canvas.
|no
+|Tooltips
+a|A group of its own in the *Pipeline and Workflow canvas* section: one
checkbox per kind of tooltip the canvas shows when the mouse rests on
something. Untick a kind to stop only that one; *Show tooltip when hovering
over a hop or Action/Transform* in the *Tooltips* section of the General tab
still switches all of them off at once.
+
+* *Edit hint on transform and action names*: the "Click to edit" hint on a
name.
+* *Transform and action descriptions*: the description on an icon and its info
badge, along with the transform partitioning and whether a transform can start
a pipeline.
+* *Deprecation warnings*: the warning on the icon of a deprecated transform or
action, and its replacement.
+* *Hop details*: the source, target and status of a hop when the mouse rests
on its line, and the badges on it: info, error, copies, row distribution,
target streams and the conditions of workflow hops.
+* *Execution results*: after a run, the failure logs, the output rows a
transform or hop holds, the result of an action and where a workflow restarted
from a checkpoint.
+* *Note links*: where a hyperlink in a note leads.
+* *Plugin tooltips*: tooltips that plugins add to the canvas, such as the
custom debug levels.
+* *Selection cleared notice*: the short "Selection cleared" notice after a
click on the empty canvas while something was selected.
+|all on
+
|Use global bookmarks in the file dialog|Bookmarks in the file dialog are
global (across projects) by default. Enable to make them project-specific|yes
|===
diff --git
a/rcp/src/test/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraphClickContractTest.java
b/rcp/src/test/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraphClickContractTest.java
index 76676b5b5f..10f695f538 100644
---
a/rcp/src/test/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraphClickContractTest.java
+++
b/rcp/src/test/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraphClickContractTest.java
@@ -19,6 +19,7 @@ package org.apache.hop.ui.hopgui.file.pipeline;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.LinkedHashMap;
@@ -42,6 +43,7 @@ import org.apache.hop.ui.core.gui.HopToolTip;
import org.apache.hop.ui.hopgui.HopGui;
import org.apache.hop.ui.hopgui.HopGuiEnvironment;
import org.apache.hop.ui.hopgui.file.GraphCanvasTestBase;
+import org.apache.hop.ui.hopgui.file.shared.CanvasToolTip;
import org.apache.hop.ui.hopgui.palette.GraphPalette;
import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
import org.eclipse.swt.SWT;
@@ -255,6 +257,93 @@ class HopGuiPipelineGraphClickContractTest extends
GraphCanvasTestBase {
});
}
+ /** One hover: the spot, the option that owns its tooltip and a piece of the
text it shows. */
+ private record Hover(Where where, CanvasToolTip toolTip, String text) {
+ @Override
+ public String toString() {
+ return where.label + " - " + toolTip;
+ }
+ }
+
+ static Stream<Hover> hovers() {
+ return Stream.of(
+ new Hover(
+ Where.NAME, CanvasToolTip.EDIT_HINT,
msg("HopGuiPipelineGraph.TransformName.Tooltip")),
+ new Hover(Where.INFO_BADGE, CanvasToolTip.DESCRIPTION, "Reads the
rows"),
+ new Hover(Where.HOP_LINE, CanvasToolTip.HOP,
msg("PipelineGraph.Dialog.HopInfo")),
+ new Hover(Where.HOP_COPY_BADGE, CanvasToolTip.HOP, SOURCE_TRANSFORM));
+ }
+
+ /**
+ * Every tooltip on the canvas has a switch of its own in the Look &
Feel options: with the
+ * switch on the hover shows it, with the switch off the same hover shows
nothing.
+ */
+ @ParameterizedTest(name = "{0}")
+ @MethodSource("hovers")
+ void hovering(Hover hover) {
+ Cell cell = new Cell(false, hover.where, LEFT, null, scene -> {});
+ onCanvas(
+ cell,
+ scene -> {
+ Point at = scene.aim(hover.where);
+ try {
+ onUi(() ->
PropsUi.getInstance().setCanvasToolTipShown(hover.toolTip, true));
+ fire(scene.canvas, SWT.MouseHover, scene.scale, at, 0, SWT.NONE);
+ scene.noteBalloon();
+ String shown = scene.balloon;
+
+ onUi(() ->
PropsUi.getInstance().setCanvasToolTipShown(hover.toolTip, false));
+ fire(scene.canvas, SWT.MouseHover, scene.scale, at, 0, SWT.NONE);
+ scene.noteBalloon();
+ String hidden = scene.balloon;
+
+ assertAll(
+ () -> assertNotNull(shown, "the hover should have put up a
tooltip"),
+ () -> assertTrue(shown.contains(hover.text), "unexpected
tooltip: " + shown),
+ () -> assertNull(hidden, "the tooltip is switched off, yet it
shows: " + hidden),
+ () -> assertNoFailures());
+ } finally {
+ onUi(() ->
PropsUi.getInstance().setCanvasToolTipShown(hover.toolTip, true));
+ }
+ });
+ }
+
+ /**
+ * The general tooltip option on the General tab switches every canvas
tooltip off at once, the
+ * "Selection cleared" notice included, even while its own checkbox is left
on.
+ */
+ @Test
+ void generalToolTipOptionSwitchesOffTheSelectionClearedNotice() {
+ Cell cell = new Cell(false, Where.EMPTY_SELECTED, LEFT, null,
Scene::nothingSelected);
+ onCanvas(
+ cell,
+ scene -> {
+ Point at = scene.aim(cell.where);
+ try {
+ onUi(
+ () -> {
+
PropsUi.getInstance().setCanvasToolTipShown(CanvasToolTip.NOTICE, true);
+ PropsUi.getInstance().setShowToolTips(false);
+ });
+
+ List<String> dialogs =
+ clickAndCatchDialogs(
+ scene.bot, scene.canvas, scene.scale, at, LEFT, SWT.NONE,
scene::noteBalloon);
+
+ assertAll(
+ () -> assertDialogs(null, dialogs),
+ () -> cell.sideEffect.accept(scene),
+ () ->
+ assertNull(
+ scene.balloon,
+ "tooltips are switched off, yet the notice shows: " +
scene.balloon),
+ () -> assertNoFailures());
+ } finally {
+ onUi(() -> PropsUi.getInstance().setShowToolTips(true));
+ }
+ });
+ }
+
// ------------------------------------------------------------------
assertions
private static void assertDialogs(String expected, List<String> actual) {
diff --git
a/rcp/src/test/java/org/apache/hop/ui/hopgui/perspective/configuration/tabs/ConfigGuiOptionsTabCanvasToolTipsTest.java
b/rcp/src/test/java/org/apache/hop/ui/hopgui/perspective/configuration/tabs/ConfigGuiOptionsTabCanvasToolTipsTest.java
new file mode 100644
index 0000000000..afbbf35829
--- /dev/null
+++
b/rcp/src/test/java/org/apache/hop/ui/hopgui/perspective/configuration/tabs/ConfigGuiOptionsTabCanvasToolTipsTest.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.hopgui.perspective.configuration.tabs;
+
+import static
org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory.allOf;
+import static
org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory.widgetOfType;
+import static
org.eclipse.swtbot.swt.finder.matchers.WidgetMatcherFactory.withText;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.EnumMap;
+import java.util.Map;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.i18n.BaseMessages;
+import org.apache.hop.ui.core.PropsUi;
+import org.apache.hop.ui.core.dialog.BaseDialog;
+import org.apache.hop.ui.hopgui.HopGuiEnvironment;
+import org.apache.hop.ui.hopgui.file.GraphCanvasTestBase;
+import org.apache.hop.ui.hopgui.file.shared.CanvasToolTip;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swtbot.swt.finder.utils.SWTUtils;
+import org.eclipse.swtbot.swt.finder.widgets.SWTBotCheckBox;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+
+/**
+ * The Look & Feel tab offers one checkbox per kind of canvas tooltip, in
a group of its own
+ * inside the "Pipeline and Workflow canvas" section, and a click on one lands
in the properties.
+ */
+@Tag("uitest")
+class ConfigGuiOptionsTabCanvasToolTipsTest extends GraphCanvasTestBase {
+
+ @BeforeAll
+ static void registerGuiPlugins() throws HopException {
+ HopGuiEnvironment.init();
+ }
+
+ @Test
+ void everyCanvasToolTipHasACheckboxInItsOwnGroup() {
+ Map<CanvasToolTip, Boolean> before = new EnumMap<>(CanvasToolTip.class);
+ try {
+ withScene(
+ shell -> {
+ hopGui();
+ for (CanvasToolTip toolTip : CanvasToolTip.values()) {
+ before.put(toolTip,
PropsUi.getInstance().isCanvasToolTipShown(toolTip));
+ PropsUi.getInstance().setCanvasToolTipShown(toolTip, true);
+ }
+ shell.setSize(700, 1000);
+ shell.setLayout(new FillLayout());
+ CTabFolder tabFolder = new CTabFolder(shell, SWT.NONE);
+ new ConfigGuiOptionsTab().addGuiOptionsTab(tabFolder);
+ tabFolder.setSelection(0);
+ },
+ bot -> {
+ Group group =
+ bot.widget(
+ allOf(
+ widgetOfType(Group.class),
+
withText(msg("EnterOptionsDialog.CanvasToolTips.Label"))));
+
+ Map<CanvasToolTip, SWTBotCheckBox> boxes = new
EnumMap<>(CanvasToolTip.class);
+ for (CanvasToolTip toolTip : CanvasToolTip.values()) {
+ boxes.put(toolTip, bot.checkBox(msg(toolTip.getLabelKey())));
+ }
+ // Scroll the group into view and keep a picture of it, for a look
at the layout.
+ onUi(
+ () -> {
+ Composite content = group.getParent();
+ while (!(content.getParent() instanceof ScrolledComposite)) {
+ content = content.getParent();
+ }
+ ScrolledComposite scrolled = (ScrolledComposite)
content.getParent();
+ Rectangle inContent =
+ group.getDisplay().map(group.getParent(), content,
group.getBounds());
+ scrolled.setOrigin(0, inContent.y);
+ scrolled.getShell().forceActive();
+ });
+ Rectangle shellBounds = onUi(() -> group.getShell().getBounds());
+ SWTUtils.captureScreenshot(
+ "target/screenshots/canvas-tooltips-options.png", shellBounds);
+
+ assertAll(
+ boxes.entrySet().stream()
+ .map(
+ entry ->
+ () -> {
+ assertSame(
+ group,
+ onUi(() ->
entry.getValue().widget.getParent()),
+ entry.getKey() + " should sit in the
Tooltips group");
+ assertTrue(
+ entry.getValue().isChecked(),
+ entry.getKey() + " should start checked");
+ }));
+
+ // A click lands in the properties at once, and only for that kind.
+ boxes.get(CanvasToolTip.EDIT_HINT).click();
+ assertFalse(
+ onUi(() ->
PropsUi.getInstance().isCanvasToolTipShown(CanvasToolTip.EDIT_HINT)),
+ "unticking the edit hint should switch it off");
+ assertTrue(
+ onUi(() ->
PropsUi.getInstance().isCanvasToolTipShown(CanvasToolTip.HOP)),
+ "the other kinds stay on");
+
+ boxes.get(CanvasToolTip.EDIT_HINT).click();
+ assertTrue(
+ onUi(() ->
PropsUi.getInstance().isCanvasToolTipShown(CanvasToolTip.EDIT_HINT)),
+ "ticking the edit hint again should switch it back on");
+ });
+ } finally {
+ onUi(
+ () ->
+ before.forEach(
+ (toolTip, shown) ->
PropsUi.getInstance().setCanvasToolTipShown(toolTip, shown)));
+ }
+ }
+
+ private static String msg(String key) {
+ return BaseMessages.getString(BaseDialog.class, key);
+ }
+}
diff --git a/ui/src/main/java/org/apache/hop/ui/core/PropsUi.java
b/ui/src/main/java/org/apache/hop/ui/core/PropsUi.java
index 50bc949d55..fa4aa12ae2 100644
--- a/ui/src/main/java/org/apache/hop/ui/core/PropsUi.java
+++ b/ui/src/main/java/org/apache/hop/ui/core/PropsUi.java
@@ -38,6 +38,7 @@ import org.apache.hop.ui.hopgui.HopGuiKeyHandler;
import org.apache.hop.ui.hopgui.ISingletonProvider;
import org.apache.hop.ui.hopgui.ImplementationLoader;
import org.apache.hop.ui.hopgui.TextSizeUtilFacade;
+import org.apache.hop.ui.hopgui.file.shared.CanvasToolTip;
import org.apache.hop.ui.util.EnvironmentUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
@@ -70,6 +71,7 @@ public class PropsUi extends Props {
private static final String STRING_SHOW_COPY_OR_DISTRIBUTE_WARNING =
"ShowCopyOrDistributeWarning";
private static final String SHOW_TOOL_TIPS = "ShowToolTips";
+ private static final String SHOW_CANVAS_TOOL_TIP_PREFIX =
"ShowCanvasToolTip";
private static final String RESOLVE_VARIABLES_IN_TOOLTIPS =
"ResolveVariablesInToolTips";
private static final String SHOW_HELP_TOOL_TIPS = "ShowHelpToolTips";
private static final String HIDE_MENU_BAR = "HideMenuBar";
@@ -1253,6 +1255,18 @@ public class PropsUi extends Props {
setProperty(SHOW_TOOL_TIPS, show ? YES : NO);
}
+ /**
+ * Whether the pipeline and workflow canvas show one kind of tooltip. Every
kind is on by default;
+ * {@link #showToolTips()} switches all of them off at once.
+ */
+ public boolean isCanvasToolTipShown(CanvasToolTip toolTip) {
+ return YES.equalsIgnoreCase(getProperty(SHOW_CANVAS_TOOL_TIP_PREFIX +
toolTip.getCode(), YES));
+ }
+
+ public void setCanvasToolTipShown(CanvasToolTip toolTip, boolean show) {
+ setProperty(SHOW_CANVAS_TOOL_TIP_PREFIX + toolTip.getCode(), show ? YES :
NO);
+ }
+
public boolean resolveVariablesInToolTips() {
return YES.equalsIgnoreCase(getProperty(RESOLVE_VARIABLES_IN_TOOLTIPS,
YES));
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraph.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraph.java
index 5bafba3bb1..f743301ad2 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraph.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/pipeline/HopGuiPipelineGraph.java
@@ -197,6 +197,7 @@ import
org.apache.hop.ui.hopgui.file.pipeline.delegates.HopGuiPipelineUndoDelega
import
org.apache.hop.ui.hopgui.file.pipeline.extension.HopGuiPipelineFinishedExtension;
import
org.apache.hop.ui.hopgui.file.pipeline.extension.HopGuiPipelineGraphExtension;
import
org.apache.hop.ui.hopgui.file.pipeline.extension.PipelineRenamedExtension;
+import org.apache.hop.ui.hopgui.file.shared.CanvasToolTip;
import org.apache.hop.ui.hopgui.file.shared.DrillDownGuiPlugin;
import org.apache.hop.ui.hopgui.file.shared.HopGuiAbstractGraph;
import org.apache.hop.ui.hopgui.file.shared.HopGuiGraphSnapshotUndo;
@@ -1702,10 +1703,12 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
// Show a short tooltip
//
toolTip.setVisible(false);
- toolTip.setAutoHide(true);
- toolTip.setText(Const.CR + " Selection cleared " + Const.CR);
- showToolTip(new org.eclipse.swt.graphics.Point(e.x, e.y));
- toolTip.hideAfter(TRANSIENT_TOOLTIP_MILLIS);
+ if (isToolTipShown(CanvasToolTip.NOTICE)) {
+ toolTip.setAutoHide(true);
+ toolTip.setText(Const.CR + " Selection cleared " + Const.CR);
+ showToolTip(new org.eclipse.swt.graphics.Point(e.x, e.y));
+ toolTip.hideAfter(TRANSIENT_TOOLTIP_MILLIS);
+ }
return;
}
@@ -4659,7 +4662,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
//
StringBuilder tip = new StringBuilder();
AreaOwner areaOwner = getVisibleAreaOwner(x, y);
- if (areaOwner != null && areaOwner.getAreaType() != null) {
+ if (isAreaToolTipShown(areaOwner)) {
AreaType areaType = areaOwner.getAreaType();
switch (areaType) {
case NOTE_LINK:
@@ -4793,7 +4796,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
TransformMeta iconTransformMeta = (TransformMeta)
areaOwner.getOwner();
// If transform is deprecated, display first
- if (iconTransformMeta.isDeprecated()) {
+ if (iconTransformMeta.isDeprecated() &&
isToolTipShown(CanvasToolTip.DEPRECATION)) {
tip.append(
BaseMessages.getString(PKG,
"PipelineGraph.DeprecatedTransform.Tooltip.Title"))
.append(Const.CR);
@@ -4818,11 +4821,14 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
iconTransformMeta.getSuggestion()));
}
tipImage = GuiResource.getInstance().getImageDeprecated();
- } else if (!Utils.isEmpty(iconTransformMeta.getDescription())) {
+ } else if (isToolTipShown(CanvasToolTip.DESCRIPTION)
+ && !Utils.isEmpty(iconTransformMeta.getDescription())) {
tip.append(iconTransformMeta.getDescription());
}
ITransformMeta sourceMeta = iconTransformMeta.getTransform();
- if (sourceMeta != null && sourceMeta.canStartWithoutInput()) {
+ if (isToolTipShown(CanvasToolTip.DESCRIPTION)
+ && sourceMeta != null
+ && sourceMeta.canStartWithoutInput()) {
if (tip.length() > 0) {
tip.append(Const.CR);
}
@@ -4877,7 +4883,8 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
}
}
- if (hi != null && tip.isEmpty()) { // We clicked on a HOP!
+ boolean hopTipShown = hi != null && isToolTipShown(CanvasToolTip.HOP);
+ if (hopTipShown && tip.isEmpty()) { // We clicked on a HOP!
// Set the tooltip for the hop:
tip.append(Const.CR)
.append(BaseMessages.getString(PKG, "PipelineGraph.Dialog.HopInfo"))
@@ -4893,7 +4900,7 @@ public class HopGuiPipelineGraph extends
HopGuiAbstractGraph
if (newTip == null) {
hideHoverToolTip();
- if (hi != null) { // We clicked on a HOP!
+ if (hopTipShown) { // We clicked on a HOP!
// Set the tooltip for the hop:
newTip =
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/CanvasToolTip.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/CanvasToolTip.java
new file mode 100644
index 0000000000..8652ee3541
--- /dev/null
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/CanvasToolTip.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.hopgui.file.shared;
+
+import java.util.EnumSet;
+import java.util.Set;
+import lombok.Getter;
+import org.apache.hop.core.gui.AreaOwner.AreaType;
+
+/**
+ * The kinds of tooltip the pipeline and workflow canvas can show. Each one
can be switched off on
+ * its own in the Look & Feel options; the global "Show tool tips" option
still switches all of
+ * them off at once.
+ */
+@Getter
+public enum CanvasToolTip {
+ /** "Click to edit" on a transform or action name. */
+ EDIT_HINT("EditHint"),
+ /**
+ * The description of a transform or action on its icon and info badge,
along with the transform
+ * partitioning and the "can start a pipeline" note.
+ */
+ DESCRIPTION("Description"),
+ /** The warning on the icon of a deprecated transform or action. */
+ DEPRECATION("Deprecation"),
+ /** Hop lines and every badge on a hop: info, error, copies, row
distribution, targets. */
+ HOP("Hop"),
+ /** What a run left behind: failure logs, output row buffers, action results
and checkpoints. */
+ EXECUTION_RESULT("ExecutionResult"),
+ /** The link target of a hyperlink in a note. */
+ NOTE_LINK("NoteLink"),
+ /** Tooltips that plugins add through the area-hover extension points. */
+ PLUGIN("Plugin"),
+ /** The "Selection cleared" notice after a click on the empty canvas. */
+ NOTICE("Notice");
+
+ private final String code;
+
+ CanvasToolTip(String code) {
+ this.code = code;
+ }
+
+ /** The key of the checkbox label in the options dialog bundle. */
+ public String getLabelKey() {
+ return "EnterOptionsDialog.CanvasToolTip." + code + ".Label";
+ }
+
+ /** The key of the checkbox tooltip in the options dialog bundle. */
+ public String getToolTipKey() {
+ return "EnterOptionsDialog.CanvasToolTip." + code + ".ToolTip";
+ }
+
+ /**
+ * The kinds of tooltip an area of the canvas can put up. Usually one; an
icon can carry either a
+ * deprecation warning or a description, so it lists both.
+ */
+ public static Set<CanvasToolTip> forAreaType(AreaType areaType) {
+ if (areaType == null) {
+ return EnumSet.noneOf(CanvasToolTip.class);
+ }
+ return switch (areaType) {
+ case TRANSFORM_NAME, ACTION_NAME -> EnumSet.of(EDIT_HINT);
+ case TRANSFORM_ICON, TRANSFORM_INFO_ICON, ACTION_ICON, ACTION_INFO_ICON
->
+ EnumSet.of(DESCRIPTION, DEPRECATION);
+ case TRANSFORM_PARTITIONING -> EnumSet.of(DESCRIPTION);
+ case HOP_COPY_ICON,
+ HOP_ERROR_ICON,
+ HOP_INFO_ICON,
+ HOP_INFO_TRANSFORM_COPIES_ERROR,
+ HOP_INFO_TRANSFORMS_PARTITIONED,
+ TRANSFORM_TARGET_HOP_ICON,
+ ROW_DISTRIBUTION_ICON,
+ WORKFLOW_HOP_ICON,
+ WORKFLOW_HOP_PARALLEL_ICON ->
+ EnumSet.of(HOP);
+ case TRANSFORM_FAILURE_ICON,
+ TRANSFORM_OUTPUT_DATA,
+ HOP_OUTPUT_DATA,
+ ACTION_RESULT_SUCCESS,
+ ACTION_RESULT_FAILURE,
+ ACTION_RESULT_CHECKPOINT ->
+ EnumSet.of(EXECUTION_RESULT);
+ case NOTE_LINK -> EnumSet.of(NOTE_LINK);
+ // CUSTOM and every area the graphs do not describe themselves go to
the plugin extension
+ // points.
+ default -> EnumSet.of(PLUGIN);
+ };
+ }
+}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/HopGuiAbstractGraph.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/HopGuiAbstractGraph.java
index ab8324b479..b7d6f06b07 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/HopGuiAbstractGraph.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/HopGuiAbstractGraph.java
@@ -172,6 +172,34 @@ public abstract class HopGuiAbstractGraph extends
DragViewZoomBase
return !emptyCanvas || GraphPalette.isVisible();
}
+ /**
+ * Whether this kind of canvas tooltip is shown: the general tooltip option
on the General tab
+ * must be on, and so must the kind's own checkbox in the Look & Feel
options. The general
+ * option is checked here rather than in {@link
PropsUi#isCanvasToolTipShown(CanvasToolTip)},
+ * since the Look & Feel checkboxes read that one and would otherwise
save every kind as off.
+ */
+ protected boolean isToolTipShown(CanvasToolTip toolTip) {
+ PropsUi props = hopGui.getProps();
+ return props.showToolTips() && props.isCanvasToolTipShown(toolTip);
+ }
+
+ /**
+ * Whether any of the tooltips an area can put up is still on. The icon of a
transform or action
+ * carries either a deprecation warning or a description, so it stays
hoverable as long as one of
+ * the two is on; the branch that builds the text checks the exact one.
+ */
+ protected boolean isAreaToolTipShown(AreaOwner areaOwner) {
+ if (areaOwner == null || areaOwner.getAreaType() == null) {
+ return false;
+ }
+ for (CanvasToolTip toolTip :
CanvasToolTip.forAreaType(areaOwner.getAreaType())) {
+ if (isToolTipShown(toolTip)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* The hide for a mouse move: takes down the tooltip of whatever was under
the pointer, but not a
* notice such as "Selection cleared". That one is not tied to the pointer
and stays until its
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopGuiWorkflowGraph.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopGuiWorkflowGraph.java
index d34adc8855..9afaddbec5 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopGuiWorkflowGraph.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/file/workflow/HopGuiWorkflowGraph.java
@@ -137,6 +137,7 @@ import org.apache.hop.ui.hopgui.file.IHopFileType;
import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
import org.apache.hop.ui.hopgui.file.delegates.HopGuiNoteLinkSupport;
import org.apache.hop.ui.hopgui.file.delegates.HopGuiNotePadDelegate;
+import org.apache.hop.ui.hopgui.file.shared.CanvasToolTip;
import org.apache.hop.ui.hopgui.file.shared.DrillDownGuiPlugin;
import org.apache.hop.ui.hopgui.file.shared.HopGuiAbstractGraph;
import org.apache.hop.ui.hopgui.file.shared.HopGuiGraphSnapshotUndo;
@@ -1420,9 +1421,11 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
// Show a short tooltip
//
toolTip.setVisible(false);
- toolTip.setText(Const.CR + " Selection cleared " + Const.CR);
- showToolTip(new org.eclipse.swt.graphics.Point(event.x, event.y));
- toolTip.hideAfter(TRANSIENT_TOOLTIP_MILLIS);
+ if (isToolTipShown(CanvasToolTip.NOTICE)) {
+ toolTip.setText(Const.CR + " Selection cleared " + Const.CR);
+ showToolTip(new org.eclipse.swt.graphics.Point(event.x, event.y));
+ toolTip.hideAfter(TRANSIENT_TOOLTIP_MILLIS);
+ }
return;
}
@@ -3934,7 +3937,7 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
//
StringBuilder tip = new StringBuilder();
AreaOwner areaOwner = getVisibleAreaOwner(x, y);
- if (areaOwner != null && areaOwner.getAreaType() != null) {
+ if (isAreaToolTipShown(areaOwner)) {
ActionMeta actionCopy;
switch (areaOwner.getAreaType()) {
case NOTE_LINK:
@@ -3987,10 +3990,13 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
break;
case CUSTOM:
- String message = (String) areaOwner.getOwner();
- tip.append(message);
- tipImage = null;
- GuiResource.getInstance().getImagePipeline();
+ // A plain message is shown as is; anything else, such as the debug
level bee, is
+ // described by the plugin that drew it.
+ //
+ if (areaOwner.getOwner() instanceof String message) {
+ tip.append(message);
+ }
+ tipImage = callAreaHoverExtension(x, y, screenX, screenY, areaOwner,
tip);
break;
case ACTION_RESULT_FAILURE, ACTION_RESULT_SUCCESS:
@@ -4063,7 +4069,7 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
ActionMeta actionMetaInfo = (ActionMeta) areaOwner.getOwner();
// If transform is deprecated, display first
- if (actionMetaInfo.isDeprecated()) { // only need tooltip if action
is deprecated
+ if (actionMetaInfo.isDeprecated() &&
isToolTipShown(CanvasToolTip.DEPRECATION)) {
tip.append(BaseMessages.getString(PKG,
"WorkflowGraph.DeprecatedEntry.Tooltip.Title"))
.append(Const.CR);
String tipNext =
@@ -4089,7 +4095,8 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
actionMetaInfo.getSuggestion()));
}
tipImage = GuiResource.getInstance().getImageDeprecated();
- } else if (!Utils.isEmpty(actionMetaInfo.getDescription())) {
+ } else if (isToolTipShown(CanvasToolTip.DESCRIPTION)
+ && !Utils.isEmpty(actionMetaInfo.getDescription())) {
tip.append(actionMetaInfo.getDescription());
}
break;
@@ -4100,28 +4107,12 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
default:
// For plugins...
//
- try {
- HopGuiTooltipExtension tooltipExt =
- new HopGuiTooltipExtension(x, y, screenX, screenY, areaOwner,
tip);
- ExtensionPointHandler.callExtensionPoint(
- hopGui.getLog(),
- variables,
- HopExtensionPoint.HopGuiWorkflowGraphAreaHover.name(),
- tooltipExt);
- tipImage = tooltipExt.tooltipImage;
- } catch (Exception ex) {
- hopGui
- .getLog()
- .logError(
- "Error calling extension point "
- +
HopExtensionPoint.HopGuiWorkflowGraphAreaHover.name(),
- ex);
- }
+ tipImage = callAreaHoverExtension(x, y, screenX, screenY, areaOwner,
tip);
break;
}
}
- if (hi != null && tip.isEmpty()) {
+ if (hi != null && tip.isEmpty() && isToolTipShown(CanvasToolTip.HOP)) {
// Set the tooltip for the hop:
tip.append(BaseMessages.getString(PKG,
"WorkflowGraph.Dialog.HopInfo")).append(Const.CR);
tip.append(BaseMessages.getString(PKG,
"WorkflowGraph.Dialog.HopInfo.SourceEntry"))
@@ -4159,6 +4150,34 @@ public class HopGuiWorkflowGraph extends
HopGuiAbstractGraph
}
}
+ /**
+ * Lets plugins describe an area they drew on the canvas: they append to the
tip and may set an
+ * image.
+ *
+ * @return the image the plugins set for the tooltip, or null
+ */
+ private Image callAreaHoverExtension(
+ int x, int y, int screenX, int screenY, AreaOwner areaOwner,
StringBuilder tip) {
+ try {
+ HopGuiTooltipExtension tooltipExt =
+ new HopGuiTooltipExtension(x, y, screenX, screenY, areaOwner, tip);
+ ExtensionPointHandler.callExtensionPoint(
+ hopGui.getLog(),
+ variables,
+ HopExtensionPoint.HopGuiWorkflowGraphAreaHover.name(),
+ tooltipExt);
+ return tooltipExt.tooltipImage;
+ } catch (Exception ex) {
+ hopGui
+ .getLog()
+ .logError(
+ "Error calling extension point "
+ + HopExtensionPoint.HopGuiWorkflowGraphAreaHover.name(),
+ ex);
+ return null;
+ }
+ }
+
public void launchStuff(ActionMeta actionCopy) {
String[] references =
actionCopy.getAction().getReferencedObjectDescriptions();
if (!Utils.isEmpty(references)) {
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/configuration/tabs/ConfigGuiOptionsTab.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/configuration/tabs/ConfigGuiOptionsTab.java
index 30c51b2f8a..8ddb686a72 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/configuration/tabs/ConfigGuiOptionsTab.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/configuration/tabs/ConfigGuiOptionsTab.java
@@ -18,6 +18,8 @@
package org.apache.hop.ui.hopgui.perspective.configuration.tabs;
+import java.util.EnumMap;
+import java.util.Map;
import java.util.function.Consumer;
import org.apache.hop.core.Const;
import org.apache.hop.core.Props;
@@ -40,6 +42,7 @@ import org.apache.hop.ui.core.gui.IToolbarContainer;
import org.apache.hop.ui.core.widget.OsHelper;
import org.apache.hop.ui.hopgui.HopGui;
import org.apache.hop.ui.hopgui.ToolbarFacade;
+import org.apache.hop.ui.hopgui.file.shared.CanvasToolTip;
import
org.apache.hop.ui.hopgui.perspective.configuration.ConfigurationPerspective;
import org.apache.hop.ui.util.EnvironmentUtils;
import org.eclipse.swt.SWT;
@@ -66,6 +69,7 @@ import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.ExpandBar;
import org.eclipse.swt.widgets.ExpandItem;
import org.eclipse.swt.widgets.FontDialog;
+import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
@@ -115,6 +119,7 @@ public class ConfigGuiOptionsTab {
private Button wEnableInfiniteMove;
private Button wDisableZoomScrolling;
private Button wMetricsOnTransforms;
+ private final Map<CanvasToolTip, Button> wCanvasToolTips = new
EnumMap<>(CanvasToolTip.class);
private Button wHideMenuBar;
private Button wShowTableViewToolbar;
private Button wShowTextCompositeToolbar;
@@ -214,6 +219,8 @@ public class ConfigGuiOptionsTab {
}
wDrawBorderAroundCanvasNames.setSelection(props.isBorderDrawnAroundCanvasNames());
wEnableInfiniteMove.setSelection(props.isInfiniteCanvasMoveEnabled());
+ wCanvasToolTips.forEach(
+ (toolTip, button) ->
button.setSelection(props.isCanvasToolTipShown(toolTip)));
wHideMenuBar.setSelection(props.isHidingMenuBar());
wShowTableViewToolbar.setSelection(props.isShowTableViewToolbar());
if (wShowTextCompositeToolbar != null &&
!wShowTextCompositeToolbar.isDisposed()) {
@@ -795,6 +802,10 @@ public class ConfigGuiOptionsTab {
props.isShowingMetricsAboveRunningTransforms(),
lastCanvasControl,
margin);
+ lastCanvasControl = wMetricsOnTransforms;
+
+ // The tooltips of the canvas, one checkbox per kind, in a group of their
own
+ createCanvasToolTipsGroup(canvasContent, lastCanvasControl, margin);
// Create the expand item
ExpandItem canvasItem = new ExpandItem(canvasExpandBar, SWT.NONE);
@@ -1390,6 +1401,8 @@ public class ConfigGuiOptionsTab {
props.setInfiniteCanvasMoveEnabled(wEnableInfiniteMove.getSelection());
props.setZoomScrollingDisabled(wDisableZoomScrolling.getSelection());
props.setShowingMetricsAboveRunningTransforms(wMetricsOnTransforms.getSelection());
+ wCanvasToolTips.forEach(
+ (toolTip, button) -> props.setCanvasToolTipShown(toolTip,
button.getSelection()));
// On macOS (and other non-Windows), dark mode follows system; persist
system theme, not
// checkbox. In Web environment, isSystemDarkTheme() is not available.
boolean previousDarkMode = props.isDarkMode();
@@ -1707,6 +1720,43 @@ public class ConfigGuiOptionsTab {
return expandBar;
}
+ /**
+ * A titled group below {@code above} with one checkbox per kind of canvas
tooltip. A {@link
+ * Group} inside the ExpandBar content works on the desktop and in Hop Web
alike, and keeps the
+ * eight checkboxes apart from the other canvas options.
+ */
+ private void createCanvasToolTipsGroup(Composite parent, Control above, int
margin) {
+ PropsUi props = PropsUi.getInstance();
+
+ Group group = new Group(parent, SWT.NONE);
+ PropsUi.setLook(group);
+ group.setText(BaseMessages.getString(PKG,
"EnterOptionsDialog.CanvasToolTips.Label"));
+ group.setToolTipText(BaseMessages.getString(PKG,
"EnterOptionsDialog.CanvasToolTips.ToolTip"));
+ FormLayout groupLayout = new FormLayout();
+ groupLayout.marginWidth = PropsUi.getFormMargin();
+ groupLayout.marginHeight = PropsUi.getFormMargin();
+ group.setLayout(groupLayout);
+ FormData fdGroup = new FormData();
+ fdGroup.left = new FormAttachment(0, 0);
+ fdGroup.right = new FormAttachment(100, 0);
+ fdGroup.top = new FormAttachment(above, 2 * margin);
+ group.setLayoutData(fdGroup);
+
+ Control last = null;
+ for (CanvasToolTip toolTip : CanvasToolTip.values()) {
+ Button button =
+ createCheckbox(
+ group,
+ toolTip.getLabelKey(),
+ toolTip.getToolTipKey(),
+ props.isCanvasToolTipShown(toolTip),
+ last,
+ margin);
+ wCanvasToolTips.put(toolTip, button);
+ last = button;
+ }
+ }
+
private Button createCheckbox(
Composite parent,
String labelKey,
diff --git
a/ui/src/main/resources/org/apache/hop/ui/core/dialog/messages/messages_en_US.properties
b/ui/src/main/resources/org/apache/hop/ui/core/dialog/messages/messages_en_US.properties
index ca24e62a4e..e6ce3c9167 100644
---
a/ui/src/main/resources/org/apache/hop/ui/core/dialog/messages/messages_en_US.properties
+++
b/ui/src/main/resources/org/apache/hop/ui/core/dialog/messages/messages_en_US.properties
@@ -228,6 +228,24 @@ EnterOptionsDialog.UseRightClickForContextDialog.Label=Use
right click for the c
EnterOptionsDialog.UseRightClickForContextDialog.ToolTip=A right click opens
the context dialog of whatever is under the pointer and a left click only
selects. Off: a left click opens the context dialog.
EnterOptionsDialog.UseMenusInsteadOfContextDialog.Label=Use menus instead of
the context dialog
EnterOptionsDialog.UseMenusInsteadOfContextDialog.ToolTip=Transforms, actions,
hops and notes show their actions in a pop-up menu with a submenu per category.
A click on the empty canvas keeps the context dialog while the design palette
is hidden, since that is where new transforms and actions are searched for.
+EnterOptionsDialog.CanvasToolTips.Label=Tooltips
+EnterOptionsDialog.CanvasToolTips.ToolTip=Which tooltips the pipeline and
workflow canvases show when the mouse rests on something. "Show tooltip when
hovering over a hop or Action/Transform" in the Tooltips section of the General
tab switches all of them off at once.
+EnterOptionsDialog.CanvasToolTip.EditHint.Label=Edit hint on transform and
action names
+EnterOptionsDialog.CanvasToolTip.EditHint.ToolTip=Show "Click to edit" when
the mouse rests on the name of a transform or action.
+EnterOptionsDialog.CanvasToolTip.Description.Label=Transform and action
descriptions
+EnterOptionsDialog.CanvasToolTip.Description.ToolTip=Show the description of a
transform or action on its icon and info badge, along with the transform
partitioning and whether a transform can start a pipeline.
+EnterOptionsDialog.CanvasToolTip.Deprecation.Label=Deprecation warnings
+EnterOptionsDialog.CanvasToolTip.Deprecation.ToolTip=Warn on the icon of a
deprecated transform or action and name its replacement.
+EnterOptionsDialog.CanvasToolTip.Hop.Label=Hop details
+EnterOptionsDialog.CanvasToolTip.Hop.ToolTip=Describe a hop when the mouse
rests on its line or on one of its badges: info, error, copies, row
distribution, target streams, and the conditions of workflow hops.
+EnterOptionsDialog.CanvasToolTip.ExecutionResult.Label=Execution results
+EnterOptionsDialog.CanvasToolTip.ExecutionResult.ToolTip=After a run, show
failure logs, the output rows a transform or hop holds, the result of an action
and where a workflow restarted from a checkpoint.
+EnterOptionsDialog.CanvasToolTip.NoteLink.Label=Note links
+EnterOptionsDialog.CanvasToolTip.NoteLink.ToolTip=Show where a hyperlink in a
note leads.
+EnterOptionsDialog.CanvasToolTip.Plugin.Label=Plugin tooltips
+EnterOptionsDialog.CanvasToolTip.Plugin.ToolTip=Tooltips that plugins add to
the canvas, such as the custom debug levels on transforms and actions.
+EnterOptionsDialog.CanvasToolTip.Notice.Label=Selection cleared notice
+EnterOptionsDialog.CanvasToolTip.Notice.ToolTip=Show a short "Selection
cleared" notice after a click on the empty canvas while something was selected.
EnterOptionsDialog.DialogsOnAnyScreen.Label=Allow dialogs to open on any screen
EnterOptionsDialog.DialogsOnAnyScreen.ToolTip=Off: transform, action and
metadata dialogs follow the Hop window and stay above it. On: they open as
windows of their own that you can move to another screen.
EnterOptionsDialog.UseGlobalFileBookmarks.Label=Use global bookmarks in the
file dialog
diff --git
a/ui/src/test/java/org/apache/hop/ui/hopgui/file/shared/CanvasToolTipTest.java
b/ui/src/test/java/org/apache/hop/ui/hopgui/file/shared/CanvasToolTipTest.java
new file mode 100644
index 0000000000..8fd21e59fc
--- /dev/null
+++
b/ui/src/test/java/org/apache/hop/ui/hopgui/file/shared/CanvasToolTipTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.hopgui.file.shared;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.hop.core.gui.AreaOwner.AreaType;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+class CanvasToolTipTest {
+
+ /** Every area the canvas registers has an option that switches its tooltip
off. */
+ @ParameterizedTest
+ @EnumSource(AreaType.class)
+ void everyAreaTypeHasAnOption(AreaType areaType) {
+ assertFalse(CanvasToolTip.forAreaType(areaType).isEmpty(), areaType + "
has no option");
+ }
+
+ /** Every option is reachable from the canvas: the notice is the only one
without an area. */
+ @Test
+ void everyOptionExceptTheNoticeCoversAnArea() {
+ Set<CanvasToolTip> covered = new HashSet<>();
+ for (AreaType areaType : AreaType.values()) {
+ covered.addAll(CanvasToolTip.forAreaType(areaType));
+ }
+ assertEquals(EnumSet.complementOf(EnumSet.of(CanvasToolTip.NOTICE)),
covered);
+ }
+
+ @Test
+ void namesCarryTheEditHint() {
+ assertEquals(
+ EnumSet.of(CanvasToolTip.EDIT_HINT),
CanvasToolTip.forAreaType(AreaType.TRANSFORM_NAME));
+ assertEquals(
+ EnumSet.of(CanvasToolTip.EDIT_HINT),
CanvasToolTip.forAreaType(AreaType.ACTION_NAME));
+ }
+
+ /** An icon shows either the deprecation warning or the description, so both
options apply. */
+ @Test
+ void iconsCarryDescriptionAndDeprecation() {
+ for (AreaType icon :
+ EnumSet.of(
+ AreaType.TRANSFORM_ICON,
+ AreaType.TRANSFORM_INFO_ICON,
+ AreaType.ACTION_ICON,
+ AreaType.ACTION_INFO_ICON)) {
+ assertEquals(
+ EnumSet.of(CanvasToolTip.DESCRIPTION, CanvasToolTip.DEPRECATION),
+ CanvasToolTip.forAreaType(icon),
+ icon.name());
+ }
+ }
+
+ @Test
+ void unknownAreasGoToPlugins() {
+ assertEquals(EnumSet.of(CanvasToolTip.PLUGIN),
CanvasToolTip.forAreaType(AreaType.CUSTOM));
+ assertEquals(EnumSet.of(CanvasToolTip.PLUGIN),
CanvasToolTip.forAreaType(AreaType.ACTION_BUSY));
+ assertTrue(CanvasToolTip.forAreaType(null).isEmpty());
+ }
+
+ @Test
+ void codesAreUniqueAndStable() {
+ Set<String> codes = new HashSet<>();
+ for (CanvasToolTip toolTip : CanvasToolTip.values()) {
+ assertTrue(codes.add(toolTip.getCode()), "duplicate code " +
toolTip.getCode());
+ assertTrue(toolTip.getLabelKey().endsWith(toolTip.getCode() + ".Label"));
+ }
+ }
+}