blob: 250843c0480305206931abf9486ed2b90fbda192 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Broadcom Corp. - James Blackburn - Fix for Bug 305529 -
* [Markers] NPE in MarkerFieldEditor if MarkerFieldConfiguration scope is unset
* Kit Lo (IBM) - Bug 542713 - Empty entries in Show menu after switching UI language to German
*******************************************************************************/
package org.eclipse.ui.internal.views.markers;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Adapters;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IPath;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.AggregateWorkingSet;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.Policy;
import org.eclipse.ui.internal.ide.StatusUtil;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.ui.views.markers.FiltersContributionParameters;
import org.eclipse.ui.views.markers.MarkerField;
import org.eclipse.ui.views.markers.MarkerFieldFilter;
import org.eclipse.ui.views.markers.internal.MarkerFilter;
import org.eclipse.ui.views.markers.internal.MarkerSupportRegistry;
import org.eclipse.ui.views.markers.internal.MarkerType;
/**
* MarkerFieldFilterGroup is the representation of a grouping of marker filters.
*
* @since 3.4
*
*/
class MarkerFieldFilterGroup {
private static final String ATTRIBUTE_ON_ANY_IN_SAME_CONTAINER = "ON_ANY_IN_SAME_CONTAINER";//$NON-NLS-1$
private static final String ATTRIBUTE_ON_SELECTED_AND_CHILDREN = "ON_SELECTED_AND_CHILDREN";//$NON-NLS-1$
private static final String ATTRIBUTE_ON_SELECTED_ONLY = "ON_SELECTED_ONLY"; //$NON-NLS-1$
/**
* The attribute values for the scope
*
*/
private static final String ATTRIBUTE_SCOPE = "scope"; //$NON-NLS-1$
private static final String ATTRIBUTE_VALUES = "values"; //$NON-NLS-1$
/**
* Constant for any element.
*/
static final int ON_ANY = 0;
/**
* Constant for any element in same container.
*/
static final int ON_ANY_IN_SAME_CONTAINER = 3;
/**
* Constant for selected element and children.
*/
static final int ON_SELECTED_AND_CHILDREN = 2;
/**
* Constant for any selected element only.
*/
static final int ON_SELECTED_ONLY = 1;
/**
* Constant for on working set.
*/
static final int ON_WORKING_SET = 4;
static final String TAG_ENABLED = "enabled"; //$NON-NLS-1$
private static final String TAG_SCOPE = "scope"; //$NON-NLS-1$
private static final String TAG_FIELD_FILTER_ENTRY = "fieldFilter"; //$NON-NLS-1$
private static final String TAG_WORKING_SET = "workingSet"; //$NON-NLS-1$
private static final String TAG_LIMIT = "filterLimit"; //$NON-NLS-1$
// The identifier for user filters
private static String USER = "USER"; //$NON-NLS-1$
protected MarkerContentGenerator generator;
private IConfigurationElement element;
private Map<String, String> EMPTY_MAP = new HashMap<>();
private boolean enabled = true;
protected MarkerFieldFilter[] fieldFilters;
private int scope;
private int limit;
private String name;
private String id;
/**
* The entry for testing filters. Cached to prevent garbage.
*/
private MarkerEntry testEntry = new MarkerEntry(null);
private IWorkingSet workingSet;
private IResource[] wSetResources;
/**
* Create a new instance of the receiver.
*
* @param configurationElement
* @param markerBuilder
*/
public MarkerFieldFilterGroup(IConfigurationElement configurationElement, MarkerContentGenerator markerBuilder) {
element = configurationElement;
generator = markerBuilder;
initializeWorkingSet();
scope = processScope();
if (configurationElement == null) {
return;
}
String stringValue = configurationElement.getAttribute(MarkerSupportRegistry.ENABLED);
if (MarkerSupportInternalUtilities.FALSE.equals(stringValue)) {
enabled = false;
}
stringValue = configurationElement.getAttribute(MarkerSupportRegistry.FILTER_LIMIT);
if (stringValue == null || stringValue.length() == 0) {
limit = -1;
}
}
/**
* Get the root types for the receiver
*
* @return Collection of {@link MarkerType}
*/
Collection<MarkerType> getAllTypes() {
return generator.getMarkerTypes();
}
/**
* Get the filters registered on the receiver.
*
* @return MarkerFieldFilter[]
*/
private MarkerFieldFilter[] getFieldFilters() {
if (fieldFilters == null) {
calculateFilters();
}
return fieldFilters;
}
/**
* Calculate the filters for the receiver.
*/
protected void calculateFilters() {
Map<String, String> values = getValues();
Collection<MarkerFieldFilter> filters = new ArrayList<>();
for (MarkerField visibleField : generator.getVisibleFields()) {
MarkerFieldFilter fieldFilter = MarkerSupportInternalUtilities.generateFilter(visibleField);
if (fieldFilter != null) {
filters.add(fieldFilter);
// The type filter needs information from the generator
if (fieldFilter instanceof MarkerTypeFieldFilter) {
// Show everything by default
((MarkerTypeFieldFilter) fieldFilter).setContentGenerator(generator);
}
if (values != null) {
fieldFilter.initialize(values);
}
}
}
MarkerFieldFilter[] newFilters = new MarkerFieldFilter[filters.size()];
filters.toArray(newFilters);
fieldFilters = newFilters;
}
/**
* Return the MarkerFieldFilter for field or <code>null</code> if there
* isn't one.
*
* @param field
* @return MarkerFieldFilter
*/
public MarkerFieldFilter getFilter(MarkerField field) {
for (MarkerFieldFilter filter : getFieldFilters()) {
if (filter.getField().equals(field)) {
return filter;
}
}
return null;
}
/**
* Return the id of the receiver.
*
* @return String
*/
public String getID() {
if (id == null) {
if (element == null) {
id = USER + String.valueOf(System.currentTimeMillis());
} else {
id = element.getAttribute(MarkerSupportInternalUtilities.ATTRIBUTE_ID);
}
}
return id;
}
/**
* Return the name of the receiver.
*
* @return String
*/
public String getName() {
if (name == null) {
if (element == null) {
name = MarkerSupportInternalUtilities.EMPTY_STRING;
} else {
name = element.getAttribute(MarkerSupportInternalUtilities.ATTRIBUTE_NAME);
}
}
return name;
}
/**
* Return the resources in the working set. If it is empty then return the
* workspace root.
*
* @return IResource[]
*/
IResource[] getResourcesInWorkingSet() {
if (workingSet == null) {
return new IResource[0];
}
//Return workspace root for aggregates with no containing workingsets,ex. window working set
if (workingSet.isAggregateWorkingSet()&&workingSet.isEmpty()){
if(((AggregateWorkingSet) workingSet).getComponents().length==0) {
return new IResource[] { ResourcesPlugin.getWorkspace().getRoot()};
}
}
IAdaptable[] elements = workingSet.getElements();
List<IResource> result = new ArrayList<>(elements.length);
for (IAdaptable adaptable : elements) {
IResource next = Adapters.adapt(adaptable, IResource.class);
if (next != null) {
result.add(next);
}
}
return result.toArray(new IResource[result.size()]);
}
/**
* Return the value of the scope.
*
* @return int
* @see #ON_ANY
* @see #ON_ANY_IN_SAME_CONTAINER
* @see #ON_SELECTED_AND_CHILDREN
* @see #ON_SELECTED_ONLY
* @see #ON_WORKING_SET
*/
@SuppressWarnings("javadoc")
public int getScope() {
return scope;
}
/**
* Get the values defined for the receiver.
*
* @return Map of values to apply to a {@link MarkerFieldFilter}
*/
private Map<String, String> getValues() {
try {
String className = null;
if (element != null) {
className = element.getAttribute(ATTRIBUTE_VALUES);
if (className != null) {
FiltersContributionParameters parameters = (FiltersContributionParameters) IDEWorkbenchPlugin
.createExtension(element, ATTRIBUTE_VALUES);
return parameters.getParameterValues();
}
}
} catch (CoreException e) {
Policy.handle(e);
return null;
}
return EMPTY_MAP;
}
/**
* Get the working set for the receiver.
*
* @return IWorkingSet
*/
IWorkingSet getWorkingSet() {
return workingSet;
}
/**
* Gather the resource is in the working set
*/
private void computeWorkingSetResources() {
if(workingSet!=null){
/* MarkerFieldFilterGroup will have to re-get the resources in
* a working set for every marker it filters using the select method
* Or we may do this once before the markers are filtered.
*/
wSetResources=getResourcesInWorkingSet();
}else{
wSetResources = new IResource[] { ResourcesPlugin.getWorkspace().getRoot() };
}
}
/**
* Return true if the resource is in the working set
* @param resource
* @return boolean
*/
private boolean isInWorkingSet(IResource resource) {
if (wSetResources == null) {
computeWorkingSetResources();
}
for (IResource wSetResource : wSetResources) {
if(wSetResource.getFullPath().isPrefixOf(resource.getFullPath())){
return true;
}
}
return false;
}
/**
* Initialise the working set for the receiver. Use the window working set
* for the working set and set the scope to ON_WORKING_SET if they are to be
* used by default.
*/
private void initializeWorkingSet() {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window != null) {
IWorkbenchPage page = window.getActivePage();
if (page != null) {
setWorkingSet(page.getAggregateWorkingSet());
if ((PlatformUI.getPreferenceStore()
.getBoolean(IWorkbenchPreferenceConstants.USE_WINDOW_WORKING_SET_BY_DEFAULT))) {
setScope(ON_WORKING_SET);
}
}
}
}
/**
* Return whether or not the receiver is enabled.
*
* @return boolean
*/
public boolean isEnabled() {
return enabled;
}
/**
* Return whether or not this is a system or user group.
*
* @return boolean <code>true</code> if it is a system group.
*/
public boolean isSystem() {
return element != null;
}
/**
* Load the settings from the legacy child.
*
* @param memento
*/
void legacyLoadSettings(IMemento memento) {
String enabledString = memento.getString(TAG_ENABLED);
if (enabledString != null && enabledString.length() > 0) {
enabled = Boolean.valueOf(enabledString).booleanValue();
}
Integer resourceSetting = memento.getInteger(MarkerFilter.TAG_ON_RESOURCE);
if (resourceSetting != null) {
scope = resourceSetting.intValue();
}
String workingSetName = memento.getString(TAG_WORKING_SET);
if (workingSetName != null) {
setWorkingSet(PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSet(workingSetName));
}
if (element == null) {
String nameString = memento.getID();
if (nameString != null && nameString.length() > 0) {
name = nameString;
}
String idString = memento.getString(IMemento.TAG_ID);
if (idString != null && idString.length() > 0) {
id = idString;
}
}
for (MarkerFieldFilter filter : getFieldFilters()) {
if (filter instanceof CompatibilityFieldFilter) {
((CompatibilityFieldFilter) filter).loadLegacySettings(memento, generator);
}
}
}
/**
* Load the current settings from the child.
*
* @param memento -
* the memento to load from
*/
void loadSettings(IMemento memento) {
String stringValue = memento.getString(TAG_ENABLED);
if (stringValue != null && stringValue.length() > 0){
enabled = Boolean.valueOf(stringValue).booleanValue();
}
scope = memento.getInteger(TAG_SCOPE).intValue();
String workingSetName = memento.getString(TAG_WORKING_SET);
if (workingSetName != null) {
setWorkingSet(PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSet(workingSetName));
}
stringValue = memento.getString(TAG_LIMIT);
if (stringValue != null && stringValue.length() > 0) {
setLimit(Integer.parseInt(stringValue));
}
Map<String, MarkerFieldFilter> filterMap = new HashMap<>();
for (MarkerFieldFilter filter : getFieldFilters()) {
filterMap.put(MarkerSupportInternalUtilities.getId(filter.getField()), filter);
}
for (IMemento childMemento : memento.getChildren(TAG_FIELD_FILTER_ENTRY)) {
String filterId = childMemento.getID();
MarkerFieldFilter filter = filterMap.get(filterId);
if (filter != null) {
if (filter instanceof MarkerTypeFieldFilter) {
((MarkerTypeFieldFilter) filter).setContentGenerator(generator);
}
filter.loadSettings(childMemento);
}
}
if (element == null) {
String nameString = memento .getString(MarkerSupportInternalUtilities.ATTRIBUTE_NAME);
if (nameString != null && nameString.length() > 0) {
name = nameString;
}
String idString = memento.getString(IMemento.TAG_ID);
if (idString != null && idString.length() > 0) {
id = idString;
}
}
}
/**
* Make a working copy of the receiver.
*
* @return MarkerFieldFilterGroup or <code> null</code> if it failed.
*/
MarkerFieldFilterGroup makeWorkingCopy() {
MarkerFieldFilterGroup clone = new MarkerFieldFilterGroup(this.element, this.generator);
if (populateClone(clone)) {
return clone;
}
return null;
}
/**
* Populate the clone and return true if successful.
*
* @param clone
*/
protected boolean populateClone(MarkerFieldFilterGroup clone) {
clone.scope = this.scope;
clone.limit = limit;
clone.workingSet = this.workingSet;
clone.enabled = this.enabled;
clone.fieldFilters = new MarkerFieldFilter[getFieldFilters().length];
clone.name = name;
clone.id = id;
for (int i = 0; i < fieldFilters.length; i++) {
try {
clone.fieldFilters[i] = fieldFilters[i].getClass().getDeclaredConstructor().newInstance();
fieldFilters[i].populateWorkingCopy(clone.fieldFilters[i]);
} catch (InstantiationException | IllegalArgumentException | IllegalAccessException
| InvocationTargetException | NoSuchMethodException
| SecurityException e) {
StatusManager.getManager().handle(StatusUtil.newError(e), StatusManager.SHOW);
return false;
}
}
return true;
}
/**
* Process the scope attribute.
*
* @return int
*/
private int processScope() {
if (element == null) {
return ON_ANY;
}
String scopeValue = element.getAttribute(ATTRIBUTE_SCOPE);
if (ATTRIBUTE_ON_SELECTED_ONLY.equals(scopeValue)) {
return ON_SELECTED_ONLY;
}
if (ATTRIBUTE_ON_SELECTED_AND_CHILDREN.equals(scopeValue)) {
return ON_SELECTED_AND_CHILDREN;
}
if (ATTRIBUTE_ON_ANY_IN_SAME_CONTAINER.equals(scopeValue)) {
return ON_ANY_IN_SAME_CONTAINER;
}
return ON_ANY;
}
/**
* Save the settings for the receiver in the memento.
*
* @param memento
*/
void saveFilterSettings(IMemento memento) {
memento.putString(TAG_ENABLED, String.valueOf(enabled));
memento.putString(TAG_SCOPE, String.valueOf(scope));
memento.putString(TAG_LIMIT, String.valueOf(limit));
if (workingSet != null) {
memento.putString(TAG_WORKING_SET, workingSet.getName());
}
if (element == null) {
memento.putString(MarkerSupportInternalUtilities.ATTRIBUTE_NAME, getName());
memento.putString(IMemento.TAG_ID, getID());
}
for (MarkerFieldFilter filter : getFieldFilters()) {
IMemento child = memento.createChild(TAG_FIELD_FILTER_ENTRY,
MarkerSupportInternalUtilities.getId(filter.getField()));
filter.saveSettings(child);
}
}
/**
* Return whether or not this IMarker is being shown.
*
* @param marker
* @return <code>true</code> if it is being shown
*/
public boolean select(IMarker marker) {
testEntry.setMarker(marker);
return select(testEntry);
}
/**
* Return whether or not this MarkerEntry can be shown.
*
* @param entry
*
* @return <code>true</code> if it can be shown
*/
public boolean select(MarkerEntry entry) {
MarkerFieldFilter[] filters = getFieldFilters();
if (scope == ON_WORKING_SET && workingSet != null) {
if (!workingSet.isAggregateWorkingSet()){
if (!isInWorkingSet(entry.getMarker().getResource())) {
return false;
}
}
//skip this for aggregates with no containing workingsets, ex. window working set
else if(((AggregateWorkingSet) workingSet).getComponents().length!=0){
if (!isInWorkingSet(entry.getMarker().getResource())) {
return false;
}
}
}
for (MarkerFieldFilter filter : filters) {
if (filter.select(entry)) {
continue;
}
return false;
}
return true;
}
/**
* Set whether or not the receiver is enabled.
*
* @param enabled
* The enabled to set.
*/
void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* Set the name of the receiver.
*
* @param newName
*/
public void setName(String newName) {
name = newName;
}
/**
* Set the scope of the receiver.
*
* @param newScope
*/
public void setScope(int newScope) {
scope = newScope;
}
/**
* Set the working set of the receiver.
*
* @param workingSet
*/
void setWorkingSet(IWorkingSet workingSet) {
this.workingSet = workingSet;
}
/**
* @return Returns -1 for no limit else the limit.
*/
int getLimit() {
return limit;
}
/**
* @param limit
* The limit to set, -1 or 0 for no limit.
*/
void setLimit(int limit) {
this.limit = limit;
}
/**
* Refresh the MarkerFieldFilterGroup .
*/
void refresh() {
if (getScope() == ON_WORKING_SET) {
computeWorkingSetResources();
}
}
public boolean selectByFilters(MarkerEntry entry) {
return select(entry);
}
public boolean selectByScope(MarkerEntry entry, IResource[] resources) {
int scopeVal = getScope();
switch (scopeVal) {
case MarkerFieldFilterGroup.ON_ANY: {
return true;
}
case MarkerFieldFilterGroup.ON_SELECTED_ONLY: {
IPath markerPath=entry.getMarker().getResource().getFullPath();
for (IResource resource : resources) {
if(markerPath.equals(resource.getFullPath())){
return true;
}
}
return false;
}
case MarkerFieldFilterGroup.ON_SELECTED_AND_CHILDREN: {
IPath markerPath=entry.getMarker().getResource().getFullPath();
for (IResource resource : resources) {
if(resource.getFullPath().isPrefixOf(markerPath)){
return true;
}
}
return false;
}
case MarkerFieldFilterGroup.ON_ANY_IN_SAME_CONTAINER: {
IPath markerProjectPath=entry.getMarker().getResource().getFullPath();
IProject[] projects=MarkerResourceUtil.getProjects(resources);
for (IProject project : projects) {
if(project.getFullPath().isPrefixOf(markerProjectPath)){
return true;
}
}
return false;
}
case MarkerFieldFilterGroup.ON_WORKING_SET: {
return isInWorkingSet(entry.getMarker().getResource());
}
}
return true;
}
}