blob: 4b1489ed03fab3315ba87d730800d0d6383f89c1 [file] [log] [blame]
/*
* Copyright (c) 2014-2016 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.RepositoryList;
import org.eclipse.oomph.p2.Requirement;
import org.eclipse.oomph.p2.VersionSegment;
import org.eclipse.oomph.p2.core.Agent;
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.OomphDialog;
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.edit.ui.action.CopyAction;
import org.eclipse.emf.edit.ui.action.PasteAction;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
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.MetadataFactory;
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.ActionContributionItem;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
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.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CCombo;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
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.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
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.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.forms.FormColors;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.ViewPart;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @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());
static final int DND_OPERATIONS = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK;
static final List<? extends OomphTransferDelegate> DND_DELEGATES = Collections.singletonList(new OomphTransferDelegate.TextTransferDelegate());
public static final Transfer[] DND_TRANSFERS = new Transfer[] { DND_DELEGATES.get(0).getTransfer() };
static final List<? extends OomphTransferDelegate> DND_REPOSITORY_DELEGATES = Arrays
.asList(new OomphTransferDelegate[] { new OomphTransferDelegate.TextTransferDelegate(), new OomphTransferDelegate.FileTransferDelegate() });
public static final Transfer[] DND_REPOSITORY_TRANSFERS = new Transfer[] { DND_REPOSITORY_DELEGATES.get(0).getTransfer(),
DND_REPOSITORY_DELEGATES.get(1).getTransfer() };
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 SOURCE_FEATURE_SUFFIX = SOURCE_SUFFIX + Requirement.FEATURE_SUFFIX;
private static final Object[] NO_ELEMENTS = new Object[0];
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 RepositoryComboHandler repositoryComboHandler = new RepositoryComboHandler();
private final RepositoryHistoryListener repositoryHistoryListener = new RepositoryHistoryListener();
private final VersionProvider versionProvider = new VersionProvider();
private final CollapseAllAction collapseAllAction = new CollapseAllAction();
private final SearchAction searchAction = new SearchAction();
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;
private FormToolkit formToolkit;
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()
{
if (formToolkit != null)
{
formToolkit.dispose();
}
disposeRepositoryProvider();
super.dispose();
}
private void disposeRepositoryProvider()
{
if (repositoryProvider != null)
{
repositoryProvider.dispose();
repositoryProvider = null;
}
}
@Override
public void setFocus()
{
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);
}
}
});
itemsViewer.addDoubleClickListener(new IDoubleClickListener()
{
public void doubleClick(DoubleClickEvent event)
{
String id = getSelectedCapatiblityID(itemsViewer);
if (id != null)
{
showIUDetails(id, null);
}
}
});
collapseAllAction.updateEnablement();
analyzeJob.reschedule();
}
}
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 && !(mode instanceof CapabilitiesMode))
{
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();
formToolkit = new FormToolkit(display);
FormColors colors = formToolkit.getColors();
colors.createColor("initial_repository", FormColors.blend(colors.getForeground().getRGB(), colors.getBackground().getRGB(), 75));
Form form = formToolkit.createForm(parent);
container = form.getBody();
container.setLayout(new GridLayout(1, false));
createRepositoriesArea(container);
createItemsArea(container);
createVersionsArea(container);
updateMode();
String activeRepository = RepositoryManager.INSTANCE.getActiveRepository();
repositoryComboHandler.setActiveRepository(activeRepository);
if (activeRepository != null)
{
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(repositoryComboHandler);
repositoryCombo.addKeyListener(repositoryHistoryListener);
repositoryCombo.addMouseListener(new MouseAdapter()
{
@Override
public void mouseDown(MouseEvent e)
{
if (!repositoryCombo.isFocusControl())
{
repositoryCombo.setFocus();
}
}
});
repositoryViewer = new ComboViewer(repositoryCombo);
repositoryViewer.setContentProvider(new RepositoryContentProvider());
repositoryViewer.setLabelProvider(new LabelProvider());
repositoryViewer.setInput(RepositoryManager.INSTANCE);
repositoryViewer.addSelectionChangedListener(repositoryHistoryListener);
final GeneralDragAdapter generalDragAdapter = new GeneralDragAdapter(repositoryViewer, new GeneralDragAdapter.DraggedObjectsFactory()
{
public List<Object> createDraggedObjects(ISelection selection) throws Exception
{
List<Object> result = new ArrayList<Object>();
String text = repositoryCombo.getText();
Point selectionRange = repositoryCombo.getSelection();
if (selectionRange.y - selectionRange.x > 0)
{
result.add(text.substring(selectionRange.x, selectionRange.y));
}
return result;
}
}, DND_REPOSITORY_DELEGATES);
repositoryViewer.addDragSupport(DND_OPERATIONS, DND_TRANSFERS, generalDragAdapter);
final RepositoryList repositoryList = P2Factory.eINSTANCE.createRepositoryList();
repositoryViewer.addDropSupport(DND_OPERATIONS, DND_REPOSITORY_TRANSFERS,
new GeneralDropAdapter(repositoryViewer, repositoryList, 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);
}
}
}
}));
MenuManager contextMenu = generalDragAdapter.getContextMenu();
contextMenu.addMenuListener(new IMenuListener()
{
public void menuAboutToShow(IMenuManager manager)
{
ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
IContributionItem copyAction = manager.find(ActionFactory.COPY.getId());
if (copyAction == null)
{
Action generalCopyAction = new Action("Copy")
{
@Override
public void run()
{
repositoryCombo.copy();
}
};
Point selection = repositoryCombo.getSelection();
generalCopyAction.setEnabled(selection.y - selection.x > 0);
generalCopyAction.setId(ActionFactory.COPY.getId());
generalCopyAction.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
copyAction = new ActionContributionItem(generalCopyAction);
manager.add(copyAction);
}
Action cutAction = new Action("Cut")
{
@Override
public void run()
{
repositoryCombo.cut();
}
};
cutAction.setEnabled(copyAction.isEnabled());
cutAction.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_CUT));
manager.insertBefore(copyAction.getId(), cutAction);
PasteAction pasteAction = new PasteAction(generalDragAdapter.getEditingDomain())
{
@Override
public void run()
{
super.run();
Collection<?> result = command.getResult();
String repository = result.iterator().next().toString();
repositoryCombo.setText(repository);
repositoryCombo.setSelection(new Point(0, repository.length()));
repositoryHistoryListener.selectionChanged(null);
}
};
pasteAction.setText("Paste");
pasteAction.setEnabled(pasteAction.updateSelection(new StructuredSelection(repositoryList)));
Action generalPasteAction = pasteAction;
if (!pasteAction.isEnabled())
{
generalPasteAction = new Action("Paste")
{
@Override
public void run()
{
repositoryCombo.paste();
}
};
}
generalPasteAction.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE));
manager.add(generalPasteAction);
}
});
}
private void createItemsArea(Composite parent)
{
GridLayout containerLayout = new GridLayout(2, false);
containerLayout.marginWidth = 0;
containerLayout.marginHeight = 0;
Composite container = formToolkit.createComposite(parent, SWT.NONE);
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)
{
if (category != null)
{
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 = formToolkit.createComposite(container, SWT.NONE);
selectorComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
itemsComposite = formToolkit.createComposite(container, SWT.NONE);
itemsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
itemsComposite.setLayout(new FillLayout());
}
private void createVersionsArea(Composite container)
{
Composite versionsComposite = formToolkit.createComposite(container, SWT.NONE);
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);
versionsViewer.addDoubleClickListener(new IDoubleClickListener()
{
public void doubleClick(DoubleClickEvent event)
{
String id = getSelectedCapatiblityID(versionsViewer);
if (id != null)
{
Version version = getSelectedVersion(versionsViewer);
if (version != null)
{
showIUDetails(id, version);
}
}
}
});
formToolkit.adapt(versionsViewer.getControl(), false, false);
Composite versionsGroup = formToolkit.createComposite(versionsComposite, SWT.NONE);
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("search"));
toolbarManager.add(searchAction);
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 String getSelectedCapatiblityID(Viewer viewer)
{
Object firstItem = ((IStructuredSelection)viewer.getSelection()).getFirstElement();
if (firstItem instanceof VersionedItem)
{
VersionedItem item = (VersionedItem)firstItem;
return item.getName();
}
if (firstItem instanceof VersionProvider.ItemVersion)
{
VersionProvider.ItemVersion itemVersion = (VersionProvider.ItemVersion)firstItem;
return itemVersion.getItem().getName();
}
return null;
}
private Version getSelectedVersion(Viewer viewer)
{
Object firstVersion = ((IStructuredSelection)viewer.getSelection()).getFirstElement();
if (firstVersion instanceof VersionProvider.ItemVersion)
{
VersionProvider.ItemVersion itemVersion = (VersionProvider.ItemVersion)firstVersion;
return itemVersion.getVersion();
}
return null;
}
protected void showIUDetails(String id, Version version)
{
try
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IUWriter writer = new IUWriter(baos);
boolean first = true;
VersionRange versionRange = version == null ? VersionRange.emptyRange
: P2Factory.eINSTANCE.createVersionRange(version, versionProvider.getVersionSegment(), compatibleVersion);
IRequirement requirement = MetadataFactory.createRequirement(expertMode ? currentNamespace : DEFAULT_CAPABILITY_NAMESPACE, id, versionRange, null, true,
true, true);
IMatchExpression<IInstallableUnit> matches = requirement.getMatches();
IQueryResult<IInstallableUnit> query = installableUnits.query(QueryUtil.createMatchQuery(matches), new NullProgressMonitor());
List<Version> versions = new ArrayList<Version>();
int count = 0;
int limit = 100;
for (IInstallableUnit iu : P2Util.asIterable(query))
{
for (IProvidedCapability providedCapability : iu.getProvidedCapabilities())
{
if (currentNamespace.equals(providedCapability.getNamespace()) && id.equals(providedCapability.getName()))
{
Version providedCapabilityVersion = providedCapability.getVersion();
if (versionRange.isIncluded(providedCapabilityVersion))
{
versions.add(providedCapabilityVersion);
}
}
}
if (++count <= limit)
{
if (first)
{
first = false;
}
else
{
writer.newLine();
}
writer.writeInstallableUnit(iu);
writer.flush();
}
}
if (count > limit)
{
writer.newLine();
writer.writeString(count - limit + " more...");
writer.newLine();
}
String xml = baos.toString("UTF-8");
new IUDialog(getSite().getShell(), xml, expertMode ? currentNamespace : null, id, versions).open();
}
catch (Exception ex)
{
P2UIPlugin.INSTANCE.log(ex);
}
}
private void addDragSupport(final StructuredViewer viewer)
{
final GeneralDragAdapter.DraggedObjectsFactory draggedObjectsFactory = new GeneralDragAdapter.DraggedObjectsFactory()
{
public List<Object> createDraggedObjects(ISelection selection) throws Exception
{
List<Object> result = new ArrayList<Object>();
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 = getFilter(itemVersion.getFilters());
element = itemVersion.getItem();
}
if (element instanceof Item && !(element instanceof StatusItem) && !(element instanceof LoadingItem))
{
Item item = (Item)element;
String namespace = item.getNamespace();
if (namespace != null)
{
if (filter == null && item instanceof VersionedItem)
{
VersionedItem versionedItem = (VersionedItem)item;
Set<IMatchExpression<IInstallableUnit>> allFilters = new LinkedHashSet<IMatchExpression<IInstallableUnit>>();
for (Set<IMatchExpression<IInstallableUnit>> filterSets : versionedItem.getVersions().values())
{
allFilters.addAll(filterSets);
}
filter = getFilter(allFilters);
}
Requirement requirement = P2Factory.eINSTANCE.createRequirement();
requirement.setNamespace(namespace);
requirement.setName(item.getName());
requirement.setVersionRange(versionRange);
requirement.setFilter(filter);
result.add(requirement);
}
}
}
return result;
}
};
final GeneralDragAdapter generalDragAdapter = new GeneralDragAdapter(viewer, draggedObjectsFactory, DND_DELEGATES);
viewer.addDragSupport(DND_OPERATIONS, DND_TRANSFERS, generalDragAdapter);
final CopyAction copyAction = new CopyAction(generalDragAdapter.getEditingDomain());
try
{
ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
copyAction.setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_COPY));
copyAction.setText("Copy with Version Range");
}
catch (RuntimeException ex)
{
// Ignore it if we can't set an image.
}
MenuManager contextMenu = generalDragAdapter.getContextMenu();
final CopyAction simpleCopyAction = generalDragAdapter.getCopyAction();
viewer.getControl().addFocusListener(new FocusListener()
{
public void focusLost(FocusEvent e)
{
getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.COPY.getId(), null);
}
public void focusGained(FocusEvent e)
{
getViewSite().getActionBars().setGlobalActionHandler(ActionFactory.COPY.getId(), simpleCopyAction);
}
});
viewer.addSelectionChangedListener(new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
List<Object> selectedObjects = new ArrayList<Object>();
try
{
selectedObjects.addAll(draggedObjectsFactory.createDraggedObjects(event.getSelection()));
}
catch (Exception ex)
{
P2UIPlugin.INSTANCE.log(ex);
}
simpleCopyAction.setEnabled(simpleCopyAction.updateSelection(new StructuredSelection(selectedObjects)));
}
});
contextMenu.addMenuListener(new IMenuListener()
{
final Action showDetailsAction = new Action("Show Details...")
{
@Override
public void run()
{
String id = getSelectedCapatiblityID(viewer);
if (id != null)
{
showIUDetails(id, getSelectedVersion(viewer));
}
}
};
public void menuAboutToShow(IMenuManager manager)
{
IStructuredSelection selection = (IStructuredSelection)viewer.getSelection();
List<Object> versionItems = new ArrayList<Object>();
for (Object object : selection.toArray())
{
Object[] elements = versionProvider.getElements(object);
if (elements.length > 0)
{
versionItems.add(elements[elements.length - 1]);
}
}
try
{
List<Object> draggedObjects = draggedObjectsFactory.createDraggedObjects(new StructuredSelection(versionItems));
if (!draggedObjects.isEmpty())
{
copyAction.updateSelection(new StructuredSelection(draggedObjects));
manager.add(copyAction);
manager.add(new Separator());
manager.add(showDetailsAction);
}
}
catch (Exception ex)
{
P2UIPlugin.INSTANCE.log(ex);
}
}
});
}
private String getFilter(Set<IMatchExpression<IInstallableUnit>> filters)
{
if (filters.contains(null))
{
return null;
}
Set<String> expressions = new LinkedHashSet<String>();
for (IMatchExpression<IInstallableUnit> filter : filters)
{
expressions.add(RequirementImpl.formatMatchExpression(filter));
}
if (expressions.size() == 1)
{
return expressions.iterator().next();
}
StringBuilder result = new StringBuilder("");
for (String expression : expressions)
{
if (result.length() == 0)
{
result.append("(|");
}
result.append(expression);
}
result.append(')');
return result.toString();
}
private static String[] sortStrings(Collection<String> c)
{
String[] array = c.toArray(new String[c.size()]);
Arrays.sort(array);
return array;
}
static void minimizeNamespaces(Set<String> flavors, Set<String> namespaces)
{
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;
}
}
}
}
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 boolean isCategory(IInstallableUnit iu)
{
return "true".equalsIgnoreCase(iu.getProperty(QueryUtil.PROP_TYPE_CATEGORY));
}
private static boolean isFeature(IInstallableUnit iu)
{
return iu.getId().endsWith(Requirement.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
*/
@SuppressWarnings("restriction")
private static final class IUWriter extends org.eclipse.equinox.internal.p2.metadata.repository.io.MetadataWriter
{
private ByteArrayOutputStream output;
public IUWriter(ByteArrayOutputStream output) throws UnsupportedEncodingException
{
super(output, null);
this.output = output;
flush();
output.reset();
}
@Override
public void writeInstallableUnit(IInstallableUnit resolvedIU)
{
// Just make this method publicly available.
super.writeInstallableUnit(resolvedIU);
}
@Override
public void flush()
{
// Just make this method publicly available.
super.flush();
}
public void newLine()
{
writeString(StringUtil.NL);
}
public void writeString(String string)
{
try
{
byte[] bytes = string.getBytes("UTF-8");
output.write(bytes, 0, bytes.length);
}
catch (Exception ex)
{
P2UIPlugin.INSTANCE.log(ex);
}
}
}
/**
* @author Eike Stepper
*/
private static final class IUDialog extends OomphDialog
{
public static final String TITLE = "Installable Unit Details";
private final String xml;
private Pattern pattern;
public IUDialog(Shell parentShell, String xml, String namespace, String id, List<Version> versions)
{
super(parentShell, TITLE, 900, 750, P2UIPlugin.INSTANCE, false);
setShellStyle(SWT.TITLE | SWT.MAX | SWT.RESIZE | SWT.BORDER | SWT.APPLICATION_MODAL);
this.xml = xml;
StringBuilder expression = new StringBuilder();
if (namespace == null)
{
expression.append("<unit[^>]+'>");
}
else
{
expression.append("<provided namespace='").append(namespace).append("' name='").append(id).append("' version='(");
for (int i = 0, size = versions.size(); i < size; ++i)
{
if (i != 0)
{
expression.append('|');
}
expression.append(versions.get(i));
}
expression.append(")'/>");
}
pattern = Pattern.compile(expression.toString());
}
@Override
protected String getShellText()
{
return TITLE;
}
@Override
protected String getDefaultMessage()
{
return "Browse the XML representation of the selected installable units.";
}
@Override
protected String getImagePath()
{
return "wizban/ProfileDetails.png";
}
@Override
protected void createUI(Composite parent)
{
StyledText text = new StyledText(parent, SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL);
text.setBackground(text.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
text.setLayoutData(new GridData(GridData.FILL_BOTH));
text.setText(xml);
text.setEditable(false);
List<StyleRange> styleRanges = new ArrayList<StyleRange>();
for (Matcher matcher = pattern.matcher(xml); matcher.find();)
{
StyleRange styleRange = new StyleRange();
styleRange.start = matcher.start();
styleRange.length = matcher.end() - styleRange.start;
styleRange.fontStyle = SWT.BOLD;
styleRanges.add(styleRange);
}
text.setStyleRanges(styleRanges.toArray(new StyleRange[styleRanges.size()]));
}
@Override
protected void createButtonsForButtonBar(Composite parent)
{
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.CLOSE_LABEL, true);
}
}
/**
* @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 Ed Merks
*/
private final class SearchAction extends Action
{
public SearchAction()
{
super("Search", Action.AS_CHECK_BOX);
setImageDescriptor(P2UIPlugin.INSTANCE.getImageDescriptor("tool16/search"));
setToolTipText("Search Eclipse repositories by provided capabilities");
}
@Override
public void run()
{
if (isChecked())
{
final SearchEclipseRepositoryDialog searchEclipseRepositoryDialog = SearchEclipseRepositoryDialog.openFor(getSite().getWorkbenchWindow());
searchEclipseRepositoryDialog.getDockable().associate(this);
searchEclipseRepositoryDialog.getShell().addDisposeListener(new DisposeListener()
{
public void widgetDisposed(DisposeEvent e)
{
if (searchEclipseRepositoryDialog.getReturnCode() == Dialog.OK)
{
try
{
getViewSite().getWorkbenchWindow().getActivePage().showView(ID);
activateAndLoadRepository(searchEclipseRepositoryDialog.getSelectedRepository());
}
catch (PartInitException ex)
{
// This should never happen.
}
}
}
});
}
else
{
SearchEclipseRepositoryDialog.closeFor(getSite().getWorkbenchWindow());
}
}
}
/**
* @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 StatusItem(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;
Agent agent = P2Util.getAgentManager().getCurrentAgent();
agent.flushRepositoryCaches();
IMetadataRepositoryManager repositoryManager = agent.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 StatusItem(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 : P2Util.asIterable(installableUnits))
{
P2UIPlugin.checkCancelation(monitor);
String id = iu.getId();
names.put(id, P2Util.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()
{
if (roots.length == 0)
{
setItems(new Item[] { new StatusItem(new Status(IStatus.WARNING, P2UIPlugin.INSTANCE.getSymbolicName(),
"No categorized items " + (filter == null ? "" : "matching '" + filter + "'") + ". Disable 'Group items by category' to see more.")) });
}
else
{
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, Set<IMatchExpression<IInstallableUnit>>>> versions = new HashMap<Item, Map<Version, Set<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);
if (set != null)
{
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()) + Requirement.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, Set<IMatchExpression<IInstallableUnit>>> map = versions.get(child);
if (map == null)
{
map = new HashMap<Version, Set<IMatchExpression<IInstallableUnit>>>();
versions.put(child, map);
}
CollectionUtil.add(map, version, matchExpression);
}
}
}
}
}
}
}
}
for (Map.Entry<Item, Map<Version, Set<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(categoryID);
Map<Version, Set<IMatchExpression<IInstallableUnit>>> map = new LinkedHashMap<Version, Set<IMatchExpression<IInstallableUnit>>>();
for (IInstallableUnit categoryIU : ius.get(categoryID))
{
CollectionUtil.add(map, categoryIU.getVersion(), categoryIU.getFilter());
}
categoryItem.setLabel(names.get(categoryID));
categoryItem.setChildren(children.values().toArray(new Item[children.size()]));
categoryItem.setVersions(map);
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, Set<IMatchExpression<IInstallableUnit>>>> versions = new HashMap<String, Map<Version, Set<IMatchExpression<IInstallableUnit>>>>();
for (IInstallableUnit iu : P2Util.asIterable(installableUnits))
{
P2UIPlugin.checkCancelation(monitor);
String id = iu.getId();
if (id.endsWith(Requirement.FEATURE_SUFFIX) && !id.endsWith(SOURCE_FEATURE_SUFFIX))
{
String name = P2Util.getName(iu);
if (isFiltered(name))
{
names.put(id, name);
Version version = iu.getVersion();
IMatchExpression<IInstallableUnit> filter = iu.getFilter();
Map<Version, Set<IMatchExpression<IInstallableUnit>>> map = versions.get(id);
if (map == null)
{
map = new HashMap<Version, Set<IMatchExpression<IInstallableUnit>>>();
versions.put(id, map);
}
CollectionUtil.add(map, 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, Set<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()
{
if (featureItems.length == 0)
{
setItems(new Item[] { new StatusItem(new Status(IStatus.WARNING, P2UIPlugin.INSTANCE.getSymbolicName(),
"No feature items " + (filter == null ? "" : "matching '" + filter + "'") + ". Enable 'Expert mode' to see more.")) });
}
else
{
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.setComparator(new ViewerComparator());
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 (newNamespace != null && !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, Map<Version, Set<IMatchExpression<IInstallableUnit>>>> versions = new HashMap<String, Map<Version, Set<IMatchExpression<IInstallableUnit>>>>();
for (IInstallableUnit iu : P2Util.asIterable(installableUnits))
{
IMatchExpression<IInstallableUnit> filter = iu.getFilter();
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 = Version.emptyVersion;
}
Map<Version, Set<IMatchExpression<IInstallableUnit>>> map = versions.get(name);
if (map == null)
{
map = new LinkedHashMap<Version, Set<IMatchExpression<IInstallableUnit>>>();
versions.put(name, map);
}
CollectionUtil.add(map, version, filter);
}
}
}
minimizeNamespaces(flavors, namespaces);
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())
{
if (capabilityItems.length == 0)
{
setItems(new Item[] { new StatusItem(new Status(IStatus.WARNING, P2UIPlugin.INSTANCE.getSymbolicName(),
"No items " + (filter == null ? "" : "matching '" + filter + "'") + ".")) });
}
else
{
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 RepositoryComboHandler implements FocusListener
{
private static final String INITIAL_REPOSITORY_TEXT = "type repository url, drag and drop, or pick from list";
private Color initialTextForegroundColor;
private Color originalForeground;
public void setActiveRepository(String activeRepository)
{
repositoryCombo.setForeground(getForegroundColor(activeRepository));
repositoryCombo.setText(activeRepository == null ? repositoryCombo.isFocusControl() ? "" : INITIAL_REPOSITORY_TEXT : activeRepository);
}
private Color getForegroundColor(String activeRepository)
{
if (originalForeground == null)
{
originalForeground = repositoryCombo.getForeground();
}
if (initialTextForegroundColor == null)
{
initialTextForegroundColor = formToolkit.getColors().getColor("initial_repository");
}
return activeRepository == null && !repositoryCombo.isFocusControl() ? initialTextForegroundColor : originalForeground;
}
public void focusGained(FocusEvent e)
{
if (repositoryCombo.getText().equals(INITIAL_REPOSITORY_TEXT))
{
setActiveRepository("");
}
}
public void focusLost(FocusEvent e)
{
if (StringUtil.isEmpty(repositoryCombo.getText().trim()))
{
setActiveRepository(null);
}
}
}
/**
* @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(container, new Runnable()
{
public void run()
{
repositoryViewer.refresh();
UIUtil.asyncExec(container, new Runnable()
{
public void run()
{
String activeRepository = RepositoryManager.INSTANCE.getActiveRepository();
if (activeRepository == null)
{
repositoryViewer.setSelection(StructuredSelection.EMPTY);
repositoryComboHandler.setActiveRepository(activeRepository);
}
else
{
ISelection selection = new StructuredSelection(activeRepository);
repositoryViewer.setSelection(selection);
repositoryComboHandler.setActiveRepository(activeRepository);
repositoryCombo.setSelection(new Point(0, activeRepository.length()));
}
}
});
}
});
}
public void activeRepositoryChanged(RepositoryManager repositoryManager, String repository)
{
repositoryComboHandler.setActiveRepository(repository);
}
}
/**
* @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, Set<IMatchExpression<IInstallableUnit>>> versions = versionedItem.getVersions();
if (versions != null)
{
Set<ItemVersion> itemVersions = new HashSet<ItemVersion>();
for (Map.Entry<Version, Set<IMatchExpression<IInstallableUnit>>> entry : versions.entrySet())
{
ItemVersion itemVersion = getItemVersion(versionedItem, 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(VersionedItem item, Version version, Set<IMatchExpression<IInstallableUnit>> filters)
{
int segments = version.getSegmentCount();
if (segments == 0)
{
return new ItemVersion(item, version, "0.0.0", filters);
}
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(item, version, builder.toString(), filters);
}
/**
* @author Eike Stepper
*/
public static final class ItemVersion implements Comparable<ItemVersion>
{
private final VersionedItem item;
private final Version version;
private final String label;
private final Set<IMatchExpression<IInstallableUnit>> filters;
public ItemVersion(VersionedItem item, Version version, String label, Set<IMatchExpression<IInstallableUnit>> filters)
{
this.item = item;
this.version = version;
this.label = label;
this.filters = filters;
}
public VersionedItem getItem()
{
return item;
}
public Version getVersion()
{
return version;
}
public Set<IMatchExpression<IInstallableUnit>> getFilters()
{
return filters;
}
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 = StringUtil.safe(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 StatusItem extends Item
{
private final IStatus status;
public StatusItem(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 VersionedItem
{
private static final Image IMAGE = P2UIPlugin.INSTANCE.getSWTImage("obj16/category");
private Item[] children;
private String name;
public CategoryItem()
{
}
public CategoryItem(String name)
{
this.name = name;
}
@Override
public String getName()
{
return name;
}
@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, Set<IMatchExpression<IInstallableUnit>>> versions;
public VersionedItem()
{
}
public Map<Version, Set<IMatchExpression<IInstallableUnit>>> getVersions()
{
return versions;
}
public void setVersions(Map<Version, Set<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;
}
@Override
public Image getImage()
{
if (IInstallableUnit.NAMESPACE_IU_ID.equals(namespace))
{
if (getLabel().endsWith(Requirement.FEATURE_SUFFIX))
{
return FEATURE_IMAGE;
}
return PLUGIN_IMAGE;
}
if (RequirementItemProvider.NAMESPACE_PACKAGE_ID.equals(namespace))
{
return PACKAGE_IMAGE;
}
return IMAGE;
}
}
}