VsdxShape.java 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172
  1. /**
  2. * Copyright (c) 2006-2016, JGraph Ltd
  3. * Copyright (c) 2006-2016, Gaudenz Alder
  4. */
  5. package com.mxgraph.io.vsdx;
  6. import java.io.ByteArrayOutputStream;
  7. import java.io.IOException;
  8. import java.io.UnsupportedEncodingException;
  9. import java.util.ArrayList;
  10. import java.util.Arrays;
  11. import java.util.HashMap;
  12. import java.util.HashSet;
  13. import java.util.LinkedHashMap;
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.Set;
  17. import java.util.logging.Logger;
  18. import java.util.zip.Deflater;
  19. import javax.xml.parsers.DocumentBuilder;
  20. import javax.xml.parsers.DocumentBuilderFactory;
  21. import org.apache.commons.codec.binary.Base64;
  22. import org.apache.commons.lang3.StringUtils;
  23. import org.w3c.dom.Element;
  24. import org.w3c.dom.Node;
  25. import org.w3c.dom.NodeList;
  26. import com.mxgraph.io.vsdx.theme.Color;
  27. import com.mxgraph.model.mxCell;
  28. import com.mxgraph.model.mxGeometry;
  29. import com.mxgraph.online.Utils;
  30. import com.mxgraph.util.mxConstants;
  31. import com.mxgraph.util.mxPoint;
  32. import com.mxgraph.util.mxResources;
  33. import com.mxgraph.view.mxGraph;
  34. /**
  35. * This class is a wrapper for one Shape Element.<br/>
  36. * This class is responsible for retrieve all the properties of the shape and add it
  37. * to the graph. If a property is not found in the shape element but it is an instance
  38. * of a Master, the property is taken from the masterShape element. If the property
  39. * is not found neither in the masterShape , and it has a reference to a stylesheet
  40. * the property is taken from there.
  41. */
  42. public class VsdxShape extends Shape
  43. {
  44. private static final String ARROW_NO_FILL_MARKER = "0";
  45. /**
  46. * Number of d.p. to round non-integers to
  47. */
  48. static public int maxDp = 2;
  49. // For debugging to switch off shape matching by name
  50. static public boolean USE_SHAPE_MATCH = true;
  51. /**
  52. * Whether or not to assume HTML labels
  53. */
  54. public boolean htmlLabels = true;
  55. /**
  56. * Master Shape referenced by the shape.
  57. */
  58. protected Shape masterShape;
  59. /**
  60. * Master element referenced by the shape.
  61. */
  62. protected mxVsdxMaster master;
  63. /**
  64. * If the shape is a sub shape, this is a reference to its root shape, otherwise null
  65. */
  66. protected VsdxShape rootShape = this;
  67. public double parentHeight;
  68. /**
  69. * The prefix of the shape name
  70. */
  71. protected String shapeName = null;
  72. /**
  73. * Whether this cell is a vertex
  74. */
  75. protected boolean vertex = true;
  76. protected Map<Integer, VsdxShape> childShapes = new HashMap<Integer, VsdxShape>();
  77. protected static DocumentBuilder docBuilder = null;
  78. public static final Set<String> OFFSET_ARRAY = new HashSet<String>(Arrays.asList(
  79. new String[] {"Organizational unit",
  80. "Domain 3D"}
  81. ));
  82. public static final String stencilTemplate = "<shape h=\"htemplate\" w=\"wtemplate\" aspect=\"variable\" strokewidth=\"inherit\"><connections></connections><background></background><foreground></foreground></shape>";
  83. public static final float[] arrowSizes = {2, 3, 5, 7, 9, 22, 45};
  84. public static final Map<Integer, String> arrowTypes;
  85. static
  86. {
  87. try
  88. {
  89. mxResources.add("com/mxgraph/io/vdx/resources/edgeNameU");
  90. mxResources.add("com/mxgraph/io/vdx/resources/nameU");
  91. DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
  92. docBuilder = docFactory.newDocumentBuilder();
  93. }
  94. catch (Exception e)
  95. {
  96. // todo
  97. }
  98. arrowTypes = new HashMap<Integer, String>();
  99. arrowTypes.put(0, mxConstants.NONE);
  100. arrowTypes.put(1, mxConstants.ARROW_OPEN);
  101. arrowTypes.put(2, "blockThin");
  102. arrowTypes.put(3, mxConstants.ARROW_OPEN);
  103. arrowTypes.put(4, mxConstants.ARROW_BLOCK);
  104. arrowTypes.put(5, mxConstants.ARROW_CLASSIC);
  105. arrowTypes.put(10, mxConstants.ARROW_OVAL);
  106. arrowTypes.put(13, mxConstants.ARROW_BLOCK);
  107. arrowTypes.put(14, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
  108. arrowTypes.put(17, ARROW_NO_FILL_MARKER + mxConstants.ARROW_CLASSIC);
  109. arrowTypes.put(20, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
  110. arrowTypes.put(22, ARROW_NO_FILL_MARKER + "diamond");
  111. arrowTypes.put(23, "dash");
  112. arrowTypes.put(24, "ERone");
  113. arrowTypes.put(25, "ERmandOne");
  114. arrowTypes.put(27, "ERmany");
  115. arrowTypes.put(28, "ERoneToMany");
  116. arrowTypes.put(29, "ERzeroToMany");
  117. arrowTypes.put(30, "ERzeroToOne");
  118. //approximations
  119. arrowTypes.put(6, mxConstants.ARROW_BLOCK);
  120. arrowTypes.put(7, mxConstants.ARROW_OPEN);
  121. arrowTypes.put(8, mxConstants.ARROW_CLASSIC);
  122. arrowTypes.put(9, "openAsync");
  123. arrowTypes.put(11, "diamond");
  124. arrowTypes.put(12, mxConstants.ARROW_OPEN);
  125. arrowTypes.put(15, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
  126. arrowTypes.put(16, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
  127. arrowTypes.put(18, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
  128. arrowTypes.put(19, ARROW_NO_FILL_MARKER + mxConstants.ARROW_CLASSIC);
  129. arrowTypes.put(21, ARROW_NO_FILL_MARKER + "diamond");
  130. arrowTypes.put(26, "ERmandOne");
  131. arrowTypes.put(31, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
  132. arrowTypes.put(32, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
  133. arrowTypes.put(33, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
  134. arrowTypes.put(34, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
  135. arrowTypes.put(35, mxConstants.ARROW_OVAL);
  136. arrowTypes.put(36, mxConstants.ARROW_OVAL);
  137. arrowTypes.put(37, mxConstants.ARROW_OVAL);
  138. arrowTypes.put(38, mxConstants.ARROW_OVAL);
  139. arrowTypes.put(39, mxConstants.ARROW_BLOCK);
  140. arrowTypes.put(40, ARROW_NO_FILL_MARKER + mxConstants.ARROW_BLOCK);
  141. arrowTypes.put(41, ARROW_NO_FILL_MARKER + mxConstants.ARROW_OVAL);
  142. arrowTypes.put(42, mxConstants.ARROW_OVAL);
  143. arrowTypes.put(43, mxConstants.ARROW_OPEN);
  144. arrowTypes.put(44, mxConstants.ARROW_OPEN);
  145. arrowTypes.put(45, mxConstants.ARROW_OPEN);
  146. }
  147. private final static Logger LOGGER = Logger.getLogger(VsdxShape.class.getName());
  148. /**
  149. * Create a new instance of mxVdxShape.
  150. * This method get the references to the master element, master shape
  151. * and stylesheet.
  152. * @param shape
  153. */
  154. public VsdxShape(mxVsdxPage page, Element shape, boolean vertex, Map<String, mxVsdxMaster> masters, mxVsdxMaster master, mxVsdxModel model)
  155. {
  156. super(shape, model);
  157. String masterId = this.getMasterId();
  158. String masterShapeLocal = this.getShapeMasterId();
  159. if (masterId != null)
  160. {
  161. this.master = masters.get(masterId);
  162. }
  163. else
  164. {
  165. this.master = master;
  166. }
  167. if (this.master != null)
  168. {
  169. // Check if the master ID corresponds to the one passed in. If it doesn't, or doesn't
  170. // exist on this shape, this shape is within a group that has that master
  171. if (masterId == null && masterShapeLocal != null)
  172. {
  173. this.masterShape = this.master.getSubShape(masterShapeLocal);
  174. }
  175. else
  176. {
  177. this.masterShape = this.master.getMasterShape();
  178. }
  179. }
  180. if (this.debug != null && this.masterShape != null)
  181. {
  182. this.masterShape.debug = this.debug;
  183. }
  184. String name = getNameU();
  185. int index = name.lastIndexOf(".");
  186. if (index != -1)
  187. {
  188. name = name.substring(0, index);
  189. }
  190. this.shapeName = name;
  191. // Get sub-shapes
  192. NodeList shapesList = shape.getElementsByTagName(mxVsdxConstants.SHAPES);
  193. if (shapesList != null && shapesList.getLength() > 0)
  194. {
  195. Element shapesElement = (Element) shapesList.item(0);
  196. this.childShapes = page.parseShapes(shapesElement, this.master, false);
  197. }
  198. for (Map.Entry<Integer, VsdxShape> entry : childShapes.entrySet())
  199. {
  200. entry.getValue().setRootShape(this);
  201. }
  202. double rotation = this.calcRotation();
  203. this.rotation = rotation * 100/100;
  204. this.rotation = this.rotation % 360.0;
  205. this.vertex = vertex;
  206. mxVsdxTheme theme = model.getThemes().get(page.getCellIntValue("ThemeIndex", 33));
  207. int variant = page.getCellIntValue("VariationColorIndex", 0);
  208. setThemeAndVariant(theme, variant);
  209. //process shape geometry
  210. if (masterShape != null)
  211. {
  212. masterShape.processGeomList(null);
  213. processGeomList(masterShape.getGeomList());
  214. //recalculate width and height using master data
  215. if (this.width == 0) this.width = getScreenNumericalValue(getCellElement(mxVsdxConstants.WIDTH), 0);
  216. if (this.height == 0) this.height = getScreenNumericalValue(getCellElement(mxVsdxConstants.HEIGHT), 0);
  217. }
  218. else
  219. {
  220. processGeomList(null);
  221. }
  222. }
  223. /**
  224. * Locates the first entry for the specified attribute string in the shape hierarchy.
  225. * The order is to look locally, then delegate the request to the master shape
  226. * if it doesn't exist locally
  227. * @param key The key of the shape to find
  228. * @return the Element that first resolves to that shape key or null or none is found
  229. */
  230. public Element getShapeNode(String key)
  231. {
  232. Element elem = this.cellElements.get(key);
  233. if (elem == null && this.masterShape != null)
  234. {
  235. return this.masterShape.getCellElement(key);
  236. }
  237. return elem;
  238. }
  239. /**
  240. * Returns the value of the Text element.<br/>
  241. * If the shape has no text, it is obtained from the master shape.
  242. * @return Text label of the shape.
  243. */
  244. public String getTextLabel()
  245. {
  246. NodeList txtChildren = getTextChildren();
  247. if (txtChildren == null && masterShape != null)
  248. {
  249. txtChildren = masterShape.getTextChildren();
  250. }
  251. if (this.htmlLabels)
  252. {
  253. if (txtChildren != null)
  254. {
  255. // Collect text into same formatting paragraphs. If there's one paragraph, use the new system, otherwise
  256. // leave it to the old one.
  257. if (this.paragraphs == null)
  258. {
  259. initLabels(txtChildren);
  260. }
  261. if (this.paragraphs.size() == 0)
  262. {
  263. // valid way to have an empty label override a master value "<text />"
  264. return "";
  265. }
  266. else if (this.paragraphs.size() == 1)
  267. {
  268. return createHybridLabel(this.paragraphs.keySet().iterator().next());
  269. }
  270. else
  271. {
  272. return getHtmlTextContent(txtChildren);
  273. }
  274. }
  275. }
  276. else
  277. {
  278. String text = this.getText();
  279. if (text == null && masterShape != null)
  280. {
  281. return masterShape.getText();
  282. }
  283. else
  284. {
  285. return text;
  286. }
  287. }
  288. return null;
  289. }
  290. /**
  291. * Initialises the text labels
  292. * @param children the text Elements
  293. */
  294. protected void initLabels(NodeList children)
  295. {
  296. // Lazy init
  297. paragraphs = new LinkedHashMap<String,Paragraph>();
  298. String ch = null;
  299. String pg = null;
  300. String fld = null;
  301. for (int index = 0; index < children.getLength(); index++)
  302. {
  303. String value = null;
  304. Node node = children.item(index);
  305. String nodeName = node.getNodeName();
  306. switch (nodeName)
  307. {
  308. case "cp":
  309. {
  310. Element elem = (Element)node;
  311. ch = elem.getAttribute("IX");
  312. }
  313. break;
  314. case "tp":
  315. {
  316. // TODO
  317. Element elem = (Element)node;
  318. elem.getAttribute("IX");
  319. }
  320. break;
  321. case "pp":
  322. {
  323. Element elem = (Element)node;
  324. pg = elem.getAttribute("IX");
  325. }
  326. break;
  327. case "fld":
  328. {
  329. Element elem = (Element)node;
  330. fld = elem.getAttribute("IX");
  331. break;
  332. }
  333. case "#text":
  334. {
  335. value = StringUtils.chomp(node.getTextContent());
  336. // Assumes text is always last
  337. // null key is allowed
  338. Paragraph para = paragraphs.get(pg);
  339. if (para == null)
  340. {
  341. para = new Paragraph(value, ch, pg, fld);
  342. paragraphs.put(pg, para);
  343. }
  344. else
  345. {
  346. para.addText(value, ch, fld);
  347. }
  348. }
  349. }
  350. }
  351. }
  352. /**
  353. *
  354. * @param index
  355. * @return
  356. */
  357. protected String createHybridLabel(String index)
  358. {
  359. Paragraph para = this.paragraphs.get(index);
  360. // Paragraph
  361. this.styleMap.put(mxConstants.STYLE_ALIGN, getHorizontalAlign(index, false));
  362. this.styleMap.put(mxConstants.STYLE_SPACING_LEFT, getIndentLeft(index));
  363. this.styleMap.put(mxConstants.STYLE_SPACING_RIGHT, getIndentRight(index));
  364. this.styleMap.put(mxConstants.STYLE_SPACING_TOP, getSpBefore(index));
  365. this.styleMap.put(mxConstants.STYLE_SPACING_BOTTOM, getSpAfter(index));
  366. //this.styleMap.put("text-indent", getIndentFirst(index));
  367. this.styleMap.put(mxConstants.STYLE_VERTICAL_ALIGN, getAlignVertical());
  368. this.styleMap.put("fontColor", getTextColor(index));
  369. this.styleMap.put("fontSize", String.valueOf(Double.parseDouble(this.getTextSize(index))));
  370. this.styleMap.put("fontFamily", getTextFont(index));
  371. // Character
  372. int fontStyle = isBold(index) ? mxConstants.FONT_BOLD : 0;
  373. fontStyle |= isItalic(index) ? mxConstants.FONT_ITALIC : 0;
  374. fontStyle |= isUnderline(index) ? mxConstants.FONT_UNDERLINE : 0;
  375. this.styleMap.put("fontStyle", String.valueOf(fontStyle));
  376. this.styleMap.put(mxConstants.STYLE_TEXT_OPACITY, getTextOpacity(index));
  377. int numValues = para.numValues();
  378. String result = null;
  379. for (int i = 0; i < numValues; i++)
  380. {
  381. String value = para.getValue(i);
  382. if (value.isEmpty() && this.fields != null)
  383. {
  384. String fieldIx = para.getField(i);
  385. if (fieldIx != null)
  386. {
  387. value = this.fields.get(fieldIx);
  388. if (value == null && masterShape != null && masterShape.fields != null)
  389. {
  390. value = masterShape.fields.get(fieldIx);
  391. }
  392. }
  393. }
  394. if (value != null)
  395. {
  396. result = result == null ? value : result + value;
  397. }
  398. }
  399. return result;
  400. }
  401. /**
  402. * Checks if a nameU is for big connectors.
  403. * @param nameU NameU attribute.
  404. * @return Returns <code>true</code> if a nameU is for big connectors.
  405. */
  406. public boolean isConnectorBigNameU(String nameU)
  407. {
  408. return nameU.startsWith("60 degree single")
  409. || nameU.startsWith("45 degree single")
  410. || nameU.startsWith("45 degree double")
  411. || nameU.startsWith("60 degree double")
  412. || nameU.startsWith("45 degree tail")
  413. || nameU.startsWith("60 degree tail")
  414. || nameU.startsWith("45 degree tail")
  415. || nameU.startsWith("60 degree tail")
  416. || nameU.startsWith("Flexi-arrow 2")
  417. || nameU.startsWith("Flexi-arrow 1")
  418. || nameU.startsWith("Flexi-arrow 3")
  419. || nameU.startsWith("Double flexi-arrow")
  420. || nameU.startsWith("Fancy arrow");
  421. }
  422. /**
  423. * Checks if the shape represents a vertex.
  424. * @return Returns <code>true</code> if the shape represents a vertex.
  425. */
  426. public boolean isVertex()
  427. {
  428. return vertex;
  429. }
  430. /**
  431. * Returns the coordinates of the top left corner of the Shape.
  432. * When a coordinate is not found, it is taken from masterShape.
  433. * @param parentHeight Height of the parent cell of the shape.
  434. * @param rotation whether to allow for cell rotation
  435. * @return mxPoint that represents the coordinates
  436. */
  437. public mxPoint getOriginPoint(double parentHeight, boolean rotation)
  438. {
  439. double px = this.getPinX();
  440. double py = this.getPinY();
  441. double lpy = this.getLocPinY();
  442. double lpx = this.getLocPinX();
  443. double w = getScreenNumericalValue(this.getShapeNode(mxVsdxConstants.WIDTH), 0);
  444. double h = getScreenNumericalValue(this.getShapeNode(mxVsdxConstants.HEIGHT), 0);
  445. double x = px - lpx;
  446. double y = parentHeight - ((py) + (h - lpy));
  447. // If the location pins are not in the center of the vertex we
  448. // need to translate the origin
  449. if (rotation && (lpy != h/2 || lpx != w/2))
  450. {
  451. if (this.rotation != 0)
  452. {
  453. double vecX = w/2 - lpx;
  454. double vecY = lpy - h/2;
  455. double cos = Math.cos(Math.toRadians(360 - this.rotation));
  456. double sin = Math.sin(Math.toRadians(360 - this.rotation));
  457. return new mxPoint(x + vecX - (vecX * cos - vecY * sin), (vecX * sin + vecY * cos) + y -vecY);
  458. }
  459. }
  460. return new mxPoint(x, y);
  461. }
  462. /**
  463. * Returns the width and height of the Shape expressed like an mxPoint.<br/>
  464. * x = width<br/>
  465. * y = height<br/>
  466. * When a dimension is not found, it is taken from masterShape.
  467. * @return mxPoint that represents the dimensions of the shape.
  468. */
  469. public mxPoint getDimensions()
  470. {
  471. double w = getScreenNumericalValue(this.getShapeNode(mxVsdxConstants.WIDTH), 0);
  472. double h = getScreenNumericalValue(this.getShapeNode(mxVsdxConstants.HEIGHT), 0);
  473. return new mxPoint(w, h);
  474. }
  475. /**
  476. * Returns the value of the pinX element.
  477. * @return The shape pinX element
  478. */
  479. public double getPinX()
  480. {
  481. return getScreenNumericalValue(this.getShapeNode(mxVsdxConstants.PIN_X), 0);
  482. }
  483. /**
  484. * Returns the value of the pinY element in pixels.
  485. * @return Numerical value of the pinY element.
  486. */
  487. public double getPinY()
  488. {
  489. return getScreenNumericalValue(this.getShapeNode(mxVsdxConstants.PIN_Y), 0);
  490. }
  491. /**
  492. * Returns the value of the locPinX element in pixels.
  493. * @return Numerical value of the pinY element.
  494. */
  495. public double getLocPinX()
  496. {
  497. return getScreenNumericalValue(this.getShapeNode(mxVsdxConstants.LOC_PIN_X), 0);
  498. }
  499. /**
  500. * Returns the value of the locPinY element in pixels.
  501. * @return Numerical value of the locPinY element.
  502. */
  503. public double getLocPinY()
  504. {
  505. return getScreenNumericalValue(this.getShapeNode(mxVsdxConstants.LOC_PIN_Y), 0);
  506. }
  507. /**
  508. * Returns the opacity of the Shape.<br/>
  509. * @return Double in the range of (transparent = 0)..(100 = opaque)
  510. */
  511. private double getOpacity(String key)
  512. {
  513. double opacity = 100;
  514. if (this.isGroup())
  515. {
  516. opacity = 0;
  517. }
  518. opacity = getValueAsDouble(this.getCellElement(key), 0);
  519. opacity = 100 - opacity * 100;
  520. opacity = Math.max(opacity, 0);
  521. opacity = Math.min(opacity, 100);
  522. return opacity;
  523. }
  524. /**
  525. * Returns the background color for apply in the gradient.<br/>
  526. * If no gradient must be applicated, returns an empty string.
  527. * @return hexadecimal representation of the color.
  528. */
  529. private String getGradient()
  530. {
  531. String gradient = "";
  532. String fillPattern = this.getValue(this.getCellElement(mxVsdxConstants.FILL_PATTERN), "0");
  533. if (fillPattern.equals("25") || fillPattern.equals("27") || fillPattern.equals("28") || fillPattern.equals("30"))
  534. {
  535. gradient = this.getColor(this.getCellElement(mxVsdxConstants.FILL_BKGND));
  536. }
  537. else
  538. {
  539. mxVsdxTheme theme = getTheme();
  540. if (theme != null)
  541. {
  542. int styleFillClr = Integer.parseInt(this.getValue(this.getCellElement("QuickStyleFillColor"), "1"));
  543. int styleFillMtx = Integer.parseInt(this.getValue(this.getCellElement("QuickStyleFillMatrix"), "0"));
  544. Color gradColor = theme.getFillGraientColor(styleFillClr, styleFillMtx);
  545. if (gradColor != null) gradient = gradColor.toHexStr();
  546. }
  547. }
  548. return gradient;
  549. }
  550. /**
  551. * Returns the direction of the gradient.<br/>
  552. * If no gradient has to be applied, returns an empty string.
  553. * @return Direction.(east, west, north or south)
  554. */
  555. private String getGradientDirection()
  556. {
  557. String direction = "";
  558. String fillPattern = this.getValue(this.getCellElement(mxVsdxConstants.FILL_PATTERN), "0");
  559. if (fillPattern.equals("25"))
  560. {
  561. direction = mxConstants.DIRECTION_EAST;
  562. }
  563. else if (fillPattern.equals("27"))
  564. {
  565. direction = mxConstants.DIRECTION_WEST;
  566. }
  567. else if (fillPattern.equals("28"))
  568. {
  569. direction = mxConstants.DIRECTION_SOUTH;
  570. }
  571. else if (fillPattern.equals("30"))
  572. {
  573. direction = mxConstants.DIRECTION_NORTH;
  574. }
  575. return direction;
  576. }
  577. /**
  578. * Returns the rotation of the shape.<br/>
  579. * @return Rotation of the shape in degrees.
  580. */
  581. public double calcRotation()
  582. {
  583. double rotation = Double.valueOf(this.getValue(this.getCellElement(mxVsdxConstants.ANGLE), "0"));
  584. rotation = Math.toDegrees(rotation);
  585. rotation = rotation % 360;
  586. rotation = rotation * 100/100;
  587. return 360 - rotation;
  588. }
  589. /**
  590. * Used to pass in a parents rotation to the child
  591. * @param parentRotation the rotation of the parent
  592. */
  593. public void propagateRotation(double parentRotation)
  594. {
  595. this.rotation += parentRotation;
  596. this.rotation %= 360;
  597. this.rotation = this.rotation * 100/100;
  598. }
  599. /**
  600. * Returns the top spacing of the label in pixels.<br/>
  601. * The property may to be defined in master shape or text stylesheet.<br/>
  602. * @return Top spacing in double precision.
  603. */
  604. public double getTopSpacing()
  605. {
  606. double topMargin = this.getTextTopMargin();
  607. topMargin = (topMargin / 2 - 2.8) * 100/100;
  608. return topMargin;
  609. }
  610. /**
  611. * Returns the bottom spacing of the label in pixels.<br/>
  612. * The property may to be defined in master shape or text stylesheet.<br/>
  613. * @return Bottom spacing in double precision.
  614. */
  615. public double getBottomSpacing()
  616. {
  617. double bottomMargin = this.getTextBottomMargin();
  618. bottomMargin = (bottomMargin / 2 - 2.8) * 100/100;
  619. return bottomMargin;
  620. }
  621. /**
  622. * Returns the left spacing of the label in pixels.<br/>
  623. * The property may to be defined in master shape or text stylesheet.<br/>
  624. * @return Left spacing in double precision.
  625. */
  626. public double getLeftSpacing()
  627. {
  628. double leftMargin = this.getTextLeftMargin();
  629. leftMargin = (leftMargin / 2 - 2.8) * 100/100;
  630. return leftMargin;
  631. }
  632. /**
  633. * Returns the right spacing of the label in pixels.<br/>
  634. * The property may to be defined in master shape or text stylesheet.<br/>
  635. * @return Right spacing in double precision.
  636. */
  637. public double getRightSpacing()
  638. {
  639. double rightMargin = this.getTextRightMargin();
  640. rightMargin = (rightMargin / 2 - 2.8) * 100/100;
  641. return rightMargin;
  642. }
  643. /**
  644. * Checks if the label must be rotated.<br/>
  645. * The property may to be defined in master shape or text stylesheet.<br/>
  646. * @return Returns <code>true<code/> if the label should remain horizontal.
  647. */
  648. public boolean getLabelRotation()
  649. {
  650. boolean hor = true;
  651. //Defines rotation.
  652. double rotation = this.calcRotation();
  653. double angle = Double.valueOf(this.getValue(this.getCellElement(mxVsdxConstants.TXT_ANGLE), "0"));
  654. angle = Math.toDegrees(angle);
  655. angle = angle - rotation;
  656. if (!(Math.abs(angle) < 45 || Math.abs(angle) > 270))
  657. {
  658. hor = false;
  659. }
  660. return hor;
  661. }
  662. /**
  663. * Analyzes the shape and returns a string with the style.
  664. * @return style read from the shape.
  665. */
  666. public Map<String, String> getStyleFromShape()
  667. {
  668. styleMap.put("vsdxID", this.getId().toString());
  669. // Rotation.
  670. String labelRotation = getLabelRotation() ? "1" : "0";
  671. this.rotation = Math.round(this.rotation);
  672. if (!labelRotation.equals("1") && this.rotation != 90 && this.rotation != 270)
  673. {
  674. styleMap.put(mxConstants.STYLE_HORIZONTAL, labelRotation);
  675. }
  676. if (this.rotation != 0)
  677. {
  678. styleMap.put(mxConstants.STYLE_ROTATION, Double.toString(this.rotation));
  679. }
  680. // Fill color
  681. String fillcolor = getFillColor();
  682. if (!fillcolor.equals(""))
  683. {
  684. styleMap.put(mxConstants.STYLE_FILLCOLOR, fillcolor);
  685. }
  686. else
  687. {
  688. styleMap.put(mxConstants.STYLE_FILLCOLOR, "none");
  689. }
  690. Integer id = this.getId();
  691. this.styleDebug("ID = " + id + " , Fill Color = " + fillcolor);
  692. //Defines gradient
  693. String gradient = getGradient();
  694. if (!gradient.equals(""))
  695. {
  696. styleMap.put(mxConstants.STYLE_GRADIENTCOLOR, gradient);
  697. String gradientDirection = getGradientDirection();
  698. if (!gradientDirection.equals("") && !gradientDirection.equals(mxConstants.DIRECTION_SOUTH))
  699. {
  700. styleMap.put(mxConstants.STYLE_GRADIENT_DIRECTION, gradientDirection);
  701. }
  702. }
  703. else
  704. {
  705. styleMap.put(mxConstants.STYLE_GRADIENTCOLOR, "none");
  706. }
  707. double opacity = this.getOpacity(mxVsdxConstants.FILL_FOREGND_TRANS);
  708. if (opacity < 100)
  709. {
  710. styleMap.put(mxConstants.STYLE_FILL_OPACITY, Double.toString(opacity));
  711. }
  712. opacity = this.getOpacity(mxVsdxConstants.LINE_COLOR_TRANS);
  713. if (opacity < 100)
  714. {
  715. styleMap.put(mxConstants.STYLE_STROKE_OPACITY, Double.toString(opacity));
  716. }
  717. Map<String, String> form = getForm();
  718. if (form.containsKey(mxConstants.STYLE_SHAPE) &&
  719. (form.get(mxConstants.STYLE_SHAPE).startsWith("image;")))
  720. {
  721. styleMap.put(mxConstants.STYLE_WHITE_SPACE, "wrap");
  722. }
  723. styleMap.putAll(form);
  724. //Defines line Pattern
  725. if (isDashed())
  726. {
  727. styleMap.put(mxConstants.STYLE_DASHED, "1");
  728. String dashPattern = getDashPattern();
  729. if (dashPattern != null)
  730. {
  731. styleMap.put(mxConstants.STYLE_DASH_PATTERN, dashPattern);
  732. }
  733. }
  734. String color = getStrokeColor();
  735. double tr = this.getStrokeTransparency();
  736. this.styleDebug("ID = " + id + " , Color = " + color + " , stroke transparency = " + tr);
  737. if (!color.equals("") && tr != 1)
  738. {
  739. styleMap.put(mxConstants.STYLE_STROKECOLOR, color);
  740. }
  741. else
  742. {
  743. //styleMap.put(mxConstants.STYLE_STROKECOLOR, "none");
  744. }
  745. //Defines the line width
  746. double lWeight = getLineWidth() * 100/100;
  747. if (lWeight != 1)
  748. {
  749. styleMap.put(mxConstants.STYLE_STROKEWIDTH, Double.toString(lWeight));
  750. }
  751. /** SHADOW **/
  752. if (isShadow())
  753. {
  754. styleMap.put(mxConstants.STYLE_SHADOW, mxVsdxConstants.TRUE);
  755. }
  756. //Defines label top spacing
  757. double topMargin = getTopSpacing() * 100/100;
  758. if (topMargin != 0)
  759. {
  760. styleMap.put(mxConstants.STYLE_SPACING_TOP, Double.toString(topMargin));
  761. }
  762. //Defines label bottom spacing
  763. double bottomMargin = getBottomSpacing() * 100/100;
  764. if (bottomMargin != 0)
  765. {
  766. styleMap.put(mxConstants.STYLE_SPACING_BOTTOM, Double.toString(bottomMargin));
  767. }
  768. //Defines label left spacing
  769. double leftMargin = getLeftSpacing() * 100/100;
  770. if (leftMargin != 0)
  771. {
  772. styleMap.put(mxConstants.STYLE_SPACING_LEFT, Double.toString(leftMargin));
  773. }
  774. //Defines label right spacing
  775. double rightMargin = getRightSpacing() * 100/100;
  776. if(rightMargin !=0)
  777. {
  778. styleMap.put(mxConstants.STYLE_SPACING_RIGHT, Double.toString(rightMargin));
  779. }
  780. String direction = getDirection(form);
  781. if (direction != mxConstants.DIRECTION_EAST)
  782. {
  783. styleMap.put(mxConstants.STYLE_DIRECTION, direction);
  784. }
  785. Element xForm = (Element) shape.getElementsByTagName(mxVsdxConstants.X_FORM).item(0);
  786. if (xForm != null)
  787. {
  788. Node flipX = xForm.getElementsByTagName(mxVsdxConstants.FLIP_X).item(0);
  789. Node flipY = xForm.getElementsByTagName(mxVsdxConstants.FLIP_Y).item(0);
  790. if (flipX != null && flipX.getTextContent().equals("1"))
  791. {
  792. styleMap.put(mxConstants.STYLE_FLIPH, "1");
  793. }
  794. if (flipY != null && flipY.getTextContent().equals("1"))
  795. {
  796. styleMap.put(mxConstants.STYLE_FLIPV, "1");
  797. }
  798. }
  799. resolveCommonStyles();
  800. return this.styleMap;
  801. }
  802. private String getDashPattern() {
  803. ArrayList<Double> pattern = null;
  804. String linePattern = this.getValue(this.getCellElement(mxVsdxConstants.LINE_PATTERN), "0");
  805. if (linePattern.equals("Themed"))
  806. {
  807. mxVsdxTheme theme = getTheme();
  808. if (theme != null)
  809. {
  810. int styleLineMtx = Integer.parseInt(this.getValue(this.getCellElement("QuickStyleLineMatrix"), "0"));
  811. pattern = isVertex()? theme.getLineDashPattern(styleLineMtx) : theme.getConnLineDashPattern(styleLineMtx);
  812. }
  813. }
  814. else
  815. {
  816. pattern = getLineDashPattern(Integer.parseInt(linePattern));
  817. }
  818. if (pattern != null && !pattern.isEmpty())
  819. {
  820. StringBuilder str = new StringBuilder();
  821. for (Double len : pattern)
  822. {
  823. str.append(String.format("%.2f ", len));
  824. }
  825. return str.toString().trim();
  826. }
  827. return null;
  828. }
  829. /**
  830. * Checks if the lines of the shape are dashed.<br/>
  831. * The property may to be defined in master shape or line stylesheet.<br/>
  832. * @return Returns <code>true</code> if the lines of the shape are dashed.
  833. */
  834. public boolean isDashed()
  835. {
  836. String linePattern = this.getValue(this.getCellElement(mxVsdxConstants.LINE_PATTERN), "0");
  837. if (linePattern.equals("Themed"))
  838. {
  839. mxVsdxTheme theme = getTheme();
  840. if (theme != null)
  841. {
  842. int styleLineMtx = Integer.parseInt(this.getValue(this.getCellElement("QuickStyleLineMatrix"), "0"));
  843. return isVertex()? theme.isLineDashed(styleLineMtx) : theme.isConnLineDashed(styleLineMtx);
  844. }
  845. }
  846. else if (!(linePattern.equals("0") || linePattern.equals("1")))
  847. {
  848. return true;
  849. }
  850. return false;
  851. }
  852. /**
  853. * Returns the line width.<br/>
  854. * The property may to be defined in master shape or line stylesheet.<br/>
  855. * @return Line width in pixels.
  856. */
  857. public double getLineWidth()
  858. {
  859. //if an edge has a fill geometry, then the line width matches the min of the shape width & height
  860. if (!isVertex() && geomList != null && !geomList.isNoFill())
  861. {
  862. return Math.min(height, width);
  863. }
  864. String lineWeight = getValue(this.getCellElement(mxVsdxConstants.LINE_WEIGHT), "0");
  865. double lWeight = 0;
  866. try
  867. {
  868. if (lineWeight.equals("Themed"))
  869. {
  870. mxVsdxTheme theme = getTheme();
  871. if (theme != null)
  872. {
  873. int styleLineMtx = Integer.parseInt(this.getValue(this.getCellElement("QuickStyleLineMatrix"), "0"));
  874. lWeight = (isVertex()? theme.getLineWidth(styleLineMtx) : theme.getConnLineWidth(styleLineMtx)) / 10000.0;
  875. }
  876. }
  877. else
  878. {
  879. lWeight = Double.parseDouble(lineWeight);
  880. lWeight = getScreenNumericalValue(lWeight);
  881. }
  882. }
  883. catch (Exception e)
  884. {
  885. // ignore
  886. }
  887. //Value is fixed for weight < 1
  888. if (lWeight < 1)
  889. {
  890. lWeight *= 2;
  891. }
  892. return lWeight;
  893. }
  894. /**
  895. * Returns the start arrow size.<br/>
  896. * The property may to be defined in master shape or line stylesheet.<br/>
  897. * Determines the value in pixels of each arrow size category in .vdx.
  898. * @return Size in pixels.
  899. */
  900. public float getStartArrowSize()
  901. {
  902. String baSize = getValue(this.getCellElement(mxVsdxConstants.BEGIN_ARROW_SIZE), "4");
  903. try
  904. {
  905. int size = 4;
  906. if (baSize.equals("Themed"))
  907. {
  908. mxVsdxTheme theme = getTheme();
  909. if (theme != null)
  910. {
  911. int styleLineMtx = Integer.parseInt(this.getValue(this.getCellElement("QuickStyleLineMatrix"), "0"));
  912. size = isVertex()? theme.getStartSize(styleLineMtx) : theme.getConnStartSize(styleLineMtx);
  913. }
  914. }
  915. else
  916. {
  917. size = Integer.valueOf(baSize);
  918. }
  919. return VsdxShape.arrowSizes[size];
  920. }
  921. catch (Exception e)
  922. {
  923. // ignore
  924. }
  925. return 4;
  926. }
  927. /**
  928. * Returns the end arrow size.<br/>
  929. * The property may to be defined in master shape or line stylesheet.<br/>
  930. * Determines the value in pixels of each arrow size category in .vdx.
  931. * @return Size in pixels.
  932. */
  933. public float getFinalArrowSize()
  934. {
  935. String eaSize = getValue(this.getCellElement(mxVsdxConstants.END_ARROW_SIZE), "4");
  936. try
  937. {
  938. int size = 4;
  939. if (eaSize.equals("Themed"))
  940. {
  941. mxVsdxTheme theme = getTheme();
  942. if (theme != null)
  943. {
  944. int styleLineMtx = Integer.parseInt(this.getValue(this.getCellElement("QuickStyleLineMatrix"), "0"));
  945. size = isVertex()? theme.getEndSize(styleLineMtx) : theme.getConnEndSize(styleLineMtx);
  946. }
  947. }
  948. else
  949. {
  950. size = Integer.valueOf(eaSize);
  951. }
  952. return VsdxShape.arrowSizes[size];
  953. }
  954. catch (Exception e)
  955. {
  956. // ignore
  957. }
  958. return 4;
  959. }
  960. /**
  961. * Returns whether the cell is Rounded.<br/>
  962. * The property may to be defined in master shape or line stylesheet.<br/>
  963. * @return Returns <code>true</code> if the cell is Rounded.
  964. */
  965. public boolean isRounded()
  966. {
  967. String val = getValue(this.getCellElement(mxVsdxConstants.ROUNDING), "0");
  968. return Double.valueOf(val) > 0;
  969. }
  970. /**
  971. * Return if the line has shadow.<br/>
  972. * The property may to be defined in master shape or line stylesheet.<br/>
  973. * @return Returns <code>mxVdxConstants.TRUE</code> if the line has shadow.
  974. */
  975. public boolean isShadow()
  976. {
  977. // https://msdn.microsoft.com/en-us/library/office/jj230454.aspx TODO
  978. // double shdwShow = this.getNumericalValue(this.getStyleNode(mxVdxConstants.SHDW_PATTERN), 0);
  979. String shdw = this.getValue(this.getCellElement(mxVsdxConstants.SHDW_PATTERN), "0");
  980. if (shdw.equals("Themed"))
  981. {
  982. // TODO get value from theme
  983. }
  984. else if (!shdw.equals("0"))
  985. {
  986. return true;
  987. }
  988. return false;
  989. }
  990. /**
  991. * Returns the style of the edge. (Orthogonal or straight)
  992. * @return Edge Style.
  993. */
  994. public Map<String, String> getEdgeStyle(Map<String, String> edgeShape)
  995. {
  996. Map<String, String> result = new HashMap<String, String>();
  997. String edgeName = edgeShape.get(mxConstants.STYLE_SHAPE);
  998. if (edgeName.equals("mxgraph.lean_mapping.electronic_info_flow_edge"))
  999. {
  1000. result.put(mxConstants.STYLE_EDGE, mxConstants.NONE);
  1001. return result;
  1002. }
  1003. else
  1004. {
  1005. result.put(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_ELBOW);
  1006. return result;
  1007. }
  1008. // else
  1009. // {
  1010. // result.put(mxConstants.STYLE_EDGE, mxConstants.NONE);
  1011. // return result;
  1012. // }
  1013. }
  1014. /**
  1015. * Returns the master's Id of the Shape.
  1016. * @return Master's ID of the shape, null if has not a master.
  1017. */
  1018. public String getMasterId()
  1019. {
  1020. if (shape.hasAttribute(mxVsdxConstants.MASTER))
  1021. {
  1022. return shape.getAttribute(mxVsdxConstants.MASTER);
  1023. }
  1024. else
  1025. {
  1026. return null;
  1027. }
  1028. }
  1029. /**
  1030. * Returns the masterShape's Id of the shape.
  1031. * @return Master Shape's ID of the shape, null if has not a master shape.
  1032. */
  1033. public String getShapeMasterId()
  1034. {
  1035. if (shape.hasAttribute(mxVsdxConstants.MASTER_SHAPE))
  1036. {
  1037. return shape.getAttribute(mxVsdxConstants.MASTER_SHAPE);
  1038. }
  1039. else
  1040. {
  1041. return null;
  1042. }
  1043. }
  1044. /**
  1045. * Checks if a shape contains other shapes inside.
  1046. * @return Returns <code>true</code> if a shape contains other shapes inside.
  1047. */
  1048. public boolean isGroup()
  1049. {
  1050. return shape.getAttribute("Type").equals("Group");
  1051. }
  1052. /**
  1053. * Checks if a shape contains other shapes inside.
  1054. * @return Returns <code>true</code> if a shape contains other shapes inside.
  1055. */
  1056. public static String getType(Element shape)
  1057. {
  1058. return shape.getAttribute("Type");
  1059. }
  1060. public mxVsdxMaster getMaster()
  1061. {
  1062. return master;
  1063. }
  1064. /**
  1065. * Returns the NameU attribute.
  1066. * @return Value of the NameU attribute.
  1067. */
  1068. public String getNameU()
  1069. {
  1070. String result = shape.getAttribute(mxVsdxConstants.NAME_U);
  1071. if ((result == null || result.equals("")) && masterShape != null)
  1072. {
  1073. result = masterShape.getNameU();
  1074. }
  1075. return result;
  1076. }
  1077. /**
  1078. * Returns the master name of the shape
  1079. * @return Master name of the shape
  1080. */
  1081. public String getMasterName()
  1082. {
  1083. return shapeName;
  1084. }
  1085. public void setLabelOffset(mxCell vertex, String style)
  1086. {
  1087. String nameU = "";
  1088. String masterNameU = "";
  1089. if (shape.hasAttribute(mxVsdxConstants.NAME_U))
  1090. {
  1091. nameU = shape.getAttribute(mxVsdxConstants.NAME_U);
  1092. }
  1093. if (this.getMaster() != null && this.getMaster().getMasterElement() != null)
  1094. {
  1095. if (this.getMaster().getMasterElement().hasAttribute(mxVsdxConstants.NAME_U))
  1096. {
  1097. masterNameU = this.getMaster().getMasterElement().getAttribute(mxVsdxConstants.NAME_U);
  1098. }
  1099. }
  1100. //check for shape name/type, because of different (shape specific) treatment of each
  1101. if (nameU.startsWith("Organizational unit")
  1102. || masterNameU.startsWith("Organizational unit"))
  1103. {
  1104. Element control = (Element) shape.getElementsByTagName(mxVsdxConstants.CONTROL).item(0);
  1105. Element xEl = null;
  1106. String xS = "0.0";
  1107. Element yEl = null;
  1108. String yS = "-0.4";
  1109. if (control != null)
  1110. {
  1111. xEl = (Element) control.getElementsByTagName(mxVsdxConstants.X).item(0);
  1112. if (xEl.hasAttribute("F"))
  1113. {
  1114. xS = xEl.getAttribute("F");
  1115. }
  1116. else
  1117. {
  1118. xS = xEl.getTextContent();
  1119. }
  1120. yEl = (Element) control.getElementsByTagName(mxVsdxConstants.Y).item(0);
  1121. if (yEl.hasAttribute("F"))
  1122. {
  1123. yS = yEl.getAttribute("F");
  1124. }
  1125. else
  1126. {
  1127. yS = yEl.getTextContent();
  1128. }
  1129. }
  1130. mxGeometry geometry = vertex.getGeometry();
  1131. //clean the formula strings and hope it will work with a specific algorithm
  1132. xS = xS.replace("Width/2+", "");
  1133. xS = xS.replace("DL", "");
  1134. yS = yS.replace("Height*", "");
  1135. if (xS.equals("Inh"))
  1136. {
  1137. xS = "0.0";
  1138. }
  1139. if (yS.equals("Inh"))
  1140. {
  1141. yS = "-0.4";
  1142. }
  1143. if (yS.contains("txtHeight"))
  1144. {
  1145. yS = "-0.4";
  1146. }
  1147. String[] styleArray = style.split(";");
  1148. String tabHeight = "";
  1149. for (int i = 0; i < styleArray.length; i++)
  1150. {
  1151. String currStyle = styleArray[i];
  1152. currStyle = currStyle.trim();
  1153. if(currStyle.startsWith("tabHeight="))
  1154. {
  1155. tabHeight = currStyle.replace("tabHeight=", "");
  1156. }
  1157. }
  1158. if (tabHeight.equals(""))
  1159. {
  1160. tabHeight = "20";
  1161. }
  1162. Double tH = Double.valueOf(tabHeight);
  1163. Double x = Double.parseDouble(xS);
  1164. Double y = Double.parseDouble(yS);
  1165. Double h = geometry.getHeight();
  1166. Double xFinal = geometry.getWidth() * 0.1 + x * 100;
  1167. Double yFinal = h - h * y - tH / 2;
  1168. mxPoint offset = new mxPoint(xFinal, yFinal);
  1169. vertex.getGeometry().setOffset(offset);
  1170. }
  1171. else if (nameU.startsWith("Domain 3D")
  1172. || masterNameU.startsWith("Domain 3D"))
  1173. {
  1174. Element control = (Element) shape.getElementsByTagName(mxVsdxConstants.CONTROL).item(0);
  1175. Element xEl = null;
  1176. String xS = "0.0";
  1177. Element yEl = null;
  1178. String yS = "-0.4";
  1179. if (control != null)
  1180. {
  1181. xEl = (Element) control.getElementsByTagName(mxVsdxConstants.X).item(0);
  1182. xS = xEl.getAttribute("F");
  1183. yEl = (Element) control.getElementsByTagName(mxVsdxConstants.Y).item(0);
  1184. yS = yEl.getAttribute("F");
  1185. }
  1186. mxGeometry geometry = vertex.getGeometry();
  1187. //clean the formula strings and hope it will work with a specific algorithm
  1188. xS = xS.replace("Width/2+", "");
  1189. xS = xS.replace("DL", "");
  1190. yS = yS.replace("Height*", "");
  1191. if (xS.equals("Inh") || xS.equals(""))
  1192. {
  1193. xS = "0.0";
  1194. }
  1195. if (yS.equals("Inh") || yS.equals(""))
  1196. {
  1197. yS = "-0.4";
  1198. }
  1199. if (yS.contains("txtHeight"))
  1200. {
  1201. yS = "-0.4";
  1202. }
  1203. Double x = Double.parseDouble(xS);
  1204. Double y = Double.parseDouble(yS);
  1205. Double h = geometry.getHeight();
  1206. Double xFinal = geometry.getWidth() * 0.1 + x * 100;
  1207. Double yFinal = h - h * y;
  1208. mxPoint offset = new mxPoint(xFinal, yFinal);
  1209. vertex.getGeometry().setOffset(offset);
  1210. }
  1211. }
  1212. /**
  1213. * Returns the constant that represents the Shape.
  1214. * @return String that represent the form.
  1215. */
  1216. public Map<String, String> getForm()
  1217. {
  1218. Map<String, String> result = new HashMap<String, String>();
  1219. this.styleDebug("Looking to match shape = " + shapeName);
  1220. if (shapeName != null && !shapeName.equals("") && VsdxShape.USE_SHAPE_MATCH)
  1221. {
  1222. String trans = mxResources.get(shapeName);
  1223. if (trans != null && !trans.equals(""))
  1224. {
  1225. this.styleDebug("Translation = " + trans);
  1226. result.put(mxConstants.STYLE_SHAPE, trans);
  1227. return result;
  1228. }
  1229. }
  1230. if (this.isVertex())
  1231. {
  1232. try
  1233. {
  1234. String type = VsdxShape.getType(this.getShape());
  1235. // String foreignType = "";
  1236. this.styleDebug("shape type = " + type);
  1237. //The master may contain the foreign object data
  1238. if (this.imageData != null || (mxVsdxConstants.FOREIGN.equals(type) && masterShape != null && masterShape.imageData != null))
  1239. {
  1240. Map<String, String> imageData = this.imageData != null? this.imageData : masterShape.imageData;
  1241. result.put("shape", "image");
  1242. result.put("aspect", "fixed");
  1243. String iType = imageData.get("iType");
  1244. String iData = imageData.get("iData");
  1245. result.put("image", "data:image/" + iType + "," + iData);
  1246. return result;
  1247. }
  1248. //Shape inherit master geometry and can change some of it or override it completely. So, no need to parse the master instead of the shape itself
  1249. String parsedGeom = this.parseGeom();
  1250. if (parsedGeom.equals(""))
  1251. {
  1252. this.styleDebug("No geom found");
  1253. return result;
  1254. }
  1255. String stencil = Utils.encodeURIComponent(parsedGeom, "UTF-8");
  1256. byte[] bytes = stencil.getBytes("UTF-8");
  1257. Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, true);
  1258. deflater.setInput(bytes);
  1259. ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  1260. deflater.finish();
  1261. byte[] buffer = new byte[1024];
  1262. while (!deflater.finished())
  1263. {
  1264. int count = deflater.deflate(buffer);
  1265. outputStream.write(buffer, 0, count);
  1266. }
  1267. try
  1268. {
  1269. outputStream.close();
  1270. }
  1271. catch (IOException e)
  1272. {
  1273. // TODO Auto-generated catch block
  1274. e.printStackTrace();
  1275. }
  1276. byte[] output = outputStream.toByteArray();
  1277. deflater.end();
  1278. byte[] encoded = Base64.encodeBase64(output);
  1279. String enc = new String(encoded, "UTF-8");
  1280. result.put(mxConstants.STYLE_SHAPE, "stencil(" + enc + ")");
  1281. }
  1282. catch (UnsupportedEncodingException e)
  1283. {
  1284. // TODO Auto-generated catch block
  1285. e.printStackTrace();
  1286. }
  1287. }
  1288. else
  1289. {
  1290. return getEdgeStyle();
  1291. }
  1292. return result;
  1293. }
  1294. /**
  1295. * Checks if a shape may to be imported like an Off page reference.
  1296. * @return Returns <code>true</code> if a shape may to be imported like an Off page reference.
  1297. */
  1298. public boolean isOff_page_reference()
  1299. {
  1300. String name = getNameU();
  1301. if (name.equals("Off-page reference") || name.equals("Lined/Shaded process"))
  1302. {
  1303. return true;
  1304. }
  1305. return false;
  1306. }
  1307. /**
  1308. * Checks if a shape may to be imported like an External process.
  1309. * @return Returns <code>true</code> if a shape may to be imported like an External process.
  1310. */
  1311. public boolean isExternal_process()
  1312. {
  1313. return (shapeName.equals("External process"));
  1314. }
  1315. /**
  1316. * Returns the direction of the shape.
  1317. * @param form Form of the shape.
  1318. * @return Direction(south, north, east and south)
  1319. */
  1320. public String getDirection(Map<String, String> form)
  1321. {
  1322. String offsetS = (String) mxResources.get("mxOffset" + shapeName);
  1323. if (offsetS == null || offsetS.equals("0") || offsetS.equals(""))
  1324. {
  1325. return mxConstants.DIRECTION_EAST;
  1326. }
  1327. else if (offsetS.equals("1"))
  1328. {
  1329. return mxConstants.DIRECTION_SOUTH;
  1330. }
  1331. else if (offsetS.equals("2"))
  1332. {
  1333. return mxConstants.DIRECTION_WEST;
  1334. }
  1335. else if (offsetS.equals("3"))
  1336. {
  1337. return mxConstants.DIRECTION_NORTH;
  1338. }
  1339. return mxConstants.DIRECTION_EAST;
  1340. }
  1341. /**
  1342. * Checks if a shape may to be imported like a Sub-process.
  1343. * This method is approximated.
  1344. * @return Returns <code>true</code> if a shape may to be imported like a
  1345. * Sub-process.
  1346. */
  1347. public boolean isSubproces()
  1348. {
  1349. return shapeName.equals("Subproces");
  1350. }
  1351. /**
  1352. * @return style map containing the proper shape and style (if needed) of a Visio "dynamic connector" edge
  1353. */
  1354. public Map<String, String> getEdgeStyle()
  1355. {
  1356. Map<String, String> result = new HashMap<String, String>();
  1357. result.put("edgeStyle", "none");
  1358. return result;
  1359. //result.put("edgeStyle", "orthogonalEdgeStyle");
  1360. //return result;
  1361. //result.put("curved", "1");
  1362. //return result;
  1363. //return null;
  1364. }
  1365. public Map<Integer, VsdxShape> getChildShapes()
  1366. {
  1367. return childShapes;
  1368. }
  1369. public void setChildShapes(Map<Integer, VsdxShape> childShapes)
  1370. {
  1371. this.childShapes = childShapes;
  1372. }
  1373. public boolean isDisplacedLabel()
  1374. {
  1375. String txtPinXF = this.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_PIN_X, "F", "");
  1376. String txtPinYF = this.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_PIN_Y, "F", "");
  1377. String txtWidthF = this.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_WIDTH, "F", "");
  1378. String txtHeightF = this.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_HEIGHT, "F", "");
  1379. if (masterShape != null)
  1380. {
  1381. if (txtPinXF == "" || txtPinXF.toLowerCase().equals("inh"))
  1382. {
  1383. txtPinXF = masterShape.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_PIN_X, "F", "");
  1384. }
  1385. if (txtPinYF == "" || txtPinYF.toLowerCase().equals("inh"))
  1386. {
  1387. txtPinYF = masterShape.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_PIN_Y, "F", "");
  1388. }
  1389. if (txtWidthF == "" || txtWidthF.toLowerCase().equals("inh"))
  1390. {
  1391. txtWidthF = masterShape.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_WIDTH, "F", "");
  1392. }
  1393. if (txtHeightF == "" || txtHeightF.toLowerCase().equals("inh"))
  1394. {
  1395. txtHeightF = masterShape.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_HEIGHT, "F", "");
  1396. }
  1397. }
  1398. if (txtPinXF.toLowerCase().equals("width*0.5") &&
  1399. txtPinYF.toLowerCase().equals("height*0.5") &&
  1400. txtWidthF.toLowerCase().equals("width*1") &&
  1401. txtHeightF.toLowerCase().equals("height*1"))
  1402. {
  1403. return false;
  1404. }
  1405. else if (txtPinXF.toLowerCase().startsWith("width*") &&
  1406. txtPinYF.toLowerCase().startsWith("height*") &&
  1407. txtWidthF.toLowerCase().startsWith("width*") &&
  1408. txtHeightF.toLowerCase().startsWith("height*"))
  1409. // else if (txtPinXF.toLowerCase().startsWith("width*") &&
  1410. // txtPinYF.toLowerCase().startsWith("height*"))
  1411. {
  1412. return true;
  1413. }
  1414. else if (txtPinXF.toLowerCase().startsWith("controls.row_") ||
  1415. txtPinYF.toLowerCase().startsWith("controls.row_"))
  1416. {
  1417. return true;
  1418. }
  1419. return false;
  1420. }
  1421. public boolean isRotatedLabel()
  1422. {
  1423. String txtAngleValue = this.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_ANGLE, "V", "");
  1424. if (masterShape != null)
  1425. {
  1426. if (txtAngleValue.equals(""))
  1427. {
  1428. txtAngleValue = masterShape.getAttribute(mxVsdxConstants.TEXT_X_FORM, mxVsdxConstants.TXT_ANGLE, "V", "");
  1429. }
  1430. }
  1431. if (!txtAngleValue.equals("0") && !txtAngleValue.equals("0.0") && !txtAngleValue.equals(""))
  1432. {
  1433. return true;
  1434. }
  1435. return false;
  1436. }
  1437. public void setRootShape(VsdxShape shape)
  1438. {
  1439. this.rootShape = shape;
  1440. }
  1441. public VsdxShape getRootShape()
  1442. {
  1443. return this.rootShape;
  1444. }
  1445. // Edge specific methods
  1446. /**
  1447. * Returns the coordinates of the begin point of an Edge Shape.
  1448. * @param parentHeight Height of the parent of the shape.
  1449. * @return mxPoint that represents the coordinates.
  1450. */
  1451. public mxPoint getStartXY(double parentHeight)
  1452. {
  1453. double startX = getScreenNumericalValue(this.getCellElement(mxVsdxConstants.BEGIN_X), 0);
  1454. double startY = parentHeight - getScreenNumericalValue(this.getCellElement(mxVsdxConstants.BEGIN_Y), 0);
  1455. return new mxPoint(startX, startY);
  1456. }
  1457. /**
  1458. * Returns the coordinates of the end point of an Edge Shape.
  1459. * @param parentHeight Height of the parent of the shape.
  1460. * @return mxPoint that represents the coordinates.
  1461. */
  1462. public mxPoint getEndXY(double parentHeight)
  1463. {
  1464. double endX = getScreenNumericalValue(this.getCellElement(mxVsdxConstants.END_X), 0);
  1465. double endY = parentHeight- getScreenNumericalValue(this.getCellElement(mxVsdxConstants.END_Y), 0);
  1466. return new mxPoint(endX, endY);
  1467. }
  1468. /**
  1469. * Returns the list of routing points of a edge shape.
  1470. * @param parentHeight Height of the parent of the shape.
  1471. * @return List of mxPoint that represents the routing points.
  1472. */
  1473. public List<mxPoint> getRoutingPoints(double parentHeight, mxPoint startPoint, double rotation/*, boolean flibX, boolean flibY*/)
  1474. {
  1475. if (geomList != null)
  1476. {
  1477. return geomList.getRoutingPoints(parentHeight, startPoint, rotation);
  1478. }
  1479. return null;
  1480. }
  1481. /**
  1482. * Returns the list of control points of a edge shape.
  1483. * @param parentHeight Height of the parent of the shape.
  1484. * @return List of mxPoint that represents the control points.
  1485. */
  1486. public List<mxPoint> getControlPoints(double parentHeight)
  1487. {
  1488. mxPoint startXY = getStartXY(parentHeight);
  1489. mxPoint endXY = getEndXY(parentHeight);
  1490. ArrayList<mxPoint> pointList = new ArrayList<mxPoint>();
  1491. if (shape != null)
  1492. {
  1493. NodeList geomList = shape.getElementsByTagName(mxVsdxConstants.GEOM);
  1494. if (geomList.getLength() > 0)
  1495. {
  1496. Element firstGeom = (Element) geomList.item(0);
  1497. Element firstNURBS = (Element) firstGeom.getElementsByTagName(mxVsdxConstants.NURBS_TO).item(0);
  1498. Element firstE = (Element) firstNURBS.getElementsByTagName("E").item(0);
  1499. if (firstE != null)
  1500. {
  1501. String f = firstE.getAttribute("F");
  1502. f = f.replaceAll("NURBS\\(", "");
  1503. f = f.replaceAll("\\)", "");
  1504. f = f.replaceAll(",", " ");
  1505. f = f.replaceAll("\\s\\s", " ");
  1506. String[] pointsS = f.split(" ");
  1507. double[] pointsRaw = new double[pointsS.length];
  1508. for (int i = 0; i < pointsS.length; i++)
  1509. {
  1510. pointsRaw[i] = Double.parseDouble(pointsS[i]);
  1511. }
  1512. for (int i = 2; i + 4 < pointsS.length; i = i + 4)
  1513. {
  1514. mxPoint currPoint = new mxPoint();
  1515. double rawX = pointsRaw[i + 2];
  1516. double rawY = pointsRaw[i + 3];
  1517. double width = Math.abs(endXY.getX() - startXY.getX());
  1518. double widthFixed = Math.min(100, width);
  1519. double heightFixed = 100;
  1520. double finalX = 0;
  1521. finalX = startXY.getX() + widthFixed * rawX;
  1522. currPoint.setX(finalX);
  1523. currPoint.setY(startXY.getY() - heightFixed * rawY);
  1524. pointList.add(currPoint);
  1525. }
  1526. return pointList;
  1527. }
  1528. else
  1529. {
  1530. return null;
  1531. }
  1532. }
  1533. }
  1534. return null;
  1535. }
  1536. /**
  1537. * Analyzes a edge shape and returns a string with the style.
  1538. * @return style read from the edge shape.
  1539. */
  1540. public Map<String, String> getStyleFromEdgeShape(double parentHeight)
  1541. {
  1542. styleMap.put("vsdxID", this.getId().toString());
  1543. // Rotation.
  1544. // double rotation = this.getRotation();
  1545. // rotation = Math.round(rotation);
  1546. //
  1547. // String rotationString = getLabelRotation() ? "1" : "0";
  1548. //
  1549. // if (!rotationString.equals("1") && rotation != 90 && rotation != 270)
  1550. // {
  1551. // styleMap.put(mxConstants.STYLE_HORIZONTAL, rotationString);
  1552. // }
  1553. //
  1554. // if (rotation != 0 && rotation != 360)
  1555. // {
  1556. // rotation = rotation * 100/100;
  1557. //
  1558. // styleMap.put(mxConstants.STYLE_ROTATION, Double.toString(rotation));
  1559. // }
  1560. //Defines Edge Shape
  1561. Map<String, String> edgeShape = getForm();
  1562. if (edgeShape != null && !edgeShape.equals(""))
  1563. {
  1564. styleMap.putAll(edgeShape);
  1565. }
  1566. //Defines Pattern
  1567. if (isDashed())
  1568. {
  1569. styleMap.put(mxConstants.STYLE_DASHED, "1");
  1570. String dashPattern = getDashPattern();
  1571. if (dashPattern != null)
  1572. {
  1573. styleMap.put(mxConstants.STYLE_DASH_PATTERN, dashPattern);
  1574. }
  1575. }
  1576. //Defines Begin Arrow
  1577. String startArrow = getEdgeMarker(true);
  1578. if(startArrow != null)
  1579. {
  1580. if (startArrow.startsWith(ARROW_NO_FILL_MARKER))
  1581. {
  1582. startArrow = startArrow.substring(ARROW_NO_FILL_MARKER.length());
  1583. styleMap.put(mxConstants.STYLE_STARTFILL, "0");
  1584. }
  1585. styleMap.put(mxConstants.STYLE_STARTARROW, startArrow);
  1586. }
  1587. //Defines End Arrow
  1588. String endArrow = getEdgeMarker(false);
  1589. if(endArrow != null)
  1590. {
  1591. if (endArrow.startsWith(ARROW_NO_FILL_MARKER))
  1592. {
  1593. endArrow = endArrow.substring(ARROW_NO_FILL_MARKER.length());
  1594. styleMap.put(mxConstants.STYLE_ENDFILL, "0");
  1595. }
  1596. styleMap.put(mxConstants.STYLE_ENDARROW, endArrow);
  1597. }
  1598. //Defines the start arrow size.
  1599. float saSize = getStartArrowSize() * 100/100;
  1600. if (saSize != 6)
  1601. {
  1602. styleMap.put(mxConstants.STYLE_STARTSIZE, Float.toString(saSize));
  1603. }
  1604. //Defines the end arrow size.
  1605. float faSize = getFinalArrowSize() * 100/100;
  1606. if (faSize != 6)
  1607. {
  1608. styleMap.put(mxConstants.STYLE_ENDSIZE, Float.toString(faSize));
  1609. }
  1610. //Defines the line width
  1611. double lWeight = getLineWidth() * 100/100;
  1612. if (lWeight != 1.0)
  1613. {
  1614. styleMap.put(mxConstants.STYLE_STROKEWIDTH, Double.toString(lWeight));
  1615. }
  1616. // Color
  1617. String color = getStrokeColor();
  1618. if (!color.equals(""))
  1619. {
  1620. styleMap.put(mxConstants.STYLE_STROKECOLOR, color);
  1621. }
  1622. // Shadow
  1623. if (isShadow())
  1624. {
  1625. styleMap.put(mxConstants.STYLE_SHADOW, mxVsdxConstants.TRUE);
  1626. }
  1627. if (isConnectorBigNameU(getNameU()))
  1628. {
  1629. styleMap.put(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_ARROW);
  1630. String fillcolor = getFillColor();
  1631. if (!fillcolor.equals(""))
  1632. {
  1633. styleMap.put(mxConstants.STYLE_FILLCOLOR, fillcolor);
  1634. }
  1635. }
  1636. //Defines label top spacing
  1637. double topMargin = getTopSpacing() * 100/100;
  1638. styleMap.put(mxConstants.STYLE_SPACING_TOP, Double.toString(topMargin));
  1639. //Defines label bottom spacing
  1640. double bottomMargin = getBottomSpacing() * 100/100;
  1641. styleMap.put(mxConstants.STYLE_SPACING_BOTTOM, Double.toString(bottomMargin));
  1642. //Defines label left spacing
  1643. double leftMargin = getLeftSpacing() * 100/100;
  1644. styleMap.put(mxConstants.STYLE_SPACING_LEFT, Double.toString(leftMargin));
  1645. //Defines label right spacing
  1646. double rightMargin = getRightSpacing() * 100/100;
  1647. styleMap.put(mxConstants.STYLE_SPACING_RIGHT, Double.toString(rightMargin));
  1648. //Defines label vertical align
  1649. String verticalAlign = getAlignVertical();
  1650. styleMap.put(mxConstants.STYLE_VERTICAL_ALIGN, verticalAlign);
  1651. //Defines Label Rotation
  1652. // styleMap.put(mxConstants.STYLE_HORIZONTAL, getLabelRotation());
  1653. styleMap.put("html", "1");
  1654. resolveCommonStyles();
  1655. // System.out.println(this.getId());
  1656. // System.out.println(Arrays.toString(styleMap.entrySet().toArray()));
  1657. return this.styleMap;
  1658. }
  1659. /**
  1660. * Analyzes a edge shape and returns a string with the style.
  1661. * @return style read from the edge shape.
  1662. */
  1663. public Map<String, String> resolveCommonStyles()
  1664. {
  1665. /** LABEL BACKGROUND COLOR **/
  1666. String lbkgnd = this.getTextBkgndColor(this.getCellElement(mxVsdxConstants.TEXT_BKGND));
  1667. if (!lbkgnd.equals(""))
  1668. {
  1669. this.styleMap.put(mxConstants.STYLE_LABEL_BACKGROUNDCOLOR, lbkgnd);
  1670. }
  1671. /** ROUNDING **/
  1672. this.styleMap.put(mxConstants.STYLE_ROUNDED, isRounded() ? mxVsdxConstants.TRUE : mxVsdxConstants.FALSE);
  1673. return styleMap;
  1674. }
  1675. /**
  1676. * Returns the arrow of the line.
  1677. * @return Type of arrow.
  1678. */
  1679. public String getEdgeMarker(boolean start)
  1680. {
  1681. String marker = this.getValue(this.getCellElement(start ? mxVsdxConstants.BEGIN_ARROW : mxVsdxConstants.END_ARROW), "0");
  1682. int val = 0;
  1683. try
  1684. {
  1685. if (marker.equals("Themed"))
  1686. {
  1687. mxVsdxTheme theme = getTheme();
  1688. if (theme != null)
  1689. {
  1690. int styleLineMtx = Integer.parseInt(this.getValue(this.getCellElement("QuickStyleLineMatrix"), "0"));
  1691. val = isVertex()? theme.getEdgeMarker(start, styleLineMtx) : theme.getConnEdgeMarker(start, styleLineMtx);
  1692. }
  1693. }
  1694. else
  1695. {
  1696. val = Integer.parseInt(marker);
  1697. }
  1698. }
  1699. catch (Exception e)
  1700. {
  1701. // ignore
  1702. }
  1703. String type = VsdxShape.arrowTypes.get(val);
  1704. if (val > 0 && type == null)
  1705. {
  1706. //if arrow head type is not supported, use the open arrow instead
  1707. type = VsdxShape.arrowTypes.get(1);
  1708. }
  1709. return type;
  1710. }
  1711. /**
  1712. * Locates the first entry for the specified style string in the style hierarchy.
  1713. * The order is to look locally, then delegate the request to the relevant parent style
  1714. * if it doesn't exist locally
  1715. * @param key The key of the style to find
  1716. * @return the Element that first resolves to that style key or null or none is found
  1717. */
  1718. protected Element getCellElement(String key)
  1719. {
  1720. Element elem = super.getCellElement(key);
  1721. if (elem == null && this.masterShape != null)
  1722. {
  1723. return this.masterShape.getCellElement(key);
  1724. }
  1725. return elem;
  1726. }
  1727. protected Element getCellElement(String cellKey, String index, String sectKey)
  1728. {
  1729. Element elem = super.getCellElement(cellKey, index, sectKey);
  1730. if (elem == null && this.masterShape != null)
  1731. {
  1732. return this.masterShape.getCellElement(cellKey, index, sectKey);
  1733. }
  1734. return elem;
  1735. }
  1736. /**
  1737. * Creates a sub shape for <b>shape</b> that contains the label. Used internally, when the label is positioned by an anchor.
  1738. * @param graph
  1739. * @param shape the shape we want to create the label for
  1740. * @param parent
  1741. * @param parentHeight
  1742. * @return label sub-shape
  1743. */
  1744. public mxCell createLabelSubShape(mxGraph graph, mxCell parent)
  1745. {
  1746. double txtWV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_WIDTH), getWidth());
  1747. double txtHV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_HEIGHT), getHeight());
  1748. double txtLocPinXV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_LOC_PIN_X), txtWV / 2.0);
  1749. double txtLocPinYV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_LOC_PIN_Y), txtHV / 2.0);
  1750. double txtPinXV =getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_PIN_X), txtLocPinXV);
  1751. double txtPinYV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_PIN_Y), txtLocPinYV);
  1752. double txtAngleV = getValueAsDouble(getShapeNode(mxVsdxConstants.TXT_ANGLE), 0);
  1753. String textLabel = getTextLabel();
  1754. if (textLabel != null && !textLabel.isEmpty())
  1755. {
  1756. Map<String, String> styleMap = new HashMap<String, String>(getStyleMap());
  1757. styleMap.put(mxConstants.STYLE_FILLCOLOR, mxConstants.NONE);
  1758. styleMap.put(mxConstants.STYLE_STROKECOLOR, mxConstants.NONE);
  1759. styleMap.put(mxConstants.STYLE_GRADIENTCOLOR, mxConstants.NONE);
  1760. //We don't need to override these attributes in order to properly align the text
  1761. if (!styleMap.containsKey("align")) styleMap.put("align", "center");
  1762. if (!styleMap.containsKey("verticalAlign")) styleMap.put("verticalAlign", "middle");
  1763. if (!styleMap.containsKey("whiteSpace")) styleMap.put("whiteSpace", "wrap");
  1764. // Doesn't make sense to set a shape, it's not rendered and doesn't affect the text perimeter
  1765. styleMap.remove("shape");
  1766. //styleMap.put("html", "1");
  1767. if (txtAngleV != 0)
  1768. {
  1769. double labRot = txtAngleV * 180 / Math.PI;
  1770. labRot = Math.round((labRot + getRotation()) * 100.0) / 100.0;
  1771. if (labRot != 0.0)
  1772. {
  1773. styleMap.put("rotation", Double.toString(labRot));
  1774. }
  1775. }
  1776. String style = "text;"
  1777. + mxVsdxUtils.getStyleString(styleMap, "=");
  1778. double y = parent.getGeometry().getHeight() - (txtPinYV + txtHV - txtLocPinYV);
  1779. double x = txtPinXV - txtLocPinXV;
  1780. mxCell v1 = (mxCell) graph.insertVertex(parent, null, textLabel, x, y, txtWV, txtHV, style + ";html=1;");
  1781. return v1;
  1782. }
  1783. return null;
  1784. }
  1785. public mxPoint getLblEdgeOffset(mxPoint beginXY, mxPoint endXY, List<mxPoint> points)
  1786. {
  1787. //currently, edges with multiple segments are not supported
  1788. //TODO use the code from https://github.com/jgraph/mxgraph/blob/master/javascript/src/js/view/mxGraphView.js#L1953 to calculate mxGraph label offset instead of the default mid point (width/2, height/2)
  1789. if (points == null || points.isEmpty() || (points.size() == 1 && points.get(0).equals(endXY)))
  1790. {
  1791. //Calculate the text offset
  1792. double txtWV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_WIDTH), getWidth());
  1793. double txtHV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_HEIGHT), getHeight());
  1794. double txtLocPinXV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_LOC_PIN_X), 0);
  1795. double txtLocPinYV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_LOC_PIN_Y), 0);
  1796. double txtPinXV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_PIN_X), 0);
  1797. double txtPinYV = getScreenNumericalValue(getShapeNode(mxVsdxConstants.TXT_PIN_Y), 0);
  1798. double y = getHeight()/2 - (txtPinYV - txtLocPinYV + txtHV/2);
  1799. double x = txtPinXV - txtLocPinXV + txtWV/2 - getWidth()/2;
  1800. return new mxPoint(x, y);
  1801. }
  1802. else
  1803. {
  1804. return null;
  1805. }
  1806. }
  1807. }