|
|
|
|
|
The project implements a new component palette that will be reused by other projects. The new palette should provide a common look and feel for Form editor, Mobility, J2EE and possible other modules as well. UI draft specification is available at http://ui.netbeans.org/docs/ui/palette/index.html
Question (arch-overall): Describe the overall architecture. Answer:The API provides access to the Common Component Palette. The palette clients can use this API to define content to be displayed in the common palette TopComponent when their editors are active. The module will autoload. Palette
The API includes support for the clients writing palette content insertable into the text editor.
This support covers the DTD definition of the palette item definition file format and the content
of the Lookup holding object(s) representing the selected item.
editor-palette-item-1_0.dtd
The Common Palette content is a two-level hierarchy. The top-most level are Categories, the Category children are Items. It's possible to select (highlight) items in the palette panel using a mouse or keyboard and then inserted/dropped into an editor that supports the palette.
The palette content can come from two different sources:
The following steps must be taken if a module wants to define its own palette content as a hierarchy of folders and files in its XML layer:
<filesystem> <folder name="MyModulePalette"> <folder name="Category1"> <file name="PaletteItem_1.myitem" url="palette/PaletteItem_1.xml" /> <file name="PaletteItem_2.myitem" url="palette/PaletteItem_2.xml" /> <file name="PaletteItem_3.myitem" url="palette/PaletteItem_3.xml" /> </folder> <folder name="Category2"> <file name="PaletteItem_4.myitem" url="palette/PaletteItem_4.xml" /> <file name="PaletteItem_5.myitem" url="palette/PaletteItem_5.xml" /> <file name="PaletteItem_6.myitem" url="palette/PaletteItem_6.xml" /> </folder> </folder> </filesystem>
class MyPaletteActions extends PaletteActions { public Action getPreferredAction(Lookup lookup) { Node itemNode = (Node)lookup.lookup( Node.class ); if( null != itemNode ) { return new InsertItemAtDefaultLocationAction( itemNode ); } return null; } public Action[] getCustomItemActions(Lookup lookup) { Node itemNode = (Node)lookup.lookup( Node.class ); if( null != itemNode ) { return new Action[] { new CustomizeItemAction( itemNode ) }; } return null; } public Action[] getCustomCategoryActions(Lookup lookup) { Node categoryNode = (Node)lookup.lookup( Node.class ); if( null != categoryNode ) { return new Action[] { new CustomizeCategoryAction( categoryNode ) }; } return null; } public Action[] getImportActions() { return new Action[] { new ImportItemsFromWebAction() }; } public Action[] getCustomPaletteActions() { return null; //no custom actions for palette's root } }
class MyClass { PaletteController controller; PaletteController initializePalette() { try { controller = PaletteFactory.createPalette( "MyPalette", new MyPaletteActions() ); } catch (IOException ex) { ex.printStackTrace(); return; } controller.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if( PaletteController.PROP_SELECTED_ITEM.equals( evt.getPropertyName() ) ) { Lookup selItem = controller.getSelectedItem(); if( null == selItem ) { //nothing is selected in palette } else { Node selNode = (Node)selItem.lookup( Node.class ); if( null != selNode ) { //change mouse cursor for editor window to indicate //the type of palette item that can be dropped changeCursorInEditorWindow( selNode ); } } } } }); return controller; } }
class MyEditorTopComponent extends TopComponent { private MyEditorTopComponent() { this( new InstanceContent() ); } private MyEditorTopComponent( InstanceContent content ) { super( new AbstractLookup( content ) ); content.add( initializePalette() ); initEditorComponents(); } PaletteController controller; private PaletteController initializePalette() { if( null == controller ) { controller = PaletteFactory.createPalette( "MyPalette", new MyPaletteActions() ); } return controller; } }
When an item is selected in the palette and user clicks into the editor window then the module can ask for selected item by calling PaletteController.getSelectedItem(). This method returns a Lookup that holds object(s) representing the selected item. After the item is inserted into the editor window the module may clear palette's selection (PaletteController.clearSelection()) or leave the item selected to implement 'multi drop' insertion scenario.
It is possible to filter palette content and hide some categories and/or items from the user by extending PaletteFilter class.
class MyPaletteFilter extends PaletteFilter { public boolean isValidItem(Lookup lookup) { Node itemNode = (Node)lookup.lookup( Node.class ); return isItemVisibleInCurrentEditorContext( itemNode ); } public boolean isValidCategory(Lookup lookup) { Node categoryNode = (Node)lookup.lookup( Node.class ); return isCategoryVisibleInCurrentEditorContext( categoryNode ); } private boolean isItemVisibleInCurrentEditorContext( Node item ) { boolean res = true; //check current cursor positions and/or item type and decide whether //the item is valid, i.e. can be selected and dropped into editor return res; } private boolean isCategoryVisibleInCurrentEditorContext( Node item ) { boolean res = true; //check current cursor positions and/or category type and decide whether //the category is valid, i.e. its items can be selected and dropped into editor return res; }
Then initialize the palette using the following method:
MyPaletteFilter filter = new MyPaletteFilter(); PaletteController controller = PaletteFactory.createPalette( "MyPalette", new MyPaletteActions(), filter, null );
It is necessary to call PaletteController.refresh() to refresh and repaint the palette window whenever the filtering condition has changed:
myPaletteFilter.setShowSomeSpecialCategories( false ); paletteController.refresh();
The initial state of the palette can be overridden by setting appropriate attributes to palette model. The list of supported attributes is defined in PaletteController class. If the palette model is create from Nodes then the attributes are extracted by calling Node.getValue() method on the root Node and category and item nodes. If the palette model is defined as folders and files in the layer then the attributes are extracted by calling FileObject.getAttribute().
In the example below the palette will not show item names initially
(only icons are visible), the user can change this in palette's context menu.
Category1 is read-only therefore the user cannot remove it.
Category2 is not initially visible, the user can change this in
palette's customizer.
<filesystem> <folder name="MyModulePalette"> <attr name="showItemNames" stringvalue="false"/> <folder name="Category1"> <attr name="isReadonly" stringvalue="true"/> <file name="PaletteItem_1.myitem" url="palette/PaletteItem_1.myitem" /> <file name="PaletteItem_2.myitem" url="palette/PaletteItem_2.myitem" /> <file name="PaletteItem_3.myitem" url="palette/PaletteItem_3.myitem" /> </folder> <folder name="Category2"> <attr name="isVisible" stringvalue="false"/> <file name="PaletteItem_4.myitem" url="palette/PaletteItem_4.myitem" /> <file name="PaletteItem_5.myitem" url="palette/PaletteItem_5.myitem" /> <file name="PaletteItem_6.myitem" url="palette/PaletteItem_6.myitem" /> </folder> </folder> </filesystem>
It is possible to add new palette categories and/or palette item at runtime when the palette window is already visible.
Adding a new category is very straight-forward, it basically means creating a new folder under palette's root folder in XML layer:
FileObject paletteRoot = FileUtil.getConfigFile( "MyModulePalette" ); paletteRoot.createFolder( "NewCategory" );
Adding a new item is a similar task:
FileObject paletteRoot = FileUtil.getConfigFile( "MyPalette" ); FileObject targetCategoryFO = paletteRoot.getFileObject( "CategoryName" ); DataFolder targetCategoryDF = DataFolder.findFolder( targetCategoryFO ); DataObject dobj = (DataObject)itemNode.getLookup().lookup( DataObject.class ); dobj.copy( targetCategoryFolder );
Please refer to Nodes API in case the palette content is defined as a hierarchy of arbitrary Nodes.
The following steps must be taken when writing the item using the support provided by this module:
The remaining work is about 1 man/weeks (July 20th 2005).
Question (arch-quality): How will the quality of your code be tested and how are future regressions going to be prevented? Answer:There are unit tests for Palette's model implementation and assertions are used where appropriate.
Question (arch-where): Where one can find sources for your module? Answer:
The sources for the module are in the NetBeans Mercurial repositories.
OpenAPIs -
For acces to Nodes, winsys TopComponent, ActiveEditorDrop, lookups, resource bundles etc.
The default answer to this question is:
These modules are required in project.xml:
None
Question (dep-platform): On which platforms does your module run? Does it run in the same way on each? Answer:No platform dependencies.
Question (dep-jre): Which version of JRE do you need (1.2, 1.3, 1.4, etc.)? Answer:1.4 or greater
Question (dep-jrejdk): Do you require the JDK or is the JRE enough? Answer:JRE should be enough.
Just the module jar file: org-netbeans-modules-palette.jar
Question (deploy-nbm): Can you deploy an NBM via the Update Center? Answer:Yes
Question (deploy-shared): Do you need to be installed in the shared location only, or in the user directory only, or can your module be installed anywhere? Answer:Install location should not matter.
Question (deploy-packages): Are packages of your module made inaccessible by not declaring them public? Answer:Yes, non-API packages are not declared public.
Question (deploy-dependencies): What do other modules need to do to declare a dependency on this one, in addition to or instead of the normal module dependency declaration (e.g. tokens to require)? Answer:Nothing.
Yes (any uninternationalized text will be fixed during implementation).
Question (compat-standards): Does the module implement or define any standards? Is the implementation exact or does it deviate somehow? Answer:The palette's user inteface should match the look and feel of comparable components in competitive IDEs as defined in the UI specification document.
Question (compat-version): Can your module coexist with earlier and future versions of itself? Can you correctly read all old settings? Will future versions be able to read your current settings? Can you read or politely ignore settings stored by a future version? Answer:API should be backwards compatible, old settings can be ignored if needed. All user settings are stored in an XML file that can be easily extended.
Question (compat-deprecation): How the introduction of your project influences functionality provided by previous version of the product? WARNING: Question with id="compat-deprecation" has not been answered!java.io.File
directly?
Answer:
No
Question (resources-layer): Does your module provide own layer? Does it create any files or folders in it? What it is trying to communicate by that and with which components? Answer:
Yes, it creates folder PaletteSettings where a file is created for user settings
for each palette model.
There's also Window System definition of palette's TopComponent group and mode.
Palette clients (editor modules) may define palette contents in their layers.
The default palette model is based on Nodes that may be defined in layer hierarchy.
Question (resources-mask): Does your module mask/hide/override any resources provided by other modules in their layers? Answer:No
Question (resources-preferences): Does your module uses preferences via Preferences API? Does your module use NbPreferences or or regular JDK Preferences ? Does it read, write or both ? Does it share preferences with other modules ? If so, then why ? WARNING: Question with id="resources-preferences" has not been answered!org.openide.util.Lookup
or any similar technology to find any components to communicate with? Which ones?
Answer:
Palette listens to system activated node changes. The palette TopComponent
opens when an editor TopComponent with a PaletteController instance in its Lookup
is opened or activated. Palette window closes when the editor window is closed
or deactivated and no other visible editor window supports the palette.
The palette window always shows the content from the last active editor
window regardless where the input focus is. The palette content is updated
when user activates a different editor window that supports the palette.
node_represention
-
The palette item implementor can either directly provide the item body
or her own item class implementing org.openide.text.ActiveEditorDrop
interface.
Lookup that holds object(s) representing the selected item then associates
custom item class instance with the org.openide.text.ActiveEditorDrop.class
key and
the body with java.lang.String
key.
Editor side implementor can use the Lookup content whenever the Lookup is given,
namely in the editor-provided implementations of the PaletteActions
,
DragAndDropHandler
and PropertyChangeListener
(registered
on the PaletteController
) interfaces.
No
System.getProperty
) property?
On a similar note, is there something interesting that you
pass to java.util.logging.Logger
? Or do you observe
what others log?
Answer:
No
Question (exec-component): Is execution of your code influenced by any (string) property of any of your components? Answer:No
Question (exec-ant-tasks): Do you define or register any ant tasks that other can use? Answer:No
Question (exec-classloader): Does your code create its own class loader(s)? Answer:No
Question (exec-reflection): Does your code use Java Reflection to execute other code? Answer:No
Question (exec-privateaccess): Are you aware of any other parts of the system calling some of your methods by reflection? Answer:No
Question (exec-process): Do you execute an external process from your module? How do you ensure that the result is the same on different platforms? Do you parse output? Do you depend on result code? Answer:No external processes.
Question (exec-introspection): Does your module use any kind of runtime type information (instanceof
,
work with java.lang.Class
, etc.)?
Answer:
No
Question (exec-threading): What threading models, if any, does your module adhere to? How the project behaves with respect to threading? Answer:All API classes are thread safe.
Question (security-policy): Does your functionality require modifications to the standard policy file? Answer:No
Question (security-grant): Does your code grant additional rights to some other code? Answer:No
There's a private XML file for user settings for each palette model.
Question (format-dnd): Which protocols (if any) does your code understand during Drag & Drop? Answer:
Palette extends the default drag'n'drop implementation from Nodes. When an item
is being dragged from the palette to editor window the Transferable is provided
by the default Node.drag() method and a another data flavor is added
(see PaletteController.ITEM_DATA_FLAVOR) which contains the Lookup of dragged
item's Node.
Palette clients can provide their own data flavors to items being dragged by
subclassing the DragAndDropHandler class. This class also provides methods
to implement the drop of new items from e.g. editor area to the palette window.
java.awt.datatransfer.Transferable
?
Answer:
Palette extends the default clipboard implementation from Nodes. When a palette item (Node) is copied/cut to clipboard it adds another data flavor to Transferable created by the default Node implementation, see PaletteController.ITEM_DATA_FLAVOR. The transfer data for this flavor is the Lookup of item's Node.
No
Question (perf-exit): Does your module run any code on exit? Answer:No
Question (perf-scale): Which external criteria influence the performance of your program (size of file in editor, number of files in menu, in source directory, etc.) and how well your code scales? Answer:The default palette model implementation is based on Nodes, therefore the performance criteria are the same as those for Nodes.
Question (perf-limit): Are there any hard-coded or practical limits in the number or size of elements your code can handle? Answer:No
Question (perf-mem): How much memory does your component consume? Estimate with a relation to the number of windows, etc. Answer:Depends on the palette contents provided by palette clients. The Palette module provides only user interface for the palette contents.
Question (perf-wakeup): Does any piece of your code wake up periodically and do something even when the system is otherwise idle (no user interaction)? Answer:No
Question (perf-progress): Does your module execute any long-running tasks? Answer:Depends on the palette contents provided by palette clients. When the palette contents is being switched (i.e. user activates a different editor) the palette UI must display icons and/or names for items in expanded categories. This is being done in AWT thread. On the other hand the palette can show only a limited number of items according to screen resolution so there will be only a limited number of of requests for item's name and icon during this switch.
Question (perf-huge_dialogs): Does your module contain any dialogs or wizards with a large number of GUI controls such as combo boxes, lists, trees, or text areas? Answer:There's a 'Palette Customizer' dialog window that displays hierarchy of palette contents (categories and their items) and contains some buttons to customize the palette contents. The Palette Customizer window design depends on the final version of the UI specification.
Question (perf-menus): Does your module use dynamically updated context menus, or context-sensitive actions with complicated and slow enablement logic? Answer:No
Question (perf-spi): How the performance of the plugged in code will be enforced? Answer:Just javadoc recommendations.
Built on June 4 2024. | Copyright © 2017-2024 Apache Software Foundation. All Rights Reserved.