-
Notifications
You must be signed in to change notification settings - Fork 31
WindowBuilder Lifecycle
org.eclipse.wb.core.editor.multi.MultiPageEditor contains two pages:
- Source - standard org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor
- Design - org.eclipse.wb.core.editor.DesignPage
org.eclipse.wb.core.editor.DesignPage is a PageBook with two pages:
- The actual GUI editor - org.eclipse.wb.core.editor.DesignComposite
- Error display - org.eclipse.wb.core.editor.errors.ExceptionComposite
When switching from Source to Design in MultiPageEditor, DesignPage.handleActivate() is called, which triggers
org.eclipse.wb.core.editor.UndoManager.activate(). If UndoManager detects that the ICompilationUnit source hasn't been
parsed yet or has changed, it sets various listeners, and then triggers DesignPage.internal_refreshGEF().
DesignPage.internal_refreshGEF() performs two operations:
-
calls DesignPage.disposeAll(), which destroys the current model, including all resources it holds, and clears the GEF and palette. - raises IRunnableWithProgress, which calls
DesignPage.internal_refreshGEF_withProgress(), handling errors and, if necessary, callingDesignPage.showExceptionOnDesignPane().
DesignPage.internal_refreshGEF_withProgress() uses JavaInfoParser.parse(m_compilationUnit), obtaining the root
JavaInfo. It then configures this root JavaInfo with the DesignPageSite, which can be used to communicate with the
current editor. Why does m_rootObject.refresh() trigger? Finally, the call to
DesignComposite.refresh(m_rootObject, monitor) displays the GEF, component tree, palette, and actions.
org.eclipse.wb.core.parser.JavaInfoParser creates an ASTEditor, i.e., an AST CompilationUnit, and asks each
org.eclipse.wb.core.parser.IParseFactory.getRootContext() method in turn. If a CompilationUnit with types related to
this IParseFactory and its native toolkit is passed, it returns ParseRootContext.
ParseRootContext is a container with a root JavaInfo (only if we have something like "public class MyFrame extends JFrame"; if "main()" is used, it will be "null"); plus an ExecutionFlowDescription.
ExecutionFlowDescription is a description of how to traverse the AST. It starts with some MethodDeclarations, and then
org.eclipse.wb.core.eval.ExecutionFlowUtils walks the AST Statement by Statement, making transitions to the local
methods being called, using org.eclipse.wb.core.model.creation.ThisCreationSupport and CGLib, even if the calls to these
local methods are made from the bytecode of a subperclass.
If none of the IParseFactories return a ParseRootContext for JavaInfoParser, then it's assumed we must have a "main()" function. If there is no "main()", an error will occur.
When JavaInfoParser receives the ParseRootContext, it asks ExecutionFlowUtils to traverse the AST for this execution
flow using the visitor org.eclipse.wb.core.parser.JavaInfoParser.ExecutionFlowParseVisitor. During this process, each
encountered ClassInstanceCreation or MethodInvocation is passed to each IParseFactory. If the IParseFactory determines
that the passed-in component is a creation from its toolkit, it creates it (with the appropriate CreationSupport) and
returns it. The first one to succeed wins, but there shouldn't be any conflicts.
ExecutionFlowParseVisitor.bindChild_MethodInvocation() or bindChild_ClassInstanceCreation() is used to create declaration-based parent/child relationships based on parent/child flags in *.wbp-component.xml declarations.
After all ASTs have been traversed, JavaInfoParser.getRoot() is called. It:
- sends m_editorState.getBroadcast().getListener(JavaEventListener.class).bindComponents(m_components), giving it a chance to bind anything that would like to bind, given all the created JavaInfo objects.
- calls JavaInfoUtils.bindBinaryComponents(m_components), which binds the toolkit object models in parent/child if the toolkit objects are actually bound, but this happened in code we haven't seen—say, somewhere in the bytecode of the parent class. - the root JavaInfo is selected as the JavaInfo with the longest member... that is, the one with the largest number of children... although it turns out it started correctly...
- this root JavaInfo is notified to everyone that it is the main one:
root.getBroadcastJava().treeAlmostComplete(root, m_components)
Parsing is complete at this point.
During editing, all edit operations are performed between calls to ObjectInfo.start/endEdit(), either directly or
indirectly via org.eclipse.wb.core.utils.execution.ExecutionUtils.run(ObjectInfo objectInfo, RunnableEx runnable).
When ObjectInfo.endEdit() notices that we've completed the top-level operation, it calls ObjectInfo.refresh(). After
that, it calls various ObjectInfo.refresh*() methods. Specifically, JavaInfo.refresh_create(), which performs the same
AST traversal for execution flow, as JavaInfoParser. This time, models aren't created; they're simply executed via
org.eclipse.wb.core.model.JavaInfoEvaluationHelper. Finally, ObjectInfo.refresh() sends two notifications:
getBroadcastObject().refreshed();-
getBroadcastObject().refreshed2();GEF listens to one or both notifications and performs arefresh()for the EditParts.
Almost all GEF commands are implemented via org.eclipse.wb.core.gef.command.EditCommand, which uses
ExecutionUtils.run(ObjectInfo objectInfo, RunnableEx runnable), thus initiating a refresh() operation upon
completion.