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 }