/**
* This file Copyright (c) 2005-2008 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain other free and open source software ("FOSS") code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.editors.unified.folding;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IKeyBindingService;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import com.aptana.ide.editors.UnifiedEditorsPlugin;
import com.aptana.ide.editors.preferences.IPreferenceConstants;
import com.aptana.ide.editors.unified.IUnifiedEditor;
import com.aptana.ide.editors.unified.UnifiedEditor;
/**
* @author Kevin Sawicki (ksawicki@aptana.com)
*/
public final class FoldingExtensionPointLoader
{
/**
* Foldable types for a language
*/
public class FoldingStructure
{
String language;
String label;
IFoldingContextHandler handler;
Map types = new HashMap();
boolean foldAllParents = true;
/**
* Returns whether all nodes with children will be foldable
*
* @return - true if making parents foldable, false otherwise
*/
public boolean foldAllParents()
{
return foldAllParents;
}
/**
* Sets whether parents should be foldable or not
*
* @param foldAllParents -
* true for parents foldable, false otherwise
*/
public void setFoldAllParents(boolean foldAllParents)
{
this.foldAllParents = foldAllParents;
}
/**
* Gets the label for this folding structure
*
* @return - label for language
*/
public String getLabel()
{
return label;
}
/**
* Sets the label for this folding structure
*
* @param label -
* language label
*/
public void setLabel(String label)
{
this.label = label;
}
/**
* Gets the language
*
* @return - language mime type
*/
public String getLanguage()
{
return language;
}
/**
* Sets the language
*
* @param language -
* mime type
*/
public void setLanguage(String language)
{
this.language = language;
}
/**
* Gets the foldable types for this folding structure
*
* @return - list of strings of foldable node types
*/
public Map getTypes()
{
return types;
}
/**
* Sets the foldable node type list
*
* @param types
*/
public void setTypes(Map types)
{
this.types = types;
}
/**
* @return the foldAllParents
*/
public boolean isFoldAllParents()
{
return foldAllParents;
}
/**
* @return the handler
*/
public IFoldingContextHandler getHandler()
{
return handler;
}
/**
* @param handler
* the handler to set
*/
public void setHandler(IFoldingContextHandler handler)
{
this.handler = handler;
}
}
/**
* Folding action that is updateable
*/
private abstract static class FoldingAction extends Action
{
/**
* Creates a new folding action
*
* @param name
* @param style
*/
public FoldingAction(String name, int style)
{
super(name, style);
}
}
private static class AnnotationPosition implements Comparable<AnnotationPosition>
{
/**
* Position;
*/
private Position position;
/**
* Annotation.
*/
private Annotation annotation;
/**
* AnnotationPosition constructor.
* @param position - position.
* @param annotation - annotation.
*/
public AnnotationPosition(Position position, Annotation annotation)
{
super();
this.position = position;
this.annotation = annotation;
}
/**
* Gets position.
* @return the position.
*/
public Position getPosition()
{
return position;
}
/**
* Gets annotation.
* @return the annotation.
*/
public Annotation getAnnotation()
{
return annotation;
}
/**
* {@inheritDoc}
*/
public int compareTo(AnnotationPosition o)
{
return o.getPosition().getLength() - this.getPosition().getLength();
}
}
/**
* "Expand current" action ID.
*/
public static final String EXPAND_CURRENT_ACTION_ID = "org.eclipse.ui.edit.text.folding.expand"; //$NON-NLS-1$
/**
* "Collapse current" action ID.
*/
public static final String COLLAPSE_CURRENT_ACTION_ID = "org.eclipse.ui.edit.text.folding.collapse"; //$NON-NLS-1$
private Map structs = new HashMap();
private static FoldingExtensionPointLoader instance;
private FoldingExtensionPointLoader()
{
IExtensionRegistry reg = Platform.getExtensionRegistry();
IExtensionPoint ep = reg.getExtensionPoint(UnifiedEditorsPlugin.FOLDING_EXTENSION_POINT);
if (ep != null && ep.getExtensions() != null)
{
IExtension[] extensions = ep.getExtensions();
for (int i = 0; i < extensions.length; i++)
{
IConfigurationElement[] ce = extensions[i].getConfigurationElements();
for (int j = 0; j < ce.length; j++)
{
String language = ce[j].getAttribute("language"); //$NON-NLS-1$
String label = ce[j].getAttribute("label"); //$NON-NLS-1$
String foldParents = ce[j].getAttribute("foldAllParents"); //$NON-NLS-1$
if (language != null && label != null)
{
FoldingStructure fs = null;
if (structs.containsKey(language))
{
fs = (FoldingStructure) structs.get(language);
}
else
{
fs = new FoldingStructure();
structs.put(language, fs);
}
fs.language = language;
fs.label = label;
fs.foldAllParents = Boolean.valueOf(foldParents).booleanValue();
String handlerClass = ce[j].getAttribute("contextHandler"); //$NON-NLS-1$
if (handlerClass != null)
{
try
{
Object obj = ce[j].createExecutableExtension("contextHandler"); //$NON-NLS-1$
if (obj instanceof IFoldingContextHandler)
{
fs.handler = (IFoldingContextHandler) obj;
}
}
catch (CoreException e)
{
}
}
IConfigurationElement[] types = ce[j].getChildren("type"); //$NON-NLS-1$
for (int k = 0; k < types.length; k++)
{
String name = types[k].getAttribute("name"); //$NON-NLS-1$
String typeLabel = types[k].getAttribute("label"); //$NON-NLS-1$
if (name != null)
{
fs.types.put(name, typeLabel);
}
}
}
}
}
}
}
/**
* Gets the instance
*
* @return - the instance
*/
public static FoldingExtensionPointLoader getInstance()
{
if (instance == null)
{
instance = new FoldingExtensionPointLoader();
}
return instance;
}
/**
* Creates the folding actions for an editor
*
* @param editor
*/
public static void createFoldingActions(final UnifiedEditor editor)
{
final FoldingExtensionPointLoader loader = getInstance();
final String[] supportedTypes = editor.getBaseContributor().getContentTypes();
final FoldingAction fAllCollapseAll = new FoldingAction(Messages.FoldingExtensionPointLoader_10, IAction.AS_PUSH_BUTTON)
{
public void run()
{
if (editor.getViewer() != null && editor.getViewer() instanceof ProjectionViewer)
{
ProjectionViewer viewer = (ProjectionViewer) editor.getViewer();
if (viewer.canDoOperation(ProjectionViewer.COLLAPSE_ALL))
{
viewer.doOperation(ProjectionViewer.COLLAPSE_ALL);
}
}
}
};
editor.setAction(createCollapseAllActionId(), fAllCollapseAll);
final FoldingAction fAllExpandAll = new FoldingAction(Messages.FoldingExtensionPointLoader_11, IAction.AS_PUSH_BUTTON)
{
public void run()
{
if (editor.getViewer() != null && editor.getViewer() instanceof ProjectionViewer)
{
ProjectionViewer viewer = (ProjectionViewer) editor.getViewer();
if (viewer.canDoOperation(ProjectionViewer.EXPAND_ALL))
{
viewer.doOperation(ProjectionViewer.EXPAND_ALL);
}
}
}
};
editor.setAction(createExpandAllActionId(), fAllExpandAll);
final FoldingAction fExpandCurrent = new FoldingAction(Messages.FoldingExtensionPointLoader_12, IAction.AS_PUSH_BUTTON)
{
/**
* {@inheritDoc}
*/
@Override
public void run()
{
if (editor.getViewer() != null && editor.getViewer() instanceof ProjectionViewer)
{
ProjectionViewer viewer = (ProjectionViewer) editor.getViewer();
if (viewer.getProjectionAnnotationModel() != null)
{
ISelection selection = viewer.getSelection();
if (selection != null && selection instanceof TextSelection)
{
TextSelection textSelection = (TextSelection) selection;
ProjectionAnnotationModel model = viewer.getProjectionAnnotationModel();
model.expandAll(textSelection.getOffset(), textSelection.getLength());
}
}
}
}
};
fExpandCurrent.setActionDefinitionId(EXPAND_CURRENT_ACTION_ID);
editor.setAction(createExpandCurrentActionId(), fExpandCurrent);
final FoldingAction fCollapseCurrent = new FoldingAction(Messages.FoldingExtensionPointLoader_13, IAction.AS_PUSH_BUTTON)
{
/**
* {@inheritDoc}
*/
@Override
public void run()
{
if (editor.getViewer() != null && editor.getViewer() instanceof ProjectionViewer)
{
ProjectionViewer viewer = (ProjectionViewer) editor.getViewer();
if (viewer.getProjectionAnnotationModel() != null)
{
ISelection selection = viewer.getSelection();
if (selection != null && selection instanceof TextSelection)
{
TextSelection textSelection = (TextSelection) selection;
ProjectionAnnotationModel model = viewer.getProjectionAnnotationModel();
Iterator iterator= model.getAnnotationIterator();
List<AnnotationPosition> annotations = new ArrayList<AnnotationPosition>();
while (iterator.hasNext())
{
ProjectionAnnotation annotation= (ProjectionAnnotation) iterator.next();
if (!annotation.isCollapsed())
{
Position position= model.getPosition(annotation);
if (position != null && position.overlapsWith(position.getOffset(), position.getLength()))
{
annotations.add(new AnnotationPosition(position, annotation));
}
}
}
if (annotations.size() != 0)
{
model.collapse(annotations.get(annotations.size() - 1).getAnnotation());
}
}
}
}
}
};
fCollapseCurrent.setActionDefinitionId(COLLAPSE_CURRENT_ACTION_ID);
editor.setAction(createCollapseCurrentActionId(), fCollapseCurrent);
for (int i = 0; i < supportedTypes.length; i++)
{
if (loader.structs.containsKey(supportedTypes[i]))
{
final FoldingStructure fs = (FoldingStructure) loader.structs.get(supportedTypes[i]);
final String prefID = createEnablePreferenceId(fs.language);
final FoldingAction fExpandAll = new FoldingAction(Messages.FoldingExtensionPointLoader_14, IAction.AS_PUSH_BUTTON)
{
public void run()
{
if (editor.getViewer() != null && editor.getViewer() instanceof ProjectionViewer)
{
ProjectionViewer viewer = (ProjectionViewer) editor.getViewer();
if (viewer.getProjectionAnnotationModel() != null)
{
List mods = new ArrayList();
Iterator annotationIterator = viewer.getProjectionAnnotationModel()
.getAnnotationIterator();
if (annotationIterator != null)
{
while (annotationIterator.hasNext())
{
Annotation annotation = (Annotation) annotationIterator.next();
if (annotation instanceof LanguageProjectAnnotation)
{
LanguageProjectAnnotation lpa = (LanguageProjectAnnotation) annotation;
if (fs.language.equals(lpa.getLanguage()) && lpa.isCollapsed())
{
lpa.markExpanded();
mods.add(lpa);
}
}
}
viewer.getProjectionAnnotationModel().modifyAnnotations(null, null,
(Annotation[]) mods.toArray(new Annotation[mods.size()]));
}
}
}
}
};
editor.setAction(createExpandAllActionId(fs.language), fExpandAll); //$NON-NLS-1$
final FoldingAction fCollapseAll = new FoldingAction(Messages.FoldingExtensionPointLoader_15, IAction.AS_PUSH_BUTTON)
{
public void run()
{
if (editor.getViewer() != null && editor.getViewer() instanceof ProjectionViewer)
{
ProjectionViewer viewer = (ProjectionViewer) editor.getViewer();
if (viewer.getProjectionAnnotationModel() != null)
{
List mods = new ArrayList();
Iterator annotationIterator = viewer.getProjectionAnnotationModel()
.getAnnotationIterator();
if (annotationIterator != null)
{
while (annotationIterator.hasNext())
{
Annotation annotation = (Annotation) annotationIterator.next();
if (annotation instanceof LanguageProjectAnnotation)
{
LanguageProjectAnnotation lpa = (LanguageProjectAnnotation) annotation;
if (fs.language.equals(lpa.getLanguage()) && !lpa.isCollapsed())
{
lpa.markCollapsed();
mods.add(lpa);
}
}
}
viewer.getProjectionAnnotationModel().modifyAnnotations(null, null,
(Annotation[]) mods.toArray(new Annotation[mods.size()]));
}
}
}
}
};
editor.setAction(createCollapseAllActionId(fs.language), fCollapseAll); //$NON-NLS-1$
final FoldingAction fToggle = new FoldingAction(Messages.FoldingExtensionPointLoader_LBL_EnableFolding, IAction.AS_CHECK_BOX) {
public void run()
{
UnifiedEditorsPlugin.getDefault().getPreferenceStore().setValue(prefID, this.isChecked());
fCollapseAll.setEnabled(this.isChecked());
fExpandAll.setEnabled(this.isChecked());
}
};
fToggle.setEnabled(true);
fToggle.setChecked(true);
editor.setAction(createToggleActionId(fs.language), fToggle);
Iterator iterator = fs.types.keySet().iterator();
while (iterator.hasNext())
{
String name = (String) iterator.next();
String label = (String) fs.types.get(name);
if (label != null)
{
final FoldingAction nameExpandAction = new FoldingAction(Messages.FoldingExtensionPointLoader_16 + label,
IAction.AS_PUSH_BUTTON)
{
public void run()
{
super.run();
}
};
editor.setAction(createExpandActionId(fs.language, name), nameExpandAction);
final FoldingAction nameCollapseAction = new FoldingAction(Messages.FoldingExtensionPointLoader_17 + label,
IAction.AS_PUSH_BUTTON)
{
public void run()
{
super.run();
}
};
editor.setAction(createCollapseActionId(fs.language, name), nameCollapseAction);
}
}
}
}
}
/**
* Loads the reconciling strategy functionality for an editor from the folding extension point. The map returned
* from this method is used to determine what folding positions will be emitted from the UnifiedReconcilingStrategy.
*
* @param editor -
* editor to add folding
* @return - map of languages to folding structure objects
*/
public static Map loadChildTypes(UnifiedEditor editor)
{
Map childTypes = new HashMap();
final FoldingExtensionPointLoader loader = getInstance();
Iterator iter = loader.structs.keySet().iterator();
while (iter.hasNext())
{
final FoldingStructure fs = (FoldingStructure) loader.structs.get(iter.next());
// Check to see if language is in this editor before adding folding options
boolean containsLanguage = false;
String[] supportedTypes = editor.getBaseContributor().getContentTypes();
for (int i = 0; i < supportedTypes.length; i++)
{
if (fs.language.equals(supportedTypes[i]))
{
containsLanguage = true;
break;
}
}
if (containsLanguage)
{
childTypes.put(fs.language, fs);
}
}
return childTypes;
}
/**
* Registers key bindings.
* @param service - key binding service.
*/
public static void registerKeyBindings(ITextEditor editor, IKeyBindingService service)
{
IAction fExpandCurrentAction = editor.getAction(createExpandCurrentActionId());
if (fExpandCurrentAction != null)
{
service.registerAction(fExpandCurrentAction);
}
}
private static String createCollapseAllActionId()
{
return "FoldingCollapseAllLanguages"; //$NON-NLS-1$
}
private static String createExpandAllActionId()
{
return "FoldingExpandAllLanguages"; //$NON-NLS-1$
}
private static String createExpandCurrentActionId()
{
return "FoldingExpandCurrent"; //$NON-NLS-1$
}
private static String createCollapseCurrentActionId()
{
return "FoldingECollapseCurrent"; //$NON-NLS-1$
}
private static String createCollapseActionId(String language, String name)
{
return "FoldingCollapse" + language + name; //$NON-NLS-1$
}
private static String createExpandActionId(String language, String name)
{
return "FoldingExpand" + language + name; //$NON-NLS-1$
}
private static String createToggleActionId(String language)
{
return "FoldingToggle" + language; //$NON-NLS-1$
}
private static String createCollapseAllActionId(String language)
{
return "FoldingCollapseAll" + language; //$NON-NLS-1$
}
private static String createExpandAllActionId(String language)
{
return "FoldingExpandAll" + language; //$NON-NLS-1$
}
/**
* Creates a preference id for a language to store folding preferences
*
* @param language
* @return - preference string
*/
public static String createEnablePreferenceId(String language)
{
return IPreferenceConstants.EDITOR_FOLDING_ENABLED + "." + language; //$NON-NLS-1$
}
/**
* Creates a preference id for an initial folding of name and language
*
* @param language
* @param name
* @return - preference string
*/
public static String createInitialFoldingPreferenceId(String language, String name)
{
return IPreferenceConstants.INITIAL_FOLDING_ENABLED + "." + language + "." + name; //$NON-NLS-1$ //$NON-NLS-2$
}
private static void updateLanguageActions(ITextEditor editor, FoldingStructure fs)
{
IPreferenceStore store = UnifiedEditorsPlugin.getDefault().getPreferenceStore();
// Get preference for type
String prefId = createEnablePreferenceId(fs.language);
boolean fold = store.getBoolean(prefId);
// Toggle expand/collapse
IAction tAction = editor.getAction(createToggleActionId(fs.language));
if (tAction != null)
{
tAction.setChecked(fold);
tAction.setEnabled(true);
}
IAction eAction = editor.getAction(createExpandAllActionId(fs.language));
if (eAction != null)
{
eAction.setEnabled(fold);
}
IAction cAction = editor.getAction(createCollapseAllActionId(fs.language));
if (cAction != null)
{
cAction.setEnabled(fold);
}
Iterator iter = fs.types.keySet().iterator();
while (iter.hasNext())
{
String name = (String) iter.next();
IAction enAction = editor.getAction(createExpandActionId(fs.language, name));
if (enAction != null)
{
enAction.setEnabled(fold);
}
IAction cnAction = editor.getAction(createCollapseActionId(fs.language, name));
if (cnAction != null)
{
cnAction.setEnabled(fold);
}
}
}
/**
* Updates the action state (enabled, disabled, checked) for a given editor. The IUnifiedEditor passed in must also
* implement ITextEditor so the getAction method can be called.
*
* @param editor -
* IUnifiedEditor and ITextEditor implementing editor
*/
public static void updateActions(IUnifiedEditor editor)
{
final FoldingExtensionPointLoader loader = getInstance();
final String[] supportedTypes = editor.getBaseContributor().getContentTypes();
if (editor instanceof ITextEditor)
{
ITextEditor tEditor = (ITextEditor) editor;
if (supportedTypes.length == 1 && loader.structs.containsKey(supportedTypes[0]))
{
FoldingStructure fs = (FoldingStructure) loader.structs.get(supportedTypes[0]);
updateLanguageActions(tEditor, fs);
}
else
{
// Update language actions
for (int i = 0; i < supportedTypes.length; i++)
{
if (loader.structs.containsKey(supportedTypes[i]))
{
FoldingStructure fs = (FoldingStructure) loader.structs.get(supportedTypes[i]);
updateLanguageActions(tEditor, fs);
}
}
}
}
}
/**
* Fills a context menu for an editor with the folding options
*
* @param editor
* @param menu
*/
public static void fillRulerContextMenu(UnifiedEditor editor, IMenuManager menu)
{
final FoldingExtensionPointLoader loader = getInstance();
IMenuManager foldingMenu = new MenuManager("Folding", "projection"); //$NON-NLS-1$ //$NON-NLS-2$
menu.appendToGroup(ITextEditorActionConstants.GROUP_RULERS, foldingMenu);
String[] supportedTypes = editor.getBaseContributor().getContentTypes();
updateActions(editor);
if (supportedTypes.length == 1)
{
FoldingStructure fs = (FoldingStructure) loader.structs.get(supportedTypes[0]);
if (fs != null)
{
addFoldingStructureAction(foldingMenu, fs, editor);
}
}
else
{
IAction action = editor.getAction(createExpandAllActionId());
if (action != null)
{
foldingMenu.add(action);
}
action = editor.getAction(createCollapseAllActionId());
if (action != null)
{
foldingMenu.add(action);
}
Iterator iter = loader.structs.keySet().iterator();
while (iter.hasNext())
{
final FoldingStructure fs = (FoldingStructure) loader.structs.get(iter.next());
// Check to see if language is in this editor before adding folding options
boolean containsLanguage = false;
for (int i = 0; i < supportedTypes.length; i++)
{
if (fs.language.equals(supportedTypes[i]))
{
containsLanguage = true;
break;
}
}
if (containsLanguage)
{
IMenuManager languageMenu = new MenuManager(fs.label, fs.language);
foldingMenu.add(languageMenu);
addFoldingStructureAction(languageMenu, fs, editor);
}
}
}
}
private static void addFoldingStructureAction(IMenuManager parent, FoldingStructure fs, UnifiedEditor editor)
{
IAction action = editor.getAction(createToggleActionId(fs.language));
if (action != null)
{
parent.add(action);
}
action = editor.getAction(createExpandAllActionId(fs.language));
if (action != null)
{
parent.add(action);
}
action = editor.getAction(createCollapseAllActionId(fs.language));
if (action != null)
{
parent.add(action);
}
Iterator iter = fs.types.keySet().iterator();
while (iter.hasNext())
{
String name = (String) iter.next();
action = editor.getAction(createExpandActionId(fs.language, name));
if (action != null)
{
parent.add(action);
}
action = editor.getAction(createCollapseActionId(fs.language, name));
if (action != null)
{
parent.add(action);
}
}
}
/**
* @param model
* @param lang
* @param node
*/
public static void collapseAll(ProjectionAnnotationModel model, String lang, String node)
{
Iterator annotationIterator = model.getAnnotationIterator();
while (annotationIterator.hasNext())
{
Annotation annotation = (Annotation) annotationIterator.next();
if (annotation instanceof LanguageProjectAnnotation)
{
LanguageProjectAnnotation projectionAnnotation = (LanguageProjectAnnotation) annotation;
if (projectionAnnotation.getLanguage().equals(lang))
{
if (projectionAnnotation.getNodeType().equals(node))
{
model.collapse(annotation);
}
}
}
}
}
/**
* @param model
* @param lang
* @param node
*/
public static void expandAll(ProjectionAnnotationModel model, String lang, String node)
{
Iterator annotationIterator = model.getAnnotationIterator();
while (annotationIterator.hasNext())
{
Annotation annotation = (Annotation) annotationIterator.next();
if (annotation instanceof LanguageProjectAnnotation)
{
LanguageProjectAnnotation projectionAnnotation = (LanguageProjectAnnotation) annotation;
if (projectionAnnotation.getLanguage().equals(lang))
{
if (projectionAnnotation.getNodeType().equals(node))
{
model.expand(annotation);
}
}
}
}
}
}