This is an automated email from the ASF dual-hosted git repository.

mcasters 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 5c3dd26062 Selection of the latest projects used and searchable list 
#6163 (#6193)
5c3dd26062 is described below

commit 5c3dd260620a57784b994391c43fa548a6547e3b
Author: Nicolas Adment <[email protected]>
AuthorDate: Mon Dec 15 15:00:41 2025 +0100

    Selection of the latest projects used and searchable list #6163 (#6193)
---
 .../main/java/org/apache/hop/git/GitGuiPlugin.java |   6 +-
 .../hop/git/messages/messages_en_US.properties     |   8 +-
 .../apache/hop/projects/config/ProjectsConfig.java |   6 +
 .../config/ProjectsConfigOptionPlugin.java         |  20 ++++
 .../apache/hop/projects/gui/ProjectsGuiPlugin.java | 126 ++++++++++++++++-----
 .../config/messages/messages_en_US.properties      |   1 +
 .../gui/messages/messages_en_US.properties         |   5 +-
 7 files changed, 138 insertions(+), 34 deletions(-)

diff --git 
a/plugins/misc/git/src/main/java/org/apache/hop/git/GitGuiPlugin.java 
b/plugins/misc/git/src/main/java/org/apache/hop/git/GitGuiPlugin.java
index 1b67da3f11..ae233199e2 100644
--- a/plugins/misc/git/src/main/java/org/apache/hop/git/GitGuiPlugin.java
+++ b/plugins/misc/git/src/main/java/org/apache/hop/git/GitGuiPlugin.java
@@ -363,10 +363,12 @@ public class GitGuiPlugin
       // int count = 0;
       String currentBranch = git.getBranch();
       for (String name : git.getBranches()) {
-        MenuItem item = new MenuItem(menu, SWT.CHECK);
+        MenuItem item = new MenuItem(menu, SWT.NONE);
         item.setText(name);
         // If the item is the active branch, mark it as checked
-        item.setSelection(currentBranch.equals(name));
+        if (currentBranch.equals(name)) {
+          item.setImage(GuiResource.getInstance().getImageCheck());
+        }
         // Change Branch when selecting one of the branch options
         item.addListener(SWT.Selection, e -> gitCheckoutBranch(name));
       }
diff --git 
a/plugins/misc/git/src/main/resources/org/apache/hop/git/messages/messages_en_US.properties
 
b/plugins/misc/git/src/main/resources/org/apache/hop/git/messages/messages_en_US.properties
index 32b820dbdc..dee9a017c6 100644
--- 
a/plugins/misc/git/src/main/resources/org/apache/hop/git/messages/messages_en_US.properties
+++ 
b/plugins/misc/git/src/main/resources/org/apache/hop/git/messages/messages_en_US.properties
@@ -63,12 +63,12 @@ GitGuiPlugin.Dialog.StageFiles.Header=Select files to commit
 GitGuiPlugin.Dialog.StageFiles.Message=Please select the files to commit. 
They'll be staged (add) for the commit to git
 GitGuiPlugin.Info.Label=Git Info: {0}
 GitGuiPlugin.Menu.Add.Text=Git Add
-GitGuiPlugin.Menu.Branch.Create.Text=Create Branch...
-GitGuiPlugin.Menu.Branch.Delete.Text=Delete Branch...
-GitGuiPlugin.Menu.Branch.Merge.Text=Merge Branch...
+GitGuiPlugin.Menu.Branch.Create.Text=Create branch...
+GitGuiPlugin.Menu.Branch.Delete.Text=Delete branch...
+GitGuiPlugin.Menu.Branch.Merge.Text=Merge branch...
 GitGuiPlugin.Menu.Branch.Pull.Text=Pull...
 GitGuiPlugin.Menu.Branch.Push.Text=Push...
