This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.
this has been initially posted as part of #72091. The project UI customizer should be pluggable from 3rd party codebase. Even though the original submission was just for webapp projects, this is a rather general issue so probably belongs into the project/projectuiapi module. pasting from the #72091 issue: Define some registration mechanism, such as this layer.xml example: <folder name="WebProject"> <!-- These panels get placed in the project properties UI --> <folder name="customizers"> <file name="foo.instance"> <attr name="instanceClass" stringvalue="com.nuance.tools.speechproject.ui.FooPanelFactory"/> </file> </folder> </folder> </folder> Files in this folder denote instances of ProjectAwareUIFactory: public interface ProjectAwareUIFactory { String getCodeName(); String getDisplayName(); JComponent createComponent(Project p); } ...which are read in CustomizerProviderImpl.init(), and added to the list of categories and panels.
Hard to suggest something when the request is just vaguely formulated, but I'd like to stress that the API should be natuarally connected to ProjectCustomizer and if possible also somehow mimic core/options, so people who want to add a dialog to project or for tools/options need to do (nearly) similar thing. As concern the factory, I would say that it should create directly: http://www.netbeans.org/download/dev/javadoc/org-netbeans-modules-projectuiapi/org/netbeans/spi/project/ui/support/ProjectCustomizer.Category.html
random thoughts One possible issue is the handling of subcategories, on the declarative layer it could be solved by folders (one can set displaynames/icons there etc). a limitation of this is that one cannot have a panel for the node with subcategories, however I don't think it's an issue as currently all the project customizers have an empty panel there. I assume all the panels, even the default ones should be created using this API and we should have a single factory method in spi.support package somewhere that would create the customizer for the given layer data. eg. public static Dialog createCompositeCustomizerDialog(....) re yarda: creating Category instances is not enough. crutial is the createComponent(Project p) method that is not part of Category right now. Additionally the Category instance lists the children panels/categories and these should be probably also declarative to allow composition of nested categories.
Does the component need to handle OK/Cancel events?
Created attachment 29624 [details] initial API proposal
Here's the initial API proposal. I've tried to utilize the existing support classes as much as possible. what's added: 1. a factory method in ProjectCustomizer tha creates a dialog based on layer tree structure content. 2. the layer content is composed of CompositeCategoryProvider instances. The customizer-to-panel context transfer is done through passing Lookup instance as parameter. In the lookup one would put the Project instance and/or some custom API that is to be defined on per project type basis. 3. possible problem area is the creation of Category instances. These can be currently created using a factory method that includes an array of child category instances. But with declaratively defined categories it's not possible/useful to obtain this list from the SPI user's codebase. We could inject the children at later stage though. The create method allows to pass null or empty array as children, so we can even use the same factory method. jglick: just as they currently do. The panels can influence validity of the data through the Category.isValid()/setValid() method. If one of the panels is not valid, the customizer should not allow applying the changes.
Created attachment 29752 [details] complete patch (API+implementation) for projectuiapi
Created attachment 29753 [details] rewrite of j2seproject type that uses the new api.
please review.
I like it. It's an improvement over my initial implementation, which did not allow subcategories. I have 2 concerns, though: 1. Passing the project's Lookup into the factory methods may not be sufficient. There's all kinds of info I can get/set on a Project that I cannot get to with its Lookup. For example, if I'm setting information in the project.properties file of an ant-based project, I need the AntProjectHelper, which is not in the Lookup. I'd prefer just passing the Project into the factory methods for this reason (unless you have a better way of getting to the ant properties using just the Lookup). 2. My implementation adds a single interface, ProjectAwareUIFactory: String getCodeName(); String getDisplayName(); JComponent createComponent(Project p); Though my implementation didn't allow for subcategories, it probably could, with a little more code on the sysFs introspection code, allow folders. I think this is easier than having to learn about Categories and Subcategories. BTW, thanks for taking this up! My work life just got a lot more complicated, so I'm not moving on this as quickly as I should...
Milosi please do: cd $NB_CVS/java/j2seproject cvs add src/org/netbeans/modules/java/j2seproject/ui/customizer/J2SECompositePanelProvider.java cvs di -N and put a new diff since this one does not contain J2SECompositePanelProvider which I'm also curious about. Or just attach J2SECompositePanelProvider alone as an attachment. Thanks.
Created attachment 29777 [details] file missing from the j2se diff
Rich, re 1: The lookup passes into the factories/providers is not the project's lookup. It's a custom lookup created by the customizer implemetation. What is passed in there is up to the project type. For j2se project I put the J2seproject instance and a j2seprojectProperties instance. This is a private contract between the project type and the panels that plug into it. Not to be solved in projectuiapi module. re 2: the reason for having categories created and passed to panels is because it's a carrier of communication from panel to customizer. For example it allows the panels to set valid state and error message. and given it's a class from the api module used by the providers, it's easy to extend in backward compatible manner.
rich 1: from what I see the context provider is not restricted to pass exactly Project's lookup. The provider is free in consideration what should be passed in the Lookup. I.e. the provider "dictates" what others are able to do. So is is not the API proposed by Milos who restrict you but individual implementator, e.g. J2SEProject. So you rather need to communicate to idividual providers and ask them to put something in the lookup. API is benevolent enough. At least this is how I understand it ;)
Umm, sorry. Did not notice Milos's comment sent just before mine.
One question. The attached implementation behaves in the way that if a provider returns from CompositeCategoryProvider.createCategory() null, the creation of category is effectively skipped, i.e. the category is not shown in the project's customizer without any warnings/errors. I like this behaviour since I'm able to show my category based on the Lookup content. Possible usecase: I could implement a general ProjectCustomizer.CompositeCategoryProvider which I would inject into all Project's customizers and then very easily "hide" my category for unsatisfactory contexts (e.g. there is not Project instance in the lookup). But not sure if this just undocumented feature I can depend on or if I would have to go another way in the above use case. I hope that this is just fast draft and Javadoc will be ehnanced a little bit so e.g. the above will be clear. Nitpicking.... J2SECompositePanelProvider: - constructor should be private - use of foreign class in NbBundle.getBundle(CustomizerProviderImpl.class) Just PMD-ized it ;) I'm curious since API Support customizer... Also thinking about API Wizard but that's another story depending on the success of review...
AB01: I would suggest not to use a top-level layer folder such as "J2SEProject" for the customizer. What about creating a hierarchy similar to Loaders/mime/type/Actions, so maybe Projects/project-type/Customizer? Note issue 72441 seems to use Projects/Nodes/projecttype for now, but I think the former approach would be better, since everything (nodes, categories, etc.) would be under a single folder. Of course a project type can ultimately use whatever path it chooses to, but it would be nice if the Javadoc suggested (and the J2SE project used) a good value. AB02: apart from mkleint's comment #3 about injecting the subcategories, the API does not seem to discourage a client from returning a category which already contains subcategories (i.e., created by passing a non-null value as the subcategories parameter of Category.create()) from CompositeCategoryProvider.createCategory(). However, DelegateCategoryProvider.create() throws an AssertionError for the subcategories because they are not in the category2provider map. Perhaps this should be also supported. I agree with Martin's comment about supporting null values from CCP.createCategory().
Created attachment 29895 [details] updated diff of projects/projectuiapi
Created attachment 29897 [details] updated j2seproject changes
mkrauskopf: yes, returning null in CompositeCategoryprovider shall be allowed. I've updated the javadocs. AB01: good catch, I've moved the j2se project's customizers to Projects/J2SEproject/Customizer folder. AB02: I've added an assertion that makes sure noone is returning a category with children.
Thanks to all for the comments. about to apply the changes to trunk later this week.
Sorry for the late comments. But it looks good. For folder name, prefer to use the ant/project project type code as a convention, so e.g. Projects/org-netbeans-modules-java-j2seproject/Customizer J2SECompositePanelProvider.java: SPL instanceClass attr in j2seproject layer is definitely superfluous, and instanceOf can probably be omitted as well - just instanceCreate is enough here.
jglick: all comments accepted and integrated. The changes are now in trunk.