blob: b8bca1eae373df10da682dc4900dcfd391d92567 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2007 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.views.markers.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.osgi.util.NLS;
/**
* The MarkerAdapter is the adapter for the deferred update of markers.
*
* @since 3.1
*
*/
public class MarkerAdapter {
class MarkerCategory extends MarkerNode {
MarkerAdapter markerAdapter;
int start;
int end;
private ConcreteMarker[] children;
private String name;
/**
* Create a new instance of the receiver that has the markers between
* startIndex and endIndex showing.
*
* @param adapter
* @param startIndex
* @param endIndex
*/
MarkerCategory(MarkerAdapter adapter, int startIndex, int endIndex,
String categoryName) {
markerAdapter = adapter;
start = startIndex;
end = endIndex;
name = categoryName;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.views.markers.internal.MarkerNode#getChildren()
*/
public MarkerNode[] getChildren() {
if (children == null) {
// Return nothing while a build is going on as this could be
// stale
if (building) {
return Util.EMPTY_MARKER_ARRAY;
}
ConcreteMarker[] allMarkers = markerAdapter.lastMarkers
.toArray();
int totalSize = getDisplayedSize();
children = new ConcreteMarker[totalSize];
System.arraycopy(allMarkers, start, children, 0, totalSize);
// Sort them locally now
view.getTableSorter().sort(view.getViewer(), children);
for (int i = 0; i < children.length; i++) {
children[i].setCategory(this);
}
}
return children;
}
/**
* Return the number of errors being displayed.
*
* @return int
*/
int getDisplayedSize() {
if (view.getMarkerLimit() > 0) {
return Math.min(getTotalSize(), view.getMarkerLimit());
}
return getTotalSize();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.views.markers.internal.MarkerNode#getParent()
*/
public MarkerNode getParent() {
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.views.markers.internal.MarkerNode#getDescription()
*/
public String getDescription() {
int size = end - start + 1;
if (size <= view.getMarkerLimit()) {
if (size == 1)
return NLS.bind(MarkerMessages.Category_One_Item_Label,
new Object[] { name });
return NLS.bind(MarkerMessages.Category_Label, new Object[] {
name, String.valueOf(getDisplayedSize()) });
}
return NLS.bind(MarkerMessages.Category_Limit_Label, new Object[] {
name, String.valueOf(getDisplayedSize()),
String.valueOf(getTotalSize()) });
}
/**
* Get the total size of the receiver.
*
* @return int
*/
private int getTotalSize() {
return end - start + 1;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.views.markers.internal.MarkerNode#isConcrete()
*/
public boolean isConcrete() {
return false;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.views.markers.internal.MarkerNode#getConcreteRepresentative()
*/
public ConcreteMarker getConcreteRepresentative() {
return markerAdapter.lastMarkers.getMarker(start);
}
/**
* Return the name of the receiver.
*
* @return String
*/
public String getName() {
return name;
}
}
MarkerView view;
private MarkerList lastMarkers;
private MarkerCategory[] categories;
private boolean building = true;// Start with nothing until we have
// something
/**
* Create a new instance of the receiver.
*
* @param markerView
*/
MarkerAdapter(MarkerView markerView) {
view = markerView;
}
/**
* Return the category sorter for the receiver. This should only be called
* in hierarchal mode or there will be a ClassCastException.
*
* @return CategorySorter
*/
public CategoryComparator getCategorySorter() {
return (CategoryComparator) view.getViewer().getComparator();
}
/**
* Build all of the markers in the receiver.
*
* @param collector
* @param monitor
*/
public void buildAllMarkers(IProgressMonitor monitor) {
building = true;
MarkerList newMarkers;
try {
int markerLimit = view.getMarkerLimit();
monitor.beginTask(MarkerMessages.MarkerView_19,
markerLimit == -1 ? 60 : 100);
try {
monitor.subTask(MarkerMessages.MarkerView_waiting_on_changes);
if (monitor.isCanceled())
return;
monitor
.subTask(MarkerMessages.MarkerView_searching_for_markers);
SubProgressMonitor subMonitor = new SubProgressMonitor(monitor,
10);
MarkerFilter[] filters = view.getEnabledFilters();
if (filters.length > 0)
newMarkers = MarkerList.compute(filters, subMonitor, true);
else
// Grab any filter as a disabled filter gives all of them
newMarkers = MarkerList.compute(new MarkerFilter[] { view
.getAllFilters()[0] }, subMonitor, true);
if (monitor.isCanceled())
return;
view.refreshMarkerCounts(monitor);
} catch (CoreException e) {
Util.log(e);
newMarkers = new MarkerList();
return;
}
if (monitor.isCanceled())
return;
ViewerComparator sorter = view.getViewer().getComparator();
if (markerLimit == -1 || isShowingHierarchy()) {
sorter.sort(view.getViewer(), newMarkers.toArray());
} else {
monitor.subTask(MarkerMessages.MarkerView_18);
SubProgressMonitor mon = new SubProgressMonitor(monitor, 40);
newMarkers = SortUtil.getFirst(newMarkers, (Comparator) sorter,
markerLimit, mon);
if (monitor.isCanceled())
return;
sorter.sort(view.getViewer(), newMarkers.toArray());
}
if (newMarkers.getSize() == 0) {
categories = new MarkerCategory[0];
lastMarkers = newMarkers;
monitor.done();
return;
}
monitor.subTask(MarkerMessages.MarkerView_queueing_updates);
if (monitor.isCanceled())
return;
if (isShowingHierarchy()) {
MarkerCategory[] newCategories = buildHierarchy(newMarkers, 0,
newMarkers.getSize() - 1, 0);
if (monitor.isCanceled())
return;
categories = newCategories;
}
lastMarkers = newMarkers;
monitor.done();
} finally {
building = false;
}
}
/**
* Return whether or not a hierarchy is showing.
*
* @return boolean
*/
boolean isShowingHierarchy() {
ViewerComparator sorter = view.getViewer().getComparator();
if (sorter instanceof CategoryComparator) {
return ((CategoryComparator) sorter).getCategoryField() != null;
}
return false;
}
/**
* Break the marker up into categories
*
* @param markers
* @param start
* the start index in the markers
* @param end
* the last index to check
* @param sortIndex -
* the parent of the field
* @param parent
* @return MarkerCategory[] or <code>null</code> if we are at the bottom
* of the tree
*/
MarkerCategory[] buildHierarchy(MarkerList markers, int start, int end,
int sortIndex) {
CategoryComparator sorter = getCategorySorter();
if (sortIndex > 0) {
return null;// Are we out of categories?
}
Collection categories = new ArrayList();
Object previous = null;
int categoryStart = start;
Object[] elements = markers.getArray();
for (int i = start; i <= end; i++) {
if (previous != null) {
// Are we at a category boundary?
if (sorter.compare(previous, elements[i], sortIndex, false) != 0) {
categories.add(new MarkerCategory(this, categoryStart,
i - 1, getNameForIndex(markers, categoryStart)));
categoryStart = i;
}
}
previous = elements[i];
}
if (end >= categoryStart) {
categories.add(new MarkerCategory(this, categoryStart, end,
getNameForIndex(markers, categoryStart)));
}
// Flatten single categories
// if (categories.size() == 1) {
// return buildHierarchy(markers, start, end, sortIndex + 1, parent);
// }
MarkerCategory[] nodes = new MarkerCategory[categories.size()];
categories.toArray(nodes);
return nodes;
}
/**
* Get the name for the category from the marker at categoryStart in
* markers.
*
* @param markers
* @param categoryStart
* @return String
*/
private String getNameForIndex(MarkerList markers, int categoryStart) {
return getCategorySorter().getCategoryField().getValue(
markers.toArray()[categoryStart]);
}
/**
* Return the current list of markers.
*
* @return MarkerList
*/
public MarkerList getCurrentMarkers() {
if (lastMarkers == null) {// First time?
view.scheduleMarkerUpdate(Util.SHORT_DELAY);
building = true;
}
if (building) {
return new MarkerList();
}
return lastMarkers;
}
/**
* Return the elements in the adapter.
*
* @param root
* @return Object[]
*/
public Object[] getElements() {
if (lastMarkers == null) {// First time?
view.scheduleMarkerUpdate(Util.SHORT_DELAY);
building = true;
}
if (building) {
return Util.EMPTY_MARKER_ARRAY;
}
if (isShowingHierarchy() && categories != null) {
return categories;
}
return lastMarkers.toArray();
}
/**
* Return whether or not the receiver has markers without scheduling
* anything if it doesn't.
*
* @return boolean <code>true</code> if the markers have not been
* calculated.
*/
public boolean hasNoMarkers() {
return lastMarkers == null;
}
/**
* Return the categories for the receiver.
*
* @return MarkerCategory[] or <code>null</code> if there are no
* categories.
*/
public MarkerCategory[] getCategories() {
if (building) {
return null;
}
return categories;
}
/**
* Return whether or not the receiver is building.
* @return boolean
*/
boolean isBuilding() {
return building;
}
}