1 /*******************************************************************************
2  * Copyright (c) 2007, 2020 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *     Alexander Fedorov <alexander.fedorov@arsysop.ru> - ongoing support
14  *******************************************************************************/
15 
16 package org.eclipse.ui.internal.views.markers;
17 
18 import java.lang.reflect.InvocationTargetException;
19 import java.util.Collection;
20 import java.util.Map;
21 import java.util.Objects;
22 import java.util.Optional;
23 import java.util.function.Consumer;
24 
25 import org.eclipse.core.resources.IMarker;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.e4.ui.internal.workspace.markers.Translation;
28 import org.eclipse.jface.operation.IRunnableWithProgress;
29 import org.eclipse.jface.viewers.StructuredViewer;
30 import org.eclipse.jface.wizard.Wizard;
31 import org.eclipse.swt.widgets.Control;
32 import org.eclipse.swt.widgets.Display;
33 import org.eclipse.ui.IMarkerResolution;
34 import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
35 import org.eclipse.ui.views.markers.WorkbenchMarkerResolution;
36 import org.eclipse.ui.views.markers.internal.MarkerMessages;
37 
38 /**
39  * QuickFixWizard is the wizard for quick fixes.
40  *
41  * @since 3.4
42  *
43  */
44 class QuickFixWizard extends Wizard {
45 
46 	private IMarker[] selectedMarkers;
47 	private Map<IMarkerResolution, Collection<IMarker>> resolutionMap;
48 	private String description;
49 	private final Consumer<StructuredViewer> showMarkers;
50 	private final Consumer<Control> bindHelp;
51 	private final Consumer<Throwable> reporter;
52 	private QuickFixPage quickFixPage;
53 
54 	/**
55 	 * Create the wizard with the map of resolutions.
56 	 *
57 	 * @param description     the description of the problem
58 	 * @param selectedMarkers the markers that were selected
59 	 * @param resolutions     Map key {@link IMarkerResolution} value
60 	 *                        {@link IMarker} []
61 	 * @param showMarkers     the consumer to show markers
62 	 * @param bindHelp        the consumer to bind help system
63 	 * @param reporter        used to report failures during
64 	 *                        {@link Wizard#performFinish()} call
65 	 */
QuickFixWizard(String description, IMarker[] selectedMarkers, Map<IMarkerResolution, Collection<IMarker>> resolutions, Consumer<StructuredViewer> showMarkers, Consumer<Control> bindHelp, Consumer<Throwable> reporter)66 	public QuickFixWizard(String description, IMarker[] selectedMarkers,
67 			Map<IMarkerResolution, Collection<IMarker>> resolutions, Consumer<StructuredViewer> showMarkers,
68 			Consumer<Control> bindHelp,
69 			Consumer<Throwable> reporter) {
70 		Objects.requireNonNull(reporter);
71 		this.selectedMarkers= selectedMarkers;
72 		this.resolutionMap = resolutions;
73 		this.description = description;
74 		this.showMarkers = showMarkers;
75 		this.bindHelp = bindHelp;
76 		this.reporter = reporter;
77 		setDefaultPageImageDescriptor(IDEInternalWorkbenchImages
78 				.getImageDescriptor(IDEInternalWorkbenchImages.IMG_DLGBAN_QUICKFIX_DLG));
79 		setNeedsProgressMonitor(true);
80 	}
81 
82 	@Override
addPages()83 	public void addPages() {
84 		quickFixPage = new QuickFixPage(description, selectedMarkers, resolutionMap, showMarkers, bindHelp);
85 		addPage(quickFixPage);
86 	}
87 
88 	@Override
performFinish()89 	public boolean performFinish() {
90 		Optional<IMarkerResolution> resolution = quickFixPage.getSelectedMarkerResolution();
91 		if (!resolution.isPresent()) {
92 			return true; // for backward compatibility
93 		}
94 		final IMarker[] markers = quickFixPage.getCheckedMarkers();
95 		if (markers.length == 0) {
96 			return true; // for backward compatibility
97 		}
98 		IRunnableWithProgress finishRunnable = monitor -> processResolution(resolution.get(), markers, monitor);
99 		try {
100 			getContainer().run(false, true, finishRunnable);
101 		} catch (InvocationTargetException | InterruptedException e) {
102 			reporter.accept(e);
103 			return false;
104 		}
105 		return true;
106 	}
107 
108 	/**
109 	 * Runs the resolution in UI thread. It should be in UI because a lot of
110 	 * resolutions expect to be executed in the UI thread at the moment. We can
111 	 * think about some interface to mark resolutions that are ready to be executed
112 	 * outside of the UI thread.
113 	 *
114 	 * @param resolution the resolution to run
115 	 * @param markers    the array of markers to resolve
116 	 * @param monitor    progress callback
117 	 */
processResolution(final IMarkerResolution resolution, final IMarker[] markers, IProgressMonitor monitor)118 	private void processResolution(final IMarkerResolution resolution, final IMarker[] markers,
119 			IProgressMonitor monitor) {
120 		monitor.beginTask(MarkerMessages.MarkerResolutionDialog_Fixing, markers.length);
121 		ensureRepaint();
122 		if (resolution instanceof WorkbenchMarkerResolution) {
123 			((WorkbenchMarkerResolution) resolution).run(markers, monitor);
124 		} else {
125 			Translation translation = new Translation();
126 			for (IMarker marker : markers) {
127 				ensureRepaint();
128 				if (monitor.isCanceled()) {
129 					return;
130 				}
131 				monitor.subTask(translation.message(marker).orElse("")); //$NON-NLS-1$
132 				resolution.run(marker);
133 				monitor.worked(1);
134 			}
135 		}
136 	}
137 
138 	/**
139 	 * org.eclipse.jface.wizard.ProgressMonitorPart needs to take a breath
140 	 */
ensureRepaint()141 	private void ensureRepaint() {
142 		final Display display = getShell().getDisplay();
143 		boolean dispatch = true;
144 		while (dispatch) {
145 			dispatch = display.readAndDispatch();
146 		}
147 	}
148 
149 }
150