org.eclipse.wst.jsdt.ui.JavaScriptElementComparator.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.wst.jsdt.ui.JavaScriptElementComparator.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2010 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.wst.jsdt.ui;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.viewers.ContentViewer;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.wst.jsdt.core.Flags;
import org.eclipse.wst.jsdt.core.IField;
import org.eclipse.wst.jsdt.core.IFunction;
import org.eclipse.wst.jsdt.core.IInitializer;
import org.eclipse.wst.jsdt.core.IJarEntryResource;
import org.eclipse.wst.jsdt.core.IJavaScriptElement;
import org.eclipse.wst.jsdt.core.IJavaScriptProject;
import org.eclipse.wst.jsdt.core.IMember;
import org.eclipse.wst.jsdt.core.IPackageFragment;
import org.eclipse.wst.jsdt.core.IPackageFragmentRoot;
import org.eclipse.wst.jsdt.core.IType;
import org.eclipse.wst.jsdt.core.JavaScriptModelException;
import org.eclipse.wst.jsdt.core.Signature;
import org.eclipse.wst.jsdt.internal.corext.util.JavaModelUtil;
import org.eclipse.wst.jsdt.internal.corext.util.JdtFlags;
import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
import org.eclipse.wst.jsdt.internal.ui.packageview.NamespaceGroup;
import org.eclipse.wst.jsdt.internal.ui.packageview.PackageFragmentRootContainer;
import org.eclipse.wst.jsdt.internal.ui.preferences.MembersOrderPreferenceCache;

/**
 * Viewer comparator for JavaScript elements. Ordered by element category, then by element name. 
 * Package fragment roots are sorted as ordered on the classpath.
 * 
 * <p>
 * This class may be instantiated; it is not intended to be subclassed.
 * </p>
 * 
 * Provisional API: This class/interface is part of an interim API that is still under development and expected to
 * change significantly before reaching stability. It is being made available at this early stage to solicit feedback
 * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken
 * (repeatedly) as the API evolves.
 */
public class JavaScriptElementComparator extends ViewerComparator {

    private static final int PROJECTS = 1;
    private static final int PACKAGEFRAGMENTROOTS = 2;
    private static final int PACKAGEFRAGMENT = 3;

    private static final int JAVASCRIPTUNITS = 4;
    private static final int CLASSFILES = 5;

    private static final int RESOURCEFOLDERS = 7;
    private static final int RESOURCES = 8;

    private static final int IMPORT_CONTAINER = 11;
    private static final int IMPORT_DECLARATION = 12;

    // Includes all categories ordered using the OutlineSortOrderPage:
    // types, initializers, methods & fields
    private static final int MEMBERSOFFSET = 15;

    private static final int JAVAELEMENTS = 50;
    private static final int OTHERS = 51;

    private MembersOrderPreferenceCache fMemberOrderCache;

