blob: 6989497a5292b55f50ba1349c9197e947c2bc0a9 [file] [log] [blame]
/*
* Copyright (c) 2014, 2015 Eike Stepper (Berlin, Germany) 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.p2.internal.ui;
import org.eclipse.oomph.internal.ui.GeneralDragAdapter;
import org.eclipse.oomph.internal.ui.GeneralDropAdapter;
import org.eclipse.oomph.internal.ui.GeneralDropAdapter.DroppedObjectHandler;
import org.eclipse.oomph.internal.ui.OomphTransferDelegate;
import org.eclipse.oomph.p2.P2Exception;
import org.eclipse.oomph.p2.P2Factory;
import org.eclipse.oomph.p2.P2Package;
import org.eclipse.oomph.p2.Repository;
import org.eclipse.oomph.p2.Requirement;
import org.eclipse.oomph.p2.VersionSegment;
import org.eclipse.oomph.p2.core.P2Util;
import org.eclipse.oomph.p2.core.RepositoryProvider;
import org.eclipse.oomph.p2.impl.RequirementImpl;
import org.eclipse.oomph.p2.internal.ui.RepositoryManager.RepositoryManagerListener;
import org.eclipse.oomph.p2.provider.RequirementItemProvider;
import org.eclipse.oomph.ui.SearchField;
import org.eclipse.oomph.ui.SearchField.FilterHandler;
import org.eclipse.oomph.ui.UIUtil;
import org.eclipse.oomph.util.CollectionUtil;
import org.eclipse.oomph.util.ObjectUtil;
import org.eclipse.oomph.util.StringUtil;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.metadata.IProvidedCapability;
import org.eclipse.equinox.p2.metadata.IRequirement;
import org.eclipse.equinox.p2.metadata.Version;
import org.eclipse.equinox.p2.metadata.VersionRange;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.query.IQueryResult;
import org.eclipse.equinox.p2.query.QueryUtil;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepository;
import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Eike Stepper
*/
public class RepositoryExplorer extends ViewPart implements FilterHandler
{
public static final String ID = "org.eclipse.oomph.p2.ui.RepositoryExplorer"; //$NON-NLS-1$
private static final IDialogSettings SETTINGS = P2UIPlugin.INSTANCE.getDialogSettings(RepositoryExplorer.class.getSimpleName());
private static final int DND_OPERATIONS = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
private static final Transfer[] DND_TRANSFERS = OomphTransferDelegate.asTransfers(org.eclipse.oomph.internal.ui.OomphTransferDelegate.DELEGATES)
.toArray(new Transfer[OomphTransferDelegate.asTransfers(org.eclipse.oomph.internal.ui.OomphTransferDelegate.DELEGATES).size()]);
private static final String DEFAULT_CAPABILITY_NAMESPACE = IInstallableUnit.NAMESPACE_IU_ID;
private static final String CURRENT_NAMESPACE_KEY = "currentNamespace";
private static final String EXPERT_MODE_KEY = "expertMode";
private static final String CATEGORIZE_ITEMS_KEY = "categorizeItems";
private static final String VERSION_SEGMENT_KEY = "versionSegment";
private static final String COMPATIBLE_VERSION_KEY = "compatibleVersion";
private static final String SOURCE_SUFFIX = ".source";
private static final String FEATURE_SUFFIX = ".feature.group";
private static final String SOURCE_FEATURE_SUFFIX = SOURCE_SUFFIX + FEATURE_SUFFIX;
private static final Object[] NO_ELEMENTS = new Object[0];
private static final Color WHITE = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE);
private final LoadJob loadJob = new LoadJob();
private final AnalyzeJob analyzeJob = new AnalyzeJob();
private final Mode categoriesMode = new CategoriesMode();
private final Mode featuresMode = new FeaturesMode();
private final Mode capabilitiesMode = new CapabilitiesMode();
private final RepositoryFocusListener repositoryFocusListener = new RepositoryFocusListener();
private final RepositoryHistoryListener repositoryHistoryListener = new RepositoryHistoryListener();
private final VersionProvider versionProvider = new VersionProvider();
private final CollapseAllAction collapseAllAction = new CollapseAllAction();
private Color gray;
private Composite container;
private ComboViewer repositoryViewer;
private CCombo repositoryCombo;
private RepositoryProvider.Metadata repositoryProvider;
private Composite selectorComposite;
private Composite itemsComposite;
private StructuredViewer itemsViewer;
private CategoryItem itemsViewerInput;
private TableViewer versionsViewer;
private String currentNamespace;
private boolean expertMode;
private boolean categorizeItems;
private boolean compatibleVersion;
private Mode mode;
private IQueryResult<IInstallableUnit> installableUnits;
private String filter;
public RepositoryExplorer()
{
currentNamespace = SETTINGS.get(CURRENT_NAMESPACE_KEY);
if (currentNamespace == null)
{
currentNamespace = DEFAULT_CAPABILITY_NAMESPACE;
}
expertMode = SETTINGS.getBoolean(EXPERT_MODE_KEY);
String value = SETTINGS.get(CATEGORIZE_ITEMS_KEY);
if (value == null || value.length() == 0)
{
categorizeItems = true;
}
else
{
categorizeItems = "true".equals(value);
}
compatibleVersion = SETTINGS.getBoolean(COMPATIBLE_VERSION_KEY);
}
@Override
public void dispose()
{
gray.dispose();
gray = null;
disposeRepositoryProvider();
super.dispose();
}
private void disposeRepositoryProvider()
{
if (repositoryProvider != null)
{
repositoryProvider.dispose();
repositoryProvider = null;
}
}
@Override
public void setFocus()
{
if (RepositoryManager.INSTANCE.getActiveRepository() != null)
{
repositoryCombo.setFocus();
}
}
private void updateMode()
{
Mode mode = expertMode ? capabilitiesMode : categorizeItems ? categoriesMode : featuresMode;
if (this.mode != mode)
{
this.mode = mode;
GridLayout selectorLayout = new GridLayout();
selectorLayout.marginWidth = 0;
selectorLayout.marginHeight = 0;
selectorComposite.setLayout(selectorLayout);
mode.fillSelector(selectorComposite);
selectorComposite.layout();
selectorComposite.getParent().layout();
mode.fillItems(itemsComposite);
itemsComposite.layout();
itemsViewer.addSelectionChangedListener(new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
IStructuredSelection selection = (IStructuredSelection)itemsViewer.getSelection();
if (selection.size() == 1)
{
versionsViewer.setInput(selection.getFirstElement());
}
else
{
versionsViewer.setInput(null);
}
}
});
analyzeJob.reschedule();
collapseAllAction.updateEnablement();
}
}
private void setItems(Item... items)
{
if (!container.isDisposed())
{
versionsViewer.setInput(null);
itemsViewerInput = new CategoryItem();
itemsViewerInput.setChildren(items);
itemsViewer.setInput(itemsViewerInput);
if (itemsViewer instanceof TreeViewer && filter != null)
{
TreeViewer treeViewer = (TreeViewer)itemsViewer;
treeViewer.expandAll();
}
}
}
private boolean isFiltered(String string)
{
return filter == null || string == null || string.toLowerCase().contains(filter);
}
public void handleFilter(String filter)
{
if (filter == null || filter.length() == 0)
{
this.filter = null;
}
else
{
this.filter = filter.toLowerCase();
}
analyzeJob.reschedule();
}
@Override
public void createPartControl(Composite parent)
{
final Display display = parent.getDisplay();
gray = new Color(display, 75, 75, 75);
container = new Composite(parent, SWT.NONE);
container.setBackground(WHITE);
container.setLayout(new GridLayout(1, false));
createRepositoriesArea(container);
createItemsArea(container);
createVersionsArea(container);
updateMode();
String activeRepository = RepositoryManager.INSTANCE.getActiveRepository();
if (activeRepository == null)
{
// Force hint to be shown.
repositoryFocusListener.focusLost(null);
}
else
{
repositoryCombo.setText(activeRepository);
triggerLoad(activeRepository);
}
hookActions();
}
private static CCombo createCombo(Composite parent, int style, boolean grabExcessHorizontalSpace)
{
CCombo combo = new CCombo(parent, style);
GridData layoutData = new GridData(SWT.FILL, SWT.FILL, grabExcessHorizontalSpace, false);
int increaseHeight = 0;
String ws = Platform.getWS();
if (Platform.WS_COCOA.equals(ws))
{
increaseHeight = 7;
}
else if (Platform.WS_GTK.equals(ws))
{
increaseHeight = 9;
}
if (increaseHeight != 0)
{
FontData[] fontData = combo.getFont().getFontData();
layoutData.heightHint = fontData[0].getHeight() + increaseHeight;
}
combo.setLayoutData(layoutData);
return combo;
}
private void createRepositoriesArea(Composite container)
{
repositoryCombo = createCombo(container, SWT.BORDER, true);
repositoryCombo.setToolTipText("Repository location (type a URL, drop a repository or pick from the drop down history)");
repositoryCombo.addFocusListener(repositoryFocusListener);
repositoryCombo.addKeyListener(repositoryHistoryListener);
repositoryViewer = new ComboViewer(repositoryCombo);
repositoryViewer.setContentProvider(new RepositoryContentProvider());
repositoryViewer.setLabelProvider(new LabelProvider());
repositoryViewer.setInput(RepositoryManager.INSTANCE);
repositoryViewer.addSelectionChangedListener(repositoryHistoryListener);
repositoryViewer.addDropSupport(DND_OPERATIONS, DND_TRANSFERS, new GeneralDropAdapter(repositoryViewer, P2Factory.eINSTANCE.createRepositoryList(),
P2Package.Literals.REPOSITORY_LIST__REPOSITORIES, new DroppedObjectHandler()
{
public void handleDroppedObject(Object object) throws Exception
{
if (object instanceof Repository)
{
Repository repository = (Repository)object;
String url = repository.getURL();
if (!StringUtil.isEmpty(url))
{
activateAndLoadRepository(url);
}
}
}
}));
}
private void createItemsArea(Composite parent)
{
GridLayout containerLayout = new GridLayout(2, false);
containerLayout.marginWidth = 0;
containerLayout.marginHeight = 0;
Composite container = new Composite(parent, SWT.NONE);
container.setBackground(WHITE);
container.setLayout(containerLayout);
container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
SearchField searchField = new SearchField(container, this)
{
@Override
protected void finishFilter()
{
itemsViewer.getControl().setFocus();
selectFirstLeaf(itemsViewerInput);
}
private void selectFirstLeaf(CategoryItem category)
{
Item[] children = category.getChildren();
if (children != null && children.length != 0)
{
Item firstChild = children[0];
if (firstChild instanceof CategoryItem)
{
CategoryItem firstCategory = (CategoryItem)firstChild;
selectFirstLeaf(firstCategory);
}
else
{
itemsViewer.setSelection(new StructuredSelection(firstChild));
}
}
}
};
searchField.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
selectorComposite = new Composite(container, SWT.NONE);
selectorComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
selectorComposite.setBackground(WHITE);
itemsComposite = new Composite(container, SWT.NONE);
itemsComposite.setBackground(WHITE);
itemsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
itemsComposite.setLayout(new FillLayout());
}
private void createVersionsArea(Composite container)
{
Composite versionsComposite = new Composite(container, SWT.NONE);
versionsComposite.setBackground(WHITE);
GridLayout gl_versionsComposite = new GridLayout(2, false);
gl_versionsComposite.marginWidth = 0;
gl_versionsComposite.marginHeight = 0;
versionsComposite.setLayout(gl_versionsComposite);
versionsComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
versionsViewer = new TableViewer(versionsComposite, SWT.BORDER);
versionsViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
versionsViewer.setContentProvider(versionProvider);
versionsViewer.setLabelProvider(versionProvider);
addDragSupport(versionsViewer);
Composite versionsGroup = new Composite(versionsComposite, SWT.NONE);
versionsGroup.setBackground(WHITE);
versionsGroup.setLayout(new GridLayout(1, false));
versionsGroup.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false));
final Button compatibleButton = new Button(versionsGroup, SWT.CHECK);
compatibleButton.setText("Compatible");
compatibleButton.setToolTipText("Show compatible versions");
compatibleButton.setSelection(compatibleVersion);
final Button majorButton = addVersionSegmentButton(versionsGroup, "Major", "Show major versions", VersionSegment.MAJOR);
final Button minorButton = addVersionSegmentButton(versionsGroup, "Minor", "Show minor versions", VersionSegment.MINOR);
addVersionSegmentButton(versionsGroup, "Micro", "Show micro versions", VersionSegment.MICRO);
addVersionSegmentButton(versionsGroup, "Qualifier", "Show qualified versions", VersionSegment.QUALIFIER);
majorButton.setEnabled(!compatibleVersion);
compatibleButton.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
boolean compatible = compatibleButton.getSelection();
if (compatibleVersion != compatible)
{
compatibleVersion = compatible;
SETTINGS.put(COMPATIBLE_VERSION_KEY, compatibleVersion);
majorButton.setEnabled(!compatible);
if (compatible && versionProvider.getVersionSegment() == VersionSegment.MAJOR)
{
majorButton.setSelection(false);
minorButton.setSelection(true);
versionProvider.setVersionSegment(VersionSegment.MINOR);
}
}
}
});
}
private Button addVersionSegmentButton(Composite parent, String text, String toolTip, final VersionSegment versionSegment)
{
Button button = new Button(parent, SWT.RADIO);
button.setText(text);
button.setToolTipText(toolTip);
button.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
versionProvider.setVersionSegment(versionSegment);
}
});
if (versionSegment == versionProvider.getVersionSegment())
{
button.setSelection(true);
}
return button;
}
private void hookActions()
{
IActionBars actionBars = getViewSite().getActionBars();
IToolBarManager toolbarManager = actionBars.getToolBarManager();
toolbarManager.add(new Separator("additions"));
toolbarManager.add(collapseAllAction);
toolbarManager.add(new Action("Refresh", P2UIPlugin.INSTANCE.getImageDescriptor("refresh"))
{
{
setToolTipText("Reload the active repository and refresh the tree");
}
@Override
public void run()
{
String activeRepository = RepositoryManager.INSTANCE.getActiveRepository();
if (activeRepository != null)
{
disposeRepositoryProvider();
triggerLoad(activeRepository);
}
}
});
toolbarManager.add(new Separator("modes"));
toolbarManager.add(new Action("Expert Mode", IAction.AS_CHECK_BOX)
{
{
setImageDescriptor(P2UIPlugin.INSTANCE.getImageDescriptor("obj16/capability"));
setChecked(expertMode);
}
@Override
public void run()
{
expertMode = isChecked();
SETTINGS.put(EXPERT_MODE_KEY, expertMode);
updateMode();
}
});
toolbarManager.add(new Separator("end"));
}
private void activateAndLoadRepository(String repository)
{
if (RepositoryManager.INSTANCE.setActiveRepository(repository))
{
triggerLoad(repository);
}
}
private void triggerLoad(String repository)
{
try
{
IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager();
repository = manager.performStringSubstitution(repository);
}
catch (Exception ex)
{
//$FALL-THROUGH$
}
URI location = null;
try
{
location = new URI(repository);
}
catch (URISyntaxException ex)
{
File folder = new File(repository);
if (folder.isDirectory())
{
location = folder.toURI();
}
}
if (location != null)
{
loadJob.reschedule(location);
}
}
private void addDragSupport(StructuredViewer viewer)
{
viewer.addDragSupport(DND_OPERATIONS, DND_TRANSFERS, new GeneralDragAdapter(viewer, new GeneralDragAdapter.DraggedObjectsFactory()
{
public List<EObject> createDraggedObjects(ISelection selection) throws Exception
{
List<EObject> result = new ArrayList<EObject>();
IStructuredSelection ssel = (IStructuredSelection)selection;
for (Iterator<?> it = ssel.iterator(); it.hasNext();)
{
Object element = it.next();
VersionRange versionRange = VersionRange.emptyRange;
String filter = null;
if (element instanceof VersionProvider.ItemVersion)
{
VersionProvider.ItemVersion itemVersion = (VersionProvider.ItemVersion)element;
Version version = itemVersion.getVersion();
VersionSegment versionSegment = versionProvider.getVersionSegment();
versionRange = P2Factory.eINSTANCE.createVersionRange(version, versionSegment, compatibleVersion);
filter = RequirementImpl.formatMatchExpression(itemVersion.getFilter());
element = ((IStructuredSelection)itemsViewer.getSelection()).getFirstElement();
}
if (element instanceof Item)
{
Item item = (Item)element;
String namespace = item.getNamespace();
if (namespace != null)
{
if (filter == null && item instanceof VersionedItem)
{
VersionedItem versionedItem = (VersionedItem)item;
for (IMatchExpression<IInstallableUnit> matchExpression : versionedItem.getVersions().values())
{
String string = RequirementImpl.formatMatchExpression(matchExpression);
if (filter == null || filter.equals(string))
{
filter = string;
}
else
{
filter = null;
break;
}
}
}
Requirement requirement = P2Factory.eINSTANCE.createRequirement();
requirement.setNamespace(namespace);
requirement.setName(item.getName());
requirement.setVersionRange(versionRange);
requirement.setFilter(filter);
result.add(requirement);
}
}
}
return result;
}
}));
}
private static String[] sortStrings(Collection<String> c)
{
String[] array = c.toArray(new String[c.size()]);
Arrays.sort(array);
return array;
}
private static String[] getMinimalFlavors(final Set<String> flavors)
{
String[] flavorIDs = sortStrings(flavors);
int start = 0;
while (start < flavorIDs.length)
{
boolean changed = false;
for (int i = start + 1; i < flavorIDs.length; i++)
{
String flavorID = flavorIDs[i];
if (flavorID.startsWith(flavorIDs[start]))
{
flavors.remove(flavorID);
changed = true;
}
}
if (changed)
{
flavorIDs = sortStrings(flavors);
}
++start;
}
return flavorIDs;
}
private static String getName(IInstallableUnit iu)
{
String name = iu.getProperty(IInstallableUnit.PROP_NAME, null);
if (StringUtil.isEmpty(name))
{
return iu.getId();
}
return name;
}
private static boolean isCategory(IInstallableUnit iu)
{
return "true".equalsIgnoreCase(iu.getProperty(QueryUtil.PROP_TYPE_CATEGORY));
}
private static boolean isFeature(IInstallableUnit iu)
{
return iu.getId().endsWith(FEATURE_SUFFIX);
}
public static boolean explore(String repository)
{
IWorkbenchWindow window = UIUtil.WORKBENCH.getActiveWorkbenchWindow();
if (window != null)
{
IWorkbenchPage page = window.getActivePage();
if (page != null)
{
IViewPart view = page.findView(ID);
if (view == null)
{
try
{
view = page.showView(ID);
}
catch (PartInitException ex)
{
P2UIPlugin.INSTANCE.log(ex);
}
}
if (view instanceof RepositoryExplorer)
{
RepositoryExplorer explorer = (RepositoryExplorer)view;
explorer.activateAndLoadRepository(repository);
return true;
}
}
}
return false;
}
/**
* @author Eike Stepper
*/
private final class CollapseAllAction extends Action
{
public CollapseAllAction()
{
super("Collapse All", P2UIPlugin.INSTANCE.getImageDescriptor("collapse-all"));
setToolTipText("Collapse all tree items");
updateEnablement();
}
public void updateEnablement()
{
setEnabled(itemsViewer instanceof TreeViewer);
}
@Override
public void run()
{
if (itemsViewer instanceof TreeViewer)
{
TreeViewer treeViewer = (TreeViewer)itemsViewer;
treeViewer.collapseAll();
}
}
}
/**
* @author Eike Stepper
*/
private abstract class SafeJob extends Job
{
public SafeJob(String name)
{
super(name);
}
@Override
protected final IStatus run(IProgressMonitor monitor)
{
try
{
doSafe(monitor);
return Status.OK_STATUS;
}
catch (OperationCanceledException ex)
{
return Status.CANCEL_STATUS;
}
catch (Exception ex)
{
if (ex instanceof P2Exception)
{
Throwable cause = ex.getCause();
if (cause instanceof CoreException)
{
ex = (CoreException)cause;
}
}
final IStatus status = P2UIPlugin.INSTANCE.getStatus(ex);
UIUtil.asyncExec(new Runnable()
{
public void run()
{
setItems(new ErrorItem(status));
}
});
return Status.OK_STATUS;
}
catch (Throwable t)
{
return P2UIPlugin.INSTANCE.getStatus(t);
}
}
protected abstract void doSafe(IProgressMonitor monitor) throws Throwable;
}
/**
* @author Eike Stepper
*/
private final class LoadJob extends SafeJob
{
private URI location;
public LoadJob()
{
super("Loading repository");
}
public void reschedule(URI location)
{
this.location = location;
setItems(new LoadingItem(location));
cancel();
schedule();
}
@Override
@SuppressWarnings("restriction")
protected void doSafe(IProgressMonitor monitor) throws Throwable
{
analyzeJob.cancel();
installableUnits = null;
IMetadataRepositoryManager repositoryManager = P2Util.getAgentManager().getCurrentAgent().getMetadataRepositoryManager();
if (repositoryProvider == null || !repositoryProvider.getLocation().equals(location))
{
disposeRepositoryProvider();
repositoryProvider = new RepositoryProvider.Metadata(repositoryManager, location);
}
SubMonitor progress = SubMonitor.convert(monitor, 101);
IMetadataRepository repository = repositoryProvider.getRepository(progress.newChild(100));
if (repository instanceof org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository)
{
org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository compositeRepository = (org.eclipse.equinox.internal.p2.metadata.repository.CompositeMetadataRepository)repository;
org.eclipse.equinox.internal.p2.persistence.CompositeRepositoryState state = compositeRepository.toState();
URI[] children = state.getChildren();
final List<Item> errors = new ArrayList<Item>();
Set<String> messages = new HashSet<String>();
for (URI child : children)
{
try
{
URI absolute = URIUtil.makeAbsolute(child, location);
if (repositoryManager.loadRepository(absolute, null) == null)
{
throw new ProvisionException("No repository found at " + absolute + ".");
}
}
catch (Exception ex)
{
IStatus status = P2UIPlugin.INSTANCE.getStatus(ex);
if (messages.add(status.getMessage()))
{
errors.add(new ErrorItem(status));
}
}
}
if (!errors.isEmpty())
{
UIUtil.asyncExec(new Runnable()
{
public void run()
{
setItems(errors.toArray(new Item[errors.size()]));
}
});
return;
}
}
installableUnits = repository.query(QueryUtil.createIUAnyQuery(), progress.newChild(1));
analyzeJob.reschedule();
}
}
/**
* @author Eike Stepper
*/
private final class AnalyzeJob extends SafeJob
{
public AnalyzeJob()
{
super("Analyzing repository");
}
public void reschedule()
{
cancel();
if (installableUnits != null)
{
schedule();
}
}
@Override
protected void doSafe(IProgressMonitor monitor) throws Throwable
{
mode.analyzeInstallableUnits(monitor);
}
}
/**
* @author Eike Stepper
*/
private abstract class Mode
{
protected final void disposeChildren(Composite parent)
{
for (Control child : parent.getChildren())
{
child.dispose();
}
}
protected final void fillCategorySelector(Composite parent)
{
Control[] children = parent.getChildren();
if (children.length == 1 && children[0] instanceof Button)
{
((Button)children[0]).setSelection(categorizeItems);
return;
}
disposeChildren(parent);
final Button button = new Button(parent, SWT.CHECK);
button.setText("Group items by category");
button.setToolTipText("Whether to show items in categories or in a complete list");
button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
button.setSelection(categorizeItems);
button.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
categorizeItems = button.getSelection();
SETTINGS.put(CATEGORIZE_ITEMS_KEY, categorizeItems);
updateMode();
}
});
}
public abstract void fillSelector(Composite parent);
public abstract void fillItems(Composite parent);
public abstract void analyzeInstallableUnits(IProgressMonitor monitor);
}
/**
* @author Eike Stepper
*/
private final class CategoriesMode extends Mode
{
@Override
public void fillSelector(Composite parent)
{
fillCategorySelector(parent);
}
@Override
public void fillItems(Composite parent)
{
disposeChildren(parent);
TreeViewer categoriesViewer = new TreeViewer(parent, SWT.BORDER | SWT.MULTI);
categoriesViewer.setUseHashlookup(true);
categoriesViewer.setContentProvider(new ItemContentProvider());
categoriesViewer.setLabelProvider(new ItemLabelProvider());
addDragSupport(categoriesViewer);
itemsViewer = categoriesViewer;
}
@SuppressWarnings("restriction")
@Override
public void analyzeInstallableUnits(IProgressMonitor monitor)
{
// IU.id -> value
Map<String, String> names = new HashMap<String, String>();
Map<String, Set<IInstallableUnit>> ius = new HashMap<String, Set<IInstallableUnit>>();
Map<String, Set<IRequirement>> categories = new HashMap<String, Set<IRequirement>>();
for (IInstallableUnit iu : installableUnits)
{
P2UIPlugin.checkCancelation(monitor);
String id = iu.getId();
names.put(id, getName(iu));
CollectionUtil.add(ius, id, iu);
if (isCategory(iu))
{
CollectionUtil.addAll(categories, id, iu.getRequirements());
}
}
Set<String> rootIDs = new HashSet<String>();
for (String categoryID : categories.keySet())
{
P2UIPlugin.checkCancelation(monitor);
rootIDs.add(categoryID);
}
for (Set<IRequirement> requirements : categories.values())
{
for (IRequirement requirement : requirements)
{
P2UIPlugin.checkCancelation(monitor);
if (requirement instanceof org.eclipse.equinox.internal.p2.metadata.IRequiredCapability)
{
org.eclipse.equinox.internal.p2.metadata.IRequiredCapability requiredCapability = (org.eclipse.equinox.internal.p2.metadata.IRequiredCapability)requirement;
if (IInstallableUnit.NAMESPACE_IU_ID.equals(requiredCapability.getNamespace()))
{
rootIDs.remove(requiredCapability.getName());
}
}
}
}
Set<CategoryItem> rootCategories = new HashSet<CategoryItem>();
for (String rootID : rootIDs)
{
P2UIPlugin.checkCancelation(monitor);
CategoryItem rootCategory = analyzeCategory(names, ius, categories, rootID, monitor);
if (rootCategory != null)
{
rootCategories.add(rootCategory);
}
}
final CategoryItem[] roots = rootCategories.toArray(new CategoryItem[rootCategories.size()]);
UIUtil.asyncExec(new Runnable()
{
public void run()
{
setItems(roots);
}
});
}
@SuppressWarnings("restriction")
private CategoryItem analyzeCategory(Map<String, String> names, Map<String, Set<IInstallableUnit>> ius, Map<String, Set<IRequirement>> categories,
String categoryID, IProgressMonitor monitor)
{
Map<String, Item> children = new HashMap<String, Item>();
Map<Item, Map<Version, IMatchExpression<IInstallableUnit>>> versions = new HashMap<Item, Map<Version, IMatchExpression<IInstallableUnit>>>();
for (IRequirement requirement : categories.get(categoryID))
{
P2UIPlugin.checkCancelation(monitor);
if (requirement instanceof org.eclipse.equinox.internal.p2.metadata.IRequiredCapability)
{
org.eclipse.equinox.internal.p2.metadata.IRequiredCapability requiredCapability = (org.eclipse.equinox.internal.p2.metadata.IRequiredCapability)requirement;
if (IInstallableUnit.NAMESPACE_IU_ID.equals(requiredCapability.getNamespace()))
{
String requiredID = requiredCapability.getName();
if (categories.containsKey(requiredID))
{
CategoryItem child = analyzeCategory(names, ius, categories, requiredID, monitor);
if (child != null)
{
children.put(requiredID, child);
}
}
else
{
VersionRange range = requiredCapability.getRange();
Item child = children.get(requiredID);
Set<IInstallableUnit> set = ius.get(requiredID);
for (IInstallableUnit iu : set)
{
P2UIPlugin.checkCancelation(monitor);
Version version = iu.getVersion();
if (range.isIncluded(version))
{
if (child == null)
{
String name = names.get(requiredID);
if (isFiltered(name))
{
if (isFeature(iu))
{
if (requiredID.endsWith(SOURCE_FEATURE_SUFFIX))
{
String mainID = requiredID.substring(0, requiredID.length() - SOURCE_FEATURE_SUFFIX.length()) + FEATURE_SUFFIX;
String mainName = names.get(mainID);
if (ObjectUtil.equals(name, mainName))
{
name += " (Source)";
}
}
child = new FeatureItem(requiredID);
}
else
{
if (requiredID.endsWith(SOURCE_SUFFIX))
{
String mainID = requiredID.substring(0, requiredID.length() - SOURCE_SUFFIX.length());
String mainName = names.get(mainID);
if (ObjectUtil.equals(name, mainName))
{
name += " (Source)";
}
}
child = new PluginItem(requiredID);
}
child.setLabel(name);
children.put(requiredID, child);
}
}
if (child != null)
{
IMatchExpression<IInstallableUnit> matchExpression = iu.getFilter();
Map<Version, IMatchExpression<IInstallableUnit>> map = versions.get(child);
if (map == null)
{
map = new HashMap<Version, IMatchExpression<IInstallableUnit>>();
versions.put(child, map);
}
map.put(version, matchExpression);
}
}
}
}
}
}
}
for (Map.Entry<Item, Map<Version, IMatchExpression<IInstallableUnit>>> entry : versions.entrySet())
{
P2UIPlugin.checkCancelation(monitor);
Item child = entry.getKey();
if (child instanceof VersionedItem)
{
VersionedItem versionedItem = (VersionedItem)child;
versionedItem.setVersions(entry.getValue());
}
}
if (children.isEmpty())
{
return null;
}
CategoryItem categoryItem = new CategoryItem();
categoryItem.setLabel(names.get(categoryID));
categoryItem.setChildren(children.values().toArray(new Item[children.size()]));
return categoryItem;
}
}
/**
* @author Eike Stepper
*/
private final class FeaturesMode extends Mode
{
@Override
public void fillSelector(Composite parent)
{
fillCategorySelector(parent);
}
@Override
public void fillItems(Composite parent)
{
disposeChildren(parent);
TableViewer featuresViewer = new TableViewer(parent, SWT.BORDER | SWT.MULTI | SWT.VIRTUAL);
featuresViewer.setUseHashlookup(true);
featuresViewer.setContentProvider(new ItemContentProvider());
featuresViewer.setLabelProvider(new ItemLabelProvider());
addDragSupport(featuresViewer);
itemsViewer = featuresViewer;
}
@Override
public void analyzeInstallableUnits(IProgressMonitor monitor)
{
Map<String, String> names = new HashMap<String, String>();
Map<String, Map<Version, IMatchExpression<IInstallableUnit>>> versions = new HashMap<String, Map<Version, IMatchExpression<IInstallableUnit>>>();
for (IInstallableUnit iu : installableUnits)
{
P2UIPlugin.checkCancelation(monitor);
String id = iu.getId();
if (id.endsWith(FEATURE_SUFFIX) && !id.endsWith(SOURCE_FEATURE_SUFFIX))
{
String name = getName(iu);
if (isFiltered(name))
{
names.put(id, name);
Version version = iu.getVersion();
IMatchExpression<IInstallableUnit> filter = iu.getFilter();
Map<Version, IMatchExpression<IInstallableUnit>> map = versions.get(id);
if (map == null)
{
map = new HashMap<Version, IMatchExpression<IInstallableUnit>>();
versions.put(id, map);
}
map.put(version, filter);
}
}
}
final FeatureItem[] featureItems = new FeatureItem[versions.size()];
Iterator<String> iterator = versions.keySet().iterator();
for (int i = 0; i < featureItems.length; i++)
{
P2UIPlugin.checkCancelation(monitor);
String id = iterator.next();
Map<Version, IMatchExpression<IInstallableUnit>> map = versions.get(id);
FeatureItem featureItem = new FeatureItem(id);
featureItem.setVersions(map);
featureItem.setLabel(names.get(id));
featureItems[i] = featureItem;
}
UIUtil.asyncExec(new Runnable()
{
public void run()
{
setItems(featureItems);
}
});
}
}
/**
* @author Eike Stepper
*/
private final class CapabilitiesMode extends Mode
{
private ComboViewer namespaceViewer;
@Override
public void fillSelector(Composite parent)
{
disposeChildren(parent);
CCombo namespaceCombo =
// new CCombo(parent, SWT.BORDER | SWT.READ_ONLY | SWT.FLAT);
createCombo(parent, SWT.BORDER | SWT.READ_ONLY | SWT.FLAT, false);
namespaceCombo.setToolTipText("Select the namespace of the capabilities to show");
namespaceViewer = new ComboViewer(namespaceCombo);
namespaceViewer.setSorter(new ViewerSorter());
namespaceViewer.setContentProvider(new ArrayContentProvider());
namespaceViewer.setLabelProvider(new LabelProvider());
namespaceViewer.setInput(new String[] { currentNamespace });
namespaceViewer.addSelectionChangedListener(new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
IStructuredSelection selection = (IStructuredSelection)namespaceViewer.getSelection();
String newNamespace = (String)selection.getFirstElement();
if (!ObjectUtil.equals(newNamespace, currentNamespace))
{
SETTINGS.put(CURRENT_NAMESPACE_KEY, newNamespace);
currentNamespace = newNamespace;
analyzeJob.reschedule();
}
}
});
namespaceViewer.setSelection(new StructuredSelection(currentNamespace));
}
@Override
public void fillItems(Composite parent)
{
disposeChildren(parent);
TableViewer capabilitiesViewer = new TableViewer(parent, SWT.BORDER | SWT.MULTI | SWT.VIRTUAL);
capabilitiesViewer.setUseHashlookup(true);
capabilitiesViewer.setContentProvider(new ItemContentProvider());
capabilitiesViewer.setLabelProvider(new ItemLabelProvider());
addDragSupport(capabilitiesViewer);
itemsViewer = capabilitiesViewer;
}
@Override
public void analyzeInstallableUnits(IProgressMonitor monitor)
{
final Set<String> flavors = new HashSet<String>();
final Set<String> namespaces = new HashSet<String>();
Map<String, Set<Version>> versions = new HashMap<String, Set<Version>>();
for (IInstallableUnit iu : installableUnits)
{
for (IProvidedCapability capability : iu.getProvidedCapabilities())
{
P2UIPlugin.checkCancelation(monitor);
String namespace = capability.getNamespace();
String name = capability.getName();
if ("org.eclipse.equinox.p2.flavor".equals(namespace))
{
flavors.add(name);
}
else if (!"A.PDE.Target.Platform".equalsIgnoreCase(namespace))
{
namespaces.add(namespace);
}
if (ObjectUtil.equals(namespace, currentNamespace) && isFiltered(name))
{
Version version = capability.getVersion();
if (version != null && !Version.emptyVersion.equals(version))
{
CollectionUtil.add(versions, name, version);
}
}
}
}
String[] flavorIDs = getMinimalFlavors(flavors);
for (Iterator<String> it = namespaces.iterator(); it.hasNext();)
{
String namespace = it.next();
for (int i = 0; i < flavorIDs.length; i++)
{
String flavor = flavorIDs[i];
if (namespace.startsWith(flavor))
{
it.remove();
break;
}
}
}
if (!namespaces.contains(currentNamespace))
{
String newCurrentNamespace = null;
if (namespaces.contains(DEFAULT_CAPABILITY_NAMESPACE))
{
newCurrentNamespace = DEFAULT_CAPABILITY_NAMESPACE;
}
else if (!namespaces.isEmpty())
{
newCurrentNamespace = namespaces.iterator().next();
}
if (newCurrentNamespace != null)
{
currentNamespace = newCurrentNamespace;
analyzeInstallableUnits(monitor);
return;
}
}
final CapabilityItem[] capabilityItems = new CapabilityItem[versions.size()];
Iterator<String> iterator = versions.keySet().iterator();
for (int i = 0; i < capabilityItems.length; i++)
{
String id = iterator.next();
CapabilityItem capabilityItem = new CapabilityItem();
capabilityItem.setVersions(versions.get(id));
capabilityItem.setNamespace(currentNamespace);
capabilityItem.setLabel(id);
capabilityItems[i] = capabilityItem;
}
UIUtil.asyncExec(new Runnable()
{
public void run()
{
if (!container.isDisposed())
{
setItems(capabilityItems);
namespaceViewer.setInput(namespaces);
namespaceViewer.getCCombo().pack();
selectorComposite.getParent().layout();
UIUtil.asyncExec(new Runnable()
{
public void run()
{
if (!container.isDisposed() && currentNamespace != null)
{
namespaceViewer.setSelection(new StructuredSelection(currentNamespace));
}
}
});
}
}
});
}
}
/**
* @author Eike Stepper
*/
private final class RepositoryFocusListener implements FocusListener
{
private Color originalForeground;
public void focusGained(FocusEvent e)
{
if (originalForeground != null)
{
repositoryCombo.setText("");
repositoryCombo.setForeground(originalForeground);
originalForeground = null;
}
}
public void focusLost(FocusEvent e)
{
String activeRepository = RepositoryManager.INSTANCE.getActiveRepository();
if (activeRepository == null)
{
originalForeground = repositoryCombo.getForeground();
repositoryCombo.setText("type repository url, drag and drop, or pick from list");
repositoryCombo.setForeground(gray);
}
else
{
if (!activeRepository.equals(repositoryCombo.getText()))
{
repositoryCombo.setText(activeRepository);
}
}
}
}
/**
* @author Eike Stepper
*/
private final class RepositoryHistoryListener extends KeyAdapter implements ISelectionChangedListener
{
private boolean listVisible;
private String listRepository;
@Override
public void keyReleased(KeyEvent e)
{
boolean currentListVisible = repositoryCombo.getListVisible();
if (currentListVisible)
{
String repository = getSelectedRepository();
if (!StringUtil.isEmpty(repository))
{
listRepository = repository;
}
}
if (currentListVisible && (e.keyCode == SWT.DEL || e.keyCode == SWT.BS))
{
RepositoryManager.INSTANCE.removeRepository(listRepository);
}
else if (e.keyCode == SWT.CR && listVisible && !currentListVisible)
{
selectRepository();
}
listVisible = currentListVisible;
}
public void selectionChanged(SelectionChangedEvent event)
{
listVisible = repositoryCombo.getListVisible();
if (!listVisible)
{
selectRepository();
}
}
private void selectRepository()
{
String newRepository = getSelectedRepository();
activateAndLoadRepository(newRepository);
}
private String getSelectedRepository()
{
IStructuredSelection selection = (IStructuredSelection)repositoryViewer.getSelection();
return selection.isEmpty() ? repositoryCombo.getText() : (String)selection.getFirstElement();
}
}
/**
* @author Eike Stepper
*/
private final class RepositoryContentProvider implements IStructuredContentProvider, RepositoryManagerListener
{
public RepositoryContentProvider()
{
RepositoryManager.INSTANCE.addListener(this);
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
}
public void dispose()
{
RepositoryManager.INSTANCE.removeListener(this);
}
public Object[] getElements(Object element)
{
return RepositoryManager.INSTANCE.getRepositories();
}
public void repositoriesChanged(RepositoryManager repositoryManager)
{
UIUtil.asyncExec(new Runnable()
{
public void run()
{
if (!container.isDisposed())
{
repositoryViewer.refresh();
UIUtil.asyncExec(new Runnable()
{
public void run()
{
if (!container.isDisposed())
{
String activeRepository = RepositoryManager.INSTANCE.getActiveRepository();
if (activeRepository == null)
{
repositoryViewer.setSelection(StructuredSelection.EMPTY);
repositoryCombo.setText("");
}
else
{
ISelection selection = new StructuredSelection(activeRepository);
repositoryViewer.setSelection(selection);
repositoryCombo.setText(activeRepository);
repositoryCombo.setSelection(new Point(0, activeRepository.length()));
}
}
}
});
}
}
});
}
public void activeRepositoryChanged(RepositoryManager repositoryManager, String repository)
{
// Do nothing.
}
}
/**
* @author Eike Stepper
*/
private final class ItemContentProvider implements ITreeContentProvider
{
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
}
public void dispose()
{
}
public Object getParent(Object element)
{
return null;
}
public Object[] getElements(Object element)
{
return getChildren(element);
}
public Object[] getChildren(Object element)
{
Item[] children = ((Item)element).getChildren();
if (children != null)
{
return children;
}
return NO_ELEMENTS;
}
public boolean hasChildren(Object element)
{
return ((Item)element).hasChildren();
}
}
/**
* @author Eike Stepper
*/
private static final class ItemLabelProvider extends LabelProvider
{
@Override
public Image getImage(Object element)
{
Item item = (Item)element;
return item.getImage();
}
@Override
public String getText(Object element)
{
Item item = (Item)element;
return item.getLabel();
}
}
/**
* @author Eike Stepper
*/
private static final class VersionProvider extends LabelProvider implements IStructuredContentProvider
{
private static final Image IMAGE = P2UIPlugin.INSTANCE.getSWTImage("obj16/version");
private TableViewer versionsViewer;
private VersionSegment versionSegment;
public VersionProvider()
{
try
{
versionSegment = VersionSegment.get(SETTINGS.get(VERSION_SEGMENT_KEY));
}
catch (Exception ex)
{
//$FALL-THROUGH$
}
if (versionSegment == null)
{
versionSegment = VersionSegment.QUALIFIER;
}
}
public VersionSegment getVersionSegment()
{
return versionSegment;
}
public void setVersionSegment(VersionSegment versionSegment)
{
if (this.versionSegment != versionSegment)
{
this.versionSegment = versionSegment;
SETTINGS.put(VERSION_SEGMENT_KEY, versionSegment.getLiteral());
if (versionsViewer != null)
{
versionsViewer.refresh();
}
}
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
versionsViewer = (TableViewer)viewer;
}
@Override
public void dispose()
{
}
public Object[] getElements(Object inputElement)
{
if (inputElement instanceof VersionedItem)
{
VersionedItem versionedItem = (VersionedItem)inputElement;
Map<Version, IMatchExpression<IInstallableUnit>> versions = versionedItem.getVersions();
if (versions != null)
{
Set<ItemVersion> itemVersions = new HashSet<ItemVersion>();
for (Map.Entry<Version, IMatchExpression<IInstallableUnit>> entry : versions.entrySet())
{
ItemVersion itemVersion = getItemVersion(entry.getKey(), entry.getValue());
itemVersions.add(itemVersion);
}
ItemVersion[] array = itemVersions.toArray(new ItemVersion[itemVersions.size()]);
Arrays.sort(array);
return array;
}
}
return NO_ELEMENTS;
}
@Override
public Image getImage(Object element)
{
return IMAGE;
}
private ItemVersion getItemVersion(Version version, IMatchExpression<IInstallableUnit> filter)
{
int segments = version.getSegmentCount();
if (segments == 0)
{
return new ItemVersion(version, "0.0.0", filter);
}
segments = Math.min(segments, versionSegment.ordinal() + 1);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < segments; i++)
{
String segment = version.getSegment(i).toString();
if (StringUtil.isEmpty(segment))
{
break;
}
if (builder.length() != 0)
{
builder.append('.');
}
builder.append(segment);
}
version = Version.create(builder.toString());
if (segments < 3)
{
builder.append(".x");
}
return new ItemVersion(version, builder.toString(), filter);
}
/**
* @author Eike Stepper
*/
public static final class ItemVersion implements Comparable<ItemVersion>
{
private final Version version;
private final String label;
private final IMatchExpression<IInstallableUnit> filter;
public ItemVersion(Version version, String label, IMatchExpression<IInstallableUnit> filter)
{
this.version = version;
this.label = label;
this.filter = filter;
}
public Version getVersion()
{
return version;
}
public IMatchExpression<IInstallableUnit> getFilter()
{
return filter;
}
public int compareTo(ItemVersion o)
{
return version.compareTo(o.version);
}
@Override
public int hashCode()
{
return version.hashCode();
}
@Override
public boolean equals(Object obj)
{
return version.equals(((ItemVersion)obj).version);
}
@Override
public String toString()
{
return label;
}
}
}
/**
* @author Eike Stepper
*/
private static abstract class Item implements Comparable<Item>
{
protected static final Integer CATEGORY_ORDER = 0;
protected static final Integer NON_CATEGORY_ORDER = 1;
private String label;
public Item()
{
}
public abstract Image getImage();
public String getNamespace()
{
return IInstallableUnit.NAMESPACE_IU_ID;
}
public String getName()
{
return getLabel();
}
public String getLabel()
{
return label;
}
public void setLabel(String label)
{
this.label = label;
}
public Item[] getChildren()
{
return null;
}
public boolean hasChildren()
{
return false;
}
@Override
public String toString()
{
return label;
}
@Override
public final int hashCode()
{
return super.hashCode();
}
@Override
public final boolean equals(Object obj)
{
return super.equals(obj);
}
public int compareTo(Item o)
{
Integer category1 = getCategoryOrder();
Integer category2 = o.getCategoryOrder();
int result = category1.compareTo(category2);
if (result == 0)
{
String label1 = label.toLowerCase();
String label2 = o.label.toLowerCase();
result = label1.compareTo(label2);
}
return result;
}
protected Integer getCategoryOrder()
{
return NON_CATEGORY_ORDER;
}
}
/**
* @author Eike Stepper
*/
private static final class LoadingItem extends Item
{
private static final Image IMAGE = P2UIPlugin.INSTANCE.getSWTImage("obj16/repository");
private final URI location;
public LoadingItem(URI location)
{
this.location = location;
}
@Override
public Image getImage()
{
return IMAGE;
}
@Override
public String getLabel()
{
return "Loading " + location;
}
}
/**
* @author Eike Stepper
*/
private static final class ErrorItem extends Item
{
private final IStatus status;
public ErrorItem(IStatus status)
{
this.status = status;
}
@Override
public Image getImage()
{
return UIUtil.getStatusImage(status.getSeverity());
}
@Override
public String getLabel()
{
return status.getMessage();
}
}
/**
* @author Eike Stepper
*/
private static final class CategoryItem extends Item
{
private static final Image IMAGE = P2UIPlugin.INSTANCE.getSWTImage("obj16/category");
private Item[] children;
public CategoryItem()
{
}
@Override
public Image getImage()
{
return IMAGE;
}
@Override
public boolean hasChildren()
{
return children != null && children.length != 0;
}
@Override
public Item[] getChildren()
{
return children;
}
public void setChildren(Item[] children)
{
Arrays.sort(children);
this.children = children;
}
@Override
protected Integer getCategoryOrder()
{
return CATEGORY_ORDER;
}
}
/**
* @author Eike Stepper
*/
private static abstract class VersionedItem extends Item
{
private Map<Version, IMatchExpression<IInstallableUnit>> versions;
public VersionedItem()
{
}
public Map<Version, IMatchExpression<IInstallableUnit>> getVersions()
{
return versions;
}
public void setVersions(Map<Version, IMatchExpression<IInstallableUnit>> map)
{
versions = map;
}
}
/**
* @author Eike Stepper
*/
private static final class FeatureItem extends VersionedItem
{
private static final Image IMAGE = P2UIPlugin.INSTANCE.getSWTImage("obj16/artifactFeature");
private final String id;
public FeatureItem(String id)
{
this.id = id;
}
@Override
public Image getImage()
{
return IMAGE;
}
@Override
public String getName()
{
return id;
}
}
/**
* @author Eike Stepper
*/
private static final class PluginItem extends VersionedItem
{
private static final Image IMAGE = P2UIPlugin.INSTANCE.getSWTImage("obj16/artifactPlugin");
private final String id;
public PluginItem(String id)
{
this.id = id;
}
@Override
public Image getImage()
{
return IMAGE;
}
@Override
public String getName()
{
return id;
}
}
/**
* @author Eike Stepper
*/
private static final class CapabilityItem extends VersionedItem
{
private static final Image IMAGE = P2UIPlugin.INSTANCE.getSWTImage("obj16/capability");
private static final Image FEATURE_IMAGE = P2UIPlugin.INSTANCE.getSWTImage("obj16/artifactFeature");
private static final Image PLUGIN_IMAGE = P2UIPlugin.INSTANCE.getSWTImage("obj16/artifactPlugin");
private static final Image PACKAGE_IMAGE = P2UIPlugin.INSTANCE.getSWTImage("full/obj16/Requirement_Package");
private String namespace;
public CapabilityItem()
{
}
@Override
public String getNamespace()
{
return namespace;
}
public void setNamespace(String namespace)
{
this.namespace = namespace;
}
public void setVersions(Set<Version> versions)
{
Map<Version, IMatchExpression<IInstallableUnit>> map = new HashMap<Version, IMatchExpression<IInstallableUnit>>();
for (Version version : versions)
{
map.put(version, null);
}
setVersions(map);
}
@Override
public Image getImage()
{
if (IInstallableUnit.NAMESPACE_IU_ID.equals(namespace))
{
if (getLabel().endsWith(FEATURE_SUFFIX))
{
return FEATURE_IMAGE;
}
return PLUGIN_IMAGE;
}
if (RequirementItemProvider.NAMESPACE_PACKAGE_ID.equals(namespace))
{
return PACKAGE_IMAGE;
}
return IMAGE;
}
}
}