1 /*******************************************************************************
2  * Copyright (c) 2007, 2018 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  *     EclipseSource - ongoing development
14  *     Sonatype, Inc. - ongoing development
15  *     Red Hat, Inc. - support for remediation page
16  *******************************************************************************/
17 package org.eclipse.equinox.internal.p2.ui.dialogs;
18 
19 import java.util.Collection;
20 import org.eclipse.core.runtime.IStatus;
21 import org.eclipse.core.runtime.Status;
22 import org.eclipse.equinox.internal.p2.ui.*;
23 import org.eclipse.equinox.internal.p2.ui.model.*;
24 import org.eclipse.equinox.internal.p2.ui.viewers.*;
25 import org.eclipse.equinox.p2.engine.IProvisioningPlan;
26 import org.eclipse.equinox.p2.metadata.IInstallableUnit;
27 import org.eclipse.equinox.p2.operations.ProfileChangeOperation;
28 import org.eclipse.equinox.p2.operations.ProvisioningJob;
29 import org.eclipse.equinox.p2.query.IQueryable;
30 import org.eclipse.equinox.p2.ui.ProvisioningUI;
31 import org.eclipse.jface.dialogs.Dialog;
32 import org.eclipse.jface.dialogs.IDialogConstants;
33 import org.eclipse.jface.viewers.*;
34 import org.eclipse.swt.SWT;
35 import org.eclipse.swt.custom.SashForm;
36 import org.eclipse.swt.graphics.Image;
37 import org.eclipse.swt.layout.*;
38 import org.eclipse.swt.widgets.*;
39 import org.eclipse.ui.statushandlers.StatusManager;
40 
41 /**
42  * A wizard page that shows detailed information about a resolved install
43  * operation.  It allows drill down into the elements that will be installed.
44  *
45  * @since 3.4
46  *
47  */
48 public abstract class ResolutionResultsWizardPage extends ResolutionStatusPage {
49 
50 	private static final String DIALOG_SETTINGS_SECTION = "ResolutionResultsPage"; //$NON-NLS-1$
51 
52 	protected IUElementListRoot input;
53 	ProfileChangeOperation resolvedOperation;
54 	TreeViewer treeViewer;
55 	ProvElementContentProvider contentProvider;
56 	IUDetailsLabelProvider labelProvider;
57 	protected Display display;
58 	private IUDetailsGroup iuDetailsGroup;
59 	SashForm sashForm;
60 
ResolutionResultsWizardPage(ProvisioningUI ui, ProvisioningOperationWizard wizard, IUElementListRoot input, ProfileChangeOperation operation)61 	protected ResolutionResultsWizardPage(ProvisioningUI ui, ProvisioningOperationWizard wizard, IUElementListRoot input, ProfileChangeOperation operation) {
62 		super("ResolutionPage", ui, wizard); //$NON-NLS-1$
63 		this.resolvedOperation = operation;
64 		if (input == null)
65 			this.input = new IUElementListRoot(ui);
66 		else
67 			this.input = input;
68 	}
69 
70 	@Override
createControl(Composite parent)71 	public void createControl(Composite parent) {
72 		display = parent.getDisplay();
73 		sashForm = new SashForm(parent, SWT.VERTICAL);
74 		FillLayout layout = new FillLayout();
75 		sashForm.setLayout(layout);
76 		GridData data = new GridData(GridData.FILL_BOTH);
77 		sashForm.setLayoutData(data);
78 		initializeDialogUnits(sashForm);
79 
80 		Composite composite = new Composite(sashForm, SWT.NONE);
81 		GridLayout gridLayout = new GridLayout();
82 		gridLayout.marginWidth = 0;
83 		gridLayout.marginHeight = 0;
84 		composite.setLayout(gridLayout);
85 
86 		treeViewer = createTreeViewer(composite);
87 		data = new GridData(GridData.FILL_BOTH);
88 		data.heightHint = convertHeightInCharsToPixels(ILayoutConstants.DEFAULT_TABLE_HEIGHT);
89 		data.widthHint = convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_TABLE_WIDTH);
90 		Tree tree = treeViewer.getTree();
91 		tree.setLayoutData(data);
92 		tree.setHeaderVisible(true);
93 		activateCopy(tree);
94 		TreeViewerColumn nameColumn = new TreeViewerColumn(treeViewer, SWT.LEFT);
95 		nameColumn.getColumn().setText(ProvUIMessages.ProvUI_NameColumnTitle);
96 		nameColumn.getColumn().setWidth(400);
97 		nameColumn.getColumn().setMoveable(true);
98 		nameColumn.setLabelProvider(new ColumnLabelProvider() {
99 			@Override
100 			public String getText(Object element) {
101 				IInstallableUnit iu = ProvUI.getAdapter(element, IInstallableUnit.class);
102 				String label = iu.getProperty(IInstallableUnit.PROP_NAME, null);
103 				if (label == null)
104 					label = iu.getId();
105 				return label;
106 			}
107 
108 			@Override
109 			public Image getImage(Object element) {
110 				if (element instanceof ProvElement)
111 					return ((ProvElement) element).getImage(element);
112 				if (ProvUI.getAdapter(element, IInstallableUnit.class) != null)
113 					return ProvUIImages.getImage(ProvUIImages.IMG_IU);
114 				return null;
115 			}
116 
117 			@Override
118 			public String getToolTipText(Object element) {
119 				if (element instanceof AvailableIUElement && ((AvailableIUElement) element).getImageOverlayId(null) == ProvUIImages.IMG_INFO)
120 					return ProvUIMessages.RemedyElementNotHighestVersion;
121 				return super.getToolTipText(element);
122 			}
123 		});
124 		TreeViewerColumn versionColumn = new TreeViewerColumn(treeViewer, SWT.LEFT);
125 		versionColumn.getColumn().setText(ProvUIMessages.ProvUI_VersionColumnTitle);
126 		versionColumn.getColumn().setWidth(200);
127 		versionColumn.setLabelProvider(new ColumnLabelProvider() {
128 			@Override
129 			public String getText(Object element) {
130 				IInstallableUnit iu = ProvUI.getAdapter(element, IInstallableUnit.class);
131 				if (element instanceof IIUElement) {
132 					if (((IIUElement) element).shouldShowVersion())
133 						return iu.getVersion().toString();
134 					return ""; //$NON-NLS-1$
135 				}
136 				return iu.getVersion().toString();
137 			}
138 		});
139 		TreeViewerColumn idColumn = new TreeViewerColumn(treeViewer, SWT.LEFT);
140 		idColumn.getColumn().setText(ProvUIMessages.ProvUI_IdColumnTitle);
141 		idColumn.getColumn().setWidth(200);
142 
143 		idColumn.setLabelProvider(new ColumnLabelProvider() {
144 			@Override
145 			public String getText(Object element) {
146 				IInstallableUnit iu = ProvUI.getAdapter(element, IInstallableUnit.class);
147 				return iu.getId();
148 			}
149 		});
150 
151 		// Filters and sorters before establishing content, so we don't refresh unnecessarily.
152 		IUComparator comparator = new IUComparator(IUComparator.IU_NAME);
153 		comparator.useColumnConfig(getColumnConfig());
154 		treeViewer.setComparator(comparator);
155 		treeViewer.setComparer(new ProvElementComparer());
156 		ColumnViewerToolTipSupport.enableFor(treeViewer);
157 		contentProvider = new ProvElementContentProvider();
158 		treeViewer.setContentProvider(contentProvider);
159 		//		labelProvider = new IUDetailsLabelProvider(null, getColumnConfig(), getShell());
160 		//		treeViewer.setLabelProvider(labelProvider);
161 
162 		// Optional area to show the size
163 		createSizingInfo(composite);
164 
165 		// The text area shows a description of the selected IU, or error detail if applicable.
166 		iuDetailsGroup = new IUDetailsGroup(sashForm, treeViewer, convertWidthInCharsToPixels(ILayoutConstants.DEFAULT_TABLE_WIDTH), true);
167 
168 		setControl(sashForm);
169 		sashForm.setWeights(getSashWeights());
170 		Dialog.applyDialogFont(sashForm);
171 
172 		// Controls for filtering/presentation/site selection
173 		Composite controlsComposite = new Composite(composite, SWT.NONE);
174 		gridLayout = new GridLayout();
175 		gridLayout.marginWidth = 0;
176 		gridLayout.marginHeight = 0;
177 		gridLayout.numColumns = 2;
178 		gridLayout.makeColumnsEqualWidth = true;
179 		gridLayout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
180 		controlsComposite.setLayout(layout);
181 		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false);
182 		controlsComposite.setLayoutData(gd);
183 
184 		final Runnable runnable = () -> {
185 			treeViewer.addSelectionChangedListener(event -> setDetailText(resolvedOperation));
186 			setDrilldownElements(input, resolvedOperation);
187 			treeViewer.setInput(input);
188 		};
189 
190 		if (resolvedOperation != null && !resolvedOperation.hasResolved()) {
191 			try {
192 				getContainer().run(true, false, monitor -> {
193 					resolvedOperation.resolveModal(monitor);
194 					display.asyncExec(runnable);
195 				});
196 			} catch (Exception e) {
197 				StatusManager.getManager().handle(new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, e.getMessage(), e));
198 			}
199 		} else {
200 			runnable.run();
201 		}
202 	}
203 
204 	@Override
updateStatus(IUElementListRoot newRoot, ProfileChangeOperation op)205 	public void updateStatus(IUElementListRoot newRoot, ProfileChangeOperation op) {
206 		super.updateStatus(newRoot, op);
207 	}
208 
createSizingInfo(Composite parent)209 	protected void createSizingInfo(Composite parent) {
210 		// Default is to do nothing
211 	}
212 
performFinish()213 	public boolean performFinish() {
214 		if (resolvedOperation.getResolutionResult().getSeverity() != IStatus.ERROR) {
215 			getProvisioningUI().schedule(resolvedOperation.getProvisioningJob(null), StatusManager.SHOW | StatusManager.LOG);
216 			return true;
217 		}
218 		return false;
219 	}
220 
getTreeViewer()221 	protected TreeViewer getTreeViewer() {
222 		return treeViewer;
223 	}
224 
getCurrentPlan()225 	public IProvisioningPlan getCurrentPlan() {
226 		if (resolvedOperation != null)
227 			return resolvedOperation.getProvisioningPlan();
228 		return null;
229 	}
230 
231 	@Override
getSelectedElements()232 	protected Object[] getSelectedElements() {
233 		return treeViewer.getStructuredSelection().toArray();
234 	}
235 
236 	@Override
getSelectedIU()237 	protected IInstallableUnit getSelectedIU() {
238 		java.util.List<IInstallableUnit> units = ElementUtils.elementsToIUs(getSelectedElements());
239 		if (units.size() == 0)
240 			return null;
241 		return units.get(0);
242 	}
243 
244 	@Override
shouldCompleteOnCancel()245 	protected boolean shouldCompleteOnCancel() {
246 		return false;
247 	}
248 
getIUs()249 	protected Collection<IInstallableUnit> getIUs() {
250 		return ElementUtils.elementsToIUs(input.getChildren(input));
251 	}
252 
setDrilldownElements(IUElementListRoot root, ProfileChangeOperation operation)253 	void setDrilldownElements(IUElementListRoot root, ProfileChangeOperation operation) {
254 		if (operation == null || operation.getProvisioningPlan() == null)
255 			return;
256 		Object[] elements = root.getChildren(root);
257 		for (Object element : elements) {
258 			if (element instanceof QueriedElement) {
259 				((QueriedElement) element).setQueryable(getQueryable(operation.getProvisioningPlan()));
260 			}
261 		}
262 	}
263 
getOperationLabel()264 	protected abstract String getOperationLabel();
265 
266 	/**
267 	 * Returns the restart policy for this operation.
268 	 *
269 	 * @return an integer constant describing whether the running profile
270 	 * needs to be restarted.
271 	 *
272 	 * @see ProvisioningJob#RESTART_NONE
273 	 * @see ProvisioningJob#RESTART_ONLY
274 	 * @see ProvisioningJob#RESTART_OR_APPLY
275 	 *
276 	 */
getRestartPolicy()277 	protected int getRestartPolicy() {
278 		return ProvisioningJob.RESTART_OR_APPLY;
279 	}
280 
281 	/**
282 	 * Returns the task name for this operation, or <code>null</code> to display
283 	 * a generic task name.
284 	 */
getOperationTaskName()285 	protected String getOperationTaskName() {
286 		return null;
287 	}
288 
createTreeViewer(Composite parent)289 	protected TreeViewer createTreeViewer(Composite parent) {
290 		return new TreeViewer(parent, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION);
291 	}
292 
getQueryable(IProvisioningPlan plan)293 	protected abstract IQueryable<IInstallableUnit> getQueryable(IProvisioningPlan plan);
294 
295 	@Override
getClipboardText(Control control)296 	protected String getClipboardText(Control control) {
297 		return CopyUtils.getIndentedClipboardText(getSelectedElements(), labelProvider);
298 	}
299 
300 	@Override
getDetailsGroup()301 	protected IUDetailsGroup getDetailsGroup() {
302 		return iuDetailsGroup;
303 	}
304 
305 	@Override
isCreated()306 	protected boolean isCreated() {
307 		return treeViewer != null;
308 	}
309 
310 	@Override
updateCaches(IUElementListRoot newRoot, ProfileChangeOperation op)311 	protected void updateCaches(IUElementListRoot newRoot, ProfileChangeOperation op) {
312 		resolvedOperation = op;
313 		if (newRoot != null) {
314 			setDrilldownElements(newRoot, resolvedOperation);
315 			if (treeViewer != null) {
316 				if (input != newRoot)
317 					treeViewer.setInput(newRoot);
318 				else
319 					treeViewer.refresh();
320 			}
321 			input = newRoot;
322 		}
323 	}
324 
325 	@Override
getDialogSettingsName()326 	protected String getDialogSettingsName() {
327 		return getWizard().getClass().getName() + "." + DIALOG_SETTINGS_SECTION; //$NON-NLS-1$
328 	}
329 
330 	@Override
getColumnWidth(int index)331 	protected int getColumnWidth(int index) {
332 		return treeViewer.getTree().getColumn(index).getWidth();
333 	}
334 
335 	@Override
getSashForm()336 	protected SashForm getSashForm() {
337 		return sashForm;
338 	}
339 }