blob: ceb02f621772a66730d675a7e825efec06bb3bc2 [file] [log] [blame]
package org.eclipse.update.internal.ui.search;
import java.net.URL;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.update.configuration.*;
import org.eclipse.update.core.*;
import org.eclipse.update.internal.ui.UpdateUIPlugin;
import org.eclipse.update.internal.ui.forms.ActivityConstraints;
import org.eclipse.update.internal.ui.model.*;
import org.eclipse.update.internal.ui.parts.*;
import org.eclipse.update.internal.ui.preferences.MainPreferencePage;
import org.eclipse.update.ui.forms.internal.FormWidgetFactory;
public class UpdatesSearchCategory extends SearchCategory {
private static final String KEY_CURRENT_SEARCH =
"UpdatesSearchCategory.currentSearch";
private CheckboxTableViewer tableViewer;
class FeatureContentProvider
extends DefaultContentProvider
implements IStructuredContentProvider {
public Object[] getElements(Object parent) {
if (candidates == null)
return new Object[0];
return candidates.toArray();
}
}
class FeatureLabelProvider extends LabelProvider {
public String getText(Object obj) {
if (obj instanceof IFeatureReference) {
IFeatureReference fref = (IFeatureReference)obj;
try {
return fref.getVersionedIdentifier().toString();
}
catch (CoreException e) {
}
}
return obj.toString();
}
}
class Hit {
IFeature candidate;
IFeatureReference ref;
public Hit(IFeature candidate, IFeatureReference ref) {
this.candidate = candidate;
this.ref = ref;
}
public PendingChange getJob() {
try {
IFeature feature = ref.getFeature();
return new PendingChange(candidate, feature);
} catch (CoreException e) {
return null;
}
}
}
class SiteAdapter implements ISiteAdapter {
IURLEntry entry;
SiteAdapter(IURLEntry entry) {
this.entry = entry;
}
public URL getURL() {
return entry.getURL();
}
public String getLabel() {
String label = entry.getAnnotation();
if (label == null || label.length() == 0)
label = getURL().toString();
return label;
}
public ISite getSite() {
try {
return SiteManager.getSite(getURL());
} catch (CoreException e) {
return null;
}
}
}
class HitSorter extends Sorter {
public boolean compare(Object left, Object right) {
Hit hit1 = (Hit) left;
Hit hit2 = (Hit) right;
try {
VersionedIdentifier hv1 = hit1.ref.getVersionedIdentifier();
VersionedIdentifier hv2 = hit2.ref.getVersionedIdentifier();
return isNewerVersion(hv2, hv1);
} catch (CoreException e) {
return false;
}
}
}
class UpdateQuery implements ISearchQuery {
IFeature candidate;
ISiteAdapter adapter;
int match = IImport.RULE_PERFECT;
public UpdateQuery(IFeature candidate) {
this.candidate = candidate;
IURLEntry entry = candidate.getUpdateSiteEntry();
if (entry != null && entry.getURL() != null)
adapter = new SiteAdapter(entry);
}
public UpdateQuery(IFeature candidate, int match) {
this(candidate);
this.match = match;
}
public ISiteAdapter getSearchSite() {
return adapter;
}
private boolean isBroken() {
try {
IStatus status =
SiteManager.getLocalSite().getFeatureStatus(candidate);
return status.getSeverity() == IStatus.ERROR;
} catch (CoreException e) {
return false;
}
}
private boolean isMissingOptionalChildren(IFeature feature) {
try {
IFeatureReference [] children=feature.getIncludedFeatureReferences();
for (int i=0; i<children.length; i++) {
IFeatureReference ref = children[i];
try {
IFeature child = ref.getFeature();
// If we are here, the child is not missing.
// Check it's children recursively.
if (isMissingOptionalChildren(child))
return true;
}
catch (CoreException e) {
// Missing child. Return true if optional,
// otherwise it is a broken feature that we
// do not care about.
if (ref.isOptional()) {
return true;
}
}
}
}
catch (CoreException e) {
}
return false;
}
public IFeature[] getMatchingFeatures(
ISite site,
IProgressMonitor monitor) {
ArrayList hits = new ArrayList();
boolean broken = isBroken();
boolean missingOptionalChildren = false;
// Don't bother to compute missing optional children
// if the feature is broken - all we want is to
// see if we should allow same-version re-install.
if (!broken)
missingOptionalChildren = isMissingOptionalChildren(candidate);
IFeatureReference[] refs = site.getFeatureReferences();
monitor.beginTask("", refs.length + 1);
for (int i = 0; i < refs.length; i++) {
IFeatureReference ref = refs[i];
try {
if (isNewerVersion(candidate.getVersionedIdentifier(),
ref.getVersionedIdentifier(), match)) {
hits.add(new Hit(candidate, ref));
} else {
// accept the same feature if the installed
// feature is broken
if ((broken || missingOptionalChildren)
&& candidate.getVersionedIdentifier().equals(
ref.getVersionedIdentifier()))
hits.add(new Hit(candidate, ref));
}
} catch (CoreException e) {
}
monitor.worked(1);
if (monitor.isCanceled())
return new IFeature[0];
}
IFeature[] result;
if (hits.size() == 0)
result = new IFeature[0];
else {
IFeature topHit = getFirstValid(hits);
if (topHit == null)
result = new IFeature[0];
else
result = new IFeature[] { topHit };
}
monitor.worked(1);
monitor.done();
return result;
}
}
private ArrayList candidates;
public UpdatesSearchCategory() {
}
private IFeature getFirstValid(ArrayList hits) {
Object[] array = hits.toArray();
HitSorter sorter = new HitSorter();
sorter.sortInPlace(array);
for (int i = 0; i < array.length; i++) {
Hit hit = (Hit) array[i];
PendingChange job = hit.getJob();
if (job == null)
continue;
// do not accept updates without a license
if (!UpdateModel.hasLicense(job))
continue;
IStatus status = ActivityConstraints.validatePendingChange(job);
if (status == null)
return job.getFeature();
}
// no valid hits
return null;
}
public void initialize() {
candidates = new ArrayList();
try {
ILocalSite localSite = SiteManager.getLocalSite();
IInstallConfiguration config = localSite.getCurrentConfiguration();
IConfiguredSite[] isites = config.getConfiguredSites();
for (int i = 0; i < isites.length; i++) {
IFeatureReference[] refs = isites[i].getConfiguredFeatures();
ArrayList candidatesPerSite = new ArrayList();
for (int j = 0; j < refs.length; j++) {
IFeatureReference ref = refs[j];
candidatesPerSite.add(ref);
}
// All included features must be local to the
// configuration site, so filter out included
// features here.
filterIncludedFeatures(candidatesPerSite);
// Add the remaining root candidates to
// the global list of candidates.
candidates.addAll(candidatesPerSite);
}
} catch (CoreException e) {
UpdateUIPlugin.logException(e, false);
}
}
private void filterIncludedFeatures(ArrayList candidates)
throws CoreException {
IFeatureReference[] array =
(IFeatureReference[]) candidates.toArray(new IFeatureReference[candidates.size()]);
// filter out included features so that only top-level features remain on the list
for (int i = 0; i < array.length; i++) {
IFeature feature = array[i].getFeature();
IFeatureReference[] included =
feature.getIncludedFeatureReferences();
for (int j = 0; j < included.length; j++) {
IFeatureReference fref = included[j];
int index = candidates.indexOf(fref);
if (index != -1) {
// leave it on the list only
// if 'match' is not perfect.
if (fref.getMatch()==IImport.RULE_PERFECT)
candidates.remove(index);
}
}
}
}
public ISearchQuery[] getQueries() {
initialize();
ArrayList selected = getSelectedCandidates();
ISearchQuery[] queries = new ISearchQuery[selected.size()];
for (int i = 0; i < selected.size(); i++) {
IFeatureReference ref = (IFeatureReference)selected.get(i);
try {
IFeature candidate = ref.getFeature();
queries[i] = new UpdateQuery(candidate, ref.getMatch());
}
catch (CoreException e) {
// cannot really be here
queries[i] = null;
}
}
return queries;
}
public String getCurrentSearch() {
return UpdateUIPlugin.getResourceString(KEY_CURRENT_SEARCH);
}
private boolean isNewerVersion(
VersionedIdentifier fvi,
VersionedIdentifier cvi) {
if (!fvi.getIdentifier().equals(cvi.getIdentifier()))
return false;
PluginVersionIdentifier fv = fvi.getVersion();
PluginVersionIdentifier cv = cvi.getVersion();
String mode = MainPreferencePage.getUpdateVersionsMode();
boolean greater = cv.isGreaterThan(fv);
if (!greater)
return false;
if (mode.equals(MainPreferencePage.EQUIVALENT_VALUE))
return cv.isEquivalentTo(fv);
else if (mode.equals(MainPreferencePage.COMPATIBLE_VALUE))
return cv.isCompatibleWith(fv);
else
return false;
}
private boolean isNewerVersion(
VersionedIdentifier fvi,
VersionedIdentifier cvi,
int match) {
if (!fvi.getIdentifier().equals(cvi.getIdentifier()))
return false;
PluginVersionIdentifier fv = fvi.getVersion();
PluginVersionIdentifier cv = cvi.getVersion();
String mode = MainPreferencePage.getUpdateVersionsMode();
boolean greater = cv.isGreaterThan(fv);
if (!greater)
return false;
int userMatch = IImport.RULE_GREATER_OR_EQUAL;
if (mode.equals(MainPreferencePage.EQUIVALENT_VALUE))
userMatch = IImport.RULE_EQUIVALENT;
else if (mode.equals(MainPreferencePage.COMPATIBLE_VALUE))
userMatch = IImport.RULE_COMPATIBLE;
// By default, use match rule defined in the preferences
int resultingMatch = userMatch;
//If match has been encoded in the feature reference,
// pick the most conservative of the two values.
if (match!=IImport.RULE_PERFECT) {
if (match==IImport.RULE_EQUIVALENT || userMatch==IImport.RULE_EQUIVALENT)
resultingMatch = IImport.RULE_EQUIVALENT;
else
resultingMatch = IImport.RULE_COMPATIBLE;
}
if (resultingMatch==IImport.RULE_EQUIVALENT)
return cv.isEquivalentTo(fv);
else if (resultingMatch==IImport.RULE_COMPATIBLE)
return cv.isCompatibleWith(fv);
else
return false;
}
public void createControl(Composite parent, FormWidgetFactory factory) {
Composite container = factory.createComposite(parent);
GridLayout layout = new GridLayout();
//layout.numColumns = 2;
layout.marginWidth = 2;
layout.marginHeight = 2;
container.setLayout(layout);
tableViewer =
CheckboxTableViewer.newCheckList(
container,
SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
tableViewer.setContentProvider(new FeatureContentProvider());
tableViewer.setLabelProvider(new FeatureLabelProvider());
tableViewer.setInput(this);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.heightHint = 100;
tableViewer.getControl().setLayoutData(gd);
factory.paintBordersFor(container);
setControl(container);
}
public void load(Map map, boolean editable) {
initialize();
tableViewer.refresh();
tableViewer.setAllChecked(true);
String value = (String) map.get("unchecked");
if (value == null)
return;
StringTokenizer stok = new StringTokenizer(value, ":");
while (stok.hasMoreTokens()) {
String token = stok.nextToken();
int loc = token.lastIndexOf('_');
String id;
String version = null;
if (loc != -1) {
id = token.substring(0, loc);
version = token.substring(loc + 1);
} else {
id = token;
version = "0.0.0";
}
IFeature feature =
findCandidate(new VersionedIdentifier(id, version));
if (feature != null)
tableViewer.setChecked(feature, false);
}
}
private IFeature findCandidate(VersionedIdentifier vid) {
if (candidates == null)
initialize();
for (int i = 0; i < candidates.size(); i++) {
IFeature candidate = (IFeature) candidates.get(i);
if (candidate.getVersionedIdentifier().equals(vid))
return candidate;
}
return null;
}
public void store(Map map) {
if (candidates == null)
return;
int counter = 0;
StringBuffer buf = new StringBuffer();
for (int i = 0; i < candidates.size(); i++) {
IFeature candidate = (IFeature) candidates.get(i);
if (tableViewer.getChecked(candidate) == false) {
if (counter > 0)
buf.append(":");
buf.append(candidate.getVersionedIdentifier().toString());
}
}
map.put("unchecked", buf.toString());
}
private ArrayList getSelectedCandidates() {
if (tableViewer == null
|| tableViewer.getControl() == null
|| tableViewer.getControl().isDisposed()) {
return candidates;
}
ArrayList selected = new ArrayList();
Object[] sel = tableViewer.getCheckedElements();
for (int i = 0; i < sel.length; i++)
selected.add(sel[i]);
return selected;
}
}