blob: 1275b3ecd30eba99fac5d0d807ad66a0fe213426 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Sonatype, Inc. - ongoing development
* Red Hat, Inc. - support for remediation page
* Lars Vogel <Lars.Vogel@vogella.com> - Bug 479145
*******************************************************************************/
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.*;
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));
}
@Override
protected ResolutionResultsWizardPage createResolutionPage() {
return new InstallWizardPage(ui, this, root, operation);
}
@Override
protected ISelectableIUsPage createMainPage(IUElementListRoot input, Object[] selections) {
mainPage = new AvailableIUsPage(ui, this);
if (selections != null && selections.length > 0)
mainPage.setCheckedElements(selections);
return mainPage;
}
@Override
protected void initializeResolutionModelElements(Object[] selectedElements) {
if (selectedElements == null)
return;
root = new IUElementListRoot(ui);
if (operation instanceof RemediationOperation) {
AvailableIUElement[] elements = ElementUtils
.requestToElement(((RemediationOperation) operation).getCurrentRemedy(), true);
root.setChildren(elements);
planSelections = elements;
} else {
ArrayList<AvailableIUElement> list = new ArrayList<>(selectedElements.length);
ArrayList<AvailableIUElement> selections = new ArrayList<>(selectedElements.length);
for (Object selectedElement : selectedElements) {
IInstallableUnit iu = ElementUtils.getIU(selectedElement);
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.
*/
@Override
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;
}
@Override
protected ProvisioningContext getProvisioningContext() {
return ((AvailableIUsPage) mainPage).getProvisioningContext();
}
@Override
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;
}
@Override
protected RemediationPage createRemediationPage() {
remediationPage = new RemediationPage(ui, this, root, operation);
return remediationPage;
}
@Override
protected ProfileChangeOperation getProfileChangeOperation(Object[] elements) {
InstallOperation op = new InstallOperation(ui.getSession(), ElementUtils.elementsToIUs(elements));
op.setProfileId(getProfileId());
// op.setRootMarkerKey(getRootMarkerKey());
return op;
}
@Override
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();
}
@Override
protected void planChanged() {
super.planChanged();
synchSelections(getOperationSelectionsPage());
}
/*
* overridden to ensure that the main page selections stay in synch with changes
* to the error page.
*/
@Override
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.
*/
@Override
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(() -> {
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(), 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.
*
*/
@Override
public boolean statusOverridesOperation() {
return super.statusOverridesOperation() || (installHandlerStatus != null && !installHandlerStatus.isOK()
&& couldNotResolveStatus == installHandlerStatus);
}
}