blob: 2b7f32d38811c90fdf17c6e518e9c88eeb50f558 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2015 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
* Andrey Loskutov <loskutov@gmx.de> - generified interface, bug 461762
*******************************************************************************/
package org.eclipse.ui.internal.views.markers;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ui.internal.ide.Policy;
import org.eclipse.ui.views.markers.MarkerViewUtil;
import org.eclipse.ui.views.markers.internal.MarkerMessages;
import org.eclipse.ui.views.markers.internal.MarkerTypesModel;
import com.ibm.icu.text.CollationKey;
import com.ibm.icu.text.Collator;
/**
* The MarkerEntry is the class that wrappers an {@link IMarker} for display in
* an {@link ExtendedMarkersView}.
*
* @since 3.4
*
*/
class MarkerEntry extends MarkerSupportItem implements IAdaptable {
static {
Platform.getAdapterManager().registerAdapters(new IAdapterFactory() {
@Override
public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
if (adapterType == IMarker.class && adaptableObject instanceof MarkerEntry) {
return adapterType.cast(((MarkerEntry) adaptableObject).getMarker());
}
return null;
}
@Override
public Class<?>[] getAdapterList() {
return new Class[] { IMarker.class };
}
}, MarkerEntry.class);
}
// The key for the string we built for display
private static final String LOCATION_STRING = "LOCATION_STRING"; //$NON-NLS-1$
private MarkerCategory category;
private Map<String, Object> cache;
/**
* Set the MarkerEntry to be stale, if discovered at any point of time
* of its use.This will greatly speed up a lot of parts of the view.
* @since 3.6
*/
private boolean stale;
/**
* Important:
* access to these fields must be via methods, they must be in sync and their
* values should reflect correctly the state of the other
*/
private IMarker marker;
/**
* Create a new instance of the receiver.
*
* @param marker
*/
public MarkerEntry(IMarker marker) {
this.marker = marker;
stale = false;
}
@Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter.equals(IMarker.class)) {
return adapter.cast(marker);
}
return null;
}
@Override
public boolean getAttributeValue(String attribute, boolean defaultValue) {
Object value = getAttributeValue(attribute);
if (value == null) {
return defaultValue;
}
return ((Boolean) value).booleanValue();
}
@Override
public int getAttributeValue(String attribute, int defaultValue) {
Object value = getAttributeValue(attribute);
if (value == null) {
return defaultValue;
}
return ((Integer) value).intValue();
}
/**
* Return the Object that is the marker value for attribute. Return null if
* it is not found.
*
* @param attribute
* @return Object or <code>null</code>
*/
Object getAttributeValue(String attribute) {
Object value = getCache().get(attribute);
if(value == null) {
if(stale){
return value;
}
try {
value = marker.getAttribute(attribute);
} catch (CoreException e) {
checkIfMarkerStale() ;
value = null;
}
if(value != null) {
getCache().put(attribute, value);
}
}
if (value instanceof CollationKey) {
return ((CollationKey) value).getSourceString();
}
return value;
}
@Override
public String getAttributeValue(String attribute, String defaultValue) {
Object value = getAttributeValue(attribute);
if (value == null) {
return defaultValue;
}
// The following toString() is a no-op for string attribute
// values (which we expect!), but safeguards against clients
// who used non-String objects (e.g. Integer) as attribute values,
// see bug 218249.
return value.toString();
}
/**
* Get the category of the receiver.
*
* @return {@link MarkerCategory}
*/
MarkerCategory getCategory() {
return category;
}
@Override
MarkerSupportItem[] getChildren() {
return MarkerSupportInternalUtilities.EMPTY_MARKER_ITEM_ARRAY;
}
/**
* Get the CollationKey for the string attribute.
*
* @param attribute
* @param defaultValue
* the defaultValue if the value is not set
* @return CollationKey
*/
CollationKey getCollationKey(String attribute, String defaultValue) {
String attributeValue;
Object value = getCache().get(attribute);
if (value != null) {
// Only return a collation key otherwise
//use the value to generate it
if (value instanceof CollationKey) {
return (CollationKey) value;
}
attributeValue = value.toString();
} else {
attributeValue = getAttributeValue(attribute, defaultValue);
}
if (attributeValue.length() == 0) {
return MarkerSupportInternalUtilities.EMPTY_COLLATION_KEY;
}
CollationKey key = Collator.getInstance().getCollationKey(attributeValue);
getCache().put(attribute, key);
return key;
}
@Override
long getCreationTime() {
if(stale){
return -1;
}
try {
return marker.getCreationTime();
} catch (CoreException e) {
checkIfMarkerStale();
Policy.handle(e);
return -1;
}
}
@Override
String getDescription() {
return getAttributeValue(IMarker.MESSAGE, MarkerSupportInternalUtilities.UNKNOWN_ATRRIBTE_VALUE_STRING);
}
@Override
long getID() {
return marker.getId();
}
@Override
public String getLocation() {
if(stale||checkIfMarkerStale()){
return MarkerSupportInternalUtilities.UNKNOWN_ATRRIBTE_VALUE_STRING;
}
if (getCache().containsKey(LOCATION_STRING)) {
Object value = getCache().get(LOCATION_STRING);
if (value instanceof CollationKey) {
return ((CollationKey) value).getSourceString();
}
return (String) value;
}
// Is the location override set?
String locationString = getAttributeValue(IMarker.LOCATION, MarkerSupportInternalUtilities.EMPTY_STRING);
if (locationString.length() > 0) {
getCache().put(LOCATION_STRING, locationString);
return locationString;
}
// No override so use line number
int lineNumber = getAttributeValue(IMarker.LINE_NUMBER, -1);
String lineNumberString;
if (lineNumber < 0) {
lineNumberString = MarkerMessages.Unknown;
} else {
lineNumberString = NLS.bind(MarkerMessages.label_lineNumber, Integer.toString(lineNumber));
}
getCache().put(LOCATION_STRING, lineNumberString);
return lineNumberString;
}
@Override
public IMarker getMarker() {
return marker;
}
@Override
String getMarkerTypeName() {
if(stale){
return NLS.bind(MarkerMessages.FieldMessage_WrongType, marker.toString());
}
try {
return MarkerTypesModel.getInstance().getType(marker.getType()).getLabel();
} catch (CoreException e) {
checkIfMarkerStale() ;
Policy.handle(e);
return NLS.bind(MarkerMessages.FieldMessage_WrongType, marker.toString());
}
}
String getMarkerTypeId() {
if(stale){
return NLS.bind(MarkerMessages.FieldMessage_WrongType, marker.toString());
}
try {
return marker.getType();
} catch (CoreException e) {
checkIfMarkerStale();
Policy.handle(e);
return NLS.bind(MarkerMessages.FieldMessage_WrongType, marker.toString());
}
}
@Override
MarkerSupportItem getParent() {
return category;
}
@Override
public String getPath() {
String folder = getAttributeValue(MarkerViewUtil.PATH_ATTRIBUTE, null);
if (folder != null) {
return folder;
}
if (stale||checkIfMarkerStale()) {
return MarkerSupportInternalUtilities.UNKNOWN_ATRRIBTE_VALUE_STRING;
}
IPath path = marker.getResource().getFullPath();
int n = path.segmentCount() - 1; // n is the number of segments
// in container, not path
if (n <= 0) {
return super.getPath();
}
folder = path.removeLastSegments(1).removeTrailingSeparator().toString();
getCache().put(MarkerViewUtil.PATH_ATTRIBUTE, folder);
return folder;
}
@Override
boolean isConcrete() {
return true;
}
/**
* Set the category to markerCategory.
*
* @param markerCategory
*/
void setCategory(MarkerCategory markerCategory) {
category = markerCategory;
}
/**
* Set the marker for the receiver.
*
* @param marker
* The marker to set.
*/
void setMarker(IMarker marker) {
this.marker = marker;
// reset stale
stale = false;
clearCache();
}
/**
* Get the cache for the receiver. Create if neccessary.
*
* @return {@link HashMap}
*/
Map<String, Object> getCache() {
if (cache == null) {
cache = new HashMap<>(2);
}
return cache;
}
/**
* Clear the cached values for performance reasons.
*/
@Override
void clearCache() {
cache = null;
}
/**
* @return true if the marker does not exist
* else false
*/
boolean checkIfMarkerStale() {
if (stale) {
return true;
}
if (marker == null || !marker.exists()) {
stale = true;
}
return stale;
}
/**
*
* @return true if the {@link MarkerEntry} is stale,i.e. the marker does not
* exist. A false value can mean that marker's state of existence was
* never captured or that it exists.#checkIfMarkerExists() will
* accurately indicate its state.
*/
boolean getStaleState() {
return stale;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((marker == null) ? 0 : marker.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof MarkerEntry)) {
return false;
}
MarkerEntry other = (MarkerEntry) obj;
if (marker == null) {
if (other.marker != null) {
return false;
}
} else if (!marker.equals(other.marker)) {
return false;
}
return true;
}
}