Standard Actions Specification
Author: Nathan FiedlerThe standard actions consist of delete, cut, copy, paste, and drag-n-drop. This specification seeks to describe how these features will perform on the columns view of the schema editor.
Phased Implementation
Because of the depth of features possible with copy/paste and drag/drop, the design and implementation will be taken in a phased approach. The most basic features will be implemented first, while the complex features, such as refactoring, will come at a later date.
Phase 1
In Phase 1 of the standard actions implementation, the copy and paste, as well as drag and drop, will operate in much the same way as the similar features in NetBeans. That is, copying and pasting components will not involve any adjustments to references or alterations to the data in any way. It is up to the user to ensure that the schema is still valid before it is employed.
Supported Features
- Copy and paste will simply make a copy of the component in the new location (no refactoring, no references)
- Pasting components with a namespace may elide the namespace if it is not needed
- Drag and drop, like copy and paste, will be implemented in a similar fashion, with the same limitations
- Modifying a component's visibility, such that a global component can become a local component, and vice versa
Phase 2
Phase 2 of the implementation will add refactoring capabilities to take care of some of the more mundane work on behalf of the user.
Supported Features
- Pasting a component where it cannot immediately be added will result in finding the first matching child component that can accept the paste.
- Pasting a component as a reference will be possible for those types of components that can have references
- Pasting a component as a reference from another schema will create an import and the reference to the source component
- Safely moving a component via refactoring
Delete
The delete feature was implemented earlier in the development
cycle and has been functional for some time. At first it was labelled
as "Remove" and would only allow deletion of components
that were not used elsewhere. In May 2006, the
RemoveAction
was renamed to
SafelyDeleteAction
and the standard NetBeans
DeleteAction
was added to the schema component nodes.
This allows the user to forcefully delete nearly anything, without
regards to references to that component. On the other hand, if the
user wants to remove a component only after ensuring it is not used
elsewhere, they can select the "Safe Delete" action.
Cut, Copy, and Paste
The cut operation will need to be handled in the same fashion as delete, since the user could cut a component from the document and not paste it back again. This is effectively the same as a delete, and since we cannot know what the user will do, it should be handled defensively. Components that are not being used elsewhere in the same document, can be cut, just as they can be deleted.
The copy operation, on the other hand, is unrestricted in that any component can be copied and pasted, regardless of whether it is being used elsewhere.
Is the following necessary? If the name of the original component is identical to that of another component in the destination container, it must be changed to one that is unique. This is similar to the behavior of copy/paste within Java projects, in which a source file is renamed to avoid collision with existing files.
Drag and Drop
Drag and drop can be treated differently from cut and paste, since we know for certain the affected components will not be discarded. That is, dragging and dropping a component is a single operation, rather than two distinct events as in cut/paste — no components can be lost.
Where drag/drop is particularly useful is in changing the order of elements in a sequence. Whereas paste can only be applied on the parent component, the drop can be performed between components. That is, if an element is copied to the clipboard, then pasted, it must be pasted onto a component that can contain it (e.g. a sequence). The drag and drop interface allows the user to insert a component between other components, thus allowing the order of elements in a sequence to be changed, for example.
The condition of maintaining unique component names within a container, mentioned in the copy and paste section above, holds for drag and drop. That is, dropping a component into a container that contains a component with the same name as that which is being dropped will result in the dropped component being renamed to avoid collision.
Global to Local
The table below describes what kinds of components can go where when moving from a global context to a local one.
Component Kind | Destination Kind | Result |
---|---|---|
Attribute | Attribute Group | Move, unless referenced. |
Attribute | Complex Type | Move, unless referenced. |
Attribute Group | Attribute Group | A reference is created. |
Attribute Group | Complex Type | A reference is created. |
Attribute Group | Redefine | Move, unless referenced. |
Complex Type | Element | Move, unless referenced. |
Complex Type | Redefine | Move, unless referenced. |
Simple Type | Attribute | Move, unless referenced. |
Simple Type | Element | Move, unless referenced. |
Simple Type | List | Move, unless referenced. |
Simple Type | Redefine | Move, unless referenced. |
Simple Type | Restriction | Move, unless referenced. |
Simple Type | Union | Move, unless referenced. |
Local to Global
The table below describes what kinds of components can be moved from a local context to the global (child of schema root component).
Component Kind | Parent Kind | Exceptions |
---|---|---|
Attribute | Attribute Group | |
Attribute | Complex Type | |
Attribute Group | Attribute Group | Invalid case |
Attribute Group | Complex Type | Invalid case |
Attribute Group | Redefine | |
Complex Type | Element | |
Complex Type | Redefine | |
Simple Type | Attribute | |
Simple Type | Element | |
Simple Type | List | |
Simple Type | Redefine | |
Simple Type | Restriction | |
Simple Type | Union |
Unless noted otherwise, the components can be moved from a local context to the root schema component. If the component does not have a name, it will be given one (e.g. "attribute0").
Implementation Details
Determining Ability to Paste
To determine if it is possible to paste a particular type of
component into another component, the SchemaComponent
class provides a method called canPaste()
that takes a
SchemaComponent
parameter and returns true
indicating that the component can contain that child. In the case of
CategoryNode
this is trivial since the
childType
field gives us the type of components being
shown in that category.
Visibility Changes
When a component is being copied to a destination context that is different from its origin (global vs. local), it will be necessary to create a new component of the appropriate type, then copy the attributes from the original component to its clone. The model handles this already.
Copying Components
The Component
class provides a copy()
method that creates a deep clone of a component for a new parent.
This is used for the copy operation.
Format (i.e. DataFlavor)
By default, the AbstractNode
implementation copies
itself to the clipboard and handles the paste via a
PasteType
implementation. Since this is the most
straightforward means of supporting copy and paste, as well as drag
and drop, this will be the format used for the clipboard
transferables.
Aside from overriding createPasteTypes()
in our
Node
subclasses, there is a
ComponentPasteType
utility class that does the work of
creating the PasteType
implementations for our
nodes.
Operations
The Category
node class will need to override
canCopy()
to return false, as it makes little sense to
copy an entire category to the clipboard. Likewise, need to override
createPasteTypes()
to ensure that only nodes of the same
type as what the category contains are permitted to be pasted.
The SchemaComponentNode
class will override
canCopy()
and canCut()
to return
true
, since basically any node can be copied and cut. It
also overrides the method createPasteTypes()
to ensure
that only nodes representing components that can be contained in the
node's component are able to be pasted to the node.
To allow pasting a component to a logical parent, which may
not be the structural parent, the PasteType
will employ
FindContainerVisitor
to find the first reasonable parent
component for the paste.
Drag and Drop
NetBeans drag and drop support is a little strange. Most of the
drag-n-drop specific code is suppressed and it is all handled via
copy/paste and the org.openide.nodes.Index
cookie. For
instance, the index parameter is always -1 when
Node.getDropType()
is called, so ordering the nodes by
that method is useless (this problem is caused by the
DragDropUtilities
class). Likewise, there is no use in
overriding drag()
since it is apparently not called
(again, DragDropUtilities
is the culprit, in that it
invokes clipboardCut()
for drag-move).
To allow reordering the nodes, you must implement the
org.openide.nodes.Index
cookie. This is most easily done
by implementing it on a subclass of
org.openide.nodes.Children
, which provides an
implementation of a couple of the Index
methods
already.