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 f29d9f406c add searchbox, expand/collapse all, fixes #6431 (#6432)
f29d9f406c is described below
commit f29d9f406c714cdcb2b5d3f05e0b3ab5ff03b8d3
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Wed Jan 21 08:18:37 2026 +0100
add searchbox, expand/collapse all, fixes #6431 (#6432)
---
.../perspective/metadata/MetadataPerspective.java | 146 +++++++++++++++++++--
.../metadata/messages/messages_en_US.properties | 5 +-
2 files changed, 142 insertions(+), 9 deletions(-)
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java
index d7ac17fe58..98deb654a4 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/metadata/MetadataPerspective.java
@@ -115,6 +115,10 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
public static final String TOOLBAR_ITEM_DUPLICATE =
"MetadataPerspective-Toolbar-10030-Duplicate";
public static final String TOOLBAR_ITEM_DELETE =
"MetadataPerspective-Toolbar-10040-Delete";
public static final String TOOLBAR_ITEM_RENAME =
"MetadataPerspective-Toolbar-10020-Rename";
+ public static final String TOOLBAR_ITEM_EXPAND_ALL =
+ "MetadataPerspective-Toolbar-10060-ExpandAll";
+ public static final String TOOLBAR_ITEM_COLLAPSE_ALL =
+ "MetadataPerspective-Toolbar-10070-CollapseAll";
public static final String TOOLBAR_ITEM_REFRESH =
"MetadataPerspective-Toolbar-10100-Refresh";
private static final String KEY_HELP = "Help";
@@ -132,6 +136,8 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
private TreeEditor treeEditor;
private CTabFolder tabFolder;
private GuiToolbarWidgets toolBarWidgets;
+ private Text searchText;
+ private String currentSearchFilter = "";
private final List<MetadataEditor<?>> editors = new ArrayList<>();
@@ -215,11 +221,35 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
protected void createTree(Composite parent) {
// Create composite
//
- Composite composite = new Composite(parent, SWT.BORDER);
+ Composite treeComposite = new Composite(parent, SWT.NONE);
FormLayout layout = new FormLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
- composite.setLayout(layout);
+ treeComposite.setLayout(layout);
+
+ // Create search/filter text box
+ //
+ searchText = new Text(treeComposite, SWT.SEARCH | SWT.ICON_CANCEL |
SWT.ICON_SEARCH);
+ searchText.setMessage(BaseMessages.getString(PKG,
"MetadataPerspective.Search.Placeholder"));
+ PropsUi.setLook(searchText);
+ FormData searchFormData = new FormData();
+ searchFormData.left = new FormAttachment(0, 0);
+ searchFormData.top = new FormAttachment(0, 0);
+ searchFormData.right = new FormAttachment(100, 0);
+ searchText.setLayoutData(searchFormData);
+
+ // Add search listener
+ searchText.addListener(SWT.Modify, e -> filterTree());
+
+ // Create a composite with toolbar and tree for the border
+ Composite composite = new Composite(treeComposite, SWT.BORDER);
+ composite.setLayout(new FormLayout());
+ FormData layoutData = new FormData();
+ layoutData.left = new FormAttachment(0, 0);
+ layoutData.top = new FormAttachment(searchText, PropsUi.getMargin());
+ layoutData.right = new FormAttachment(100, 0);
+ layoutData.bottom = new FormAttachment(100, 0);
+ composite.setLayoutData(layoutData);
// Create toolbar
//
@@ -227,11 +257,11 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
toolBarWidgets = new GuiToolbarWidgets();
toolBarWidgets.registerGuiPluginObject(this);
toolBarWidgets.createToolbarWidgets(toolBar, GUI_PLUGIN_TOOLBAR_PARENT_ID);
- FormData layoutData = new FormData();
- layoutData.left = new FormAttachment(0, 0);
- layoutData.top = new FormAttachment(0, 0);
- layoutData.right = new FormAttachment(100, 0);
- toolBar.setLayoutData(layoutData);
+ FormData toolBarFormData = new FormData();
+ toolBarFormData.left = new FormAttachment(0, 0);
+ toolBarFormData.top = new FormAttachment(0, 0);
+ toolBarFormData.right = new FormAttachment(100, 0);
+ toolBar.setLayoutData(toolBarFormData);
toolBar.pack();
PropsUi.setLook(toolBar, Props.WIDGET_STYLE_TOOLBAR);
@@ -316,7 +346,7 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
FormData treeFormData = new FormData();
treeFormData.left = new FormAttachment(0, 0);
- treeFormData.top = new FormAttachment(toolBar, 0);
+ treeFormData.top = new FormAttachment(toolBar, PropsUi.getMargin());
treeFormData.right = new FormAttachment(100, 0);
treeFormData.bottom = new FormAttachment(100, 0);
tree.setLayoutData(treeFormData);
@@ -777,6 +807,46 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
activeHandler.updateGui();
}
+ @GuiToolbarElement(
+ root = GUI_PLUGIN_TOOLBAR_PARENT_ID,
+ id = TOOLBAR_ITEM_EXPAND_ALL,
+ toolTip = "i18n::MetadataPerspective.ToolbarElement.ExpandAll.Tooltip",
+ image = "ui/images/expand-all.svg")
+ public void expandAll() {
+ if (tree == null || tree.isDisposed()) {
+ return;
+ }
+
+ tree.setRedraw(false);
+ try {
+ for (TreeItem item : tree.getItems()) {
+ expandTreeItem(item, true);
+ }
+ } finally {
+ tree.setRedraw(true);
+ }
+ }
+
+ @GuiToolbarElement(
+ root = GUI_PLUGIN_TOOLBAR_PARENT_ID,
+ id = TOOLBAR_ITEM_COLLAPSE_ALL,
+ toolTip = "i18n::MetadataPerspective.ToolbarElement.CollapseAll.Tooltip",
+ image = "ui/images/collapse-all.svg")
+ public void collapseAll() {
+ if (tree == null || tree.isDisposed()) {
+ return;
+ }
+
+ tree.setRedraw(false);
+ try {
+ for (TreeItem item : tree.getItems()) {
+ expandTreeItem(item, false);
+ }
+ } finally {
+ tree.setRedraw(true);
+ }
+ }
+
@GuiToolbarElement(
root = GUI_PLUGIN_TOOLBAR_PARENT_ID,
id = TOOLBAR_ITEM_REFRESH,
@@ -830,6 +900,11 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
Collections.sort(names);
for (final String name : names) {
+ // Apply filter - skip non-matching items
+ if (!matchesFilter(name)) {
+ continue;
+ }
+
IHopMetadata hopMetadata;
try {
hopMetadata = serializer.load(name);
@@ -869,6 +944,12 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
VIRTUAL_PATH,
folderItem.getParentItem().getData(VIRTUAL_PATH) + "/" +
folder);
folderItem.setData(KEY_TYPE, FOLDER);
+
+ // Expand folders when filtering to show matches
+ if (!Utils.isEmpty(currentSearchFilter)) {
+ folderItem.setExpanded(true);
+ }
+
parentItem = folderItem;
}
}
@@ -886,12 +967,29 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
}
}
+ // Remove empty class items (those with no children after filtering)
+ if (!Utils.isEmpty(currentSearchFilter)) {
+ List<TreeItem> itemsToRemove = new ArrayList<>();
+ for (TreeItem classItem : tree.getItems()) {
+ if (classItem.getItemCount() == 0) {
+ itemsToRemove.add(classItem);
+ } else {
+ // Expand class items when filtering to show matches
+ classItem.setExpanded(true);
+ }
+ }
+ for (TreeItem item : itemsToRemove) {
+ item.dispose();
+ }
+ }
+
TreeUtil.setOptimalWidthOnColumns(tree);
TreeMemory.setExpandedFromMemory(tree, METADATA_PERSPECTIVE_TREE);
tree.setRedraw(true);
updateGui();
+ updateSelection();
} catch (Exception e) {
new ErrorDialog(
getShell(),
@@ -901,16 +999,48 @@ public class MetadataPerspective implements
IHopPerspective, TabClosable {
}
}
+ /** Filter the tree based on search text */
+ protected void filterTree() {
+ if (searchText == null || searchText.isDisposed()) {
+ return;
+ }
+
+ currentSearchFilter = searchText.getText();
+
+ // Refresh to rebuild the tree with or without filter
+ refresh();
+ }
+
+ /** Check if a metadata name matches the current filter */
+ private boolean matchesFilter(String name) {
+ if (Utils.isEmpty(currentSearchFilter)) {
+ return true;
+ }
+ return name != null &&
name.toLowerCase().contains(currentSearchFilter.toLowerCase());
+ }
+
+ /** Recursively expand or collapse a tree item and all its children */
+ private void expandTreeItem(TreeItem item, boolean expand) {
+ item.setExpanded(expand);
+ for (TreeItem child : item.getItems()) {
+ expandTreeItem(child, expand);
+ }
+ }
+
protected void updateSelection() {
boolean isMetadataSelected = false;
+ boolean isAnythingSelected = false;
+
if (tree.getSelectionCount() > 0) {
+ isAnythingSelected = true;
TreeItem treeItem = tree.getSelection()[0];
if (treeItem.getData(KEY_TYPE).equals(FILE)) {
isMetadataSelected = true;
}
}
+ toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_NEW, isAnythingSelected);
toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_EDIT, isMetadataSelected);
toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_RENAME, isMetadataSelected);
toolBarWidgets.enableToolbarItem(TOOLBAR_ITEM_DUPLICATE,
isMetadataSelected);
diff --git
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties
index 1220ae6613..43f2cf846b 100644
---
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties
+++
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/metadata/messages/messages_en_US.properties
@@ -41,6 +41,9 @@ MetadataPerspective.RefreshMetadata.Error.Message=Error
refreshing metadata tree
MetadataPerspective.ToolbarElement.CreateCopy.Tooltip=Create a copy
MetadataPerspective.ToolbarElement.Delete.Tooltip=Delete
MetadataPerspective.ToolbarElement.Edit.Tooltip=Edit
+MetadataPerspective.ToolbarElement.ExpandAll.Tooltip=Expand all metadata items
+MetadataPerspective.ToolbarElement.CollapseAll.Tooltip=Collapse all metadata
items
MetadataPerspective.ToolbarElement.New.Tooltip=Create a new metadata element
MetadataPerspective.ToolbarElement.Refresh.Tooltip=Refresh
-MetadataPerspective.ToolbarElement.Rename.Tooltip=Rename
\ No newline at end of file
+MetadataPerspective.ToolbarElement.Rename.Tooltip=Rename
+MetadataPerspective.Search.Placeholder=Search metadata...
\ No newline at end of file