/*******************************************************************************
* Copyright (c) 2008, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Sonatype, Inc. - ongoing development
*******************************************************************************/
package org.eclipse.equinox.internal.p2.ui.dialogs;
import java.net.URI;
import java.util.ArrayList;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.*;
import org.eclipse.equinox.internal.p2.ui.*;
import org.eclipse.equinox.internal.p2.ui.model.*;
import org.eclipse.equinox.internal.p2.ui.query.IUViewQueryContext;
import org.eclipse.equinox.internal.p2.ui.viewers.*;
import org.eclipse.equinox.internal.provisional.p2.repository.RepositoryEvent;
import org.eclipse.equinox.p2.core.ProvisionException;
import org.eclipse.equinox.p2.metadata.IInstallableUnit;
import org.eclipse.equinox.p2.repository.IRepositoryManager;
import org.eclipse.equinox.p2.ui.LoadMetadataRepositoryJob;
import org.eclipse.equinox.p2.ui.ProvisioningUI;
import org.eclipse.jface.viewers.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
/**
* An AvailableIUGroup is a reusable UI component that displays the
* IU's available for installation. By default, content from all available
* repositories is shown.
*
* @since 3.4
*/
public class AvailableIUGroup extends StructuredIUGroup {
/**
* Show contents from all repositories
*/
public static final int AVAILABLE_ALL = 1;
/**
* Don't show any repository content
*/
public static final int AVAILABLE_NONE = 2;
/**
* Show local repository content
*/
public static final int AVAILABLE_LOCAL = 3;
/**
* Show content for a specific repository
*/
public static final int AVAILABLE_SPECIFIED = 4;
IUViewQueryContext queryContext;
int filterConstant = AVAILABLE_ALL;
URI repositoryFilter;
QueryableMetadataRepositoryManager queryableManager;
// We restrict the type of the filter used because PatternFilter does
// unnecessary accesses of children that cause problems with the deferred
// tree.
AvailableIUPatternFilter filter;
private boolean useBold = false;
private IUDetailsLabelProvider labelProvider;
private int repoFlags;
Display display;
DelayedFilterCheckboxTree filteredTree;
Job lastRequestedLoadJob;
/**
* Create a group that represents the available IU's from all available
* repositories. The default policy controls the visibility flags for
* repositories and IU's.
*
* @param parent the parent composite for the group
*/
public AvailableIUGroup(ProvisioningUI ui, final Composite parent) {
this(ui, parent, parent.getFont(), null, getDefaultColumnConfig(), AVAILABLE_ALL);
}
private static IUColumnConfig[] getDefaultColumnConfig() {
// increase primary column width because we might be nesting names under categories and require more space than a flat list
IUColumnConfig nameColumn = new IUColumnConfig(ProvUIMessages.ProvUI_NameColumnTitle, IUColumnConfig.COLUMN_NAME, ILayoutConstants.DEFAULT_PRIMARY_COLUMN_WIDTH + 15);
IUColumnConfig versionColumn = new IUColumnConfig(ProvUIMessages.ProvUI_VersionColumnTitle, IUColumnConfig.COLUMN_VERSION, ILayoutConstants.DEFAULT_COLUMN_WIDTH);
return new IUColumnConfig[] {nameColumn, versionColumn};
}
/**
* Create a group that represents the available IU's.
*
* @param ui the policy to use for deciding what should be shown
* @param parent the parent composite for the group
* @param font The font to use for calculating pixel sizes. This font is
* not managed by the receiver.
* @param queryContext the IUViewQueryContext that determines additional
* information about what is shown, such as the visible repositories
* @param columnConfig the description of the columns that should be shown. If null, a default
* will be used.
* @param filterConstant a constant specifying which repositories are used when showing content
*/
public AvailableIUGroup(ProvisioningUI ui, final Composite parent, Font font, IUViewQueryContext queryContext, IUColumnConfig[] columnConfig, int filterConstant) {
super(ui, parent, font, columnConfig);
this.display = parent.getDisplay();
if (queryContext == null)
this.queryContext = ProvUI.getQueryContext(getPolicy());
else
this.queryContext = queryContext;
repoFlags = ui.getRepositoryTracker().getMetadataRepositoryFlags();
this.queryableManager = new QueryableMetadataRepositoryManager(ui, false);
this.filterConstant = filterConstant;
this.filter = new AvailableIUPatternFilter(getColumnConfig());
this.filter.setIncludeLeadingWildcard(true);
createGroupComposite(parent);
}
protected StructuredViewer createViewer(Composite parent) {
// Table of available IU's
filteredTree = new DelayedFilterCheckboxTree(parent, SWT.MULTI | SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER, filter, getPreFilterJobProvider());
final TreeViewer availableIUViewer = filteredTree.getViewer();
// If the user expanded or collapsed anything while we were loading a repo
// in the background, we would not want to disrupt their work by making
// a newly loaded visible and expanding it. Setting the load job to null
// will take care of this.
availableIUViewer.getTree().addTreeListener(new TreeListener() {
public void treeCollapsed(TreeEvent e) {
lastRequestedLoadJob = null;
}
public void treeExpanded(TreeEvent e) {
lastRequestedLoadJob = null;
}
});
labelProvider = new IUDetailsLabelProvider(filteredTree, getColumnConfig(), getShell());
labelProvider.setUseBoldFontForFilteredItems(useBold);
labelProvider.setToolTipProperty(IInstallableUnit.PROP_DESCRIPTION);
// Filters and sorters before establishing content, so we don't refresh unnecessarily.
IUComparator comparator = new IUComparator(IUComparator.IU_NAME);
comparator.useColumnConfig(getColumnConfig());
availableIUViewer.setComparator(comparator);
availableIUViewer.setComparer(new ProvElementComparer());
// Now the content provider.
DeferredQueryContentProvider contentProvider = new DeferredQueryContentProvider();
availableIUViewer.setContentProvider(contentProvider);
// Now the presentation, columns before label provider.
setTreeColumns(availableIUViewer.getTree());
availableIUViewer.setLabelProvider(labelProvider);
// Notify the filtered tree so that it can hook listeners on the
// content provider. This is needed so that filtering is only allowed
// after content has been retrieved.
filteredTree.contentProviderSet(contentProvider);
final StructuredViewerProvisioningListener listener = new StructuredViewerProvisioningListener(getClass().getName(), availableIUViewer, ProvUIProvisioningListener.PROV_EVENT_METADATA_REPOSITORY, getProvisioningUI().getOperationRunner()) {
protected void repositoryAdded(final RepositoryEvent event) {
makeRepositoryVisible(event.getRepositoryLocation());
}
protected void refreshViewer() {
final TreeViewer treeViewer = filteredTree.getViewer();
final Tree tree = treeViewer.getTree();
IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench.isClosing())
return;
if (tree != null && !tree.isDisposed()) {
updateAvailableViewState();
}
}
};
ProvUI.getProvisioningEventBus(getProvisioningUI().getSession()).addListener(listener);
availableIUViewer.getControl().addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
ProvUI.getProvisioningEventBus(getProvisioningUI().getSession()).removeListener(listener);
}
});
updateAvailableViewState();
return availableIUViewer;
}
private void setTreeColumns(Tree tree) {
tree.setHeaderVisible(true);
IUColumnConfig[] cols = getColumnConfig();
for (int i = 0; i < cols.length; i++) {
TreeColumn tc = new TreeColumn(tree, SWT.NONE, i);
tc.setResizable(true);
tc.setText(cols[i].getColumnTitle());
tc.setWidth(cols[i].getWidthInPixels(tree));
}
}
Object getNewInput() {
if (repositoryFilter != null) {
return new MetadataRepositoryElement(queryContext, getProvisioningUI(), repositoryFilter, true);
} else if (filterConstant == AVAILABLE_NONE) {
// Dummy object that explains empty site list
return new ProvElement(null) {
public Object[] getChildren(Object o) {
String description;
String name;
int severity;
if (!getPolicy().getRepositoriesVisible()) {
// shouldn't get here ideally. No sites and no way to add any.
severity = IStatus.ERROR;
name = ProvUIMessages.AvailableIUGroup_NoSitesConfiguredExplanation;
description = ProvUIMessages.AvailableIUGroup_NoSitesConfiguredDescription;
} else {
severity = IStatus.INFO;
name = ProvUIMessages.AvailableIUGroup_NoSitesExplanation;
description = ProvUIMessages.ColocatedRepositoryManipulator_NoContentExplanation;
}
return new Object[] {new EmptyElementExplanation(null, severity, name, description)};
}
public String getLabel(Object o) {
// Label not needed for input
return null;
}
};
} else {
queryableManager.setRespositoryFlags(repoFlags);
return new MetadataRepositories(queryContext, getProvisioningUI(), queryableManager);
}
}
/**
* Set a boolean indicating whether a bold font should be used when
* showing filtered items. This method does not refresh the tree or
* labels, so that must be done explicitly by the caller.
* @param useBoldFont
*/
public void setUseBoldFontForFilteredItems(boolean useBoldFont) {
if (labelProvider != null)
labelProvider.setUseBoldFontForFilteredItems(useBoldFont);
}
/**
* Return the composite that contains the controls in this group.
* @return the composite
*/
public Composite getComposite() {
return super.getComposite();
}
/**
* Get the viewer used to represent the available IU's
* @return the viewer
*/
public StructuredViewer getStructuredViewer() {
return super.getStructuredViewer();
}
/**
* Get the selected IU's
* @return the array of selected IU's
*/
// overridden for visibility in the public package
public java.util.List getSelectedIUs() {
return super.getSelectedIUs();
}
// overridden to weed out non-IU elements, such as repositories or empty explanations
public Object[] getSelectedIUElements() {
Object[] elements = ((IStructuredSelection) viewer.getSelection()).toArray();
ArrayList