Please use the Apache issue tracking system for new NetBeans issues ( !!
Bug 74373 - API for adding panels in the project customizer
API for adding panels in the project customizer
Product: projects
Classification: Unclassified
Component: Generic Projects UI
All All
: P3 (vote)
: 6.x
Assigned To: Milos Kleint
Depends on:
Blocks: 72091
  Show dependency treegraph
Reported: 2006-04-04 13:01 UTC by Milos Kleint
Modified: 2006-11-20 13:03 UTC (History)
6 users (show)

See Also:

initial API proposal (4.36 KB, patch)
2006-04-05 14:08 UTC, Milos Kleint
Details | Diff
complete patch (API+implementation) for projectuiapi (11.69 KB, patch)
2006-04-11 10:31 UTC, Milos Kleint
Details | Diff
rewrite of j2seproject type that uses the new api. (22.15 KB, patch)
2006-04-11 10:32 UTC, Milos Kleint
Details | Diff
file missing from the j2se diff (6.44 KB, text/plain)
2006-04-12 07:28 UTC, Milos Kleint
updated diff of projects/projectuiapi (13.38 KB, patch)
2006-04-18 13:16 UTC, Milos Kleint
Details | Diff
updated j2seproject changes (25.58 KB, patch)
2006-04-18 13:23 UTC, Milos Kleint
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Milos Kleint 2006-04-04 13:01:25 UTC
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"

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.
Comment 1 Jaroslav Tulach 2006-04-04 13:51:21 UTC
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:
Comment 2 Milos Kleint 2006-04-04 14:42:19 UTC
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 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.
Comment 3 Jesse Glick 2006-04-04 18:55:02 UTC
Does the component need to handle OK/Cancel events?
Comment 4 Milos Kleint 2006-04-05 14:08:34 UTC
Created attachment 29624 [details]
initial API proposal
Comment 5 Milos Kleint 2006-04-05 14:39:59 UTC
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.
Comment 6 Milos Kleint 2006-04-11 10:31:41 UTC
Created attachment 29752 [details]
complete patch (API+implementation) for projectuiapi
Comment 7 Milos Kleint 2006-04-11 10:32:16 UTC
Created attachment 29753 [details]
rewrite of j2seproject type that uses the new api.
Comment 8 Milos Kleint 2006-04-11 10:37:55 UTC
please review.
Comment 9 Rich Unger 2006-04-11 21:46:36 UTC
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
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...
Comment 10 Martin Krauskopf 2006-04-12 07:04:24 UTC
Milosi please do:

  cd $NB_CVS/java/j2seproject
  cvs add
  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.
Comment 11 Milos Kleint 2006-04-12 07:28:27 UTC
Created attachment 29777 [details]
file missing from the j2se diff
Comment 12 Milos Kleint 2006-04-12 07:58:04 UTC
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
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.
Comment 13 Martin Krauskopf 2006-04-12 08:05:53 UTC
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 ;)
Comment 14 Martin Krauskopf 2006-04-12 08:07:37 UTC
Umm, sorry. Did not notice Milos's comment sent just before mine.
Comment 15 Martin Krauskopf 2006-04-12 10:07:50 UTC
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.


  - 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...
Comment 16 Andrei Badea 2006-04-12 22:34:05 UTC
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

I agree with Martin's comment about supporting null values from
Comment 17 Milos Kleint 2006-04-18 13:16:07 UTC
Created attachment 29895 [details]
updated diff of projects/projectuiapi
Comment 18 Milos Kleint 2006-04-18 13:23:13 UTC
Created attachment 29897 [details]
updated j2seproject changes
Comment 19 Milos Kleint 2006-04-18 13:32:47 UTC
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
Comment 20 Milos Kleint 2006-04-24 14:25:37 UTC
Thanks to all for the comments.
about to apply the changes to trunk later this week.
Comment 21 Jesse Glick 2006-04-24 18:47:47 UTC
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 SPL

instanceClass attr in j2seproject layer is definitely superfluous, and
instanceOf can probably be omitted as well - just instanceCreate is enough here.
Comment 22 Milos Kleint 2006-04-25 13:25:18 UTC
jglick: all comments accepted and integrated.

The changes are now in trunk.

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2014, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo