Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: fbe048e0e0694f96a5639ec5b791b07dd70ec019 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
/*******************************************************************************
 * Copyright (c) 2005, 2011 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
 *     QNX Software System
 *     Anton Leherbauer (Wind River Systems)
 *     Markus Schorn (Wind River Systems)
 *******************************************************************************/
package org.eclipse.cdt.ui;

import java.util.Comparator;

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.preference.IPreferenceStore;
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.ViewerSorter;
import org.eclipse.ui.model.IWorkbenchAdapter;

import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.IArchiveContainer;
import org.eclipse.cdt.core.model.IBinaryContainer;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.IIncludeReference;
import org.eclipse.cdt.core.model.ILibraryReference;
import org.eclipse.cdt.core.model.IMember;
import org.eclipse.cdt.core.model.IMethodDeclaration;
import org.eclipse.cdt.core.model.ISourceRoot;

/**
 *	A sorter to sort the file and the folders in the C viewer in the following order:
 * 	1 Project
 * 	2 BinaryContainer
 *  3 ArchiveContainer
 *  4 LibraryContainer
 *  5 IncludeContainer
 *  6 Source roots
 *  5 C Elements
 *  6 non C Elements
 *  
 *  @noextend This class is not intended to be subclassed by clients.
 */
public class CElementSorter extends ViewerSorter { 

    protected static final int CMODEL = 0;
	protected static final int PROJECTS = 10;
	protected static final int BINARYCONTAINER = 12;
	protected static final int ARCHIVECONTAINER = 13;
	protected static final int INCLUDEREFCONTAINER = 14;
	protected static final int LIBRARYREFCONTAINER = 15;
	protected static final int SOURCEROOTS = 16;
	protected static final int CCONTAINERS = 17;
	protected static final int LIBRARYREFERENCES = 18;
	protected static final int INCLUDEREFERENCES = 19;
	protected static final int TRANSLATIONUNIT_HEADERS = 20;
	protected static final int TRANSLATIONUNIT_SOURCE = 21;
	protected static final int TRANSLATIONUNITS = 22;
	protected static final int BINARIES = 23;
	protected static final int ARCHIVES = 24;
	
	protected static final int INCLUDES = 28;
	protected static final int MACROS = 29;
	protected static final int USINGS = 30;
	protected static final int NAMESPACES = 32;
	protected static final int NAMESPACES_RESERVED = 33;
	protected static final int NAMESPACES_SYSTEM = 34;
	/**
	 * @since 5.1
	 */
	protected static final int TYPES = 35;

	@Deprecated
	protected static final int VARIABLEDECLARATIONS = 36;
	@Deprecated
	protected static final int FUNCTIONDECLARATIONS = 37;
	protected static final int VARIABLES = 38;
	protected static final int VARIABLES_RESERVED = 39;
	protected static final int VARIABLES_SYSTEM = 40;
	protected static final int FUNCTIONS = 41;
	protected static final int FUNCTIONS_RESERVED = 42;
	protected static final int FUNCTIONS_SYSTEM = 43;
	@Deprecated
	protected static final int METHODDECLARATIONS = 44;

	protected static final int CELEMENTS = 100;
	protected static final int CELEMENTS_RESERVED = 101;
	protected static final int CELEMENTS_SYSTEM = 102;

	protected static final int RESOURCEFOLDERS= 200;
	protected static final int RESOURCES= 201;
	protected static final int STORAGE= 202;
	protected static final int OTHERS= 500;


	/*
	 * Constants added for names starting with '_' or '__'
	 */
	private static final int NORMAL = 0;
	private static final int RESERVED = 1;
	private static final int SYSTEM = 2;

	/*
	 * Constants for ordering different member kinds.
	 */
	private static final int STATIC_MEMBER = 0;
	private static final int CONSTRUCTOR = 1;
	private static final int DESTRUCTOR = 2;
	private static final int MEMBER = 3;

	/**
	 * Flag indicating whether header files and source files should be separated.
	 * If <code>true</code>, header files will be sorted before source files,
	 * otherwise header and source files will be sorted by name.
	 */
	private boolean fSeparateHeaderAndSource;
	
	private boolean fKeepSortOrderOfExcludedFiles;

	/**
	 * Default constructor for use as executable extension.
	 */
	public CElementSorter() {
		final IPreferenceStore store= CUIPlugin.getDefault().getPreferenceStore();
		fSeparateHeaderAndSource= store.getBoolean(PreferenceConstants.CVIEW_SEPARATE_HEADER_AND_SOURCE);
		fKeepSortOrderOfExcludedFiles= store.getBoolean(PreferenceConstants.SORT_ORDER_OF_EXCLUDED_FILES);
	}
	
