KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > emf > edit > provider > DelegatingWrapperItemProvider


1 /**
2  * <copyright>
3  *
4  * Copyright (c) 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: DelegatingWrapperItemProvider.java,v 1.6 2005/06/08 06:17:05 nickb Exp $
16  */

17 package org.eclipse.emf.edit.provider;
18
19
20 import java.util.ArrayList JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.HashSet JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.ListIterator JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.Set JavaDoc;
30
31 import org.eclipse.emf.common.command.Command;
32 import org.eclipse.emf.common.command.CommandWrapper;
33 import org.eclipse.emf.common.command.UnexecutableCommand;
34 import org.eclipse.emf.common.notify.AdapterFactory;
35 import org.eclipse.emf.common.notify.Notification;
36 import org.eclipse.emf.ecore.EStructuralFeature;
37 import org.eclipse.emf.edit.command.CommandActionDelegate;
38 import org.eclipse.emf.edit.command.CommandParameter;
39 import org.eclipse.emf.edit.command.DragAndDropCommand;
40 import org.eclipse.emf.edit.command.SetCommand;
41 import org.eclipse.emf.edit.domain.EditingDomain;
42 import org.eclipse.emf.edit.provider.IItemPropertyDescriptor.OverrideableCommandOwner;
43
44
45 /**
46  * A wrapper for model objects and other wrappers. This handles most of the item provider methods by delegating to the
47  * item provider returned by adapting on the value, but it returns the {@link org.eclipse.emf.edit.provider.WrapperItemProvider#getParent(Object) owner}
48  * as the parent, and it has to decorate the children, property descriptors, and commands that it returns.
49  */

