diff --git a/bundles/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF
index 85b7c3d682c6..7c3f352aad7e 100644
--- a/bundles/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.ui.ide.application/META-INF/MANIFEST.MF
@@ -8,7 +8,7 @@ Bundle-Localization: plugin
Require-Bundle: org.eclipse.ui.ide;bundle-version="[3.21.0,4.0.0)",
org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)",
org.eclipse.core.resources;bundle-version="[3.19.0,4.0.0)",
- org.eclipse.ui;bundle-version="[3.208.0,4.0.0)",
+ org.eclipse.ui;bundle-version="[3.209.0,4.0.0)",
org.eclipse.ui.navigator.resources;bundle-version="[3.9.0,4.0.0)",
org.eclipse.core.net;bundle-version="[1.5.0,2.0.0)",
org.eclipse.core.filesystem;bundle-version="1.10.0",
diff --git a/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java b/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java
index de109fddcea5..a4bc366a90fa 100644
--- a/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java
+++ b/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2003, 2020 IBM Corporation and others.
+ * Copyright (c) 2003, 2025 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -24,11 +24,9 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
-import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -42,7 +40,6 @@
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
-import org.eclipse.core.runtime.URIUtil;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.eclipse.equinox.app.IApplication;
@@ -65,6 +62,7 @@
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.Workbench;
import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.internal.WorkspaceLock;
import org.eclipse.ui.internal.ide.ChooseWorkspaceData;
import org.eclipse.ui.internal.ide.ChooseWorkspaceDialog;
import org.eclipse.ui.internal.ide.IDEInternalPreferences;
@@ -89,19 +87,10 @@ public class IDEApplication implements IApplication, IExecutableExtension {
private static final String VERSION_FILENAME = "version.ini"; //$NON-NLS-1$
- private static final Path LOCK_INFO_FILE = Path.of(METADATA_FOLDER, ".lock_info"); //$NON-NLS-1$
-
private static final String DISPLAY_VAR = "DISPLAY"; //$NON-NLS-1$
private static final String HOST_NAME_VAR = "HOSTNAME"; //$NON-NLS-1$
- private static final String PROCESS_ID = "process-id"; //$NON-NLS-1$
-
- private static final String DISPLAY = "display"; //$NON-NLS-1$
-
- private static final String HOST = "host"; //$NON-NLS-1$
-
- private static final String USER = "user"; //$NON-NLS-1$
private static final String USER_NAME = "user.name"; //$NON-NLS-1$
@@ -223,12 +212,13 @@ public void setInitializationData(IConfigurationElement config,
}
/**
- * Return null if a valid workspace path has been set and an exit code otherwise.
- * Prompt for and set the path if possible and required.
+ * Returns null if a valid workspace has been selected or locked
+ * successfully, and an exit code otherwise. Prompts for and sets the workspace
+ * path if required.
*
* @param applicationArguments the command line arguments
- * @return null if a valid instance location has been set and an exit code
- * otherwise
+ * @return null if a valid instance location has been set and an
+ * exit code otherwise
*/
@SuppressWarnings("rawtypes")
protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
@@ -273,29 +263,29 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
return EXIT_WORKSPACE_LOCKED;
}
- String wsLockedError = NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceCannotLockMessage,
- workspaceDirectory.getAbsolutePath());
// check if there is a lock info then append it to error message.
- String lockInfo = getWorkspaceLockInfo(instanceLoc.getURL());
- if (lockInfo != null && !lockInfo.isBlank()) {
- wsLockedError = wsLockedError + System.lineSeparator() + System.lineSeparator()
- + NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Message, lockInfo);
+ String lockInfo = WorkspaceLock.getWorkspaceLockDetails(instanceLoc.getURL());
+ if (lockInfo != null) {
+ hideSplash(shell);
+ WorkspaceLock.showWorkspaceLockedDialog(shell, workspaceDirectory.getAbsolutePath(),
+ lockInfo);
+ } else {
+ hideSplash(shell);
+ MessageDialog.openError(shell,
+ IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,
+ IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);
}
- MessageDialog.openError(
- shell,
- IDEWorkbenchMessages.IDEApplication_workspaceCannotLockTitle,
- wsLockedError);
} else {
+ hideSplash(shell);
MessageDialog.openError(
shell,
IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,
IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);
}
} catch (IOException e) {
- IDEWorkbenchPlugin.log("Could not obtain lock for workspace location", //$NON-NLS-1$
- e);
- MessageDialog
- .openError(
+ hideSplash(shell);
+ IDEWorkbenchPlugin.log("Could not obtain lock for workspace location", e); //$NON-NLS-1$
+ MessageDialog.openError(
shell,
IDEWorkbenchMessages.InternalError,
e.getMessage());
@@ -311,12 +301,10 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
// -data is specified but invalid according to checkValidWorkspace(): re-launch
ChooseWorkspaceData launchData = new ChooseWorkspaceData(instanceLoc.getDefault());
- boolean parentShellVisible = false;
if (isValid(shell)) {
- parentShellVisible = shell.getVisible();
// bug 455162, bug 427393: hide the splash if the workspace
// prompt dialog should be opened
- if (parentShellVisible && launchData.getShowDialog()) {
+ if (shell.getVisible() && launchData.getShowDialog()) {
shell.setVisible(false);
}
}
@@ -349,7 +337,15 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
try {
if (instanceLoc.isSet()) {
// restart with new location
- return Workbench.setRestartArguments(workspaceUrl.getFile());
+ Object workbenchExitCode = Workbench.setRestartArguments(workspaceUrl.getFile());
+ // "null" workbenchExitCode indicates an error: application is running in
+ // development mode and doesn't support restart.
+ if (workbenchExitCode == null) {
+ // No error to show, it was shown in Workbench.setRestartArguments() already.
+ // Just exit.
+ return EXIT_OK;
+ }
+ return workbenchExitCode;
}
// the operation will fail if the url is not a valid
@@ -360,25 +356,18 @@ protected Object checkInstanceLocation(Shell shell, Map applicationArguments) {
writeWsLockInfo(instanceLoc.getURL());
return null;
}
- } catch (IllegalStateException e) {
+ } catch (IOException | IllegalStateException e) {
MessageDialog
.openError(
shell,
IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,
IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);
- return EXIT_OK;
- } catch (IOException e) {
- MessageDialog
- .openError(
- shell,
- IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetTitle,
- IDEWorkbenchMessages.IDEApplication_workspaceCannotBeSetMessage);
}
// by this point it has been determined that the workspace is
// already in use -- force the user to choose again
- String lockInfo = getWorkspaceLockInfo(workspaceUrl);
+ String lockInfo = WorkspaceLock.getWorkspaceLockDetails(workspaceUrl);
MessageDialog dialog = new MessageDialog(null, IDEWorkbenchMessages.IDEApplication_workspaceInUseTitle,
null, NLS.bind(IDEWorkbenchMessages.IDEApplication_workspaceInUseMessage, workspaceUrl.getFile()),
@@ -412,49 +401,6 @@ protected Control createCustomArea(Composite parent) {
}
}
- /**
- * Read workspace lock file and parse all the properties present. Based on the
- * eclipse version and operating system some or all the properties may not
- * present. In such scenario it will return empty string.
- *
- * @return Previous lock owner details.
- */
- protected String getWorkspaceLockInfo(URL workspaceUrl) {
- try {
- Path lockFile = getLockInfoFile(workspaceUrl);
- if (!Files.exists(lockFile)) {
- return null;
- }
-
- StringBuilder sb = new StringBuilder();
- Properties props = new Properties();
- try (InputStream is = Files.newInputStream(lockFile)) {
- props.load(is);
- String prop = props.getProperty(USER);
- if (prop != null) {
- sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_User, prop));
- }
- prop = props.getProperty(HOST);
- if (prop != null) {
- sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Host, prop));
- }
- prop = props.getProperty(DISPLAY);
- if (prop != null) {
- sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_Disp, prop));
- }
- prop = props.getProperty(PROCESS_ID);
- if (prop != null) {
- sb.append(NLS.bind(IDEWorkbenchMessages.IDEApplication_Ws_Lock_Owner_P_Id, prop));
- }
- return sb.toString();
- }
- } catch (Exception e) {
- IDEWorkbenchPlugin.log("Could not read lock info file: ", e); //$NON-NLS-1$
-
- }
- return null;
- }
-
/**
* Write lock owner details onto workspace lock file. Data includes user, host,
* display and current java process id.
@@ -464,19 +410,19 @@ protected void writeWsLockInfo(URL workspaceUrl) {
String user = System.getProperty(USER_NAME);
if (user != null) {
- props.setProperty(USER, user);
+ props.setProperty(WorkspaceLock.USER, user);
}
String host = getHostName();
if (host != null) {
- props.setProperty(HOST, host);
+ props.setProperty(WorkspaceLock.HOST, host);
}
String display = getDisplay();
if (display != null) {
- props.setProperty(DISPLAY, display);
+ props.setProperty(WorkspaceLock.DISPLAY, display);
}
String pid = getProcessId();
if (pid != null) {
- props.setProperty(PROCESS_ID, pid);
+ props.setProperty(WorkspaceLock.PROCESS_ID, pid);
}
if (props.isEmpty()) {
@@ -532,20 +478,6 @@ private String getHostName() {
return hostName;
}
- /**
- * Returns the .lock_info file. Does not check if it exists.
- *
- * @param workspaceUrl
- * @return .lock_info file.
- */
- private static Path getLockInfoFile(URL workspaceUrl) {
- try {
- return Path.of(URIUtil.toURI(workspaceUrl)).resolve(LOCK_INFO_FILE);
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
/**
* Creates the .lock_info file if it does not exist.
*
@@ -553,7 +485,7 @@ private static Path getLockInfoFile(URL workspaceUrl) {
* @return .lock_info file.
*/
private static Path createLockInfoFile(URL workspaceUrl) throws Exception {
- Path lockInfoFile = getLockInfoFile(workspaceUrl);
+ Path lockInfoFile = WorkspaceLock.getLockInfoFile(workspaceUrl);
if (!Files.exists(lockInfoFile)) {
Files.createFile(lockInfoFile);
}
@@ -736,9 +668,7 @@ protected Shell getParentShell() {
}
};
// hide splash if any
- if (isValid(shell)) {
- shell.setVisible(false);
- }
+ hideSplash(shell);
int returnCode = dialog.open();
if (returnCode == IDialogConstants.RETRY_ID || returnCode == SWT.DEFAULT) {
@@ -759,6 +689,12 @@ protected Shell getParentShell() {
return ReturnCode.VALID;
}
+ protected void hideSplash(Shell shell) {
+ if (isValid(shell)) {
+ shell.setVisible(false);
+ }
+ }
+
/**
* Compares the version of the workspace with the specified URL, to the version
* of the running IDE.
@@ -929,4 +865,4 @@ public void stop() {
}
});
}
-}
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java
index 0a14c764d017..bec664b18a5a 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/IDEWorkbenchMessages.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2017 IBM Corporation and others.
+ * Copyright (c) 2005, 2025 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -1050,8 +1050,6 @@ public class IDEWorkbenchMessages extends NLS {
public static String IDEApplication_workspaceInvalidMessage;
public static String IDEApplication_workspaceCannotBeSetTitle;
public static String IDEApplication_workspaceCannotBeSetMessage;
- public static String IDEApplication_workspaceCannotLockTitle;
- public static String IDEApplication_workspaceCannotLockMessage;
public static String IDEApplication_versionTitle_newerWorkspace;
public static String IDEApplication_versionTitle_olderWorkspace;
public static String IDEApplication_versionMessage_newerWorkspace;
@@ -1147,13 +1145,7 @@ public class IDEWorkbenchMessages extends NLS {
public static String WorkbenchPreference_maxSimultaneousBuilds;
public static String WorkbenchPreference_maxSimultaneousBuildIntervalError;
-
- public static String IDEApplication_Ws_Lock_Owner_User;
- public static String IDEApplication_Ws_Lock_Owner_Host;
- public static String IDEApplication_Ws_Lock_Owner_Disp;
- public static String IDEApplication_Ws_Lock_Owner_P_Id;
public static String IDEApplication_Ws_Lock_Owner_Message;
-
static {
// load message values from bundle file
NLS.initializeMessages(BUNDLE_NAME, IDEWorkbenchMessages.class);
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/actions/OpenWorkspaceAction.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/actions/OpenWorkspaceAction.java
index 742864e29185..26b23e36f792 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/actions/OpenWorkspaceAction.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/actions/OpenWorkspaceAction.java
@@ -13,6 +13,8 @@
*******************************************************************************/
package org.eclipse.ui.internal.ide.actions;
+import java.net.MalformedURLException;
+import java.nio.file.Path;
import java.util.ArrayList;
import org.eclipse.core.runtime.Platform;
@@ -24,6 +26,7 @@
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
@@ -31,6 +34,8 @@
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.internal.Workbench;
+import org.eclipse.ui.internal.WorkbenchMessages;
+import org.eclipse.ui.internal.WorkspaceLock;
import org.eclipse.ui.internal.ide.ChooseWorkspaceData;
import org.eclipse.ui.internal.ide.ChooseWorkspaceDialog;
import org.eclipse.ui.internal.ide.ChooseWorkspaceWithSettingsDialog;
@@ -217,8 +222,34 @@ public void run() {
public void restart(String workspacePath) {
Object result = Workbench.setRestartArguments(workspacePath);
if (result == IApplication.EXIT_RELAUNCH) {
- window.getWorkbench().restart();
+ if (canRestartWithWorkspace(workspacePath)) {
+ window.getWorkbench().restart();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given workspace is locked by another instance of the workbench.
+ * Shows error dialog if the workspace is locked or on any other error.
+ *
+ * @param workspacePath the path of the workspace to check
+ * @return true if we can restart with given workspace,
+ * false if the workspace is locked or on any error
+ *
+ */
+ private boolean canRestartWithWorkspace(String workspacePath) throws IllegalStateException {
+ Path selectedWorkspace = Path.of(workspacePath);
+ try {
+ String workspaceLockDetails = WorkspaceLock.getWorkspaceLockDetails(selectedWorkspace.toUri().toURL());
+ if (workspaceLockDetails == null) {
+ return true;
+ }
+ WorkspaceLock.showWorkspaceLockedDialog(window.getShell(), workspacePath, workspaceLockDetails);
+ } catch (MalformedURLException e) {
+ MessageDialog.openError(window.getShell(), WorkbenchMessages.OpenWorkspaceAction_invalidWorkspacePath,
+ workspacePath);
}
+ return false;
}
/**
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties
index b79612e23efe..348c34e50b9a 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/messages.properties
@@ -1,5 +1,5 @@
###############################################################################
-# Copyright (c) 2000, 2022 IBM Corporation and others.
+# Copyright (c) 2000, 2025 IBM Corporation and others.
#
# This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
@@ -1074,8 +1074,6 @@ IDEApplication_workspaceInvalidTitle=Invalid Workspace
IDEApplication_workspaceInvalidMessage=Selected workspace is not valid; choose a different one.
IDEApplication_workspaceCannotBeSetTitle=Workspace Cannot Be Created
IDEApplication_workspaceCannotBeSetMessage=Could not launch the product because the specified workspace cannot be created. The specified workspace directory is either invalid or read-only.
-IDEApplication_workspaceCannotLockTitle=Workspace Cannot Be Locked
-IDEApplication_workspaceCannotLockMessage=Could not launch the product because the associated workspace at ''{0}'' is currently in use by another Eclipse application.
IDEApplication_versionTitle_olderWorkspace=Older Workspace Version
IDEApplication_versionTitle_newerWorkspace=Newer Workspace Version
IDEApplication_versionMessage_olderWorkspace=The ''{0}'' workspace was written with an older version. \
@@ -1152,8 +1150,4 @@ editorAssociationOverride_error_couldNotCreate_message=The ''{0}'' extension fro
editorAssociationOverride_error_invalidElementName_message=An extension from plug-in ''{0}'' to the ''org.eclipse.ui.ide.editorAssociationOverride'' extension point was ignored because it contains the following invalid element: ''{1}''.
editorAssociationOverride_error_invalidExtension_message=The ''{0}'' extension from plug-in ''{1}'' to the ''org.eclipse.ui.ide.editorAssociationOverride'' extension point will be ignored because it contains invalid attributes.
-IDEApplication_Ws_Lock_Owner_User=User:\t\t{0}\n
-IDEApplication_Ws_Lock_Owner_Host=Host:\t\t{0}\n
-IDEApplication_Ws_Lock_Owner_Disp=Display:\t\t{0}\n
-IDEApplication_Ws_Lock_Owner_P_Id=Process ID:\t{0}\n
IDEApplication_Ws_Lock_Owner_Message=Workspace lock is currently held by:\n{0}
diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java
index d8997df75711..71910c2c7b1f 100644
--- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java
+++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java
@@ -2694,7 +2694,13 @@ private static String buildCommandLine(String workspace) {
* as the workspace location.
*
* @param workspacePath the new workspace location
- * @return {@link IApplication#EXIT_OK} or {@link IApplication#EXIT_RELAUNCH}
+ * @return null if application was started in development mode and
+ * the specified workspace path is different from the current one,
+ * otherwise {@link IApplication#EXIT_RELAUNCH}.
+ *
+ * In case of null return, a message dialog will be shown,
+ * so the caller doesn't need to handle the error case via dialog.
+ *
+ * This class is used during two different phases of the Eclipse application + * lifecycle: + *
+ *+ * To support both environments, this class does not rely on workbench-specific + * APIs such as {@code PlatformUI.getWorkbench()} or {@code IWorkbenchWindow}, + * nor on any API that requires an initialized workbench window. Only SWT-level + * constructs (for example, {@link org.eclipse.swt.widgets.Display} and + * {@link org.eclipse.swt.widgets.Shell}) and core/runtime APIs are used. + *
+ * + */ +public class WorkspaceLock { + + public static final String PROCESS_ID = "process-id"; //$NON-NLS-1$ + + public static final String DISPLAY = "display"; //$NON-NLS-1$ + + public static final String HOST = "host"; //$NON-NLS-1$ + + public static final String USER = "user"; //$NON-NLS-1$ + + /** + * Read workspace lock file of the selected workspace if it is locked by another + * Eclipse application and parse all the properties present. Based on the + * Eclipse version and operating system some or all the properties may be not + * present. In such scenario empty string may be returned. + * + * @param workspaceUrl theURL of workspace to check for lock
+ * details
+ * @return null if workspace is not locked, empty string if
+ * workspace is locked but no details are available (or lock file is not
+ * accessible), or a formatted string with lock details
+ */
+ public static String getWorkspaceLockDetails(URL workspaceUrl) {
+ Path lockFile = getLockInfoFile(workspaceUrl);
+ if (lockFile == null || !Files.exists(lockFile)) {
+ return null;
+ }
+ StringBuilder lockDetails = new StringBuilder();
+ try (InputStream is = Files.newInputStream(lockFile)) {
+ Properties properties = new Properties();
+ properties.load(is);
+ String prop = properties.getProperty(USER);
+ if (prop != null) {
+ lockDetails.append(NLS.bind(WorkbenchMessages.IDEApplication_workspaceLockOwner, prop));
+ }
+ prop = properties.getProperty(HOST);
+ if (prop != null) {
+ lockDetails.append(NLS.bind(WorkbenchMessages.IDEApplication_workspaceLockHost, prop));
+ }
+ prop = properties.getProperty(DISPLAY);
+ if (prop != null) {
+ lockDetails.append(NLS.bind(WorkbenchMessages.IDEApplication_workspaceLockDisplay, prop));
+ }
+ prop = properties.getProperty(PROCESS_ID);
+ if (prop != null) {
+ lockDetails.append(NLS.bind(WorkbenchMessages.IDEApplication_workspaceLockPID, prop));
+ }
+ } catch (Exception e) {
+ WorkbenchPlugin.log("Could not read lock info file: " + lockFile, e); //$NON-NLS-1$
+ }
+ return lockDetails.toString();
+ }
+
+ /**
+ * Returns the lock file.
+ *
+ * @param workspaceUrl the URL of selected workspace
+ * @return the path to the .lock_info file within the specified
+ * workspace, or null if the workspace URL cannot be
+ * converted to a valid URI
+ */
+ public static Path getLockInfoFile(URL workspaceUrl) {
+ Path lockFile = Path.of(".metadata", ".lock_info"); //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ return Path.of(URIUtil.toURI(workspaceUrl)).resolve(lockFile);
+ } catch (URISyntaxException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Opens an error dialog indicating that the selected workspace is locked by
+ * another Eclipse instance.
+ * + * This method works in both early startup (before the Workbench is created) and + * in normal runtime (after Workbench windows exist). + *
+ * + * @param shell the parent {@link Shell} for the dialog, or + * {@code null} if no workbench window is available + * @param workspacePath the absolute path of the workspace that could not + * be locked + * @param workspaceLockOwner a formatted description of the existing lock owner + */ + public static void showWorkspaceLockedDialog(Shell shell, String workspacePath, String workspaceLockOwner) { + String lockMessage = NLS.bind(WorkbenchMessages.IDEApplication_workspaceCannotLockMessage2, workspacePath); + String wsLockedError = lockMessage + System.lineSeparator() + System.lineSeparator() + + NLS.bind(WorkbenchMessages.IDEApplication_workspaceLockMessage, workspaceLockOwner); + + MessageDialog.openError(shell, + WorkbenchMessages.IDEApplication_workspaceCannotLockTitle, wsLockedError); + } + +} diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties index 3988f2dba815..0200f6f4873a 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/messages.properties @@ -1055,3 +1055,14 @@ Workbench_zoomChangedTitle=Zoom Changed Workbench_zoomChangedMessage=Restart for the zoom changes to take full effect? Workbench_RestartButton=&Restart Workbench_DontRestartButton=&Don't restart + +# Workspace lock messages +IDEApplication_workspaceLockOwner=User:\t\t{0}\n +IDEApplication_workspaceLockHost=Host:\t\t{0}\n +IDEApplication_workspaceLockDisplay=Display:\t\t{0}\n +IDEApplication_workspaceLockPID=Process ID:\t{0}\n +IDEApplication_workspaceLockMessage=Workspace lock is currently held by:\n{0} +IDEApplication_workspaceCannotLockMessage2=Could not switch to the selected workspace ''{0}'' because it is currently in use by another Eclipse instance. +IDEApplication_workspaceCannotLockTitle=Workspace Cannot Be Locked + +OpenWorkspaceAction_invalidWorkspacePath=The selected workspace location ''{0}'' is not valid. diff --git a/bundles/org.eclipse.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui/META-INF/MANIFEST.MF index 38046f50c9e4..58e479e7a4b5 100644 --- a/bundles/org.eclipse.ui/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.ui/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %Plugin.name Bundle-SymbolicName: org.eclipse.ui; singleton:=true -Bundle-Version: 3.208.100.qualifier +Bundle-Version: 3.209.0.qualifier Bundle-Activator: org.eclipse.ui.internal.UIPlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %Plugin.providerName @@ -11,7 +11,7 @@ Export-Package: org.eclipse.ui.internal;x-friends:="org.eclipse.ui.workbench.tex Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.29.0,4.0.0)", org.eclipse.swt;bundle-version="[3.133.0,4.0.0)";visibility:=reexport, org.eclipse.jface;bundle-version="[3.34.0,4.0.0)";visibility:=reexport, - org.eclipse.ui.workbench;bundle-version="[3.130.0,4.0.0)";visibility:=reexport, + org.eclipse.ui.workbench;bundle-version="[3.138.100,4.0.0)";visibility:=reexport, org.eclipse.core.expressions;bundle-version="[3.4.0,4.0.0)" Bundle-RequiredExecutionEnvironment: JavaSE-21 Automatic-Module-Name: org.eclipse.ui