package com.openMap1.mapper.views; import java.util.ArrayList; import java.util.Iterator; import java.util.Hashtable; import java.util.StringTokenizer; import java.util.Vector; import java.io.IOException; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.graphics.Image; import org.eclipse.core.runtime.IPath; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.TreeViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuManager; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IMemento; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.IViewSite; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.dialogs.SaveAsDialog; import org.eclipse.emf.ecore.EAnnotation; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EModelElement; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.ENamedElement; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; import org.eclipse.emf.edit.ui.util.EditUIUtil; import org.eclipse.xsd.XSDNamedComponent; import com.openMap1.mapper.presentation.MapperEditor; import com.openMap1.mapper.presentation.QueryEditor; import com.openMap1.mapper.presentation.MapperActionBarContributor; import com.openMap1.mapper.util.EclipseFileUtil; import com.openMap1.mapper.util.FileUtil; import com.openMap1.mapper.util.GenUtil; import com.openMap1.mapper.util.ModelUtil; import com.openMap1.mapper.util.Timer; import com.openMap1.mapper.mapping.MDLBase; import com.openMap1.mapper.mapping.objectMapping; import com.openMap1.mapper.util.messageChannel; import com.openMap1.mapper.util.SystemMessageChannel; import com.openMap1.mapper.actions.CopySimplificationsAction; import com.openMap1.mapper.actions.ImportSimplificationsAction; import com.openMap1.mapper.actions.MakeEcoreMappingsAction; import com.openMap1.mapper.actions.MergeModelsAction; import com.openMap1.mapper.actions.PasteSimplificationsAction; import com.openMap1.mapper.actions.RemoveSimplificationsAction; import com.openMap1.mapper.core.MapperException; import com.openMap1.mapper.MappedStructure; import com.openMap1.mapper.ParameterClass; /** * Shows a tree-structured view of the mapped class model, and the mappings. * * Usually the tree structure is the class hierarchy. * For HL7 RMIM applications, it is the RMIM tree. * * @author robert * */ public class ClassModelView extends ViewPart implements ISelectionChangedListener{ private boolean tracing = false; private boolean writeMappingsColumn = true; private Timer timer; private TreeViewer viewer; private ArrayList<EObject> modelRoot = new ArrayList<EObject>(); private ArrayList<LabelledEClass> rmimRoot = new ArrayList<LabelledEClass>(); /* record the class tree children of each named class in the model, including 'Object' * These are the classes which have that class as 'main' superclass - only for purposes * of tree display. Multiple inheritance of attributes and associations is not ignored. */ private Hashtable<String,ArrayList<EClass>> childVanillaClasses; /** the package which is the root of the model */ public EPackage ecoreRoot() {return ecoreRoot;} private EPackage ecoreRoot; private URI classModelURI = null; /** the URI address of the stored class model */ public URI classModelURI() {return classModelURI;} private URI mappingSetURI = null; /** the URI address of the stored mapping set, if the view is currently linked to one */ public URI mappingSetURI() {return mappingSetURI;} public void setMappingSetURI(URI uri) {mappingSetURI = uri; queryURI = null;} private URI queryURI = null; /** the URI address of the stored query, if the view is currently linked to one */ public URI queryURI() {return queryURI;} public void setQueryURI(URI uri) {queryURI = uri; mappingSetURI = null;} private MapperEditor mapperEditor = null; public MapperEditor mapperEditor() {return mapperEditor;} private MDLBase mdlBase = null; public LabelledEClass topLabelledEClass() {return topLabelledEClass;} private LabelledEClass topLabelledEClass; private Hashtable<String,Vector<String>> parentTable; //--------------------------------------------------------------------------------------------- // constructor and initialisation //--------------------------------------------------------------------------------------------- public ClassModelView() { } /** * Callback to create the viewer and initialize it. */ public void createPartControl(Composite parent) { trace("creating part control"); viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); // this column shows the tree , and gets its label provider from the viewer TreeViewerColumn tv1 = new TreeViewerColumn(viewer,SWT.LEFT); tv1.getColumn().setWidth(300); tv1.getColumn().setText("Class"); TreeViewerColumn tv2 = null; if (writeMappingsColumn) { tv2 = new TreeViewerColumn(viewer,SWT.LEFT); tv2.getColumn().setWidth(300); tv2.getColumn().setText("Mappings/Templates"); tv2.setLabelProvider(new MappingLabelProvider()); } // set up this part to be a selection provider for editors and other views getSite().setSelectionProvider(viewer); //make this view listen to its own selections, to remember what was selected viewer.addPostSelectionChangedListener(this); if (classModelURI != null) try{ // set up the class model and connect the viewer to it EObject root = FileUtil.getEMFModelRoot(classModelURI); if (!(root instanceof EPackage)) throw new MapperException("Class model root is not an EPackage"); ecoreRoot = (EPackage)root; // set up the appropriate content provider and label provider for the class model setupViewer((EPackage)root, classModelURI); /* if at the previous shutdown, the class model view was connected to a mapper editor, * re-connect it to the same one. */ if (mappingSetURI != null) { MapperEditor me = WorkBenchUtil.getMapperEditor(mappingSetURI.toString()); if ((me != null) && (root != null)) viewer.addPostSelectionChangedListener((MapperActionBarContributor)me.getActionBarContributor()); } /* if at the previous shutdown, the class model view was connected to a query editor, * re-connect it to the same one. */ if (queryURI != null) { QueryEditor qe = WorkBenchUtil.getQueryEditor(queryURI.toString()); if ((qe != null) && (root != null)) connectToQueryEditor(qe); } } catch (Exception ex) { System.out.println("Failed to open class model for class model view, at location '" + classModelURI.toString() + "'"); } // make the menu actions makeActions(); contributeToActionBars(); } /* connect to the Attribute and Association Views, if you can; * 'false' means do not force creation; Eclipse objects to the potential recursion */ private void connectToFeatureViews() { AttributeView atv = WorkBenchUtil.getAttributeView(false); if (atv != null) connectToAttributeView(atv); AssociationView asv = WorkBenchUtil.getAssociationView(false); if (asv != null) connectToAssociationView(asv); } private void setupViewer(EPackage ecoreRoot, URI uri) { trace("Set up viewer"); // viewing a class model as an RMIM tree if (isRMIMRoot(ecoreRoot)) { setRMIMClassModel(ecoreRoot, uri); setupRMIMViewer(viewer); } // viewing a class model grouped by packages else if (groupInPackages(ecoreRoot)) { setPackagedClassModel(ecoreRoot,uri); setupPackagedViewer(viewer); } // viewing a class model as an inheritance hierarchy else { setVanillaClassModel(ecoreRoot,uri); setupVanillaViewer(viewer); } // connect to the Associations and Attributes views connectToFeatureViews(); } /** * Set up the TreeViewer with the appropriate content provider and label provider, * for a vanilla class model; the tree structure follows the inheritance structure * @param viewer */ private void setupVanillaViewer(TreeViewer viewer) { trace("set up vanilla viewer"); viewer.setContentProvider(new ClassModelViewContentProvider()); viewer.setLabelProvider(new ClassModelViewLabelProvider()); viewer.getTree().setHeaderVisible(true); viewer.getTree().setLinesVisible(true); } /** * Set up the TreeViewer with the appropriate content provider and label provider, * for a class model to be viewed by package * @param viewer */ private void setupPackagedViewer(TreeViewer viewer) { trace("set up packaged viewer"); viewer.setContentProvider(new PackagedViewContentProvider()); viewer.setLabelProvider(new PackagedViewLabelProvider()); viewer.getTree().setHeaderVisible(true); viewer.getTree().setLinesVisible(true); } /** * Set up the TreeViewer with the appropriate content provider and label provider, * for an RMIM class model; the tree structure follows the RMIM associations * @param viewer */ private void setupRMIMViewer(TreeViewer viewer) { trace("set up RMIM viewer"); viewer.setContentProvider(new RMIMViewContentProvider()); viewer.setLabelProvider(new RMIMViewLabelProvider()); viewer.getTree().setHeaderVisible(true); viewer.getTree().setLinesVisible(true); } /** * * @param root * @return true if the class model is to be shown in an RMIM hierarchy view */ public static boolean isRMIMRoot(EObject root) { if ((root != null) && (root instanceof EPackage)) return (ModelUtil.getMIFAnnotation((EPackage)root,"RMIM") != null); return false; } /* replaced by calls to ModelUtil.getMIFAnnotation private String getAnnotation(EModelElement eo, String key) { String mifNamespaceURI = "urn:hl7-org:v3/mif2"; String value = null; EAnnotation ann = eo.getEAnnotation(mifNamespaceURI); if (ann != null) value = ann.getDetails().get(key); return value; } */ /** * * @param eo an EMF model object - root of the package tree * @return true if the classes are to be viewed grouped by packages, * rather than by an inheritacne hierarchy */ private Boolean groupInPackages(EModelElement eo) { boolean group = false; EAnnotation ann = eo.getEAnnotation("urn:com.openMap1.mapper"); String value = null; if (ann != null) value = ann.getDetails().get("viewByPackages"); if (value != null)group = (value.equals("true")); return group; } /** * do the startup activities when this view is associated with a mapping set * and its active mapper editor * @param MapperEditor me the active mapper editor * @param EObject umlRoot the root of the UML model being shown in this view * @param String path the path to the UML model file, for use in the view title */ public void initiateForMapperEditor(MapperEditor me, EObject root, String classModelURIString) { trace("initiate for mapper editor"); if ((root != null) && (root instanceof EPackage)) { ecoreRoot = (EPackage)root; URI uri = URI.createURI(classModelURIString); setupViewer(ecoreRoot,uri); setContentDescriptionFromURL(classModelURIString); setMappingSetURI(EditUIUtil.getURI(me.getEditorInput())); // hook up the mapper editor so it can listen to selections in this class model view viewer.addPostSelectionChangedListener((MapperActionBarContributor)me.getActionBarContributor()); // record the editor mapperEditor = me; mdlBase = null; viewer.refresh(); } else if (root == null) { //System.out.println("Class Model Root is null in ClassModelView.initiateForMapperEditor" ); } else if (!(root instanceof EPackage)) { System.out.println("Class Model Root is not an EPackage, but a " + root.eClass().getName()); return; } } /** * do the startup activities when this view is associated with a query * and its active query editor * @param QueryEditor qe the active query editor * @param EObject umlRoot the root of the UML model being shown in this view * @param String path the path to the query file, for use in the view title */ public void initiateForQueryEditor(QueryEditor qe, EObject root, String classModelURIString) { trace("initiate for query editor"); if (timer == null) timer = new Timer("Class model view"); timer.start(Timer.COMPILE); if ((root != null) && (root instanceof EPackage)) { this.ecoreRoot = (EPackage)root; URI uri = URI.createURI(classModelURIString); setupViewer(ecoreRoot,uri); setContentDescriptionFromURL(classModelURIString); setQueryURI(EditUIUtil.getURI(qe.getEditorInput())); connectToQueryEditor(qe); mapperEditor = null; // sever any previous link to a mapping set mdlBase = null; viewer.refresh(); } else if (root == null) { System.out.println("Class Model Root is null in ClassModelView.initiateForQueryEditor" ); } else if (!(root instanceof EPackage)) { System.out.println("Ecore Class Model Root is not an EPackage, but a " + root.eClass().getName()); return; } } /** * hook up the query editor so it can listen to selections in this class model view * @param qe */ public void connectToQueryEditor(QueryEditor qe) { viewer.addPostSelectionChangedListener(qe); mapperEditor = null; // sever any previous link to a mapping set } /** * hook up the Attribute View so it can listen to selections in this class model view * @param qe */ public void connectToAttributeView(AttributeView av) {viewer.addPostSelectionChangedListener(av);} /** * hook up the Association View so it can listen to selections in this class model view * @param qe */ public void connectToAssociationView(AssociationView av) {viewer.addPostSelectionChangedListener(av);} /** * Strip out a file name from a URL, and use it as the description of the view */ public void setContentDescriptionFromURL(String url) {super.setContentDescription(FileUtil.getFileName(url));} //--------------------------------------------------------------------------------------------- // Setting up a class model to be viewed in packages for the content provider and label provider //--------------------------------------------------------------------------------------------- /** * record a UML class model in the form used by the ViewContentProvider - * in the Hashtable of 'main' subclasses. * This method assumes the class model is in a single package * * @param root the root object of the UML model, assumed to be an EPackage */ public void setPackagedClassModel(EPackage root, URI classModelURI) { trace("Set packaged class model"); this.classModelURI = classModelURI; modelRoot = new ArrayList<EObject>(); modelRoot.add(root); /* ensure the viewer is expecting the right kind of content provider and label provider, * and give it the root of the tree. */ setupPackagedViewer(viewer); viewer.setInput(modelRoot); } //--------------------------------------------------------------------------------------------- // content provider and label provider for a class model to be viewed by package //--------------------------------------------------------------------------------------------- /* * The provider (= adapter) which adapts the model (in this case an EMF model) * to the viewer (in this case a TreeViewer). * There are two parts - a content provider which provides the tree structure * and a label provider which provides the icons and text */ class PackagedViewContentProvider implements IStructuredContentProvider, ITreeContentProvider { // called by viewer.setInput(Object) but need do nothing public void inputChanged(Viewer v, Object oldInput, Object newInput) {} public void dispose() {trace("packaged view dispose");} public Object[] getElements(Object parent) { // the only child of modelroot is the EPackage object if (parent.equals(modelRoot)) { return arrayOf(modelRoot); } // for all other objects (including the package) use getChildren return getChildren(parent); } /** * child EObjects: * For a package, the first children are its sub-packages; next children are the classes in it * For any class, the there are no children * For any other EObject, get the EObject child nodes */ public Object [] getChildren(Object parent) { ArrayList<EObject> result = new ArrayList<EObject>(); if (parent instanceof EPackage) { EPackage pack = (EPackage)parent; // sub-packages are the first children for (Iterator<EPackage> ip = pack.getESubpackages().iterator();ip.hasNext();) result.add(ip.next()); // next follow classes in the package for (Iterator<EClassifier> ic = pack.getEClassifiers().iterator();ic.hasNext();) { EClassifier ec = ic.next(); if (ec instanceof EClass) result.add(ec); } } return arrayOf(result); } /** * get the parent object of any object in the tree. For EClasses, this is the * its containing package. for packages, the parent is its superpackage */ public Object getParent(Object child) { EObject parent = null; if (child instanceof EClass) { parent = ((EClass)child).getEPackage(); } else if (child instanceof EPackage) { parent = ((EPackage)child).getESuperPackage(); if (parent == null) parent = ecoreRoot; } return parent; } public boolean hasChildren(Object parent) { return(getChildren(parent).length > 0); } } // end of class PackagedViewContentProvider class PackagedViewLabelProvider extends LabelProvider implements ITableLabelProvider{ public String getText(Object obj) { if (obj instanceof EObject) return getTextLabel((EObject)obj); return "not an EObject"; } public String getColumnText(Object obj, int columnIndex) { switch(columnIndex){ case 0: return getText(obj); case 1: { if (obj instanceof EClass) return getObjectMappingText((EClass)obj); } } return (""); } public Image getColumnImage(Object obj, int columnIndex) { switch(columnIndex){ case 0: return getImage(obj); case 1: return null; } return null; } public Image getImage(Object obj) { Image im = null; // default 'Folder' image if type is not recognised (eg packages) String imageKey = ISharedImages.IMG_OBJ_FOLDER; im = PlatformUI.getWorkbench().getSharedImages().getImage(imageKey); // images for Ecore classes if (obj instanceof EClass) {im = FileUtil.getImage("Class");} return im; } private String getTextLabel(EObject eo) { if (eo instanceof ENamedElement) // for named parts of Ecore models: classes and packages { return ((ENamedElement)eo).getName(); } else return eo.eClass().getName(); } } //--------------------------------------------------------------------------------------------- // Setting up a vanilla class model for the content provider and label provider //--------------------------------------------------------------------------------------------- /** * record a UML class model in the form used by the ViewContentProvider - * in the Hashtable of 'main' subclasses. * This method assumes the class model is in a single package * * @param root the root object of the UML model, assumed to be an EPackage */ public void setVanillaClassModel(EPackage root, URI classModelURI) { trace("Set vanilla class model"); this.classModelURI = classModelURI; childVanillaClasses = new Hashtable<String,ArrayList<EClass>>(); modelRoot = new ArrayList<EObject>(); modelRoot.add(root); addClasses(root); /* ensure the viewer is expecting the right kind of content provider and label provider, * and give it the root of the tree. */ setupVanillaViewer(viewer); viewer.setInput(modelRoot); } /** * add the classes in a package to the model, and recursively add * the classes in all its sub-packages * @param aPackage */ private void addClasses(EPackage aPackage) { // add the classes in this package for (Iterator<EObject> it = aPackage.eContents().iterator(); it.hasNext();) { EObject child = it.next(); // record each Class under its superclasses, or under class Object if (child instanceof EClass) recordVanillaClass((EClass)child); // ignore other things in the package - imports etc. else {} } //do the same recursively for its sub-packages for (Iterator<EPackage> it = aPackage.getESubpackages().iterator();it.hasNext();) addClasses(it.next()); } /** * record each class under its first superclass, or under class 'Object' if it has none * @param c */ private void recordVanillaClass(EClass c) { if (c.getESuperTypes().size() == 0) { addVanillaClassToSubClasses("Object",c); } // if the class has more than one superclass, choose the main superclass that it inherits most from else addVanillaClassToSubClasses(getMainSuperClass(c).getName(),c); } /** * When an EClass has more than one superclass, the 'main' superclass, * which will be its parent in the tree diagram of the mapped class model, is the * superclass with the largest number of features (i.e from which which it inherits most features). * When there is a tie for number of features, the class whose name is lexically first wins. * @param c the EClass whose main superclass is sought * @return the main EClass, or null if there are no superclasses */ private EClass getMainSuperClass(EClass c) { EClass best = null; for (Iterator<EClass> it = c.getESuperTypes().iterator();it.hasNext();) { EClass current = it.next(); if (best == null) {best = current;} else if (current.getFeatureCount() > best.getFeatureCount()) {best = current;} else if ((current.getFeatureCount() == best.getFeatureCount()) &&(current.getName().compareTo(best.getName()) < 0)) {best = current;} // compareTo: The result is a negative integer if this String object lexicographically precedes the argument string } return best; } /** * record a class under one of its superclasses * @param superClass * @param c */ private void addVanillaClassToSubClasses(String superClass,EClass c) { ArrayList<EClass> subs = childVanillaClasses.get(superClass); if (subs == null) subs = new ArrayList<EClass>(); ArrayList<EClass> newSubs = addAClass(subs,c); childVanillaClasses.put(superClass,newSubs); } /** * @param subs existing list of subclasses * @param c new subclass * @return enlarged list of subclasses, preserving alphabetical order of class names */ private ArrayList<EClass> addAClass(ArrayList<EClass> subs, EClass c) { ArrayList<EClass> newSubs = new ArrayList<EClass>(); String cName = c.getName(); boolean placed = false; // new class has not yet been added for (Iterator<EClass> it = subs.iterator();it.hasNext();) { EClass next = it.next(); // if the new class comes before the current class and has not been added, add it once if ((next.getName().compareTo(cName) > 0) && (!placed)) { newSubs.add(c); placed = true; } // add the current class in any case newSubs.add(next); } // if the new class is last, add it if (!placed) newSubs.add(c); return newSubs; } //--------------------------------------------------------------------------------------------- // content provider and label provider for a vanilla class model //--------------------------------------------------------------------------------------------- /* * The provider (= adapter) which adapts the model (in this case an EMF model) * to the viewer (in this case a TreeViewer). * There are two parts - a content provider which provides the tree structure * and a label provider which provides the icons and text */ class ClassModelViewContentProvider implements IStructuredContentProvider, ITreeContentProvider { // called by viewer.setInput(Object) but need do nothing public void inputChanged(Viewer v, Object oldInput, Object newInput) {} public void dispose() {trace("vanilla dispose");} public Object[] getElements(Object parent) { // the only child of modelroot is the EPackage object if (parent.equals(modelRoot)) { return arrayOf(modelRoot); } // for all other objects (including the package) use getChildren return getChildren(parent); } /** * child EObjects: * For the package, the children are the classes with no superclass * For any class, the children are (a) the subclasses, (b) the association markers (c) the properties * For any other EObject, get the EObject child nodes */ public Object [] getChildren(Object parent) { ArrayList<EObject> result = new ArrayList<EObject>(); String className = "NoClass"; // there will be no entry in subClasses map for this class name // direct children of the package are the subclasses of 'Object' = classes with no superclass if (parent instanceof EPackage) {className = "Object";} else if (parent instanceof EClass) {className = ((EClass)parent).getName();} if (childVanillaClasses.get(className) != null) for (Iterator<EClass> it = childVanillaClasses.get(className).iterator(); it.hasNext();) {result.add(it.next());} return arrayOf(result); } /** * get the parent object of any object in the tree. For EClasses, this is the * 'main' superclass, or the package if there are no superclasses */ public Object getParent(Object child) { EObject parent = null; if (child instanceof EClass) { parent = getMainSuperClass((EClass)child); if (parent == null) parent = ecoreRoot; } return parent; } public boolean hasChildren(Object parent) { return(getChildren(parent).length > 0); } } // end of class ViewContentProvider private EObject[] arrayOf (ArrayList<EObject> aList) {return (EObject[])aList.toArray(new EObject[aList.size()]);} class ClassModelViewLabelProvider extends LabelProvider implements ITableLabelProvider{ public String getText(Object obj) { if (obj instanceof EObject) return getTextLabel((EObject)obj); return "not an EObject"; } public String getColumnText(Object obj, int columnIndex) { switch(columnIndex){ case 0: return getText(obj); case 1: { if (obj instanceof EClass) return getObjectMappingText((EClass)obj); } } return (""); } public Image getColumnImage(Object obj, int columnIndex) { switch(columnIndex){ case 0: return getImage(obj); case 1: return null; } return null; } public Image getImage(Object obj) { Image im = null; // default 'Folder' image if type is not recognised (eg packages) String imageKey = ISharedImages.IMG_OBJ_FOLDER; im = PlatformUI.getWorkbench().getSharedImages().getImage(imageKey); // images for Ecore classes if (obj instanceof EClass) {im = FileUtil.getImage("Class");} return im; } private String getTextLabel(EObject eo) { if (eo instanceof ENamedElement) // for named parts of Ecore models: classes and packages { return ((ENamedElement)eo).getName(); } else if (eo instanceof XSDNamedComponent) // for XML schemas { return eo.eClass().getName() + ": " + ((XSDNamedComponent)eo).getName(); } else return eo.eClass().getName(); } } //--------------------------------------------------------------------------------------------- // setup for an RMIM class model //--------------------------------------------------------------------------------------------- /** * find the LabelledEClass which is the root of the class tree of the RMIM */ public static LabelledEClass getRootLabelledEClass(EPackage topPackage) { LabelledEClass rootLabelledEClass = null; /* find the one EClass marked as the entry class; * iterate over all nested packages to find it. */ for (Iterator<EPackage> ip = topPackage.getESubpackages().iterator();ip.hasNext();) { EPackage rmimPackage = ip.next(); // Usually there is on package inside the top package. Iterate over classes in any packages found for (Iterator<EClassifier> ic = rmimPackage.getEClassifiers().iterator(); ic.hasNext();) { EClassifier ec = ic.next(); if ((ec instanceof EClass) && (ModelUtil.getMIFAnnotation(ec, "entry") != null)) { rootLabelledEClass = new LabelledEClass((EClass)ec, null, null); } } } /* if the class is not found in any packages below the top package (possibly because there are no such packages) * look for the class directly in the top package. */ if (rootLabelledEClass == null) { // iterate over classes in the top package for (Iterator<EClassifier> ic = topPackage.getEClassifiers().iterator(); ic.hasNext();) { EClassifier ec = ic.next(); if ((ec instanceof EClass) && (ModelUtil.getMIFAnnotation(ec, "entry") != null)) { rootLabelledEClass = new LabelledEClass((EClass)ec, null, null); } } } return rootLabelledEClass; } /** * @param topPackage the root package of the RMIM class model, * which has a single layer of sub-packages below it */ public void setRMIMClassModel(EPackage topPackage, URI classModelURI) { timer = new Timer("Class model view"); this.classModelURI = classModelURI; rmimRoot = new ArrayList<LabelledEClass>(); trace("Setting RMIM " + classModelURI); parentTable = ModelUtil.parentTable(topPackage); topLabelledEClass = getRootLabelledEClass(topPackage); rmimRoot.add(topLabelledEClass); /* ensure the viewer is expecting the right kind of content provider and label provider, * and give it the root of the tree. */ setupRMIMViewer(viewer); viewer.setInput(rmimRoot); /* Vector<String> noDups = new Vector<String>(); int maximum = 100000000; int dataTypeDepth = 0; int start = 0; int leafCount = countLeafNodes(start,dataTypeDepth,maximum,topLabelledEClass.eClass(),noDups); System.out.println("Leaf nodes in class model at '" + classModelURI.toString() + "': " + leafCount); */ } /** * count leaf nodes in the RMIM class tree, truncating any recursion, * ignoring text content of elements, and ignoring occurrences of data type ANY * @param start the count up to this point * @param maximum a maximum it will not count beyond, to avoid memory overflow * @param theClass class whose subtree is being added to the count * @param noDups to truncate recursion whenever the same class name is encountered twice * @return */ @SuppressWarnings("unused") private int countLeafNodes(int start,int dataTypeDepth, int maximum, EClass theClass,Vector<String> noDups) { // control depth into data type classes int MAX_DATATYPE_DEPTH = 1; int nextDTDepth = dataTypeDepth; if (theClass.getEPackage().getName().equals("datatypes"))nextDTDepth++; if (nextDTDepth > MAX_DATATYPE_DEPTH) return start; // control recursion of RMIM classes Vector<String> nextNoDups = new Vector<String>(); for (Iterator<String> it = noDups.iterator();it.hasNext();)nextNoDups.add(it.next()); nextNoDups.add(theClass.getName()); // attribute leaf nodes of this class int count = start + theClass.getEAttributes().size(); // leaf nodes of classes in subtrees for (Iterator<EReference> ir = theClass.getEAllReferences().iterator();ir.hasNext();) { EReference ref = ir.next(); EClassifier ec = ref.getEType(); if ((ec instanceof EClass) && (ref.isContainment()) && (count < maximum)) { EClass next = (EClass)ec; String name = next.getName(); if ((!GenUtil.inVector(name, nextNoDups)) && (!name.equals("ANY"))) count = countLeafNodes(count,nextDTDepth,maximum, next,nextNoDups); } } return count; } //--------------------------------------------------------------------------------------------- // content provider and label provider for an RMIM class model //--------------------------------------------------------------------------------------------- /* * The provider (= adapter) which adapts the model (in this case an EMF model) * to the viewer (in this case a TreeViewer). * There are two parts - a content provider which provides the tree structure * and a label provider which provides the icons and text */ class RMIMViewContentProvider implements IStructuredContentProvider, ITreeContentProvider { // called by viewer.setInput(Object) but need do nothing public void inputChanged(Viewer v, Object oldInput, Object newInput) {} public void dispose() {trace("RMIM dispose");} public Object[] getElements(Object parent) { // the only child of rmimRoot is the EPackage object if (parent.equals(rmimRoot)) { return array2Of(rmimRoot); } // for all other objects (including the package) use getChildren return getChildren(parent); } /** * child LabelledEClass objects: * For the package, the children are the RMIM root class * For any other LabelledEClass, get the LabelledEClass nodes for the classes linked by RMIM associations */ public Object [] getChildren(Object parent) { ArrayList<LabelledEClass> children = new ArrayList<LabelledEClass>(); if (parent instanceof LabelledEClass) children = ((LabelledEClass)parent).getChildren(); return array2Of(children); } private LabelledEClass[] array2Of(ArrayList<LabelledEClass> aList) {return (LabelledEClass[])aList.toArray(new LabelledEClass[aList.size()]);} /** * get the parent object of any object in the tree. */ public Object getParent(Object child) { LabelledEClass parent = null; if (child instanceof LabelledEClass) { parent = ((LabelledEClass)child).parent(); if (parent == null) { trace("null parent"); // parent = (LabelledEClass)child; // ?? } } return parent; } public boolean hasChildren(Object parent) { return(getChildren(parent).length > 0); } } // end of class RMIMViewContentProvider class RMIMViewLabelProvider extends LabelProvider implements ITableLabelProvider{ public String getColumnText(Object obj, int columnIndex) { switch(columnIndex){ case 0: return getText(obj); case 1: { if (obj instanceof LabelledEClass) return getObjectMappingText((LabelledEClass)obj); } } return (""); } public Image getColumnImage(Object obj, int columnIndex) { switch(columnIndex){ case 0: return getImage(obj); case 1: return null; } return null; } // label an RMIM class by the association leading to it, followed by the class name public String getText(Object obj) { if (obj instanceof LabelledEClass) { LabelledEClass lc = (LabelledEClass)obj; String name = lc.eClass().getName(); if (lc.associationName() != null) name = lc.associationName() + "." + name; EPackage CMETPackage = lc.eClass().getEPackage(); String CMETName = ModelUtil.getEAnnotationDetail(CMETPackage, "name"); if ((CMETName != null) && (!CMETName.equals(""))) name = name + " (" + CMETName + ")"; return name; } return "not a LabelledEClass"; } public Image getImage(Object obj) { Image im = null; // default 'Folder' image if type is not recognised String imageKey = ISharedImages.IMG_OBJ_FOLDER; im = PlatformUI.getWorkbench().getSharedImages().getImage(imageKey); // images for RMIM classes and data type classes if (obj instanceof LabelledEClass) { EClass theClass = ((LabelledEClass)obj).eClass(); String RIMClass = ModelUtil.getMIFAnnotation(theClass,"RIM Class"); String imageName = "Class" + getColour(RIMClass); // "ClassGreen", "ClassRed", etc. String packageName = theClass.getEPackage().getName(); if (packageName.equals("datatypes")) imageName = "DataType"; im = FileUtil.getImage(imageName); } return im; } /** * @param RIMClass * @return a string for the colour which clones of that class have in an RMIM diagram */ private String getColour(String RIMClass) { String colour = ""; if (RIMClass != null) { if (GenUtil.inArray(RIMClass, redClasses)) colour = "Red"; if (GenUtil.inArray(RIMClass, pinkClasses)) colour = "Pink"; if (GenUtil.inArray(RIMClass, blueClasses)) colour = "Blue"; if (GenUtil.inArray(RIMClass, yellowClasses)) colour = "Yellow"; if (GenUtil.inArray(RIMClass, greenClasses)) colour = "Green"; } return colour; } } // HL7 colouring of RIM classes static String[] redClasses = {"Act", "ControlAct", "Observation","DiagnosticImage","PublicHealthCase", "Supply", "Diet", "DeviceTask", "FinancialContract","InvoiceElement","FinancialTransaction","Account", "PatientEncounter","SubstanceAdministration","WorkingList","Exposure", "Procedure"}; static String[] pinkClasses = {"ActRelationship"}; static String[] blueClasses = {"Participation","ManagedParticipation"}; static String[] yellowClasses = {"Role", "RoleLink","Patient", "LicensedEntity","QualifiedEntity","Access","Employee"}; static String[] greenClasses = {"Entity","Place","Person", "LivingSubject","NonPersonLivingSubject","Organization", "Material","Device","ManufacturedMaterial","Container"}; //---------------------------------------------------------------------------------------- // Label Provider for mapping columns //---------------------------------------------------------------------------------------- /** * @return MDLBase the mappings in the mapping set being edited, * with fast retrieval methods */ public MDLBase mdlBase() { // if there is no current Mapper editor, return no MDLBase if (mapperEditor == null) return null; if (mdlBase == null) refreshMDLBase(); else if (mdlBase != null) { // if the mappings have been altered since the MDBase was last refreshed, refresh it now if (!WorkBenchUtil.mappingRoot(mapperEditor).classModelViewIsRefreshed()) refreshMDLBase(); } return mdlBase; } private void refreshMDLBase() { messageChannel mc = new SystemMessageChannel(); try { mdlBase = new MDLBase(WorkBenchUtil.mappingRoot(mapperEditor),mc); // record that the MDLBase has been refreshed WorkBenchUtil.mappingRoot(mapperEditor).setClassModelViewIsRrefreshed(true); } catch (MapperException ex) {GenUtil.surprise(ex, "ClassModelView.mdlBase");} } /** * @param ec a class * @return a text description of the object mappings to the class and its * subclasses, of the form (S)paths where S is the number of object mappings to * its proper subclasses, and 'paths' is the concatenated paths of the mappings to the class itself. */ private String getObjectMappingText(EClass ec) { String end = "; "; String text = ""; if (mdlBase() != null) try { String className = ModelUtil.getQualifiedClassName(ec); for (Iterator<objectMapping> it = mdlBase().objectMappings(className).iterator(); it.hasNext();) { objectMapping om = it.next(); String path = om.nodePath().stringForm(); if (om.hasSubset()) path = path + "(" + om.subset() + ")"; text = text + path + end; } int mappingsToSubclasses = 0; for (Iterator<EClass> it = mdlBase().ms().getAllSubClasses(ec).iterator(); it.hasNext();) { EClass ed = it.next(); if ((ec.isSuperTypeOf(ed)) && (ec != ed)) { String subclassName = ModelUtil.getQualifiedClassName(ed); mappingsToSubclasses = mappingsToSubclasses + mdlBase().objectMappings(subclassName).size(); } } if (mappingsToSubclasses > 0) text = "[" + mappingsToSubclasses + "] " + text; } catch (MapperException ex) {} if (text.endsWith(end)) text = text.substring(0,text.length() - end.length()); return text; } /** * @param lec a labelled EClass * @return a text description of the object mappings to this occurrence of the class * at this point of the RMIM tree; * or its template id if it has one */ private String getObjectMappingText(LabelledEClass lec) { String path= ""; EClass ec = lec.eClass(); LabelledEClass parent = lec.parent(); String className = ModelUtil.getQualifiedClassName(ec); // modification to show template ids in stead of a mapping, if there are any String templateId = ModelUtil.getMIFAnnotation(ec, "template"); if (templateId != null) { boolean found = true; int index = 1; // find all annotations with keys 'template_1','template_2', etc. while (found) { String nextId = ModelUtil.getMIFAnnotation(ec, "template_" + new Integer(index).toString()); if (nextId != null) templateId = templateId + "; " + nextId; else found = false; index++; } return templateId; } /* a class may only show some mapping text if (a) it is the parameter class * of the mapping set or (b) it is the root class or (c) its parent has * a mapping (already determined, as the parent node is visible)*/ boolean eligible = ((isParameterClass(lec))||(parent == null)|| ((parent != null) && (parent.isMapped()))); if ((mdlBase() != null) && eligible) try { // don't carry on looking after you have found the right object mapping boolean isLinkedToParent = false; // there may be many object mappings to this class, most of which are elsewhere in the tree for (Iterator<objectMapping> it = mdlBase().objectMappings(className).iterator(); it.hasNext();) { objectMapping om = it.next(); if (!isLinkedToParent) { // top of the RMIM tree, or top (parameter) class of an imported mapping set if ((isParameterClass(lec))|(parent == null)) path = setTheObjectMappingText(lec, om); /* for any class not at the top of the RMIM tree, its parent class must be * mapped, and the named association to this class must also be mapped * with the correct subsets. */ else { String parentClass= ModelUtil.getQualifiedClassName(parent.eClass()); String parentSubset = parent.getMappedSubset(); isLinkedToParent = (mdlBase().representsAssociationRoleLocally(parentClass, parentSubset, lec.associationName(), className,om.subset())); if (isLinkedToParent) path = setTheObjectMappingText(lec, om); } } } } catch (Exception ex) {} // odd null pointers can occur when mappings have been deleted return path; } private String setTheObjectMappingText(LabelledEClass lec, objectMapping om) { String path = om.nodePath().stringForm(); if (om.hasSubset()) path = path + "(" + om.subset() + ")"; lec.setObjectMappingText(path); lec.setMappedSubset(om.subset()); return path; } /** * * @param lec * @return true if the EClass is the parameter class of the mapping set */ private boolean isParameterClass(LabelledEClass lec) { boolean isParamClass = false; if (mapperEditor != null) { MappedStructure ms = WorkBenchUtil.mappingRoot(mapperEditor); if (ms.getParameterClasses().size() > 0) { ParameterClass pc = ms.getParameterClasses().get(0); String paramClassName = pc.getQualifiedClassName(); String mappedClassName = ModelUtil.getQualifiedClassName(lec.eClass()); isParamClass = (mappedClassName.equals(paramClassName)); } } return isParamClass; } /** * * @return if the mapping set has a parameter class, return the * qualified parameter class name; otherwise return null */ private String parameterClassName() { String paramClassName = null; if (mapperEditor != null) { MappedStructure ms = WorkBenchUtil.mappingRoot(mapperEditor); if (ms.getParameterClasses().size() > 0) { ParameterClass pc = ms.getParameterClasses().get(0); paramClassName = pc.getQualifiedClassName(); } } return paramClassName; } /** * label provider for the mappings column of the class model or RMIM model * @author robert * */ class MappingLabelProvider extends ColumnLabelProvider{ public MappingLabelProvider() { } public String getText(Object element) { String text = ""; System.out.println("getting text from label provider"); // view of a vanilla class model if ((element instanceof EClass) && (mdlBase() != null)) { EClass ec = (EClass)element; text = getObjectMappingText(ec); } // view of an RMIM class model else if ((element instanceof LabelledEClass) && (mdlBase() != null)) { EClass ec = ((LabelledEClass)element).eClass(); text = getObjectMappingText(ec); } return text; } } //---------------------------------------------------------------------------------------- // Actions for the pull-down menu //---------------------------------------------------------------------------------------- private Action saveClassModelChangesAction; private Action saveClassModelAsAction; private Action showLastSelectedClassAction; private MakeEcoreMappingsAction makeEcoreMappingsAction; private ImportSimplificationsAction importSimplificationsAction; private CopySimplificationsAction copySimplificationsAction; private PasteSimplificationsAction pasteSimplificationsAction; private RemoveSimplificationsAction removeSimplificationsAction; private MergeModelsAction mergeModelsAction; private void contributeToActionBars() { IActionBars bars = getViewSite().getActionBars(); fillLocalPullDown(bars.getMenuManager()); } private void fillLocalPullDown(IMenuManager manager) { manager.add(importSimplificationsAction); manager.add(copySimplificationsAction); manager.add(pasteSimplificationsAction); manager.add(removeSimplificationsAction); manager.add(mergeModelsAction); manager.add(saveClassModelChangesAction); manager.add(saveClassModelAsAction); manager.add(showLastSelectedClassAction); manager.add(makeEcoreMappingsAction); } /** * make the actions for the pulldown menu in the Mapped Class Model view */ private void makeActions() { saveClassModelChangesAction = new Action() { public void run() { FileUtil.saveResource(ecoreRoot().eResource()); } }; saveClassModelChangesAction.setText("Save Changes in Class Model"); saveClassModelChangesAction.setToolTipText("Save simplification annotation changes in class model"); saveClassModelChangesAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages(). getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK)); saveClassModelAsAction = new Action() { public void run() { doWriteClassModel(); } }; saveClassModelAsAction.setText("Save Class Model as.."); saveClassModelAsAction.setToolTipText("Write out a class model to be used to generate Java classes"); saveClassModelAsAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages(). getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK)); showLastSelectedClassAction = new Action() { public void run() { String path = EclipseFileUtil.getSelectedClassPath(classModelURI.toString()); TreePath pathToLastClass = getLabelledTreePath(path); if (pathToLastClass != null) { viewer.setSelection(new TreeSelection(pathToLastClass),true); // make it visible } } }; showLastSelectedClassAction.setText("Show Last Selected Class"); showLastSelectedClassAction.setToolTipText("Expand the tree to show the class model last selected by the user"); showLastSelectedClassAction.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages(). getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK)); makeEcoreMappingsAction = new MakeEcoreMappingsAction(this); importSimplificationsAction = new ImportSimplificationsAction(); copySimplificationsAction = new CopySimplificationsAction(); pasteSimplificationsAction = new PasteSimplificationsAction(); removeSimplificationsAction = new RemoveSimplificationsAction(); mergeModelsAction = new MergeModelsAction(); } /** * run the action to write the class model as an ecore file, for later code generation */ private void doWriteClassModel() { SaveAsDialog saveAsDialog = new SaveAsDialog(getSite().getShell()); saveAsDialog.open(); IPath path = saveAsDialog.getResult(); if (path != null) { // use the platform URI, not the absolute one, and Eclipse will see the resource URI resURI = URI.createPlatformResourceURI(path.toString(),true); saveAtURI(ecoreRoot,resURI,"ecore"); } } /** * Save an Ecore model at a given URI * @param model an Ecore model * @param resURI the URI it is to be saved at */ public void saveAtURI(EPackage model,URI resURI,String extension) { ResourceSet resourceSet = new ResourceSetImpl(); resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap(). put(extension, new XMIResourceFactoryImpl()); Resource resource = resourceSet.createResource(resURI); resource.getContents().add(model); try { resource.save(null); } catch (IOException ex) { System.out.println("Exception saving ecore resource at " + resURI.toString() + ": " + ex.getMessage()); } } /** * Passing the focus request to the viewer's control. */ public void setFocus() { viewer.getControl().setFocus(); } //------------------------------------------------------------------------------------------ // saving and restoring the state of the view //------------------------------------------------------------------------------------------ private static final String TAG_MAPPING_SET_URI = "mappingSetURI"; private static final String TAG_CLASS_MODEL_URI = "instanceURI"; private static final String TAG_QUERY_URI = "queryURI"; public void saveState(IMemento memento) { super.saveState(memento); if (classModelURI() != null) memento.putString(TAG_CLASS_MODEL_URI, classModelURI().toString()); // at most one of mappingSetURI and queryURI will be non-null if (mappingSetURI() != null) memento.putString(TAG_MAPPING_SET_URI, mappingSetURI().toString()); if (queryURI() != null) memento.putString(TAG_QUERY_URI, queryURI().toString()); } /** * re-initialise the model from its state at last closedown * Note the viewer does not exist when this runs. */ public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); if (memento != null) { String cmURI = memento.getString(TAG_CLASS_MODEL_URI); if (cmURI != null) classModelURI = URI.createURI(cmURI); // at most one of mappingSetURI and queryURI will be non-null String msURI = memento.getString(TAG_MAPPING_SET_URI); if (msURI != null) setMappingSetURI(URI.createURI(msURI)); String quURI = memento.getString(TAG_QUERY_URI); if (quURI != null) setQueryURI(URI.createURI(quURI)); } } //---------------------------------------------------------------------------------------- // Expanding the tree view to show a mapped class //---------------------------------------------------------------------------------------- /** * @param qualifiedClassName the package name and class name of the class whose mapping has been selected */ public void showMappedClass(String qualifiedClassName,String subset) { // RMIM case; find the named LabelledEClass and expand to it if ((isRMIMRoot(ecoreRoot)) && (subset != null)) { TreePath startPath = TreePath.EMPTY.createChildPath(topLabelledEClass); if (parameterClassName() != null) startPath = extendToParameterClass(startPath,parameterClassName()); TreePath namedPath = findLabelledPath(qualifiedClassName,subset,startPath); if (namedPath != null) { viewer.setSelection(new TreeSelection(namedPath),true); // make it visible } else {System.out.println("Null tree path");} } // non-RMIM case; find the named EClass and expand to it if (!(isRMIMRoot(ecoreRoot))) { EClass namedClass = ModelUtil.getNamedClass(ecoreRoot, qualifiedClassName); if (namedClass != null) { viewer.expandToLevel(namedClass, 0); viewer.setSelection(new StructuredSelection(namedClass)); } } } /** * recursive descent of a tree of mapped LabelledEClasses, * looking for a class with the required class name and subset * @param className * @param subset * @param path */ private TreePath findLabelledPath(String className, String subset, TreePath path) { if (path == null) return null; LabelledEClass lc = (LabelledEClass)path.getLastSegment(); // find out if the class is mapped, and if so, set its subset getObjectMappingText(lc); /* only try mapped classes and their mapped descendants * (usually any mapped class has all mapped ancestors) */ if (lc.getMappedSubset() != null) { String cName = ModelUtil.getQualifiedClassName(lc.eClass()); if ((subset.equals(lc.getMappedSubset())) && (className.equals(cName))) return path; else for (Iterator<LabelledEClass> it = lc.getChildren().iterator();it.hasNext();) { TreePath childPath = path.createChildPath(it.next()); TreePath targetPath = findLabelledPath(className, subset, childPath); if (targetPath != null) return targetPath; } } return null; } /** * @param startPath a TreePath with one step - the entry class of the RMIM * @param parameterClassName name of the parameter class of the mapping set * @return a TreePath to one example of the parameter class (there may be several) * found by a tree search cut off at repeated class names */ private TreePath extendToParameterClass(TreePath startPath,String parameterClassName) { TreePath currentPath = startPath; // from parents of each class, find a path of parent classes to the top class Vector<String> parentsToRoot = new Vector<String>(); parentsToRoot.add(parameterClassName); String topClassName = ModelUtil.getQualifiedClassName(topLabelledEClass.eClass()); parentsToRoot = extendToAncestorClass(parentsToRoot,topClassName); // use these to construct a TreePath of LabelledEClass objects if (parentsToRoot != null) { for (int i = 1; i < parentsToRoot.size(); i++) { LabelledEClass current = (LabelledEClass)currentPath.getLastSegment(); boolean found = false; for (Iterator<LabelledEClass> ic = current.getChildren().iterator();ic.hasNext();) { LabelledEClass child = ic.next(); if (ModelUtil.getQualifiedClassName(child.eClass()).equals(parentsToRoot.get(i))) { found = true; currentPath = currentPath.createChildPath(child); } } if (!found) return null; } return currentPath; } return null; } private Vector<String> extendToAncestorClass(Vector<String>parentsToRoot,String className) { if (parentsToRoot.get(0).equals(className)) return parentsToRoot; else { Vector<String> parents = parentTable.get(parentsToRoot.get(0)); for (Iterator<String> ip = parents.iterator(); ip.hasNext();) { String parent = ip.next(); if (!GenUtil.inVector(parent, parentsToRoot)) { Vector<String> newTrail = new Vector<String>(); newTrail.add(parent); for (Iterator<String> is = parentsToRoot.iterator();is.hasNext();) newTrail.add(is.next()); Vector<String> result = extendToAncestorClass(newTrail,className); if (result != null) return result; } } } return null; } /** * * @param path * @return the treePath of LabelledEClasses got by following a string path, * or null if it cannot be followed */ private TreePath getLabelledTreePath(String path) { TreePath result = null; if (path != null) { StringTokenizer steps = new StringTokenizer(path,"/"); String topName = steps.nextToken(); // check the first step, which should be the name of the top class if (topName.equals(topLabelledEClass.eClass().getName())) { result = TreePath.EMPTY.createChildPath(topLabelledEClass); LabelledEClass currentClass = topLabelledEClass; while ((steps.hasMoreTokens()) && (currentClass != null)) { String step = steps.nextToken(); currentClass = currentClass.getNamedAssocChild(step); if (currentClass != null) result = result.createChildPath(currentClass); else result = null; } } } return result; } //----------------------------------------------------------------------------------------------------------------- // Listening for the selection of a new class in this View, for copy and paste of simplification annotations, // and also to reopen the class model at the last selected class //----------------------------------------------------------------------------------------------------------------- private LabelledEClass selectedLabelledEClass = null; /** get the node that has been selected, for copy and paste of simplification annotations */ public LabelledEClass getSelectedLabelledEClass() {return selectedLabelledEClass;} private LabelledEClass copiedLabelledEClass = null; /** set the node that has been copied, for later paste of simplification annotations */ public void setCopiedLabelledEClass(LabelledEClass copied) {copiedLabelledEClass= copied;} /** get the node that has been copied, for later paste of simplification annotations */ public LabelledEClass getCopiedLabelledEClass() {return copiedLabelledEClass;} /** * remember the node selected in this view, as a local variable * and remember the path to it as a local variable and in an XML file in the workspace */ public void selectionChanged(SelectionChangedEvent event) { ISelection selection = event.getSelection(); if (selection instanceof IStructuredSelection && ((IStructuredSelection)selection).size() == 1) { Object object = ((IStructuredSelection)selection).getFirstElement(); // RMIM class model view if (object instanceof LabelledEClass) { selectedLabelledEClass = (LabelledEClass)object; String path = selectedLabelledEClass.getPath(); try {EclipseFileUtil.saveClassPath(classModelURI().toString(), path);} catch (MapperException ex) {trace("Exception saving path to selected class:" + ex.getMessage());} } } } //---------------------------------------------------------------------------------------- // Trivia //---------------------------------------------------------------------------------------- private void trace(String s) { if (tracing) System.out.println(s);} }