50 public class DelegatingWrapperItemProvider extends WrapperItemProvider
51   implements
52     IStructuredItemContentProvider,
53     ITreeItemContentProvider,
54     IItemLabelProvider,
55     IItemPropertySource,
56     IEditingDomainItemProvider,
57     IChangeNotifier,
58     INotifyChangedListener
59 {
60   /**
61    * The wrapped value's item provider, to which most methods are delegated.
62    */

63   protected Object JavaDoc delegateItemProvider;
64
65   /**
66    * The wrapped children are cached here, keyed by the children returned by the delegate item provider.
67    */

68   protected Map JavaDoc childrenMap;
69
70   /**
71    * The collection of children last returned by the delegate item provider is cached here.
72    */

73   protected Collection JavaDoc delegateChildren;
74
75   /**
76    * The decorated property descriptors are cached here.
77    */

78   protected List JavaDoc propertyDescriptors;
79
80   /**
81    * Records any listeners for this wrapper and fires notifications to them.
82    */

83   protected IChangeNotifier changeNotifier;
84
85   /**
86    * Creates an instance for the given value. A decorator for the object's item provider is created, and
87    * set up to repeat notifications, decorating them, so that they will update this wrapper, rather than the model
88    * object they originate from.
89    *
90    * @exception IllegalArgumentException If the specified value is null.
91    */

92   public DelegatingWrapperItemProvider(Object JavaDoc value, Object JavaDoc owner, EStructuralFeature feature, int index, AdapterFactory adapterFactory)
93   {
94     super(value, owner, feature, index, adapterFactory);
95
96     if (value == null)
97     {
98       throw new IllegalArgumentException JavaDoc("value=null");
99     }
100
101     Object JavaDoc delegateValue = getDelegateValue();
102     if (delegateValue != null)
103     {
104       delegateItemProvider = getRootAdapterFactory().adapt(delegateValue, IStructuredItemContentProvider.class);
105       if (delegateItemProvider instanceof IChangeNotifier)
106       {
107         ((IChangeNotifier)delegateItemProvider).addListener(this);
108       }
109     }
110   }
111
112   /**
113    * Creates an instance for the given value, when the feature and index that specify the value are unknown.
114    *
115    * @exception IllegalArgumentException If the specified value is null.
116    *
117    * @deprecated As of EMF 2.0.1, replaced by {@link #DelegatingWrapperItemProvider(Object, org.eclipse.emf.ecore.EObject, EStructuralFeature, int, AdapterFactory)
118    * this form}. This constructor will be removed as public API, but remain available as a protected method.
119    */

120   public DelegatingWrapperItemProvider(Object JavaDoc value, Object JavaDoc owner, AdapterFactory adapterFactory)
121   {
122     this(value, owner, null, CommandParameter.NO_INDEX, adapterFactory);
123   }
124
125   /**
126    * Deactivates notification repeating and disposes any wrappers it is maintaining for its children.
127    */

128   public void dispose()
129   {
130     if (delegateItemProvider instanceof IChangeNotifier)
131     {
132       ((IChangeNotifier)delegateItemProvider).removeListener(this);
133     }
134
135     if (childrenMap != null)
136     {
137       for (Iterator JavaDoc i = childrenMap.values().iterator(); i.hasNext();)
138       {
139         ((IDisposable)i.next()).dispose();
140       }
141     }
142   }
143
144   /**
145    * Returns the value from which to obtain and which to pass to a delegate item provider. If this returns null,
146    * no delegate item provider should ever be obtained. This implementation simply returns the value of the wrapper,
147    * though subclasses may override it to return something else.
148    */

149   protected Object JavaDoc getDelegateValue()
150   {
151     return value;
152   }
153
154   /**
155    * Uses the delegate item provider to return the delegate value's elements.
156    */

157   public Collection JavaDoc getElements(Object JavaDoc object)
158   {
159     return delegateItemProvider instanceof IStructuredItemContentProvider ?
160       ((IStructuredItemContentProvider)delegateItemProvider).getElements(getDelegateValue()) :
161       Collections.EMPTY_LIST;
162   }
163
164   /**
165    * Uses the delgate item provider to return the delegate value's children, with appropriate wrappers to ensure that
166    * this wrapper is considered their parent. Each child is replaced by the corresponding wrapper from {@link
167    * #childrenMap}, after updating it by calling {@link #updateChildren updateChildren}.
168    */

169   public Collection JavaDoc getChildren(Object JavaDoc object)
170   {
171     updateChildren();
172
173     Collection JavaDoc result = new ArrayList JavaDoc(delegateChildren.size());
174     for (Iterator JavaDoc i = delegateChildren.iterator(); i.hasNext(); )
175     {
176       result.add(childrenMap.get(i.next()));
177     }
178     return result;
179   }
180
181   /**
182    * Uses the delegate item provider to get the delegate value's children, assigning the collection to {@link
183    * #delegateChildren}, and to update the {@link #childrenMap}. New chidren are wrapped by calling {@link
184    * #createWrapper createWrapper} and added to the map; Wrappers for children that have been removed are disposed.
185    */

186   protected void updateChildren()
187   {
188     if (delegateItemProvider instanceof ITreeItemContentProvider)
189     {
190       boolean changed = false;
191       Set JavaDoc oldDelegateChildren = delegateChildren != null ? new HashSet JavaDoc(delegateChildren) : Collections.EMPTY_SET;
192       delegateChildren = ((ITreeItemContentProvider)delegateItemProvider).getChildren(getDelegateValue());
193
194       if (childrenMap == null && !delegateChildren.isEmpty())
195       {
196         childrenMap = new HashMap JavaDoc();
197       }
198       
199       // Wrap any new children and add them to the map. Remove each current child from the set of old children.
200
//
201
for (Iterator JavaDoc i = delegateChildren.iterator(); i.hasNext(); )
202       {
203         Object JavaDoc child = i.next();
204         
205         if (!childrenMap.containsKey(child))
206         {
207           IWrapperItemProvider wrapper = createWrapper(child, this, adapterFactory);
208           childrenMap.put(child, wrapper);
209           changed = true;
210         }
211         oldDelegateChildren.remove(child);
212       }
213
214       // Remove and dispose any wrappers for remaining old children.
215
//
216
if (!oldDelegateChildren.isEmpty())
217       {
218         changed = true;
219
220         for (Iterator JavaDoc i = oldDelegateChildren.iterator(); i.hasNext(); )
221         {
222           Object JavaDoc child = i.next();
223
224           IWrapperItemProvider wrapper = (IWrapperItemProvider)childrenMap.remove(child);
225           if (wrapper != null)
226           {
227             wrapper.dispose();
228           }
229         }
230       }
231
232       // If any children were added or removed, reset the indices.
233
if (changed)
234       {
235         int index = 0;
236         for (Iterator JavaDoc i = delegateChildren.iterator(); i.hasNext(); index++)
237         {
238           ((IWrapperItemProvider)childrenMap.get(i.next())).setIndex(index);
239         }
240       }
241     }
242     else
243     {
244       delegateChildren = Collections.EMPTY_LIST;
245     }
246   }
247
248   /**
249    * Creates a new instance of this wrapper for the given value, owner, and adapter factory.
250    */

251   protected IWrapperItemProvider createWrapper(Object JavaDoc value, Object JavaDoc owner, AdapterFactory adapterFactory)
252   {
253     return new DelegatingWrapperItemProvider(value, owner, adapterFactory);
254   }
255
256   /**
257    * Uses the delegate item provider to test whether the delegate vlaue has children.
258    */

259   public boolean hasChildren(Object JavaDoc object)
260   {
261     return delegateItemProvider instanceof ITreeItemContentProvider ?
262       ((ITreeItemContentProvider)delegateItemProvider).hasChildren(getDelegateValue()) :
263       false;
264   }
265
266   /**
267    * Uses the delegate item provider to return the delegate value's text.
268    */

269   public String JavaDoc getText(Object JavaDoc object)
270   {
271     return delegateItemProvider instanceof IItemLabelProvider ?
272       ((IItemLabelProvider)delegateItemProvider).getText(getDelegateValue()) :
273       null;
274   }
275
276   /**
277    * Uses the delegate item provider to return the delegate value's image.
278    */

279   public Object JavaDoc getImage(Object JavaDoc object)
280   {
281     return delegateItemProvider instanceof IItemLabelProvider ?
282       ((IItemLabelProvider)delegateItemProvider).getImage(getDelegateValue()) :
283       null;
284   }
285
286   /**
287    * Wraps the property descriptors returned by the delegate item provider, caching and returning them.
288    */

289   public List JavaDoc getPropertyDescriptors(Object JavaDoc object)
290   {
291     if (propertyDescriptors == null)
292     {
293       if (delegateItemProvider instanceof IItemPropertySource)
294       {
295         List JavaDoc l = ((IItemPropertySource)delegateItemProvider).getPropertyDescriptors(getDelegateValue());
296         propertyDescriptors = new ArrayList JavaDoc(l.size());
297
298         for (Iterator JavaDoc i = l.iterator(); i.hasNext(); )
299         {
300           IItemPropertyDescriptor desc = (IItemPropertyDescriptor)i.next();
301           propertyDescriptors.add(new DelegatingWrapperItemPropertyDescriptor(getDelegateValue(), desc));
302         }
303       }
304       else
305       {
306         propertyDescriptors = Collections.EMPTY_LIST;
307       }
308     }
309     return propertyDescriptors;
310   }
311
312   /**
313    * Uses the delegate item provider to return an editable value.
314    */

315   public Object JavaDoc getEditableValue(Object JavaDoc object)
316   {
317     return delegateItemProvider instanceof IItemPropertySource ?
318       ((IItemPropertySource)delegateItemProvider).getEditableValue(getDelegateValue()) :
319       null;
320   }
321   
322   /**
323    * Uses the delegate item provider to return the delegate value's new child descriptors.
324    */

325   public Collection JavaDoc getNewChildDescriptors(Object JavaDoc object, EditingDomain editingDomain, Object JavaDoc sibling)
326   {
327     return delegateItemProvider instanceof IEditingDomainItemProvider ?
328       ((IEditingDomainItemProvider)delegateItemProvider).getNewChildDescriptors(getDelegateValue(), editingDomain, sibling) :
329       Collections.EMPTY_LIST;
330   }
331
332   /**
333    * Uses the delegate item provider to create a command for the delegate value, and then calls {@link #wrapCommand
334    * wrapCommand} to return an appropriate wrapper-substituting command wrapper for it. Drag and drop commands are
335    * created directly by calling {@link WrapperItemProvider#createDragAndDropCommand createDragAndDropCommand}.
336    */

337   public Command createCommand(Object JavaDoc object, EditingDomain domain, Class JavaDoc commandClass, CommandParameter commandParameter)
338   {
339     if (commandClass == DragAndDropCommand.class)
340     {
341       DragAndDropCommand.Detail detail = (DragAndDropCommand.Detail)commandParameter.getFeature();
342       return createDragAndDropCommand(domain, commandParameter.getOwner(), detail.location, detail.operations, detail.operation, commandParameter.getCollection());
343     }
344     
345     if (delegateItemProvider instanceof IEditingDomainItemProvider)
346     {
347       Object JavaDoc commandOwner = getDelegateValue();
348       Command result = null;
349
350       // A SetCommand needs to go through SetCommand.create() to ensure it can execute and undo.
351
//
352
if (commandClass == SetCommand.class)
353       {
354         Object JavaDoc feature = commandParameter.getFeature();
355         result = SetCommand.create(domain, commandOwner, feature, commandParameter.getValue(), commandParameter.getIndex());
356
357         // A set command without a feature sets the value of this wrapper, hence replacing it with a new wrapper. So,
358
// we need a special command wrapper that selects this new wrapper as the affected object.
359
//
360
if (feature == null)
361         {
362           return new ReplacementAffectedObjectCommand(result);
363         }
364       }
365       else
366       {
367         commandParameter.setOwner(commandOwner);
368         result = ((IEditingDomainItemProvider)delegateItemProvider).createCommand(commandOwner, domain, commandClass, commandParameter);
369       }
370       return wrapCommand(result, commandClass);
371     }
372     return UnexecutableCommand.INSTANCE;
373   }
374
375   /**
376    * Wraps the given command in an appropriate command that will substitute the delegating wrapper for its value and
377    * child wrappers for their corresponding values, whenever they appear in the affected objects. This implementation
378    * returns an {@link AffectedObjectsWrappingCommand} or an {@link AffectedObjectsWrappingCommandActionDelegate},
379    * depending on whether the given command implements {@link CommandActionDelegate}.
380    */

381   protected Command wrapCommand(Command command, Class JavaDoc commandClass)
382   {
383     return command instanceof CommandActionDelegate ?
384       new AffectedObjectsWrappingCommandActionDelegate((CommandActionDelegate)command) :
385       new AffectedObjectsWrappingCommand(command);
386   }
387
388   /**
389    * An <code>AffectedObjectsWrappingCommand</code> wraps another command to substitue this wrapper for its value
390    * and child wrappers for their corresonding child values, whenever they appear in the affected objects.
391    */

392   protected class AffectedObjectsWrappingCommand extends CommandWrapper
393   {
394     public AffectedObjectsWrappingCommand(Command command)
395     {
396       super(command);
397     }
398
399     public Collection JavaDoc getAffectedObjects()
400     {
401       List JavaDoc result = new ArrayList JavaDoc(super.getAffectedObjects());
402       updateChildren();
403
404       for (ListIterator JavaDoc i = result.listIterator(); i.hasNext(); )
405       {
406         Object JavaDoc object = i.next();
407
408         if (object == getDelegateValue())
409         {
410           i.set(DelegatingWrapperItemProvider.this);
411         }
412         else if (childrenMap != null)
413         {
414           Object JavaDoc wrapper = childrenMap.get(object);
415           if (wrapper != null)
416           {
417             i.set(wrapper);
418           }
419         }
420       }
421       return result;
422     }
423   }
424
425   /**
426    * An <code>AffectedObjectsWrappingCommandActionDelegate</code> wraps another command that also implements
427    * <code>CommandActionDelegate</code>, to substitue this wrapper for its value and child wrappers for their
428    * corresonding child values, whenever they appear in the affected objects. Action delegate methods are delegated
429    * directly to the wrapped command.
430    */

431   protected class AffectedObjectsWrappingCommandActionDelegate extends AffectedObjectsWrappingCommand
432     implements CommandActionDelegate
433   {
434     CommandActionDelegate commandActionDelegate;
435     
436     /**
437      * Returns a new <code>AffectedObjectsWrappingCommandActionDelegate</code> for the given command.
438      * @exception ClassCastException If the specified command does not implement {@link org.eclipse.emf.common.command.Command}.
439      */

440     public AffectedObjectsWrappingCommandActionDelegate(CommandActionDelegate command)
441     {
442       super((Command)command);
443       commandActionDelegate = command;
444     }
445
446     public boolean canExecute()
447     {
448       return commandActionDelegate.canExecute();
449     }
450
451     public Object JavaDoc getImage()
452     {
453       return commandActionDelegate.getImage();
454     }
455
456     public String JavaDoc getText()
457     {
458       return commandActionDelegate.getText();
459     }
460
461     public String JavaDoc getDescription()
462     {
463       return commandActionDelegate.getDescription();
464     }
465
466     public String JavaDoc getToolTipText()
467     {
468       return commandActionDelegate.getToolTipText();
469     }
470   }
471
472   /**
473    * Adds a listener to receive this wrapper's repeated notifications.
474    */

475   public void addListener(INotifyChangedListener listener)
476   {
477     if (changeNotifier == null)
478     {
479       changeNotifier = new ChangeNotifier();
480     }
481     changeNotifier.addListener(listener);
482   }
483
484   /**
485    * Removes a notification listener.
486    */

487   public void removeListener(INotifyChangedListener listener)
488   {
489     if (changeNotifier != null)
490     {
491       changeNotifier.removeListener(listener);
492     }
493   }
494
495   /**
496    * Fires a notification to the adapter factory and any registered listeners.
497    */

498   public void fireNotifyChanged(Notification notification)
499   {
500     if (adapterFactory instanceof IChangeNotifier)
501     {
502       IChangeNotifier adapterFactoryChangeNotifier = (IChangeNotifier)adapterFactory;
503       adapterFactoryChangeNotifier.fireNotifyChanged(notification);
504     }
505     if (changeNotifier != null)
506     {
507       changeNotifier.fireNotifyChanged(notification);
508     }
509   }
510
511   /**
512    * Called by {@link #delegateItemProvider} when it normally fires a notification to it's adapter factory; if the
513    * notification originated from the delegate value, this repeats the notification, using {@link #wrapNotification
514    * wrapNotification} to substitute this wrapper as the operative object.
515    */

516   public void notifyChanged(Notification notification)
517   {
518     if (getRefreshElement(notification) == getDelegateValue())
519     {
520       fireNotifyChanged(wrapNotification(notification));
521     }
522   }
523
524   /**
525    * Returns the operative object of this notification, from which the viewer would be refreshed. If the notification
526    * is an {@link IViewerNotification}, the {@link IViewerNotification#getElement element} is returned. Otherwise, the
527    * {@link org.eclipse.emf.common.notify.Notification#getNotifier notifier} is returned.
528    */

529   protected Object JavaDoc getRefreshElement(Notification notification)
530   {
531     if (notification instanceof IViewerNotification)
532     {
533       return ((IViewerNotification)notification).getElement();
534     }
535     return notification.getNotifier();
536   }
537
538   /**
539    * Wraps the given notification, substituting this wrapper as the operative object, by calling {@link
540    * ViewerNotification#wrapNotification ViewerNotification.wrapNotification}.
541    */

542   protected Notification wrapNotification(Notification notification)
543   {
544     return ViewerNotification.wrapNotification(notification, this);
545   }
546
547   /**
548    * A <code>DelegatingWrapperItemPropertyDescriptor</code> decorates an <code>ItemPropertyDescriptor</code> and
549    * manages a command owner override. If its command owner is non-null, it ensures that the decorated descriptor,
550    * if it also implements <code>OverrideableCommandOwner</code>, will have its command owner set to the same object
551    * when {@link #resetPropertyValue resetPropertyValue} or {@link #setPropertyValue setPropertyValue} is called.
552    * If its command owner is null, then the decorated descriptors's command owner will be set to this wrapper item
553    * provider.
554    */

555   protected class DelegatingWrapperItemPropertyDescriptor extends ItemPropertyDescriptorDecorator
556     implements OverrideableCommandOwner
557   {
558     protected Object JavaDoc commandOwner;
559     
560     public DelegatingWrapperItemPropertyDescriptor(Object JavaDoc object, IItemPropertyDescriptor itemPropertyDescriptor)
561     {
562       super(object, itemPropertyDescriptor);
563     }
564
565     /**
566      * Sets the override command owner and, if the decorated descriptor also implements {@link
567      * IItemPropertyDescriptor.OverrideableCommandOwner OverrideableCommandOwner}, updates its command owner.
568      */

569     public void setCommandOwner(Object JavaDoc commandOwner)
570     {
571       this.commandOwner = commandOwner;
572       if (itemPropertyDescriptor instanceof OverrideableCommandOwner)
573       {
574         ((OverrideableCommandOwner)itemPropertyDescriptor).setCommandOwner(commandOwner);
575       }
576     }
577
578     /**
579      * Returns the override command owner.
580      */

581     public Object JavaDoc getCommandOwner()
582     {
583       return commandOwner;
584     }
585
586     /**
587      * Updates the decorated descriptor's command owner and invokes <code>resetPropertyValue</code> on it.
588      */

589     public void resetPropertyValue(Object JavaDoc thisObject)
590     {
591       boolean hasCommandOwner = commandOwner != null;
592       if (!hasCommandOwner)
593       {
594         setCommandOwner(DelegatingWrapperItemProvider.this);
595       }
596       itemPropertyDescriptor.resetPropertyValue(object);
597       if (!hasCommandOwner)
598       {
599         setCommandOwner(null);
600       }
601     }
602
603     /**
604      * Updates the decorated descriptor's command owner and invokes <code>setPropertyValue</code> on it.
605
606      */

607     public void setPropertyValue(Object JavaDoc thisObject, Object JavaDoc value)
608     {
609       boolean hasCommandOwner = commandOwner != null;
610       if (!hasCommandOwner)
611       {
612         setCommandOwner(DelegatingWrapperItemProvider.this);
613       }
614       itemPropertyDescriptor.setPropertyValue(object, value);
615       if (!hasCommandOwner)
616       {
617         setCommandOwner(null);
618       }
619     }
620   }
621 }
Popular Tags