/*******************************************************************************
* Copyright (c) 2010 The Eclipse Foundation 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:
* The Eclipse Foundation - initial API and implementation
* Yatta Solutions - category filtering (bug 314936), error handling (bug 374105),
* multiselect hints (bug 337774), public API (bug 432803),
* performance (bug 413871), featured market (bug 461603)
*******************************************************************************/
package org.eclipse.epp.internal.mpc.ui.commands;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.epp.internal.mpc.core.MarketplaceClientCore;
import org.eclipse.epp.internal.mpc.ui.CatalogRegistry;
import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUi;
import org.eclipse.epp.internal.mpc.ui.MarketplaceClientUiPlugin;
import org.eclipse.epp.internal.mpc.ui.catalog.MarketplaceCatalog;
import org.eclipse.epp.internal.mpc.ui.catalog.ResourceProvider;
import org.eclipse.epp.internal.mpc.ui.wizards.AbstractTagFilter;
import org.eclipse.epp.internal.mpc.ui.wizards.ComboTagFilter;
import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceCatalogConfiguration;
import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceFilter;
import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard;
import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizard.WizardState;
import org.eclipse.epp.internal.mpc.ui.wizards.MarketplaceWizardDialog;
import org.eclipse.epp.mpc.core.model.ICatalog;
import org.eclipse.epp.mpc.core.model.ICategory;
import org.eclipse.epp.mpc.core.model.IMarket;
import org.eclipse.epp.mpc.core.service.ICatalogService;
import org.eclipse.epp.mpc.core.service.ServiceHelper;
import org.eclipse.epp.mpc.ui.CatalogDescriptor;
import org.eclipse.epp.mpc.ui.IMarketplaceClientConfiguration;
import org.eclipse.epp.mpc.ui.Operation;
import org.eclipse.equinox.internal.p2.discovery.DiscoveryCore;
import org.eclipse.equinox.internal.p2.discovery.model.Tag;
import org.eclipse.equinox.internal.p2.ui.discovery.util.WorkbenchUtil;
import org.eclipse.equinox.internal.p2.ui.discovery.wizards.CatalogFilter;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.statushandlers.StatusManager;
/**
* @author David Green
* @author Carsten Reckord
*/
public class MarketplaceWizardCommand extends AbstractHandler implements IHandler {
private List<CatalogDescriptor> catalogDescriptors;
private CatalogDescriptor selectedCatalogDescriptor;
private String wizardState;
private Map<String, Operation> operations;
private WizardState wizardDialogState;
public Object execute(ExecutionEvent event) throws ExecutionException {
final MarketplaceCatalog catalog = new MarketplaceCatalog();
catalog.setEnvironment(DiscoveryCore.createEnvironment());
catalog.setVerifyUpdateSiteAvailability(false);
MarketplaceCatalogConfiguration configuration = new MarketplaceCatalogConfiguration();
configuration.setVerifyUpdateSiteAvailability(false);
if (catalogDescriptors == null || catalogDescriptors.isEmpty()) {
final IStatus remoteCatalogStatus = installRemoteCatalogs();
configuration.getCatalogDescriptors().addAll(CatalogRegistry.getInstance().getCatalogDescriptors());
if (configuration.getCatalogDescriptors().isEmpty()) {
// doesn't make much sense to continue without catalogs.
// nothing will work and no way to recover later
IStatus cause;
if (!remoteCatalogStatus.isOK()) {
cause = remoteCatalogStatus;
} else {
cause = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID,
Messages.MarketplaceWizardCommand_noRemoteCatalogs);
}
IStatus exitStatus = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID, cause.getCode(),
Messages.MarketplaceWizardCommand_cannotOpenMarketplace, new CoreException(cause));
try {
MarketplaceClientUi.handle(exitStatus,
StatusManager.SHOW | StatusManager.BLOCK
| (exitStatus.getSeverity() == IStatus.CANCEL ? 0 : StatusManager.LOG));
} catch (Exception ex) {
// HOTFIX for bug 477269 - Display might get disposed during call to handle due to workspace shutdown or similar.
// In that case, just log...
MarketplaceClientUi.getLog().log(exitStatus);
}
return null;
} else if (!remoteCatalogStatus.isOK()) {
MarketplaceClientUi.handle(remoteCatalogStatus, StatusManager.LOG);
}
} else {
configuration.getCatalogDescriptors().addAll(catalogDescriptors);
}
if (selectedCatalogDescriptor != null) {
if (selectedCatalogDescriptor.getLabel().equals("org.eclipse.epp.mpc.descriptorHint")) { //$NON-NLS-1$
CatalogDescriptor resolvedDescriptor = CatalogRegistry.getInstance().findCatalogDescriptor(
selectedCatalogDescriptor.getUrl().toExternalForm());
if (resolvedDescriptor == null) {
IStatus status = new Status(IStatus.ERROR, MarketplaceClientUi.BUNDLE_ID,
Messages.MarketplaceWizardCommand_CouldNotFindMarketplaceForSolution, new ExecutionException(
selectedCatalogDescriptor.getUrl().toExternalForm()));
MarketplaceClientUi.handle(status,
StatusManager.SHOW | StatusManager.BLOCK | StatusManager.LOG);
return null;
} else {
configuration.setCatalogDescriptor(resolvedDescriptor);
}
} else {
configuration.setCatalogDescriptor(selectedCatalogDescriptor);
}
}
configuration.getFilters().clear();
final ComboTagFilter marketFilter = new ComboTagFilter() {
@Override
public void catalogUpdated(boolean wasCancelled) {
List<Tag> choices = new ArrayList<Tag>();
List<IMarket> markets = catalog.getMarkets();
for (IMarket market : markets) {
Tag marketTag = new Tag(IMarket.class, market.getId(), market.getName());
marketTag.setData(market);
choices.add(marketTag);
}
setChoices(choices);
}
};
marketFilter.setSelectAllOnNoSelection(true);
marketFilter.setNoSelectionLabel(Messages.MarketplaceWizardCommand_allMarkets);
marketFilter.setTagClassification(ICategory.class);
marketFilter.setChoices(new ArrayList<Tag>());
final ComboTagFilter marketCategoryTagFilter = new ComboTagFilter() {
@Override
public void catalogUpdated(boolean wasCancelled) {
updateCategoryChoices(this, marketFilter);
}
};
marketCategoryTagFilter.setSelectAllOnNoSelection(true);
marketCategoryTagFilter.setNoSelectionLabel(Messages.MarketplaceWizardCommand_allCategories);
marketCategoryTagFilter.setTagClassification(ICategory.class);
marketCategoryTagFilter.setChoices(new ArrayList<Tag>());
final IPropertyChangeListener marketListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
final String property = event.getProperty();
if (AbstractTagFilter.PROP_SELECTED.equals(property)) {
updateCategoryChoices(marketCategoryTagFilter, marketFilter);
}
}
};
marketFilter.addPropertyChangeListener(marketListener);
configuration.getFilters().add(marketFilter);
configuration.getFilters().add(marketCategoryTagFilter);
configuration.setInitialState(wizardState);
if (operations != null && !operations.isEmpty()) {
configuration.setInitialOperations(operations);
}
for (CatalogFilter filter : configuration.getFilters()) {
((MarketplaceFilter) filter).setCatalog(catalog);
}
MarketplaceWizard wizard = new MarketplaceWizard(catalog, configuration);
wizard.setInitialState(wizardDialogState);
wizard.setWindowTitle(Messages.MarketplaceWizardCommand_eclipseMarketplace);
WizardDialog dialog = new MarketplaceWizardDialog(WorkbenchUtil.getShell(), wizard);
dialog.open();
return null;
}
private void updateCategoryChoices(final ComboTagFilter marketCategoryTagFilter, final ComboTagFilter marketFilter) {
Set<Tag> newChoices = new HashSet<Tag>();
List<Tag> choices = new ArrayList<Tag>();
Set<IMarket> selectedMarkets = new HashSet<IMarket>();
for (Tag marketTag : marketFilter.getSelected()) {
selectedMarkets.add((IMarket) marketTag.getData());
}
final MarketplaceCatalog catalog = (MarketplaceCatalog) marketCategoryTagFilter.getCatalog();
List<IMarket> markets = catalog.getMarkets();
for (IMarket market : markets) {
if (selectedMarkets.isEmpty() || selectedMarkets.contains(market)) {
for (ICategory marketCategory : market.getCategory()) {
Tag categoryTag = new Tag(ICategory.class, marketCategory.getId(), marketCategory.getName());
categoryTag.setData(marketCategory);
if (newChoices.add(categoryTag)) {
choices.add(categoryTag);
}
}
}
}
Collections.sort(choices, new Comparator<Tag>() {
public int compare(Tag o1, Tag o2) {
return o1.getLabel().compareTo(o2.getLabel());
}
});
marketCategoryTagFilter.setChoices(choices);
}
public void setCatalogDescriptors(List<CatalogDescriptor> catalogDescriptors) {
this.catalogDescriptors = catalogDescriptors;
}
public void setSelectedCatalogDescriptor(CatalogDescriptor selectedCatalogDescriptor) {
this.selectedCatalogDescriptor = selectedCatalogDescriptor;
}
public void setWizardState(String wizardState) {
this.wizardState = wizardState;
}
public void setWizardDialogState(WizardState wizardState) {
this.wizardDialogState = wizardState;
}
/**
* @deprecated use {@link #setOperations(Map)} instead
*/
@Deprecated
public void setOperationByNodeId(Map<String, org.eclipse.epp.internal.mpc.ui.wizards.Operation> operationByNodeId) {
this.operations = org.eclipse.epp.internal.mpc.ui.wizards.Operation.mapAllBack(operationByNodeId);
}
public void setOperations(Map<String, Operation> operationByNodeId) {
this.operations = operationByNodeId;
}
public void setConfiguration(IMarketplaceClientConfiguration configuration) {
setCatalogDescriptors(configuration.getCatalogDescriptors());
setOperations(configuration.getInitialOperations());
setWizardState((String) configuration.getInitialState());
setSelectedCatalogDescriptor(configuration.getCatalogDescriptor());
}
public IStatus installRemoteCatalogs() {
try {
final AtomicReference<List<? extends ICatalog>> result = new AtomicReference<List<? extends ICatalog>>();
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
ICatalogService catalogService = ServiceHelper.getMarketplaceServiceLocator()
.getCatalogService();
final List<? extends ICatalog> catalogs = catalogService.listCatalogs(monitor);
result.set(catalogs);
} catch (CoreException e) {
if (e.getStatus().getSeverity() == IStatus.CANCEL) {
throw new InterruptedException();
}
throw new InvocationTargetException(e);
}
}
});
List<? extends ICatalog> catalogs = result.get();
for (ICatalog catalog : catalogs) {
ResourceProvider resourceProvider = MarketplaceClientUiPlugin.getInstance().getResourceProvider();
String catalogName = catalog.getName();
String requestSource = NLS.bind(Messages.MarketplaceWizardCommand_requestCatalog, catalogName,
catalog.getId());
String catalogImageUrl = catalog.getImageUrl();
if (catalogImageUrl != null) {
try {
resourceProvider.retrieveResource(requestSource, catalogImageUrl);
} catch (Exception e) {
MarketplaceClientUi.log(IStatus.WARNING,
Messages.MarketplaceWizardCommand_FailedRetrievingCatalogImage, catalogName,
catalogImageUrl, e);
}
}
if (catalog.getBranding() != null && catalog.getBranding().getWizardIcon() != null) {
String wizardIconUrl = catalog.getBranding().getWizardIcon();
try {
resourceProvider.retrieveResource(requestSource, wizardIconUrl);
} catch (Exception e) {
MarketplaceClientUi.log(IStatus.WARNING,
Messages.MarketplaceWizardCommand_FailedRetrievingCatalogWizardIcon, catalogName,
wizardIconUrl, e);
}
}
CatalogDescriptor descriptor = new CatalogDescriptor(catalog);
registerOrOverrideCatalog(descriptor);
}
} catch (InterruptedException ie) {
if (ie.getMessage() == null || "".equals(ie.getMessage())) {
InterruptedException ie1 = new InterruptedException("Operation cancelled");
ie1.setStackTrace(ie.getStackTrace());
if (ie.getCause() != null) {
ie1.initCause(ie.getCause());
}
ie = ie1;
}
IStatus errorStatus = MarketplaceClientCore.computeStatus(ie,
Messages.MarketplaceWizardCommand_CannotInstallRemoteLocations);
return new Status(IStatus.CANCEL, MarketplaceClientCore.BUNDLE_ID, errorStatus.getMessage(), ie);
} catch (Exception e) {
IStatus status = MarketplaceClientCore.computeStatus(e, Messages.MarketplaceWizardCommand_CannotInstallRemoteLocations);
return status;
}
return Status.OK_STATUS;
}
private void registerOrOverrideCatalog(CatalogDescriptor descriptor) {
CatalogRegistry catalogRegistry = CatalogRegistry.getInstance();
List<CatalogDescriptor> descriptors = catalogRegistry.getCatalogDescriptors();
for (CatalogDescriptor catalogDescriptor : descriptors) {
if (catalogDescriptor.getUrl().toExternalForm().equals(descriptor.getUrl().toExternalForm())) {
catalogRegistry.unregister(catalogDescriptor);
}
}
catalogRegistry.register(descriptor);
}
}