-GitGuiPlugin.Menu.Branch.Rename.Text=Rename Branch...
+GitGuiPlugin.Menu.Branch.Rename.Text=Rename branch...
 GitGuiPlugin.Menu.Commit.Text=Git Commit
 GitGuiPlugin.Menu.Info.Text=Git Info
 GitGuiPlugin.Menu.Revert.Text=Git Revert
diff --git 
a/plugins/misc/projects/src/main/java/org/apache/hop/projects/config/ProjectsConfig.java
 
b/plugins/misc/projects/src/main/java/org/apache/hop/projects/config/ProjectsConfig.java
index 24cfaa9ca5..a435acb437 100644
--- 
a/plugins/misc/projects/src/main/java/org/apache/hop/projects/config/ProjectsConfig.java
+++ 
b/plugins/misc/projects/src/main/java/org/apache/hop/projects/config/ProjectsConfig.java
@@ -21,11 +21,15 @@ import 
com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.commons.lang.StringUtils;
 import org.apache.hop.projects.environment.LifecycleEnvironment;
 import org.apache.hop.projects.lifecycle.ProjectLifecycle;
 import org.apache.hop.projects.project.ProjectConfig;
 
+@Getter
+@Setter
 @JsonIgnoreProperties(value = {"openingLastProjectAtStartup"})
 public class ProjectsConfig {
 
@@ -37,6 +41,7 @@ public class ProjectsConfig {
   private boolean projectMandatory;
   private boolean environmentMandatory;
   private boolean environmentsForActiveProject;
+  private boolean sortByNameLastUsedProjects;
   private String defaultProject;
   private String defaultEnvironment;
   private String standardParentProject;
@@ -69,6 +74,7 @@ public class ProjectsConfig {
     standardProjectsFolder = config.standardProjectsFolder;
     defaultProjectConfigFile = config.defaultProjectConfigFile;
     environmentsForActiveProject = config.environmentsForActiveProject;
+    sortByNameLastUsedProjects = config.sortByNameLastUsedProjects;
   }
 
   public ProjectConfig findProjectConfig(String projectName) {
diff --git 
a/plugins/misc/projects/src/main/java/org/apache/hop/projects/config/ProjectsConfigOptionPlugin.java
 
b/plugins/misc/projects/src/main/java/org/apache/hop/projects/config/ProjectsConfigOptionPlugin.java
index 4448483ffd..f52a6246b9 100644
--- 
a/plugins/misc/projects/src/main/java/org/apache/hop/projects/config/ProjectsConfigOptionPlugin.java
+++ 
b/plugins/misc/projects/src/main/java/org/apache/hop/projects/config/ProjectsConfigOptionPlugin.java
@@ -19,6 +19,8 @@ package org.apache.hop.projects.config;
 
 import java.util.ArrayList;
 import java.util.List;
+import lombok.Getter;
+import lombok.Setter;
 import org.apache.commons.lang.StringUtils;
 import org.apache.hop.core.config.plugin.ConfigPlugin;
 import org.apache.hop.core.config.plugin.IConfigOptions;
@@ -67,6 +69,8 @@ public class ProjectsConfigOptionPlugin
       "10070-restrict-environments-to-active-project";
   private static final String WIDGET_ID_DEFAULT_PROJECT_CONFIG_FILENAME =
       "10070-default-project-config-filename";
+  private static final String WIDGET_ID_SORT_BY_NAME_LAST_USED_PROJECTS =
+      "10080-sort-by-name-last-used-project";
 
   @GuiWidgetElement(
       id = WIDGET_ID_ENABLE_PROJECTS,
@@ -167,6 +171,16 @@ public class ProjectsConfigOptionPlugin
       description = "Restrict environment list to active project")
   private Boolean environmentsForActiveProject;
 
+  @GuiWidgetElement(
+      id = WIDGET_ID_SORT_BY_NAME_LAST_USED_PROJECTS,
+      parentId = ConfigPluginOptionsTab.GUI_WIDGETS_PARENT_ID,
+      type = GuiElementType.CHECKBOX,
+      variables = false,
+      label = "i18n::ProjectConfig.SortByNameLastUsedProjects.Message")
+  @Getter
+  @Setter
+  private Boolean sortByNameLastUsedProjects;
+
   /**
    * Gets instance
    *
@@ -185,6 +199,7 @@ public class ProjectsConfigOptionPlugin
     instance.standardProjectsFolder = config.getStandardProjectsFolder();
     instance.defaultProjectConfigFile = config.getDefaultProjectConfigFile();
     instance.environmentsForActiveProject = 
config.isEnvironmentsForActiveProject();
+    instance.sortByNameLastUsedProjects = 
config.isSortByNameLastUsedProjects();
     return instance;
   }
 
@@ -368,6 +383,11 @@ public class ProjectsConfigOptionPlugin
           ProjectsConfigSingleton.getConfig()
               .setEnvironmentsForActiveProject(environmentsForActiveProject);
           break;
+        case WIDGET_ID_SORT_BY_NAME_LAST_USED_PROJECTS:
+          sortByNameLastUsedProjects = ((Button) control).getSelection();
+          ProjectsConfigSingleton.getConfig()
+              .setSortByNameLastUsedProjects(sortByNameLastUsedProjects);
+          break;
         default:
           break;
       }
diff --git 
a/plugins/misc/projects/src/main/java/org/apache/hop/projects/gui/ProjectsGuiPlugin.java
 
b/plugins/misc/projects/src/main/java/org/apache/hop/projects/gui/ProjectsGuiPlugin.java
index 761f84c519..b3d34b988f 100644
--- 
a/plugins/misc/projects/src/main/java/org/apache/hop/projects/gui/ProjectsGuiPlugin.java
+++ 
b/plugins/misc/projects/src/main/java/org/apache/hop/projects/gui/ProjectsGuiPlugin.java
@@ -28,6 +28,7 @@ import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -54,6 +55,7 @@ import org.apache.hop.core.variables.IVariables;
 import org.apache.hop.core.variables.Variables;
 import org.apache.hop.core.vfs.HopVfs;
 import org.apache.hop.history.AuditEvent;
+import org.apache.hop.history.AuditList;
 import org.apache.hop.history.AuditManager;
 import org.apache.hop.i18n.BaseMessages;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
@@ -61,6 +63,7 @@ import org.apache.hop.metadata.api.IHopMetadataSerializer;
 import org.apache.hop.pipeline.config.PipelineRunConfiguration;
 import org.apache.hop.pipeline.engines.local.LocalPipelineRunConfiguration;
 import org.apache.hop.projects.config.ProjectsConfig;
+import org.apache.hop.projects.config.ProjectsConfigOptionPlugin;
 import org.apache.hop.projects.config.ProjectsConfigSingleton;
 import org.apache.hop.projects.environment.LifecycleEnvironment;
 import org.apache.hop.projects.environment.LifecycleEnvironmentDialog;
@@ -102,6 +105,9 @@ public class ProjectsGuiPlugin {
 
   public static final Class<?> PKG = ProjectsGuiPlugin.class; // i18n
 
+  private static final String LAST_USED_PROJECTS_AUDIT_TYPE = "last-projects";
+  private static final int LAST_USED_PROJECTS_MAX_ENTRIES = 15;
+
   public static final String ID_TOOLBAR_ITEM_PROJECT = 
"toolbar-item-10000-project";
   public static final String ID_CONTEXT_MENU_PROJECT = "context-menu-project";
   public static final String ID_CONTEXT_MENU_PROJECT_ADD = 
"context-menu-project-40010-add";
@@ -126,6 +132,7 @@ public class ProjectsGuiPlugin {
       "0005-navigate-project-home"; // right next to Home button
 
   FileTree tree;
+  private static List<String> lastUsedProjects;
 
   /** Automatically instantiated when the toolbar widgets need it */
   public ProjectsGuiPlugin() {
@@ -212,6 +219,10 @@ public class ProjectsGuiPlugin {
       //
       hopGui.getActiveFileTypeHandler().updateGui();
 
+      // Remember the last used projects for the toolbar
+      //
+      rememberLastUsedProjects(projectName);
+
       // Update the toolbar items
       //
       updateProjectToolItem(projectName);
@@ -316,6 +327,54 @@ public class ProjectsGuiPlugin {
     }
   }
 
+  public static List<String> getLastUsedProjects() {
+    // Initialize the list of last used projects
+    if (lastUsedProjects == null) {
+      List<String> allProjectNames = 
ProjectsConfigSingleton.getConfig().listProjectConfigNames();
+      lastUsedProjects = new LinkedList<>();
+      try {
+        AuditList auditList =
+            AuditManager.getActive()
+                .retrieveList(HopGui.DEFAULT_HOP_GUI_NAMESPACE, 
LAST_USED_PROJECTS_AUDIT_TYPE);
+
+        for (String name : auditList.getNames()) {
+          if (allProjectNames.contains(name)) {
+            lastUsedProjects.add(name);
+          }
+        }
+      } catch (Exception e) {
+        LogChannel.GENERAL.logError("Error loading last used projects", e);
+        lastUsedProjects.addAll(allProjectNames.subList(0, 
LAST_USED_PROJECTS_MAX_ENTRIES));
+      }
+    }
+
+    return lastUsedProjects;
+  }
+
+  /** Remember the last used projects */
+  public static void rememberLastUsedProjects(String projectName) {
+
+    // Initialize
+    getLastUsedProjects();
+
+    // Keep only a limited number of last-used projects
+    lastUsedProjects.remove(projectName);
+    lastUsedProjects.add(0, projectName);
+    if (lastUsedProjects.size() > LAST_USED_PROJECTS_MAX_ENTRIES) {
+      lastUsedProjects = lastUsedProjects.subList(0, 
LAST_USED_PROJECTS_MAX_ENTRIES);
+    }
+
+    // Write the audit list of last used projects
+    try {
+      AuditList auditList = new AuditList(lastUsedProjects);
+      AuditManager.getActive()
+          .storeList(HopGui.DEFAULT_HOP_GUI_NAMESPACE, 
LAST_USED_PROJECTS_AUDIT_TYPE, auditList);
+    } catch (Exception e) {
+      LogChannel.GENERAL.logError(
+          "Error writing list of last used projects " + 
LAST_USED_PROJECTS_AUDIT_TYPE, e);
+    }
+  }
+
   
//////////////////////////////////////////////////////////////////////////////////
   // Environment toolbar items...
   //
@@ -455,23 +514,32 @@ public class ProjectsGuiPlugin {
 
     new MenuItem(menu, SWT.SEPARATOR);
 
+    // Display the last-used projects
+    List<String> names = new ArrayList<>(getLastUsedProjects());
+
+    // If the user prefers to display in alphabetical order
+    if 
(ProjectsConfigOptionPlugin.getInstance().getSortByNameLastUsedProjects()) {
+      names.sort(String::compareToIgnoreCase);
+    }
+
     String currentProjectName = HopNamespace.getNamespace();
-    List<String> names = 
ProjectsConfigSingleton.getConfig().listProjectConfigNames();
+
     int count = 0;
     for (String name : names) {
-      MenuItem item = new MenuItem(menu, SWT.CHECK);
+      MenuItem item = new MenuItem(menu, SWT.NONE);
       item.setText(name);
-      item.setSelection(currentProjectName.equals(name));
       item.addListener(SWT.Selection, e -> selectProject(name));
-      //    if (++count == 10) break;
+      if (currentProjectName.equals(name)) {
+        item.setImage(GuiResource.getInstance().getImageCheck());
+      }
+      if (++count == LAST_USED_PROJECTS_MAX_ENTRIES) break;
     }
-    // TODO: display only the last 10 used projects
-    //    if (count == 5) {
-    //      new MenuItem(menu, SWT.SEPARATOR);
-    //      MenuItem item = new MenuItem(menu, SWT.PUSH);
-    //      item.setText("More...");
-    //      item.addListener(SWT.Selection, e -> selectProject());
-    //    }
+
+    // Add a menu to open a dialog to select it
+    new MenuItem(menu, SWT.SEPARATOR);
+    MenuItem item = new MenuItem(menu, SWT.PUSH);
+    item.setText(BaseMessages.getString(PKG, 
"HopGui.Toolbar.Project.Select.Tooltip"));
+    item.addListener(SWT.Selection, e -> selectProject());
 
     return menu;
   }
@@ -498,34 +566,25 @@ public class ProjectsGuiPlugin {
     String currentProjectName = getProjectToolItem().getText();
     String currentEnvironmentName = getEnvironmentToolItem().getText();
 
-    // List of first 10 projects
+    // Display list of environments
     //
     ProjectsConfig config = ProjectsConfigSingleton.getConfig();
     List<String> names = config.listEnvironmentNames();
-    int count = 0;
     for (String name : names) {
 
       // Exclude environment linked to another project
       LifecycleEnvironment environment = config.findEnvironment(name);
       if (Utils.isEmpty(environment.getProjectName())
           || currentProjectName.equals(environment.getProjectName())) {
-        MenuItem item = new MenuItem(menu, SWT.CHECK);
+        MenuItem item = new MenuItem(menu, SWT.NONE);
         item.setText(name);
-        item.setSelection(currentEnvironmentName.equals(name));
         item.addListener(SWT.Selection, e -> selectEnvironment(name));
-        // if (++count == 10) break;
+        if (currentEnvironmentName.equals(name)) {
+          item.setImage(GuiResource.getInstance().getImageCheck());
+        }
       }
     }
 
-    // TODO: display only the last 10 used environments
-    // If more projects, open a dialog to select it
-    //    if (count == 10) {
-    //      new MenuItem(menu, SWT.SEPARATOR);
-    //      MenuItem item = new MenuItem(menu, SWT.PUSH);
-    //      item.setText("More...");
-    //      item.addListener(SWT.Selection, e -> selectEnvironment());
-    //    }
-
     return menu;
   }
 
@@ -548,13 +607,26 @@ public class ProjectsGuiPlugin {
 
   public void selectProject() {
     List<String> projectNames = 
ProjectsConfigSingleton.getConfig().listProjectConfigNames();
+    projectNames.sort(String::compareToIgnoreCase);
+
+    String[] projects = projectNames.toArray(new String[0]);
+
     EnterSelectionDialog dialog =
         new EnterSelectionDialog(
             HopGui.getInstance().getActiveShell(),
-            projectNames.toArray(new String[0]),
+            projects,
             BaseMessages.getString(PKG, 
"ProjectGuiPlugin.Dialog.AvailableProjects.Title"),
             BaseMessages.getString(PKG, 
"ProjectGuiPlugin.Dialog.AvailableProjects.Message"));
-    dialog.setCurrentValue(HopNamespace.getNamespace());
+
+    String currentProject = HopNamespace.getNamespace();
+    dialog.setCurrentValue(currentProject);
+    int index = Const.indexOfString(currentProject, projects);
+    if (index >= 0) {
+      dialog.setSelectedNrs(
+          new int[] {
+            index,
+          });
+    }
 
     String name = dialog.open();
     if (name != null) {
diff --git 
a/plugins/misc/projects/src/main/resources/org/apache/hop/projects/config/messages/messages_en_US.properties
 
b/plugins/misc/projects/src/main/resources/org/apache/hop/projects/config/messages/messages_en_US.properties
index d7baa29a70..54179949bb 100644
--- 
a/plugins/misc/projects/src/main/resources/org/apache/hop/projects/config/messages/messages_en_US.properties
+++ 
b/plugins/misc/projects/src/main/resources/org/apache/hop/projects/config/messages/messages_en_US.properties
@@ -30,6 +30,7 @@ 
ProjectConfig.ProjectNotExists.StandardProject.Error.Message=Project ''{0}'' can
 ProjectConfig.RestrictEnvsToActiveProject.Message=Restrict environment list to 
active project
 ProjectConfig.SavingOption.ErrorDialog.Header=Error
 ProjectConfig.SavingOption.ErrorDialog.Message=Error saving option
+ProjectConfig.SortByNameLastUsedProjects.Message=Sort the last used projects 
alphabetically
 ProjectConfig.StdProjectFilename.Message=The project configuration filename 
for new projects
 ProjectConfig.StdProjectFolder.Description=The standard projects folder for 
new projects
 ProjectConfig.StdProjectFolder.Message=The standard projects folder for new 
projects
diff --git 
a/plugins/misc/projects/src/main/resources/org/apache/hop/projects/gui/messages/messages_en_US.properties
 
b/plugins/misc/projects/src/main/resources/org/apache/hop/projects/gui/messages/messages_en_US.properties
index 87c39f9806..7545f18d5c 100644
--- 
a/plugins/misc/projects/src/main/resources/org/apache/hop/projects/gui/messages/messages_en_US.properties
+++ 
b/plugins/misc/projects/src/main/resources/org/apache/hop/projects/gui/messages/messages_en_US.properties
@@ -36,6 +36,7 @@ HopGui.Toolbar.Project.Delete.Label=Delete project...
 HopGui.Toolbar.Project.Delete.Tooltip=Delete the selected project
 HopGui.Toolbar.Project.Edit.Label=Edit project...
 HopGui.Toolbar.Project.Edit.Tooltip=Edit the selected project
+HopGui.Toolbar.Project.Select.Tooltip=More projects...
 ProjectGuiPlugin.AddEnvironment.Error.Dialog.Header=Error
 ProjectGuiPlugin.AddEnvironment.Error.Dialog.Message=Error adding lifecycle 
environment
 ProjectGuiPlugin.AddProject.Error.Dialog.Header=Error
@@ -57,6 +58,8 @@ ProjectGuiPlugin.DeleteProject.Error.Dialog.Message=Error 
removing project ''{0}
 ProjectGuiPlugin.DeleteProject.ProjectReferencedAsParent.Header=Can''t delete 
the project!
 ProjectGuiPlugin.DeleteProject.ProjectReferencedAsParent.Message1=Current 
project cannot be deleted because is referenced as parent project in following 
projects:
 ProjectGuiPlugin.DeleteProject.ProjectReferencedAsParent.Message2=To perform 
the deletion, you MUST firstly remove the parent project reference in the 
listed projects and then retry.
+ProjectGuiPlugin.Dialog.AvailableProjects.Title=Available projects
+ProjectGuiPlugin.Dialog.AvailableProjects.Message=Select a project to activate
 ProjectGuiPlugin.EditEnvironment.Error.Dialog.Header=Error
 ProjectGuiPlugin.EditEnvironment.Error.Dialog.Message=Error editing 
environment ''{0}''
 ProjectGuiPlugin.EditProject.Error.Dialog.Header=Error
@@ -81,4 +84,4 @@ ProjectGuiPlugin.ZipDirectory.Error.Dialog.Header=Error
 ProjectGuiPlugin.ZipDirectory.Error.Dialog.Message=Error zipping project
 ProjectGuiPlugin.ZipDirectory.Taskname.Text=Zipping project directory...
 ProjectGuiPlugin.IncludeVariables.Label=Include variables in export
-ProjectGuiPlugin.IncludeMetadata.Label=Include metadata in export
\ No newline at end of file
+ProjectGuiPlugin.IncludeMetadata.Label=Include metadata in export

Reply via email to