/******************************************************************************* * Copyright © 2012, 2013 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.edt.debug.core.java.filters; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.edt.debug.core.EDTDebugCoreMessages; import org.eclipse.edt.debug.core.EDTDebugCorePlugin; import org.eclipse.edt.debug.core.IEGLDebugCoreConstants; import org.eclipse.edt.debug.core.PreferenceUtil; import org.eclipse.edt.debug.core.java.IEGLJavaDebugTarget; import org.eclipse.edt.debug.internal.core.java.filters.DefaultTypeFilterCategory; import org.eclipse.osgi.util.NLS; /** * Various type filter utility methods. */ public class TypeFilterUtil implements IPreferenceChangeListener { /** * The single instance. */ public static final TypeFilterUtil INSTANCE = new TypeFilterUtil(); /** * The ID for the type filters extension point. */ public static final String EXTENSION_POINT_TYPE_FILTERS = "javaTypeFilters"; //$NON-NLS-1$ /** * The type filter categories. */ private ITypeFilterCategory[] filterCategories; /** * The active type filters. */ private ITypeFilter[] activeFilters; /** * All the type filters. */ private ITypeFilter[] allFilters; private TypeFilterUtil() { // Only allow the singleton. } /** * @return all the installed filters. */ public synchronized ITypeFilter[] getAllFilters() { if ( allFilters == null ) { loadFilters(); } return allFilters; } /** * @return the currently enabled filters. */ public synchronized ITypeFilter[] getActiveFilters() { if ( activeFilters == null ) { loadFilters(); } return activeFilters; } private void calculateActiveFilters() { List<ITypeFilter> filterList = new ArrayList<ITypeFilter>( 10 ); for ( ITypeFilterCategory category : getTypeFilterCategories() ) { if ( category.isEnabled() ) { for ( ITypeFilter filter : category.getFilters() ) { filterList.add( filter ); } } } activeFilters = filterList.toArray( new ITypeFilter[ filterList.size() ] ); } /** * @return all the installed filter categories. */ public synchronized ITypeFilterCategory[] getTypeFilterCategories() { if ( filterCategories == null ) { loadFilters(); } return filterCategories; } private void loadFilters() { IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor( EDTDebugCorePlugin.PLUGIN_ID, EXTENSION_POINT_TYPE_FILTERS ); List<ITypeFilterCategory> categories = new ArrayList<ITypeFilterCategory>( elements.length ); List<ITypeFilter> filters = new ArrayList<ITypeFilter>( elements.length ); for ( IConfigurationElement element : elements ) { String name = element.getName(); if ( "category".equals( name ) ) //$NON-NLS-1$ { ITypeFilterCategory category = createCategory( element ); if ( category != null ) { categories.add( category ); } } else if ( "filter".equals( name ) ) //$NON-NLS-1$ { ITypeFilter filter = createFilter( element ); if ( filter != null ) { filters.add( filter ); } } } // Before we associate the filters with categories, save a copy so that we have a list of all the filters. allFilters = filters.toArray( new ITypeFilter[ filters.size() ] ); // Associate providers with the categories. if ( filters.size() > 0 ) { // For each provider, find its category. for ( Iterator<ITypeFilter> it = filters.iterator(); it.hasNext(); ) { ITypeFilter filter = it.next(); String targetId = filter.getCategoryId(); for ( ITypeFilterCategory category : categories ) { if ( targetId.equals( category.getId() ) ) { filter.setCategory( category ); category.addFilter( filter ); it.remove(); break; } } } if ( filters.size() > 0 ) { // For each provider still in the list, its target category wasn't found. StringBuilder buf = new StringBuilder( 100 ); for ( ITypeFilter filter : filters ) { buf.append( "id=" ); //$NON-NLS-1$ buf.append( filter.getId() ); buf.append( ", categoryId=" ); //$NON-NLS-1$ buf.append( filter.getCategoryId() ); buf.append( '\n' ); } EDTDebugCorePlugin.log( new Status( IStatus.WARNING, EDTDebugCorePlugin.PLUGIN_ID, NLS.bind( EDTDebugCoreMessages.TypeFilterProviderMissingCategory, buf.toString() ) ) ); } } filterCategories = categories.toArray( new ITypeFilterCategory[ categories.size() ] ); applyFilterEnablementPreferences(); applyStepTypePreferences(); calculateActiveFilters(); PreferenceUtil.addPreferenceChangeListener( this ); } private void applyFilterEnablementPreferences() { String enablement = PreferenceUtil.getString( IEGLDebugCoreConstants.PREFERENCE_TYPE_FILTER_ENABLEMENT, null ); if ( enablement != null && enablement.length() > 0 ) { // For any categories not in the preference, set it to use its defaults. List<ITypeFilterCategory> categoriesNotListed = new ArrayList<ITypeFilterCategory>( Arrays.asList( filterCategories ) ); // Comma-separated list of "categoryId=enablement" StringTokenizer tok = new StringTokenizer( enablement, ",", false ); //$NON-NLS-1$ while ( tok.hasMoreTokens() ) { String next = tok.nextToken(); int equals = next.indexOf( '=' ); if ( equals != -1 && equals < next.length() - 1 ) { String id = next.substring( 0, equals ); for ( ITypeFilterCategory category : filterCategories ) { if ( id.equals( category.getId() ) ) { category.setEnabled( Boolean.parseBoolean( next.substring( equals + 1 ) ) ); categoriesNotListed.remove( category ); break; } } } } for ( ITypeFilterCategory category : categoriesNotListed ) { category.setEnabled( category.getDefaultEnablement() ); } } else { // Use defaults. for ( ITypeFilterCategory category : filterCategories ) { category.setEnabled( category.getDefaultEnablement() ); } } } private void applyStepTypePreferences() { String stepTypes = PreferenceUtil.getString( IEGLDebugCoreConstants.PREFERENCE_TYPE_FILTER_STEP_TYPES, null ); if ( stepTypes != null && stepTypes.length() > 0 ) { // For any categories not in the preference, set it to use its defaults. List<ITypeFilterCategory> categoriesNotListed = new ArrayList<ITypeFilterCategory>( Arrays.asList( filterCategories ) ); // Comma-separated list of "categoryId=stepType" StringTokenizer tok = new StringTokenizer( stepTypes, ",", false ); //$NON-NLS-1$ while ( tok.hasMoreTokens() ) { String next = tok.nextToken(); int equals = next.indexOf( '=' ); if ( equals != -1 && equals < next.length() - 1 ) { String id = next.substring( 0, equals ); for ( ITypeFilterCategory category : filterCategories ) { if ( id.equals( category.getId() ) ) { category.setStepType( FilterStepType.parse( next.substring( equals + 1 ) ) ); categoriesNotListed.remove( category ); break; } } } } for ( ITypeFilterCategory category : categoriesNotListed ) { category.setStepType( category.getDefaultStepType() ); } } else { // Use defaults. for ( ITypeFilterCategory category : filterCategories ) { category.setStepType( category.getDefaultStepType() ); } } } private ITypeFilterCategory createCategory( IConfigurationElement element ) { ITypeFilterCategory category = null; // Required attributes. String id = element.getAttribute( "id" ); //$NON-NLS-1$ if ( id == null || (id = id.trim()).length() == 0 ) { EDTDebugCorePlugin.log( new Status( IStatus.WARNING, EDTDebugCorePlugin.PLUGIN_ID, NLS.bind( EDTDebugCoreMessages.TypeFilterExtensionRequiredAttributeMissing, "id" ) ) ); //$NON-NLS-1$ return null; } String name = element.getAttribute( "name" ); //$NON-NLS-1$ if ( name == null || (name = name.trim()).length() == 0 ) { EDTDebugCorePlugin.log( new Status( IStatus.WARNING, EDTDebugCorePlugin.PLUGIN_ID, NLS.bind( EDTDebugCoreMessages.TypeFilterExtensionRequiredAttributeMissing, "name" ) ) ); //$NON-NLS-1$ return null; } // Optional attributes. String clazz = element.getAttribute( "class" ); //$NON-NLS-1$ if ( clazz != null && (clazz = clazz.trim()).length() > 0 ) { try { Object o = element.createExecutableExtension( "class" ); //$NON-NLS-1$ if ( o instanceof ITypeFilterCategory ) { category = (ITypeFilterCategory)o; } } catch ( CoreException ce ) { EDTDebugCorePlugin.log( ce ); } } if ( category == null ) { category = new DefaultTypeFilterCategory(); } category.setId( id ); category.setName( name ); String desc = element.getAttribute( "description" ); //$NON-NLS-1$ if ( desc == null || (desc = desc.trim()).length() == 0 ) { category.setDescription( EDTDebugCoreMessages.NoDescription ); } else { category.setDescription( desc ); } String visible = element.getAttribute( "visible" ); //$NON-NLS-1$ if ( visible == null || (visible = visible.trim()).length() == 0 ) { category.setVisible( true ); } else { category.setVisible( Boolean.parseBoolean( visible ) ); } String defStepType = element.getAttribute( "defaultStepType" ); //$NON-NLS-1$ if ( defStepType == null || (defStepType = defStepType.trim()).length() == 0 ) { category.setDefaultStepType( FilterStepType.STEP_INTO ); } else { category.setDefaultStepType( FilterStepType.parse( defStepType ) ); } String defEnablement = element.getAttribute( "defaultEnablement" ); //$NON-NLS-1$ if ( defEnablement == null || (defEnablement = defEnablement.trim()).length() == 0 ) { category.setDefaultEnablement( true ); } else { category.setDefaultEnablement( Boolean.parseBoolean( defEnablement ) ); } // Initialize these to their default values, and then when processing the preferences these values might change if not using the default. category.setStepType( category.getDefaultStepType() ); category.setEnabled( category.getDefaultEnablement() ); return category; } private ITypeFilter createFilter( IConfigurationElement element ) { // All attributes are required. String id = element.getAttribute( "id" ); //$NON-NLS-1$ if ( id == null || (id = id.trim()).length() == 0 ) { EDTDebugCorePlugin.log( new Status( IStatus.WARNING, EDTDebugCorePlugin.PLUGIN_ID, NLS.bind( EDTDebugCoreMessages.TypeFilterExtensionRequiredAttributeMissing, "id" ) ) ); //$NON-NLS-1$ return null; } String categoryId = element.getAttribute( "categoryId" ); //$NON-NLS-1$ if ( categoryId == null || (categoryId = categoryId.trim()).length() == 0 ) { EDTDebugCorePlugin.log( new Status( IStatus.WARNING, EDTDebugCorePlugin.PLUGIN_ID, NLS.bind( EDTDebugCoreMessages.TypeFilterExtensionRequiredAttributeMissing, "categoryId" ) ) ); //$NON-NLS-1$ return null; } try { Object o = element.createExecutableExtension( "class" ); //$NON-NLS-1$ if ( o instanceof ITypeFilter ) { ITypeFilter filter = (ITypeFilter)o; filter.setId( id ); filter.setCategoryId( categoryId ); return filter; } } catch ( CoreException ce ) { EDTDebugCorePlugin.log( ce ); } return null; } @Override public void preferenceChange( PreferenceChangeEvent event ) { String key = event.getKey(); if ( IEGLDebugCoreConstants.PREFERENCE_TYPE_FILTER_STEP_TYPES.equals( key ) ) { applyStepTypePreferences(); } else if ( IEGLDebugCoreConstants.PREFERENCE_TYPE_FILTER_ENABLEMENT.equals( key ) ) { applyFilterEnablementPreferences(); calculateActiveFilters(); // Have each EGL Java target initialize the active filters, in case any are newly enabled. ITypeFilter[] filters = getActiveFilters(); for ( IDebugTarget target : DebugPlugin.getDefault().getLaunchManager().getDebugTargets() ) { IEGLJavaDebugTarget eglTarget = (IEGLJavaDebugTarget)target.getAdapter( IEGLJavaDebugTarget.class ); if ( eglTarget != null ) { for ( ITypeFilter filter : filters ) { filter.initialize( eglTarget ); } } } } } public void dispose() { if ( filterCategories != null ) { for ( ITypeFilterCategory category : filterCategories ) { category.dispose(); } filterCategories = null; } PreferenceUtil.removePreferenceChangeListener( this ); } }