# Tutorial: EMF Clipboard Copy and Paste

Version: 0.1 | Date: June 08, 2005

## Contents

- Overview
- References
- Introduction
- EMF Resource Setup
- Clipboard Support Setup
- Copying EObjects
- Pasting EObjects
- Summary

## Overview

[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.

## References

[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.

## Introduction

[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.

## EMF Resource Setup

[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>

## Clipboard Support Setup

[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="http:///org/eclipse/emf/examples/library/extlibrary.ecore/1.0.0" priority="highest"/> </extension>

## Copying EObjects

[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.

## Pasting EObjects

[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."); }

## Summary

[back to top]

In this tutorial, we did the following:

1. Created an EMF resource that will satisfy the prerequisites for EMF clipboard
2. Developed the necessary clipboard support for library metamodel
3. Copied a group of EObjects into a string object
4. Pasted a group of EObjects from the string object