Miscellaneous classes that don't fit into any of the other packages.
The most important of these is CMFactory, which is the class that provides access to the singleton instances of IProjectManager, ISwcManager, IRegistrar, and others.
Code model projects and listeners.
When the user opens the first file in an ActionScript or Flex project, the code model creates a code model project for it, reading all of the relevant ActionScript and MXML documents and SWC files in the project, its linked folders, and its class and library paths. (You can force a project to open before this point by using the IRegistrar class.). From that point on, you can retrieve an IProject from the IProjectManager and use it to find out about the contents of the project.
Various indices that provide interesting views on the saved data in the project.
The "name" indices (like IClassNameIndex and IVariableNameIndex) let you look up definitions by name. IEventAttributeIndex and IStyleAttributeIndex cache information about metadata attributes (e.g. [Style(name="color")] and [Event(name="click")] that exist in source files. And ITagInformationIndex and IVisibleComponentIndex let you examine the components and component properties that are implied by the ActionScript classes and MXML components in the project. With Flex Builder 3, there is now an ISearchIndex that enables reference and declaration detection.
The indices are updated whenever you save a file. If the user has changed a file but has not yet saved it, the changes will not yet be reflected in the indices.
Definitions and scopes.
Definitions include packages, classes, interfaces, variables, functions, and certain metadata (Style, Event and Effect tags). You can retrieve the definitions in a project in several ways. Various indices provide access to lists of definitions or allow you to look them up by qualified name (e.g. mx.core.Button) or short name (Button). IClasses or IInterfaces know how to return their members. IVariables and IFunctions can resolve their types to definitions. IASScopes can return lists of definitions in scope. IExpressionNodes can evaluate themselves and provide a definition.
There is a scope for each {} block in a file (including function bodies, class bodies, and so on). There is also a file-level scope for each file in the project and a project-level scope that holds cross-file definitions. Scopes keep track of which definitions are available where.
ASDefinitionFilter allows you to control how to search when looking for definitions. You will usually want to use one of the various static "create" methods to create a reasonable definition filter.
ActionScript parse tree nodes.
MXML and ActionScript files both have ActionScript parse trees. In the case of an MXML document, the MXML is translated into an equivalent ActionScript. Parts of the MXML document that are "ActionScript-y", like <mx:Script> tags, event attributes, and ID attributes on components are translated in such a way that the offsets into the original MXML file are put into the ActionScript parse tree.
ASOffsetInformation can be used to take an offset into a MXML or ActionScript file and find the corresponding position in the ActionScript parse tree (as an IASNode). From there, you can walk the parse tree. Some parse tree nodes are IExpressionNodes, for which you can retrieve a definition. Depending on context, individual identifiers may have definitions that are IVariables, IFunctions, IInterfaces, IClasses, or IPackages. Composite expressions (like foo.bar or (12+16)/4) will always resolve to an IClass or IInterface. Other parse tree nodes are IScopedNodes. These represent the nested scopes in the document ({} blocks, function bodies, class bodies, package bodies, and files). You can retrieve an IASScope from an IScopedNode and use it to look up definitions that are in scope.
Cache of SWFs and icons from SWC files in the project.
You should never hold onto an IProject or IIndex (or any of the structures that those things provide access to).
/**
* Given an open Flex project, get all qualified class names (e.g. mx.core.Button) in the project.
* @param flexProject Flex project
* @return array of qualified class names
*/
static public String [] getAllQualifiedClassNamesInProject(IFlexProject flexProject)
{
// Make sure the project has been registered. It will already have been registered
// if the user has already opened an MXML or ActionScript file in the project or any
// of its linked folders.
CMFactory.getRegistrar().registerProject(flexProject.getProject(), null);
String [] allClassNames = new String[0];
synchronized (CMFactory.getLockObject())
{
IProject project = CMFactory.getManager().getProjectFor(flexProject.getProject());
if (project != null)
{
IClassNameIndex classIndex = (IClassNameIndex)project.getIndex(IClassNameIndex.ID);
if (classIndex != null)
{
IClass [] allClasses = classIndex.getAllClasses();
allClassNames = new String[allClasses.length];
for (int i = 0; i < allClasses.length; i++)
{
allClassNames[i] = allClasses[i].getQualifiedName();
}
}
}
}
return allClassNames;
}
/**
* Given an open Flex project and a component, find the default property for that component (which is
* defined with a [DefaultProperty("")] metadata attribute above the class that generates the component)
* @param flexProject Flex project
* @param componentName full name of the component (XML namespace + short name)
* @return name of the default property
*/
static public String getDefaultPropertyForComponent(IFlexProject flexProject, XMLName componentName)
{
// Make sure the project has been registered. It will already have been registered
// if the user has already opened an MXML or ActionScript file in the project or any
// of its linked folders.
CMFactory.getRegistrar().registerProject(flexProject.getProject(), null);
String defaultPropertyName = null;
synchronized (CMFactory.getLockObject())
{
IProject project = CMFactory.getManager().getProjectFor(flexProject.getProject());
if (project != null)
{
ITagInformationIndex tagIndex = (ITagInformationIndex)project.getIndex(ITagInformationIndex.ID);
if (tagIndex != null)
{
ITagInformation tagInfo = tagIndex.getTagInformation(componentName);
if (tagInfo != null)
{
IClass currentClass = tagInfo.getClassForTag();
HashSet recursionGuard = new HashSet();
while (currentClass != null)
{
IMetaTags tags = currentClass.getMetaTags();
if (tags != null)
{
IMetaTag defaultTag = tags.getTagByName("DefaultProperty"); //$NON-NLS-1$
if (defaultTag instanceof IDefaultPropertyTag)
{
defaultPropertyName = ((IDefaultProperty)defaultTag.getPropertyName();
break;
}
}
currentClass = currentClass.getBaseClassDefinition(recursionGuard);
}
}
}
}
}
return defaultPropertyName;
}
/**
* Given an open Flex project, a component, and a property name, find the variable that corresponds to the
* component property and get the fully qualified name of its type (e.g. "Array" or "mx.controls.Button").
* @param flexProject Flex project
* @param componentName full name of the component (XML namespace + short name)
* @param propertyName name of a component property
* @return fully qualified name of the type of the component property
*/
static public String getTypeOfComponentProperty(IFlexProject flexProject, XMLName componentName, String propertyName)
{
// Make sure the project has been registered. It will already have been registered
// if the user has already opened an MXML or ActionScript file in the project or any
// of its linked folders.
CMFactory.getRegistrar().registerProject(flexProject.getProject(), null);
String defaultPropertyName = null;
synchronized (CMFactory.getLockObject())
{
IProject project = CMFactory.getManager().getProjectFor(flexProject.getProject());
if (project != null)
{
ITagInformationIndex tagIndex = (ITagInformationIndex)project.getIndex(ITagInformationIndex.ID);
if (tagIndex != null)
{
ITagInformation tagInfo = tagIndex.getTagInformation(componentName);
if (tagInfo != null)
{
ITagAttribute attributeInfo = tagInfo.getTagAttribute(propertyName);
if (attributeInfo instanceof ITagInspectableAttribute)
{
IVariable inspectableVariable = ((ITagInspectableAttribute)attributeInfo).getInspectable();
if (inspectableVariable != null)
{
IDefinition variableType = inspectableVariable.resolveVariableType(new ASDefinitionCache());
defaultPropertyName = variableType != null ? variableType.getQualifiedName() : null;
}
}
}
}
}
}
return defaultPropertyName;
}
/**
* Given a document and an offset, build an array of all of the classes, interfaces, functions, and variables
* in scope at the particular offset.
* @param document open document
* @param offset offset into document
* @return array of definitions in scope
*/
static public String [] getAllDefinitionsInScope(IDocument document, int offset)
{
String [] definitionStrings = new String[0];
synchronized (CMFactory.getLockObject())
{
IProject project = CMFactory.getManager().getProjectForDocument(document);
if (project != null)
{
IPath documentPath = CMFactory.getManager().getPathForDocument(document);
IFileNode fileNode = project.findFileNodeInProject(documentPath);
ASOffsetInformation offsetInformation = new ASOffsetInformation(offset, fileNode);
IASNode immediateNode = offsetInformation.getContainingNode();
IASNode currentNode = immediateNode;
while (currentNode != null && !(currentNode instanceof IScopedNode))
currentNode = currentNode.getParent();
if (currentNode instanceof IScopedNode)
{
IASScope scope = ((IScopedNode)currentNode).getScope();
ASDefinitionFilter filter = ASDefinitionFilter.createAllSymbolsFilter(immediateNode);
ArrayList definitionList = new ArrayList();
scope.findAllDefinitions(filter, new ASDefinitionCache(), definitionList);
ArrayList stringList = new ArrayList();
Iterator definitions = definitionList.iterator();
while (definitions.hasNext())
{
IDefinition currentDefinition = (IDefinition)definitions.next();
if (!currentDefinition.isImplicit())
{
if (currentDefinition instanceof IVariable ||
currentDefinition instanceof IClass ||
currentDefinition instanceof IInterface)
{
// Getters and setters implement both IVariable and IFunction. By looking for
// IVariable first, we're treating them as variables for our list.
stringList.add(currentDefinition.getName());
}
else if (currentDefinition instanceof IFunction)
{
IFunction currentFunction = (IFunction)currentDefinition;
if (!currentFunction.isConstructor())
{
String functionString = currentFunction.getName();
functionString += "("; //$NON-NLS-1$
IVariable [] arguments = currentFunction.getArguments();
for (int i = 0; i < arguments.length; i++)
{
if (i > 0)
functionString += ","; //$NON-NLS-1$
functionString += arguments[i].getName();
}
functionString += ")"; //$NON-NLS-1$
stringList.add(functionString);
}
}
}
}
definitionStrings = (String [])stringList.toArray(new String[0]);
}
}
}
return definitionStrings;
}