	@Override
	public int category (Object element) {
		if (element instanceof ICElement) {
			ICElement cElement = (ICElement) element;
			switch (cElement.getElementType()) {
			case ICElement.C_MODEL:
				return CMODEL;
			case ICElement.C_PROJECT:
				return PROJECTS;
			case ICElement.C_CCONTAINER:
				if (element instanceof ISourceRoot) {
					return SOURCEROOTS;
				}
				return CCONTAINERS;
			case ICElement.C_VCONTAINER:
				if (element instanceof IBinaryContainer) {
					return BINARYCONTAINER;
				} else if (element instanceof IArchiveContainer) {
					return ARCHIVECONTAINER;
				} else if (element instanceof ILibraryReference) {
					return LIBRARYREFERENCES;
				} else if (element instanceof IIncludeReference) {
					return INCLUDEREFERENCES;
				}
				return CCONTAINERS;
			case ICElement.C_UNIT:
				return getTranslationUnitCategory(cElement.getCProject().getProject(), cElement.getElementName());
			case ICElement.C_INCLUDE:
				return INCLUDES;
			case ICElement.C_MACRO:
				return MACROS;
			case ICElement.C_NAMESPACE:
				return NAMESPACES + getNameKind(cElement.getElementName());
			case ICElement.C_USING:
				return USINGS;
			case ICElement.C_TYPEDEF:
			case ICElement.C_CLASS: 
			case ICElement.C_CLASS_DECLARATION:
			case ICElement.C_TEMPLATE_CLASS:
			case ICElement.C_TEMPLATE_CLASS_DECLARATION:
			case ICElement.C_STRUCT:
			case ICElement.C_STRUCT_DECLARATION:
			case ICElement.C_TEMPLATE_STRUCT:
			case ICElement.C_TEMPLATE_STRUCT_DECLARATION:
			case ICElement.C_UNION:
			case ICElement.C_UNION_DECLARATION:
			case ICElement.C_TEMPLATE_UNION:
			case ICElement.C_TEMPLATE_UNION_DECLARATION:
			case ICElement.C_ENUMERATION:
				return TYPES;
			case ICElement.C_VARIABLE_DECLARATION:
			case ICElement.C_VARIABLE:
			case ICElement.C_TEMPLATE_VARIABLE:
			case ICElement.C_FIELD:
				return VARIABLES + getNameKind(cElement.getElementName());
			case ICElement.C_FUNCTION_DECLARATION:
			case ICElement.C_FUNCTION:
			case ICElement.C_TEMPLATE_FUNCTION_DECLARATION:
			case ICElement.C_TEMPLATE_FUNCTION:
			case ICElement.C_METHOD_DECLARATION:
			case ICElement.C_METHOD:
			case ICElement.C_TEMPLATE_METHOD_DECLARATION:
			case ICElement.C_TEMPLATE_METHOD:
				return FUNCTIONS + getNameKind(cElement.getElementName());
			case ICElement.C_ARCHIVE:
				return ARCHIVES;
			case ICElement.C_BINARY:
				return BINARIES;
			default:
				return CELEMENTS + getNameKind(cElement.getElementName());
			}
		} else if (element instanceof IResource) {
			IResource resource = (IResource) element;
			switch (resource.getType()) {
			case IResource.PROJECT:
				return PROJECTS;
			case IResource.FOLDER:
				return RESOURCEFOLDERS;
			default: // translation unit that was excluded from the build
				if(fKeepSortOrderOfExcludedFiles &&
						CoreModel.isValidTranslationUnitName(resource.getProject(), resource.getName())) {
					return getTranslationUnitCategory(resource.getProject(), resource.getName());
				} 
				return RESOURCES;
			}
		} else if (element instanceof IStorage) {
			return STORAGE;
		} else if (element instanceof CElementGrouping) {
			int type = ((CElementGrouping)element).getType();
			switch (type) {
			case CElementGrouping.INCLUDES_GROUPING:
				return INCLUDES;
			case CElementGrouping.MACROS_GROUPING:
				return MACROS;
			case CElementGrouping.CLASS_GROUPING:
				return TYPES;
			case CElementGrouping.NAMESPACE_GROUPING:
				return NAMESPACES;
			case CElementGrouping.LIBRARY_REF_CONTAINER:
				return LIBRARYREFCONTAINER;
			case CElementGrouping.INCLUDE_REF_CONTAINER:
				return INCLUDEREFCONTAINER;
			}
		}
		return OTHERS;
	}

	private int getNameKind(String name) {
		int length = name.length();
		if (length > 0 && name.charAt(0) == '_') {
			if (length > 1 && name.charAt(1) == '_') {
				return SYSTEM;
			}
			return RESERVED;
		}
		return NORMAL;
	}
	
	private int getTranslationUnitCategory(IProject project, String name) {
		if (fSeparateHeaderAndSource) {
			if (CoreModel.isValidHeaderUnitName(project, name)) {
				return TRANSLATIONUNIT_HEADERS;
			}
			if (CoreModel.isValidSourceUnitName(project, name)) {
				return TRANSLATIONUNIT_SOURCE;
			}
		}
		return TRANSLATIONUNITS;
	} 

