GliffyObject.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. package com.mxgraph.io.gliffy.model;
  2. import java.util.Collections;
  3. import java.util.Comparator;
  4. import java.util.HashMap;
  5. import java.util.HashSet;
  6. import java.util.List;
  7. import java.util.Map;
  8. import java.util.Set;
  9. import com.mxgraph.io.gliffy.importer.PostDeserializer.PostDeserializable;
  10. import com.mxgraph.model.mxCell;
  11. import com.mxgraph.model.mxGeometry;
  12. /**
  13. * Class representing Gliffy diagram object
  14. *
  15. */
  16. public class GliffyObject implements PostDeserializable
  17. {
  18. private static Set<String> GRAPHICLESS_SHAPES = new HashSet<String>();
  19. private static Set<String> GROUP_SHAPES = new HashSet<String>();
  20. private static Set<String> MINDMAP_SHAPES = new HashSet<>();
  21. private static Map<String, double[]> SHAPES_COORD_FIX = new HashMap<>();
  22. public float x;
  23. public float y;
  24. public int id;
  25. public float width;
  26. public float height;
  27. public float rotation;
  28. public String uid;
  29. public String tid;
  30. public String order;
  31. public boolean lockshape;
  32. public Graphic graphic;
  33. public List<GliffyObject> children;
  34. public Constraints constraints;
  35. public List<LinkMap> linkMap;
  36. public mxCell mxObject;// the mxCell this gliffy object got converted into
  37. public GliffyObject parent = null;
  38. static
  39. {
  40. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.package");
  41. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.class");
  42. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.simple_class");
  43. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.object_timeline");
  44. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.lifeline");
  45. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.use_case");
  46. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.actor");
  47. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.use_case");
  48. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.self_message");
  49. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.message");
  50. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.activation");
  51. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.dependency");
  52. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.dependency");
  53. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.composition");
  54. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.aggregation");
  55. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.association");
  56. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.package");
  57. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.simple_class");
  58. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.class");
  59. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.class2");
  60. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.interface");
  61. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.enumeration");
  62. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.lifeline");
  63. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.boundary_lifeline");
  64. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.control_lifeline");
  65. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.entity_lifeline");
  66. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.deployment.package");
  67. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.component.package");
  68. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.use_case.package");
  69. GRAPHICLESS_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_attributes");
  70. GRAPHICLESS_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_multiple_attributes");
  71. GRAPHICLESS_SHAPES.add("com.gliffy.shape.bpmn.bpmn_v1.data_artifacts.annotation");
  72. GRAPHICLESS_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_multiple_attributes");
  73. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.navigation.navbar");
  74. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.forms_controls.combo_box");
  75. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.tooltip_top");
  76. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.popover_bottom");
  77. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.forms_controls.selector");
  78. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.icon_symbols.annotate_left");
  79. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.icon_symbols.annotate_right");
  80. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.icon_symbols.annotate_top");
  81. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.popover_top");
  82. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.page");
  83. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.home");
  84. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.gliffy");
  85. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.form");
  86. /*GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.page");
  87. */
  88. GROUP_SHAPES.add("com.gliffy.shape.basic.basic_v1.default.group");
  89. GROUP_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_attributes");
  90. GROUP_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_multiple_attributes");
  91. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.interaction_use");
  92. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.opt_combined_fragment");
  93. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.loop_combined_fragment");
  94. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.alt_combined_fragment");
  95. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.object");
  96. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.enumeration");
  97. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.interface");
  98. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.class2");
  99. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.class");
  100. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.data_type");
  101. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.state_machine.composite_state");
  102. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.state_machine.orthoganal_state");
  103. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.package");
  104. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.boundary_lifeline");
  105. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.lifeline");
  106. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.entity_lifeline");
  107. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.control_lifeline");
  108. GROUP_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.speech_bubble_right");
  109. GROUP_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.speech_bubble_left");
  110. //UML V1
  111. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.object_timeline");
  112. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.class");
  113. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.object");
  114. MINDMAP_SHAPES.add("com.gliffy.shape.mindmap.mindmap_v1.default.main_topic");
  115. MINDMAP_SHAPES.add("com.gliffy.shape.mindmap.mindmap_v1.default.subtopic");
  116. MINDMAP_SHAPES.add("com.gliffy.shape.mindmap.mindmap_v1.default.child_node");
  117. SHAPES_COORD_FIX.put("com.gliffy.shape.flowchart.flowchart_v1.default.paper_tape", new double[]{0, -0.1, 0, 0.2});
  118. SHAPES_COORD_FIX.put("com.gliffy.shape.uml.uml_v1.default.node", new double[]{0, -10, 10, 10});
  119. SHAPES_COORD_FIX.put("com.gliffy.shape.uml.uml_v2.deployment.node", new double[]{0, -10, 10, 10});
  120. SHAPES_COORD_FIX.put("com.gliffy.shape.uml.uml_v2.deployment.device_node", new double[]{0, -10, 10, 10});
  121. SHAPES_COORD_FIX.put("com.gliffy.shape.uml.uml_v2.deployment.execution_environment_node", new double[]{0, -10, 10, 10});
  122. }
  123. public GliffyObject()
  124. {
  125. }
  126. public Graphic getGraphic()
  127. {
  128. if (graphic != null)
  129. return graphic;
  130. else if (isUml() || GRAPHICLESS_SHAPES.contains(uid))
  131. return getFirstChildGraphic();
  132. else
  133. return null;
  134. }
  135. public mxCell getMxObject()
  136. {
  137. return mxObject;
  138. }
  139. /**
  140. * Returns the object that represents the caption for this object
  141. *
  142. * @return
  143. */
  144. public GliffyObject getTextObject()
  145. {
  146. return getTextObject(0, 0);
  147. }
  148. private GliffyObject getTextObject(double x, double y)
  149. {
  150. if (isText())
  151. {
  152. return this;
  153. }
  154. if (children == null)
  155. {
  156. return null;
  157. }
  158. for (GliffyObject child : children)
  159. {
  160. if (child.getGraphic() != null && child.getGraphic().getType().equals(Graphic.Type.TEXT))
  161. {
  162. child.x += x;
  163. child.y += y;
  164. return child;
  165. }
  166. else
  167. {
  168. GliffyObject txtObj = child.getTextObject(child.x, child.y);
  169. if (txtObj != null)
  170. return txtObj;
  171. }
  172. }
  173. return null;
  174. }
  175. public String getText()
  176. {
  177. return graphic.getText().getHtml();
  178. }
  179. public String getLink()
  180. {
  181. if (linkMap != null && !linkMap.isEmpty())
  182. return linkMap.get(0).url;
  183. return null;
  184. }
  185. /**
  186. * Some shapes like UML package, class and interface do not have a graphic object but instead rely on graphic of their children.
  187. * In that case, graphic is the same for all children
  188. * @return graphic of the first child or null of there are no children
  189. */
  190. public Graphic getFirstChildGraphic()
  191. {
  192. return children.size() > 0 ? children.get(0).graphic : null;
  193. }
  194. public boolean isGroup()
  195. {
  196. return (uid != null && (GROUP_SHAPES.contains(uid) || uid.startsWith("com.gliffy.shape.table")))
  197. //Since we treat text in a different way (added as cell value instead of another child cell, this is probably the best way to detect groups when uid is null)
  198. || (uid == null && hasChildren() && !children.get(0).isText());
  199. }
  200. public boolean isMindmap()
  201. {
  202. return uid != null && MINDMAP_SHAPES.contains(uid);
  203. }
  204. public boolean isLine()
  205. {
  206. return graphic != null && graphic.getType().equals(Graphic.Type.LINE);
  207. }
  208. private boolean isUml()
  209. {
  210. return uid != null && (uid.startsWith("com.gliffy.shape.uml.uml"));
  211. }
  212. public boolean isShape()
  213. {
  214. if (graphic != null)
  215. {
  216. return graphic.getType().equals(Graphic.Type.SHAPE) || graphic.getType().equals(Graphic.Type.MINDMAP);
  217. }
  218. else
  219. {
  220. //some UML shapes do not have a graphic,instead their graphic type is determined by their first child
  221. Graphic g = getFirstChildGraphic();
  222. return g != null && g.getType().equals(Graphic.Type.SHAPE);
  223. }
  224. }
  225. public boolean isSvg()
  226. {
  227. return graphic != null && graphic.type.equals(Graphic.Type.SVG);
  228. }
  229. public boolean isSwimlane()
  230. {
  231. return uid != null && uid.contains("com.gliffy.shape.swimlanes");
  232. }
  233. public boolean isText()
  234. {
  235. return graphic != null && graphic.getType().equals(Graphic.Type.TEXT);
  236. }
  237. public boolean isImage()
  238. {
  239. return graphic != null && graphic.getType().equals(Graphic.Type.IMAGE);
  240. }
  241. public boolean isVennCircle()
  242. {
  243. return uid != null && uid.startsWith("com.gliffy.shape.venn");
  244. }
  245. public String getGradientColor()
  246. {
  247. String gradientColor = "#FFFFFF";
  248. // Gradient colors are lighter version of the fill color except for radial
  249. // venn shapes, where white is used with a radial gradient (we use linear)
  250. if (graphic != null && graphic.Shape != null && uid != null && !uid.startsWith("com.gliffy.shape.radial"))
  251. {
  252. String hex = graphic.Shape.fillColor;
  253. if (hex != null && hex.length() == 7 && hex.charAt(0) == '#')
  254. {
  255. long clr = Long.parseLong(hex.substring(1), 16);
  256. long r = Math.min(0xFF0000, ((clr & 0xFF0000) + 0xAA0000)) & 0xFF0000;
  257. long g = Math.min(0x00FF00, ((clr & 0x00FF00) + 0x00AA00)) & 0x00FF00;
  258. long b = Math.min(0x0000FF, ((clr & 0x0000FF) + 0x0000AA)) & 0x0000FF;
  259. gradientColor = String.format("#%06X", 0xFFFFFF & (r + g + b));
  260. }
  261. }
  262. return gradientColor;
  263. }
  264. /**
  265. * LATER: Add more cases where gradient is ignored.
  266. */
  267. public boolean isGradientIgnored()
  268. {
  269. return uid != null && (uid.startsWith("com.gliffy.shape.venn.outline") || uid.startsWith("com.gliffy.shape.venn.flat"));
  270. }
  271. /**
  272. * Returns a boolean indicating if this object is a subroutine
  273. * @return true if subroutine, false otherwise
  274. */
  275. public boolean isSubRoutine()
  276. {
  277. return "com.gliffy.shape.flowchart.flowchart_v1.default.subroutine".equals(uid);
  278. }
  279. public boolean isUnrecognizedGraphicType()
  280. {
  281. return graphic != null && graphic.type == null;
  282. }
  283. public Constraints getConstraints()
  284. {
  285. return constraints;
  286. }
  287. public boolean hasChildren()
  288. {
  289. return children != null && children.size() > 0;
  290. }
  291. @Override
  292. public String toString()
  293. {
  294. return uid != null ? uid : tid;
  295. }
  296. @Override
  297. public void postDeserialize()
  298. {
  299. if (isGroup())
  300. normalizeChildrenCoordinates();
  301. }
  302. /**
  303. * Some Gliffy diagrams have groups whose children have negative coordinates.
  304. * This is a problem in draw.io as they get set to 0.
  305. * This method expands the groups left and up and adjusts children's coordinates so that they are never less than zero.
  306. */
  307. private void normalizeChildrenCoordinates()
  308. {
  309. //sorts the list to find the leftmost child and it's X
  310. Comparator<GliffyObject> cx = new Comparator<GliffyObject>()
  311. {
  312. @Override
  313. public int compare(GliffyObject o1, GliffyObject o2)
  314. {
  315. return (int) (o1.x - o2.x);
  316. }
  317. };
  318. Collections.sort(children, cx);
  319. float xMin = children.get(0).x;
  320. if (xMin < 0)
  321. {
  322. width += -xMin; //increase width
  323. x += xMin;
  324. for (GliffyObject child : children) //increase x
  325. child.x += -xMin;
  326. }
  327. //sorts the list to find the uppermost child and it's Y
  328. Comparator<GliffyObject> cy = new Comparator<GliffyObject>()
  329. {
  330. @Override
  331. public int compare(GliffyObject o1, GliffyObject o2)
  332. {
  333. return (int) (o1.y - o2.y);
  334. }
  335. };
  336. Collections.sort(children, cy);
  337. float yMin = children.get(0).y;
  338. if (yMin < 0)
  339. {
  340. height += -yMin; //increase height
  341. y += yMin;
  342. for (GliffyObject child : children) //increase y
  343. child.y += -yMin;
  344. }
  345. }
  346. public void adjustGeo(mxGeometry geo)
  347. {
  348. double[] arr = SHAPES_COORD_FIX.get(uid);
  349. if (arr != null)
  350. {
  351. double x = geo.getX(), y = geo.getY(), w = geo.getWidth(), h = geo.getHeight();
  352. geo.setX(x + (Math.abs(arr[0]) < 1 ? w * arr[0]: arr[0]));
  353. geo.setY(y + (Math.abs(arr[1]) < 1 ? h * arr[1]: arr[1]));
  354. geo.setWidth(w + (Math.abs(arr[2]) < 1 ? w * arr[2]: arr[2]));
  355. geo.setHeight(h + (Math.abs(arr[3]) < 1 ? h * arr[3]: arr[3]));
  356. }
  357. }
  358. public void adjustTextPos(GliffyObject textObject)
  359. {
  360. double[] arr = SHAPES_COORD_FIX.get(uid);
  361. if (arr != null)
  362. {
  363. textObject.x -= (Math.abs(arr[0]) < 1 ? width * arr[0]: arr[0]);
  364. textObject.y -= (Math.abs(arr[1]) < 1 ? height * arr[1]: arr[1]);
  365. }
  366. }
  367. }