KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > emf > edit > command > AddCommand


1 /**
2  * <copyright>
3  *
4  * Copyright (c) 2002-2004 IBM Corporation and others.
5  * All rights reserved. This program and the accompanying materials
6  * are made available under the terms of the Eclipse Public License v1.0
7  * which accompanies this distribution, and is available at
8  * http://www.eclipse.org/legal/epl-v10.html
9  *
10  * Contributors:
11  * IBM - Initial API and implementation
12  *
13  * </copyright>
14  *
15  * $Id: AddCommand.java,v 1.7 2005/06/08 06:17:05 nickb Exp $
16  */

17 package org.eclipse.emf.edit.command;
18
19
20 import java.util.Collection JavaDoc;
21 import java.util.Collections JavaDoc;
22 import java.util.HashSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Set JavaDoc;
25
26 import org.eclipse.emf.common.command.Command;
27 import org.eclipse.emf.common.util.EList;
28 import org.eclipse.emf.ecore.EClass;
29 import org.eclipse.emf.ecore.EObject;
30 import org.eclipse.emf.ecore.EReference;
31 import org.eclipse.emf.ecore.EStructuralFeature;
32 import org.eclipse.emf.ecore.util.ExtendedMetaData;
33 import org.eclipse.emf.ecore.util.FeatureMap;
34 import org.eclipse.emf.ecore.util.FeatureMapUtil;
35 import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
36 import org.eclipse.emf.edit.EMFEditPlugin;
37 import org.eclipse.emf.edit.domain.EditingDomain;
38
39
40 /**
41  * The add command logically acts upon an owner object that has a collection-based feature to which other objects can be added.
42  * The static create methods delegate command creation to {@link EditingDomain#createCommand EditingDomain.createCommand},
43  * which may or may not result in the actual creation of an instance of this class.
44  *
45  * <p>
46  * The implementation of this class is low-level and EMF specific;
47  * it allows one or more objects to be added to a many-valued feature of an owner,
48  * i.e., it is equivalent of the call
49  * <pre>
50  * ((EList)((EObject)owner).eGet((EStructuralFeature)feature)).addAll(index, (Collection)collection);
51  * </pre>
52  *
53  * <p>
54  * It can also be used as an equivalent to the call
55  * <pre>
56  * ((EList)extent).addAll(index, (Collection)collection);
57  * </pre>
58  * which is how root objects are added into the contents of a resource.
59  * Like all the low-level comands in this package, the add command is undoable.
60  *
61  * <p>
62  * An add command is an {@link OverrideableCommand}.
63  */

64 public class AddCommand extends AbstractOverrideableCommand
65 {
66   /**
67    * This creates a command to add a particular value to the specified feature of the owner.
68    * The feature will often be null because the domain will deduce it.
69    */

70   public static Command create(EditingDomain domain, Object JavaDoc owner, Object JavaDoc feature, Object JavaDoc value)
71   {
72     return create(domain, owner, feature, Collections.singleton(value), CommandParameter.NO_INDEX);
73   }
74
75   /**
76    * This creates a command to insert particular value at a particular index in the specified feature of the owner.
77    * The feature will often be null because the domain will deduce it.
78    */

79   public static Command create(EditingDomain domain, Object JavaDoc owner, Object JavaDoc feature, Object JavaDoc value, int index)
80   {
81     return create(domain, owner, feature, Collections.singleton(value), index);
82   }
83
84   /**
85    * This creates a command to add a collection of values to the specified feature of the owner.
86    * The feature will often be null because the domain will deduce it.
87    */

88   public static Command create(EditingDomain domain, Object JavaDoc owner, Object JavaDoc feature, Collection JavaDoc collection)
89   {
90     return domain.createCommand(AddCommand.class, new CommandParameter(owner, feature, collection, CommandParameter.NO_INDEX));
91   }
92
93   /**
94    * This creates a command to insert a collection of values at a particular index in the specified feature of the owner.
95    * The feature will often be null because the domain will deduce it.
96    */

97   public static Command create(EditingDomain domain, Object JavaDoc owner, Object JavaDoc feature, Collection JavaDoc collection, int index)
98   {
99     return domain.createCommand(AddCommand.class, new CommandParameter(owner, feature, collection, index));
100   }
101
102   /**
103    * This caches the label.
104    */

105   protected static final String JavaDoc LABEL = EMFEditPlugin.INSTANCE.getString("_UI_AddCommand_label");
106
107   /**
108    * This cachaes the description.
109    */

110   protected static final String JavaDoc DESCRIPTION = EMFEditPlugin.INSTANCE.getString("_UI_AddCommand_description");
111
112   /**
113    * This cachaes the description for a list-based addition.
114    */

115   protected static final String JavaDoc DESCRIPTION_FOR_LIST = EMFEditPlugin.INSTANCE.getString("_UI_AddCommand_description_for_list");
116     
117   /**
118    * This is the owner object upon which the command will act.
119    * It could be null in the case that we are dealing with an {@link org.eclipse.emf.common.util.EList}.
120    */

121   protected EObject owner;
122
123   /**
124    * This is the feature of the owner object upon the command will act.
125    * It could be null, in the case that we are dealing with an {@link org.eclipse.emf.common.util.EList}.
126    */

127   protected EStructuralFeature feature;
128
129   /**
130    * This is the list to which the command will add the collection.
131    */

132   protected EList ownerList;
133
134   /**
135    * This is the collection of objects being added to the owner list.
136    */

137   protected Collection JavaDoc collection;
138
139   /**
140    * This is the position at which the objects will be inserted.
141    */

142   protected int index;
143
144   /**
145    * This is the value returned by {@link Command#getAffectedObjects}.
146    * The affected objects are different after an execute than after an undo, so we record it.
147    */

148   protected Collection JavaDoc affectedObjects;
149
150   /**
151    * This constructs a primitive command to add a particular value to the specified many-valued feature of the owner.
152    */

153   public AddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object JavaDoc value)
154   {
155     this(domain, owner, feature, Collections.singleton(value), CommandParameter.NO_INDEX);
156   }
157
158   /**
159    * This constructs a primitive command to insert particular value into the specified many-valued feature of the owner.
160    */

