| 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; |
| } |
| } |