PageRenderTime 69ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 1ms

/emf-2.8.0/org.eclipse.emf.edit/src/org/eclipse/emf/edit/command/ReplaceCommand.java

#
Java | 353 lines | 154 code | 48 blank | 151 comment | 15 complexity | 283947e4b13e7f25d444c477f7b15f3f MD5 | raw file
  1. /**
  2. * Copyright (c) 2002-2006 IBM Corporation and others.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * IBM - Initial API and implementation
  10. */
  11. package org.eclipse.emf.edit.command;
  12. import java.util.Collection;
  13. import java.util.Collections;
  14. import org.eclipse.emf.common.command.Command;
  15. import org.eclipse.emf.common.util.EList;
  16. import org.eclipse.emf.ecore.EObject;
  17. import org.eclipse.emf.ecore.EStructuralFeature;
  18. import org.eclipse.emf.edit.EMFEditPlugin;
  19. import org.eclipse.emf.edit.domain.EditingDomain;
  20. /**
  21. * The replace command logically acts upon an owner object that has a collection-type feature
  22. * in which an object can be replaced by a collection of other objects.
  23. * The static create methods delegate command creation to {@link EditingDomain#createCommand EditingDomain.createCommand},
  24. * which may or may not result in the actual creation of an instance of this class.
  25. *
  26. * <p>
  27. * The implementation of this class is low-level and EMF specific;
  28. * it allows an object from a many-valued feature of an owner to be replaced by a collection of other objects.
  29. * i.e., it is equivalent of the call
  30. * <pre>
  31. * int index = ((EList)((EObject)owner).eGet((EStructuralFeature)feature)).indexOf(value);
  32. * ((EList)((EObject)owner).eGet((EStructuralFeature)feature)).remove(value);
  33. * ((EList)((EObject)owner).eGet((EStructuralFeature)feature)).addAll(index, (Collection)collection);
  34. * </pre>
  35. *
  36. * <p>
  37. * It can also be used as an equivalent to the call
  38. * <pre>
  39. * int index = ((EList)extent).indexOf(value);
  40. * ((EList)extent).remove(value);
  41. * ((EList)extent).addAll(index, (Collection)collection);
  42. * </pre>
  43. * which is how root objects are replaced in the contents of a resource.
  44. * Like all the low level commands in this package, the replace command is undoable.
  45. *
  46. * <p>
  47. * A replace command is an {@link OverrideableCommand}.
  48. */
  49. public class ReplaceCommand extends AbstractOverrideableCommand
  50. {
  51. /**
  52. * This creates a command to replace an object with a collection of replacements.
  53. */
  54. public static Command create(EditingDomain domain, Object value, Collection<?> collection)
  55. {
  56. return create(domain, null, null, value, collection);
  57. }
  58. /**
  59. * This creates a command to replace a particular value in the specified feature of the owner with a collection replacements objects.
  60. */
  61. public static Command create(EditingDomain domain, Object owner, Object feature, Object value, Collection<?> collection)
  62. {
  63. return domain.createCommand(ReplaceCommand.class, new CommandParameter(owner, feature, value, collection));
  64. }
  65. /**
  66. * This caches the label.
  67. */
  68. protected static final String LABEL = EMFEditPlugin.INSTANCE.getString("_UI_ReplaceCommand_label");
  69. /**
  70. * This caches the description.
  71. */
  72. protected static final String DESCRIPTION = EMFEditPlugin.INSTANCE.getString("_UI_ReplaceCommand_description");
  73. /**
  74. * This is the owner object upon which the command will act.
  75. * It could be null, in the case that we are dealing with an {@link org.eclipse.emf.common.util.EList}.
  76. */
  77. protected EObject owner;
  78. /**
  79. * This is the feature of the owner object upon the command will act.
  80. * It could be null, in the case that we are dealing with an {@link org.eclipse.emf.common.util.EList}.
  81. */
  82. protected EStructuralFeature feature;
  83. /**
  84. * This is the list from which the command will replace.
  85. */
  86. protected EList<Object> ownerList;
  87. /**
  88. * This is value that is being replaced.
  89. */
  90. protected Object value;
  91. /**
  92. * This is the collection of replacements.
  93. */
  94. protected Collection<?> collection;
  95. /**
  96. * This is the index at which to reinsert the replaced object during an undo so as to achieve the original list order.
  97. */
  98. protected int index;
  99. /**
  100. * The is the value returned by {@link Command#getAffectedObjects}.
  101. * The affected objects are different after an execute than after an undo, so we record it.
  102. */
  103. protected Collection<?> affectedObjects;
  104. /**
  105. * This constructs a primitive command to replace a particular value in the specified feature of the owner
  106. * with the specified replacement.
  107. */
  108. public ReplaceCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object value, Object replacement)
  109. {
  110. this(domain, owner, feature, value, Collections.singleton(replacement));
  111. }
  112. /**
  113. * This constructs a primitive command to replace a particular value in the specified feature of the owner
  114. * with the specified collection of replacements.
  115. */
  116. public ReplaceCommand(EditingDomain domain, EObject owner, EStructuralFeature feature, Object value, Collection<?> collection)
  117. {
  118. super(domain, LABEL, DESCRIPTION);
  119. // Initialize all the fields from the command parameter.
  120. //
  121. this.owner = owner;
  122. this.feature = feature;
  123. this.value = value;
  124. this.collection = collection;
  125. ownerList = getOwnerList(this.owner, feature);
  126. }
  127. /**
  128. * This constructs a primitive command to replace a particular value in the specified extent with the given replacement.
  129. */
  130. public ReplaceCommand(EditingDomain domain, EList<?> list, Object value, Object replacement)
  131. {
  132. this(domain, list, value, Collections.singleton(replacement));
  133. }
  134. /**
  135. * This constructs a primitive command to replace a particular value in the specified extent with the given collection of replacements.
  136. */
  137. public ReplaceCommand(EditingDomain domain, EList<?> list, Object value, Collection<?> collection)
  138. {
  139. super(domain, LABEL, DESCRIPTION);
  140. // Initialize all the fields from the command parameter.
  141. //
  142. this.value = value;
  143. this.collection = collection;
  144. @SuppressWarnings("unchecked")
  145. EList<Object> untypedList = (EList<Object>)list;
  146. ownerList = untypedList;
  147. }
  148. /**
  149. * This returns the owner object upon which the command will act.
  150. * It could be null, in the case that we are dealing with an {@link org.eclipse.emf.common.util.EList}.
  151. */
  152. public EObject getOwner()
  153. {
  154. return owner;
  155. }
  156. /**
  157. * This returns the feature of the owner object upon the command will act.
  158. * It could be null, in the case that we are dealing with an {@link org.eclipse.emf.common.util.EList}.
  159. */
  160. public EStructuralFeature getFeature()
  161. {
  162. return feature;
  163. }
  164. /**
  165. * This returns the list in which the command will replace.
  166. */
  167. public EList<Object> getOwnerList()
  168. {
  169. return ownerList;
  170. }
  171. /**
  172. * This returns the value being replaced.
  173. */
  174. public Object getValue()
  175. {
  176. return value;
  177. }
  178. /**
  179. * This returns the collection of replacement objects.
  180. */
  181. public Collection<?> getCollection()
  182. {
  183. return collection;
  184. }
  185. /**
  186. * This returns the index at which to reinsert the replace objects during an undo so as to achieve the original list order.
  187. */
  188. public int getIndex()
  189. {
  190. return index;
  191. }
  192. @Override
  193. protected boolean prepare()
  194. {
  195. // This can't execute if there is no owner list
  196. // or the owner list doesn't contain the value being replaced or
  197. // there are not replacements.
  198. //
  199. if (ownerList == null || !ownerList.contains(value) || collection == null || collection.isEmpty())
  200. {
  201. return false;
  202. }
  203. else if (owner != null && domain.isReadOnly(owner.eResource()))
  204. {
  205. return false;
  206. }
  207. else if (feature == null)
  208. {
  209. // An extent allows anything to be added.
  210. //
  211. return true;
  212. }
  213. else
  214. {
  215. // Make sure each object conforms to the type of the feature.
  216. //
  217. for (Object replacement : collection)
  218. {
  219. if (!feature.getEType().isInstance(replacement))
  220. {
  221. return false;
  222. }
  223. }
  224. return true;
  225. }
  226. }
  227. @Override
  228. public void doExecute()
  229. {
  230. // Record the position of the value in the owner list.
  231. //
  232. index = ownerList.indexOf(value);
  233. // Simply remove the object from the owner list.
  234. //
  235. ownerList.remove(value);
  236. // Insert the collection at the right place.
  237. //
  238. ownerList.addAll(index, collection);
  239. // Update the containing map, if necessary.
  240. //
  241. updateEMap(owner, feature);
  242. // We'd like the collection of replacements selected after this replace completes.
  243. //
  244. affectedObjects = collection;
  245. }
  246. @Override
  247. public void doUndo()
  248. {
  249. // Remove the collection of replacements.
  250. //
  251. ownerList.removeAll(collection);
  252. // Add the value back in the right place.
  253. //
  254. ownerList.add(index, value);
  255. // Update the containing map, if necessary.
  256. //
  257. updateEMap(owner, feature);
  258. // We'd like the replaced selected after this undo replace completes.
  259. //
  260. affectedObjects = Collections.singleton(value);
  261. }
  262. @Override
  263. public void doRedo()
  264. {
  265. // Simply remove the object from the owner list.
  266. //
  267. ownerList.remove(value);
  268. // Insert the collection at the right place.
  269. //
  270. ownerList.addAll(index, collection);
  271. // Update the containing map, if necessary.
  272. //
  273. updateEMap(owner, feature);
  274. // We'd like the collection of replacements selected after this replace completes.
  275. //
  276. affectedObjects = collection;
  277. }
  278. @Override
  279. public Collection<?> doGetResult()
  280. {
  281. return collection;
  282. }
  283. @Override
  284. public Collection<?> doGetAffectedObjects()
  285. {
  286. return affectedObjects;
  287. }
  288. /**
  289. * This gives an abbreviated name using this object's own class' name, without package qualification,
  290. * followed by a space separated list of <tt>field:value</tt> pairs.
  291. */
  292. @Override
  293. public String toString()
  294. {
  295. StringBuffer result = new StringBuffer(super.toString());
  296. result.append(" (owner: " + owner + ")");
  297. result.append(" (feature: " + feature + ")");
  298. result.append(" (ownerList: " + ownerList + ")");
  299. result.append(" (value: " + value + ")");
  300. result.append(" (collection: " + collection + ")");
  301. result.append(" (index: " + index + ")");
  302. result.append(" (affectedObjects:" + affectedObjects + ")");
  303. return result.toString();
  304. }
  305. }