New Window System API Changes
Version: 0.6, January 8, 2004
Author: Peter Zavadsky,
Sun Microsystems/NetBeans
Marek Slama, Sun
Microsystems/NetBeans
- Abstract:
- Following document describes changes in API which emerged both
from UI spec
and problems with adjusting to the older API. It shows also recommends
how the client code should be adjusted to the new window system.
- Document History:
[10/01/2003] : version 0.1 : {First preliminary version of the document}
[10/08/2003] : version 0.2 : {Merged groups and workspaces documents
into this one to have the changes together}
[10/10/2003] : version 0.3 : {Changed API according to internal API
review, added explanation of createMode method behavior}
[10/20/2003] : version 0.4 : {Added also persistence descriptions (XML
layers)}
[11/25/2003] : version 0.5 : {Added method findTopComponent}
[01/08/2004] : version 0.6 : {Added method TopComponent.getPersistenceType}
Contents:
1 Overview
This document describes all changes which come with the new window
system implementation. There are a lot of them, abandoning workspaces,
introducing window groups, new version of XML declarations, various API
enhancements and API deprecations.
There is necessary to say, that the new window system is compatible
with the older API, thus all older client code should work somehow even
unchanged. On the other hand due to a significant changes it is
recommended that those deprecated code is revised and adjusted to the
new state accordingly, the special is about XML layer, which is almost
necessary to redefine, in order to get the proper layout, since the
change in layout is significant comparing to the older one.
2 New Concepts
The
window
spec UI spec introduced a couple of new concepts the implementation
has to deal with. Those are changed layout from the border like one to
generic split layout, division windows to documents and views, introduction
of window groups, and abandoning workspaces.
2.1 Generic Split Layout
The original 'border-like' layout, which allowed center, north, south,
west and east positioning of windows inside mode and also inside desktop
was changed to generic split layout of desktop while mode isn't divided
itself anymore. This has especially impact on changes of XML layer
declaration, while the API is still kept kind of asymmetric like it was
before, i.e. it is not possible to achieve the same layout from
client code. Currently the layout is matter of layers only. Client
programmer is not allowed to manipulate it, just user. Manipulation of
layout means adding, removing, repositioning of modes, which represent
kind of cell in the generic split layout. Using API is allowed just move
the windows (TopComponents) via those existing modes.
2.2 Document and View Windows
The windows (TopComponents) are divided to documents and views. From UI
point of view document is window which is supposed for the main work.
The most of working time is spent in it. Those are editors, GUI editor,
image viewer etc. Views are windows which are just helper windows to the
documents ones. Those are typically explorers, debugger windows, form
palette and inspector, properties etc. The impact on user is, these
windows can't be mixed together, i.e. they may not be contained in the
same mode, e.g. editor (java source) can't be at the same place with
explorer and vice versa.
Documents Area:
Therefore are also modes divided to document and view kinds. There is
also defined (from UI point of view) editor are, which is always present
on screen. This divides for user the views and documents. Every window
(mode) which resides inside the document area are document windows (i.e.
modes are documents kind) and all windows (modes) around that area are
view windows (i.e. modes are of view kind). User can differentiate these
two types by different UI of the tabbed components, (and also that she
is not allowed to mix those windows together, e.g. when trying DnD).
Internal Implementation:
Currently
it is implemented quite hard way. Modes are declared whether they are
view or document (editor) kind (That way it defines whether its
constraints are relative to the document area or not).
// PENDING
Problem how to define undefined windows Problematic is
current implementation of TopComponent (window) type. It is defined by
client property. Then this property is checked whether the TopComponent
can or can't be added to particular mode. If the TopComponent is not
defined (doesn't contain that client property) it is defined the way,
depending to which mode is adding first time, it is set the appropriate
type. But problem appears if some mode doesn't exist (e.g. mode was not
loaded, because it was in old layer defined), then it is put into
default editor mode.
After talk with Yarda, it seems there could be better solution than the
current one, i.e. don't define the kind of TopComponent internally. For
client programmer allow to add (dock) the TopComponent anywhere. For
user prohibit the mixing (to achieve the UI goal) that way, take the
type of TopComponent from mode it currently reside.
2.3 Window Groups
Window groups offer client programmer easily to follow the
concept of user managed opening/closing of 'helper' windows. There are
tasks (like GUI editing, debugging) which typically uses certain helper
windows needed to accomplish that task (like Component Palette/Inspector,
debugger windows etc.). Those windows are typically needed to be present
just during the time of that task, no sooner, no later. To get this
goal, it could seems is enough just to open and close those windows,
upon the task start or finish. But groups offer something more. They
allow user to manage opening state of those helping windows. before,
during and after that task. Window system group implementation allows
this concept easily to follow for client programmers, it offers very
simple API (the only more "complicate" part is the group definition in
XML layer). All the runtime difficulties are done behind the scenes in
window system implementation.
Note
about older name Window Sets: Please start to use term "window
group" instead often older one "window set". Window set is a name coming
from UI spec, but is a bit misleading, since in java is Set an
unordered collection of objects. The group name fits much better,
because it tells that those windows belong somehow together while they
don't represent any collection at the same time.
Groups are considered to be a replacement of
workspaces concept. But those are not the same. In short there is a at
least one significant difference, i.e.
groups
don't change the layout of windows, they manage just opening and
closing of them. More detailed explanation should give UI document (
UI spec).
About the concept of groups: At first sight you can
see the group is nothing more than just sheer opening or closing more
windows. You would say it is nothing special, you can achieve the same
goal with the API not using groups at all. Why are there those groups?
The reason is there is some value group
implementation adds there. I.e. groups can manage the opening/closing of
its windows "accordingly to the user". Look at the scenarios.
List of scenarios:
- Opening
group when none of the member TopComponents are opened
In that case, when group is opening (call group.open() method) all the
member TopComponents with opening flag set to true are opened. In NB
(new WS build) when you select the Form Designer window all the windows
(Component Palette, Component Inspector, Properties) gets opened.
- Closing
group when none of the member TopComponents were opened before the
group was opened
In that case, when group is closing (call group.close() method) all the
member TopComponents with closing flag set to true are closed. In our
case when you 'unselect' last Form Designer window (that way no
FormDesigner window is selected on screen) all the windows (Component
Palette, Component Inspector, Properties) gets closed.,
- Closing
group when some of the member TopComponents were opened before the group
was opened
In that case are closed just those member TopComponents which closing
flag is set to true and were not opened before the group was opened. In
our case when you had opened e.g. Component Palette before the group was
opened, then when closing the group Component Palette window remains
opened (unless you closed it explicitly while the group was opened).
- Opening
group when some of the member TopComponents were closed while the group
was previously opened
In that case was the opening flag of those member
TopComponents set to false, thus upon next group opening are opened just
those member TopComponents which have the opening flag set to true. In
our case when you have opened form group (selected Form Designer window)
and closed e.g. Component Palette during the time the group was
previously opened, then closed the group ('unselect' Form Designer
window). When opening the group next time the Component Palette is not
opened. (User can get back the old behavior when opens the Component
Palette while the group is opened see the next point.)
- Opening
group when come of the member TopComponents were opened while the group
was previously opened
In this case was the opening flag of those member TopComponents set to
true, thus upon next group opening are opened together with other member
TopComponents which have the opening flag set to true. In our case
(continue from the previous step), if you have opened the form group
while the Component Palette wasn't, you can open the Component Palette
'manually' from the menu (before the group was closed), the close the
group and when open the group again, you get also opened Component
Palette.
These scenarios is a bit complicated to explain. Much more
understandable is when you try it out, and imagine that for client
programmer it is just simple group.open() and group.close() method calls.
See also
Window Groups API.
2.4 Abandoning Workspaces
Since the new window system doesn't support concept of workspaces (
see the UI
spec) anymore, the older API dealing with workspaces (Workspace
interface, and couple of methods in other class in org.openide.windows
package) becomes useless. However the older client code dealing with the
workspaces should work somehow. See more in
deprecated
API. This document also shows what are the replacements of the older
Workspace API.
Replacements of the Workspace API should be understandable and
self explaining. It could happen that some of the solutions may not fit,
e.g. when finding of Workspace according some name the current solution
returns the singleton implementation which has (in almost all cases)
different name. If you feel it is wrong, please demand the change of
that solution. I preferred the most straightforward one in order to keep
the older code working as much as possible.
Compatibility
Issues:
In order the older API is working in some way, the
new window system pretends it works with one internal workspace (which
can be assumed as singleton workspace implementation). It means that
all older client code referring to workspaces will remain working
somehow. I.e. it always gets the singleton instance of workspace, e.g.
when creating the new workspace, there is returned the singleton
instance, when asking for workspaces, it is again returned set which
contains only the one singleton instance. Other older API methods
which uses workspace as an argument, just ignore the argument and are
considering they are working in the singleton workspace instance context.
See also
deprecated API working with Workspaces.
2.5 Note about Focus Management
Old window system supported, probably from the wrong reasons, managing
of itself by requesting focus of Component (please don't mix with old
API TopComponent.requestFocus() call). I.e. when was passed focus to
e.g. JButton which was contained
in not active TopComponent, that TopComponent got activated.
This is no more supported, (I believe) this was an undocumented
feature and is highly problematic... for managing of window system, i.e.
activating TopComponents is necessary used purely the API from
org.openide.windows package.
3 Summary of API Changes
Describes API changes both in code and XML layer declarations.
3.1 API Enhancements
There are a couple of API enhancements.
3.1.1 Window Groups API
The API for window groups is extremely simple. It consists currently
of a method in WindowManager class and one TopComponentGroup interface.
The WindowManager methods are:
public
TopComponentGroup
findTopComponentGroup(String
name) { ... }
The method is used to find the TopComponentGroup according its specified
name.
There is an interface which represents the group
public interface
TopComponentGroup {
public void open();
public void close();
}
The interface is used to open or close the group respectively.
Usage:
The TopComponentGroup interface helps client
programmer (module owner) to use the concept of groups in a very simple
way. There is necessary to specify the group in XML layer, define member
TopComponents (
see below), find it via
WindowManager.findTopComponentGroup(String name) method and then open or
close it when needed. All the other staff adds window system group
implementation, i.e. the managing opening and closing according to the
above scenarios. Let have a look at the real example:
Code snippet from form/src/.... FormGroupActivator.java:
TopComponentGroup group = WindowManager.
getDefault().
findTopComponentGroup(
"form");
// NOI18N
if(group !=
null) {
if(
isFormDesignerSelected()) {
group.
open();
}
else {
group.
close();
}
}
The client code is very simple. It just finds the group named "form"
(form group defined in XML layer) and opens or closes it respectively
according to its needs (i.e. when there is selected FormDesigner
component or not respectively). The group has to be properly defined in
the XML layer (i.e. define its members and opening and closing flags, in
our case it includes Component Palette, Component Inspector and
Properties windows all with opening and closing flags set to true ).
Hint for modules:
Usage of group is restricted to view kind of TopComponents... i.e. to
the helper singleton windows. Programmatically isn't allowed anything but
opening and closing of the group. This is a warning before
overusing of this feature. First have a look at the already using form,
output and execution groups.
3.1.2 Other API Enhancements
TopComponent.activate() method
replaces usage of
TopComponent.requestFocus()
method. The
requestFocus()
method was misused in the past API for activation of
TopComponent, which could cause
problems if that method is used for requesting focus only (e.g. by focus
management framework when the
TopComponent
is used as an ordinary
Component).
Instead of this method client code should use
TopComponent.activate() method.
Older
API
|
New
API
|
Explanation
|
method public void requestFocus () in TopComponent class
[Note: this is talked about using this method for TopComponent
activation]
|
method public void requestActive() in TopComponent class
|
|
method public void setName(String name) in TopComponent
class
|
methods public void setDisplayName(String displayName)
in TopComponent class
|
Field name is supposed to be
programmatic name of component
|
method public String getName() in TopComponent class
|
methods public String getDisplayName() in TopComponent
class
|
Field name is supposed to be
programmatic name of component |
No API
|
method public int getPersistenceType() in TopComponent
class
|
This method should be overriden in subclass
to return proper constant defining component persistence type. Possible values are
TopComponent.PERSISTENCE_ALWAYS,
TopComponent.PERSISTENCE_ONLY_OPENED,
TopComponent.PERSISTENCE_NEVER. It replaces TopComponent client property
PersistenceType.
|
No API
|
method public
String findTopComponentID(TopComponent)
in WindowManager class and method protected
String preferredID() in
TopComponent class
|
Provides unique ID for each
TopComponent instance, preferredID method allows subclasses influence the
resulting ID, it is used as a base when creating the ID.
|
No API
|
method public
TopComponent findTopComponent(String)
in WindowManager class
|
Retrieves TopComponent instance by TopComponent
unique ID. It is used mainly to access persistent singleton TopComponent instance. Complementary
method with method findTopComponentID.
|
No API
|
method public
TopComponent getSelectedTopComponent()
in Mode interface |
|
No API
|
There is also introduced new
API, i.e. TopComponentGroup interface, which allows client programmer to
use concept of window groups. Have a look at TopComponentGroup
API description |
|
3.2 API Deprecations
3.2.1 API Replacing Deprecated Workspace
Table shows what are the replacements instead of the deprecated
Workspace API.
Deprecated
Workspace API
|
API
replacing the deprecated Workspace API
|
| field public static final
String PROP_MODES |
Use field public static final
String PROP_MODES in WindowManager class |
| field public static final
String PROP_NAME |
Do not use anymore, it is
redundant
|
field public static final
String PROP_DISPLAY_NAME
|
Do not use anymore, it is
redundant
|
method public String getName ();
|
Do not use anymore, it is
redundant |
method public String getDisplayName ();
|
Do not use anymore, it is
redundant |
method public Set getModes ();
|
Use method public Set getModes() in WindowManager class
|
method public
Rectangle getBounds ();
|
Do not use anymore, it is
redundant
|
method public void activate ();
|
Do not use anymore, it is
redundant |
method public Mode createMode (String name, String
displayName, URL icon);
|
see explanation |
method public Mode findMode (String name);
|
Use method public Mode findMode(String name) in
WindowManager class
|
method public Mode findMode (TopComponent tc);
|
Use method public Mode findMode(TopComponent tc) in
WindowManager class
|
method public void remove ();
|
Do not use anymore, it is
redundant
|
method public void addPropertyChangeListener
(PropertyChangeListener list);
|
Use method public abstract void addPropertyChangeListener
(PropertyChangeListener l); in WindowManager class
|
method public void removePropertyChangeListener
(PropertyChangeListener list);
|
Use method public abstract void removePropertyChangeListener
(PropertyChangeListener l); in WindowManager class
|
Problem with createMode method
Since the current layout differs from the previous one, and
restrictions defined by UI to the current behavior differs dramatically.
It was needed to change behavior of createMode method. That method
currently doesn't create new mode instance but always returns the
default editor mode (the one in documents area). Thus currently there is
no way to create mode programmaticaly. It is possible via declaration in
XML layer only. This restriction was made from the reason, that no
floating modes (nor the internal ones) are allowed, just those ones
residing in the generic split layout. Since the usecase for the
createMode method was to create floating mode, it was bypassed the above
described way. This solution is fully reasonable for current
implementation which is 'MDI like'. That is the mainly supported state
and only focused by HIE. However there is also support for 'SDI like'
state. For that case the creation of the floating modes has sense. Thus
it is necessary to specify how the createMode method should behave,
whether is could differ depending on which state is currently on.
3.2.2 Deprecated API Working with Workspaces in
WindowManager Class
In the class WindowManager are deprecated following:
Deprecated
API dealing with Workspaces in WindowManager class
|
API
replacing the deprecated one
|
| field public static final
String PROP_WORKSPACES |
Do not use anymore, it is
redundant |
| method public final
Workspace createWorkspace
(String name) |
Do not use anymore, it is
redundant. It always returns the singleton Workspace implementation |
| method public abstract
Workspace createWorkspace
(String name, String displayName); |
Do not use anymore, it is
redundant. It always returns the singleton Workspace implementation |
| method public abstract
Workspace findWorkspace (String
name); |
Do not use anymore, it is
redundant. It always returns the singleton Workspace implementation |
| method public abstract
Workspace[] getWorkspaces (); |
Do not use anymore, it is
redundant. It always retuns an array containing the singleton Workspace
implementation only |
| method public abstract void setWorkspaces (Workspace[]
workspaces); |
Do not use anymore. Does nothing
|
| method public abstract
Workspace getCurrentWorkspace (); |
Do not use anymore, it is
redundant. It always returns the singleton Workspace implementation |
3.2.3 Deprecated API Working with Workspaces in
Mode Interface
In the interface Mode is deprecated following:
Deprecated
API dealing with Workspaces in Mode Interface
|
API
replacing the deprecated one
|
method public
Workspace getWorkspace ()
|
Do not use anymore, it is
redundant. It always returns the singleton Workspace implementation
|
3.2.4 Deprecated API Working with Workspaces in
TopComponent Class
In the class TopComponent are deprecated following:
Deprecated
API dealing with Workspaces in TopComponent class
|
API
replacing the deprecated one
|
field public static final
int CLOSE_EACH
|
Do not use anymore, it is
redundant
|
field public static final
int CLOSE_LAST
|
Do not use anymore, it is
redundant
|
method public void open (Workspace workspace)
|
Use method public void open () in TopComponent class instead
|
method public final boolean isOpened(Workspace workspace)
|
Use method public final boolean isOpened () in TopComponent class
instead
|
method public final boolean close (Workspace workspace)
|
Use method public final boolean close () in TopComponent class instead
|
method public boolean canClose (Workspace workspace, boolean last)
|
Use method public boolean canClose() in TopComponent class
instead
|
3.3 Internal API changes
No change is
required from modules! These changes are relevant only to implementors
of window system!
This is purely internal change unless you are creating its own
window system implementation.
There is added a bunch of protected methods in WindowManager
class which replace the interface Component in WindowManager class.
Those methods better describe the needs of management of TopComponents.
It is also saved not just one class in window system implementation but
all instances of that class created per one TopComponent instance.
Older
API
|
New
API
|
| method public void open () in WindowManager.Component
interface |
method protected void topComponentOpen(TopComponent tc) in
WindowManager class |
| method public void open (Workspace workspace) in
WindowManager.Component interface |
No new API, Workspaces are not
supported, use the above method.
|
| method public void close (Workspace workspace) in
WindowManager.Component interface |
method protected void topComponentClose(TopComponent tc)
in WindowManager class |
| method public void requestFocus () in
WindowManager.Component interface |
method protected void topComponentRequestActive(TopComponent
tc) in WindowManager class |
| method public void requestVisible () in
WindowManager.Component interface |
method protected void topComponentRequestVisible(TopComponent
tc) in WindowManager class |
| method public Node[] getActivatedNodes () in
WindowManager.Component interface |
No new API, the TopComponent
itself manages activated nodes.
|
| method public void setActivatedNodes (Node[] nodes) in
WindowManager.Component interface |
method protected void topComponentActivatedNodesChanged(TopComponent
tc, Node[] activatedNodes) in WindowManager class |
| method public void nameChanged () in
WIndowManager.Component interface |
method protected void topComponentDisplayNameChanged(TopComponent
tc, String displayName) in WindowManager class |
| method public void setIcon (Image icon) in
WindowManager.Component interface |
method protected void topComponentIconChanged(TopComponent
tc, Image icon) in WindowManager class |
| method public Image getIcon () in WindowManager.Component
interface |
No new API, the TopComponent
itself manages icon.
|
| method public Set whereOpened () in
WindowManager.Component interface |
method protected boolean topComponentIsOpened(TopComponent
tc) in WindowManager class |
No API
|
method protected void topComponentDisplayNameAnnotationChanged(TopComponent
tc, String displayNameAnnotation) in WindowManager class |
No API
|
method protected void topComponentToolTipChanged(TopComponent
tc, String toolTip) in WindowManager class |
|
method protected
String topComponentID(TopComponent
tc, String preferredID) in WindowManager class |
|
method protected
Action[] topComponentDefaultActions(TopComponent
tc, String preferredID) in WindowManager class |
3.4 Changes in XML layer declarations
Due to a new layout specified by UI specification, the XML declaration
has overcome the major redesign. There are created new
declarations for the new XML format. The older XML format is also read
and converted to the new one by window system
internally (it is scheduled to to yet), but the position of the
TopComponent in old layout should not fit as desired in the new one.
Highly recommended
changes in modules:
All modules declaring window system components in XML layer
should upgrade those definitions.
3.4.1 Overview of Changes in XML layer
declarations
State of window system must be persistent among sessions. It means that
when IDE is restarted it must restore state of window system when IDE
was exited. XML format is used to serialize state of window system.
Window system has hierarchical structure. On top there is Window
Manager. Window Manager contains global data like bounds of main window.
Below Window Manager there are modes and groups. Mode is container for
UI presentation of TopComponents. Group is logical group of
TopComponents to control simultaneous opening/closing TopComponents. Mode
and group contain reference to TopComponent. Unique TopComponent ID is
used as key. TopComponents itself are stored separately.
3.4.2 Structure of configuration data
XML configuration files are placed in folders. Folders are different
from previous version of window system. Module data and user data are
saved in separate folders. Module folder contains configuration data
defined in modules. Module folder is read only. Local folder contains
customized data. Local folder data are created when window system is
saved. Local folder is read/write.
Module folder structure:
Windows2
|--> WindowManager.wswmgr
|--> Groups
|--> Group_1.wsgrp
|--> Group_1
|--> TC_1.wstcgrp
|--> Modes
|--> Mode_1.wsmode
|--> Mode_1
|--> TC_1.wstcref
|--> TC_2.wstcref
|--> Components
|--> TC_1.settings
|--> TC_2.settings
Local folder structure:
Windows2Local
|--> WindowManager.wswmgr
|--> Groups
|--> Group_1.wsgrp
|--> Group_1
|--> TC_1.wstcgrp
|--> Modes
|--> Mode_1.wsmode
|--> Mode_1
|--> TC_1.wstcref
|--> TC_2.wstcref
|--> Components
|--> TC_1.settings
|--> TC_2.settings
Handling of configuration data in module and local folders:
When IDE is started for the first time all configuration data are present
only in module folder Windows2. When window system configuration is
saved it is saved to local folder Windows2Local. By this way it is
possible to handle changes in module and local folder separately.
Changes in module folder are caused by enabling/disabling modules.
Such changes make possible to update window system configuration when
module is disabled/enabled. (For example if module defines some opened TopComponent
this TopComponent is removed from window system ie. closed in GUI when module
is disabled and this TopComponent is added ie. opened in GUI when module is
enabled. At the same time corresponding configuration data present in local
folder ie. wstcref file are deleted when module is disabled.) Changes in
local folder are ignored.
Any configuration file is first read from local folder. If file is
present in local folder presence of the same file (file with the same
name ie. content can be different because it can be modified) in module
folder is ignored. It becomes little bit more complicated in case of
wstcref files because TopComponent can change its Mode eg. using
Drag&Drop. In such case presence of wstcref file in local folder
hides presence of file with the same name in ANY Mode folder in module
folder. By this way precedence of local folder over module folder is
achieved.
3.4.3 Split desktop
Desktop (main window content pane) can be recursively split. It can be
completely and uniquely described using N-split tree model. Model can be
serialized. We provide a few simple examples here how desktop is mapped
to XML and vice versa. Elements "constraints" and "path" are used to
give exact position of editor area and mode in model and define desktop
layout. Editor area is actually subtree of model in this context. Editor
area can contain one mode (no split inside editor area) or more modes
(editor area is recursively split). Mode inside editor area uses editor
area as root of their path ie. complete path = editor area path + mode
path. Modes inside editor area are of type "editor". Modes outside of
editor area are of type "view". (Attribute "type" of element "kind" in
mode configuration XML.)
Simplest possible desktop is no split ie. one mode on desktop
----------------------
| |
| |
| M1 |
| |
| |
| |
----------------------
"constraints" element of mode M1 will be empty in such case:
<constraints>
</constraints>
Next we can split desktop horizontally (we use JSplitPane convention) to
2 equal cells.
---------------------
| | |
| | |
| M1 | M2 |
| | |
| | |
| | |
---------------------
"constraints" element of mode M1 will be as follows:
<constraints>
<path orientation="horizontal" number="0" weight="0.5" />
</constraints>
Mode M2:
<constraints>
<path orientation="horizontal" number="1" weight="0.5" />
</constraints>
It is possible to add third cell at the same level by adding mode M3
with attribute number="2". If weight="0.5" is used all cells have the
same width. If one cell is hidden remaining cells stay equal ie. size of
visible cells is proportional to their weights.
Last example contains 4 modes, desktop is first split vertically, then
top cell is split horizontally, then right cell is split vertically.
---------------------
| | |
| | M2 |
| M1 | |
| |---------|
| | |
| | M3 |
| | |
---------------------
| |
| M4 |
| |
---------------------
Tree would be as follows (S1, S2, S3 are nodes of tree):
M1
|
S2---|
| | M2
| S3---|
DESKTOP---S1 M3
|
|
M4
Mode M1:
<constraints>
<path orientation="vertical" number="0" weight="0.7" />
<path orientation="horizontal" number="0" weight="0.5" />
</constraints>
Mode M2:
<constraints>
<path orientation="vertical" number="0" weight="0.7" />
<path orientation="horizontal" number="1" weight="0.5" />
<path orientation="vertical" number="0" weight="0.5" />
</constraints>
Mode M3:
<constraints>
<path orientation="vertical" number="0" weight="0.7" />
<path orientation="horizontal" number="1" weight="0.5" />
<path orientation="vertical" number="1" weight="0.5" />
</constraints>
Mode M4:
<constraints>
<path orientation="vertical" number="1" weight="0.3" />
</constraints>
3.4.4 Difference between new and old version of
window system persistence
- Because of new desktop layout is different from old desktop
layout configuration data are completely separated. Different folders
are used to save winsys configuration data. Major version of XML
configuration data is increased to 2.0. Format of XML configuration data
is changed. Only format of TopComponent settings files stays unchanged.
To keep backward compatibility with old XML configuration data import
(ability to read and convert old layout) from install layer ie. data
defined by modules not customized user data is supported.
- Window system is not part of project. It means that configuration
data are stored in session layer not in project layer. Window system is
not changed when projects are switched.
- Window system persistence is not based on datasystems any more
(with exception of TopComponents, their persistence is still handled by
InstanceDataObject). Main reason of this and previous change is to
improve stability and robustness of window system persistence.
3.4.5 Simple examples
Window Manager
Name of window manager configuration file is WindowManager.wswmgr.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE windowmanager PUBLIC
"-//NetBeans//DTD Window Manager Properties 2.0//EN"
"http://www.netbeans.org/dtds/windowmanager-properties2_0.dtd">
<windowmanager version="2.0">
<main-window>
<joined-properties x="0" y="0" width="1200" height="900"
centered-horizontally="true" centered-vertically="true" />
</main-window>
<editor-area state="joined">
<constraints>
<path orientation="vertical" number="0" weight="0.7" />
<path orientation="horizontal" number="1" weight="0.55" />
</constraints>
</editor-area>
<active-mode name="explorer" />
<toolbar configuration="Standard" />
</windowmanager>
Example of WindowManager.wswmgr file is given above. As desktop can be
in two different states joined or separated properties of both states
can be present. (Joined state means one main window and everything is
inside main window. Separated state means that main window and all modes
have their own native frame.) These state are independent. Current state
of desktop is given by state of editor area (element "editor-area"
attribute "state"). As properties of both states can be saved in the
same file some properties are relevant for separated state only, some
for joined state only and some does not depend on desktop state.
"joined-properties" of "main-window" in example sets initial size and
position of main window used in layer. As winsys is saved only absolute
bounds are stored. Attributes like "centered-horizontally" are suitable
to set initial size and position of main window after first start
independently on actual screen resolution. As state of editor area is
"joined" it means that example contains only properties of joined
desktop state. Element "constraints" describes where is editor area
located in N-split tree which describes whole desktop. Desktop area can
be split vertically or horizontally. Resulting area can be split again. So
it is recursive splitting. Position (size of area) and orientation of
splitter can be described completely and uniquely by N-split tree. In
example first split is "vertical" (areas from top and bottom) and editor
area is placed at first (top) cell. Second split is "horizontal" (areas
from left to right) and editor area is in second cell (right cell when
there are 2 cells, middle cell when there are 3 cells). Detail
description of all elements/attributes is in DTD.
Mode
Mode configuration file name consists of unique mode name and suffix
wsmode. Folder with the same name contains wstcref files - configuration
files of TopComponent's references in Mode.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mode PUBLIC
"-//NetBeans//DTD Mode Properties 2.0//EN"
"http://www.netbeans.org/dtds/mode-properties2_0.dtd">
<mode version="2.0">
<module name="org.netbeans.core.ui/1" spec="1.2" />
<name unique="explorer" />
<kind type="view" />
<state type="joined" />
<constraints>
<path orientation="vertical" number="0" weight="0.7" />
<path orientation="horizontal" number="0" weight="0.25" />
</constraints>
<active-tc id="filesystems" />
<empty-behavior permanent="true" />
</mode>
As example of mode configuration we use "explorer" mode. It resides on
top left cell of split desktop as it is obvious from its constraints.
Current state of mode is "joined". As in Window Manager example both
properties for split or joined state can be present. Current state
controls what properties are effective. All configuration files below
window manager ie. wsmode, wsgrp, wstcref, wstcgrp can contain module
info. It allows window system to handle correctly enabling/disabling of
modules. When module is disabled window system element defined in module
layer ie. provided by module are removed when they contain module info.
Detail description of all elements/attributes is in DTD.
TopComponent in Mode Reference
TopComponent in Mode Reference configuration file name consists of
unique TopComponent ID and suffix wstcref. File is located in
corresponding mode folder. TopComponent instances are serialized
separately in folder Components as settings files.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tc-ref PUBLIC
"-//NetBeans//DTD Top Component in Mode Properties 2.0//EN"
"http://www.netbeans.org/dtds/tc-ref2_0.dtd">
<tc-ref version="2.0">
<module name="org.netbeans.core.ui/1" spec="1.2" />
<tc-id id="filesystems" />
<state opened="true" />
</tc-ref>
Configuration file contains just unique TopComponent ID and state of
TopComponent in Mode. TopComponent state can be "opened" or "closed".
Detail description of all elements/attributes is in DTD.
Group
Group configuration file name consists of unique group name and suffix
wsgrp. Folder with the same name contains references to TopComponents in
group.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE group PUBLIC
"-//NetBeans//DTD Group Properties 2.0//EN"
"http://www.netbeans.org/dtds/group-properties2_0.dtd">
<group version="2.0">
<module name="org.netbeans.modules.form/2" spec="1.7" />
<name unique="form" />
<state opened="false" />
</group>
Group configuration contains only unique group name and state of group.
Group state can be opened or closed. State is stored as boolean flag.
Detail description of all elements/attributes is in DTD.
TopComponent in Group Reference
TopComponent in Group Reference configuration file name consists of
unique TopComponent ID and suffix wstcgrp. File is located in
corresponding group folder. TopComponent instances are serialized
separately in folder Components as settings files.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE tc-group PUBLIC
"-//NetBeans//DTD Top Component in Group Properties 2.0//EN"
"http://www.netbeans.org/dtds/tc-group2_0.dtd">
<tc-group version="2.0">
<module name="org.netbeans.modules.form/2" spec="1.7" />
<tc-id id="ComponentInspector" />
<open-close-behavior open="true" close="true" />
</tc-group>
Configuration file contains unique TopComponent ID and flags to
describe if component should be opened when group is being opened and if
component should be closed when group is being closed. Detail
description of all elements/attributes is in DTD.
TopComponent
TopComponent is serialized by InstanceDataObject as settings file.
Settings file has 2 forms. First uses default constructor or method
(method is used by singletons) to create instance of TopComponent. This
form is preferred for definition of TopComponent in module layer. Second
uses serialized data as text in settings file. When window system is
saved TopComponents are serialized using second form.
First form:
<?xml version="1.0"?>
<!DOCTYPE settings PUBLIC "-//NetBeans//DTD Session settings 1.0//EN"
"http://www.netbeans.org/dtds/sessionsettings-1_0.dtd">
<settings version="1.0">
<module name="org.netbeans.modules.form/2" spec="1.7"/>
<instanceof class="org.netbeans.modules.form.ComponentInspector"/>
<instanceof class="java.awt.MenuContainer"/>
<instanceof class="java.lang.Object"/>
<instanceof class="java.awt.image.ImageObserver"/>
<instanceof class="org.openide.windows.TopComponent"/>
<instanceof class="java.awt.Container"/>
<instanceof class="org.openide.explorer.ExplorerManager$Provider"/>
<instanceof class="org.openide.explorer.ExplorerPanel"/>
<instanceof class="java.io.Serializable"/>
<instanceof class="javax.swing.JComponent"/>
<instanceof class="java.awt.Component"/>
<instanceof class="java.io.Externalizable"/>
<instance class="org.netbeans.modules.form.ComponentInspector"
method="getInstance"/>
</settings>
Second form:
<?xml version="1.0"?>
<!DOCTYPE settings PUBLIC "-//NetBeans//DTD Session settings 1.0//EN"
"http://www.netbeans.org/dtds/sessionsettings-1_0.dtd">
<settings version="1.0">
<module name="org.netbeans.modules.form/2" spec="1.7"/>
<instanceof class="org.netbeans.modules.form.ComponentInspector"/>
<instanceof class="java.awt.MenuContainer"/>
<instanceof class="java.lang.Object"/>
<instanceof class="java.awt.image.ImageObserver"/>
<instanceof class="org.openide.windows.TopComponent"/>
<instanceof class="java.awt.Container"/>
<instanceof class="org.openide.explorer.ExplorerManager$Provider"/>
<instanceof class="org.openide.explorer.ExplorerPanel"/>
<instanceof class="java.io.Serializable"/>
<instanceof class="javax.swing.JComponent"/>
<instanceof class="java.awt.Component"/>
<instanceof class="java.io.Externalizable"/>
<serialdata class="org.netbeans.modules.form.ComponentInspector">
ACED00057372003D6F72672E6E65746265616E732E6D6F64756C65732E666F72
6D2E436F6D706F6E656E74496E7370656374
6F72245265736F6C7661626C6548656C7065726709A43777F1AF080200007870
</serialdata>
</settings>
3.4.6 Import of old configuration data
Structure of configuration data folders:
Windows
|--> WindowManager.wswmgr
|--> WindowManager
|--> Workspace_1.wswksp
|--> Workspace_1
|--> Mode_1.wsmode
|--> Mode_1
|--> TC_1.wstcref
|--> TC_2.wstcref
|--> Components
|--> TC_1.settings
|--> TC_2.settings
When old configuration data (workspace, mode and/or top component
reference) is detected at install layer (module jars) these are imported
to new desktop layout by following way:
- From the old user dir read workspaces one by one (start with the
Editing workspace). If you find a mode which is not defined in the new
layout, do the following transformation:
- a) If the unknown mode is internal and defines top components
(not already known in the new layout) in:
- the top area of the mode then create a special mode named
"top_mode" (if not already created) in the new layout and put all
unknown top components from the old mode there. Dock the "top_mode" to
the top of the document area
- the left area of the mode then put all unknown top components
into the Explorer mode
- the bottom area of the mode then put all unknown top
components into the Output mode
- the right area of the mode then put all unknown top
components into the Properties mode
- the center area of the mode then put all unknown top
components into the Explorer
- b) If the unknown mode is attached to:
- the top then dock the mode to the top of the document area
and move the unknown top components also (doesn't matter in which area
of mode the TCs were)
- the left then dock the mode to the left of the document
area and move the unknown top components also (doesn't matter in which
area of mode the TCs were)
- the bottom then dock the mode to the bottom of the document
area and move the unknown top components also (doesn't matter in which
area of mode the TCs were)
- the right then dock the mode to the right of the document
area and move the unknown top components also (doesn't matter in which
area of mode the TCs were)
- c) If the unknown mode is a separate window then use the same
rules as for the internal mode.
- d) If a mode is already present in the new layout, we should
still look for unknown TCs inside it.
- If a module with old winsys config gets installed, then follow
the same rules as for the old user dir.
4 Use Cases
This part compares old and new use cases, this way shows how the new
API should be used comparing to the old one
| Use
Case Description |
Old
Use Case |
New
Use Case |
Explanation |
Adding TopComponent into window
system layout, opening and activating it.
|
mode.dockInto(tc);
tc.open();
tc.requestFocus(); // NOW IMPROPER USAGE for activation |
mode.dockInto(tc);
tc.open();
tc.requestActive(); // NOW PROPER USAGE for activation
|
The method requestFocus was
wrongly overridden for the purpose of activation. Such API is misleading
and wrong. The new activate method is starting to repair that state
|
| Setting localized display name
of TopComponent. E.g. MyClass for java source editor window or
Properties for the helper window. |
tc.setName (localizedDisplayName);
|
tc.setDisplayName (localizedDisplayName)
|
The method setName was misued
for localized display name, which is wrong, name should be just
programmatic name of component, not localized one. Therefore is
introduced new setDisplayName method.
|
Getting display name of
TopComponent.
|
String displayName = tc.getName();
|
String displayName = tc.getDisplayName();
if(displayName == null) {
displayName = tc.getName();
}
|
Correspondent to the above case.
Note the fallback to the getName() method.
|
Retrieving selected TopComponent
in mode.
|
No API
|
TopComponent selected = mode.getSelectedTopComponent();
|
|
Finding and opening
TopComponentGroup
|
No API
|
group = wm.findTopComponentGroup("myGroup");
if(group != null) {
group.open();
}
|
The TopComponent group named
"myGroup": has to be defined in XML
layer in order the code will return non-null instance. |
Finding and closing of
TopComponentGroup
|
No API
|
group = wm.findTopComponentGroup("myGroup");
if(group
!= null)
{
group.close();
}
|
The TopComponent group named
"myGroup": has to be defined in XML
layer in order the code will return non-null instance. |
| Creating
floating mode, docking and opening TopComponent in it |
mode = wm.getCurrentWorkspace().createMode("myMode", null, null);
mode.dockInto(tc);
mode.open(); |
Floating modes are not supported
now. This case will in new window system open the TopComponent in
default editor mode.
Note: This is true for the
default "Compact" mode of window system(former MDI), but in "Separate"
mode (former SDI) the case should work as before.
|
In default "Compact" mode, the
deprecated method createMode returns always the same instance of default
editor mode (the one in documents area).
|
Creating mode
|
Used either former case for
floating mode or there was possible to declare internal or docked modes
in XML layer
|
It is not possible to create
modes programmatically (unless you are in the "Separate" mode of
window system). You have to declare the modes in XML
layer.
|
In default "Compact" mode is not
possible to create new mode. It was fine when the floating modes were
supported, but in case of generic split layout creating too much of new
modes would make the split structure clumsy, therefore was taken this
solution according to existing API.
Note: It is not true for
"Selected" mode.
|
Finding mode and docking
TopComponent into it, opening it and activating it.
|
mode = wm.getCurrentWorkspace().findMode("myMode");
if(mode
== null)
{
mode = wm.getCurrentWorkspace().createMode("myMode", null, null);
}
mode.dockInto(tc);
tc.open();
tc.requestFocus();
|
mode =wm.findMode("myMode");
if(mode
!= null)
{
mode.dockInto(tc);
}
tc.open();
tc.requestActive();
|
Note: Mode named "myMode"
is supposed to be defined in XML layer.
Both codes result to the same action in new window system (In "Compact"
mode). It is due to the fact, that createMode method returns the default
editor mode, and also that when opening undocked TopComponent it is
docked into that default editor mode.
|
Explanations used in use cases:
tc ... instance of org.openide.windows.TopComponent,
mode ... instance of org.openide.windows.Mode,
group...instance of org.openide.windows.TopComponentGroup
wm.... instance of org.openide.windows.WindowManager.
|
|
5 Summary
The new window system is implementation of window system specified by
UI spec document.
Issue:
http://www.netbeans.org/issues/show_bug.cgi?id=29836
Please put questions or comments directly into that issue
or at [nbdev] netbeans developers
mailing list.