001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.views.markers.internal;
011:
012: import java.util.ArrayList;
013: import java.util.Collection;
014: import java.util.Comparator;
015:
016: import org.eclipse.core.runtime.CoreException;
017: import org.eclipse.core.runtime.IProgressMonitor;
018: import org.eclipse.core.runtime.SubProgressMonitor;
019: import org.eclipse.jface.viewers.ViewerComparator;
020: import org.eclipse.osgi.util.NLS;
021:
022: /**
023: * The MarkerAdapter is the adapter for the deferred update of markers.
024: *
025: * @since 3.1
026: *
027: */
028: public class MarkerAdapter {
029:
030: class MarkerCategory extends MarkerNode {
031:
032: MarkerAdapter markerAdapter;
033:
034: int start;
035:
036: int end;
037:
038: private ConcreteMarker[] children;
039:
040: private String name;
041:
042: /**
043: * Create a new instance of the receiver that has the markers between
044: * startIndex and endIndex showing.
045: *
046: * @param adapter
047: * @param startIndex
048: * @param endIndex
049: */
050: MarkerCategory(MarkerAdapter adapter, int startIndex,
051: int endIndex, String categoryName) {
052: markerAdapter = adapter;
053: start = startIndex;
054: end = endIndex;
055: name = categoryName;
056: }
057:
058: /*
059: * (non-Javadoc)
060: *
061: * @see org.eclipse.ui.views.markers.internal.MarkerNode#getChildren()
062: */
063: public MarkerNode[] getChildren() {
064:
065: if (children == null) {
066:
067: // Return nothing while a build is going on as this could be
068: // stale
069: if (building) {
070: return Util.EMPTY_MARKER_ARRAY;
071: }
072:
073: ConcreteMarker[] allMarkers = markerAdapter.lastMarkers
074: .toArray();
075:
076: int totalSize = getDisplayedSize();
077: children = new ConcreteMarker[totalSize];
078:
079: System.arraycopy(allMarkers, start, children, 0,
080: totalSize);
081: // Sort them locally now
082: view.getTableSorter().sort(view.getViewer(), children);
083:
084: for (int i = 0; i < children.length; i++) {
085: children[i].setCategory(this );
086: }
087: }
088: return children;
089:
090: }
091:
092: /**
093: * Return the number of errors being displayed.
094: *
095: * @return int
096: */
097: int getDisplayedSize() {
098: if (view.getMarkerLimit() > 0) {
099: return Math.min(getTotalSize(), view.getMarkerLimit());
100: }
101: return getTotalSize();
102: }
103:
104: /*
105: * (non-Javadoc)
106: *
107: * @see org.eclipse.ui.views.markers.internal.MarkerNode#getParent()
108: */
109: public MarkerNode getParent() {
110: return null;
111: }
112:
113: /*
114: * (non-Javadoc)
115: *
116: * @see org.eclipse.ui.views.markers.internal.MarkerNode#getDescription()
117: */
118: public String getDescription() {
119:
120: int size = end - start + 1;
121:
122: if (size <= view.getMarkerLimit()) {
123:
124: if (size == 1)
125: return NLS.bind(
126: MarkerMessages.Category_One_Item_Label,
127: new Object[] { name });
128:
129: return NLS.bind(MarkerMessages.Category_Label,
130: new Object[] { name,
131: String.valueOf(getDisplayedSize()) });
132: }
133: return NLS.bind(MarkerMessages.Category_Limit_Label,
134: new Object[] { name,
135: String.valueOf(getDisplayedSize()),
136: String.valueOf(getTotalSize()) });
137: }
138:
139: /**
140: * Get the total size of the receiver.
141: *
142: * @return int
143: */
144: private int getTotalSize() {
145: return end - start + 1;
146: }
147:
148: /*
149: * (non-Javadoc)
150: *
151: * @see org.eclipse.ui.views.markers.internal.MarkerNode#isConcrete()
152: */
153: public boolean isConcrete() {
154: return false;
155: }
156:
157: /*
158: * (non-Javadoc)
159: *
160: * @see org.eclipse.ui.views.markers.internal.MarkerNode#getConcreteRepresentative()
161: */
162: public ConcreteMarker getConcreteRepresentative() {
163: return markerAdapter.lastMarkers.getMarker(start);
164: }
165:
166: /**
167: * Return the name of the receiver.
168: *
169: * @return String
170: */
171: public String getName() {
172: return name;
173: }
174: }
175:
176: MarkerView view;
177:
178: private MarkerList lastMarkers;
179:
180: private MarkerCategory[] categories;
181:
182: private boolean building = true;// Start with nothing until we have
183:
184: // something
185:
186: /**
187: * Create a new instance of the receiver.
188: *
189: * @param markerView
190: */
191: MarkerAdapter(MarkerView markerView) {
192: view = markerView;
193: }
194:
195: /**
196: * Return the category sorter for the receiver. This should only be called
197: * in hierarchal mode or there will be a ClassCastException.
198: *
199: * @return CategorySorter
200: */
201: public CategoryComparator getCategorySorter() {
202: return (CategoryComparator) view.getViewer().getComparator();
203: }
204:
205: /**
206: * Build all of the markers in the receiver.
207: *
208: * @param collector
209: * @param monitor
210: */
211: public void buildAllMarkers(IProgressMonitor monitor) {
212: building = true;
213: MarkerList newMarkers;
214: try {
215: int markerLimit = view.getMarkerLimit();
216: monitor.beginTask(MarkerMessages.MarkerView_19,
217: markerLimit == -1 ? 60 : 100);
218: try {
219: monitor
220: .subTask(MarkerMessages.MarkerView_waiting_on_changes);
221:
222: if (monitor.isCanceled())
223: return;
224:
225: monitor
226: .subTask(MarkerMessages.MarkerView_searching_for_markers);
227: SubProgressMonitor subMonitor = new SubProgressMonitor(
228: monitor, 10);
229: MarkerFilter[] filters = view.getEnabledFilters();
230: if (filters.length > 0)
231: newMarkers = MarkerList.compute(filters,
232: subMonitor, true);
233: else
234: // Grab any filter as a disabled filter gives all of them
235: newMarkers = MarkerList
236: .compute(new MarkerFilter[] { view
237: .getAllFilters()[0] }, subMonitor,
238: true);
239:
240: if (monitor.isCanceled())
241: return;
242:
243: view.refreshMarkerCounts(monitor);
244:
245: } catch (CoreException e) {
246: Util.log(e);
247: newMarkers = new MarkerList();
248: return;
249: }
250:
251: if (monitor.isCanceled())
252: return;
253:
254: ViewerComparator sorter = view.getViewer().getComparator();
255:
256: if (markerLimit == -1 || isShowingHierarchy()) {
257: sorter.sort(view.getViewer(), newMarkers.toArray());
258: } else {
259:
260: monitor.subTask(MarkerMessages.MarkerView_18);
261: SubProgressMonitor mon = new SubProgressMonitor(
262: monitor, 40);
263:
264: newMarkers = SortUtil.getFirst(newMarkers,
265: (Comparator) sorter, markerLimit, mon);
266: if (monitor.isCanceled())
267: return;
268:
269: sorter.sort(view.getViewer(), newMarkers.toArray());
270: }
271:
272: if (newMarkers.getSize() == 0) {
273: categories = new MarkerCategory[0];
274: lastMarkers = newMarkers;
275: monitor.done();
276: return;
277: }
278:
279: monitor.subTask(MarkerMessages.MarkerView_queueing_updates);
280:
281: if (monitor.isCanceled())
282: return;
283:
284: if (isShowingHierarchy()) {
285: MarkerCategory[] newCategories = buildHierarchy(
286: newMarkers, 0, newMarkers.getSize() - 1, 0);
287: if (monitor.isCanceled())
288: return;
289: categories = newCategories;
290: }
291:
292: lastMarkers = newMarkers;
293: monitor.done();
294: } finally {
295: building = false;
296: }
297:
298: }
299:
300: /**
301: * Return whether or not a hierarchy is showing.
302: *
303: * @return boolean
304: */
305: boolean isShowingHierarchy() {
306:
307: ViewerComparator sorter = view.getViewer().getComparator();
308: if (sorter instanceof CategoryComparator) {
309: return ((CategoryComparator) sorter).getCategoryField() != null;
310: }
311: return false;
312: }
313:
314: /**
315: * Break the marker up into categories
316: *
317: * @param markers
318: * @param start
319: * the start index in the markers
320: * @param end
321: * the last index to check
322: * @param sortIndex -
323: * the parent of the field
324: * @param parent
325: * @return MarkerCategory[] or <code>null</code> if we are at the bottom
326: * of the tree
327: */
328: MarkerCategory[] buildHierarchy(MarkerList markers, int start,
329: int end, int sortIndex) {
330: CategoryComparator sorter = getCategorySorter();
331:
332: if (sortIndex > 0) {
333: return null;// Are we out of categories?
334: }
335:
336: Collection categories = new ArrayList();
337:
338: Object previous = null;
339: int categoryStart = start;
340:
341: Object[] elements = markers.getArray();
342:
343: for (int i = start; i <= end; i++) {
344:
345: if (previous != null) {
346: // Are we at a category boundary?
347: if (sorter.compare(previous, elements[i], sortIndex,
348: false) != 0) {
349: categories.add(new MarkerCategory(this ,
350: categoryStart, i - 1, getNameForIndex(
351: markers, categoryStart)));
352: categoryStart = i;
353: }
354: }
355: previous = elements[i];
356:
357: }
358:
359: if (end >= categoryStart) {
360: categories.add(new MarkerCategory(this , categoryStart, end,
361: getNameForIndex(markers, categoryStart)));
362: }
363:
364: // Flatten single categories
365: // if (categories.size() == 1) {
366: // return buildHierarchy(markers, start, end, sortIndex + 1, parent);
367: // }
368: MarkerCategory[] nodes = new MarkerCategory[categories.size()];
369: categories.toArray(nodes);
370: return nodes;
371:
372: }
373:
374: /**
375: * Get the name for the category from the marker at categoryStart in
376: * markers.
377: *
378: * @param markers
379: * @param categoryStart
380: * @return String
381: */
382: private String getNameForIndex(MarkerList markers, int categoryStart) {
383: return getCategorySorter().getCategoryField().getValue(
384: markers.toArray()[categoryStart]);
385: }
386:
387: /**
388: * Return the current list of markers.
389: *
390: * @return MarkerList
391: */
392: public MarkerList getCurrentMarkers() {
393: if (lastMarkers == null) {// First time?
394: view.scheduleMarkerUpdate(Util.SHORT_DELAY);
395: building = true;
396: }
397: if (building) {
398: return new MarkerList();
399: }
400: return lastMarkers;
401: }
402:
403: /**
404: * Return the elements in the adapter.
405: *
406: * @param root
407: * @return Object[]
408: */
409: public Object[] getElements() {
410:
411: if (lastMarkers == null) {// First time?
412: view.scheduleMarkerUpdate(Util.SHORT_DELAY);
413: building = true;
414: }
415: if (building) {
416: return Util.EMPTY_MARKER_ARRAY;
417: }
418: if (isShowingHierarchy() && categories != null) {
419: return categories;
420: }
421: return lastMarkers.toArray();
422: }
423:
424: /**
425: * Return whether or not the receiver has markers without scheduling
426: * anything if it doesn't.
427: *
428: * @return boolean <code>true</code> if the markers have not been
429: * calculated.
430: */
431: public boolean hasNoMarkers() {
432: return lastMarkers == null;
433: }
434:
435: /**
436: * Return the categories for the receiver.
437: *
438: * @return MarkerCategory[] or <code>null</code> if there are no
439: * categories.
440: */
441: public MarkerCategory[] getCategories() {
442: if (building) {
443: return null;
444: }
445: return categories;
446: }
447:
448: /**
449: * Return whether or not the receiver is building.
450: * @return boolean
451: */
452: boolean isBuilding() {
453: return building;
454: }
455:
456: }
|