161   public AddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object JavaDoc value, int index)
162   {
163     this(domain, owner, feature, Collections.singleton(value), index);
164   }
165
166   /**
167    * This constructs a primitive command to add a collection of values to the specified many-valued feature of the owner.
168    */

169   public AddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection JavaDoc collection)
170   {
171     this(domain, owner, feature, collection, CommandParameter.NO_INDEX);
172   }
173
174   /**
175    * This constructs a primitive command to insert a collection of values into the specified many-valued feature of the owner.
176    */

177   public AddCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Collection JavaDoc collection, int index)
178   {
179     super(domain, LABEL, DESCRIPTION);
180
181     this.owner = owner;
182     this.feature = feature;
183     this.collection = collection;
184     this.index = index;
185
186     ownerList = getOwnerList(owner, feature);
187   }
188
189   /**
190    * This constructs a primitive command to add a particular value into the specified extent.
191    */

192   public AddCommand(EditingDomain domain, EList list, Object JavaDoc value)
193   {
194     this(domain, list, Collections.singleton(value), CommandParameter.NO_INDEX);
195   }
196
197   /**
198    * This constructs a primitive command to insert particular value into the specified extent.
199    */

200   public AddCommand(EditingDomain domain, EList list, Object JavaDoc value, int index)
201   {
202     this(domain, list, Collections.singleton(value), index);
203   }
204
205   /**
206    * This constructs a primitive command to insert a collection of values into the specified extent.
207    */

208   public AddCommand(EditingDomain domain, EList list, Collection JavaDoc collection)
209   {
210     this(domain, list, collection, CommandParameter.NO_INDEX);
211   }
212
213   /**
214    * This constructs a primitive command to insert a collection of values into the specified extent.
215    */

216   public AddCommand(EditingDomain domain, EList list, Collection JavaDoc collection, int index)
217   {
218     super(domain, LABEL, DESCRIPTION_FOR_LIST);
219
220     this.collection = collection;
221     this.index = index;
222
223     ownerList = list;
224   }
225
226   /**
227    * This returns the owner object upon which the command will act.
228    * It could be null in the case that we are dealing with an {@link org.eclipse.emf.common.util.EList}.
229    */

230   public EObject getOwner()
231   {
232     return owner;
233   }
234
235   /**
236    * This returns the feature of the owner object upon the command will act.
237    * It could be null, in the case that we are dealing with an {@link org.eclipse.emf.common.util.EList}.
238    */

239   public EStructuralFeature getFeature()
240   {
241     return feature;
242   }
243
244   /**
245    * This returns the list to which the command will add.
246    */

247   public EList getOwnerList()
248   {
249     return ownerList;
250   }
251
252   /**
253    * This returns the collection of objects being added.
254    */

255   public Collection JavaDoc getCollection()
256   {
257     return collection;
258   }
259
260   /**
261    * This returns the position at which the objects will be added.
262    */

