KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xml > xam > ui > ComponentPasteType


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.xml.xam.ui;
21
22 import java.awt.datatransfer.Transferable JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.util.Arrays JavaDoc;
25 import java.util.HashSet JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Set JavaDoc;
28 import org.netbeans.modules.xml.xam.Component;
29 import org.netbeans.modules.xml.xam.Model;
30 import org.netbeans.modules.xml.xam.Nameable;
31 import org.netbeans.modules.xml.xam.Named;
32 import org.netbeans.modules.xml.xam.ui.cookies.GetComponentCookie;
33 import org.openide.nodes.Node;
34 import org.openide.nodes.NodeTransfer;
35 import org.openide.util.datatransfer.PasteType;
36
37 /**
38  * Paste type for XAM-based components. Expects Nodes in the Transferable
39  * and determines what is allowed to be pasted where, delegating most
40  * of the work to the model.
41  *
42  * @author Nathan Fiedler
43  */

44 public class ComponentPasteType {
45     /** NodeTransfer operations we use by default. */
46     private static final int[] STANDARD_OPERATIONS = new int[] {
47         NodeTransfer.COPY,
48         NodeTransfer.MOVE
49     };
50
51     /**
52      * Create PasteType to receive the transferable into the given component.
53      *
54      * @param target the target component.
55      * @param transfer the component(s) being pasted.
56      * @param type type of the component to allow (e.g. Element.class),
57      * or null to allow all types.
58      * @return the new paste type.
59      */

60     public static PasteType getPasteType(Component target,
61             Transferable JavaDoc transfer, Class JavaDoc<? extends Component> type) {
62         return getPasteType(target, transfer, type, STANDARD_OPERATIONS, -1);
63     }
64
65     /**
66      * Create PasteType to receive the transferable into the given component.
67      *
68      * @param target the target component.
69      * @param transfer the component(s) being pasted.
70      * @param type type of the component to allow (e.g. Element.class),
71      * or null to allow all types.
72      * @param action the NodeTransfer constant for cut/copy.
73      * @param index index at which to paste the component (-1 to append).
74      * @return the new paste type.
75      */

76     public static PasteType getDropType(Component target,
77             Transferable JavaDoc transfer, Class JavaDoc<? extends Component> type,
78             int action, int index) {
79 // The action value passed to AbstractNode.getDropType() is wrong so we
80
// must ignore it and use our standard values.
81
// int[] operations = new int[] { action };
82
return getPasteType(target, transfer, type, STANDARD_OPERATIONS, index);
83     }
84
85     /**
86      * Create PasteType to receive the transferable into the given component.
87      *
88      * @param target the target component.
89      * @param transfer the component(s) being pasted.
90      * @param type type of the component to allow (e.g. Element.class),
91      * or null to allow all types.
92      * @param operations set of NodeTransfer constants for cut/copy.
93      * @param index index at which to paste the component (-1 to append).
94      * @return the new paste type.
95      */

96     private static PasteType getPasteType(Component target,
97             Transferable JavaDoc transfer, Class JavaDoc<? extends Component> type,
98             int[] operations, int index) {
99         PasteType retVal = null;
100         // Check each operation until a supported one is found.
101
for (int oper : operations) {
102             // Attempt to retrieve the nodes from transferable.
103
Node[] nodes = NodeTransfer.nodes(transfer, oper);
104             if (nodes != null) {
105                 // Can any of these be pasted into the target?
106
if (canPaste(nodes, target, oper, type)) {
107                     retVal = new PasteTypeImpl(Arrays.asList(nodes), target,
108                             oper, index);
109                     break;
110                 }
111             }
112         }
113         return retVal;
114     }
115
116     /**
117      * Determine if all of the given nodes can be pasted into the component.
118      *
119      * @param nodes the nodes being pasted.
120      * @param target the target component.
121      * @param operation the NodeTransfer constant for cut/copy.
122      * @param type type of the component to allow (e.g. Element.class),
123      * or null to allow all types.
124      * @return true if the nodes can be pasted.
125      */

126     private static boolean canPaste(Node[] nodes, Component target,
127             int operation, Class JavaDoc<? extends Component> type) {
128         Set JavaDoc<Node> pasteableNodes = new HashSet JavaDoc<Node>();
129         for (Node pasteableNode : nodes) {
130             // The node must provide a Component, otherwise we cannot use it.
131
GetComponentCookie gcc = (GetComponentCookie) pasteableNode.
132                     getLookup().lookup(GetComponentCookie.class);
133             if (gcc != null) {
134                 Component pasteableComponent = gcc.getComponent();
135                 // Check that the target can receive this component.
136
// Ensure that the model is still valid, in case the
137
// component was deleted or moved elsewhere.
138
if ((type == null ||
139                         type.isAssignableFrom(gcc.getComponentType())) &&
140                         pasteableComponent.getModel() != null &&
141                         target.canPaste(pasteableComponent)) {
142                     boolean isCopyPaste = (operation & NodeTransfer.COPY) != 0;
143                     // Prevent cutting and pasting into the same component.
144
boolean isCutPaste = (operation & NodeTransfer.MOVE) != 0 &&
145                             !(pasteableComponent.getParent().equals(target)) &&
146                             pasteableNode.canDestroy();
147                     if (isCopyPaste || isCutPaste) {
148                         if (isCutPaste) {
149                             // Prevent cutting/pasting into a child component.
150
Component parent = target;
151                             while (parent != null) {
152                                 if (parent.equals(pasteableComponent)) {
153                                     return false;
154                                 }
155                                 parent = parent.getParent();
156                             }
157                         }
158                         // We could check for duplicates here, but at this
159
// time we are allowing them.
160
pasteableNodes.add(pasteableNode);
161                     }
162                 }
163             }
164         }
165         return pasteableNodes.size() == nodes.length;
166     }
167
168     /**
169      * Our PasteType implementation for component nodes.
170      */

171     private static class PasteTypeImpl extends PasteType {
172         /** The component to receive the paste. */
173         private Component target;
174         /** The nodes being pasted. */
175         private List JavaDoc<Node> nodes;
176         /** NodeTransfer constant (e.g. COPY, MOVE). */
177         private int operation;
178         /** Position at which to insert item (-1 to append). */
179         private int index;
180
181         /**
182          * Creates a new instance of PasteTypeImpl.
183          *
184          * @param nodes those which are to be pasted.
185          * @param target the paste recipient.
186          * @param operation NodeTransfer constant indicating cut/copy.
187          * @param index position to paste, or -1 to append.
188          */

189         private PasteTypeImpl(List JavaDoc<Node> nodes,
190                 Component target, int operation, int index) {
191             this.target = target;
192             this.nodes = nodes;
193             this.operation = operation;
194             if (index < 0) {
195                 // Instead of appending at the end, let's prepend at the
196
// beginning, to avoid the subsequent re-ordering that the
197
// NetBeans code performs if we were to append.
198
this.index = 0;
199             } else {
200                 this.index = index;
201             }
202         }
203
204         @SuppressWarnings JavaDoc("unchecked")
205         public Transferable JavaDoc paste() throws IOException JavaDoc {
206             // Perform the cut or copy to the target component.
207
if (target != null && nodes.size() > 0) {
208                 Model model = target.getModel();
209                 GetComponentCookie gcc = (GetComponentCookie) nodes.get(0).
210                         getCookie(GetComponentCookie.class);
211                 if (gcc == null) {
212                     // We can go nowhere without a valid node.
213
return null;
214                 }
215                 Model srcModel = gcc.getComponent().getModel();
216                 // Keep everything in a single transaction so the undo/redo
217
// acts on the entire set rather than individual nodes.
218
// This makes the assumption that the source nodes are all
219
// coming from a single model, which should always be true.
220
model.startTransaction();
221                 try {
222                     for (Node node : nodes) {
223                         gcc = (GetComponentCookie) node.getCookie(
224                                 GetComponentCookie.class);
225                         Component child = gcc.getComponent();
226                         // Always make a clone of the component, even for the cut
227
// operation, since it converts global to local and vice
228
// versa, and we want to be consistent with the copy
229
// operation in that respect.
230
Component copy = child.copy(target);
231                         // 'copy' will be null if the copy was unsuccessful.
232
// Better to fail silently than throw assertion errors,
233
// so make sure the child is non-null before proceeding.
234
if (copy != null) {
235                             if ((operation & NodeTransfer.MOVE) != 0) {
236                                 // For cut, remove the component from its model.
237
// This should allow it to be collected.
238
boolean srcInTransaction = srcModel.isIntransaction();
239                                 try {
240                                     if (!srcInTransaction) {
241                                         // Must be separate models, in which
242
// case create a new transaction.
243
srcModel.startTransaction();
244                                     }
245                                     srcModel.removeChildComponent(child);
246                                 } finally {
247                                     if (!srcInTransaction) {
248                                         srcModel.endTransaction();
249                                     }
250                                 }
251                             }
252                             // Ensure the name of the copy is unique within
253
// the target component, if it is nameable.
254
if (copy instanceof Nameable) {
255                                 String JavaDoc name = ((Nameable) copy).getName();
256                                 String JavaDoc preferredName = name;
257                                 HashSet JavaDoc<String JavaDoc> nameSet = new HashSet JavaDoc<String JavaDoc>();
258                                 for (Object JavaDoc sibling : target.getChildren()) {
259                                     if (sibling instanceof Named) {
260                                         nameSet.add(((Named) sibling).getName());
261                                     }
262                                 }
263                                 int unique = 1;
264                                 while (nameSet.contains(name)) {
265                                     name = preferredName + unique;
266                                     unique++;
267                                 }
268                                 ((Nameable) copy).setName(name);
269                             }
270                             // Add child to target model under component.
271
model.addChildComponent(target, copy, index);
272                         }
273                     }
274                 } finally {
275                     model.endTransaction();
276                 }
277             }
278             return null;
279         }
280
281         public String JavaDoc toString() {
282             return "PasteTypeImpl=[operation=" + operation + ",index=" + index + "]";
283         }
284     }
285 }
286
Popular Tags