GliffyObject.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  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.Iterator;
  7. import java.util.List;
  8. import java.util.Map;
  9. import java.util.Set;
  10. import com.mxgraph.io.gliffy.importer.PostDeserializer.PostDeserializable;
  11. import com.mxgraph.model.mxCell;
  12. import com.mxgraph.model.mxGeometry;
  13. import com.mxgraph.online.Utils;
  14. /**
  15. * Class representing Gliffy diagram object
  16. *
  17. */
  18. public class GliffyObject implements PostDeserializable
  19. {
  20. private static Set<String> GRAPHICLESS_SHAPES = new HashSet<String>();
  21. private static Set<String> GROUP_SHAPES = new HashSet<String>();
  22. private static Set<String> MINDMAP_SHAPES = new HashSet<>();
  23. private static Set<String> FILLCLR_IS_STROKECLR_SHAPES = new HashSet<>();
  24. private static Map<String, double[]> SHAPES_COORD_FIX = new HashMap<>();
  25. public float x;
  26. public float y;
  27. public int id;
  28. public float width;
  29. public float height;
  30. public float rotation;
  31. public String uid;
  32. public String tid;
  33. public String order;
  34. public boolean lockshape;
  35. public String layerId;
  36. public Graphic graphic;
  37. public List<GliffyObject> children;
  38. public Constraints constraints;
  39. public mxCell mxObject;// the mxCell this gliffy object got converted into
  40. public GliffyObject parent = null;
  41. static
  42. {
  43. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.package");
  44. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.class");
  45. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.simple_class");
  46. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.object_timeline");
  47. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.lifeline");
  48. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.use_case");
  49. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.actor");
  50. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.use_case");
  51. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.self_message");
  52. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.message");
  53. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.activation");
  54. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.dependency");
  55. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.dependency");
  56. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.composition");
  57. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.aggregation");
  58. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.association");
  59. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.package");
  60. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.simple_class");
  61. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.class");
  62. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.class2");
  63. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.interface");
  64. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.enumeration");
  65. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.lifeline");
  66. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.boundary_lifeline");
  67. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.control_lifeline");
  68. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.entity_lifeline");
  69. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.deployment.package");
  70. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.component.package");
  71. GRAPHICLESS_SHAPES.add("com.gliffy.shape.uml.uml_v2.use_case.package");
  72. GRAPHICLESS_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_attributes");
  73. GRAPHICLESS_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_multiple_attributes");
  74. GRAPHICLESS_SHAPES.add("com.gliffy.shape.bpmn.bpmn_v1.data_artifacts.annotation");
  75. GRAPHICLESS_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_multiple_attributes");
  76. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.navigation.navbar");
  77. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.forms_controls.combo_box");
  78. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.tooltip_top");
  79. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.tooltip_bottom");
  80. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.tooltip_left");
  81. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.tooltip_right");
  82. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.popover_top");
  83. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.popover_bottom");
  84. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.forms_controls.selector");
  85. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.icon_symbols.annotate_left");
  86. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.icon_symbols.annotate_right");
  87. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.icon_symbols.annotate_top");
  88. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.speech_bubble_right");
  89. GRAPHICLESS_SHAPES.add("com.gliffy.shape.ui.ui_v3.containers_content.speech_bubble_left");
  90. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.page");
  91. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.home");
  92. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.gliffy");
  93. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.form");
  94. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.shopping_cart");
  95. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.text");
  96. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.video");
  97. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.upload");
  98. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.slideshow");
  99. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.sitemap");
  100. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.settings");
  101. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.search");
  102. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.script");
  103. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.print");
  104. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.pricing");
  105. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.photo");
  106. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.map");
  107. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.login");
  108. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.game");
  109. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.gallery");
  110. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.download");
  111. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.document");
  112. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.chat");
  113. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.calendar");
  114. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.audio");
  115. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.profile");
  116. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.error");
  117. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.success");
  118. GRAPHICLESS_SHAPES.add("com.gliffy.shape.sitemap.sitemap_v2.cloud");
  119. GROUP_SHAPES.add("com.gliffy.shape.basic.basic_v1.default.group");
  120. GROUP_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_attributes");
  121. GROUP_SHAPES.add("com.gliffy.shape.erd.erd_v1.default.entity_with_multiple_attributes");
  122. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.interaction_use");
  123. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.opt_combined_fragment");
  124. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.loop_combined_fragment");
  125. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.alt_combined_fragment");
  126. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.object");
  127. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.enumeration");
  128. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.interface");
  129. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.class2");
  130. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.class");
  131. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.data_type");
  132. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.state_machine.composite_state");
  133. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.state_machine.orthoganal_state");
  134. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.class.package");
  135. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.boundary_lifeline");
  136. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.lifeline");
  137. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.entity_lifeline");
  138. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v2.sequence.control_lifeline");
  139. //UML V1
  140. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.object_timeline");
  141. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.class");
  142. GROUP_SHAPES.add("com.gliffy.shape.uml.uml_v1.default.object");
  143. //ios
  144. GROUP_SHAPES.add("com.gliffy.shape.iphone.iphone_ios7.containers_content.table");
  145. GROUP_SHAPES.add("com.gliffy.shape.iphone.iphone_ios7.forms_controls.button_stack");
  146. GROUP_SHAPES.add("com.gliffy.shape.iphone.iphone_ios7.forms_controls.alert_2options");
  147. GROUP_SHAPES.add("com.gliffy.shape.iphone.iphone_ios7.forms_controls.alert");
  148. GROUP_SHAPES.add("com.gliffy.shape.iphone.iphone_ios7.navigation.contextual_menu");
  149. GROUP_SHAPES.add("com.gliffy.shape.iphone.iphone_ios7.navigation.nav_3tabs");
  150. GROUP_SHAPES.add("com.gliffy.shape.iphone.iphone_ios7.containers_content.title_bar");
  151. GROUP_SHAPES.add("com.gliffy.shape.iphone.iphone_ios7.navigation.tab_bar");
  152. GROUP_SHAPES.add("com.gliffy.shape.iphone.iphone_ios7.forms_controls.search");
  153. //android
  154. GROUP_SHAPES.add("com.gliffy.shape.android.android_v1.general.dialog");
  155. GROUP_SHAPES.add("com.gliffy.shape.android.android_v1.general.list_1line");
  156. GROUP_SHAPES.add("com.gliffy.shape.android.android_v1.general.list_2lines");
  157. GROUP_SHAPES.add("com.gliffy.shape.android.android_v1.general.tabs01");
  158. GROUP_SHAPES.add("com.gliffy.shape.android.android_v1.general.tabs02");
  159. //others
  160. GROUP_SHAPES.add("com.gliffy.shape.network.network_v3.business.user_group");
  161. //ui
  162. GROUP_SHAPES.add("com.gliffy.shape.ui.ui_v3.navigation.navbar");
  163. GROUP_SHAPES.add("com.gliffy.shape.ui.ui_v3.navigation.navbar_vertical");
  164. GROUP_SHAPES.add("com.gliffy.shape.ui.ui_v3.forms_controls.dropdown");
  165. //It is a group but we have one similar
  166. //GROUP_SHAPES.add("com.gliffy.shape.ui.ui_v3.forms_controls.audio_controls");
  167. MINDMAP_SHAPES.add("com.gliffy.shape.mindmap.mindmap_v1.default.main_topic");
  168. MINDMAP_SHAPES.add("com.gliffy.shape.mindmap.mindmap_v1.default.subtopic");
  169. MINDMAP_SHAPES.add("com.gliffy.shape.mindmap.mindmap_v1.default.child_node");
  170. //This map is used to change Gliffy coordinates to match mxGraph ones
  171. //Format [xShift, yShift, widthShift, heightShift, DONT REPOSITION TEXT] values between ]-1, 1[ means percentage
  172. SHAPES_COORD_FIX.put("com.gliffy.shape.flowchart.flowchart_v1.default.paper_tape", new double[]{0, -0.1, 0, 0.2});
  173. SHAPES_COORD_FIX.put("com.gliffy.shape.uml.uml_v1.default.node", new double[]{0, -10, 10, 10});
  174. SHAPES_COORD_FIX.put("com.gliffy.shape.uml.uml_v2.deployment.node", new double[]{0, -10, 10, 10});
  175. SHAPES_COORD_FIX.put("com.gliffy.shape.uml.uml_v2.deployment.device_node", new double[]{0, -10, 10, 10});
  176. SHAPES_COORD_FIX.put("com.gliffy.shape.uml.uml_v2.deployment.execution_environment_node", new double[]{0, -10, 10, 10});
  177. SHAPES_COORD_FIX.put("com.gliffy.shape.flowchart.flowchart_v1.default.data_storage", new double[]{0, 0, 0.115, 0});
  178. //these shapes cannot be resized (width is fixed) in Gliffy
  179. SHAPES_COORD_FIX.put("com.gliffy.stencil.entity_lifeline.uml_v2", new double[]{10, 0, -20, 0});
  180. SHAPES_COORD_FIX.put("com.gliffy.stencil.boundary_lifeline.uml_v2", new double[]{35, 0, -70, 0});
  181. SHAPES_COORD_FIX.put("com.gliffy.stencil.control_lifeline.uml_v2", new double[]{10, 0, -20, 0});
  182. //Our browser window has a larger header so increase it
  183. SHAPES_COORD_FIX.put("com.gliffy.shape.ui.ui_v3.containers_content.browser", new double[]{0, -40, 0, 40, 1});
  184. //There are many shapes where fillColor is the strokeColor
  185. FILLCLR_IS_STROKECLR_SHAPES.add("com.gliffy.stencil.rectangle.no_fill_line_bottom_2px_off");
  186. }
  187. public GliffyObject()
  188. {
  189. }
  190. public Graphic getGraphic()
  191. {
  192. if (graphic != null)
  193. return graphic;
  194. else if (isUml() || GRAPHICLESS_SHAPES.contains(uid))
  195. return getFirstChildGraphic();
  196. else
  197. return null;
  198. }
  199. public mxCell getMxObject()
  200. {
  201. return mxObject;
  202. }
  203. /**
  204. * Returns the object that represents the caption for this object
  205. *
  206. * @return
  207. */
  208. public GliffyObject getTextObject()
  209. {
  210. return getTextObject(0, 0);
  211. }
  212. private GliffyObject getTextObject(double x, double y)
  213. {
  214. if (isText())
  215. {
  216. return this;
  217. }
  218. if (children == null)
  219. {
  220. return null;
  221. }
  222. for (GliffyObject child : children)
  223. {
  224. if (child.getGraphic() != null && child.getGraphic().getType().equals(Graphic.Type.TEXT))
  225. {
  226. child.x += x;
  227. child.y += y;
  228. return child;
  229. }
  230. else
  231. {
  232. GliffyObject txtObj = child.getTextObject(child.x, child.y);
  233. if (txtObj != null)
  234. return txtObj;
  235. }
  236. }
  237. return null;
  238. }
  239. public String getText()
  240. {
  241. return graphic.getText().getHtml();
  242. }
  243. public String getLink()
  244. {
  245. if(children == null || children.isEmpty())
  246. return null;
  247. Iterator<GliffyObject> it = children.iterator();
  248. while(it.hasNext())
  249. {
  250. GliffyObject child = it.next();
  251. if(child.isLink())
  252. return child.graphic.getLink().href;
  253. }
  254. return null;
  255. }
  256. /**
  257. * Some shapes like UML package, class and interface do not have a graphic object but instead rely on graphic of their children.
  258. * In that case, graphic is the same for all children
  259. * @return graphic of the first child or null of there are no children
  260. */
  261. public Graphic getFirstChildGraphic()
  262. {
  263. return children.size() > 0 ? children.get(0).graphic : null;
  264. }
  265. public boolean isGroup()
  266. {
  267. return (hasChildren() && ((uid != null && (GROUP_SHAPES.contains(uid) || uid.startsWith("com.gliffy.shape.table")))
  268. //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)
  269. || (uid == null && !children.get(0).isText())));
  270. }
  271. public boolean isSelection()
  272. {
  273. return uid != null && uid.contains("default.selection");
  274. }
  275. public boolean isMindmap()
  276. {
  277. return uid != null && MINDMAP_SHAPES.contains(uid);
  278. }
  279. public boolean isLine()
  280. {
  281. return graphic != null && graphic.getType().equals(Graphic.Type.LINE);
  282. }
  283. public boolean isLink()
  284. {
  285. return graphic != null && graphic.getType().equals(Graphic.Type.LINK);
  286. }
  287. private boolean isUml()
  288. {
  289. return uid != null && (uid.startsWith("com.gliffy.shape.uml.uml"));
  290. }
  291. public boolean isShape()
  292. {
  293. if (graphic != null)
  294. {
  295. return graphic.getType().equals(Graphic.Type.SHAPE) || graphic.getType().equals(Graphic.Type.MINDMAP);
  296. }
  297. else
  298. {
  299. //some UML shapes do not have a graphic,instead their graphic type is determined by their first child
  300. Graphic g = getFirstChildGraphic();
  301. return g != null && g.getType().equals(Graphic.Type.SHAPE);
  302. }
  303. }
  304. public boolean isSvg()
  305. {
  306. return graphic != null && graphic.type.equals(Graphic.Type.SVG);
  307. }
  308. public boolean isSwimlane()
  309. {
  310. return uid != null && uid.contains("com.gliffy.shape.swimlanes");
  311. }
  312. public boolean isText()
  313. {
  314. return graphic != null && graphic.getType().equals(Graphic.Type.TEXT);
  315. }
  316. public boolean isImage()
  317. {
  318. return graphic != null && graphic.getType().equals(Graphic.Type.IMAGE);
  319. }
  320. public boolean isVennCircle()
  321. {
  322. return uid != null && uid.startsWith("com.gliffy.shape.venn");
  323. }
  324. public String getGradientColor()
  325. {
  326. String gradientColor = "#FFFFFF";
  327. // Gradient colors are lighter version of the fill color except for radial
  328. // venn shapes, where white is used with a radial gradient (we use linear)
  329. if (graphic != null && graphic.Shape != null && uid != null && !uid.startsWith("com.gliffy.shape.radial"))
  330. {
  331. String hex = graphic.Shape.fillColor;
  332. if (hex != null && hex.length() == 7 && hex.charAt(0) == '#')
  333. {
  334. long clr = Long.parseLong(hex.substring(1), 16);
  335. long r = Math.min(0xFF0000, ((clr & 0xFF0000) + 0xAA0000)) & 0xFF0000;
  336. long g = Math.min(0x00FF00, ((clr & 0x00FF00) + 0x00AA00)) & 0x00FF00;
  337. long b = Math.min(0x0000FF, ((clr & 0x0000FF) + 0x0000AA)) & 0x0000FF;
  338. gradientColor = String.format("#%06X", 0xFFFFFF & (r + g + b));
  339. }
  340. }
  341. return gradientColor;
  342. }
  343. /**
  344. * LATER: Add more cases where gradient is ignored.
  345. */
  346. public boolean isGradientIgnored()
  347. {
  348. return uid != null && (uid.startsWith("com.gliffy.shape.venn.outline") || uid.startsWith("com.gliffy.shape.venn.flat"));
  349. }
  350. /**
  351. * Returns a boolean indicating if this object is a subroutine
  352. * @return true if subroutine, false otherwise
  353. */
  354. public boolean isSubRoutine()
  355. {
  356. return "com.gliffy.shape.flowchart.flowchart_v1.default.subroutine".equals(uid);
  357. }
  358. public boolean isUnrecognizedGraphicType()
  359. {
  360. return graphic != null && graphic.type == null;
  361. }
  362. public Constraints getConstraints()
  363. {
  364. return constraints;
  365. }
  366. public boolean hasChildren()
  367. {
  368. return children != null && children.size() > 0;
  369. }
  370. @Override
  371. public String toString()
  372. {
  373. return uid != null ? uid : tid;
  374. }
  375. @Override
  376. public void postDeserialize()
  377. {
  378. if (isGroup() && hasChildren())
  379. {
  380. normalizeChildrenCoordinates();
  381. adjustZOrder();
  382. }
  383. }
  384. /**
  385. * Some Gliffy diagrams have groups whose children have negative coordinates.
  386. * This is a problem in draw.io as they get set to 0.
  387. * This method expands the groups left and up and adjusts children's coordinates so that they are never less than zero.
  388. */
  389. private void normalizeChildrenCoordinates()
  390. {
  391. //Sometimes, a group does not have children
  392. if (!hasChildren())
  393. {
  394. return;
  395. }
  396. //sorts the list to find the leftmost child and it's X
  397. Comparator<GliffyObject> cx = new Comparator<GliffyObject>()
  398. {
  399. @Override
  400. public int compare(GliffyObject o1, GliffyObject o2)
  401. {
  402. return (int) (o1.x - o2.x);
  403. }
  404. };
  405. Collections.sort(children, cx);
  406. float xMin = children.get(0).x;
  407. if (xMin < 0)
  408. {
  409. width += -xMin; //increase width
  410. x += xMin;
  411. for (GliffyObject child : children) //increase x
  412. child.x += -xMin;
  413. }
  414. //sorts the list to find the uppermost child and it's Y
  415. Comparator<GliffyObject> cy = new Comparator<GliffyObject>()
  416. {
  417. @Override
  418. public int compare(GliffyObject o1, GliffyObject o2)
  419. {
  420. return (int) (o1.y - o2.y);
  421. }
  422. };
  423. Collections.sort(children, cy);
  424. float yMin = children.get(0).y;
  425. if (yMin < 0)
  426. {
  427. height += -yMin; //increase height
  428. y += yMin;
  429. for (GliffyObject child : children) //increase y
  430. child.y += -yMin;
  431. }
  432. }
  433. /**
  434. * Fix for https://desk.draw.io/helpdesk/tickets/5205
  435. * Since Gliffy can have groups whose children interleave in terms of z order and we can't, we assign the group a z order
  436. * to that of it's highest ordered rectangle child
  437. */
  438. private void adjustZOrder()
  439. {
  440. Integer maxOrder = null;
  441. for(GliffyObject c : children)
  442. {
  443. if(c.uid != null && c.uid.equals("com.gliffy.shape.basic.basic_v1.default.rectangle") && c.x == 0 && c.y== 0 && c.width == width && c.height == height)
  444. {
  445. try {
  446. Integer childOrder = Integer.parseInt(c.order);
  447. if(maxOrder == null || childOrder > maxOrder)
  448. {
  449. maxOrder = childOrder;
  450. }
  451. } catch (NumberFormatException e) {}
  452. }
  453. }
  454. if(maxOrder != null)
  455. this.order = maxOrder.toString();
  456. }
  457. private mxGeometry getAdjustShifts(double[] arr, double x, double y, double w, double h)
  458. {
  459. double xShift = (Math.abs(arr[0]) < 1 ? w * arr[0] : arr[0]);
  460. double yShift = (Math.abs(arr[1]) < 1 ? h * arr[1] : arr[1]);
  461. double wShift = (Math.abs(arr[2]) < 1 ? w * arr[2] : arr[2]);
  462. double hShift = (Math.abs(arr[3]) < 1 ? h * arr[3] : arr[3]);
  463. mxGeometry mod = new mxGeometry(x + xShift, y + yShift, w + wShift, h + hShift);
  464. //TODO test all possible cases!
  465. if (rotation > 0)
  466. {
  467. mxGeometry orig = new mxGeometry(x, y, w, h);
  468. Utils.rotatedGeometry(orig, rotation, 0, 0);
  469. Utils.rotatedGeometry(mod, rotation, 0, 0);
  470. xShift += mod.getX() - orig.getX();
  471. yShift += mod.getY() - orig.getY();
  472. }
  473. mod.setX(xShift);
  474. mod.setY(yShift);
  475. mod.setWidth(wShift);
  476. mod.setHeight(hShift);
  477. return mod;
  478. }
  479. public void adjustGeo(mxGeometry geo)
  480. {
  481. double[] arr = SHAPES_COORD_FIX.get(uid != null? uid : (graphic != null && graphic.getShape() != null ? graphic.getShape().tid : null));
  482. if (arr != null)
  483. {
  484. double x = geo.getX(), y = geo.getY(), w = geo.getWidth(), h = geo.getHeight();
  485. mxGeometry shifts = getAdjustShifts(arr, x, y, w, h);
  486. geo.setX(x + shifts.getX());
  487. geo.setY(y + shifts.getY());
  488. geo.setWidth(w + shifts.getWidth());
  489. geo.setHeight(h + shifts.getHeight());
  490. }
  491. }
  492. public void adjustTextPos(GliffyObject textObject)
  493. {
  494. double[] arr = SHAPES_COORD_FIX.get(uid);
  495. if (arr != null && arr.length == 4)
  496. {
  497. mxGeometry shifts = getAdjustShifts(arr, x, y, width, height);
  498. textObject.x -= shifts.getX();
  499. textObject.y -= shifts.getY();
  500. }
  501. }
  502. public boolean isUseFillColor4StrokeColor()
  503. {
  504. return FILLCLR_IS_STROKECLR_SHAPES.contains(uid != null? uid : (graphic != null && graphic.getShape() != null ? graphic.getShape().tid : null));
  505. }
  506. }