ContentManager
class provides the user a way to select from among all the open nodes, which are usually files, in the IDE. It appears in JBuilder's UI as the set of tabs located at the top of the content pane. Each tab contains an open node's display name. It's possible using OpenTools to append your own menu options to the context popup that appears when right-clicking on a tab.
There is only one ContentManager
instance for each
Browser
. You can access its functionality indirectly only through Browser
methods. You can't replace the ContentManager
with the OpenTools API.
The
ContentView
provides the user a way to select from all the possible views of
the node currently selected through the ContentManager
. It appears in JBuilder's UI as the set of tabs at the bottom of the content pane and the pane itself. There is one tab for each NodeViewer
that accepts the node opened in the content pane. Each NodeViewer
is created by a NodeViewerFactory
that was registered with the Browser in the initOpenTool()
method.
There is one instance of ContentView
for each open node. You can access its functionality indirectly only through Browser
methods. You can't replace the ContentView
with the OpenTools API.
Each view of a node is provided by a separate instance of
NodeViewer
(usually implemented with the
AbstractNodeViewer
class).
Each NodeViewer
is created by its
NodeViewerFactory
, which must be registered with the Browser
during the OpenTools discovery process.
Each NodeViewer
must supply a JComponent
that becomes a child of the JTabbedPane
provided
by ContentView
. The entire JBuilder IDE is based on the Swing component architecture, so all ContentManager
UI components must be Swing-based.
Each NodeViewerFactory
must be associated with at least one particular
FileNode
class. There's no limit on the number of factories that can be registered for
the same FileNode
. JBuilder provides many different FileNode
classes. If a FileNode
isn't already defined for your file type, you must register a new one you create in your OpenTool's initOpenTool()
method. If a file with an extension hasn't been registered, it's treated as if it were a
TextFileNode
.
Here is an example of how it all works together. The TextNodeViewerFactory
is a registered NodeViewerFactory
that can display, or it accepts, all nodes of type TextFileNode
and its subclasses. When a TextFileNode
is added to the content pane (the ContentView
) in the browser, the TextNodeViewerFactory
creates an instance of TextNodeViewer
to display the contents of the node on the Source page in the content pane when the Source tab is selected.
Browser
methods provide access to the ContentManager
and its component classes. For convenience, some of those methods are also available in the
ProjectView
class.
The most commonly used Browser
methods are getActiveNode()
and
setActiveNode()
. The active node is the file that is currently selected in the ContentManager
. If the given node isn't currently open, calling setActiveNode()
opens it. The ConentManager
class contains other methods that find open nodes, close nodes, navigate between nodes, find NodeViewers
, and navigate between NodeViewers
.
The Browser
also provides some
BrowserListener
events that are tied to NodeViewer
activation and deactivation. If you are writing a NodeViewer
, however, you should override the similar NodeViewer
methods instead of using these events. (For instance browserActivated
only
goes to the active NodeViewer
which may change when the Browser
is "deactivated" because a wizard or other dialog has the focus. To ensure a
NodeViewer
is notified of the Browser, always invoke browserActivated()
prior to viewerActivated()
so it may fire multiple times.)
You can accomplish the same thing with code in the initOpenTool()
method that looks like this:
public static void initOpenTool(byte majorVersion, byte minorVersion) { if (majorVersion == PrimeTime.CURRENT_MAJOR_VERSION) { FileType ft = FileType.getFileType("mytxt"); if (ft == null) { ft.registerFileType("mytxt", FileType.getFileType("txt")); } } }
If can't associate your new file type with an existing one, you must register your own FileNode
in the initOpenTool()
method. Here's an example:
public static void initOpenTool(byte majorVersion, byte minorVersion) { if (majorVersion == PrimeTime.CURRENT_MAJOR_VERSION) { Icon ICON = BrowserIcons.ICON_FILEIMAGE; registerFileNodeClass("mine", "My source file", MyFileNode.class, ICON); } }
NodeViewerFactory
must provide the standard interface looked for by the OpenTools discovery
process and use it to register with the
Browser
with the registerNodeViewerFactory()
method. This method has an asFirst
boolean parameter that, if true, means that the NodeViewerFactory
is requesting that it appear as the first NodeViewer
for the file types it supports in the
ContentView's
JTabbedPane
. If more than one NodeViewerFactory
for the same file type makes the same request as all the OpenTools are discovered, only one can be honored, of course, so making the request doesn't guarantee your NodeViewerFactory
will have priority.
This code example registers a new NodeViewerFactory
with the Browser
and requests that it be the first NodeViewerFactory
:
public static void initOpenTool(byte majorVersion, byte minorVersion) { if (majorVersion == PrimeTime.CURRENT_MAJOR_VERSION) { Browser.registerNodeViewerFactory(new MyNodeViewerFactory(), true); } }
If you specify the -verbose command-line option as you start up JBuilder, the console display reports the successful registration of all NodeViewerFactories
.
FileNode
. Your implementation should look like the following:
public class MyFileNode extends FileNode { public static final Icon ICON = BrowserIcons.ICON_FILEIMAGE; public MyFileNode(Project project, Node parent, Url url) throws DuplicateNodeException { super(project, parent, url); } public javax.swing.Icon getDisplayIcon() { return ICON; } }
If the file contains text, you could base your implementation on
TextFileNode
. In that case, your implementation might be something like this:
public class MyFileNode extends TextFileNode { public MyFileNode(Project project, Node parent, Url url) throws DuplicateNodeException { super(project, parent, url); } public Class getEditorKitClass() { return MyEditorKit.class; } public Class getTextStructureClass() { return MyTextStructure.class; } }
In this example, you would have to register the MyEditorKit
class using the Open Tools API. See the Editor documentation for more details.
NodeViewerFactory
is a simple interface with only two methods to implement: canDisplayNode()
and createNodeViewer()
. When a user opens a file in JBuilder, each registered factory is checked to see if it can create a NodeViewer
for that file type. Here's an implementation of a NodeViewerFactory
:
public class MyNodeViewerFactory implements NodeViewerFactory { public boolean canDisplayNode(Node node) { return (node instanceof MyFileNode); } public NodeViewer createNodeViewer(Context context) { if (canDisplayNode(context.getNode())) { return new MyNodeViewer(context); } return null; } }
NodeViewer
: those that view a
FileNode
and those that view a
TextFileNode
.
The TextFileNode
viewer can use existing logic of the JBuilder editor.
AbstractNodeViewer
class, implementing a FileNode
-based NodeViewer
is easy. All you must do is provide a JComponent
for the file content and an optional JComponent
for the file structure to appear in the structure pane. You supply the name that appears on the
ContentView
tab, and the text that becomes the tab's tooltip. Here's an example:
public class MyNodeViewer extends AbstractNodeViewer { public MyNodeViewer(Context context) { super(context); } public String getViewerTitle() { return "MyView"; } public String getViewerDescription() { return "My cool viewer"; } public JComponent createViewerComponent() { if (context.getNode() instanceof MyFileNode) { return new MyViewerComponent(context); } return null; } public JComponent createStructureComponent() { return null; } }
Another way to implement such a viewer is based on AbstractBufferNodeViewer
.
If your viewer needs to read and write its content through the Virtual File System
and co-exist with other NodeViewers registered for your file type, then this
class greatly simplifies your work. It does this by notifying you that the
file buffer has changed only if your viewer is active.
TextFileNodes
, you don't need to implement the NodeViewer
. Instead you provide your customized implementations of the supporting classes used by the JBuilder editor NodeViewer
. These supporting classes include
TextEditorKit
,
and
AbstractScanner
.
If you don't override any of these, you end up with the same NodeViewer
as provided by default for a TextFileNode
.
See the Editor documentation for more details.
You can append your own
UpdateAction
or ActionGroup
to the ContentManager
pop-up menu that appears when right-click on a file tab. The following code demonstrates adding a
WizardAction
. Note that such wizards must be registered using the OpenTools API.
public static void initOpenTool(byte majorVersion, byte minorVersion) { if (majorVersion == PrimeTime.CURRENT_MAJOR_VERSION) { ContentManager.registerContextActionProvider(new ContextActionProvider() { public Action getContextAction(Browser browser, Node[] nodes) { if (browser.getActiveProject() != null) { return WIZARD_MyWizard; } return null; } }); } } public static final WizardAction WIZARD_MyWizard = new WizardAction ( "My wizard...", 'w', "My ContentManager wizard", BrowserIcons.ICON_BLANK, BrowserIcons.ICON_BLANK, false) { protected Wizard createWizard() { return new MyWizard(); } };
For more information about writing and registering wizards with the OpenTools API, see JBuilder wizard concepts.