fix #774 infinite loop in net.sourceforge.phpeclipse.builder.IdentifierIndexManager...
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / ui / JavaElementSorter.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.ui;
12
13 import java.text.Collator;
14
15 import net.sourceforge.phpdt.core.Flags;
16 import net.sourceforge.phpdt.core.IField;
17 import net.sourceforge.phpdt.core.IJavaElement;
18 import net.sourceforge.phpdt.core.IMember;
19 import net.sourceforge.phpdt.core.IMethod;
20 import net.sourceforge.phpdt.core.IPackageFragment;
21 import net.sourceforge.phpdt.core.IPackageFragmentRoot;
22 import net.sourceforge.phpdt.core.IType;
23 import net.sourceforge.phpdt.core.JavaModelException;
24 import net.sourceforge.phpdt.core.Signature;
25 import net.sourceforge.phpdt.internal.corext.util.JavaModelUtil;
26 import net.sourceforge.phpdt.internal.corext.util.JdtFlags;
27 import net.sourceforge.phpdt.internal.ui.preferences.MembersOrderPreferenceCache;
28 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
29
30 import org.eclipse.core.resources.IContainer;
31 import org.eclipse.core.resources.IFile;
32 import org.eclipse.core.resources.IProject;
33 import org.eclipse.core.resources.IStorage;
34 import org.eclipse.core.runtime.IAdaptable;
35 import org.eclipse.core.runtime.IPath;
36 import org.eclipse.jface.viewers.ContentViewer;
37 import org.eclipse.jface.viewers.IBaseLabelProvider;
38 import org.eclipse.jface.viewers.ILabelProvider;
39 import org.eclipse.jface.viewers.Viewer;
40 import org.eclipse.jface.viewers.ViewerSorter;
41 import org.eclipse.ui.model.IWorkbenchAdapter;
42
43 /**
44  * Sorter for Java elements. Ordered by element category, then by element name.
45  * Package fragment roots are sorted as ordered on the classpath.
46  * 
47  * <p>
48  * This class may be instantiated; it is not intended to be subclassed.
49  * </p>
50  * 
51  * @since 2.0
52  */
53 public class JavaElementSorter extends ViewerSorter {
54
55         private static final int PROJECTS = 1;
56
57         private static final int PACKAGEFRAGMENTROOTS = 2;
58
59         private static final int PACKAGEFRAGMENT = 3;
60
61         private static final int COMPILATIONUNITS = 4;
62
63         private static final int CLASSFILES = 5;
64
65         private static final int RESOURCEFOLDERS = 7;
66
67         private static final int RESOURCES = 8;
68
69         private static final int STORAGE = 9;
70
71         private static final int PACKAGE_DECL = 10;
72
73         private static final int IMPORT_CONTAINER = 11;
74
75         private static final int IMPORT_DECLARATION = 12;
76
77         // Includes all categories ordered using the OutlineSortOrderPage:
78         // types, initializers, methods & fields
79         private static final int MEMBERSOFFSET = 15;
80
81         private static final int JAVAELEMENTS = 50;
82
83         private static final int OTHERS = 51;
84
85         private MembersOrderPreferenceCache fMemberOrderCache;
86
87         /**
88          * Constructor.
89          */
90         public JavaElementSorter() {
91                 super(null); // delay initialization of collator
92                 fMemberOrderCache = PHPeclipsePlugin.getDefault()
93                                 .getMemberOrderPreferenceCache();
94         }
95
96         /**
97          * @deprecated Bug 22518. Method never used: does not override
98          *             ViewerSorter#isSorterProperty(Object, String). Method could
99          *             be removed, but kept for API compatibility.
100          */
101         public boolean isSorterProperty(Object element, Object property) {
102                 return true;
103         }
104
105         /*
106          * @see ViewerSorter#category
107          */
108         public int category(Object element) {
109                 if (element instanceof IJavaElement) {
110                         try {
111                                 IJavaElement je = (IJavaElement) element;
112
113                                 switch (je.getElementType()) {
114                                 case IJavaElement.METHOD: {
115                                         IMethod method = (IMethod) je;
116                                         if (method.isConstructor()) {
117                                                 return getMemberCategory(MembersOrderPreferenceCache.CONSTRUCTORS_INDEX);
118                                         }
119                                         int flags = method.getFlags();
120                                         if (Flags.isStatic(flags))
121                                                 return getMemberCategory(MembersOrderPreferenceCache.STATIC_METHODS_INDEX);
122                                         else
123                                                 return getMemberCategory(MembersOrderPreferenceCache.METHOD_INDEX);
124                                 }
125                                 case IJavaElement.FIELD: {
126                                         int flags = ((IField) je).getFlags();
127                                         if (Flags.isStatic(flags))
128                                                 return getMemberCategory(MembersOrderPreferenceCache.STATIC_FIELDS_INDEX);
129                                         else
130                                                 return getMemberCategory(MembersOrderPreferenceCache.FIELDS_INDEX);
131                                 }
132                                         // case IJavaElement.INITIALIZER :
133                                         // {
134                                         // int flags= ((IInitializer) je).getFlags();
135                                         // if (Flags.isStatic(flags))
136                                         // return
137                                         // getMemberCategory(MembersOrderPreferenceCache.STATIC_INIT_INDEX);
138                                         // else
139                                         // return
140                                         // getMemberCategory(MembersOrderPreferenceCache.INIT_INDEX);
141                                         // }
142                                 case IJavaElement.TYPE:
143                                         return getMemberCategory(MembersOrderPreferenceCache.TYPE_INDEX);
144                                 case IJavaElement.PACKAGE_DECLARATION:
145                                         return PACKAGE_DECL;
146                                 case IJavaElement.IMPORT_CONTAINER:
147                                         return IMPORT_CONTAINER;
148                                 case IJavaElement.IMPORT_DECLARATION:
149                                         return IMPORT_DECLARATION;
150                                 case IJavaElement.PACKAGE_FRAGMENT:
151                                         IPackageFragment pack = (IPackageFragment) je;
152                                         if (pack.getParent().getResource() instanceof IProject) {
153                                                 return PACKAGEFRAGMENTROOTS;
154                                         }
155                                         return PACKAGEFRAGMENT;
156                                 case IJavaElement.PACKAGE_FRAGMENT_ROOT:
157                                         return PACKAGEFRAGMENTROOTS;
158                                 case IJavaElement.JAVA_PROJECT:
159                                         return PROJECTS;
160                                 case IJavaElement.CLASS_FILE:
161                                         return CLASSFILES;
162                                 case IJavaElement.COMPILATION_UNIT:
163                                         return COMPILATIONUNITS;
164                                 }
165
166                         } catch (JavaModelException e) {
167                                 if (!e.isDoesNotExist())
168                                         PHPeclipsePlugin.log(e);
169                         }
170                         return JAVAELEMENTS;
171                 } else if (element instanceof IFile) {
172                         return RESOURCES;
173                 } else if (element instanceof IProject) {
174                         return PROJECTS;
175                 } else if (element instanceof IContainer) {
176                         return RESOURCEFOLDERS;
177                 } else if (element instanceof IStorage) {
178                         return STORAGE;
179                 }
180                 // else if (element instanceof ClassPathContainer) {
181                 // return PACKAGEFRAGMENTROOTS;
182                 // }
183                 return OTHERS;
184         }
185
186         private int getMemberCategory(int kind) {
187                 int offset = fMemberOrderCache.getCategoryIndex(kind);
188                 return offset + MEMBERSOFFSET;
189         }
190
191         /*
192          * @see ViewerSorter#compare
193          */
194         public int compare(Viewer viewer, Object e1, Object e2) {
195                 int cat1 = category(e1);
196                 int cat2 = category(e2);
197
198                 if (cat1 != cat2)
199                         return cat1 - cat2;
200
201                 if (cat1 == PROJECTS) {
202                         IWorkbenchAdapter a1 = (IWorkbenchAdapter) ((IAdaptable) e1)
203                                         .getAdapter(IWorkbenchAdapter.class);
204                         IWorkbenchAdapter a2 = (IWorkbenchAdapter) ((IAdaptable) e2)
205                                         .getAdapter(IWorkbenchAdapter.class);
206                         return getCollator().compare(a1.getLabel(e1), a2.getLabel(e2));
207                 }
208
209                 if (cat1 == PACKAGEFRAGMENTROOTS) {
210                         IPackageFragmentRoot root1 = getPackageFragmentRoot(e1);
211                         IPackageFragmentRoot root2 = getPackageFragmentRoot(e2);
212                         if (root1 == null) {
213                                 if (root2 == null) {
214                                         return 0;
215                                 } else {
216                                         return 1;
217                                 }
218                         } else if (root2 == null) {
219                                 return -1;
220                         }
221                         if (!root1.getPath().equals(root2.getPath())) {
222                                 int p1 = getClassPathIndex(root1);
223                                 int p2 = getClassPathIndex(root2);
224                                 if (p1 != p2) {
225                                         return p1 - p2;
226                                 }
227                         }
228                         e1 = root1; // normalize classpath container to root
229                         e2 = root2;
230                 }
231                 // non - java resources are sorted using the label from the viewers
232                 // label provider
233                 if (cat1 == PROJECTS || cat1 == RESOURCES || cat1 == RESOURCEFOLDERS
234                                 || cat1 == STORAGE || cat1 == OTHERS) {
235                         return compareWithLabelProvider(viewer, e1, e2);
236                 }
237
238                 if (e1 instanceof IMember) {
239                         if (fMemberOrderCache.isSortByVisibility()) {
240                                 try {
241                                         int flags1 = JdtFlags.getVisibilityCode((IMember) e1);
242                                         int flags2 = JdtFlags.getVisibilityCode((IMember) e2);
243                                         int vis = fMemberOrderCache.getVisibilityIndex(flags1)
244                                                         - fMemberOrderCache.getVisibilityIndex(flags2);
245                                         if (vis != 0) {
246                                                 return vis;
247                                         }
248                                 } catch (JavaModelException ignore) {
249                                 }
250                         }
251                 }
252
253                 String name1 = ((IJavaElement) e1).getElementName();
254                 String name2 = ((IJavaElement) e2).getElementName();
255
256                 if (e1 instanceof IType) { // handle anonymous types
257                         if (name1.length() == 0) {
258                                 if (name2.length() == 0) {
259                                         try {
260                                                 return getCollator().compare(
261                                                                 ((IType) e1).getSuperclassName(),
262                                                                 ((IType) e2).getSuperclassName());
263                                         } catch (JavaModelException e) {
264                                                 return 0;
265                                         }
266                                 } else {
267                                         return 1;
268                                 }
269                         } else if (name2.length() == 0) {
270                                 return -1;
271                         }
272                 }
273
274                 int cmp = getCollator().compare(name1, name2);
275                 if (cmp != 0) {
276                         return cmp;
277                 }
278
279                 if (e1 instanceof IMethod) {
280                         String[] params1 = ((IMethod) e1).getParameterTypes();
281                         String[] params2 = ((IMethod) e2).getParameterTypes();
282                         int len = Math.min(params1.length, params2.length);
283                         for (int i = 0; i < len; i++) {
284                                 cmp = getCollator().compare(Signature.toString(params1[i]),
285                                                 Signature.toString(params2[i]));
286                                 if (cmp != 0) {
287                                         return cmp;
288                                 }
289                         }
290                         return params1.length - params2.length;
291                 }
292                 return 0;
293         }
294
295         private IPackageFragmentRoot getPackageFragmentRoot(Object element) {
296                 // if (element instanceof ClassPathContainer) {
297                 // // return first package fragment root from the container
298                 // ClassPathContainer cp= (ClassPathContainer)element;
299                 // Object[] roots= cp.getPackageFragmentRoots();
300                 // if (roots.length > 0)
301                 // return (IPackageFragmentRoot)roots[0];
302                 // // non resolvable - return null
303                 // return null;
304                 // }
305                 return JavaModelUtil.getPackageFragmentRoot((IJavaElement) element);
306         }
307
308         private int compareWithLabelProvider(Viewer viewer, Object e1, Object e2) {
309                 if (viewer == null || !(viewer instanceof ContentViewer)) {
310                         IBaseLabelProvider prov = ((ContentViewer) viewer)
311                                         .getLabelProvider();
312                         if (prov instanceof ILabelProvider) {
313                                 ILabelProvider lprov = (ILabelProvider) prov;
314                                 String name1 = lprov.getText(e1);
315                                 String name2 = lprov.getText(e2);
316                                 if (name1 != null && name2 != null) {
317                                         return getCollator().compare(name1, name2);
318                                 }
319                         }
320                 }
321                 return 0; // can't compare
322         }
323
324         private int getClassPathIndex(IPackageFragmentRoot root) {
325                 try {
326                         IPath rootPath = root.getPath();
327                         IPackageFragmentRoot[] roots = root.getJavaProject()
328                                         .getPackageFragmentRoots();
329                         for (int i = 0; i < roots.length; i++) {
330                                 if (roots[i].getPath().equals(rootPath)) {
331                                         return i;
332                                 }
333                         }
334                 } catch (JavaModelException e) {
335                 }
336
337                 return Integer.MAX_VALUE;
338         }
339
340         /*
341          * (non-Javadoc)
342          * 
343          * @see org.eclipse.jface.viewers.ViewerSorter#getCollator()
344          */
345         public final Collator getCollator() {
346                 if (collator == null) {
347                         collator = Collator.getInstance();
348                 }
349                 return collator;
350         }
351
352 }