blob: 473356908ab1d674a55f4927bceb951a3efe9e71 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.equinox.internal.p2.ui.dialogs;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.ui.*;
import org.eclipse.equinox.internal.p2.ui.model.AvailableIUElement;
import org.eclipse.equinox.internal.p2.ui.viewers.IUDetailsLabelProvider;
import org.eclipse.equinox.internal.p2.ui.viewers.StaticContentProvider;
import org.eclipse.equinox.internal.provisional.p2.core.ProvisionException;
import org.eclipse.equinox.internal.provisional.p2.director.ProvisioningPlan;
import org.eclipse.equinox.internal.provisional.p2.engine.ProvisioningContext;
import org.eclipse.equinox.internal.provisional.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.internal.provisional.p2.ui.*;
import org.eclipse.equinox.internal.provisional.p2.ui.operations.ProfileModificationOperation;
import org.eclipse.equinox.internal.provisional.p2.ui.query.IUPropertyUtils;
import org.eclipse.equinox.internal.provisional.p2.ui.viewers.*;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.*;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.statushandlers.StatusManager;
public abstract class ProfileModificationWizardPage extends WizardPage {
private static final int DEFAULT_HEIGHT = 20;
private static final int DEFAULT_WIDTH = 120;
private static final int DEFAULT_DESCRIPTION_HEIGHT = 4;
private static final int DEFAULT_COLUMN_WIDTH = 60;
private static final int DEFAULT_SMALL_COLUMN_WIDTH = 20;
private static final String NESTING_INDENT = " "; //$NON-NLS-1$
private static final IStatus NULL_PLAN_STATUS = new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, 0, ProvUIMessages.ProfileModificationWizardPage_UnexpectedError, null);
private IInstallableUnit[] ius;
ProvisioningPlan currentPlan;
IStatus currentStatus;
private String profileId;
CheckboxTableViewer listViewer;
Text detailsArea;
StaticContentProvider contentProvider;
protected Display display;
protected ProfileModificationWizardPage(String id, IInstallableUnit[] ius, String profileID, ProvisioningPlan initialPlan) {
super(id);
this.ius = ius;
this.profileId = profileID;
this.currentPlan = initialPlan;
}
public void createControl(Composite parent) {
display = parent.getDisplay();
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
composite.setLayout(layout);
GridData data = new GridData(GridData.FILL_BOTH);
composite.setLayoutData(data);
initializeDialogUnits(composite);
// The viewer allows selection of IU's for browsing the details,
// and checking to include in the provisioning operation.
listViewer = CheckboxTableViewer.newCheckList(composite, SWT.BORDER | SWT.FULL_SELECTION);
data = new GridData(GridData.FILL_BOTH);
data.heightHint = convertHeightInCharsToPixels(DEFAULT_HEIGHT);
data.widthHint = convertWidthInCharsToPixels(DEFAULT_WIDTH);
Table table = listViewer.getTable();
table.setLayoutData(data);
table.setHeaderVisible(true);
IUColumnConfig[] columns = getColumnConfig();
for (int i = 0; i < columns.length; i++) {
TableColumn tc = new TableColumn(table, SWT.LEFT, i);
tc.setResizable(true);
tc.setText(columns[i].columnTitle);
if (columns[i].columnField == IUColumnConfig.COLUMN_SIZE) {
tc.setAlignment(SWT.RIGHT);
tc.setWidth(convertWidthInCharsToPixels(DEFAULT_SMALL_COLUMN_WIDTH));
} else
tc.setWidth(convertWidthInCharsToPixels(DEFAULT_COLUMN_WIDTH));
}
final List list = new ArrayList(ius.length);
makeElements(getIUs(), list);
listViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
checkedIUsChanged();
}
});
listViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
updateStatus();
}
});
// Filters and sorters before establishing content, so we don't refresh unnecessarily.
listViewer.setComparator(new IUComparator(IUComparator.IU_NAME));
listViewer.setComparer(new ProvElementComparer());
contentProvider = new StaticContentProvider(list.toArray());
listViewer.setContentProvider(contentProvider);
listViewer.setInput(new Object());
listViewer.setLabelProvider(new IUDetailsLabelProvider(null, getColumnConfig(), getShell()));
setInitialCheckState();
// If the initial provisioning plan was already calculated,
// no need to repeat it until the user changes selections
if (currentPlan == null)
checkedIUsChanged();
else
currentStatus = PlanStatusHelper.computeStatus(currentPlan, ius);
createSizingInfo(composite);
// The text area shows a description of the selected IU, or error detail if applicable.
Group group = new Group(composite, SWT.NONE);
group.setText(ProvUIMessages.ProfileModificationWizardPage_DetailsLabel);
group.setLayout(new GridLayout());
group.setLayoutData(new GridData(GridData.FILL_BOTH));
createDetailsArea(group);
updateStatus();
setControl(composite);
Dialog.applyDialogFont(composite);
}
protected void createSizingInfo(Composite parent) {
// Default is to do nothing
}
protected void createDetailsArea(Composite parent) {
detailsArea = new Text(parent, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY | SWT.WRAP);
GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
data.heightHint = convertHeightInCharsToPixels(DEFAULT_DESCRIPTION_HEIGHT);
data.widthHint = convertWidthInCharsToPixels(DEFAULT_WIDTH);
detailsArea.setLayoutData(data);
}
protected void makeElements(IInstallableUnit[] iusToShow, List list) {
for (int i = 0; i < iusToShow.length; i++) {
list.add(new AvailableIUElement(iusToShow[i], getProfileId()));
}
}
public boolean performFinish() {
if (currentStatus != null && currentStatus.getSeverity() != IStatus.ERROR) {
ProfileModificationOperation op = createProfileModificationOperation(currentPlan);
ProvisioningOperationRunner.schedule(op, getShell(), StatusManager.SHOW | StatusManager.LOG);
return true;
}
return false;
}
protected Object[] getCheckedElements() {
return listViewer.getCheckedElements();
}
protected Object[] getSelectedElements() {
return ((IStructuredSelection) listViewer.getSelection()).toArray();
}
protected IInstallableUnit[] elementsToIUs(Object[] elements) {
IInstallableUnit[] theIUs = new IInstallableUnit[elements.length];
for (int i = 0; i < elements.length; i++) {
theIUs[i] = (IInstallableUnit) ProvUI.getAdapter(elements[i], IInstallableUnit.class);
}
return theIUs;
}
protected IInstallableUnit getSelectedIU() {
IInstallableUnit[] units = elementsToIUs(getSelectedElements());
if (units.length == 0)
return null;
return units[0];
}
protected String getProfileId() {
return profileId;
}
protected IInstallableUnit[] getIUs() {
return ius;
}
protected IUColumnConfig[] getColumnConfig() {
return ProvUI.getIUColumnConfig();
}
protected void checkedIUsChanged() {
try {
final Object[] selections = getCheckedElements();
if (selections.length == 0) {
currentPlan = null;
currentStatus = new Status(IStatus.ERROR, ProvUIActivator.PLUGIN_ID, IStatusCodes.EXPECTED_NOTHING_TO_DO, ProvUIMessages.ProfileModificationWizardPage_NothingSelected, null);
} else
getContainer().run(true, true, new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) {
try {
currentPlan = computeProvisioningPlan(selections, monitor);
if (currentPlan != null)
currentStatus = PlanStatusHelper.computeStatus(currentPlan, elementsToIUs(selections));
else
currentStatus = NULL_PLAN_STATUS;
} catch (ProvisionException e) {
currentPlan = null;
currentStatus = ProvUI.handleException(e.getCause(), ProvUIMessages.ProfileModificationWizardPage_UnexpectedError, StatusManager.LOG);
}
}
});
} catch (InterruptedException e) {
// Nothing to report if thread was interrupted
} catch (InvocationTargetException e) {
currentPlan = null;
currentStatus = ProvUI.handleException(e.getCause(), ProvUIMessages.ProfileModificationWizardPage_UnexpectedError, StatusManager.LOG);
}
updateStatus();
}
private ProfileModificationOperation createProfileModificationOperation(ProvisioningPlan plan) {
return new ProfileModificationOperation(getOperationLabel(), profileId, plan);
}
protected abstract ProvisioningPlan computeProvisioningPlan(Object[] checkedElements, IProgressMonitor monitor) throws ProvisionException;
protected void setInitialCheckState() {
// The default is to check everything because
// in most cases, the user has selected exactly
// what they want before this page opens.
listViewer.setAllChecked(true);
}
// We currently create an empty provisioning context, but
// in the future we could consider letting clients supply this.
protected ProvisioningContext getProvisioningContext() {
return new ProvisioningContext();
}
protected abstract String getOperationLabel();
void updateStatus() {
int messageType = IMessageProvider.NONE;
boolean pageComplete = true;
if (currentStatus != null && !currentStatus.isOK()) {
messageType = IMessageProvider.INFORMATION;
int severity = currentStatus.getSeverity();
if (severity == IStatus.ERROR) {
messageType = IMessageProvider.ERROR;
pageComplete = false;
// Log errors for later support, but not if these are
// simple UI validation errors.
if (currentStatus.getCode() != IStatusCodes.EXPECTED_NOTHING_TO_DO)
ProvUI.reportStatus(currentStatus, StatusManager.LOG);
} else if (severity == IStatus.WARNING) {
messageType = IMessageProvider.WARNING;
// Log warnings for later support
ProvUI.reportStatus(currentStatus, StatusManager.LOG);
}
}
setPageComplete(pageComplete);
setMessage(getMessageText(), messageType);
detailsArea.setText(getDetailText());
}
String getDetailText() {
String detail = ""; //$NON-NLS-1$
if (currentStatus == null || currentStatus.isOK()) {
IInstallableUnit iu = getSelectedIU();
if (iu != null)
detail = getIUDescription(iu);
} else {
// current status is not OK. See if there are embedded exceptions or status to report
StringBuffer buffer = new StringBuffer();
appendDetailText(currentStatus, buffer, -1, false);
detail = buffer.toString();
}
return detail;
}
void appendDetailText(IStatus status, StringBuffer buffer, int indent, boolean includeTopLevel) {
for (int i = 0; i < indent; i++)
buffer.append(NESTING_INDENT);
if (includeTopLevel && status.getMessage() != null)
buffer.append(status.getMessage());
Throwable t = status.getException();
if (t != null) {
// A provision (or core) exception occurred. Get its status message or if none, its top level message.
if (t instanceof CoreException) {
IStatus exceptionStatus = ((CoreException) t).getStatus();
if (exceptionStatus != null && exceptionStatus.getMessage() != null)
buffer.append(exceptionStatus.getMessage());
else {
String details = t.getLocalizedMessage();
if (details != null)
buffer.append(details);
}
} else {
String details = t.getLocalizedMessage();
if (details != null)
buffer.append(details);
}
} else {
// This is the most important case. No exception occurred, we have a non-OK status after trying
// to get a provisioning plan. It's important not to lose the multi status information. The top level status
// message has already been reported
IStatus[] children = status.getChildren();
for (int i = 0; i < children.length; i++) {
appendDetailText(children[i], buffer, indent + 1, true);
buffer.append('\n');
}
}
}
String getMessageText() {
if (currentStatus == null || currentStatus.isOK())
return getDescription();
return currentStatus.getMessage();
}
protected String getIUDescription(IInstallableUnit iu) {
// Get the iu description in the default locale
String description = IUPropertyUtils.getIUProperty(iu, IInstallableUnit.PROP_DESCRIPTION);
if (description == null)
description = ""; //$NON-NLS-1$
return description;
}
}