Bug 495007 - Do not block UI in Importer when scanning folder
This basically allows to report operation from a Job inside the usual
progress monitor of the WizardDialog.
Change-Id: I5221484c6eda5731bd39c1dd5bdb0c3a4546b3da
Signed-off-by: Mickael Istria <mistria@redhat.com>
Signed-off-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/wizard/ProgressMonitorPart.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/wizard/ProgressMonitorPart.java
index 79567e0..278b9d3 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/wizard/ProgressMonitorPart.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/wizard/ProgressMonitorPart.java
@@ -157,10 +157,12 @@
fTaskName = name;
fSubTaskName = ""; //$NON-NLS-1$
updateLabel();
- if (totalWork == IProgressMonitor.UNKNOWN || totalWork == 0) {
- fProgressIndicator.beginAnimatedTask();
- } else {
- fProgressIndicator.beginTask(totalWork);
+ if (!fProgressIndicator.isDisposed()) {
+ if (totalWork == IProgressMonitor.UNKNOWN || totalWork == 0) {
+ fProgressIndicator.beginAnimatedTask();
+ } else {
+ fProgressIndicator.beginTask(totalWork);
+ }
}
if (fToolBar != null && !fToolBar.isDisposed()) {
fToolBar.setVisible(true);
@@ -279,7 +281,9 @@
@Override
public void internalWorked(double work) {
- fProgressIndicator.worked(work);
+ if (!fProgressIndicator.isDisposed()) {
+ fProgressIndicator.worked(work);
+ }
}
@Override
@@ -333,6 +337,9 @@
* Updates the label with the current task and subtask names.
*/
protected void updateLabel() {
+ if (fLabel.isDisposed() || fLabel.isAutoDirection()) {
+ return;
+ }
if (blockedStatus == null) {
String text = taskLabel();
fLabel.setText(text);
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/DataTransferMessages.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/DataTransferMessages.java
index e3f632a..e38056f 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/DataTransferMessages.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/DataTransferMessages.java
@@ -185,6 +185,8 @@
public static String SmartImportProposals_folder;
public static String SmartImportProposals_importAs;
public static String SmartImportProposals_hideExistingProjects;
+ public static String SmartImportProposals_inspecitionCanceled;
+ public static String SmartImportProposals_errorWhileInspecting;
public static String SmartImportReport_importedProjects;
public static String SmartImportReport_importedProjectsWithCount;
@@ -202,8 +204,6 @@
public static String SmartImportJob_inspecting;
public static String SmartImportJob_importingProjectIntoWorkspace;
-
-
static {
// load message values from bundle file
NLS.initializeMessages(BUNDLE_NAME, DataTransferMessages.class);
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/DelegateProgressMonitorInUIThreadAndPreservingFocus.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/DelegateProgressMonitorInUIThreadAndPreservingFocus.java
new file mode 100644
index 0000000..afe8930
--- /dev/null
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/DelegateProgressMonitorInUIThreadAndPreservingFocus.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2016 Red Hat Inc., and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Mickael Istria (Red Hat Inc.) - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.ui.internal.wizards.datatransfer;
+
+import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.wizard.ProgressMonitorPart;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Combo;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * A progress monitor that delegates report to another one wrapping invocations
+ * of delegate methods in Dislay.asyncExec() and ensuring focus is preserved
+ * during the beginTask operation.
+ *
+ * @since 3.12
+ */
+class DelegateProgressMonitorInUIThreadAndPreservingFocus implements IProgressMonitorWithBlocking {
+ private ProgressMonitorPart delegate;
+ private Display display;
+
+ /**
+ * @param delegate
+ */
+ public DelegateProgressMonitorInUIThreadAndPreservingFocus(ProgressMonitorPart delegate) {
+ this.delegate = delegate;
+ this.display = delegate.getDisplay();
+ }
+
+ private void inUIThread(Runnable r) {
+ if (display == Display.getCurrent()) {
+ r.run();
+ } else {
+ PlatformUI.getWorkbench().getDisplay().asyncExec(r);
+ }
+ }
+
+ @Override
+ public void worked(int work) {
+ inUIThread(() -> delegate.worked(work));
+ }
+
+ @Override
+ public void subTask(String name) {
+ inUIThread(() -> delegate.subTask(name));
+ }
+
+ @Override
+ public void setTaskName(String name) {
+ inUIThread(() -> delegate.setTaskName(name));
+ }
+
+ @Override
+ public void setCanceled(boolean value) {
+ inUIThread(() -> delegate.setCanceled(value));
+ }
+
+ @Override
+ public boolean isCanceled() {
+ return delegate.isCanceled();
+ }
+
+ @Override
+ public void internalWorked(double work) {
+ inUIThread(() -> delegate.internalWorked(work));
+ }
+
+ @Override
+ public void done() {
+ inUIThread(() -> delegate.done());
+ }
+
+ @Override
+ public void beginTask(String name, int totalWork) {
+ inUIThread(() -> {
+ Point initialSelection = null;
+ Control focusControl = Display.getCurrent().getFocusControl();
+ if (focusControl != null && focusControl instanceof Combo) {
+ initialSelection = ((Combo) focusControl).getSelection();
+ }
+ delegate.beginTask(name, totalWork);
+ // this is necessary because ProgressMonitorPart
+ // sets focus on Stop button
+ if (focusControl != null) {
+ focusControl.setFocus();
+ if (focusControl instanceof Combo && initialSelection != null) {
+ ((Combo) focusControl).setSelection(initialSelection);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void setBlocked(IStatus reason) {
+ inUIThread(() -> delegate.setBlocked(reason));
+ }
+
+ @Override
+ public void clearBlocked() {
+ inUIThread(() -> delegate.clearBlocked());
+ }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/SmartImportRootWizardPage.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/SmartImportRootWizardPage.java
index 4749074..04f632f 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/SmartImportRootWizardPage.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/SmartImportRootWizardPage.java
@@ -24,6 +24,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Supplier;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
@@ -32,11 +33,15 @@
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
@@ -51,6 +56,7 @@
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.wizard.IWizard;
+import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
@@ -58,26 +64,32 @@
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.ui.dialogs.WorkingSetConfigurationBlock;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
+import org.eclipse.ui.internal.progress.ProgressManager;
+import org.eclipse.ui.internal.progress.ProgressManager.JobMonitor;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.ui.wizards.datatransfer.ProjectConfigurator;
@@ -92,14 +104,10 @@
static final String IMPORTED_SOURCES = SmartImportRootWizardPage.class.getName() + ".knownSources"; //$NON-NLS-1$
+ // Root
private File selection;
- private boolean detectNestedProjects = true;
- private boolean configureProjects = true;
- private Set<IWorkingSet> workingSets;
- private ControlDecoration rootDirectoryTextDecorator;
- private WorkingSetConfigurationBlock workingSetsBlock;
-
private Combo rootDirectoryText;
+ private ControlDecoration rootDirectoryTextDecorator;
// Proposal part
private CheckboxTreeViewer tree;
private ControlDecoration proposalSelectionDecorator;
@@ -107,6 +115,45 @@
private Set<File> notAlreadyExistingProjects;
private Label selectionSummary;
protected Map<File, List<ProjectConfigurator>> potentialProjects = Collections.emptyMap();
+ // Configuration part
+ private boolean detectNestedProjects = true;
+ private boolean configureProjects = true;
+ // Working sets
+ private Set<IWorkingSet> workingSets;
+ private WorkingSetConfigurationBlock workingSetsBlock;
+ // Progress monitor
+ protected Supplier<ProgressMonitorPart> wizardProgressMonitor = new Supplier<ProgressMonitorPart>() {
+ private ProgressMonitorPart progressMonitorPart;
+ @Override
+ public ProgressMonitorPart get() {
+ if (progressMonitorPart == null) {
+ try {
+ getWizard().getContainer().run(false, true, monitor -> {
+ if (monitor instanceof ProgressMonitorPart) {
+ progressMonitorPart = (ProgressMonitorPart) monitor;
+ }
+ });
+ } catch (InvocationTargetException ite) {
+ IStatus status = new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH,
+ DataTransferMessages.SmartImportWizardPage_scanProjectsFailed, ite.getCause());
+ StatusManager.getManager().handle(status, StatusManager.LOG | StatusManager.SHOW);
+ } catch (InterruptedException operationCanceled) {
+ Thread.interrupted();
+ }
+ }
+ return progressMonitorPart;
+ }
+ };
+
+ private Job refreshProposalsJob;
+ private JobMonitor jobMonitor;
+ private DelegateProgressMonitorInUIThreadAndPreservingFocus delegateMonitor;
+ private SelectionListener cancelWorkListener = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ stopAndDisconnectCurrentWork();
+ }
+ };
private class FolderForProjectsLabelProvider extends CellLabelProvider implements IColorProvider {
public String getText(Object o) {
@@ -225,11 +272,9 @@
createInputSelectionOptions(res);
-
- Composite proposalParent = new Composite(res, SWT.NONE);
- proposalParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));
- proposalParent.setLayout(new FillLayout());
- createProposalsGroup(proposalParent);
+ GridData proposalsGroupLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1);
+ proposalsGroupLayoutData.verticalIndent = 12;
+ createProposalsGroup(res).setLayoutData(proposalsGroupLayoutData);
createConfigurationOptions(res);
@@ -283,6 +328,7 @@
expandSelectedArchive();
}
}
+ validatePage();
refreshProposals();
}
@@ -423,7 +469,7 @@
/**
* @param res
*/
- private void createProposalsGroup(Composite parent) {
+ private Composite createProposalsGroup(Composite parent) {
Composite res = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(res);
PatternFilter patternFilter = new PatternFilter();
@@ -568,6 +614,8 @@
}
});
tree.setInput(Collections.emptyMap());
+
+ return res;
}
protected void validatePage() {
@@ -587,7 +635,6 @@
setErrorMessage(this.rootDirectoryTextDecorator.getDescriptionText());
} else {
this.rootDirectoryTextDecorator.hide();
- setErrorMessage(null);
}
setPageComplete(isPageComplete());
}
@@ -619,6 +666,7 @@
public void setInitialImportRoot(File directoryOrArchive) {
this.selection = directoryOrArchive;
this.rootDirectoryText.setText(directoryOrArchive.getAbsolutePath());
+ refreshProposals();
}
/**
@@ -686,49 +734,135 @@
}
private void refreshProposals() {
- try {
- if (sourceIsValid()) {
- Point initialSelection = rootDirectoryText.getSelection();
- getContainer().run(true, true, new IRunnableWithProgress() {
- @Override
- public void run(IProgressMonitor monitor) {
- SmartImportRootWizardPage.this.potentialProjects = getWizard().getImportJob()
- .getImportProposals(monitor);
- if (!potentialProjects.containsKey(getWizard().getImportJob().getRoot())) {
- potentialProjects.put(getWizard().getImportJob().getRoot(), Collections.emptyList());
- }
-
- SmartImportRootWizardPage.this.notAlreadyExistingProjects = new HashSet<>(
- potentialProjects.keySet());
- SmartImportRootWizardPage.this.alreadyExistingProjects = new HashSet<>();
- for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
- IPath location = project.getLocation();
- if (location == null) {
- continue;
- }
- SmartImportRootWizardPage.this.notAlreadyExistingProjects.remove(location.toFile());
- SmartImportRootWizardPage.this.alreadyExistingProjects.add(location.toFile());
- }
+ stopAndDisconnectCurrentWork();
+ SmartImportRootWizardPage.this.potentialProjects = Collections.emptyMap();
+ SmartImportRootWizardPage.this.notAlreadyExistingProjects = Collections.emptySet();
+ SmartImportRootWizardPage.this.alreadyExistingProjects = Collections.emptySet();
+ proposalsUpdated();
+ // compute new state
+ if (sourceIsValid()) {
+ tree.getControl().setEnabled(false);
+ TreeItem computingItem = new TreeItem(tree.getTree(), SWT.DEFAULT);
+ computingItem
+ .setText(NLS.bind(DataTransferMessages.SmartImportJob_inspecting, selection.getAbsolutePath()));
+ final SmartImportJob importJob = getWizard().getImportJob();
+ refreshProposalsJob = new Job(
+ NLS.bind(DataTransferMessages.SmartImportJob_inspecting, selection.getAbsolutePath())) {
+ @Override
+ public IStatus run(IProgressMonitor monitor) {
+ SmartImportRootWizardPage.this.potentialProjects = importJob.getImportProposals(monitor);
+ if (monitor.isCanceled()) {
+ return Status.CANCEL_STATUS;
}
- });
- // restore selection as getContainer().run(...) looses it
- rootDirectoryText.setSelection(initialSelection);
- } else {
- SmartImportRootWizardPage.this.potentialProjects = Collections.emptyMap();
- SmartImportRootWizardPage.this.notAlreadyExistingProjects = Collections.emptySet();
- SmartImportRootWizardPage.this.alreadyExistingProjects = Collections.emptySet();
+ if (!potentialProjects.containsKey(importJob.getRoot())) {
+ potentialProjects.put(importJob.getRoot(), Collections.emptyList());
+ }
+
+ SmartImportRootWizardPage.this.notAlreadyExistingProjects = new HashSet<>(
+ potentialProjects.keySet());
+ SmartImportRootWizardPage.this.alreadyExistingProjects = new HashSet<>();
+ for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
+ IPath location = project.getLocation();
+ if (location == null) {
+ continue;
+ }
+ SmartImportRootWizardPage.this.notAlreadyExistingProjects.remove(location.toFile());
+ SmartImportRootWizardPage.this.alreadyExistingProjects.add(location.toFile());
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ Control previousFocusControl = tree.getControl().getDisplay().getFocusControl();
+ if (previousFocusControl == null) {
+ previousFocusControl = rootDirectoryText;
}
- tree.setInput(potentialProjects);
- tree.setCheckedElements(this.notAlreadyExistingProjects.toArray());
- } catch (InvocationTargetException ite) {
- this.selection = null;
- IStatus status = new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, DataTransferMessages.SmartImportWizardPage_scanProjectsFailed,
- ite.getCause());
- StatusManager.getManager().handle(status, StatusManager.LOG | StatusManager.SHOW);
- } catch (InterruptedException operationCanceled) {
+ Point initialSelection = rootDirectoryText.getSelection();
+ wizardProgressMonitor.get().attachToCancelComponent(null);
+ wizardProgressMonitor.get().setVisible(true);
+ // restore focus and selection because IWizardDialog.run(...) and
+ // attachToCancelComponent take them
+ previousFocusControl.setFocus();
+ rootDirectoryText.setSelection(initialSelection);
+ ToolItem stopButton = getStopButton(wizardProgressMonitor.get());
+ stopButton.addSelectionListener(this.cancelWorkListener);
+ jobMonitor = ProgressManager.getInstance().progressFor(refreshProposalsJob);
+ delegateMonitor = new DelegateProgressMonitorInUIThreadAndPreservingFocus(wizardProgressMonitor.get());
+ jobMonitor.addProgressListener(delegateMonitor);
+ refreshProposalsJob.setPriority(Job.INTERACTIVE);
+ refreshProposalsJob.setUser(true);
+ refreshProposalsJob.addJobChangeListener(new JobChangeAdapter() {
+ @Override
+ public void done(IJobChangeEvent event) {
+ Control control = tree.getControl();
+ if (!control.isDisposed()) {
+ control.getDisplay().asyncExec(() -> {
+ IStatus result = event.getResult();
+ if (!control.isDisposed() && result.isOK()) {
+ computingItem.dispose();
+ if (sourceIsValid() && getWizard().getImportJob() == importJob) {
+ proposalsUpdated();
+ }
+ tree.getTree().setEnabled(true);
+ } else if (result.getCode() == IStatus.CANCEL) {
+ computingItem.setText(DataTransferMessages.SmartImportProposals_inspecitionCanceled);
+ } else if (result.getCode() == IStatus.ERROR) {
+ computingItem.setText(
+ NLS.bind(DataTransferMessages.SmartImportProposals_errorWhileInspecting,
+ result.getMessage()));
+ }
+ if (!wizardProgressMonitor.get().isDisposed()
+ && refreshProposalsJob.getState() == Job.NONE) {
+ wizardProgressMonitor.get().setVisible(false);
+ }
+ });
+ }
+ }
+ });
+ refreshProposalsJob.schedule(0);
}
+ }
+
+ private static ToolItem getStopButton(ProgressMonitorPart part) {
+ for (Control control : part.getChildren()) {
+ if (control instanceof ToolBar) {
+ for (ToolItem item : ((ToolBar) control).getItems()) {
+ if (item.getToolTipText().equals(JFaceResources.getString("ProgressMonitorPart.cancelToolTip"))) { //$NON-NLS-1$ ))
+ return item;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private void stopAndDisconnectCurrentWork() {
+ if (refreshProposalsJob != null) {
+ refreshProposalsJob.cancel();
+ }
+ }
+
+ private void proposalsUpdated() {
+ tree.setInput(potentialProjects);
+ tree.setCheckedElements(this.notAlreadyExistingProjects.toArray());
proposalsSelectionChanged();
- SmartImportRootWizardPage.this.validatePage();
+ validatePage();
+ }
+
+ @Override
+ public void dispose() {
+ stopAndDisconnectCurrentWork();
+ getStopButton(wizardProgressMonitor.get()).removeSelectionListener(this.cancelWorkListener);
+ super.dispose();
+ }
+
+ /**
+ * Only made public for testing purpose
+ *
+ * @return the Wizard progress monitor
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ public ProgressMonitorPart getWizardProgressMonitor() {
+ return this.wizardProgressMonitor.get();
}
}
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/SmartImportWizard.java b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/SmartImportWizard.java
index 905ac94..31a2b0b 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/SmartImportWizard.java
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/SmartImportWizard.java
@@ -33,7 +33,6 @@
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.IImportWizard;
@@ -329,12 +328,4 @@
&& job.isConfigureProjects() == page.isConfigureProjects();
}
- @Override
- public IWizardPage getNextPage(IWizardPage page) {
- if (page == this.projectRootPage && !this.projectRootPage.isDetectNestedProject()) {
- return null;
- }
- return super.getNextPage(page);
- }
-
}
\ No newline at end of file
diff --git a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/messages.properties b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/messages.properties
index 7d41e33..6984119 100644
--- a/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/messages.properties
+++ b/bundles/org.eclipse.ui.ide/src/org/eclipse/ui/internal/wizards/datatransfer/messages.properties
@@ -191,6 +191,8 @@
SmartImportProposals_folder=Folder
SmartImportProposals_importAs=Import as
SmartImportProposals_hideExistingProjects=&Hide already open projects
+SmartImportProposals_inspecitionCanceled=Inspeciton canceled
+SmartImportProposals_errorWhileInspecting=Error while inspecting: {0}
SmartImportJob_detectAndConfigureProjects=Detecting and configuring nested projects
SmartImportJob_configuringSelectedDirectories=Configuring selected directories
SmartImportJob_configuring=Configuring project {0}
diff --git a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressManager.java b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressManager.java
index be27427..94d6e18 100644
--- a/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressManager.java
+++ b/bundles/org.eclipse.ui.workbench/Eclipse UI/org/eclipse/ui/internal/progress/ProgressManager.java
@@ -26,7 +26,9 @@
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.RejectedExecutionException;
@@ -35,6 +37,7 @@
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
+import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IProgressMonitorWithBlocking;
import org.eclipse.core.runtime.IStatus;
@@ -206,10 +209,10 @@
* The JobMonitor is the inner class that handles the IProgressMonitor
* integration with the ProgressMonitor.
*/
- class JobMonitor implements IProgressMonitorWithBlocking {
+ public class JobMonitor implements IProgressMonitorWithBlocking {
Job job;
String currentTaskName;
- IProgressMonitorWithBlocking listener;
+ Set<IProgressMonitorWithBlocking> monitors = Collections.emptySet();
/**
* Creates a monitor on the supplied job.
@@ -225,25 +228,32 @@
*
* @param monitor
*/
- void addProgressListener(IProgressMonitorWithBlocking monitor) {
- listener = monitor;
+ public void addProgressListener(IProgressMonitorWithBlocking monitor) {
+ Assert.isNotNull(monitor);
+ Set<IProgressMonitorWithBlocking> newSet = new LinkedHashSet<>(monitors);
+ newSet.add(monitor);
+ this.monitors = Collections.unmodifiableSet(newSet);
JobInfo info = getJobInfo(job);
TaskInfo currentTask = info.getTaskInfo();
if (currentTask != null) {
- listener.beginTask(currentTaskName, currentTask.totalWork);
- listener.internalWorked(currentTask.preWork);
+ monitor.beginTask(currentTaskName, currentTask.totalWork);
+ monitor.internalWorked(currentTask.preWork);
}
}
+ public void removeProgresListener(IProgressMonitorWithBlocking monitor) {
+ Set<IProgressMonitorWithBlocking> newSet = new LinkedHashSet<>(monitors);
+ newSet.remove(monitor);
+ this.monitors = Collections.unmodifiableSet(newSet);
+ }
+
@Override
public void beginTask(String taskName, int totalWork) {
JobInfo info = getJobInfo(job);
info.beginTask(taskName, totalWork);
refreshJobInfo(info);
currentTaskName = taskName;
- if (listener != null) {
- listener.beginTask(taskName, totalWork);
- }
+ monitors.stream().forEach(listener -> listener.beginTask(taskName, totalWork));
}
@Override
@@ -252,9 +262,7 @@
info.clearTaskInfo();
info.clearChildren();
runnableMonitors.remove(job);
- if (listener != null) {
- listener.done();
- }
+ monitors.stream().forEach(IProgressMonitorWithBlocking::done);
}
@Override
@@ -264,9 +272,7 @@
info.addWork(work);
refreshJobInfo(info);
}
- if (listener != null) {
- listener.internalWorked(work);
- }
+ monitors.stream().forEach(listener -> listener.internalWorked(work));
}
@Override
@@ -285,10 +291,8 @@
// Don't bother canceling twice.
if (value && !info.isCanceled()) {
info.cancel();
- // Only inform the first time.
- if (listener != null) {
- listener.setCanceled(value);
- }
+ // Only inform the first time
+ monitors.stream().forEach(listener -> listener.setCanceled(value));
}
}
@@ -304,9 +308,7 @@
info.clearChildren();
refreshJobInfo(info);
currentTaskName = taskName;
- if (listener != null) {
- listener.setTaskName(taskName);
- }
+ monitors.stream().forEach(listener -> listener.setTaskName(taskName));
}
@Override
@@ -318,9 +320,7 @@
info.clearChildren();
info.addSubTask(name);
refreshJobInfo(info);
- if (listener != null) {
- listener.subTask(name);
- }
+ monitors.stream().forEach(listener -> listener.subTask(name));
}
@Override
@@ -333,9 +333,7 @@
JobInfo info = getJobInfo(job);
info.setBlockedStatus(null);
refreshJobInfo(info);
- if (listener != null) {
- listener.clearBlocked();
- }
+ monitors.stream().forEach(IProgressMonitorWithBlocking::clearBlocked);
}
@Override
@@ -343,9 +341,7 @@
JobInfo info = getJobInfo(job);
info.setBlockedStatus(reason);
refreshJobInfo(info);
- if (listener != null) {
- listener.setBlocked(reason);
- }
+ monitors.stream().forEach(listener -> listener.setBlocked(reason));
}
}
diff --git a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/datatransfer/SmartImportTests.java b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/datatransfer/SmartImportTests.java
index 9b1dff3..a8b1eaf 100644
--- a/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/datatransfer/SmartImportTests.java
+++ b/tests/org.eclipse.ui.tests/Eclipse UI Tests/org/eclipse/ui/tests/datatransfer/SmartImportTests.java
@@ -23,12 +23,20 @@
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.wizard.ProgressMonitorPart;
import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.ToolBar;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.ui.internal.wizards.datatransfer.SmartImportRootWizardPage;
import org.eclipse.ui.internal.wizards.datatransfer.SmartImportWizard;
import org.eclipse.ui.tests.harness.util.UITestCase;
+import org.junit.Test;
/**
* @since 3.12
@@ -116,6 +124,7 @@
return null;
}
+ @Test
public void testImport6Projects() throws IOException, OperationCanceledException, InterruptedException {
URL url = FileLocator
.toFileURL(getClass().getResource("/data/org.eclipse.datatransferArchives/ProjectsArchive.zip"));
@@ -124,6 +133,7 @@
assertEquals(6, ResourcesPlugin.getWorkspace().getRoot().getProjects().length);
}
+ @Test
public void testImportModularProjectsWithSameName()
throws IOException, OperationCanceledException, InterruptedException {
URL url = FileLocator
@@ -143,4 +153,52 @@
assertTrue(implProjectNames.contains("module2_impl"));
assertTrue(implProjectNames.contains("module3_impl"));
}
+
+ @Test
+ public void testCancelWizardCancelsJob() {
+ SmartImportWizard wizard = new SmartImportWizard();
+ wizard.setInitialImportSource(File.listRoots()[0]);
+ this.dialog = new WizardDialog(getWorkbench().getActiveWorkbenchWindow().getShell(), wizard);
+ dialog.setBlockOnOpen(false);
+ dialog.open();
+ SmartImportRootWizardPage page = (SmartImportRootWizardPage) dialog.getCurrentPage();
+ ProgressMonitorPart wizardProgressMonitor = page.getWizardProgressMonitor();
+ assertNotNull("Wizard should have a progress monitor", wizardProgressMonitor);
+ ToolItem stopButton = getStopButton(wizardProgressMonitor);
+ processEventsUntil(new Condition() {
+ @Override
+ public boolean compute() {
+ return stopButton.isEnabled();
+ }
+ }, 10000);
+ assertTrue("Wizard should show progress monitor", wizardProgressMonitor.isVisible());
+ assertTrue("Stop button should be enabled", stopButton.isEnabled());
+ Event clickButtonEvent = new Event();
+ clickButtonEvent.widget = stopButton;
+ clickButtonEvent.item = stopButton;
+ clickButtonEvent.type = SWT.Selection;
+ clickButtonEvent.doit = true;
+ clickButtonEvent.stateMask = SWT.BUTTON1;
+ stopButton.notifyListeners(SWT.Selection, clickButtonEvent);
+ processEventsUntil(new Condition() {
+ @Override
+ public boolean compute() {
+ return !wizardProgressMonitor.isVisible();
+ }
+ }, 10000);
+ assertFalse("Progress monitor should be hidden within 10 seconds", wizardProgressMonitor.isVisible());
+ }
+
+ private static ToolItem getStopButton(ProgressMonitorPart part) {
+ for (Control control : part.getChildren()) {
+ if (control instanceof ToolBar) {
+ for (ToolItem item : ((ToolBar) control).getItems()) {
+ if (item.getToolTipText().equals(JFaceResources.getString("ProgressMonitorPart.cancelToolTip"))) { //$NON-NLS-1$ ))
+ return item;
+ }
+ }
+ }
+ }
+ return null;
+ }
}