	@Override
	public int compare(Viewer viewer, Object e1, Object e2) {
		int cat1 = category(e1);
		int cat2 = category(e2);

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

		// cat1 == cat2

		@SuppressWarnings("unchecked")
		final Comparator<Object> comparator = getComparator();
		if (cat1 == PROJECTS) {
			IWorkbenchAdapter a1= ((IAdaptable)e1).getAdapter(IWorkbenchAdapter.class);
			IWorkbenchAdapter a2= ((IAdaptable)e2).getAdapter(IWorkbenchAdapter.class);
			return comparator.compare(a1.getLabel(e1), a2.getLabel(e2));
		}

		if (cat1 == SOURCEROOTS) {
			ISourceRoot root1= getSourceRoot(e1);
			ISourceRoot root2= getSourceRoot(e2);
			if (root1 == null) {
				if (root2 == null) {
					return 0;
				}
				return 1;
			} else if (root2 == null) {
				return -1;
			}			
			if (!root1.getPath().equals(root2.getPath())) {
				int p1= getPathEntryIndex(root1);
				int p2= getPathEntryIndex(root2);
				if (p1 != p2) {
					return p1 - p2;
				}
			}
		}

		// non - c resources are sorted using the label from the viewers label provider
		if (cat1 == RESOURCES || cat1 == RESOURCEFOLDERS || cat1 == STORAGE || cat1 == OTHERS) {
			return compareWithLabelProvider(viewer, e1, e2);
		}
		
		String ns1 = ""; //$NON-NLS-1$
		String ns2 = ns1;
		
		String name1;
		String name2;

		if (e1 instanceof ICElement) {
			name1 = ((ICElement)e1).getElementName();
			int idx = name1.lastIndexOf("::"); //$NON-NLS-1$
			if (idx >= 0) {
				ns1 = name1.substring(0, idx);
				name1 = name1.substring(idx + 2);
			}
		    if (name1.length() > 0 && name1.charAt(0) == '~') {
		    	name1 = name1.substring(1);
		    }
		} else if (e1 instanceof IResource) {
		    name1 = ((IResource)e1).getName(); 
		} else {
			name1 = e1.toString();
		}
		if (e2 instanceof ICElement) {
			name2 = ((ICElement)e2).getElementName();
			int idx = name2.lastIndexOf("::"); //$NON-NLS-1$
			if (idx >= 0) {
				ns2 = name2.substring(0, idx);
				name2 = name2.substring(idx + 2);
			}
		    if (name2.length() > 0 && name2.charAt(0) == '~') {
		    	name2 = name2.substring(1);
		    }
		} else if(e2 instanceof IResource) {
		    name2 = ((IResource)e2).getName(); 
		} else {
			name2 = e2.toString();
		}
		
		// compare namespace
		int result = comparator.compare(ns1, ns2);
		if (result != 0) {
			return result;
		}
		
		// compare method/member kind
		if (e1 instanceof IMethodDeclaration && e2 instanceof IMethodDeclaration) {
			result = getMethodKind((IMethodDeclaration) e1) - getMethodKind((IMethodDeclaration) e2);
		} else if (e1 instanceof IMember && e2 instanceof IMember) {
			result = getMemberKind((IMember) e1) - getMemberKind((IMember) e2);
		}
		if (result != 0) {
			return result;
		}

		// compare simple name
		result = comparator.compare(name1, name2);
		if (result != 0) {
			return result;
		}
		return result;
	}

	private int getMethodKind(IMethodDeclaration method) {
		try {
			if (method.isStatic()) {
				return STATIC_MEMBER;
			}
			if (method.isConstructor()) {
				return CONSTRUCTOR;
			}
			if (method.isDestructor()) {
				return DESTRUCTOR;
			}
		} catch (CModelException exc) {
			// ignore
		}
		return MEMBER;
	}

	private int getMemberKind(IMember member) {
		try {
			if (member.isStatic()) {
				return STATIC_MEMBER;
			}
		} catch (CModelException exc) {
			// ignore
		}
		return MEMBER;
	}

	private ISourceRoot getSourceRoot(Object element) {
		ICElement celement = (ICElement)element;
		while (! (celement instanceof ISourceRoot) && celement != null) {
			celement = celement.getParent();
		}
		return (ISourceRoot)celement;
	}

	private int compareWithLabelProvider(Viewer viewer, Object e1, Object e2) {
		if (viewer instanceof ContentViewer) {
			IBaseLabelProvider prov = ((ContentViewer) viewer).getLabelProvider();
			if (prov instanceof ILabelProvider) {
				ILabelProvider lprov= (ILabelProvider) prov;
				String name1 = lprov.getText(e1);
				String name2 = lprov.getText(e2);
				if (name1 != null && name2 != null) {
					@SuppressWarnings("unchecked")
					final Comparator<Object> comparator = getComparator();
					return comparator.compare(name1, name2);
				}
			}
		}
		return 0; // can't compare
	}

	private int getPathEntryIndex(ISourceRoot root) {
		try {
			IPath rootPath= root.getPath();
			ISourceRoot[] roots= root.getCProject().getSourceRoots();
			for (int i= 0; i < roots.length; i++) {
				if (roots[i].getPath().equals(rootPath)) {
					return i;
				}
			}
		} catch (CModelException e) {
		}

		return Integer.MAX_VALUE;
	}

}

Back to the top