blob: d46370460e761cdaae08d39220be706c1dad18f3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 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
*******************************************************************************/
package org.eclipse.ui.navigator;
import java.util.Set;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreePathViewerSorter;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.internal.navigator.CommonNavigatorMessages;
import org.eclipse.ui.internal.navigator.NavigatorContentService;
import org.eclipse.ui.internal.navigator.NavigatorContentServiceContentProvider;
import org.eclipse.ui.internal.navigator.NavigatorPlugin;
import org.eclipse.ui.internal.navigator.Policy;
/**
*
* Provides an implementation of TreeViewerSorter that uses the given parent to determine the
* correct sort order based on the defined
* <b>org.eclipse.ui.navigator.navigatorContent/navigatorContent/commonSorter</b> elements
* available in the set of <i>visible</i> content extensions.
*
* <p>
* The CommonViewerSorter must be assigned a {@link INavigatorContentService} to drive its sorting
* algorithm. Without a valid content service, the sorter will return the default ordering.
* </p>
* <p>
* A CommonViewerSorter may not be attached to more than one CommonViewer.
* </p>
*
* @since 3.2
*
*/
public final class CommonViewerSorter extends TreePathViewerSorter {
private static final int LEFT_UNDERSTANDS = 1;
private static final int RIGHT_UNDERSTANDS = 2;
private static final int BOTH_UNDERSTAND = LEFT_UNDERSTANDS | RIGHT_UNDERSTANDS;
private NavigatorContentService contentService;
private INavigatorSorterService sorterService;
/**
* Create a sorter service attached to the given content service.
*
* @param aContentService
* The content service used by the viewer that will use this sorter service.
* @since 3.3
*/
public void setContentService(INavigatorContentService aContentService) {
contentService = (NavigatorContentService) aContentService;
sorterService = contentService.getSorterService();
}
@Override
public int category(Object element) {
if (contentService == null)
return 0;
INavigatorContentDescriptor source = getSource(element);
return source != null ? source.getSequenceNumber() : Priority.NORMAL_PRIORITY_VALUE;
}
private void logMissingExtension(Object parent, Object object) {
NavigatorPlugin.logError(0, NLS.bind(CommonNavigatorMessages.CommonViewerSorter_NoContentExtensionForObject,
object != null ? object.toString() : "<null>", parent != null ? parent.toString() : "<null>"), null); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public int compare(Viewer viewer, TreePath parentPath, Object e1, Object e2) {
if (contentService == null)
return -1;
INavigatorContentDescriptor sourceOfLvalue = getSource(e1);
INavigatorContentDescriptor sourceOfRvalue = getSource(e2);
Object parent;
if (parentPath == null) {
parent = viewer.getInput();
} else {
parent = parentPath.getLastSegment();
}
if (sourceOfLvalue == null) {
logMissingExtension(parent, e1);
return -1;
}
if (sourceOfRvalue == null) {
logMissingExtension(parent, e2);
return -1;
}
ViewerSorter sorter = null;
// shortcut if contributed by same source
if (sourceOfLvalue == sourceOfRvalue) {
sorter = sorterService.findSorter(sourceOfLvalue, parent, e1, e2);
} else {
boolean flags[] = new boolean[4];
flags[0] = sourceOfLvalue.isTriggerPoint(e1);
flags[1] = sourceOfLvalue.isTriggerPoint(e2);
flags[2] = sourceOfRvalue.isTriggerPoint(e1);
flags[3] = sourceOfRvalue.isTriggerPoint(e2);
int whoknows = 0;
whoknows = whoknows | (flags[0] & flags[1] ? LEFT_UNDERSTANDS : 0);
whoknows = whoknows | (flags[2] & flags[3] ? RIGHT_UNDERSTANDS : 0);
switch (whoknows) {
case BOTH_UNDERSTAND:
sorter = sourceOfLvalue.getSequenceNumber() < sourceOfRvalue.getSequenceNumber() ? sorterService
.findSorter(sourceOfLvalue, parent, e1, e2)
: sorterService.findSorter(sourceOfRvalue, parent, e1, e2);
break;
case LEFT_UNDERSTANDS:
sorter = sorterService.findSorter(sourceOfLvalue, parent, e1, e2);
break;
case RIGHT_UNDERSTANDS:
sorter = sorterService.findSorter(sourceOfRvalue, parent, e1, e2);
break;
}
}
if (sorter != null) {
return sorter.compare(viewer, e1, e2);
}
int categoryDelta = category(e1) - category(e2);
if (categoryDelta == 0) {
return super.compare(viewer, e1, e2);
}
return categoryDelta;
}
@Override
public boolean isSorterProperty(Object element, String property) {
// Have to get the parent path from the content provider
NavigatorContentServiceContentProvider cp = (NavigatorContentServiceContentProvider) contentService.createCommonContentProvider();
TreePath[] parentPaths = cp.getParents(element);
for (TreePath parentPath : parentPaths) {
if (isSorterProperty(parentPath, element, property))
return true;
}
return false;
}
@Override
public boolean isSorterProperty(TreePath parentPath, Object element, String property) {
INavigatorContentDescriptor contentDesc = getSource(element);
if (parentPath.getSegmentCount() == 0)
return false;
ViewerSorter sorter = sorterService.findSorter(contentDesc, parentPath.getLastSegment(), element, null);
if (sorter != null)
return sorter.isSorterProperty(element, property);
return false;
}
private INavigatorContentDescriptor getSource(Object o) {
// Fast path - just an optimization for the common case
INavigatorContentDescriptor ncd = contentService.getSourceOfContribution(o);
if (ncd != null) {
if (Policy.DEBUG_SORT)
System.out.println("sort: " + ncd + " object: " + o); //$NON-NLS-1$//$NON-NLS-2$
return ncd;
}
Set descriptors = contentService.findDescriptorsByTriggerPoint(o, NavigatorContentService.CONSIDER_OVERRIDES);
if (descriptors != null && descriptors.size() > 0) {
ncd = (INavigatorContentDescriptor) descriptors.iterator().next();
if (Policy.DEBUG_SORT)
System.out.println("sort: " + ncd + " object: " + o); //$NON-NLS-1$//$NON-NLS-2$
return ncd;
}
if (Policy.DEBUG_SORT)
System.out.println("sort: NULL object: " + o); //$NON-NLS-1$
return null;
}
}