263   public int getIndex()
264   {
265     return index;
266   }
267
268   protected boolean isUserElement(EStructuralFeature entryFeature)
269   {
270     return
271       entryFeature != XMLTypePackage.eINSTANCE.getXMLTypeDocumentRoot_Text() &&
272       entryFeature != XMLTypePackage.eINSTANCE.getXMLTypeDocumentRoot_CDATA() &&
273       entryFeature != XMLTypePackage.eINSTANCE.getXMLTypeDocumentRoot_Comment();
274   }
275
276   protected boolean prepare()
277   {
278     // If there is no list to add to, no collection or an empty collection from which to add, or the index is out of range...
279
//
280
if (ownerList == null ||
281           collection == null ||
282           collection.size() == 0 ||
283           index != CommandParameter.NO_INDEX && (index < 0 || index > ownerList.size()))
284     {
285       return false;
286     }
287
288     if (feature != null)
289     {
290       // If it's a feature map, we'll need to validate the entry feature and enforce its multiplicity restraints.
291
//
292
FeatureMapUtil.Validator validator = null;
293       boolean documentRoot = false;
294       Set JavaDoc entryFeatures = null;
295
296       if (FeatureMapUtil.isFeatureMap(feature))
297       {
298         EClass eClass = owner.eClass();
299         validator = FeatureMapUtil.getValidator(eClass, feature);
300
301         // Keep track of all the entry features that are already in the feature map and that will be added, excluding
302
// XML text, CDATA, and comments (if we're in a mixed type).
303
//
304
documentRoot = ExtendedMetaData.INSTANCE.getDocumentRoot(eClass.getEPackage()) == eClass;
305         boolean mixed = documentRoot || ExtendedMetaData.INSTANCE.getContentKind(eClass) == ExtendedMetaData.MIXED_CONTENT;
306         entryFeatures = new HashSet JavaDoc();
307         for (Iterator JavaDoc i = ownerList.iterator(); i.hasNext(); )
308         {
309           EStructuralFeature entryFeature = ((FeatureMap.Entry)i.next()).getEStructuralFeature();
310           if (!mixed || isUserElement(entryFeature))
311           {
312             entryFeatures.add(entryFeature);
313           }
314         }
315       }
316
317       // Check each object...
318
//
319
for (Iterator JavaDoc objects = collection.iterator(); objects.hasNext(); )
320       {
321         Object JavaDoc object = objects.next();
322         boolean containment = false;
323
324         // Check type of object.
325
//
326
if (!feature.getEType().isInstance(object))
327         {
328           return false;
329         }
330
331         // Check that the object isn't already in a unique list.
332
//
333
if (feature.isUnique() && ownerList.contains(object))
334         {
335           return false;
336         }
337
338         // For feature maps, test that the entry feature is a valid type, that the entry value is an instance of it,
339
// that there is not already something in a document root, and that there is not already something in a
340
// single-valued entry feature.
341
//
342
if (validator != null)
343         {
344           FeatureMap.Entry entry = (FeatureMap.Entry)object;
345           EStructuralFeature entryFeature = entry.getEStructuralFeature();
346           containment = entryFeature instanceof EReference && ((EReference)entryFeature).isContainment();
347           
348           if (!validator.isValid(entryFeature) || !entryFeature.getEType().isInstance(entry.getValue()))
349           {
350             return false;
351           }
352
353           if (documentRoot)
354           {
355             if (isUserElement(entryFeature))
356             {
357               if (!entryFeatures.isEmpty())
358               {
359                 return false;
360               }
361               entryFeatures.add(entryFeature);
362             }
363           }
364           else if (!entryFeatures.add(entryFeature) && !FeatureMapUtil.isMany(owner, entryFeature))
365           {
366             return false;
367           }
368         }
369
370         // Check to see if a container is being put into a contained object.
371
//
372
containment |= feature instanceof EReference && ((EReference)feature).isContainment();
373         if (containment)
374         {
375           for (EObject container = owner; container != null; container = container.eContainer())
376           {
377             if (object == container)
378             {
379               return false;
380             }
381           }
382         }
383       }
384     }
385
386     if (owner != null && domain.isReadOnly(owner.eResource()))
387     {
388       return false;
389     }
390
391     return true;
392   }
393
394   public void doExecute()
395   {
396     // Simply add the collection to the list.
397
//
398
if (index == CommandParameter.NO_INDEX)
399     {
400       ownerList.addAll(collection);
401     }
402     else
403     {
404       ownerList.addAll(index, collection);
405     }
406   
407     // We'd like the collection of things added to be selected after this command completes.
408
//
409
affectedObjects = collection;
410   }
411
412   public void doUndo()
413   {
414     // Remove the collection from the list by index.
415
//
416
int i = index != CommandParameter.NO_INDEX ? index : ownerList.size() - collection.size();
417     ownerList.subList(i, i + collection.size()).clear();
418   
419     // We'd like the owner selected after this undo completes.
420
//
421
affectedObjects = owner == null ? Collections.EMPTY_SET : Collections.singleton(owner);
422   }
423
424   public void doRedo()
425   {
426     // Simply add the collection to the list.
427
//
428
if (index == CommandParameter.NO_INDEX)
429     {
430       ownerList.addAll(collection);
431     }
432     else
433     {
434       ownerList.addAll(index, collection);
435     }
436
437     // We'd like the collection of things added to be selected after this command completes.
438
//
439
affectedObjects = collection;
440   }
441
442   public Collection JavaDoc doGetResult()
443   {
444     return collection;
445   }
446
447   public Collection JavaDoc doGetAffectedObjects()
448   {
449     return affectedObjects;
450   }
451
452   /**
453    * This gives an abbreviated name using this object's own class' name, without package qualification,
454    * followed by a space separated list of <tt>field:value</tt> pairs.
455    */

456   public String JavaDoc toString()
457   {
458     StringBuffer JavaDoc result = new StringBuffer JavaDoc(super.toString());
459     result.append(" (owner: " + owner + ")");
460     result.append(" (feature: " + feature + ")");
461     result.append(" (ownerList: " + ownerList + ")");
462     result.append(" (collection: " + collection + ")");
463     result.append(" (index: " + index + ")");
464     result.append(" (affectedObjects:" + affectedObjects + ")");
465
466     return result.toString();
467   }
468 }
469
Popular Tags