diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceDialog.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceDialog.java index 0c06c773625..1d3e7619160 100644 --- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceDialog.java +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/ChooseWorkspaceDialog.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2019 IBM Corporation and others. + * Copyright (c) 2004, 2026 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -16,6 +16,8 @@ package org.eclipse.ui.internal.ide; import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.InvalidPathException; @@ -25,9 +27,11 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Properties; import java.util.Set; import java.util.function.Function; import java.util.regex.Pattern; @@ -38,7 +42,9 @@ import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.JFaceColors; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.util.Geometry; @@ -81,6 +87,10 @@ public class ChooseWorkspaceDialog extends TitleAreaDialog { private static final String TILDE = "~"; //$NON-NLS-1$ + private static final String EMPTY = ""; //$NON-NLS-1$ + + private static final String RECENT_WORKSPACES = "RECENT_WORKSPACES"; //$NON-NLS-1$ + private static final String OPEN_FOLDER_EMOJI = new String( new byte[] { (byte) 0xF0, (byte) 0x9F, (byte) 0x93, (byte) 0x82 }, StandardCharsets.UTF_8); @@ -100,7 +110,6 @@ public class ChooseWorkspaceDialog extends TitleAreaDialog { private Button defaultButton; - /** * Create a modal dialog on the argument shell, using and updating the * argument data object. @@ -185,19 +194,13 @@ protected Control createDialogArea(Composite parent) { getTitleImageLabel().setVisible(false); } - // Should only create the Recent Workspaces Composite if Recent - // workspaces exist - boolean createRecentWorkspacesComposite = false; - if (launchData.getRecentWorkspaces()[0] != null) { - createRecentWorkspacesComposite = true; - } createWorkspaceBrowseRow(composite); if (!suppressAskAgain) { createShowDialogButton(composite); } - if (createRecentWorkspacesComposite) { - createRecentWorkspacesComposite(composite); - } + + // Create Recent Workspaces Composite always. + createRecentWorkspacesComposite(composite); Dialog.applyDialogFont(composite); return composite; @@ -205,6 +208,14 @@ protected Control createDialogArea(Composite parent) { @Override protected void createButtonsForButtonBar(Composite parent) { + // create "Import..." button first followed by Launch, Cancel + Button importButton = createButton(parent, IDialogConstants.CLIENT_ID + 1, + IDEWorkbenchMessages.ChooseWorkspaceDialog_importLabel, false); + importButton.setToolTipText(IDEWorkbenchMessages.ChooseWorkspaceDialog_importTooltip); + importButton.addListener(SWT.Selection, e -> { + showImportWorkspacesDialog(); + }); + // create OK and Cancel buttons by default createButton(parent, IDialogConstants.OK_ID, IDEWorkbenchMessages.ChooseWorkspaceDialog_launchLabel, true); createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); @@ -273,14 +284,13 @@ private void removeWorkspaceFromLauncher(String workspace, Combo combo) { recentWorkpaces.remove(workspace); launchData.setRecentWorkspaces(recentWorkpaces.toArray(new String[0])); launchData.writePersistedData(); - // Remove Workspace Composite - recentWorkspacesLinks.get(workspace).dispose(); + + // Remove Workspace link recentWorkspacesLinks.remove(workspace); - if (recentWorkspacesLinks.isEmpty()) { - recentWorkspacesForm.dispose(); - } - getShell().layout(); - initializeBounds(); + + // Refresh Recent Workspaces section + refreshRecentWorkspacesComposite(); + // Remove Workspace from combobox combo.remove(workspace); if (combo.getText().equals(workspace) || combo.getText().isEmpty()) { @@ -304,9 +314,9 @@ protected void cancelPressed() { } /** - * The Recent Workspaces area of the dialog is only shown if Recent - * Workspaces are defined. It provides a faster way to launch a specific - * Workspace + * Creates the Recent Workspaces section in the launcher dialog. Displays + * previously used workspaces and provides options to select, remove, and import + * workspaces. */ private void createRecentWorkspacesComposite(final Composite composite) { recentWorkspacesForm = new Composite(composite, SWT.NONE); @@ -364,7 +374,17 @@ private void createRecentWorkspacesComposite(final Composite composite) { toggle.addListener(SWT.MouseDown, toggleListener); label.addListener(SWT.MouseDown, toggleListener); - List recentWorkspaces = getRecentWorkspaces(); + List recentWorkspaces = filterDuplicatedPaths(launchData.getRecentWorkspaces()); + + // Check if recent workspaces list is empty + if (recentWorkspaces.isEmpty()) { + Label emptyLabel = new Label(panel, SWT.WRAP); + emptyLabel.setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_noRecentWorkspaceFound); + } else { + Label moreLabel = new Label(panel, SWT.WRAP); + moreLabel.setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_addMoreRecentWorkspaces); + } + recentWorkspacesLinks = new HashMap<>(recentWorkspaces.size()); Map uniqueWorkspaceNames = createUniqueWorkspaceNameMap(); @@ -402,6 +422,227 @@ public void widgetSelected(SelectionEvent e) { } } + /** + * Opens a dialog to import workspaces from a previous Eclipse installation. + */ + private void showImportWorkspacesDialog() { + DirectoryDialog dialog = new DirectoryDialog(getShell()); + dialog.setText(IDEWorkbenchMessages.ChooseWorkspaceDialog_importPreviousInstallationWindowTitle); + dialog.setMessage(IDEWorkbenchMessages.ChooseWorkspaceDialog_importPreviousInstallationWindowMessage); + + String selectedDir = dialog.open(); + if (selectedDir == null) { + return; + } + + // 1. Detect workspaces + List detected = importWorkspaces(selectedDir); + if (detected.isEmpty()) { + MessageDialog.openWarning(getShell(), IDEWorkbenchMessages.ChooseWorkspaceDialog_noWorkspacesFoundTitle, + IDEWorkbenchMessages.ChooseWorkspaceDialog_noWorkspacesFoundMessage); + return; + } + + // 2. Remove already imported workspaces + List existing = filterDuplicatedPaths(launchData.getRecentWorkspaces()); + List filtered = new ArrayList<>(); + + for (String ws : detected) { + if (!existing.contains(ws)) { + filtered.add(ws); + } + } + + // 3. All workspaces already imported + if (filtered.isEmpty()) { + MessageDialog.openInformation(getShell(), IDEWorkbenchMessages.ChooseWorkspaceDialog_noNewWorkspacesTitle, + IDEWorkbenchMessages.ChooseWorkspaceDialog_noNewWorkspacesMessage); + return; + } + + // 4. Open selection dialog + WorkspaceImportDialog selectionDialog = new WorkspaceImportDialog(getShell(), filtered, selectedDir, this, + existing); + + if (selectionDialog.open() != Window.OK) { + return; + } + + List selected = selectionDialog.getSelected(); + if (selected == null || selected.isEmpty()) { + MessageDialog.openInformation(getShell(), IDEWorkbenchMessages.ChooseWorkspaceDialog_nothingSelectedTitle, + IDEWorkbenchMessages.ChooseWorkspaceDialog_nothingSelectedMessage); + return; + } + + // 5. Merge + mergeSelectedWorkspaces(selected); + } + + /** + * Merges selected workspaces with existing recent workspaces, removes + * duplicates, persists the updated list, and refreshes the recent workspaces + * UI. + * + * @param selected the workspaces selected for import + */ + private void mergeSelectedWorkspaces(List selected) { + if (selected == null || selected.isEmpty()) { + return; + } + + Set merged = new LinkedHashSet<>(); + // 1. Existing workspaces + String[] existing = launchData.getRecentWorkspaces(); + + if (existing != null) { + for (String ws : existing) { + if (ws != null && new File(ws).exists()) { + merged.add(ws); + } + } + } + + // 2. Add selected + for (String ws : selected) { + if (ws != null && new File(ws).exists()) { + merged.add(ws); + } + } + + // 3. Final list + List result = new ArrayList<>(merged); + // 4. Persist + launchData.setRecentWorkspaces(result.toArray(new String[0])); + saveRecentWorkspacesToPreferences(result); + refreshRecentWorkspacesComposite(); + + MessageDialog.openInformation(getShell(), "Workspaces Updated", //$NON-NLS-1$ + "Imported " + selected.size() + " workspace(s)."); //$NON-NLS-1$ //$NON-NLS-2$ + } + + private List importWorkspaces(File directory) { + // capture return value + List result = importWorkspacesFromEclipseInstallation(directory.getAbsolutePath()); + return result != null ? result : Collections.emptyList(); + } + + public List importWorkspaces(String path) { + return importWorkspaces(new File(path)); + } + + /** + * Saves the recent workspace list to the preference store. + * + * @param workspaces the workspaces to persist + */ + private void saveRecentWorkspacesToPreferences(List workspaces) { + IPreferenceStore store = IDEWorkbenchPlugin.getDefault().getPreferenceStore(); + + if (workspaces == null || workspaces.isEmpty()) { + store.setValue(RECENT_WORKSPACES, EMPTY); + return; + } + + try { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < workspaces.size(); i++) { + String ws = workspaces.get(i); + if (ws == null) { + continue; + } + if (i > 0) { + sb.append("\n"); //$NON-NLS-1$ + } + sb.append(ws); + } + + if (Platform.getInstanceLocation().isSet()) { + store.setValue(RECENT_WORKSPACES, sb.toString()); + } +// else { +// MessageDialog.openInformation(getShell(), "saveRecentWorkspacesToPreferences", //$NON-NLS-1$ +// "Instance location not set yet. Skipping preference save."); //$NON-NLS-1$ +// } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Imports recent workspaces from a previous Eclipse installation by reading the + * Eclipse preference file. + * + * @param eclipseInstallPath the Eclipse installation directory + * @return the list of detected workspace paths + */ + private List importWorkspacesFromEclipseInstallation(String eclipseInstallPath) { + List workspaces = new ArrayList<>(); + + File recentWorkspacesFile = new File(new File(new File(eclipseInstallPath, "configuration"), ".settings"), //$NON-NLS-1$ //$NON-NLS-2$ + "org.eclipse.ui.ide.prefs"); //$NON-NLS-1$ + + if (!recentWorkspacesFile.exists()) { + File alternativePrefs = new File(eclipseInstallPath, + ".metadata/.plugins/org.eclipse.core.runtime/.settings/org.eclipse.ui.ide.prefs"); //$NON-NLS-1$ + if (!alternativePrefs.exists()) { + return workspaces; + } + recentWorkspacesFile = alternativePrefs; + } + + try { + Properties props = new Properties(); + try (FileInputStream fis = new FileInputStream(recentWorkspacesFile)) { + props.load(fis); + } + + String recentWorkspacesValue = props.getProperty("RECENT_WORKSPACES"); //$NON-NLS-1$ + if (recentWorkspacesValue == null || recentWorkspacesValue.isEmpty()) { + return workspaces; + } + + for (String path : recentWorkspacesValue.split("\\n")) { //$NON-NLS-1$ + String trimmedPath = path.trim(); + if (!trimmedPath.isEmpty() && new File(trimmedPath).exists()) { + workspaces.add(trimmedPath); + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return workspaces; + } + + /** + * Refreshes the recent workspaces UI after workspace import and updates the + * dialog layout and size. + */ + private void refreshRecentWorkspacesComposite() { + if (recentWorkspacesForm == null || recentWorkspacesForm.isDisposed()) { + return; + } + Composite parent = recentWorkspacesForm.getParent(); + if (parent == null || parent.isDisposed()) { + return; + } + + recentWorkspacesForm.dispose(); + createRecentWorkspacesComposite(parent); + parent.layout(true, true); + + Shell shell = parent.getShell(); + if (shell != null && !shell.isDisposed()) { + shell.layout(true, true); + shell.redraw(); + shell.update(); + + Point size = getInitialSize(); + shell.setBounds(getConstrainedShellBounds( + new Rectangle(shell.getLocation().x, shell.getLocation().y, size.x, size.y))); + } + } + /** * Creates a map with unique WorkspaceNames for the * RecentWorkspacesComposite. The values are full absolute paths of recently @@ -510,7 +751,7 @@ protected String getUnexpectedPathHint() { return NLS.bind(IDEWorkbenchMessages.ChooseWorkspaceDialog_NotWriteablePathWarning, normalisedPath); } } - return ""; //$NON-NLS-1$ + return EMPTY; } /** the returned value may be wrong **/ @@ -751,8 +992,7 @@ protected boolean isResizable() { } private List getRecentWorkspaces() { - String[] workspaces = launchData.getRecentWorkspaces(); - return filterDuplicatedPaths(workspaces); + return filterDuplicatedPaths(launchData.getRecentWorkspaces()); } /** @@ -764,6 +1004,10 @@ private List getRecentWorkspaces() { * @return The set of paths without duplicates. */ public static List filterDuplicatedPaths(String[] paths) { + if (paths == null || paths.length == 0) { + return Collections.emptyList(); + } + Set normalizedPaths = new HashSet<>(); List recentWorkspaces = new ArrayList<>(); for (String workspace : paths) { @@ -773,8 +1017,7 @@ public static List filterDuplicatedPaths(String[] paths) { if (workspace.startsWith(File.separator)) { normalizedPath = File.separator + normalizedPath; } - boolean nonDuplicate = normalizedPaths.add(normalizedPath); - if (nonDuplicate) { + if (normalizedPaths.add(normalizedPath)) { recentWorkspaces.add(workspace); } } 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 09eb0bc9531..ba1141dde6d 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 @@ -1014,10 +1014,22 @@ public class IDEWorkbenchMessages extends NLS { public static String ChooseWorkspaceDialog_workspaceEntryLabel; public static String ChooseWorkspaceDialog_browseLabel; public static String ChooseWorkspaceDialog_browseTooltip; + public static String ChooseWorkspaceDialog_importLabel; + public static String ChooseWorkspaceDialog_importTooltip; public static String ChooseWorkspaceDialog_launchLabel; + public static String ChooseWorkspaceDialog_importPreviousInstallationWindowTitle; + public static String ChooseWorkspaceDialog_importPreviousInstallationWindowMessage; + public static String ChooseWorkspaceDialog_noWorkspacesFoundTitle; + public static String ChooseWorkspaceDialog_noWorkspacesFoundMessage; + public static String ChooseWorkspaceDialog_noNewWorkspacesTitle; + public static String ChooseWorkspaceDialog_noNewWorkspacesMessage; + public static String ChooseWorkspaceDialog_nothingSelectedTitle; + public static String ChooseWorkspaceDialog_nothingSelectedMessage; public static String ChooseWorkspaceDialog_directoryBrowserTitle; public static String ChooseWorkspaceDialog_directoryBrowserMessage; public static String ChooseWorkspaceDialog_removeWorkspaceSelection; + public static String ChooseWorkspaceDialog_noRecentWorkspaceFound; + public static String ChooseWorkspaceDialog_addMoreRecentWorkspaces; public static String ChooseWorkspaceDialog_recentWorkspaces; public static String ChooseWorkspaceDialog_ResolvedAbsolutePath; @@ -1027,6 +1039,25 @@ public class IDEWorkbenchMessages extends NLS { public static String ChooseWorkspaceDialog_NotWriteablePathWarning; public static String ChooseWorkspaceDialog_useDefaultMessage; + public static String WorkspaceImportDialog_dialogName; + public static String WorkspaceImportDialog_dialogTitle; + public static String WorkspaceImportDialog_dialogMessage; + public static String WorkspaceImportDialog_installationPath; + public static String WorkspaceImportDialog_typeFilterText; + public static String WorkspaceImportDialog_browseLabel; + public static String WorkspaceImportDialog_browseTooltip; + public static String WorkspaceImportDialog_selectPreviousInstallationText; + public static String WorkspaceImportDialog_selectPreviousInstallationMessage; + public static String WorkspaceImportDialog_noWorkspaceFoundTitle; + public static String WorkspaceImportDialog_noWorkspaceFoundMessage; + public static String WorkspaceImportDialog_noNewWorkspacesTitle; + public static String WorkspaceImportDialog_noNewWorkspacesMessage; + public static String WorkspaceImportDialog_tableColumn1; + public static String WorkspaceImportDialog_tableColumn2; + public static String WorkspaceImportDialog_selectAllLabel; + public static String WorkspaceImportDialog_deselectAllLabel; + + public static String ChooseWorkspaceWithSettingsDialog_SettingsGroupName; public static String ChooseWorkspaceWithSettingsDialog_ProblemsTransferTitle; public static String ChooseWorkspaceWithSettingsDialog_TransferFailedMessage; diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/WorkspaceImportDialog.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/WorkspaceImportDialog.java new file mode 100644 index 00000000000..ca17d04ca66 --- /dev/null +++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/ide/WorkspaceImportDialog.java @@ -0,0 +1,380 @@ +/******************************************************************************* + * Copyright (c) 2026 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.ide; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; + +/** + * Dialog for importing workspaces from a previous Eclipse installation. + * Displays valid workspaces and allows users to select workspaces to import + * into the launcher. + */ +public class WorkspaceImportDialog extends TitleAreaDialog { + private static final String EMPTY = ""; //$NON-NLS-1$ + private List input; + private String baseInstallPath; + private CheckboxTableViewer viewer; + private List selected = new ArrayList<>(); + private List existingWorkspaces; + private Text locationText; + private ChooseWorkspaceDialog parentDialog; + + private Set checkedElements = new LinkedHashSet<>(); + + /** + * Creates a dialog for importing workspaces from a previous Eclipse + * installation. + * + * @param parentShell the parent shell + * @param input the list of valid workspaces + * @param baseInstallPath the selected Eclipse installation path + * @param parentDialog the parent workspace launcher dialog + * @param existingWorkspaces the list of already imported workspaces + */ + public WorkspaceImportDialog(Shell parentShell, List input, String baseInstallPath, + ChooseWorkspaceDialog parentDialog, List existingWorkspaces) { + super(parentShell); + this.input = input; + this.baseInstallPath = baseInstallPath; + this.parentDialog = parentDialog; + this.existingWorkspaces = existingWorkspaces; + } + + @Override + protected void configureShell(Shell shell) { + super.configureShell(shell); + shell.setText(IDEWorkbenchMessages.WorkspaceImportDialog_dialogName); + } + + @Override + public void create() { + super.create(); + setTitle(IDEWorkbenchMessages.WorkspaceImportDialog_dialogTitle); + setMessage(IDEWorkbenchMessages.WorkspaceImportDialog_dialogMessage); + } + + /** + * Creates the main dialog area and initializes the workspace import UI + * components. + */ + @Override + protected Control createDialogArea(Composite parent) { + Composite container = (Composite) super.createDialogArea(parent); + container.setLayout(new GridLayout(1, false)); + // FIX ORDER + createLocationRow(container); + createFilter(container); + createTable(container); + loadInitialInput(); + createButtons(container); + return container; + } + + /** + * Creates the installation path input row with browse support for selecting an + * application installation directory. + */ + private void createLocationRow(Composite parent) { + Composite row = new Composite(parent, SWT.NONE); + row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + row.setLayout(new GridLayout(3, false)); + + new Label(row, SWT.NONE).setText(IDEWorkbenchMessages.WorkspaceImportDialog_installationPath); + locationText = new Text(row, SWT.BORDER); + locationText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + locationText.setText(baseInstallPath != null ? baseInstallPath : EMPTY); + + Button browse = new Button(row, SWT.PUSH); + browse.setText(IDEWorkbenchMessages.WorkspaceImportDialog_browseLabel); + browse.setToolTipText(IDEWorkbenchMessages.WorkspaceImportDialog_browseTooltip); + browse.addListener(SWT.Selection, e -> { + DirectoryDialog dlg = new DirectoryDialog(parent.getShell()); + dlg.setText(IDEWorkbenchMessages.WorkspaceImportDialog_selectPreviousInstallationText); + dlg.setMessage(IDEWorkbenchMessages.WorkspaceImportDialog_selectPreviousInstallationMessage); + String selectedPath = dlg.open(); + if (selectedPath != null) { + locationText.setText(selectedPath); + // reload workspaces + reloadWorkspaces(selectedPath); + } + }); + } + + /** + * Creates the workspace filter text field and applies filtering to the + * workspace table viewer. + */ + private void createFilter(Composite parent) { + // Add ICON_CANCEL + Text filter = new Text(parent, SWT.BORDER | SWT.SEARCH | SWT.ICON_CANCEL); + filter.setMessage(IDEWorkbenchMessages.WorkspaceImportDialog_typeFilterText); + filter.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + // FILTER LOGIC + filter.addModifyListener(e -> { + String raw = filter.getText(); + if (raw.trim().isEmpty()) { + viewer.resetFilters(); + } else { + String txt = raw.toLowerCase().replace("*", EMPTY); //$NON-NLS-1$ + viewer.setFilters(new ViewerFilter[] { new ViewerFilter() { + @Override + public boolean select(Viewer v, Object p, Object el) { + String value = el.toString().toLowerCase(); + return value.contains(txt); + } + } + }); + } + viewer.refresh(); + // Restore check state after refresh + viewer.setCheckedElements(checkedElements.toArray()); + }); + + // Handle clear button click + filter.addListener(SWT.DefaultSelection, e -> { + filter.setText(EMPTY); + }); + } + + /** + * Loads and filters the initial workspace input into the table viewer and + * selects all entries by default. + */ + private void loadInitialInput() { + if (input == null) { + return; + } + + List filtered = new ArrayList<>(); + for (String ws : input) { + if (ws == null || ws.trim().isEmpty()) { + continue; + } + + if (existingWorkspaces != null && existingWorkspaces.contains(ws)) { + continue; + } + filtered.add(ws); + } + + // Set input + viewer.setInput(filtered); + + // CHECK ALL by default + checkedElements.clear(); + checkedElements.addAll(filtered); + viewer.setCheckedElements(checkedElements.toArray()); + viewer.refresh(); + } + + /** + * Creates the workspace table viewer with check-box support and initializes its + * columns and selection handling. + */ + private void createTable(Composite parent) { + viewer = CheckboxTableViewer.newCheckList(parent, + SWT.BORDER | SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL | SWT.SHADOW_IN); + + Table table = viewer.getTable(); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); + gd.minimumHeight = 250; + table.setLayoutData(gd); + + // Column 1 - workspace + TableViewerColumn col1 = new TableViewerColumn(viewer, SWT.NONE); + col1.getColumn().setText(IDEWorkbenchMessages.WorkspaceImportDialog_tableColumn1); + col1.getColumn().setWidth(200); + + col1.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return new File((String) element).getName(); + } + }); + + // Column 2 - path + TableViewerColumn col2 = new TableViewerColumn(viewer, SWT.NONE); + col2.getColumn().setText(IDEWorkbenchMessages.WorkspaceImportDialog_tableColumn2); + col2.getColumn().setWidth(400); + + col2.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return (String) element; + } + }); + + viewer.setContentProvider(ArrayContentProvider.getInstance()); + viewer.addCheckStateListener(event -> { + String element = (String) event.getElement(); + + if (event.getChecked()) { + checkedElements.add(element); + } else { + checkedElements.remove(element); + } + }); + } + + /** + * Creates the Select All and Deselect All buttons for managing workspace + * selections in the table viewer. + */ + private void createButtons(Composite parent) { + Composite bar = new Composite(parent, SWT.NONE); + bar.setLayout(new GridLayout(2, false)); + + // Select All (VISIBLE ONLY) + Button selectAll = new Button(bar, SWT.PUSH); + selectAll.setText(IDEWorkbenchMessages.WorkspaceImportDialog_selectAllLabel); + selectAll.addListener(SWT.Selection, e -> { + if (viewer == null) { + return; + } + + TableItem[] items = viewer.getTable().getItems(); + for (TableItem item : items) { + Object data = item.getData(); + if (data instanceof String) { + viewer.setChecked(data, true); + checkedElements.add((String) data); + } + } + }); + + // Deselect All (VISIBLE ONLY) + Button deselectAll = new Button(bar, SWT.PUSH); + deselectAll.setText(IDEWorkbenchMessages.WorkspaceImportDialog_deselectAllLabel); + deselectAll.addListener(SWT.Selection, e -> { + if (viewer == null) { + return; + } + + TableItem[] items = viewer.getTable().getItems(); + for (TableItem item : items) { + Object data = item.getData(); + viewer.setChecked(data, false); + checkedElements.remove(data); + } + }); + } + + @Override + protected void okPressed() { + if (viewer == null) { + super.okPressed(); + return; + } + + selected.clear(); + Object[] checked = viewer.getCheckedElements(); + for (Object o : checked) { + selected.add((String) o); + } + super.okPressed(); + } + + public List getSelected() { + return selected; + } + + /** + * Reloads and refreshes the workspace list for the selected Eclipse + * installation path. + *

+ * Displays appropriate messages when: + *

    + *
  • no workspaces are found
  • + *
  • all valid workspaces are already imported
  • + *
+ * Updates the table viewer with newly detected workspaces and restores checked + * state. + * + * @param newPath the Eclipse installation path to scan for workspaces + */ + private void reloadWorkspaces(String newPath) { + if (parentDialog == null) { + return; + } + + List rawList = parentDialog.importWorkspaces(newPath); + // No prefs file or no valid workspaces + if (rawList.isEmpty()) { + MessageDialog.openWarning(getShell(), IDEWorkbenchMessages.WorkspaceImportDialog_noWorkspaceFoundTitle, + IDEWorkbenchMessages.WorkspaceImportDialog_noWorkspaceFoundMessage); + viewer.setInput(Collections.emptyList()); + viewer.refresh(); + return; + } + + List filtered = new ArrayList<>(); + for (String ws : rawList) { + if (ws == null || ws.trim().isEmpty()) { + continue; + } + + if (existingWorkspaces != null && existingWorkspaces.contains(ws)) { + continue; + } + filtered.add(ws); + } + + // All valid workspaces are already imported + if (filtered.isEmpty()) { + MessageDialog.openInformation(getShell(), IDEWorkbenchMessages.WorkspaceImportDialog_noNewWorkspacesTitle, + IDEWorkbenchMessages.WorkspaceImportDialog_noNewWorkspacesMessage); + viewer.setInput(Collections.emptyList()); + checkedElements.clear(); + viewer.refresh(); + return; + } + + viewer.setInput(filtered); + // ALWAYS check all after browse + checkedElements.clear(); + checkedElements.addAll(filtered); + viewer.setCheckedElements(checkedElements.toArray()); + viewer.refresh(); + } +} \ No newline at end of file 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 8b887cae9eb..4f4d47c2f9b 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 @@ -1038,17 +1038,47 @@ ChooseWorkspaceDialog_defaultProductName = This product ChooseWorkspaceDialog_workspaceEntryLabel=&Workspace: ChooseWorkspaceDialog_browseLabel=&Browse... ChooseWorkspaceDialog_browseTooltip=Open file dialog to choose a directory as workspace to store preferences and development artifacts. +ChooseWorkspaceDialog_importLabel=&Import... +ChooseWorkspaceDialog_importTooltip=Import workspaces from existing application installation. ChooseWorkspaceDialog_launchLabel=&Launch +ChooseWorkspaceDialog_importPreviousInstallationWindowTitle=Select Previous Application Installation +ChooseWorkspaceDialog_importPreviousInstallationWindowMessage=Select the directory of a previous application installation. +ChooseWorkspaceDialog_noWorkspacesFoundTitle=No Workspaces Found +ChooseWorkspaceDialog_noWorkspacesFoundMessage=No workspaces found in selected installation path. +ChooseWorkspaceDialog_noNewWorkspacesTitle=No New Workspaces +ChooseWorkspaceDialog_noNewWorkspacesMessage=All valid workspaces are already imported. +ChooseWorkspaceDialog_nothingSelectedTitle=Nothing Selected +ChooseWorkspaceDialog_nothingSelectedMessage=No workspaces selected to import. ChooseWorkspaceDialog_directoryBrowserTitle=Select Workspace Directory ChooseWorkspaceDialog_directoryBrowserMessage=Select the workspace directory to use. ChooseWorkspaceDialog_removeWorkspaceSelection=Remove from launcher selection ChooseWorkspaceDialog_recentWorkspaces=&Recent Workspaces +ChooseWorkspaceDialog_noRecentWorkspaceFound=No recent workspaces found. You can import from previous installation or create a new workspace. +ChooseWorkspaceDialog_addMoreRecentWorkspaces=Add recent workspaces from another application installation. ChooseWorkspaceDialog_ResolvedAbsolutePath=Full path: {0} ChooseWorkspaceDialog_TildeNonExpandedWarning=\u26A0\uFE0F '~' is not expanded, full path: {0} ChooseWorkspaceDialog_InvalidPathWarning=\u26A0\uFE0F The path is invalid on this system: {0} ChooseWorkspaceDialog_NotWriteablePathWarning=\u26A0\uFE0F The path may not be writable by the current user: {0} ChooseWorkspaceDialog_useDefaultMessage=&Use this as the default and do not ask again +WorkspaceImportDialog_dialogName=Import Workspaces +WorkspaceImportDialog_dialogTitle=Select existing application installation +WorkspaceImportDialog_dialogMessage=Select workspaces to import +WorkspaceImportDialog_installationPath=Previous application installation: +WorkspaceImportDialog_typeFilterText=type filter text +WorkspaceImportDialog_browseLabel=&Browse... +WorkspaceImportDialog_browseTooltip=Open file dialog to choose previous application installation +WorkspaceImportDialog_selectPreviousInstallationText=Select An Application Installation +WorkspaceImportDialog_selectPreviousInstallationMessage=Select an application installation. +WorkspaceImportDialog_noWorkspaceFoundTitle=No Workspaces Found +WorkspaceImportDialog_noWorkspaceFoundMessage=No workspaces found in the selected installation path. +WorkspaceImportDialog_noNewWorkspacesTitle=No New Workspaces +WorkspaceImportDialog_noNewWorkspacesMessage=All valid workspaces are already imported. +WorkspaceImportDialog_tableColumn1=Workspace +WorkspaceImportDialog_tableColumn2=Path +WorkspaceImportDialog_selectAllLabel=&Select All +WorkspaceImportDialog_deselectAllLabel=&Deselect All + ChooseWorkspaceWithSettingsDialog_SettingsGroupName=&Copy Settings ChooseWorkspaceWithSettingsDialog_ProblemsTransferTitle=Problems Transferring Settings ChooseWorkspaceWithSettingsDialog_TransferFailedMessage=Settings transfer failed @@ -1056,8 +1086,6 @@ ChooseWorkspaceWithSettingsDialog_SaveSettingsFailed=Could not save settings ChooseWorkspaceWithSettingsDialog_ClassCreationFailed= Could not instantiate {0} ChooseWorkspaceWithSettingsDialog_copySettingsDecoLabel=Target workspace exists. Existing values will be overwritten. - - IDEApplication_workspaceMandatoryTitle=Workspace is Mandatory IDEApplication_workspaceMandatoryMessage=IDEs need a valid workspace. Restart without the @none option. IDEApplication_workspaceInUseTitle=Workspace Unavailable