If these things are straightforward to do, why isn't there just a utility method to do them? In these cases the desired functionality is really a multi-stage process that the APIs require you to logically break up into separate pieces, each of which the APIs can handle cleanly. That way you have more control over the details.
FileObject
? How do I convert them?
A: Raw files on disk are generally represented in Java using
java.io.File
.
These correspond directly to what the operating system thinks of as
a file.
In the Open APIs, raw files are very rarely manipulated
directly. Rather, you should almost always be using
FileObject
s.
Besides the fact that virtually everything else in the APIs that
works with files expects FileObject
s, these have a
number of advantages:
File
s, unless you need to interface to external
tools. However, in case translation from one to the other is really
needed:
FileObject
representing a
File
, search through the
Repository's file systems
for
LocalFileSystem
s
(or any with one class path entry from
FileSystem.Environment
,
that being the path to a directory), and see if any such file
system has a root directory which is a prefix of the file. If so,
strip off the prefix and look up the right FileObject
.
If there is no matching directory, you will need to create a
LocalFileSystem
(e.g.) to hold the file object; you
will need to
mount
this file system in the Repository if you expect compilation,
execution, or debugging to work. (However, you may use
setHidden (true)
to reduce the UI impact of doing so.) Choose the root
directory for the new file system carefully; i.e. if you are
trying to represent a Java source file, check for a
package
statement and mount the proper root directory
based on this.
The source code for the Open File utility module demonstrates these techniques.
File
from a
FileObject
, you may use
NbClassPath.toFile(...)
.
Always remember to check for null
as a return value and
handle this gracefully!
NodeAction
).
I think it corresponds to a file in the Repository; how can I get
that file?
A: Just get the DataObject
as a cookie and go from
there:
Node n = ...; DataObject dob = (DataObject) n.getCookie (DataObject.class); if (dob == null) { // not a file node } else { // could also get all files in the data object, if desired: FileObject fo = dob.getPrimaryFile (); // do something with fo }
*.class
file) it came from?
A: Use
ClassElement.forName(String)
.
This will give you the class element, if one can be found by that
name.
You can try to look for the file it came from, too. However, be
aware that elements do not need to come from any physical source:
e.g. ClassElement.forName("java.util.Vector")
will
probably give you an element that is not based on any file, but
rather the live Vector
class in the Java VM. With that
caveat:
ClassElement ce = ClassElement.forName (myClassName); if (ce != null) { SourceElement se = ce.getSource (); if (se != null) { DataObject dob = (DataObject) se.getCookie (DataObject.class); if (dob != null) { FileObject fo = dob.getPrimaryFile (); // check if desired that fo.getExt ().equals ("java"), etc. } else { // didn't specify where it came from } } else { // no containing source, probably a class found only in the VM } } else { // not found at all }
A: Yes, you could; but please instead use the standard windowing system to do these sorts of things. Then you will properly handle workspace switching, docking, context help, various keyboard shortcuts, and many other things contributing to the IDE's appearance and functionality.
The
Window System API
describes the general steps you should use to open up new function
windows, if you need such a thing. Specifically, you should use
TopComponent
s
for such purposes.
You can also use
A: Yes, you can do all of these things. Refer to the
Actions API
for details.
A: Yes; you need to first get the selected node (which if the
Editor is selected, should correspond to the file being edited);
get the most recent editor pane open on it; and then access the
caret:
A: Yes, any place where the APIs expect to have an item
installed into a popup or regular menu, you can provide a submenu
instead. Usually this is done with a dummy action whose popup and
menu presenters is a submenu. See the
Actions API
for details.
A: This is possible using code such as:
A: If the file was added to a containing directory or
otherwise modified very soon before you tried to use the
FileSystems API to access it, it is possible the change was not yet
visible to the IDE. This can happen if the change is made by use of
A: Yes and no. Yes, because all NetBeans modules are Java
code, which is written as cleanly as possible and often provides
fairly well-defined interfaces to its functionality that could be
reusable, and which NetBeans programmers do use to communicate
between modules in some case. No, because currently none of these
interfaces are properly documented.
For example, the Java Sources Module (which provides a loader
for The reason these calls are not part of the APIs is because no
API to them has been carefully thought out and documented. The
details of the calls could change greatly from one version to the
next, and nobody is tracking such changes. So you can use these
module services, but you are on your own if there is an
incompatibility. Naturally, it is preferable to use only the Open
APIs if that is possible; in some cases it is unreasonable to make
this restriction.
Note that any module, not just a standard NetBeans module, can provide an API
to other modules. That is, you may decide to release a module which
has a published API. Then other modules can access that API,
providing they specify
dependencies on it using manifest versioning according to the
Modules API.
No module should use APIs from the IDE core (i.e. API
implementation), however, and no APIs for core classes will be
published. The only NetBeans module which connects directly to the
core (partially bypassing the Open APIs) is the Auto Update module,
since the APIs do not specify any mechanism for querying or
modifying the set of installed modules (by design); so, this module
depends on specifics of the NetBeans core implementation. Similarly,
the API Support and Scripting modules use one call in the core to install test modules.
A: You do not need to do this! Using the Java Hierarchy
API, you can find class elements (see
above),
which are automatically parsed from source code, examine their
contents such as methods, and then change any of these
contents--the code in the Editor will change automatically. Just
remember to save the file afterwards if necessary, using a
Note that modification, and saving, is possible even if the file
is not visually open in an Editor window. To make sure the file is
visible, use
If you really want direct access to the text of a file, you can
use
A: Yes. See the
Modules API
which describes how to include JavaHelp documentation in a module under
Help | Contents; and you can provide rich context help
rather easily, linking into the same documentation.
A: First of all, manifest file processing tools are
according to the JAR specification required to accept and ignore
unrecognized attributes--so if you mistyped the name of an
attribute (they should be case-insensitive) the IDE will not inform
you of this. If you supplied an invalid value, however, or
some sort of runtime problem occurred (e.g. a specified instance in
the JAR did not implement a required interface), then the IDE
should produce an error message--if it does not, that is a bug
which should be reported through the normal channels.
Using the API Support module, you may browse to module manifests in
the Explorer and they should be recognized as such. Select the node
and check its properties and subnodes in the Explorer; you can see at
a glance how the IDE is parsing your manifest, and if there are any
errors.
The most common error is forgetting that there is a distinction
between global attributes (specified in the head of the
manifest before any blank lines) and manifest sections
with their own attributes (specified in individual blocks after the
header, with blank lines separating them), which are only treated
specially by the IDE if they contain the attribute
A: You can do that. If you can somehow find a class
implementing
Rather, if you know which top component you care about, you can
just call
Better still is to be agnostic about which top component should
be providing the activated nodes, and just listen to changes in the
But best of all is not to have to ever directly pay attention to
the node selection. If you only need to know the node selection in
order to make some user action enabled or not, you should simply
extend
A: No, the
You may bind a key differently in different windows, by using
the normal Swing techniques of binding keystrokes to components. In
fact, some work when into implementing the global map so that it
would work across arbitrary components; it is overridden by local
bindings, such as navigation keys on dialogs or Explorer trees, or
various editing keys in the Editor.
Before you bind a key performing a high-level specific action,
such as F9 for
A: Not easily. You have a few options:
Pros: Adds the library as desired. Cons: Very
fragile. Assumes that the ide.cfg is actually read, which
is not always true (it is not read by the *.bat scripts
or the Unix scripts, for example). Easy to clobber existing user
customizations. Dependent on the exact structure of the IDE's
bin/ directory, which has changed quite a bit in the past
and could change again. Places library in startup classpath, whereas
it is preferred to have it in the module classloader only. Must be
done before the IDE starts, requiring some kind of manual installation
step and making updating your module very difficult.
Pros: Simple to implement and should be reliable. Version
of the library shipped can be controlled to match that which the
module was compiled against, avoiding potential version skew.
Cons: Impractical when the library is physically very large,
or there are licensing issues involved in redistributing it. Bugfix
upgrades to the master library may not be reflected in the IDE's copy.
Pros: Compliant with the Open APIs and reliable. The
library JAR may be located anywhere at runtime and could even be moved
or replaced at runtime. Cons: Potentially complex to
implement. Some use of reflection required, though it should be safe.
More complex build and test procedure for the module. The partition
between the two halves must be carefully chosen, especially for large
modules, to minimize the complexity of the interfaces and push as much
implementation as possible to one side or the other.
TopManager.notify(NotifyDescriptor)
to show dialogs that interact well with the IDE's window system,
and have a number of bits of prebuilt UI. You can use various
standard subclasses of NotifyDescriptor
to represent
simple messages; exceptions; general-purpose dialogs with content
panels; or even multi-stage wizards.
Installing items to Main Window's menus & toolbars
Q: Can I add my own items to the menus in the Main Window? What
about the toolbars? Can I add complex things to the toolbars like
custom palettes? Keyboard shortcuts?
Accessing the cursor/selection in the Editor
Q: Can I find out where the cursor (or selection) is in the Editor?
Node[] n = TopComponent.getActiveComponent ().getActivatedNodes ();
if (n.length == 1) {
EditorCookie ec = (EditorCookie) n[0].getCookie (EditorCookie.class);
if (ec != null) {
JEditorPane[] panes = ec.getOpenedPanes ();
if (panes.length > 0) {
int cursor = panes[0].getCaret ().getDot ();
String selection = panes[0].getSelectedText ();
// use this info somehow...
}
}
}
Using submenus
Q: Can I install submenus into popups or other menus, instead of a regular action?
Adding items to popup menus
Q: Is it possible to add my own items to the popup menus of
(someone else's) data object nodes?
DataLoader loader = DataLoaderPool.firstProducerOf (SomeDataObject.class);
if (loader != null) {
SystemAction[] actions = loader.getActions ();
SystemAction[] newactions = new SystemAction[actions.length + 2];
System.arraycopy (actions, 0, newactions, 0, actions.length);
// Really, take more care that it is not a duplicate,
// place into a specific position, etc.:
newactions[actions.length] = null;
newactions[actions.length + 1] = SystemAction.get (SomeAction.class);
loader.setActions (newactions);
}
But you should avoid doing this unless it is really critical to
usability. Generally
service actions
should be used in such situations--then the new action will be in
the popup under the submenu Tools..., on most nodes. This is much
easier to do and safer.
Why did a file system not find my resource?
Q: I tried to find a resource on a file system (or get
children of a folder, etc.) and it did not find a file which I know
was there. What is happening?
java.io.File
or an external process; file systems
which use
AbstractFileSystem.refreshTime
to implement auto-refreshing caches do not automatically
rescan the disk every time a request is made for information about
file objects. Rather, when the next refresh occurs, or
FileObject.refresh()
is called on the containing folder, the cache is updated (and
events fired to inform other code). If you know that some sort of
external modification of files is possible immediately before you
are doing an access, please use refresh()
explicitly
to make sure the caches are synchronized.
Are there APIs to standard NetBeans modules?
Q: I have looked through the Open APIs for what I want to
do, and I realize that actually what I need is not specified in
them, because it is a part of a specific NetBeans module--for
example, the Form Editor. Are there any APIs available for these?
*.java
files, and most of their associated
functionality such as parsing, compile, source editing, etc.) does
have an API, i.e. a set of documented (as Javadoc) conventions as
to how other modules may use its services--typically, other modules
will provide a DataObject
type which subclasses
it. NetBeans programmers use this internal API to implement
Java-based types such as forms, as well as to
provide plug-in functionality such as JavaBeans support.
Changing source code in the Editor
Q: How can I get access to the source code for a class in
the Repository? I want to change some methods, etc.
SaveCookie
(gotten from the data object gotten from the source element). The
bodies of methods and so on are not parsed, but you can still set
them without needing to find the method in the source
code. Properties such as access modifiers can be adjusted without
any need for parsing or generating Java source--the element
implementation handles this for you.
OpenCookie.open()
.
EditorCookie.getDocument()
and then use the Swing API to manipulate it. (But please use
NbDocument.runAtomicAsUser(...)
!)
The Java Hierarchy API should normally synchronize with this
document automatically, according to the parser timeout.
Providing documentation for a module
Q: Is there any standard way of providing documentation for my new module?
Sanity-checking module manifests
Q: My module does not appear to be loading correctly, and I
suspect that the manifest file is not in the correct format. How do
I make sure?
OpenIDE-Module-Section
. Please see the
Modules API
for details and example manifests.
Tracking selections in the Explorer
Q: How should I keep track of what the current node
selection in the Explorer window is? Should I use the
ExplorerManager
?
ExplorerManager.Provider
then you can get the Explorer manager. This provider might in fact
be a
TopComponent
in the
TopComponent.Registry
,
if for example it was actually a
ExplorerPanel
.
But this is bad style--for example, if someone wrote a
TopComponent
that included an
ExplorerPanel
only as a subcomponent, and manually
managed the node selection, this trick would fail.
TopComponent.getActivatedNodes()
and this will work correctly even for non-Explorer components with
a node selection, such as Editor panes open on Java sources.
TopComponent.Registry.PROP_ACTIVATED_NODES
(or
TopComponent.Registry.PROP_CURRENT_NODES
as appropriate).
NodeAction
;
this class does all the dirty work for you of listening to changes
in the node selection and updating its state automatically.
Not yet written
Sorry--this question and its answer have not been written yet,
though it is planned. Please ask this question on the Open APIs
mailing list if you are curious.
Binding one key to more than one action
Q: Is it possible to bind one shortcut key to more than one
action, so they will all be run? What about binding a key
differently in different windows?
TopManager.getGlobalKeymap()
is a master keymap for the whole IDE, and like all keymaps accepts
only one action per binding. If you want multiple actions to be
run, you must create a "wrapper" action that runs them all in turn
(or in parallel).
CompileAction
,
to a different action in a local component (e.g. window), think
carefully whether this is really the right approach. In many cases
the UI of your extension and the IDE as a whole will be better
served by leaving the key binding alone, and instead providing an
appropriate cookie, action performer, or other callback associated
with your component, so that the action (and potentially other code
unknown to you) will function naturally. If you must rebind a
global key, consider whether it is appropriate to determine the
current key binding for the action (if any) in the global keymap,
and use this keystroke to rebing--so user customizations will
remain intact.
Adding a library JAR from outside the IDE installation
Q: Can my module add a library JAR to the classpath from
outside the IDE installation? For example, I have an application
called Etch-a-Kvetch for modelling customer call response systems, and
I want to build a module to integrate it into the IDE. The user may
already have Etch-a-Kvetch installed on their disk, and I want to
reuse the eak.jar main library JAR in my module. It is
not present in the IDE's installation directory. Can I add it to the
IDE's classpath so my module can use it?
-cp:a c:\eak\lib\eak.jar
This startup file, on Windows installations, provides the ability to
add classpath entries to the IDE's Java invocation. On Unix, such a
file is not read so other techniques might be needed.
URLClassLoader
whose
parent should be the first half's classloader, and including as URLs
the locations of both the second half and the library JAR; using this
classloader, look up the implementation classes by name; create new
instances of them; cast them to the interface types; and begin using
them. The second half could be physically stored in the same JAR as
the first, or for clarity could be placed in a separate JAR file; it
does not really matter so long as the first half is compiled
by itself without reference to the library JAR.
Built on February 22 2001. | Portions Copyright 1997-2000 Sun Microsystems, Inc. All rights reserved.