    /**
     * Constructor.
     */
    public JavaScriptElementComparator() {
        super(null); // delay initialization of collator
        fMemberOrderCache = JavaScriptPlugin.getDefault().getMemberOrderPreferenceCache();
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ViewerComparator#category(java.lang.Object)
     */
    public int category(Object element) {
        if (element instanceof IJavaScriptElement) {
            try {
                IJavaScriptElement je = (IJavaScriptElement) element;

                switch (je.getElementType()) {
                case IJavaScriptElement.METHOD: {
                    IFunction method = (IFunction) je;
                    if (method.isConstructor()) {
                        return getMemberCategory(MembersOrderPreferenceCache.CONSTRUCTORS_INDEX);
                    }
                    int flags = method.getFlags();
                    if (Flags.isStatic(flags))
                        return getMemberCategory(MembersOrderPreferenceCache.STATIC_METHODS_INDEX);
                    else
                        return getMemberCategory(MembersOrderPreferenceCache.METHOD_INDEX);
                }
                case IJavaScriptElement.FIELD: {
                    int flags = ((IField) je).getFlags();
                    if (Flags.isStatic(flags))
                        return getMemberCategory(MembersOrderPreferenceCache.STATIC_FIELDS_INDEX);
                    else
                        return getMemberCategory(MembersOrderPreferenceCache.FIELDS_INDEX);
                }
                case IJavaScriptElement.INITIALIZER: {
                    int flags = ((IInitializer) je).getFlags();
                    if (Flags.isStatic(flags))
                        return getMemberCategory(MembersOrderPreferenceCache.STATIC_INIT_INDEX);
                    else
                        return getMemberCategory(MembersOrderPreferenceCache.INIT_INDEX);
                }
                case IJavaScriptElement.TYPE:
                    return getMemberCategory(MembersOrderPreferenceCache.TYPE_INDEX);
                case IJavaScriptElement.IMPORT_CONTAINER:
                    return IMPORT_CONTAINER;
                case IJavaScriptElement.IMPORT_DECLARATION:
                    return IMPORT_DECLARATION;
                case IJavaScriptElement.PACKAGE_FRAGMENT:
                    return PACKAGEFRAGMENT;
                case IJavaScriptElement.PACKAGE_FRAGMENT_ROOT:
                    return PACKAGEFRAGMENTROOTS;
                case IJavaScriptElement.JAVASCRIPT_PROJECT:
                    return PROJECTS;
                case IJavaScriptElement.CLASS_FILE:
                    return CLASSFILES;
                case IJavaScriptElement.JAVASCRIPT_UNIT:
                    //                  return JAVASCRIPTUNITS;
                    return RESOURCES;
                }

            } catch (JavaScriptModelException e) {
                if (!e.isDoesNotExist())
                    JavaScriptPlugin.log(e);
            }
            return JAVAELEMENTS;
        } else if (element instanceof IFile) {
            return RESOURCES;
        } else if (element instanceof IProject) {
            return PROJECTS;
        } else if (element instanceof IContainer) {
            return RESOURCEFOLDERS;
        } else if (element instanceof IJarEntryResource) {
            if (((IJarEntryResource) element).isFile()) {
                return RESOURCES;
            }
            return RESOURCEFOLDERS;
        } else if (element instanceof PackageFragmentRootContainer) {
            return PACKAGEFRAGMENTROOTS;
        } else if (element instanceof ProjectLibraryRoot) {
            return PROJECTS;
        } else if (element instanceof NamespaceGroup) {
            return PROJECTS;
        }

        return OTHERS;
    }

    private int getMemberCategory(int kind) {
        int offset = fMemberOrderCache.getCategoryIndex(kind);
        return offset + MEMBERSOFFSET;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
     */
    public int compare(Viewer viewer, Object e1, Object e2) {
        int cat1 = category(e1);
        int cat2 = category(e2);

        if (needsClasspathComparision(e1, cat1, e2, cat2)) {
            IPackageFragmentRoot root1 = getPackageFragmentRoot(e1);
            IPackageFragmentRoot root2 = getPackageFragmentRoot(e2);
            if (root1 == null) {
                if (root2 == null) {
                    return 0;
                } else {
                    return 1;
                }
            } else if (root2 == null) {
                return -1;
            }
            // check if not same to avoid expensive class path access
            if (!root1.getPath().equals(root2.getPath())) {
                int p1 = getClassPathIndex(root1);
                int p2 = getClassPathIndex(root2);
                if (p1 != p2) {
                    return p1 - p2;
                }
            }
        }

        if (cat1 != cat2)
            return cat1 - cat2;

        if (cat1 == PROJECTS || cat1 == RESOURCES || cat1 == RESOURCEFOLDERS || cat1 == OTHERS) {
            String name1 = getNonJavaElementLabel(viewer, e1);
            String name2 = getNonJavaElementLabel(viewer, e2);
            if (name1 != null && name2 != null) {
                return getComparator().compare(name1, name2);
            }
            return 0; // can't compare
        }
        // only JavaScript elements from this point

        if (e1 instanceof IMember) {
            if (fMemberOrderCache.isSortByVisibility()) {
                try {
                    int flags1 = JdtFlags.getVisibilityCode((IMember) e1);
                    int flags2 = JdtFlags.getVisibilityCode((IMember) e2);
                    int vis = fMemberOrderCache.getVisibilityIndex(flags1)
                            - fMemberOrderCache.getVisibilityIndex(flags2);
                    if (vis != 0) {
                        return vis;
                    }
                } catch (JavaScriptModelException ignore) {
                }
            }
        }

        String name1 = getElementName(e1);
        String name2 = getElementName(e2);

        if (e1 instanceof IType) { // handle anonymous types
            if (name1.length() == 0) {
                if (name2.length() == 0) {
                    try {
                        return getComparator().compare(((IType) e1).getSuperclassName(),
                                ((IType) e2).getSuperclassName());
                    } catch (JavaScriptModelException e) {
                        return 0;
                    }
                } else {
                    return 1;
                }
            } else if (name2.length() == 0) {
                return -1;
            }
        }

        int cmp = getComparator().compare(name1, name2);
        if (cmp != 0) {
            return cmp;
        }

        if (e1 instanceof IFunction) {
            String[] params1 = ((IFunction) e1).getParameterTypes();
            String[] params2 = ((IFunction) e2).getParameterTypes();
            int len = Math.min(params1.length, params2.length);
            for (int i = 0; i < len; i++) {
                cmp = getComparator().compare(Signature.toString(params1[i]), Signature.toString(params2[i]));
                if (cmp != 0) {
                    return cmp;
                }
            }
            return params1.length - params2.length;
        }
        return 0;
    }

    private IPackageFragmentRoot getPackageFragmentRoot(Object element) {
        if (element instanceof PackageFragmentRootContainer) {
            // return first package fragment root from the container
            PackageFragmentRootContainer cp = (PackageFragmentRootContainer) element;
            Object[] roots = cp.getPackageFragmentRoots();
            if (roots.length > 0)
                return (IPackageFragmentRoot) roots[0];
            // non resolvable - return null
            return null;
        }
        return JavaModelUtil.getPackageFragmentRoot((IJavaScriptElement) element);
    }

    private String getNonJavaElementLabel(Viewer viewer, Object element) {
        // try to use the workbench adapter for non - JavaScript resources or if not available, use the viewers label provider
        if (element instanceof IResource) {
            return ((IResource) element).getName();
        }
        if (element instanceof IStorage) {
            return ((IStorage) element).getName();
        }
        if (element instanceof IAdaptable) {
            IWorkbenchAdapter adapter = (IWorkbenchAdapter) ((IAdaptable) element)
                    .getAdapter(IWorkbenchAdapter.class);
            if (adapter != null) {
                return adapter.getLabel(element);
            }
        }
        if (viewer instanceof ContentViewer) {
            IBaseLabelProvider prov = ((ContentViewer) viewer).getLabelProvider();
            if (prov instanceof ILabelProvider) {
                return ((ILabelProvider) prov).getText(element);
            }
        }
        return null;
    }

    private int getClassPathIndex(IPackageFragmentRoot root) {
        try {
            IPath rootPath = root.getPath();
            IPackageFragmentRoot[] roots = root.getJavaScriptProject().getPackageFragmentRoots();
            for (int i = 0; i < roots.length; i++) {
                if (roots[i].getPath().equals(rootPath)) {
                    return i;
                }
            }
        } catch (JavaScriptModelException e) {
        }

        return Integer.MAX_VALUE;
    }

    private boolean needsClasspathComparision(Object e1, int cat1, Object e2, int cat2) {
        if ((cat1 == PACKAGEFRAGMENTROOTS && cat2 == PACKAGEFRAGMENTROOTS)
                || (cat1 == PACKAGEFRAGMENT && ((IPackageFragment) e1).getParent().getResource() instanceof IProject
                        && cat2 == PACKAGEFRAGMENTROOTS)
                || (cat1 == PACKAGEFRAGMENTROOTS && cat2 == PACKAGEFRAGMENT
                        && ((IPackageFragment) e2).getParent().getResource() instanceof IProject)) {
            IJavaScriptProject p1 = getJavaProject(e1);
            return p1 != null && p1.equals(getJavaProject(e2));
        }
        return false;
    }

    private IJavaScriptProject getJavaProject(Object element) {
        if (element instanceof IJavaScriptElement) {
            return ((IJavaScriptElement) element).getJavaScriptProject();
        } else if (element instanceof PackageFragmentRootContainer) {
            return ((PackageFragmentRootContainer) element).getJavaProject();
        }
        return null;
    }

    private String getElementName(Object element) {
        if (element instanceof IJavaScriptElement) {
            return ((IJavaScriptElement) element).getElementName();
        } else if (element instanceof PackageFragmentRootContainer) {
            return ((PackageFragmentRootContainer) element).getLabel();
        } else {
            return element.toString();
        }
    }
}