I am aware that in this new modern world, one of the main problems is time. That happens to me, also. I don't write here to complain about that. I write this call only for two things.
First is to thank everybody who have enough patience to try and use this plugin. I write this plugin only to give something back to NetBeans and to NetBeans great community. That thing is enough.
The second thing is that I ask for some help from you, the guys who spent time and nerves using this plugin. If you want to contribute to this plugin, you are welcomed. Just ask for proper rights. If you can't afford time for that, please fill bugs and suggestions. As many as possible. I can't cover everything and I am sure you have many brilliant and useful ideas to make your and mine life easier using this plugin.
Finally, thanks to all of you. NetBeans rocks!
http://kenai.com/projects/perforcenb/pages/Home
Showing posts with label NetBeans. Show all posts
Showing posts with label NetBeans. Show all posts
July 28, 2010
March 8, 2010
Five things I like most at NetBeans Platform 6.8
NetBeans 6.8 is there since December 2009. It did not look like a very important upgrade at first. At least not very important for Platform developers. But using the new version of platform, some things which may appear small at first, has been visibly improved. The most important improvements are listed here (according to my personal feelings). For a complete overview of changes in platform API you can take a look here.
Wrapped libraries
That was one of the major headaches source. Developing modules for NetBeans (as for other platforms) requires sometimes links to other libraries. Third-party libraries, other than the modules provided by the platform, needs to be linked and wrapped in your custom pluggins or platform-based applications.
Wrapping libraries was done in the past in two ways. By creating a module library wrapper plugin for every library which need to be imported. But when you have to link a bigger library, which have a lot of jars, that was a pain. Because a module library wrapper could be created only for one jar. You can end up with easy to have twenty-thirty libraries only to link to something like apache logging libraries or Seam or similar.
The second approach was to create a big jar with all jars from library. For this operation, NetBeans is helpfull, but you have other two problem to solve. First is that the new jar will have it's own manifest. That means that if there is information in manifest files of every jar, that information is lost or not complete. If that information is important, you have a nice problem to solve. The second is that you can loose control over which libraries you have, which versions. Become very difficult in time to maintain the upgrades.
Solution is the new wrapped libraries feature. Now each plugin module in NetBeans can have it's own dependencies on external libraries. For configuration, you have a new tab panel to add as much as needed libraries. The cool thing is that you can specify also the source code and javadocs for every wrapped jar. That was not possible in the old versions.
ActionListeners are everywhere
That could not look as important as it is. In the old versions you could use ActionListeners only for always enabled type of actions. Not you can use the same interface also for context aware and callback action types. That is really cool, even it does not sounds like that at first. A main aspect here is that it is used a "well known" interface.
The first consequence is that if you want to migrate a swing-based app on NetBeans platform, is easier because you just have to pipe your actions. The second consequence is that you don't have to use specific platform interfaces like cookies. I don't say that cookies were bad, but they are old and there is better and much usable alternative.
Declarative Asynchronous actions
That's small, but makes code cleaner and flexible. Also throws away the need to manage yourself the asynchronous behavior of your actions. Nice done.
Enhanced IO API
We already had colors and links. And it was very useful. But now is even more flexible.
You can color the output as you like because you can output with IOColorPrint.print. So you can made your output lines from peaces colored independently. You can also put more hypelinks on the same line. You can, again, add an importance marker, which improves readability on verbose outputs. Finally, you can specify the parent of an IOTab and set its icon and tooltip message. All of them are small things, but used together can be very helpful on creating really effective and friendly output for your application. I appreciate very much an application which let you know what is going on.
Annotations
That's not a specific point. There are some very useful annotations added. The point is, thought, not the specific annotations added. But the trend to use as much as possible annotations. I hope that this trend will continue. I already used @OptionsPanelController.SubRegistration and @ConvertAsJavaBean. But there are more, take a look.
Wrapped libraries
That was one of the major headaches source. Developing modules for NetBeans (as for other platforms) requires sometimes links to other libraries. Third-party libraries, other than the modules provided by the platform, needs to be linked and wrapped in your custom pluggins or platform-based applications.
Wrapping libraries was done in the past in two ways. By creating a module library wrapper plugin for every library which need to be imported. But when you have to link a bigger library, which have a lot of jars, that was a pain. Because a module library wrapper could be created only for one jar. You can end up with easy to have twenty-thirty libraries only to link to something like apache logging libraries or Seam or similar.
The second approach was to create a big jar with all jars from library. For this operation, NetBeans is helpfull, but you have other two problem to solve. First is that the new jar will have it's own manifest. That means that if there is information in manifest files of every jar, that information is lost or not complete. If that information is important, you have a nice problem to solve. The second is that you can loose control over which libraries you have, which versions. Become very difficult in time to maintain the upgrades.
Solution is the new wrapped libraries feature. Now each plugin module in NetBeans can have it's own dependencies on external libraries. For configuration, you have a new tab panel to add as much as needed libraries. The cool thing is that you can specify also the source code and javadocs for every wrapped jar. That was not possible in the old versions.
ActionListeners are everywhere
That could not look as important as it is. In the old versions you could use ActionListeners only for always enabled type of actions. Not you can use the same interface also for context aware and callback action types. That is really cool, even it does not sounds like that at first. A main aspect here is that it is used a "well known" interface.
The first consequence is that if you want to migrate a swing-based app on NetBeans platform, is easier because you just have to pipe your actions. The second consequence is that you don't have to use specific platform interfaces like cookies. I don't say that cookies were bad, but they are old and there is better and much usable alternative.
Declarative Asynchronous actions
That's small, but makes code cleaner and flexible. Also throws away the need to manage yourself the asynchronous behavior of your actions. Nice done.
Enhanced IO API
We already had colors and links. And it was very useful. But now is even more flexible.
You can color the output as you like because you can output with IOColorPrint.print. So you can made your output lines from peaces colored independently. You can also put more hypelinks on the same line. You can, again, add an importance marker, which improves readability on verbose outputs. Finally, you can specify the parent of an IOTab and set its icon and tooltip message. All of them are small things, but used together can be very helpful on creating really effective and friendly output for your application. I appreciate very much an application which let you know what is going on.
Annotations
That's not a specific point. There are some very useful annotations added. The point is, thought, not the specific annotations added. But the trend to use as much as possible annotations. I hope that this trend will continue. I already used @OptionsPanelController.SubRegistration and @ConvertAsJavaBean. But there are more, take a look.
November 25, 2009
NetBeans Platform: Output windows in simple words
I/O APIs is among the most used modules from NetBeans Platform. This is one of the most common way to show information about your activity. The name can be misleading, but is much simpler that it seems. This module manages the output windows which you already have or you can create, where text information can be put.
There are a a lot of scenarios where you need output windows. You need them to show logs for bootstrapping tasks, to show log information, to receive feedback from a compiler or builder or other type of tool.
The story about output windows in NetBeans can be simple or complicated. The hard way is to implement yourself everything and control everything. That could be feasible if you plan to implement a rich output windows with a lot of controls on it. But for simple scenarios, what you have from the platform is simple enough.
Setup
From your NetBeans Platform module, all you have to do is to add "I/O APIs" as a module dependency. That's all.
"Hello world!" from output window
IOProvider is a factory for output window components. These output windows are represented by InputOutput class and hosted into a container, represented by IOContainer. It's easy and enough to proceed. First, we ask for the default provider to get an InputOutput with a specific title. We can create a new one or get an existing one. After that we activate the output and write to it. Here's the code.
Put some colors and behavior on lines
We can easily color the line from output. Also we can put some action on the line. If we create a line with an listener (our listener), the line from output would behave as a hyperlink in a browser. When the listened line will be selected, clicked or deleted, we can do something through listener. Let's see some more code.
Put some decorations on output windows
Using another class from the package, IOTab, you can easily add a tooltip text and a small icon on an output window. As a sample:
And you can do more..
There is also a simple way to add some Swing actions on output window. The output window has a small toolbar on the left side of it. If you pass an array of Swing Actions on the moment of creation, these actions will be available for use on your output window. Just to name a very often scenario: you have a long process to run, you want to give full text feedback, but you want to be able to stop the process when you think is appropriate. Just create a Swing Action to fire the canceling job and add it to the InputOutput.
Thought there are some limitations: you can't put here more than 5 actions and each action should have the property Action.SMALL_ICON defined.
Have fun with InputOutput windows!
There are a a lot of scenarios where you need output windows. You need them to show logs for bootstrapping tasks, to show log information, to receive feedback from a compiler or builder or other type of tool.
The story about output windows in NetBeans can be simple or complicated. The hard way is to implement yourself everything and control everything. That could be feasible if you plan to implement a rich output windows with a lot of controls on it. But for simple scenarios, what you have from the platform is simple enough.
Setup
From your NetBeans Platform module, all you have to do is to add "I/O APIs" as a module dependency. That's all.
"Hello world!" from output window
IOProvider is a factory for output window components. These output windows are represented by InputOutput class and hosted into a container, represented by IOContainer. It's easy and enough to proceed. First, we ask for the default provider to get an InputOutput with a specific title. We can create a new one or get an existing one. After that we activate the output and write to it. Here's the code.
InputOutput io = IOProvider.getDefault().getIO("TestIO", true);
io.select();
io.getOut().print("Hello world!");
Put some colors and behavior on lines
We can easily color the line from output. Also we can put some action on the line. If we create a line with an listener (our listener), the line from output would behave as a hyperlink in a browser. When the listened line will be selected, clicked or deleted, we can do something through listener. Let's see some more code.
try {
InputOutput io = IOProvider.getDefault().getIO("My title", false);
IOColorLines.println(io, "This is a yellow line", Color.yellow);
IOColorLines.println(io, "This is e red important line",
null, true, Color.red);
IOColorLines.println(io, "one dynamic line with event",
new LineListener(), true, Color.green);
} catch (IOException ex) {
Logger.getLogger(SameIOAction.class.getName()).log(
Level.SEVERE, null, ex);
}
[...]
class Listener implements OutputListener {
public void outputLineSelected(OutputEvent ev) {
JOptionPane.showMessageDialog(null, "line with content " +
ev.getLine() + " was selected");
}
public void outputLineAction(OutputEvent ev) {
JOptionPane.showMessageDialog(null, "line with content " +
ev.getLine() + " was actioned");
}
public void outputLineCleared(OutputEvent ev) {
JOptionPane.showMessageDialog(null, "line with content " +
ev.getLine() + " was cleared");
}
}
Put some decorations on output windows
Using another class from the package, IOTab, you can easily add a tooltip text and a small icon on an output window. As a sample:
InputOutput io = IOProvider.getDefault().getIO("My title", false);
IOTab.setToolTipText(io, "My tooltip text for Hello world!");
[..]
And you can do more..
There is also a simple way to add some Swing actions on output window. The output window has a small toolbar on the left side of it. If you pass an array of Swing Actions on the moment of creation, these actions will be available for use on your output window. Just to name a very often scenario: you have a long process to run, you want to give full text feedback, but you want to be able to stop the process when you think is appropriate. Just create a Swing Action to fire the canceling job and add it to the InputOutput.
Action[] actionList = new Action[5];
[..] // add actions here
InputOutput io = IOProvider.getDefault().getIO("My title", actionList);
Thought there are some limitations: you can't put here more than 5 actions and each action should have the property Action.SMALL_ICON defined.
Have fun with InputOutput windows!
November 3, 2009
NetBeans Platform: Implement Perforce client - part IV
Automatically add, checkout, delete or move files
This is the last article about the Perforce client. That does not mean that is fully implemented, niether I will abandon the project. The NetBeans Perforce client will continue to be developed. By me, and hopefully by others. The point with this string of articles it to illustrate in which way it can be implemented a versioning client in NetBeans.
Since last article, the Perforce client was enriched with many functionalities. Thought, only the last one is relevant for our purpose. The topic is how to integrate into Perforce the IDE file manipulation operations like add, delete, rename, move or edit. You can add here also, how to handle the same situations, when files were modified outside IDE.
The key to this functionality is a class called VCSInterceptor. This class is used by NetBeans to announce the eventually versioning system about some change over files. Either if the change was operated form inside or outside of IDE.
I will split the methods from VCSInterceptor into five categories: queries, delete, move, create and change. You can find the source (comments are very intereting to read) here. Take a close look there.
queries
This category contain only one method isMutable(File file). This method is used to ovveride the default behavior proposed by the versioning systems which uses read-only files. When a file is read only, the IDE will see the file in this state, so it will not edit it. But when this method returns true, you let the IDE know that you actually can edit the file, even if is marked as read-only from the file system.
delete
beforeDelete and doDelete work together. The first let the IDE know if you want to implement the delete action for the specified file, in the second method you actually write the delete operation. There is another one method, afterDelete. This method is called after the file was deleted from the files system. Besides the moment of the notification, there is another very important difference. All methods are called when a delete operation was realized from IDE, but only the later (afterDelete) is fired when a file was deleted outside IDE. Take this into consideration when you implement the delete handling.
move
beforeMove, doMove, afterMove. Follows the same pattern as for delete operation. beforeMove is used to tell to the IDE that is want or don't want to handle the file move. doMove implements the real move action and afterMove is called (hard to believe, but ) .. after the mov operation. The only difference from delete is that all operations are called only for IDE file rename/move opertions. For this kind of operations outside IDE, NetBeans will fire two events: afterDelete for the source and afterCreate for the target.
create
Following the same pattern, for create we have beforeCreate, doCreate and afterCreate. Adding new files from outside IDE will fire only the last event (like on delete operations). I will go on, I hate to repeat.
change
This breaks the pattern. There is an beforeEdit method called when a file is about to be opened in edit mode. The is a perfect moment to do a checkout if you are in IDE. After that we have two events, beforeChange and afterChange. These events are related to content. beforeChange is called before the file content are about to be changed. afterChange end the cycle. One thing to mention here is that only afterChange is called if the file is updated outside IDE (javadoc does not mention that, but you can trust me on that). The later is a perfect place to put a checkout for outside IDE file modifications.
Just before presenting the source code for that, I have to mention that you don't need to implement all methods. These methods tries to catch all the possible events for all the possible versioning system scenarios. In my case i found to be enough to implement only 7 from 13. And I hope I covered all.
Here is the interceptor code:
This is the last article about the Perforce client. That does not mean that is fully implemented, niether I will abandon the project. The NetBeans Perforce client will continue to be developed. By me, and hopefully by others. The point with this string of articles it to illustrate in which way it can be implemented a versioning client in NetBeans.
Since last article, the Perforce client was enriched with many functionalities. Thought, only the last one is relevant for our purpose. The topic is how to integrate into Perforce the IDE file manipulation operations like add, delete, rename, move or edit. You can add here also, how to handle the same situations, when files were modified outside IDE.
The key to this functionality is a class called VCSInterceptor. This class is used by NetBeans to announce the eventually versioning system about some change over files. Either if the change was operated form inside or outside of IDE.
I will split the methods from VCSInterceptor into five categories: queries, delete, move, create and change. You can find the source (comments are very intereting to read) here. Take a close look there.
queries
This category contain only one method isMutable(File file). This method is used to ovveride the default behavior proposed by the versioning systems which uses read-only files. When a file is read only, the IDE will see the file in this state, so it will not edit it. But when this method returns true, you let the IDE know that you actually can edit the file, even if is marked as read-only from the file system.
delete
beforeDelete and doDelete work together. The first let the IDE know if you want to implement the delete action for the specified file, in the second method you actually write the delete operation. There is another one method, afterDelete. This method is called after the file was deleted from the files system. Besides the moment of the notification, there is another very important difference. All methods are called when a delete operation was realized from IDE, but only the later (afterDelete) is fired when a file was deleted outside IDE. Take this into consideration when you implement the delete handling.
move
beforeMove, doMove, afterMove. Follows the same pattern as for delete operation. beforeMove is used to tell to the IDE that is want or don't want to handle the file move. doMove implements the real move action and afterMove is called (hard to believe, but ) .. after the mov operation. The only difference from delete is that all operations are called only for IDE file rename/move opertions. For this kind of operations outside IDE, NetBeans will fire two events: afterDelete for the source and afterCreate for the target.
create
Following the same pattern, for create we have beforeCreate, doCreate and afterCreate. Adding new files from outside IDE will fire only the last event (like on delete operations). I will go on, I hate to repeat.
change
This breaks the pattern. There is an beforeEdit method called when a file is about to be opened in edit mode. The is a perfect moment to do a checkout if you are in IDE. After that we have two events, beforeChange and afterChange. These events are related to content. beforeChange is called before the file content are about to be changed. afterChange end the cycle. One thing to mention here is that only afterChange is called if the file is updated outside IDE (javadoc does not mention that, but you can trust me on that). The later is a perfect place to put a checkout for outside IDE file modifications.
Just before presenting the source code for that, I have to mention that you don't need to implement all methods. These methods tries to catch all the possible events for all the possible versioning system scenarios. In my case i found to be enough to implement only 7 from 13. And I hope I covered all.
Here is the interceptor code:
public class PerforceInterceptor extends VCSInterceptor {
@Override
public boolean isMutable(File file) {
return true; // really, for all? we will see that
}
/**
* Automatically add to perforce the new added file.
* The code is here to handle also the files added from outside IDE.
*
* @param file file in question
*/
@Override
public void afterCreate(File file) {
if (PerforceModuleConfig.getInstance().isPerforceExcluded(file)) {
return;
}
FileStatus status = getUpdatedFileStatus(file);
if (status == null || FileStatus.STATUS_UNKNOWN.equals(status)) {
try {
// this is what we really care
P4Client p4client = PerforceSystem.getP4Client();
p4client.actionAdd(file);
} catch (PerforceActionException ex) {
Exceptions.printStackTrace(ex);
}
}
}
/**
* Called when a file is uptodate and is about to be modified.
* The file is automatically checked out.
*
* @param file file in question
*/
@Override
public void beforeEdit(final File file) {
if (PerforceModuleConfig.getInstance().isPerforceExcluded(file)) {
return;
}
FileStatus status = getUpdatedFileStatus(file);
if (!FileStatus.STATUS_VERSIONED_UPTODATE.equals(status)) {
return;
}
try {
P4Client p4client = PerforceSystem.getP4Client();
p4client.actionEdit(file);
} catch (PerforceActionException ex) {
Exceptions.printStackTrace(ex);
}
}
/**
* Check out the uptodate file. The method is called when the file was
* modified outside IDE.
* Same logic as {@link #beforeEdit(java.io.File) }.
*
* @param file file in question
*/
@Override
public void afterChange(File file) {
beforeEdit(file);
}
/**
* Mark for delete files which are delete from outside/inside IDE.
* Handle different scenarios depending on the status of the file.
*
* @param file file in question
*/
@Override
public void afterDelete(File file) {
try {
P4Client p4client = PerforceSystem.getP4Client();
FileStatus status = getUpdatedFileStatus(file);
if (status == null) {
return;
}
switch (status) {
case STATUS_VERSIONED_ADD:
p4client.actionRevert(file);
if (file.exists()) {
file.delete();
}
break;
case STATUS_VERSIONED_UPTODATE:
p4client.actionDelete(file);
break;
case STATUS_VERSIONED_EDIT:
p4client.actionRevert(file);
if (file.exists()) {
p4client.actionDelete(file);
}
break;
}
} catch (PerforceActionException ex) {
Exceptions.printStackTrace(ex);
}
}
@Override
public boolean beforeMove(File file, File file1) {
if (PerforceModuleConfig.getInstance().isPerforceExcluded(file)) {
return false;
}
return true;
}
@Override
@SuppressWarnings("fallthrough")
public void doMove(File source, File target) throws IOException {
try {
P4Client p4client = PerforceSystem.getP4Client();
FileStatus status = getUpdatedFileStatus(source);
if (status == null) {
return;
}
switch (status) {
case STATUS_VERSIONED_UPTODATE:
p4client.actionEdit(source);
case STATUS_VERSIONED_ADD:
case STATUS_VERSIONED_EDIT:
p4client.actionMove(source, target);
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
}
/**
* Retrieves the file status. If the cache is not hit, we do it the hard
* way, we push in cache the value from perforce system.
*
* @param file file in question
* @return the status of the file or null if the file is not handled at all.
*/
private FileStatus getUpdatedFileStatus(File file) {
FileStatusCache cache = PerforceSystem.getCache();
FileInformation fileInfo = cache.getFileInfo(file);
if (fileInfo == null) {
cache.refreshFiles(new String[]{file.getAbsolutePath()});
fileInfo = cache.getFileInfo(file);
}
return (fileInfo == null) ? null : fileInfo.getStatus();
}
}
As I said, foolow the source code and the project PerforceNB on kenai site at http://kenai.com/projects/perforcenb/. See you.
October 13, 2009
Dynamic libraries in NetBeans
I hear often that NetBeans is not as configurable as Eclipse (as a sample). Don't want to start a religious blind war, you'll find nothing like that here.
Regarding this problem my answer is that NetBeans is configurable, but not in a ways as you would expect at the first glance. NetBeans for some things offers a limited GUI to manage things. As a sample, when you create a library. You have a GUI which gives you the possibility to create one. You can build that library only in one way: by selecting individual jars and folders for classes, sources and javadocs (I talk about Java SE libraries). If you want to create a customized library, there's no other GUI possibility.
But you have programming. By offering a friendly and stable API you can extend the platform and IDE as you like. If you know Emacs and Lisp you know what I mean. Is the same philosophy as in Unix/Linux world. No need of GUIs with thousands of screens full of usually unused information. A text file well commented is more than enough. In NetBeans is translated: "You have a very well documented API, stable, samples, why do you need a GUI?".
I will give a 10 minute way to create dynamic libraries in NetBeans. In 10 minutes spent you can do much more than with the best GUI ever.
First, what do I mean by dynamic library. I library which can change in time by your own rules. As a sample, you could want to upgrade the jar files without selecting the new jar files according to the new versions. Or, you would like to have your libraries in different folders (one for development, other for testing machine). Or simply, you know somehow where are your libraries, you have some piece of code to get this information, but you don't want to spent you vacation selecting dozens of jars. You imagination is your limit. With this very simple method you can achieve that in minutes.
First you need to create a NetBeans module project. Call it how do you like, is not important. You do that by File -> New Project -> NetBeans Modules -> Module. After Next, you give a name to your module and can choose Standalone Module. After another next you give the base package, a code name and you have it.
First we will create a class which extends ModuleInstall. This class will be called when the module is started up. In order to do this, we have to add an manifest entry like:
This class has a method called restored(). This method is called when the module is restored during startup. Here we will put our code:
And that is all. One thing though. You need to add dependencies to some Platform Libraries. In the contextual menu of the project action Properties -> Libraries -> Add. If you don't know what dependency you need simply put the class name in filter field and you will find what you search for.
I consider that NetBeans is a tool for programmers. And programmers don't fear coding. That is why this the best tool to configure your environment. Much flexible and better that a GUI.
Hope you like it.
Regarding this problem my answer is that NetBeans is configurable, but not in a ways as you would expect at the first glance. NetBeans for some things offers a limited GUI to manage things. As a sample, when you create a library. You have a GUI which gives you the possibility to create one. You can build that library only in one way: by selecting individual jars and folders for classes, sources and javadocs (I talk about Java SE libraries). If you want to create a customized library, there's no other GUI possibility.
But you have programming. By offering a friendly and stable API you can extend the platform and IDE as you like. If you know Emacs and Lisp you know what I mean. Is the same philosophy as in Unix/Linux world. No need of GUIs with thousands of screens full of usually unused information. A text file well commented is more than enough. In NetBeans is translated: "You have a very well documented API, stable, samples, why do you need a GUI?".
I will give a 10 minute way to create dynamic libraries in NetBeans. In 10 minutes spent you can do much more than with the best GUI ever.
First, what do I mean by dynamic library. I library which can change in time by your own rules. As a sample, you could want to upgrade the jar files without selecting the new jar files according to the new versions. Or, you would like to have your libraries in different folders (one for development, other for testing machine). Or simply, you know somehow where are your libraries, you have some piece of code to get this information, but you don't want to spent you vacation selecting dozens of jars. You imagination is your limit. With this very simple method you can achieve that in minutes.
First you need to create a NetBeans module project. Call it how do you like, is not important. You do that by File -> New Project -> NetBeans Modules -> Module. After Next, you give a name to your module and can choose Standalone Module. After another next you give the base package, a code name and you have it.
First we will create a class which extends ModuleInstall. This class will be called when the module is started up. In order to do this, we have to add an manifest entry like:
OpenIDE-Module-Install: com/my/package/MyModuleInstall.class
This class has a method called restored(). This method is called when the module is restored during startup. Here we will put our code:
public class ModuleHook extends ModuleInstall {
public void restored() {
Map<String, List<URL>> map = new HashMap<String, List<URL>>();
List<URL> classpath = new ArrayList<URL>();
map.put("classpath", classpath);
List<URL> javadoc = new ArrayList<URL>();
map.put("javadoc", javadoc);
// fill the URL map as you like, with jars, sources and javadocs
// .....
// by the way, you can use FileUtil.urlForArchiveOrDir(File file)
// to easy get an URL from a File
Library library = libraryManager.getDefault().getLibrary(
"MyLibrary");
if (library != null) {
// remove it if is an old version there
LibraryManager.getDefault().removeLibrary(library);
}
LibraryManager.getDefault().createLibrary("j2se", "MyLibrary", map);
}
}
And that is all. One thing though. You need to add dependencies to some Platform Libraries. In the contextual menu of the project action Properties -> Libraries -> Add. If you don't know what dependency you need simply put the class name in filter field and you will find what you search for.
I consider that NetBeans is a tool for programmers. And programmers don't fear coding. That is why this the best tool to configure your environment. Much flexible and better that a GUI.
Hope you like it.
September 30, 2009
NetBeans Platform: Implement Perforce client - part III
Switch to P4JAPI, annotate and basic actions
All the Netbeans Plugins which tried to implement the Perforce client uses p4 command line tool. This is somehow difficult, because you have to manage the input and output of a command line. A lot of effort with no benefit. Because the perforce team put on place what is called P4Java, the Perforce Java API. You can find the release notes here (last version) http://www.perforce.com/perforce/doc.091/user/p4javanotes.txt. Download it from here. The main benefits are the fact that you work with objects, don't have to parse things, and to manage external processes. Thought, also, it is faster than its command line brother. Since this is not an NetBeans Platform thing, I will not insist on that too much.
As mentioned in a previous article, the presentation of versioning information is implemented in a class based on VCSAnnotator. In our case, this class is called PerforceAnnotator. There are some aspects which need to be explained. First is the fact that this class is a listener on some specific property change. That is done using the following code:
The PerforceAnnotator has two methods related to property change events: addPropertyChangeListener and removePropertyChangeListener. How it works? We define a logical property, named "annotationChanged". Any listener added will be notified if this property have been changed. This code works together with another piece from PerforceVS and another one from FileStatusCache. Practically, through this logical properties and wire of listeners we send messages from a component to another. They remain loosely coupled. As a sample, when the status of a file has been changed (from perforce point of view), the instance of FileStatusCache (which manages these statuses) notify PerforceVS that something on a file has been changed. PerforceVS than will notify the PerforceAnnotator about that change and the annotator will change also the status in UI (labels, colors, versioning info). The property change method is a very important concept. It is used very ofted to put UI things together, so take a closer lok on that, whenever you have some time.
PerforceAnnotator show some UI information about the status of files. The icon from explorer view is modified and the name and color of the file element is modified. These is done with the following code.
How it works? Depending on the status of the file, we modify the actual icon or label of the file from explorer view. To find the status of the file we ask the FileStatusCache, this class manages the FileInformation related to every managed file. The VCSContext represents the selection of files on which we should show information. Note that is possible to have multiple files in a context. In order to keep things simple, I considered that context have only one file and if there are many, I take into consideration only the first one. In time this should be changed. The same scenario happens for labels. On labels we use HTML tags because the view allow that to modify the aspect of a label.
One small tip to know. ImageUtilities class offers some very useful methods in managing images. We can use that class to merge two images, as is the case with PerforceAnnotator (we put a small Perforce icon over the original NetBeans file icon). We can load an image giving only a location in class path and we can transform with easy from an image into an icon and viceversa.
Let's take a look on the results of our work until now.
Another thing which PerfoceAnnotator do is to wire up some actions. It does this by implementing the method getActions. This method receives two parameters as input. The first one is the VCSContext. As noted before, the context gives information about the selected files for which the user wants to show actions. I repeat that is important to be aware that the context can represent more than one file, so behave accordingly. The second parameter is ActionDestination. This is an enum which tells us if the IDE wants the actions to be inserted on the main menu or on the contextual menu. In the sample code below the complexity of building available actions is wrapped into another class, called FileStatusManager. An action is a standard swing action. My actions usually calls the perforce client and do something with that. Since this is not a NetBeans Platform I will not talk about that, as usual, I invite you to take a look on the sources and give at least a feedback (you are welcomed anytime to submit).
One more cookie, thought. To create a progress notification which will be displayed on status bar in a dedicated section, you can use ProgressHandle. Like in the sample below taken form FileStatusCache.reloadCacheOnThread.
All the Netbeans Plugins which tried to implement the Perforce client uses p4 command line tool. This is somehow difficult, because you have to manage the input and output of a command line. A lot of effort with no benefit. Because the perforce team put on place what is called P4Java, the Perforce Java API. You can find the release notes here (last version) http://www.perforce.com/perforce/doc.091/user/p4javanotes.txt. Download it from here. The main benefits are the fact that you work with objects, don't have to parse things, and to manage external processes. Thought, also, it is faster than its command line brother. Since this is not an NetBeans Platform thing, I will not insist on that too much.
As mentioned in a previous article, the presentation of versioning information is implemented in a class based on VCSAnnotator. In our case, this class is called PerforceAnnotator. There are some aspects which need to be explained. First is the fact that this class is a listener on some specific property change. That is done using the following code:
public class PerforceAnnotator extends VCSAnnotator {
/**
* Fired when textual annotations and badges have changed.
* The NEW value is Set<File> of files that changed or NULL
* if all annotaions changed.
*/
public static final String PROP_ANNOTATIONS_CHANGED = "annotationsChanged";
private final PropertyChangeSupport support = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
support.removePropertyChangeListener(listener);
}
The PerforceAnnotator has two methods related to property change events: addPropertyChangeListener and removePropertyChangeListener. How it works? We define a logical property, named "annotationChanged". Any listener added will be notified if this property have been changed. This code works together with another piece from PerforceVS and another one from FileStatusCache. Practically, through this logical properties and wire of listeners we send messages from a component to another. They remain loosely coupled. As a sample, when the status of a file has been changed (from perforce point of view), the instance of FileStatusCache (which manages these statuses) notify PerforceVS that something on a file has been changed. PerforceVS than will notify the PerforceAnnotator about that change and the annotator will change also the status in UI (labels, colors, versioning info). The property change method is a very important concept. It is used very ofted to put UI things together, so take a closer lok on that, whenever you have some time.
PerforceAnnotator show some UI information about the status of files. The icon from explorer view is modified and the name and color of the file element is modified. These is done with the following code.
@Override
public Image annotateIcon(Image oldImage, VCSContext context) {
FileStatusCache cache = PerforceSystem.getCache();
int x = 12;
int y = 0;
if (cache.containsStatus(context, FileStatus.STATUS_VERSIONED_EDIT)) {
return ImageUtilities.mergeImages(oldImage, ImageRoot.DECORATION_EDIT, x, y);
}
if(cache.containsStatus(context, FileStatus.STATUS_VERSIONED_ADD)) {
return ImageUtilities.mergeImages(oldImage, ImageRoot.DECORATION_ADD, x, y);
}
if(cache.containsStatus(context, FileStatus.STATUS_VERSIONED_UPTODATE)) {
return super.annotateIcon(oldImage, context);
}
return super.annotateIcon(oldImage, context);
}
@Override
public String annotateName(String name, VCSContext ctx) {
FileStatusCache cache = PerforceSystem.getCache();
int version;
List<FileInformation> files;
files = cache.listFiles(ctx, FileStatus.STATUS_VERSIONED_EDIT);
if (files.size() > 0) {
version = files.get(0).getVersion();
return markName(name, "#0B610B", "#" + version + " [edit]");
}
files = cache.listFiles(ctx, FileStatus.STATUS_VERSIONED_ADD);
if (files.size() > 0) {
version = files.get(0).getVersion();
return markName(name, "#084B8A", "#" + version + " [add]");
}
files = cache.listFiles(ctx, FileStatus.STATUS_VERSIONED_UPTODATE);
if (files.size() > 0) {
version = files.get(0).getVersion();
return markName(name, null, "#" + version);
}
files = cache.listFiles(ctx, FileStatus.STATUS_UNKNOWN);
if (files.size() > 0) {
return super.annotateName(name, ctx);
}
if (name.equalsIgnoreCase("<default package>")) {
return "<default package>";
}
return super.annotateName(name, ctx);
}
private String markName(String name, String color, String label) {
boolean extra = VersioningSupport.getPreferences().getBoolean(
VersioningSupport.PREF_BOOLEAN_TEXT_ANNOTATIONS_VISIBLE, false);
if (color == null) {
return name + (extra ? label : "");
}
return "<font color=\"" + color + "\">" + name + "</font>" +
(extra ? " <font color=\"" + color + "\">" + label + "</font>" : "");
}
How it works? Depending on the status of the file, we modify the actual icon or label of the file from explorer view. To find the status of the file we ask the FileStatusCache, this class manages the FileInformation related to every managed file. The VCSContext represents the selection of files on which we should show information. Note that is possible to have multiple files in a context. In order to keep things simple, I considered that context have only one file and if there are many, I take into consideration only the first one. In time this should be changed. The same scenario happens for labels. On labels we use HTML tags because the view allow that to modify the aspect of a label.
One small tip to know. ImageUtilities class offers some very useful methods in managing images. We can use that class to merge two images, as is the case with PerforceAnnotator (we put a small Perforce icon over the original NetBeans file icon). We can load an image giving only a location in class path and we can transform with easy from an image into an icon and viceversa.
Let's take a look on the results of our work until now.
@Override
public Action[] getActions(VCSContext ctx, ActionDestination destination) {
List<Action> actions = new ArrayList<Action>();
FileStatusManager manager = FileStatusManager.getInstance();
switch (destination) {
case MainMenu:
actions.addAll(manager.getAvailableActionsOnMainMenu(ctx));
break;
case PopupMenu:
actions.addAll(manager.getAvailableActionsOnPopup(ctx));
break;
}
return actions.toArray(new Action[actions.size()]);
}
One more cookie, thought. To create a progress notification which will be displayed on status bar in a dedicated section, you can use ProgressHandle. Like in the sample below taken form FileStatusCache.reloadCacheOnThread.
final ProgressHandle progress =ProgressHandleFactory.createHandle("Perforce refresh..");progress.start();.....progress.finish();
I mention this simple thing because a lot of things in NetBeans are very simple and straightforward to implement or use. That is the meaning of strong API. The simplest form possible, intuitive and elegant. I think NetBeans Platform has a lot of those.
Untill the next time, see changes on http://kenai.com/projects/perforcenb.
Untill the next time, see changes on http://kenai.com/projects/perforcenb.
September 8, 2009
NetBeans Platform: Implement Perforce client - part II
Module preferences for PerforceNB.
Usually options for NetBeans modules are handled via option panel. For that we can use a specialized wizard. You can start the wizard from the contextual menu of the project, where we fire the New - Other - Module Development - Options Panel. In this way we can create primary or secondary panels for options.
This is not our case. That is because for versioning system options, NetBeans has created a panel already. You can find that panel from the main menu by Tools - Options - Miscellaneous - Versioning. Take a look on the dialog box and see what comes next. Our job is to insert another item in the list of versioning systems, handling preferences for Perforce.
We achieve that by extending org.netbeans.spi.options.AdvancedOption. This class represents an advanced interface element for options dialog. We create a new class which extends AdvancedOption.
After that we must configure the layout.xml to inject in the interface this element. The programmatic way is to modify by hand the layout.xml file. This file will look like below:
<filesystem>
<folder name="VersioningOptionsDialog">
<file name="PerforceOptions.instance">
<attr name="instanceClass" stringvalue="org.padreati.perforcenb.ui.PerforceOptions"/>
</file>
</folder>
</filesystem>
Another option to generate this content is to find in the IDE the layer GUI editor. Use <this layer in context> representation. Find VersioningOptionsDialog folder. There use context menu to create a new file called PerforceOptions.instance and so on.
Now we injected our UI element in NetBeans IDE. We implement the class to provide appropriate values. I implemented AdvancedOption in class PerforceOptions.
There are only some methods which are really relevant. The update method is called when IDE loads configuration data from storage, I update the interface at that moment. The applyChanges is called when a save action is fired from interface. Use isChanged to tell IDE if the configuration data was updated in UI. The UI is specified in getComponent method. This method returns an instance of PerforceOptionsPanel, a class which extends JPanel.
This is the interface. Here is how it looks:
For managing the preferences of the module I created a class called PerforceModuleConfig. This is a singleton which calls NbPreferences to persist it's properties. This class I will use in our module to see which are the options for PerforceNB module. Here is a listing:
The content is obvious. Only notice that I have used NbPreferences, a utility class from NetBeans Platform for persisting preferences. Very useful one. Here is the result of my work from this episode.
As usual, you can see the whole project and code from the kenai project page at http://kenai.com/projects/perforcenb. See you on the next episode.
Usually options for NetBeans modules are handled via option panel. For that we can use a specialized wizard. You can start the wizard from the contextual menu of the project, where we fire the New - Other - Module Development - Options Panel. In this way we can create primary or secondary panels for options.
This is not our case. That is because for versioning system options, NetBeans has created a panel already. You can find that panel from the main menu by Tools - Options - Miscellaneous - Versioning. Take a look on the dialog box and see what comes next. Our job is to insert another item in the list of versioning systems, handling preferences for Perforce.
We achieve that by extending org.netbeans.spi.options.AdvancedOption. This class represents an advanced interface element for options dialog. We create a new class which extends AdvancedOption.
After that we must configure the layout.xml to inject in the interface this element. The programmatic way is to modify by hand the layout.xml file. This file will look like below:
<folder name="VersioningOptionsDialog">
<file name="PerforceOptions.instance">
<attr name="instanceClass" stringvalue="org.padreati.perforcenb.ui.PerforceOptions"/>
</file>
</folder>
</filesystem>
The listing is clear, we provide a display name and a tooltip for the UI element. I used resources for that. The main method here is create() which returns an instance of PerforceOptionsPanelController.An OptionPanelController is the controller behind UI for managing options (MVC sounds familiar? that's one reason why I love NetBeans and Swing). The controller handles operations of managing data. Here is the listing:public class PerforceOptions extends AdvancedOption {
@Override
public String getDisplayName() {
return NbBundle.getMessage(PerforceVS.class, "CTL_Perforce_DisplayName");
}
@Override
public String getTooltip() {
return NbBundle.getMessage(PerforceVS.class, "CTL_Perforce_OptionsTooltip");
}
@Override
public OptionsPanelController create() {
return new PerforceOptionsPanelController();
}
}
public class PerforceOptionsPanelController extends OptionsPanelController {
private PerforceOptionsPanel panel;
public PerforceOptionsPanelController() {
panel = new PerforceOptionsPanel();
}
@Override
public void update() {
PerforceModuleConfig config = PerforceModuleConfig.getInstance();
config.reload();
panel.setPath(config.getP4Path());
panel.setDefaultPort(config.getP4DefaultPort());
panel.setDefaultWorkspace(config.getP4DefaultWorkspace());
}
@Override
public void applyChanges() {
PerforceModuleConfig config = PerforceModuleConfig.getInstance();
config.setP4Path(panel.getPath());
config.setP4DefaultPort(panel.getDefaultPort());
config.setP4DefaultWorkspace(panel.getDefaultWorkspace());
config.store();
}
@Override
public void cancel() {
PerforceModuleConfig.getInstance().reload();
}
@Override
public boolean isValid() {
return true;
}
@Override
public boolean isChanged() {
return panel.isDirty();
}
@Override
public JComponent getComponent(Lookup masterLookup) {
return panel;
}
@Override
public HelpCtx getHelpCtx() {
return new HelpCtx(PerforceOptionsPanel.class);
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
}
}
There are only some methods which are really relevant. The update method is called when IDE loads configuration data from storage, I update the interface at that moment. The applyChanges is called when a save action is fired from interface. Use isChanged to tell IDE if the configuration data was updated in UI. The UI is specified in getComponent method. This method returns an instance of PerforceOptionsPanel, a class which extends JPanel.
This is the interface. Here is how it looks:
For managing the preferences of the module I created a class called PerforceModuleConfig. This is a singleton which calls NbPreferences to persist it's properties. This class I will use in our module to see which are the options for PerforceNB module. Here is a listing:
public final class PerforceModuleConfig {
private static PerforceModuleConfig instance;
private final static String P4_PATH_KEY = "P4_PATH_KEY";
private final static String P4_DEFAULT_PORT_KEY = "P4_DEFAULT_PORT_KEY";
private final static String P4_DEFAULT_WORKSPACE_KEY = "P4_DEFAULT_WORKSPACE_KEY";
private String p4Path;
private String p4DefaultPort;
private String p4DefaultWorkspace;
private PerforceModuleConfig() {
}
public static PerforceModuleConfig getInstance() {
if(instance==null) {
instance = new PerforceModuleConfig();
}
return instance;
}
public String getP4Path() {
return p4Path;
}
public void setP4Path(String p4Path) {
this.p4Path = p4Path;
}
public String getP4DefaultPort() {
return p4DefaultPort;
}
public void setP4DefaultPort(String p4DefaultPort) {
this.p4DefaultPort = p4DefaultPort;
}
public String getP4DefaultWorkspace() {
return p4DefaultWorkspace;
}
public void setP4DefaultWorkspace(String p4DefaultWorkspace) {
this.p4DefaultWorkspace = p4DefaultWorkspace;
}
public void reload() {
Preferences pref = NbPreferences.forModule(PerforceModuleConfig.class);
String p4PathDefault = "p4";
if(System.getProperty("os.name").startsWith("Windows")) {
p4PathDefault = "p4.exe";
}
setP4Path(pref.get(P4_PATH_KEY, p4PathDefault));
setP4DefaultPort(pref.get(P4_DEFAULT_PORT_KEY, ""));
setP4DefaultWorkspace(pref.get(P4_DEFAULT_WORKSPACE_KEY, ""));
}
public void store() {
Preferences pref = NbPreferences.forModule(PerforceModuleConfig.class);
pref.put(P4_PATH_KEY, getP4Path());
pref.put(P4_DEFAULT_PORT_KEY, getP4DefaultPort());
pref.put(P4_DEFAULT_WORKSPACE_KEY, getP4DefaultWorkspace());
}
}
The content is obvious. Only notice that I have used NbPreferences, a utility class from NetBeans Platform for persisting preferences. Very useful one. Here is the result of my work from this episode.
As usual, you can see the whole project and code from the kenai project page at http://kenai.com/projects/perforcenb. See you on the next episode.
September 7, 2009
NetBeans Platform: Implement Perforce client - part I
NetBeans and NetBeans Platform were always the tools for the heart. Unfortunately, my usual job duties did not included enough time spent with them. So, I tool my chanses to spent some nights on these. Since I have to use Perforce versioning system and because NetBeans has not (yet!) a client for this system, I decided to implement such a client. Hope I can give something back to the community in this way, a humble little piece compared to the things I received. You will see project details here http://kenai.com/projects/perforcenb.
So, a versioning control system. If you want to know more about Perforce, you can go to their site www.perforce.com. It should be enought to say that I know at least two very big companies which use it as a main VCS.
NetBeans Platform gives us an API which can be used to integrate a client for a versioning system into the IDE. A nice side effect of this is the fact that all the versioning control system clients will behave in a similar way. We will implement our Perforce client as a NetBeans module. In this way we can use it on our daily basis usual tasks.
First thing to create is a NetBeans module project. We can do that by using New -> Project from NetBeans IDE. (I use 6.7.1, thought you should use a recent version too). We chose then NetBeans Modules -> Module for the project type and hit Next button.
In the next dialog box we insert information about the project. Like project name, location and so. You can see the data I enetered from the image. Afer that, hit the Next button again.
In the next dialog box we insert some information useful for code generation. Base package can be configured here, title of the plugin and layer. The will be important in the next parts of this story. For the moment just be sure you select it. To generate the code for the project you should use action Finish button.
So, we have now a module project which does nothing for the moment. We want to implement a versioning system client in it, so the starting point should be extending the VersioningSystem class. But, to be able to use that class, we must do another preparation step. Importing the NetBeans modules which we will base our module on. For the beginning we will add two dependencies at the project. For that, action the contextual menu of the project. From there, action Properties -> Libraries. In the dialog box fire Add button which will gives us a search screen.
The interesting thing in this screen is that you can use it in two ways. First you know already which module you should import, so you can roll over the Module list and select modules you like to use it. The second way is to use search Filter. The nice thing here is that you can search for an exposed class. So, if you don't know which module to import in order to use a specific class or interface, you filter module by that class or interface and you will have listed all the modules which offer that name. Nice trick when you are lost somehow.
So, we need to add dependencies to the following modules: Versioning and Utiities API. The last because we use an utility class for getting the resources (look for NbBundle to see what I mean).
The next stept is to let the NetBeans IDE "know" that I just implemented a new versioning client for him.We do this by extending org.netbeans.modules.versioning.spi.VersioningSystem in a service provider interface way. So we create a derived class, PerforceVS which extends VersioningSystem. We create META-INF folder into the source root. In META-INF we create a folder called services. In META-INF/services we create an empty text file. That file will be called org.netbeans.modules.versioning.spi.VersioningSystem and will have one line only: org.padreati.perforcenb.PerforceVS. This is the name of the class which extends VersioningSystem. For a broader view of Service Provider Interface you can take a look here.
This class is in the very basic form. We do the following:
So, a versioning control system. If you want to know more about Perforce, you can go to their site www.perforce.com. It should be enought to say that I know at least two very big companies which use it as a main VCS.
NetBeans Platform gives us an API which can be used to integrate a client for a versioning system into the IDE. A nice side effect of this is the fact that all the versioning control system clients will behave in a similar way. We will implement our Perforce client as a NetBeans module. In this way we can use it on our daily basis usual tasks.
First thing to create is a NetBeans module project. We can do that by using New -> Project from NetBeans IDE. (I use 6.7.1, thought you should use a recent version too). We chose then NetBeans Modules -> Module for the project type and hit Next button.
So, we have now a module project which does nothing for the moment. We want to implement a versioning system client in it, so the starting point should be extending the VersioningSystem class. But, to be able to use that class, we must do another preparation step. Importing the NetBeans modules which we will base our module on. For the beginning we will add two dependencies at the project. For that, action the contextual menu of the project. From there, action Properties -> Libraries. In the dialog box fire Add button which will gives us a search screen.
The interesting thing in this screen is that you can use it in two ways. First you know already which module you should import, so you can roll over the Module list and select modules you like to use it. The second way is to use search Filter. The nice thing here is that you can search for an exposed class. So, if you don't know which module to import in order to use a specific class or interface, you filter module by that class or interface and you will have listed all the modules which offer that name. Nice trick when you are lost somehow.
So, we need to add dependencies to the following modules: Versioning and Utiities API. The last because we use an utility class for getting the resources (look for NbBundle to see what I mean).
The next stept is to let the NetBeans IDE "know" that I just implemented a new versioning client for him.We do this by extending org.netbeans.modules.versioning.spi.VersioningSystem in a service provider interface way. So we create a derived class, PerforceVS which extends VersioningSystem. We create META-INF folder into the source root. In META-INF we create a folder called services. In META-INF/services we create an empty text file. That file will be called org.netbeans.modules.versioning.spi.VersioningSystem and will have one line only: org.padreati.perforcenb.PerforceVS. This is the name of the class which extends VersioningSystem. For a broader view of Service Provider Interface you can take a look here.
package org.padreati.perforcenb;
import java.io.File;
import org.netbeans.modules.versioning.spi.VCSAnnotator;
import org.netbeans.modules.versioning.spi.VersioningSystem;
import org.openide.util.NbBundle;
import org.padreati.perforcenb.wrapper.PerforceSystem;
/**
*
* @author padreati
*/
public class PerforceVS extends VersioningSystem {
public PerforceVS() {
putProperty(PROP_DISPLAY_NAME, NbBundle.getMessage(
PerforceVS.class, "CTL_Perforce_DisplayName")); // NOI18N
putProperty(PROP_MENU_LABEL, NbBundle.getMessage(
PerforceVS.class, "CTL_Perforce_MainMenu")); // NOI18N
}
@Override
public File getTopmostManagedAncestor(File file) {
// TODO for the moment all will be considered under
// Perforce just for testing
return new File("/");
}
@Override
public VCSAnnotator getVCSAnnotator() {
return PerforceSystem.getSystem().getAnnotator();
}
}
This class is in the very basic form. We do the following:
- In constructor we set values for menu labels. In order to work I have inserted entries into resource (properties) files for CTL_Perforce_DisplayName and CTL_Perforce_MainMenu.
- I implemented getVCSAnnotator just to return the instance of annotator we will use (details a little bit latter).
- implement getTopmostManagedAncestor. If this method returns a value, it means that the file/folder receicved as parameter is managed by our versioning system. If not, we return null.
One important aspect is the design of versioning system in NetBeans. It is considered that one resource from disk (either file or folder) can be in two states only. Either is managed by one versioning system (only one versioning system can own the resource in the same time) or is not managed at all. The versioning API consider also that if a folder is managed by a versioning system, all of the folders and files should be managed by that version control. So, to find for a folder if it is managed by a versioning control, we should tell to the versioning API that the specified files resides under a managed folder. We do that by implementing getTopmostManagedAncestor. This method should return the topmost managed folder where resides the file received as parameter.
In my sample I simply return root folder. Why, would you ask. Just for the testing purposes. Returning the root folder of the file system (this is similar to C:\ folder on Windows) I specify that all files are managed by Perforce. Obviously this is not true. We do it for now just to see where we go.
Also, I created a singleton class to hold all the references of the Perforce versioning system. For the moment we hold only annotator instance. But what is an annotator?
package org.padreati.perforcenb.impl;import java.awt.Image;import java.util.ArrayList;import java.util.List;import javax.swing.Action;import org.netbeans.modules.versioning.spi.VCSAnnotator;import org.netbeans.modules.versioning.spi.VCSContext;/**** @author padreati*/public class PerforceAnnotator extends VCSAnnotator {@Overridepublic Image annotateIcon(Image arg0, VCSContext arg1) {return super.annotateIcon(arg0, arg1);}@Overridepublic String annotateName(String name, VCSContext ctx) {return name + " [PERFORCE]";}@Overridepublic Action[] getActions(VCSContext ctx, ActionDestination destination) {// TODO complete actions, for the moment only an empty// menu as a sampleListactions = new ArrayList (); if (destination == VCSAnnotator.ActionDestination.MainMenu) {actions.add(null);}return actions.toArray(new Action[actions.size()]);}}
An VCS Annotator is the class which implements the decoration in IDE of the code elements controlled by a versioning system. In our case, all the files managed by Perforce should be specified in a way that is visible into interface. Just because we signaled that all files are managed by Perforce (we know that is not true), all the files will be decorated by this annotator.
annotateName will decorate the name of the resource, and annotateIcon will decorate the icon. These methods receives VSContext. This class encapsulates a selection of objects, so we can multiple annotate the resources. In our sample implementation we only append the [PERFORCE] string at the name of resource.
annotateName will decorate the name of the resource, and annotateIcon will decorate the icon. These methods receives VSContext. This class encapsulates a selection of objects, so we can multiple annotate the resources. In our sample implementation we only append the [PERFORCE] string at the name of resource.
The method getActions deserves also a lot of attention. Bu on that in another next chapter. For the moment just remember that this is a way to provide actions to main or contextual menus. For the moment we give an empty menu.
Until the next episode, just give it a try. Run the module. It will open the IDE with our module enabled. Open a project in IDE and watch for names, You will the the appended text for all the resources. Like it would be managed by Perforce.
On the next things in the following episode. Follow it! NetBeans Platform deserves it!
August 17, 2009
NetBeans 6.7.1 with JavaFX
NetBeans soon after 6.7 had launched another version of its IDE. That's 6.7.1 with JavaFX. As its name states, this version is an update version of the previous one containing few adiitional things:
- Support for JavaFX 1.2
- Update of GlassFish v3 Prelude
- Important bux fixes requested by users
NetBeans 6.7 was launched, what brings with him?

- NetBeans 6.7
From the beginning I must say that I am a big fun of NetBeans. I used since it was named Forte for Java version 2. I appreciate also Eclipse, but don't start here a flame on why I consider Netbeans superior.
From the release page we can see major topics on the improvements of new features brought to us by this version. You can read yourself about them. Here is my only humble opinion on this release.
Overview. The first impression is that is faster than its predecessors. The difference is visible in usage. Also, they added a feature to enable/disable features with you don't work.
Other languages than Java. Since I don't work too much with either of them I can't provide a full coverage. Still I am happy that I can have in the same IDE some tools for managing this kind of projects. That's cool. I tried PHP support, which I found quite good. Comparing with dedicated tools on that, it manages good. I found it fine for may needs. All that languages were supported before. Thought new valuable features were added for all of them. I would call here the sql editing and PHPUnit in php scripts, remote debugging for Ruby, code complettion on Groovy, profiling and QT libraries support for C/C++. Just to name few of them which are really consistent.
GlassFish. Nice that v3 is supported now. You have code completion, there is also a nice plug-in called GlassFish v3 enabler, quite usefull. You have also v2 version support.
Maven. That's really a very good thing. Maven support is much better now. You have a viewer for dependency graphs, you can configure a lot of your settings through UI. Also, you have archetypes for Java EE projects. The most appealing thing on that is that you can easily use your NetBeans project in another IDE. Practically nothing need to be done to do that. That's impressive. For the ones who want to know more on Maven they should take a look here.
Kenai. The most appealing to me. Kenai is a community similar to sourceforge, I think. But the best thing is that is fully integrated with NetBeans. For start up project is increddible. You have almost everything you can wish: bug tracking, wiki, dedicated place for a site, IM chats, etc. Take a loot at kenai.com. It worths the effort.
Conclusion. This release means "get into community" to my. Kenai is very apealing. In the same time they did not lost focus on continuous improvements. I believe everybody can found a new good reason to use NetBeans.
PS: for Eclipse developers now there's a button called "Synchronize editor with views" ;)
Subscribe to:
Posts (Atom)