/******************************************************************************* * Copyright (c) 2007, 2010 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 * Sonatype, Inc. - ongoing development *******************************************************************************/ package org.eclipse.equinox.internal.p2.ui.dialogs; import java.util.ArrayList; import java.util.Collection; import org.eclipse.core.runtime.IStatus; import org.eclipse.equinox.internal.p2.ui.*; import org.eclipse.equinox.internal.p2.ui.model.*; import org.eclipse.equinox.p2.engine.ProvisioningContext; import org.eclipse.equinox.p2.metadata.IInstallableUnit; import org.eclipse.equinox.p2.operations.InstallOperation; import org.eclipse.equinox.p2.operations.ProfileChangeOperation; import org.eclipse.equinox.p2.ui.LoadMetadataRepositoryJob; import org.eclipse.equinox.p2.ui.ProvisioningUI; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; /** * An install wizard that allows the users to browse all of the repositories * and search/select for items to install. * * @since 3.6 */ public class InstallWizard extends WizardWithLicenses { SelectableIUsPage errorReportingPage; boolean ignoreSelectionChanges = false; IStatus installHandlerStatus; public InstallWizard(ProvisioningUI ui, InstallOperation operation, Collection<IInstallableUnit> initialSelections, LoadMetadataRepositoryJob preloadJob) { super(ui, operation, initialSelections == null ? null : initialSelections.toArray(), preloadJob); setWindowTitle(ProvUIMessages.InstallIUOperationLabel); setDefaultPageImageDescriptor(ProvUIImages.getImageDescriptor(ProvUIImages.WIZARD_BANNER_INSTALL)); } protected ResolutionResultsWizardPage createResolutionPage() { return new InstallWizardPage(ui, this, root, (InstallOperation) operation); } protected ISelectableIUsPage createMainPage(IUElementListRoot input, Object[] selections) { mainPage = new AvailableIUsPage(ui, this); if (selections != null && selections.length > 0) mainPage.setCheckedElements(selections); return mainPage; } protected void initializeResolutionModelElements(Object[] selectedElements) { if (selectedElements == null) return; root = new IUElementListRoot(); ArrayList<AvailableIUElement> list = new ArrayList<AvailableIUElement>(selectedElements.length); ArrayList<AvailableIUElement> selections = new ArrayList<AvailableIUElement>(selectedElements.length); for (int i = 0; i < selectedElements.length; i++) { IInstallableUnit iu = ElementUtils.getIU(selectedElements[i]); if (iu != null) { AvailableIUElement element = new AvailableIUElement(root, iu, getProfileId(), shouldShowProvisioningPlanChildren()); list.add(element); selections.add(element); } } root.setChildren(list.toArray()); planSelections = selections.toArray(); } /* * Overridden to dynamically determine which page to get * selections from. (non-Javadoc) * @see org.eclipse.equinox.internal.p2.ui.dialogs.ProvisioningOperationWizard#getOperationSelections() */ protected Object[] getOperationSelections() { return getOperationSelectionsPage().getCheckedIUElements(); } /* * Get the page that is driving operation selections. This is * usually the main page, but it could be error page if there * was a resolution error and the user decides to change selections * and try again without going back. */ protected ISelectableIUsPage getOperationSelectionsPage() { IWizardPage page = getContainer().getCurrentPage(); if (page instanceof ISelectableIUsPage) return (ISelectableIUsPage) page; // return the main page if we weren't on main or error page return mainPage; } protected ProvisioningContext getProvisioningContext() { return ((AvailableIUsPage) mainPage).getProvisioningContext(); } protected IResolutionErrorReportingPage createErrorReportingPage() { if (root == null) errorReportingPage = new SelectableIUsPage(ui, this, null, null); else errorReportingPage = new SelectableIUsPage(ui, this, root, root.getChildren(root)); errorReportingPage.setTitle(ProvUIMessages.InstallWizardPage_Title); errorReportingPage.setDescription(ProvUIMessages.PreselectedIUInstallWizard_Description); errorReportingPage.updateStatus(root, operation); return errorReportingPage; } /* (non-Javadoc) * @see org.eclipse.equinox.internal.p2.ui.dialogs.ProvisioningOperationWizard#getProfileChangeOperation(java.lang.Object[]) */ protected ProfileChangeOperation getProfileChangeOperation(Object[] elements) { InstallOperation op = new InstallOperation(ui.getSession(), ElementUtils.elementsToIUs(elements)); op.setProfileId(getProfileId()); // op.setRootMarkerKey(getRootMarkerKey()); return op; } protected boolean shouldUpdateErrorPageModelOnPlanChange() { // We don't want the root of the error page to change unless we are on the // main page. For example, if we are on the error page, change checkmarks, and // resolve again with an error, we wouldn't want the root items to change in the // error page. return getContainer().getCurrentPage() == mainPage && super.shouldUpdateErrorPageModelOnPlanChange(); } protected void planChanged() { super.planChanged(); synchSelections(getOperationSelectionsPage()); } /* * overridden to ensure that the main page selections stay in synch * with changes to the error page. * (non-Javadoc) * @see org.eclipse.equinox.internal.p2.ui.dialogs.ProvisioningOperationWizard#operationSelectionsChanged(org.eclipse.equinox.internal.p2.ui.dialogs.ISelectableIUsPage) */ public void operationSelectionsChanged(ISelectableIUsPage page) { if (ignoreSelectionChanges) return; super.operationSelectionsChanged(page); // If we are on the error page, resolution has failed. // Our ability to move on depends on whether the selections have changed. // If they are the same selections, then we are not complete until selections are changed. if (getOperationSelectionsPage() == errorPage) ((WizardPage) errorPage).setPageComplete(pageSelectionsHaveChanged(errorPage) && errorPage.getCheckedIUElements().length > 0); synchSelections(page); } private void synchSelections(ISelectableIUsPage triggeringPage) { // We don't want our programmatic changes to cause all this to happen again ignoreSelectionChanges = true; try { if (triggeringPage == errorReportingPage) { mainPage.setCheckedElements(triggeringPage.getCheckedIUElements()); } else if (triggeringPage == mainPage) { errorReportingPage.setCheckedElements(triggeringPage.getCheckedIUElements()); } } finally { ignoreSelectionChanges = false; } } /* * Overridden to check whether there are UpdateManager install handlers in the item * to be installed. Operations don't know about this compatibility issue. * (non-Javadoc) * @see org.eclipse.equinox.internal.p2.ui.dialogs.ProvisioningOperationWizard#getCurrentStatus() */ public IStatus getCurrentStatus() { IStatus originalStatus = super.getCurrentStatus(); int sev = originalStatus.getSeverity(); // Use the previously computed status if the user cancelled or if we were already in error. // If we don't have an operation or a plan, we can't check this condition either, so just // use the normal status. if (sev == IStatus.CANCEL || sev == IStatus.ERROR || operation == null || operation.getProvisioningPlan() == null) { return originalStatus; } // Does the plan require install handler support? installHandlerStatus = UpdateManagerCompatibility.getInstallHandlerStatus(operation.getProvisioningPlan()); if (!installHandlerStatus.isOK()) { // Set the status into the wizard. This ensures future calls to this method won't // repeat the work (and prompting). couldNotResolveStatus = installHandlerStatus; // Is the update manager installer present? If so, offer to open it. // In either case, the failure will be reported in this wizard. if (ProvUI.isUpdateManagerInstallerPresent()) { PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { public void run() { Shell shell = ProvUI.getDefaultParentShell(); MessageDialog dialog = new MessageDialog(shell, ProvUIMessages.Policy_RequiresUpdateManagerTitle, null, ProvUIMessages.Policy_RequiresUpdateManagerMessage, MessageDialog.WARNING, new String[] {ProvUIMessages.LaunchUpdateManagerButton, IDialogConstants.CANCEL_LABEL}, 0); if (dialog.open() == 0) BusyIndicator.showWhile(shell.getDisplay(), new Runnable() { public void run() { UpdateManagerCompatibility.openInstaller(); } }); } }); } return installHandlerStatus; } return originalStatus; } /* * When we've found an install handler, that status trumps anything that the operation might have * determined. We are relying here on the knowledge that the wizard's couldNotResolveStatus is * reset on every new resolution, so that status only holds the installHandler status when it is * the current status. The installHandlerStatus must be non-OK for it to matter at all. * * (non-Javadoc) * @see org.eclipse.equinox.internal.p2.ui.dialogs.ProvisioningOperationWizard#statusOverridesOperation() */ public boolean statusOverridesOperation() { return installHandlerStatus != null && !installHandlerStatus.isOK() && couldNotResolveStatus == installHandlerStatus; } }