001    package com.hammurapi.render.emf;
002    
003    import java.io.File;
004    import java.util.ArrayList;
005    import java.util.Collection;
006    import java.util.Collections;
007    import java.util.Comparator;
008    import java.util.List;
009    import java.util.Locale;
010    import java.util.Map;
011    import java.util.concurrent.atomic.AtomicInteger;
012    
013    import org.eclipse.emf.common.util.TreeIterator;
014    import org.eclipse.emf.ecore.EAnnotation;
015    import org.eclipse.emf.ecore.EClass;
016    import org.eclipse.emf.ecore.EClassifier;
017    import org.eclipse.emf.ecore.EDataType;
018    import org.eclipse.emf.ecore.EModelElement;
019    import org.eclipse.emf.ecore.ENamedElement;
020    import org.eclipse.emf.ecore.EObject;
021    import org.eclipse.emf.ecore.EPackage;
022    import org.eclipse.emf.ecore.ETypedElement;
023    import org.eclipse.gmf.runtime.notation.Diagram;
024    import org.eclipse.gmf.runtime.notation.Node;
025    
026    import com.hammurapi.common.Context;
027    import com.hammurapi.common.IdentityManager;
028    import com.hammurapi.render.RenderHelper;
029    
030    /**
031     * Helper class for rendering EMF model documentation.
032     * @author Pavel Vlasov
033     *
034     */
035    public class ModelRenderHelper extends RenderHelper {
036    
037            private Map<EObject, List<Diagram>> diagramMap;
038            private Model model;
039            
040            /**
041             * Constructor
042             * @param identityManager IdentityManager.
043             * @param outputDir Output directory.
044             * @param diagramMap Maps diagram to a list of diagram elements.
045             * @param model Model.
046             * @param env Environment.
047             * @param context Context.
048             * @param locale Locale.
049             */
050            public ModelRenderHelper(
051                            IdentityManager<?> identityManager, 
052                            File outputDir, 
053                            Map<EObject, 
054                            List<Diagram>> diagramMap, 
055                            Model model, 
056                            Map<String, Object> env, 
057                            Context context, 
058                            Locale locale, 
059                            boolean http) {
060                    
061                    super(identityManager, outputDir, env, context, locale, http);
062                    this.diagramMap = diagramMap;
063                    this.model = model;
064            }
065            
066            /**
067             * @param obj
068             * @return true if given model element contains sub-elements.
069             */
070            public boolean hasChildren(EObject obj) {
071                    if (obj instanceof EPackage) {
072                            EPackage pkg = (EPackage) obj;
073                            List<Diagram> diagrams = diagramMap.get(pkg);
074                            return !pkg.getESubpackages().isEmpty() || !pkg.getEClassifiers().isEmpty() || (diagrams!=null && !diagrams.isEmpty());                         
075                    } else if (obj instanceof EClass) {
076                            EClass cls = (EClass) obj;
077                            return !cls.getEAttributes().isEmpty() 
078                            || !cls.getEOperations().isEmpty() 
079                            || !cls.getETypeParameters().isEmpty() 
080                            || !cls.getEReferences().isEmpty();
081                    }
082                    
083                    return false; // For now
084            }
085    
086            /**
087             * @param obj
088             * @return List of diagrams in the model.
089             */
090            public List<Diagram> getDiagrams(EObject obj) {
091                    List<Diagram> diagrams = diagramMap.get(obj);
092                    if (diagrams==null) {
093                            diagrams = Collections.emptyList();
094                    }
095                    
096                    Collections.sort(diagrams, new Comparator<Diagram>() {
097    
098                            @Override
099                            public int compare(Diagram o1, Diagram o2) {
100                                    if (o1==null) {
101                                            return o2==null ? 0 : 1;
102                                    }
103                                    
104                                    if (o2==null) {
105                                            return o1==null ? 0 : -1;
106                                    }
107                                    
108                                    String n1 = o1.getName();
109                                    String n2 = o2.getName();
110                                    
111                                    if (n1==null) {
112                                            return n2==null ? 0 : 1;
113                                    }
114                                    
115                                    return n2==null ? -1 : n1.compareTo(n2);
116                            }
117                            
118                    });
119                    
120                    return diagrams;
121            }
122    
123            /**
124             * @param modelElement
125             * @return Element documentation.
126             */
127            public String getDoc(EModelElement modelElement) {
128                    EAnnotation genModel = modelElement.getEAnnotation("http://www.eclipse.org/emf/2002/GenModel");
129                    if (genModel==null) {
130                            return "";
131                    }
132                    return genModel.getDetails().get("documentation");
133            }
134            
135            /**
136             * @param modelElement
137             * @return First sentence from element documentation.
138             */
139            public String firstSentence(EModelElement modelElement) {
140                    String ret = getDoc(modelElement);
141                    int idx = ret.indexOf('.');
142                    if (idx!=-1 && ret.length()>idx+1) {
143                            ret = ret.substring(0, idx+1);
144                    }
145                    return ret;
146            }
147    
148            /**
149             * @param pkg
150             * @return List of classes in the package.
151             */
152            public List<EClass> classes(EPackage pkg) {
153                    List<EClass> ret = new ArrayList<EClass>();         
154                    for (EClassifier c: pkg.getEClassifiers()) {
155                            if (c instanceof EClass) {
156                                    ret.add((EClass) c);
157                            }
158                    }
159                    return sort(ret);
160            }
161    
162            /**
163             * @param pkg
164             * @return List of data types in the package.
165             */
166            public List<EDataType> dataTypes(EPackage pkg) {
167                    List<EDataType> ret = new ArrayList<EDataType>();
168                    for (EClassifier c: pkg.getEClassifiers()) {
169                            if (c instanceof EDataType) {
170                                    ret.add((EDataType) c);
171                            }
172                    }
173                    return sort(ret);
174            }
175    
176            /**
177             * @param modelElement
178             * @return true  if model element is abstract.
179             */
180            public boolean isAbstract(EModelElement modelElement) {
181                    return modelElement instanceof EClass && ((EClass) modelElement).isAbstract();
182            }
183            
184    //      static AtomicInteger counter = new AtomicInteger();
185    
186            /**
187             * Sorts model elements list by model element name.
188             * @param <T>
189             * @param list
190             * @return
191             */
192            public <T extends ENamedElement> List<T> sort(List<T> list) {
193    //              System.out.println(counter.getAndIncrement());
194                    List<T> ret = new ArrayList<T>(list);
195                    Collections.sort(ret, new Comparator<T>() {
196    
197                            @Override
198                            public int compare(T o1, T o2) {
199                                    if (o1==null) {
200                                            return o2==null ? 0 : 1;
201                                    }
202                                    
203                                    if (o2==null) {
204                                            return o1==null ? 0 : -1;
205                                    }
206                                    
207                                    String n1 = o1.getName();
208                                    String n2 = o2.getName();
209                                    
210                                    if (n1==null) {
211                                            return n2==null ? 0 : 1;
212                                    }
213                                    
214                                    return n2==null ? -1 : n1.compareTo(n2);
215                            }
216                            
217                    });
218                    return ret;
219            }
220            
221            /**
222             * @param ete
223             * @return bounds string.
224             */
225            public String bounds(ETypedElement ete) {
226                    if (ete.getLowerBound()==ete.getUpperBound()) {
227                            return String.valueOf(ete.getLowerBound());
228                    }
229                    
230                    if (ete.getLowerBound()==0 && ete.getUpperBound()==-1) {
231                            return "*";
232                    }
233                    
234                    if (ete.getUpperBound()==-1) {
235                            return ete.getLowerBound()+"..*";
236                    }
237                    
238                    return ete.getLowerBound()+".."+ete.getUpperBound();
239            }
240            
241            /**
242             * @param cls
243             * @return List of direct subtypes of given type. 
244             */
245            public List<EClass> getSubTypes(EClass cls) {
246                    List<EClass> ret = new ArrayList<EClass>();
247                    for (EObject rp: model.getRootPackages()) {
248                            TreeIterator<EObject> rit = rp.eAllContents();
249                            while (rit.hasNext()) {
250                                    EObject obj = rit.next();
251                                    if (obj instanceof EClass && ((EClass) obj).getESuperTypes().contains(cls)) {
252                                            ret.add((EClass) obj);
253                                    }
254                            }
255                    }
256                    return ret;
257            }
258    
259            /**
260             * @param cls
261             * @return List of all (direct and indirect) subtypes of given type.
262             */
263            public List<EClass> getAllSubTypes(EClass cls) {
264                    List<EClass> ret = new ArrayList<EClass>();
265                    for (EObject rp: model.getRootPackages()) {
266                            TreeIterator<EObject> rit = rp.eAllContents();
267                            while (rit.hasNext()) {
268                                    EObject obj = rit.next();
269                                    if (obj instanceof EClass && ((EClass) obj).getEAllSuperTypes().contains(cls) && !ret.contains(obj)) {
270                                            ret.add((EClass) obj);
271                                    }
272                            }
273                    }
274                    return ret;
275            }
276    
277            /**
278             * @param diagram
279             * @return Collection of diagram elements.
280             * @throws Exception
281             */
282            public Collection<EObject> getDiagramElements(Diagram diagram) throws Exception {
283                    List<EObject> diagramElements = new ArrayList<EObject>();
284                    for (Object o: diagram.getChildren()) {
285                            if (o instanceof Node) {
286                                    EObject de = ((Node) o).getElement();
287                                    if (de!=null) {
288                                            if (de instanceof ENamedElement && ((ENamedElement) de).getName()!=null) { 
289                                                    diagramElements.add(de);
290                                            }
291                                    }
292                            }
293                    }
294                    return diagramElements;
295            }
296    
297    //  It is very hard to make it work standalone. It is kept here for the future 
298    //  implementations when it is invoked from Eclipse UI.
299    //      public void copyDiagramToImageFile(Diagram diagram) throws CoreException {
300    //              CopyToImageUtil ctiu = new CopyToImageUtil();
301    //              ImageFileFormat format = ImageFileFormat.GIF;
302    //              IPath destination = new Path(new File(getOutputDir(), getId(diagram)+".gif").getAbsolutePath());
303    //              ctiu.copyToImage(diagram, destination, format, new NullProgressMonitor(), PreferencesHint.USE_DEFAULTS);
304    //      }
305                    
306    }