|
18 | 18 | import java.lang.reflect.InvocationTargetException; |
19 | 19 | import java.net.URI; |
20 | 20 | import java.util.ArrayList; |
21 | | -import java.util.Iterator; |
| 21 | +import java.util.LinkedHashMap; |
22 | 22 | import java.util.List; |
| 23 | +import java.util.Map; |
23 | 24 |
|
24 | 25 | import org.eclipse.core.filesystem.IFileInfo; |
25 | 26 | import org.eclipse.core.filesystem.IFileStore; |
26 | 27 | import org.eclipse.core.resources.IProject; |
27 | 28 | import org.eclipse.core.resources.IResource; |
28 | | -import org.eclipse.core.resources.IResourceRuleFactory; |
29 | 29 | import org.eclipse.core.resources.IWorkspaceRoot; |
30 | 30 | import org.eclipse.core.resources.ResourcesPlugin; |
31 | 31 | import org.eclipse.core.resources.WorkspaceJob; |
|
49 | 49 | import org.eclipse.swt.widgets.Shell; |
50 | 50 | import org.eclipse.ui.PlatformUI; |
51 | 51 | import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; |
| 52 | +import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; |
52 | 53 | import org.eclipse.ui.internal.ide.IIDEHelpContextIds; |
53 | 54 | import org.eclipse.ui.internal.ide.StatusUtil; |
54 | 55 | import org.eclipse.ui.internal.ide.dialogs.IDEResourceInfoUtils; |
@@ -217,41 +218,110 @@ final public void refreshAll() { |
217 | 218 |
|
218 | 219 | @Override |
219 | 220 | final protected IRunnableWithProgress createOperation(final IStatus[] errorStatus) { |
220 | | - ISchedulingRule rule = null; |
221 | | - IResourceRuleFactory factory = ResourcesPlugin.getWorkspace().getRuleFactory(); |
222 | | - |
223 | 221 | List<? extends IResource> actionResources = new ArrayList<>(getActionResources()); |
224 | 222 | if (shouldPerformResourcePruning()) { |
225 | 223 | actionResources = pruneResources(actionResources); |
226 | 224 | } |
227 | 225 | final List<? extends IResource> resources = actionResources; |
228 | 226 |
|
229 | | - Iterator<? extends IResource> res = resources.iterator(); |
230 | | - while (res.hasNext()) { |
231 | | - rule = MultiRule.combine(rule, factory.refreshRule(res.next())); |
| 227 | + ISchedulingRule rule = null; |
| 228 | + for (IResource resource : resources) { |
| 229 | + ISchedulingRule newRule = (resource.getType() == IResource.ROOT) ? resource : resource.getProject(); |
| 230 | + rule = MultiRule.combine(rule, newRule); |
232 | 231 | } |
| 232 | + |
233 | 233 | return new WorkspaceModifyOperation(rule) { |
234 | 234 | @Override |
235 | 235 | public void execute(IProgressMonitor mon) { |
236 | 236 | SubMonitor subMonitor = SubMonitor.convert(mon, resources.size()); |
237 | | - MultiStatus errors = null; |
238 | 237 | subMonitor.setTaskName(getOperationMessage()); |
239 | | - Iterator<? extends IResource> resourcesEnum = resources.iterator(); |
240 | | - while (resourcesEnum.hasNext()) { |
| 238 | + List<IStatus> errors = new ArrayList<>(); |
| 239 | + for (IResource resource : resources) { |
241 | 240 | try { |
242 | | - IResource resource = resourcesEnum.next(); |
243 | 241 | refreshResource(resource, subMonitor.split(1)); |
244 | 242 | } catch (CoreException e) { |
245 | | - errors = recordError(errors, e); |
| 243 | + errors.add(e.getStatus()); |
246 | 244 | } |
247 | 245 | } |
248 | | - if (errors != null) { |
249 | | - errorStatus[0] = errors; |
| 246 | + if (!errors.isEmpty()) { |
| 247 | + MultiStatus multiStatus = new MultiStatus(IDEWorkbenchPlugin.IDE_WORKBENCH, IStatus.ERROR, |
| 248 | + getProblemsMessage(), null); |
| 249 | + for (IStatus s : errors) { |
| 250 | + multiStatus.merge(s); |
| 251 | + } |
| 252 | + errorStatus[0] = multiStatus; |
250 | 253 | } |
251 | 254 | } |
252 | 255 | }; |
253 | 256 | } |
254 | 257 |
|
| 258 | + /** |
| 259 | + * Creates a {@link WorkspaceJob} that refreshes the given resources under the |
| 260 | + * given scheduling rule. The job is not yet scheduled when returned, allowing |
| 261 | + * callers to attach listeners before scheduling. |
| 262 | + * |
| 263 | + * @param resources resources to refresh; must not be <code>null</code> |
| 264 | + * @param rule scheduling rule for the job (a project or workspace root) |
| 265 | + * @return the created but unscheduled job |
| 266 | + * @since 3.23 |
| 267 | + */ |
| 268 | + protected WorkspaceJob createRefreshJob(List<? extends IResource> resources, ISchedulingRule rule) { |
| 269 | + final IStatus[] errorStatus = { Status.OK_STATUS }; |
| 270 | + WorkspaceModifyOperation op = new WorkspaceModifyOperation(rule) { |
| 271 | + @Override |
| 272 | + public void execute(IProgressMonitor mon) { |
| 273 | + SubMonitor subMonitor = SubMonitor.convert(mon, resources.size()); |
| 274 | + subMonitor.setTaskName(getOperationMessage()); |
| 275 | + List<IStatus> errors = new ArrayList<>(); |
| 276 | + for (IResource resource : resources) { |
| 277 | + try { |
| 278 | + refreshResource(resource, subMonitor.split(1)); |
| 279 | + } catch (CoreException e) { |
| 280 | + errors.add(e.getStatus()); |
| 281 | + } |
| 282 | + } |
| 283 | + if (!errors.isEmpty()) { |
| 284 | + MultiStatus multiStatus = new MultiStatus(IDEWorkbenchPlugin.IDE_WORKBENCH, IStatus.ERROR, |
| 285 | + getProblemsMessage(), null); |
| 286 | + for (IStatus s : errors) { |
| 287 | + multiStatus.merge(s); |
| 288 | + } |
| 289 | + errorStatus[0] = multiStatus; |
| 290 | + } |
| 291 | + } |
| 292 | + }; |
| 293 | + WorkspaceJob job = new WorkspaceJob("refresh") { //$NON-NLS-1$ |
| 294 | + @Override |
| 295 | + public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { |
| 296 | + try { |
| 297 | + op.run(monitor); |
| 298 | + } catch (InvocationTargetException e) { |
| 299 | + String msg = NLS.bind(IDEWorkbenchMessages.WorkspaceAction_logTitle, getClass().getName(), |
| 300 | + e.getTargetException()); |
| 301 | + return StatusUtil.newStatus(IStatus.ERROR, msg, e.getTargetException()); |
| 302 | + } catch (InterruptedException e) { |
| 303 | + return Status.CANCEL_STATUS; |
| 304 | + } |
| 305 | + return errorStatus[0]; |
| 306 | + } |
| 307 | + }; |
| 308 | + job.setRule(op.getRule()); |
| 309 | + job.setUser(true); |
| 310 | + return job; |
| 311 | + } |
| 312 | + |
| 313 | + /** |
| 314 | + * Creates and schedules a {@link WorkspaceJob} for the given resources. |
| 315 | + * Subclasses may override to attach listeners before the job is scheduled. |
| 316 | + * |
| 317 | + * @param resources resources to refresh; must not be <code>null</code> |
| 318 | + * @param rule scheduling rule for the job (a project or workspace root) |
| 319 | + * @since 3.23 |
| 320 | + */ |
| 321 | + protected void scheduleRefreshJob(List<? extends IResource> resources, ISchedulingRule rule) { |
| 322 | + createRefreshJob(resources, rule).schedule(); |
| 323 | + } |
| 324 | + |
255 | 325 | /** |
256 | 326 | * Refresh the resource (with a check for deleted projects). |
257 | 327 | * <p> |
@@ -285,32 +355,19 @@ protected void refreshResource(IResource resource, IProgressMonitor monitor) thr |
285 | 355 |
|
286 | 356 | @Override |
287 | 357 | public void run() { |
288 | | - final IStatus[] errorStatus = new IStatus[1]; |
289 | | - errorStatus[0] = Status.OK_STATUS; |
290 | | - final WorkspaceModifyOperation op = (WorkspaceModifyOperation) createOperation(errorStatus); |
291 | | - WorkspaceJob job = new WorkspaceJob("refresh") { //$NON-NLS-1$ |
292 | | - |
293 | | - @Override |
294 | | - public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException { |
295 | | - try { |
296 | | - op.run(monitor); |
297 | | - } catch (InvocationTargetException e) { |
298 | | - String msg = NLS.bind( |
299 | | - IDEWorkbenchMessages.WorkspaceAction_logTitle, getClass() |
300 | | - .getName(), e.getTargetException()); |
301 | | - throw new CoreException(StatusUtil.newStatus(IStatus.ERROR, msg, e.getTargetException())); |
302 | | - } catch (InterruptedException e) { |
303 | | - return Status.CANCEL_STATUS; |
304 | | - } |
305 | | - return errorStatus[0]; |
306 | | - } |
307 | | - |
308 | | - }; |
309 | | - ISchedulingRule rule = op.getRule(); |
310 | | - if (rule != null) { |
311 | | - job.setRule(rule); |
| 358 | + List<? extends IResource> actionResources = new ArrayList<>(getActionResources()); |
| 359 | + if (shouldPerformResourcePruning()) { |
| 360 | + actionResources = pruneResources(actionResources); |
| 361 | + } |
| 362 | + // Group resources by scheduling rule so each project can be refreshed in |
| 363 | + // parallel while still holding a project-level rule during its refresh. |
| 364 | + Map<ISchedulingRule, List<IResource>> byRule = new LinkedHashMap<>(); |
| 365 | + for (IResource resource : actionResources) { |
| 366 | + ISchedulingRule rule = (resource.getType() == IResource.ROOT) ? resource : resource.getProject(); |
| 367 | + byRule.computeIfAbsent(rule, r -> new ArrayList<>()).add(resource); |
| 368 | + } |
| 369 | + for (Map.Entry<ISchedulingRule, List<IResource>> entry : byRule.entrySet()) { |
| 370 | + scheduleRefreshJob(entry.getValue(), entry.getKey()); |
312 | 371 | } |
313 | | - job.setUser(true); |
314 | | - job.schedule(); |
315 | 372 | } |
316 | 373 | } |
0 commit comments