diff options
| author | Mickael Istria | 2016-09-12 14:50:15 +0000 |
|---|---|---|
| committer | Andrey Loskutov | 2016-10-22 15:08:50 +0000 |
| commit | 9dc142efc9b8252e1c07716db1286e1cbe0e1c7e (patch) | |
| tree | d0b7ab295ab536da9b899c2458def50a42c0c422 | |
| parent | 85f074d8ae801227fbd09535c31a1fd4dd68eb20 (diff) | |
| download | eclipse.platform.ui-9dc142efc9b8252e1c07716db1286e1cbe0e1c7e.tar.gz eclipse.platform.ui-9dc142efc9b8252e1c07716db1286e1cbe0e1c7e.tar.xz eclipse.platform.ui-9dc142efc9b8252e1c07716db1286e1cbe0e1c7e.zip | |
Bug 495007 - Do not block UI in Importer when scanning folderY20161024-0700I20161024-0410I20161023-2000
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>
8 files changed, 399 insertions, 98 deletions
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 79567e0803d..278b9d3ced2 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 @@ public class ProgressMonitorPart extends Composite implements 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 @@ public class ProgressMonitorPart extends Composite implements @Override public void internalWorked(double work) { - fProgressIndicator.worked(work); + if (!fProgressIndicator.isDisposed()) { + fProgressIndicator.worked(work); + } } @Override @@ -333,6 +337,9 @@ public class ProgressMonitorPart extends Composite implements * 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 e3f632a1860..e38056f06b1 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 class DataTransferMessages extends NLS { 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 class DataTransferMessages extends NLS { 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 00000000000..afe8930ffd9 --- /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 47490740784..04f632faf7d 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.HashSet; 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.IPath; 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.ViewerColumn; 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.ModifyEvent; 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 @@ public class SmartImportRootWizardPage extends WizardPage { 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 @@ public class SmartImportRootWizardPage extends WizardPage { 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 @@ public class SmartImportRootWizardPage extends WizardPage { 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 @@ public class SmartImportRootWizardPage extends WizardPage { expandSelectedArchive(); } } + validatePage(); refreshProposals(); } @@ -423,7 +469,7 @@ public class SmartImportRootWizardPage extends WizardPage { /** * @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 @@ public class SmartImportRootWizardPage extends WizardPage { } }); tree.setInput(Collections.emptyMap()); + + return res; } protected void validatePage() { @@ -587,7 +635,6 @@ public class SmartImportRootWizardPage extends WizardPage { setErrorMessage(this.rootDirectoryTextDecorator.getDescriptionText()); } else { this.rootDirectoryTextDecorator.hide(); - setErrorMessage(null); } setPageComplete(isPageComplete()); } @@ -619,6 +666,7 @@ public class SmartImportRootWizardPage extends WizardPage { public void setInitialImportRoot(File directoryOrArchive) { this.selection = directoryOrArchive; this.rootDirectoryText.setText(directoryOrArchive.getAbsolutePath()); + refreshProposals(); } /** @@ -686,49 +734,135 @@ public class SmartImportRootWizardPage extends WizardPage { } 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()); - } + 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; + } + 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()); + 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()); } - }); - // 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(); + return Status.OK_STATUS; + } + }; + Control previousFocusControl = tree.getControl().getDisplay().getFocusControl(); + if (previousFocusControl == null) { + previousFocusControl = rootDirectoryText; + } + 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; + } + } } - 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) { } + 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 905ac94a988..31a2b0b4c8d 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.core.runtime.OperationCanceledException; 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 @@ public class SmartImportWizard extends Wizard implements IImportWizard { && 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 7d41e33d5e7..69841198e45 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_selectionSummary={0} of {1} selected 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 be274278a45..94d6e18766a 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.HashMap; 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.ScheduledFuture; 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 @@ public class ProgressManager extends ProgressProvider implements IProgressServic * 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 @@ public class ProgressManager extends ProgressProvider implements IProgressServic * * @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 @@ public class ProgressManager extends ProgressProvider implements IProgressServic info.clearTaskInfo(); info.clearChildren(); runnableMonitors.remove(job); - if (listener != null) { - listener.done(); - } + monitors.stream().forEach(IProgressMonitorWithBlocking::done); } @Override @@ -264,9 +272,7 @@ public class ProgressManager extends ProgressProvider implements IProgressServic info.addWork(work); refreshJobInfo(info); } - if (listener != null) { - listener.internalWorked(work); - } + monitors.stream().forEach(listener -> listener.internalWorked(work)); } @Override @@ -285,10 +291,8 @@ public class ProgressManager extends ProgressProvider implements IProgressServic // 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 @@ public class ProgressManager extends ProgressProvider implements IProgressServic info.clearChildren(); refreshJobInfo(info); currentTaskName = taskName; - if (listener != null) { - listener.setTaskName(taskName); - } + monitors.stream().forEach(listener -> listener.setTaskName(taskName)); } @Override @@ -318,9 +320,7 @@ public class ProgressManager extends ProgressProvider implements IProgressServic 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 @@ public class ProgressManager extends ProgressProvider implements IProgressServic JobInfo info = getJobInfo(job); info.setBlockedStatus(null); refreshJobInfo(info); - if (listener != null) { - listener.clearBlocked(); - } + monitors.stream().forEach(IProgressMonitorWithBlocking::clearBlocked); } @Override @@ -343,9 +341,7 @@ public class ProgressManager extends ProgressProvider implements IProgressServic 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 9b1dff37396..a8b1eaf5ac3 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.FileLocator; 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 @@ public class SmartImportTests extends UITestCase { 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 @@ public class SmartImportTests extends UITestCase { assertEquals(6, ResourcesPlugin.getWorkspace().getRoot().getProjects().length); } + @Test public void testImportModularProjectsWithSameName() throws IOException, OperationCanceledException, InterruptedException { URL url = FileLocator @@ -143,4 +153,52 @@ public class SmartImportTests extends UITestCase { 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; + } } |
