Tutorial: EMF Clipboard Copy and Paste
Version: 0.1
|
Date: June 08, 2005
|
Contents
[
back to top]
The EMF clipboard support allows EObjects to be copied and
pasted in an intelligent way. This is accomplished by providing
clipboard support to a metamodel so that any instances of that
metamodel may be copied in a specific way that is intuitive for
users of that metamodel.
[
back to top]
This tutorial assumes that the reader is familiar with EMF and
in particular EPackages, EClasses, EStructuralFeatures and
EReferences. A crucial part of understanding EMF is being able to
understand its reflective mechanisms. Also, extension parsers and
EPackage namespace URIs should be understood before beginning to
add clipboard support for a metamodel.
For reference, the full
example
for this tutorial is available.
[
back to top]
In order to demonstrate EMF clipboard support, we will be making
use of the Library metamodel. This metamodel is a variant of the
standard EMF example metamodel used in many of its tutorials.
For those readers who are not familiar with this metamodel, it
models a library with books and writers. A book has an author that
is a writer and both writers and books may be owned by a library.
When copying and pasting writers, their books should be copied
along with them even though the writer doesn't contain their
books.
[
back to top]
One important prerequisite for EMF clipboard support is that the
resources that will contain EObjects to be copied and/or pasted
must support UUID(Universally Unique IDs) URIs for the EObjects.
EMF clipboard will use these UUIDs to discover whether another
EObject is the original EObject and should be overwritten with the
clipboard contents. EMF's XMIResourceImpl does not normally use
UUIDs.
To ensure EMF will use a compatible resource, we will create a
new subclass of the XMIResourceImpl so that our resource is
serialized as XMI but with UUIDs:
public class LibraryResource extends XMIResourceImpl { public
LibraryResource() { super(); } public LibraryResource(URI uri) {
super(uri); } protected boolean useUUIDs() { return true; } }
As well, we will need a resource factory to provide to EMF so
that it will construct our resource implementation rather than its
own XMIResourceImpl:
public class LibraryResourceFactory extends XMIResourceFactoryImpl
{ public LibraryResourceFactory() { super(); } public Resource
createResource(URI uri) { return new LibraryResource(uri); } }
Finally, we will write an extension that will register our
factory with EMF when it encounters the "library" file
extension:
<extension point="org.eclipse.emf.ecore.extension_parser">
<parser type="library"
class="org.eclipse.gmf.examples.runtime.emf.clipboard.library.LibraryResourceFactory"/>
</extension>
[
back to top]
Now that we have set up the resource to use UUIDs, we can add
clipboard support for the library metamodel:
class LibraryClipboardSupport extends AbstractClipboardSupport {
public LibraryClipboardSupport() { super(); } /** * Provide a
mapping of name attributes for the EClasses of * the Library
metamodel. */ protected EAttribute getNameAttribute(EClass eClass)
{ EAttribute result; switch (eClass.getClassifierID()) { case
LibraryPackage.BOOK: result =
LibraryPackage.eINSTANCE.getBook_Title(); break; case
LibraryPackage.LIBRARY: result =
LibraryPackage.eINSTANCE.getLibrary_Name(); break; case
LibraryPackage.WRITER: result =
LibraryPackage.eINSTANCE.getWriter_Name(); break; default: result =
null; break; } return result; } /** * Merge an author into an
existing author of the same name when pasting. */ public
PasteAction getPasteCollisionAction(EClass eClass) { if (eClass ==
LibraryPackage.eINSTANCE.getWriter()) { return PasteAction.MERGE; }
else { return super.getPasteCollisionAction(eClass); } } /** * We
always copy an author's books. */ public boolean
isCopyAlways(EObject context, EReference eReference, Object value)
{ if (eReference == LibraryPackage.eINSTANCE.getWriter_Books()) {
return true; } else { return super.isCopyAlways(context,
eReference, value); } } }
In the above class, we extend the AbstractClipboardSupport and
we provide three key pieces of information: the name EAttribute of
an EClass, the action to perform in case of a collision of an
EObject of a particular EClass and whether to copy the contents of
an EReference. The reason for the first piece of information is
made clear in the library metamodel because although the Writer and
Library EClasses has a "name" EAttribute, the Book has a "title"
EAttribute. In cases where a paste will cause a collision with
another EObject of the same EClass, the
getPasteCollisionAction() method will dictate whether the
EObjects should be merged, added, cloned, replaced and other
possible actions (see the PasteAction class). The final piece of
information provided by the
isCopyAlways() method will provide information regarding which
EReferences should be copied along with the EObject. In our case,
we request that the author's books be copied along with the author.
The AbstractClipboardSupport class provides a default
implementation that specifies that all containment EReferences
should be copied while all derived or transient EReferences should
not be copied.
To register the LibraryClipboardSupport to the EMF Clipboard
framework, we will need to create a factory as follows:
public class LibraryClipboardSupportFactory implements
IClipboardSupportFactory { private final IClipboardSupport support
= new LibraryClipboardSupport(); public
LibraryClipboardSupportFactory() { super(); } public
IClipboardSupport newClipboardSupport(EPackage ePackage) { return
support; } }
Finally, an extension is written to register the factory against
the namespace URI of the Library EPackage:
<extension
point="org.eclipse.gmf.runtime.emf.clipboard.core.clipboardSupport">
<factory
class="org.eclipse.gmf.examples.runtime.emf.clipboard.library.LibraryClipboardSupportFactory"
nsURI="https:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0"
priority="highest"/> </extension>
[
back to top]
Once Clipboard support has been added for a metamodel, it is
relatively trivial to start copying and pasting EObjects. When
copying EObjects, they are serialized into the form of a string
where they may be later pasted into another location:
String clipString = ClipboardUtil.copyElementsToString(
getSelectedObjects(), null, new NullProgressMonitor());
The clipString may be passed around using some simple
data-passing scheme, IPC scheme or given to the operating system
clipboard using the org.eclipse.swt.dnd.Clipboard class in a
specialized org.eclipse.swt.dnd.Transfer object.
[
back to top]
After retrieving the original string from a copy operation, it
is an equivalently trivial task to paste the EObjects back into
another location underneath another EObject. The advantage of this
paste operation in the context of the library metamodel is that
authors will be pasted along with their books into other
libraries.
EObject target; Collection pasted =
ClipboardUtil.pasteElementsFromString( clipString, target, null,
new NullProgressMonitor()); if (pasted == null || pasted.isEmpty())
{ System.out.println("A EMF clipboard paste error has occurred. No
EObjects have been pasted."); }
[
back to top]
In this tutorial, we did the following:
- Created an EMF resource that will satisfy the prerequisites for
EMF clipboard
- Developed the necessary clipboard support for library
metamodel
- Copied a group of EObjects into a string object
- Pasted a group of EObjects from the string object
Copyright (c) 2000,2005
IBM Corporation and others. All Rights Reserved.