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 ba427ab25a Issue #9050 : Keep database SQL editors in the database
perspective (#9051)
ba427ab25a is described below
commit ba427ab25a0f990437e610db77ab74cc55d95a95
Author: Matt Casters <[email protected]>
AuthorDate: Wed Oct 21 13:34:12 2026 +0200
Issue #9050 : Keep database SQL editors in the database perspective (#9051)
* Issue #9050 : Keep database SQL editors in the database perspective
Saved SQL editors were restored in the file explorer as well, because
"Database SQL" is not a registered file type and the .sql extension
fell through to the explorer. Opening a .sql file while the database
perspective is active now stays there. Other file types still open in
the explorer, and a .sql file opened from the explorer stays there.
* Issue #9050 : Skip explorer copies of database SQL files only once
Startup no longer drops a File Explorer tab just because the same file
is open in a database SQL editor. An explorer copy is skipped only while
a legacy "Database SQL" entry is still in the database-perspective
last-open list. writeLastOpenFiles no longer writes those entries, so
the filter stops after the first save.
---
.../ui/hopgui/delegates/HopGuiAuditDelegate.java | 86 ++++++++++++++++++++
.../ui/hopgui/delegates/HopGuiFileDelegate.java | 28 +++++++
.../perspective/database/DatabasePerspective.java | 28 ++++++-
.../perspective/database/DatabaseSqlFileType.java | 15 +++-
.../perspective/database/DatabaseWorkbench.java | 92 +++++++++++++++++++++-
.../database/messages/messages_en_US.properties | 4 +
.../HopGuiAuditDelegateStatePropertiesTest.java | 58 ++++++++++++++
.../delegates/HopGuiFileDelegateSqlOpenTest.java | 33 ++++++++
.../database/DatabaseSqlFileOpenTest.java | 58 ++++++++++++++
9 files changed, 398 insertions(+), 4 deletions(-)
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiAuditDelegate.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiAuditDelegate.java
index bb69ba6488..aaa54a92d3 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiAuditDelegate.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiAuditDelegate.java
@@ -19,8 +19,10 @@ package org.apache.hop.ui.hopgui.delegates;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.hop.core.exception.HopException;
@@ -43,6 +45,9 @@ import org.apache.hop.ui.hopgui.file.IHopFileType;
import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
import org.apache.hop.ui.hopgui.perspective.IHopPerspective;
import org.apache.hop.ui.hopgui.perspective.TabItemHandler;
+import org.apache.hop.ui.hopgui.perspective.database.DatabasePerspective;
+import org.apache.hop.ui.hopgui.perspective.database.DatabaseSqlEditorTab;
+import org.apache.hop.ui.hopgui.perspective.database.DatabaseSqlFileType;
import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
import org.apache.hop.ui.hopgui.perspective.metadata.MetadataPerspective;
import org.apache.hop.ui.util.SwtErrorHandler;
@@ -106,6 +111,14 @@ public class HopGuiAuditDelegate {
// Collect files that fail to open
List<String> failedFiles = new ArrayList<>();
+ // Saved database SQL editors are reopened by DatabaseSqlTabMemory. A
legacy "Database SQL"
+ // entry in the database-perspective list is not a registered file type,
so the .sql extension
+ // used to open it again in the file explorer (issue #9050). Skip that
entry, and an explorer
+ // copy of the same path, only while the legacy entry is still in the
list. writeLastOpenFiles
+ // no longer writes it, so the filter stops after the first save.
+ //
+ Set<String> databasePerspectiveLastOpen =
databasePerspectiveLastOpenFiles();
+
// Open the last files for each perspective...
//
List<IHopPerspective> perspectives =
hopGui.getPerspectiveManager().getPerspectives();
@@ -173,6 +186,9 @@ public class HopGuiAuditDelegate {
HopFileTypeRegistry.getInstance().getFileTypeByName(fileTypeName);
}
}
+ if (!openInLastFiles(filename, databasePerspectiveLastOpen)) {
+ continue;
+ }
if (hopFileToUse == null) {
hopFileToUse =
HopFileTypeRegistry.getInstance().findHopFileType(resolvedFilename);
@@ -353,6 +369,9 @@ public class HopGuiAuditDelegate {
List<String> files = new ArrayList<>();
for (TabItemHandler tabItem : tabItemsToSave) {
IHopFileTypeHandler typeHandler = tabItem.getTypeHandler();
+ if (!rememberInLastOpenFiles(typeHandler)) {
+ continue;
+ }
String filename = typeHandler.getFilename();
String name = typeHandler.getName();
if (StringUtils.isNotEmpty(filename)) {
@@ -413,6 +432,73 @@ public class HopGuiAuditDelegate {
}
}
+ /**
+ * Database SQL editors are restored by {@code DatabaseSqlTabMemory}.
Keeping them in this list
+ * makes the next startup open the same file in the file explorer.
+ */
+ static boolean rememberInLastOpenFiles(IHopFileTypeHandler typeHandler) {
+ return !(typeHandler instanceof DatabaseSqlEditorTab);
+ }
+
+ /**
+ * Whether a last-open-files entry should be opened by the generic restore.
+ *
+ * <p>A legacy {@code Database SQL} entry is never opened here. An explorer
copy of the same path
+ * is skipped only while {@code databasePerspectiveLastOpen} still contains
that legacy entry.
+ * {@link #writeLastOpenFiles()} no longer writes those entries, so the
filter stops after the
+ * first save.
+ */
+ static boolean openInLastFiles(String auditName, Set<String>
databasePerspectiveLastOpen) {
+ if (StringUtils.isEmpty(auditName)) {
+ return false;
+ }
+ String fileTypeName = null;
+ String filename = auditName;
+ if (auditName.contains(TAB_KEY_DELIMITER)) {
+ String[] parts = auditName.split(Pattern.quote(TAB_KEY_DELIMITER), 2);
+ if (parts.length >= 2) {
+ fileTypeName = parts[0];
+ filename = parts[1];
+ }
+ }
+ if (DatabaseSqlFileType.NAME.equals(fileTypeName)) {
+ return false;
+ }
+ if (databasePerspectiveLastOpen == null || StringUtils.isEmpty(filename)) {
+ return true;
+ }
+ return !databasePerspectiveLastOpen.contains(
+ DatabaseSqlFileType.NAME + TAB_KEY_DELIMITER + filename);
+ }
+
+ /**
+ * Names currently stored in the database-perspective last-open list. Used
to find legacy {@code
+ * Database SQL} entries left from before those editors were kept out of
this list.
+ */
+ private Set<String> databasePerspectiveLastOpenFiles() {
+ try {
+ AuditList auditList =
+ AuditManager.getActive()
+ .retrieveList(HopNamespace.getNamespace(),
DatabasePerspective.PERSPECTIVE_ID);
+ if (auditList == null || auditList.getNames() == null) {
+ return Set.of();
+ }
+ Set<String> names = new HashSet<>();
+ for (String name : auditList.getNames()) {
+ if (StringUtils.isNotEmpty(name)) {
+ names.add(name);
+ }
+ }
+ return names;
+ } catch (Exception e) {
+ hopGui
+ .getLog()
+ .logError(
+ "Error reading audit list of perspective " +
DatabasePerspective.PERSPECTIVE_ID, e);
+ return Set.of();
+ }
+ }
+
/**
* Copy handler state into a mutable map. Some handlers return {@link
* java.util.Collections#emptyMap()}; the audit list still needs to record
active/fileType/pane.
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegate.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegate.java
index 8cbd1b7025..14a9da8a3f 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegate.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegate.java
@@ -58,7 +58,9 @@ import
org.apache.hop.ui.hopgui.file.pipeline.HopGuiPipelineGraph;
import org.apache.hop.ui.hopgui.file.workflow.HopGuiWorkflowGraph;
import org.apache.hop.ui.hopgui.perspective.IHopPerspective;
import org.apache.hop.ui.hopgui.perspective.TabItemHandler;
+import org.apache.hop.ui.hopgui.perspective.database.DatabasePerspective;
import org.apache.hop.ui.hopgui.perspective.database.DatabaseSqlEditorTab;
+import org.apache.hop.ui.hopgui.perspective.database.DatabaseSqlFileType;
import org.apache.hop.ui.hopgui.perspective.execution.ExecutionPerspective;
import org.apache.hop.ui.hopgui.perspective.explorer.ExplorerPerspective;
import org.apache.hop.ui.util.EnvironmentUtils;
@@ -141,6 +143,22 @@ public class HopGuiFileDelegate {
public IHopFileTypeHandler fileOpen(String filename, boolean
activatePerspective)
throws Exception {
+ // A .sql file opened while the database perspective is active belongs in
a SQL editor there.
+ // The file registry only knows the explorer handler, which would switch
perspectives.
+ //
+ if (openSqlInDatabasePerspective(isDatabasePerspectiveActive(), filename))
{
+ IHopPerspective active = hopGui.getActivePerspective();
+ if (active instanceof DatabasePerspective database &&
database.canOpenSqlFiles()) {
+ IHopFileTypeHandler handler = database.openLocalSqlFile(filename);
+ if (handler != null) {
+ hopGui.handleFileCapabilities(
+ handler.getFileType(), handler, handler.hasChanged(), false,
false);
+ hopGui.auditDelegate.writeLastOpenFiles();
+ }
+ return handler;
+ }
+ }
+
HopFileTypeRegistry fileRegistry = HopFileTypeRegistry.getInstance();
IHopFileType hopFile = fileRegistry.findHopFileType(filename);
if (hopFile == null) {
@@ -154,6 +172,16 @@ public class HopGuiFileDelegate {
return fileOpenWithType(filename, hopFile, activatePerspective);
}
+ /** True when {@code filename} is a SQL file and the database perspective is
the active one. */
+ static boolean openSqlInDatabasePerspective(boolean
databasePerspectiveActive, String filename) {
+ return databasePerspectiveActive &&
DatabaseSqlFileType.isSqlFilename(filename);
+ }
+
+ private boolean isDatabasePerspectiveActive() {
+ IHopPerspective active = hopGui.getActivePerspective();
+ return active instanceof DatabasePerspective &&
hopGui.isActivePerspective(active);
+ }
+
/**
* Open a file with a specific file type. Used when restoring tabs so the
same file can be
* reopened in different modes (e.g. pipeline and text).
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabasePerspective.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabasePerspective.java
index 22087e618b..b3001c1ca8 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabasePerspective.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabasePerspective.java
@@ -24,6 +24,7 @@ import org.apache.hop.core.gui.plugin.GuiPlugin;
import org.apache.hop.core.gui.plugin.key.GuiKeyboardShortcut;
import org.apache.hop.core.gui.plugin.key.GuiOsxKeyboardShortcut;
import org.apache.hop.core.logging.ILoggingObject;
+import org.apache.hop.core.util.Utils;
import org.apache.hop.core.variables.IVariables;
import org.apache.hop.metadata.api.IHopMetadataProvider;
import org.apache.hop.ui.core.FormDataBuilder;
@@ -62,6 +63,9 @@ public class DatabasePerspective implements IHopPerspective,
TabClosable, IDatab
public static final Class<?> PKG = DatabasePerspective.class;
+ /** Id of this perspective. Also the audit group of its last-open files. */
+ public static final String PERSPECTIVE_ID = "database-perspective";
+
private static DatabasePerspective instance;
private HopGui hopGui;
@@ -89,7 +93,7 @@ public class DatabasePerspective implements IHopPerspective,
TabClosable, IDatab
@Override
public String getId() {
- return "database-perspective";
+ return PERSPECTIVE_ID;
}
@GuiKeyboardShortcut(control = true, shift = true, key = 'd', global = true)
@@ -203,6 +207,28 @@ public class DatabasePerspective implements
IHopPerspective, TabClosable, IDatab
workbench.openSqlFile(filename, connection, buffer, dirty);
}
+ /** True when this perspective can open a SQL file into an editor tab. */
+ public boolean canOpenSqlFiles() {
+ return isInitialized();
+ }
+
+ /**
+ * Open {@code filename} in this perspective. Uses the selected connection,
the connection of the
+ * active editor, or the only connection. Otherwise asks. Returns null when
there is no connection
+ * or the user cancels.
+ */
+ public IHopFileTypeHandler openLocalSqlFile(String filename) {
+ if (!isInitialized() || Utils.isEmpty(filename)) {
+ return null;
+ }
+ DatabaseMeta meta = workbench.chooseConnectionForSqlFile();
+ if (meta == null) {
+ return null;
+ }
+ activate();
+ return workbench.openSqlFile(filename, meta, null, false);
+ }
+
/**
* Bring this perspective to the front, select {@code meta} in the tree,
connect in the
* background, and open a SQL tab with {@code sql} (may be empty).
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseSqlFileType.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseSqlFileType.java
index b64b726991..ae8423391d 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseSqlFileType.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseSqlFileType.java
@@ -36,6 +36,12 @@ import
org.apache.hop.ui.hopgui.perspective.explorer.file.capabilities.FileTypeC
*/
public class DatabaseSqlFileType extends HopFileTypeBase {
+ /**
+ * Stored in the open-files audit key. Not a {@code @HopFileTypePlugin}
name, so startup must not
+ * resolve it by the {@code .sql} extension.
+ */
+ public static final String NAME = "Database SQL";
+
private static final Properties CAPABILITIES =
FileTypeCapabilities.getCapabilities(
IHopFileType.CAPABILITY_SAVE,
@@ -50,7 +56,7 @@ public class DatabaseSqlFileType extends HopFileTypeBase {
@Override
public String getName() {
- return "Database SQL";
+ return NAME;
}
@Override
@@ -90,8 +96,15 @@ public class DatabaseSqlFileType extends HopFileTypeBase {
return new EmptyHopFileTypeHandler();
}
+ /** {@code .sql} path, using the same extension rules as the other file
types. */
+ public static boolean isSqlFilename(String filename) {
+ return "sql".equals(HopFileTypeBase.extractExtension(filename));
+ }
+
@Override
public boolean isHandledBy(String filename, boolean checkContent) {
+ // False so the file registry keeps the explorer handler for .sql. The
database perspective
+ // claims these files only while it is the active perspective.
return false;
}
diff --git
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseWorkbench.java
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseWorkbench.java
index 17663d4f2e..c6b7a8cf76 100644
---
a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseWorkbench.java
+++
b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseWorkbench.java
@@ -47,7 +47,9 @@ import org.apache.hop.ui.core.PropsUi;
import org.apache.hop.ui.core.bus.HopGuiEvents;
import org.apache.hop.ui.core.database.DatabaseTreeNode;
import org.apache.hop.ui.core.database.DatabaseTreeUtil;
+import org.apache.hop.ui.core.dialog.EnterSelectionDialog;
import org.apache.hop.ui.core.dialog.ErrorDialog;
+import org.apache.hop.ui.core.dialog.MessageBox;
import org.apache.hop.ui.core.dialog.MessageDialogWithToggle;
import org.apache.hop.ui.core.gui.GuiMenuWidgets;
import org.apache.hop.ui.core.gui.GuiResource;
@@ -1284,8 +1286,94 @@ public class DatabaseWorkbench extends Composite
implements TabClosable {
tab.loadDetails();
}
- public void openSqlFile(String filename, DatabaseMeta meta, String buffer,
boolean dirty) {
- openSqlTab(meta, null, filename, buffer, dirty);
+ public DatabaseSqlEditorTab openSqlFile(
+ String filename, DatabaseMeta meta, String buffer, boolean dirty) {
+ if (meta != null) {
+ selectConnection(meta.getName());
+ }
+ return openSqlTab(meta, null, filename, buffer, dirty);
+ }
+
+ /**
+ * Connection for a SQL file opened while this workbench is showing. The
selected tree connection
+ * wins, then the active editor, then the only connection in the project.
Returns null when the
+ * user must pick, or when there is no connection.
+ */
+ DatabaseMeta chooseConnectionForSqlFile() {
+ String chosenName =
+ connectionNameForOpenedSqlFile(
+ nameOf(selectedDatabaseMeta()),
nameOf(activeEditorDatabaseMeta()), connectionNames());
+ if (!Utils.isEmpty(chosenName)) {
+ DatabaseMeta chosen = findConnection(chosenName);
+ if (chosen != null) {
+ return chosen;
+ }
+ }
+ List<String> names = connectionNames();
+ if (names.isEmpty()) {
+ MessageBox box = new MessageBox(host.getShell(), SWT.OK |
SWT.ICON_INFORMATION);
+ box.setText(
+ BaseMessages.getString(PKG,
"DatabasePerspective.OpenSqlFile.NoConnection.Title"));
+ box.setMessage(
+ BaseMessages.getString(PKG,
"DatabasePerspective.OpenSqlFile.NoConnection.Message"));
+ box.open();
+ return null;
+ }
+ EnterSelectionDialog dialog =
+ new EnterSelectionDialog(
+ host.getShell(),
+ names.toArray(new String[0]),
+ BaseMessages.getString(PKG,
"DatabasePerspective.OpenSqlFile.SelectConnection.Title"),
+ BaseMessages.getString(
+ PKG,
"DatabasePerspective.OpenSqlFile.SelectConnection.Message"));
+ String selected = dialog.open();
+ if (selected == null) {
+ return null;
+ }
+ return findConnection(selected);
+ }
+
+ static String connectionNameForOpenedSqlFile(
+ String selectedName, String activeEditorName, List<String>
connectionNames) {
+ if (!Utils.isEmpty(selectedName)) {
+ return selectedName;
+ }
+ if (!Utils.isEmpty(activeEditorName)) {
+ return activeEditorName;
+ }
+ String only = null;
+ if (connectionNames != null) {
+ for (String name : connectionNames) {
+ if (Utils.isEmpty(name)) {
+ continue;
+ }
+ if (only != null) {
+ return null;
+ }
+ only = name;
+ }
+ }
+ return only;
+ }
+
+ private static String nameOf(DatabaseMeta meta) {
+ return meta == null ? null : meta.getName();
+ }
+
+ private DatabaseMeta selectedDatabaseMeta() {
+ DatabaseConnectionState state = selectedState();
+ return state == null ? null : state.getDatabaseMeta();
+ }
+
+ private DatabaseMeta activeEditorDatabaseMeta() {
+ IHopFileTypeHandler handler = getActiveFileTypeHandler();
+ if (handler instanceof DatabaseSqlEditorTab tab) {
+ return tab.getDatabaseMeta();
+ }
+ if (handler instanceof DatabaseTableInfoTab tab) {
+ return tab.getDatabaseMeta();
+ }
+ return null;
}
/**
diff --git
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/database/messages/messages_en_US.properties
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/database/messages/messages_en_US.properties
index 80688d969c..bd3583dda7 100644
---
a/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/database/messages/messages_en_US.properties
+++
b/ui/src/main/resources/org/apache/hop/ui/hopgui/perspective/database/messages/messages_en_US.properties
@@ -105,6 +105,10 @@ DatabasePerspective.Save.Error.Message=Error saving file
''{0}''
DatabasePerspective.OpenInDatabase.Title=Open in Database perspective
DatabasePerspective.OpenInDatabase.Message=Select the database connection to
run this SQL against
DatabasePerspective.OpenInDatabase.Tooltip=Open this SQL file in the Database
perspective
+DatabasePerspective.OpenSqlFile.NoConnection.Title=No database connection
+DatabasePerspective.OpenSqlFile.NoConnection.Message=Create a relational
database connection before opening a SQL file in the Database perspective.
+DatabasePerspective.OpenSqlFile.SelectConnection.Title=Open SQL file
+DatabasePerspective.OpenSqlFile.SelectConnection.Message=Select the database
connection to run this SQL against
DatabasePerspective.Dialog.Title=Database
DatabasePerspective.Menu.Tools.Window=Database window
DatabasePerspective.Error.ConnectionNotFound=Database connection ''{0}'' no
longer exists.
diff --git
a/ui/src/test/java/org/apache/hop/ui/hopgui/delegates/HopGuiAuditDelegateStatePropertiesTest.java
b/ui/src/test/java/org/apache/hop/ui/hopgui/delegates/HopGuiAuditDelegateStatePropertiesTest.java
index 0112d30d81..8202c0f35a 100644
---
a/ui/src/test/java/org/apache/hop/ui/hopgui/delegates/HopGuiAuditDelegateStatePropertiesTest.java
+++
b/ui/src/test/java/org/apache/hop/ui/hopgui/delegates/HopGuiAuditDelegateStatePropertiesTest.java
@@ -19,12 +19,17 @@ package org.apache.hop.ui.hopgui.delegates;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
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 static org.mockito.Mockito.mock;
import java.util.Collections;
import java.util.Map;
+import java.util.Set;
import org.apache.hop.ui.hopgui.file.IHopFileTypeHandler;
import org.apache.hop.ui.hopgui.file.empty.EmptyHopFileTypeHandler;
+import org.apache.hop.ui.hopgui.perspective.database.DatabaseSqlEditorTab;
+import org.apache.hop.ui.hopgui.perspective.database.DatabaseSqlFileType;
import org.junit.jupiter.api.Test;
class HopGuiAuditDelegateStatePropertiesTest {
@@ -51,4 +56,57 @@ class HopGuiAuditDelegateStatePropertiesTest {
copy.put("active", true);
assertTrue((Boolean) copy.get("active"));
}
+
+ @Test
+ void databaseSqlEditorsAreNotReopenedInTheFileExplorer() {
+ String delimiter = "\u0001";
+ String savedSql = "/tmp/load.sql";
+ // A bare filename is not a legacy "Database SQL" entry, so it does not
hide an explorer tab.
+ Set<String> databasePerspectiveLastOpen = Set.of(savedSql);
+
+ assertFalse(
+ HopGuiAuditDelegate.openInLastFiles(
+ DatabaseSqlFileType.NAME + delimiter + savedSql, Set.of()));
+ assertTrue(
+ HopGuiAuditDelegate.openInLastFiles(
+ "SQL File" + delimiter + savedSql, databasePerspectiveLastOpen));
+ assertTrue(
+ HopGuiAuditDelegate.openInLastFiles(
+ "SQL File" + delimiter + "/tmp/notes.sql",
databasePerspectiveLastOpen));
+ assertTrue(
+ HopGuiAuditDelegate.openInLastFiles("/tmp/pipeline.hpl",
databasePerspectiveLastOpen));
+ assertFalse(HopGuiAuditDelegate.openInLastFiles("",
databasePerspectiveLastOpen));
+
+
assertFalse(HopGuiAuditDelegate.rememberInLastOpenFiles(mock(DatabaseSqlEditorTab.class)));
+ assertTrue(HopGuiAuditDelegate.rememberInLastOpenFiles(new
EmptyHopFileTypeHandler()));
+ }
+
+ @Test
+ void fileOpenInBothPerspectivesKeepsItsExplorerTab() {
+ String delimiter = "\u0001";
+ String savedSql = "/tmp/load.sql";
+
+ assertTrue(HopGuiAuditDelegate.openInLastFiles("SQL File" + delimiter +
savedSql, Set.of()));
+ assertTrue(HopGuiAuditDelegate.openInLastFiles("SQL File" + delimiter +
savedSql, null));
+ }
+
+ @Test
+ void legacyDatabaseSqlEntrySkipsExplorerCopyOnce() {
+ String delimiter = "\u0001";
+ String savedSql = "/tmp/load.sql";
+ Set<String> databasePerspectiveLastOpen =
+ Set.of(DatabaseSqlFileType.NAME + delimiter + savedSql);
+
+ assertFalse(
+ HopGuiAuditDelegate.openInLastFiles(
+ "SQL File" + delimiter + savedSql, databasePerspectiveLastOpen));
+ assertFalse(
+ HopGuiAuditDelegate.openInLastFiles(
+ DatabaseSqlFileType.NAME + delimiter + savedSql,
databasePerspectiveLastOpen));
+ assertTrue(
+ HopGuiAuditDelegate.openInLastFiles(
+ "SQL File" + delimiter + "/tmp/notes.sql",
databasePerspectiveLastOpen));
+ assertTrue(
+ HopGuiAuditDelegate.openInLastFiles("/tmp/pipeline.hpl",
databasePerspectiveLastOpen));
+ }
}
diff --git
a/ui/src/test/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegateSqlOpenTest.java
b/ui/src/test/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegateSqlOpenTest.java
new file mode 100644
index 0000000000..18383fd23a
--- /dev/null
+++
b/ui/src/test/java/org/apache/hop/ui/hopgui/delegates/HopGuiFileDelegateSqlOpenTest.java
@@ -0,0 +1,33 @@
+/*
+ * 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.delegates;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+class HopGuiFileDelegateSqlOpenTest {
+
+ @Test
+ void sqlFilesStayInTheDatabasePerspectiveOnlyWhileItIsActive() {
+ assertTrue(HopGuiFileDelegate.openSqlInDatabasePerspective(true,
"/data/load.sql"));
+ assertFalse(HopGuiFileDelegate.openSqlInDatabasePerspective(false,
"/data/load.sql"));
+ assertFalse(HopGuiFileDelegate.openSqlInDatabasePerspective(true,
"/data/load.hpl"));
+ }
+}
diff --git
a/ui/src/test/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseSqlFileOpenTest.java
b/ui/src/test/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseSqlFileOpenTest.java
new file mode 100644
index 0000000000..e51d381ca8
--- /dev/null
+++
b/ui/src/test/java/org/apache/hop/ui/hopgui/perspective/database/DatabaseSqlFileOpenTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.database;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+class DatabaseSqlFileOpenTest {
+
+ @Test
+ void sqlFilenameRecognizesTheSqlExtensionOnly() {
+ assertTrue(DatabaseSqlFileType.isSqlFilename("/data/load.SQL"));
+
assertTrue(DatabaseSqlFileType.isSqlFilename("file:///tmp/query.sql?unused"));
+ assertFalse(DatabaseSqlFileType.isSqlFilename("/data/load.hpl"));
+ assertFalse(DatabaseSqlFileType.isSqlFilename("/data/notes.sql.txt"));
+ assertFalse(DatabaseSqlFileType.isSqlFilename(null));
+ assertFalse(DatabaseSqlFileType.isSqlFilename(".sql"));
+ }
+
+ @Test
+ void
openedSqlFileUsesTheSelectedConnectionThenTheActiveEditorThenTheOnlyConnection()
{
+ assertEquals(
+ "selected",
+ DatabaseWorkbench.connectionNameForOpenedSqlFile(
+ "selected", "editor", List.of("only", "other")));
+ assertEquals(
+ "editor",
+ DatabaseWorkbench.connectionNameForOpenedSqlFile(null, "editor",
List.of("only", "other")));
+ assertEquals(
+ "only", DatabaseWorkbench.connectionNameForOpenedSqlFile(null, null,
List.of("only")));
+ assertNull(
+ DatabaseWorkbench.connectionNameForOpenedSqlFile(null, null,
List.of("only", "other")));
+ assertNull(DatabaseWorkbench.connectionNameForOpenedSqlFile(null, null,
List.of()));
+ assertNull(DatabaseWorkbench.connectionNameForOpenedSqlFile(null, null,
List.of("")));
+ assertEquals(
+ "editor", DatabaseWorkbench.connectionNameForOpenedSqlFile("",
"editor", List.of("only")));
+ }
+}