modelverse_connector.js 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. class ModelVerseConnector {
  2. constructor(address) {
  3. ModelVerseConnector.taskname = "task_manager";
  4. ModelVerseConnector.address = (address == undefined) ? "http://127.0.0.1:8001" : address;
  5. ModelVerseConnector.ERROR = 0;
  6. ModelVerseConnector.WORKING = 1;
  7. ModelVerseConnector.OKAY = 2;
  8. ModelVerseConnector.curr_model = null;
  9. ModelVerseConnector.element_map = {};
  10. }
  11. static set_status(status) {
  12. let red = "rgb(220,20,60)";
  13. let yellow = "rgb(218,165,32)";
  14. let green = "rgb(50,205,50)";
  15. let colours = [red, yellow, green];
  16. let set_colour = function (colour) {
  17. let mv_toolbar = $('#div_toolbar_\\2f Toolbars\\2f ModelVerse\\2f ModelVerse\\2e buttons\\2e model');
  18. mv_toolbar.css("background-color", colour)
  19. };
  20. set_colour(colours[status]);
  21. }
  22. static save_model(response, data){
  23. if (response != 200){
  24. ModelVerseConnector.set_status(ModelVerseConnector.ERROR);
  25. return;
  26. }
  27. ModelVerseConnector.set_status(ModelVerseConnector.WORKING);
  28. console.log("Save model:");
  29. let parsed_data = JSON.parse(data);
  30. // console.log(parsed_data);
  31. let m = JSON.parse(parsed_data['data']['m']);
  32. let mms = JSON.parse(parsed_data['data']['mms']);
  33. console.log(m);
  34. // console.log(mms);
  35. let SCD = "formalisms/SimpleClassDiagrams";
  36. let model_name = "test_model";
  37. let model_create = {
  38. "data": utils.jsons(["model_add", SCD, model_name, ""])
  39. };
  40. let model_edit = {
  41. "data": utils.jsons(["model_modify", model_name, SCD])
  42. };
  43. let node_add = {
  44. "data": utils.jsons(["instantiate_node", "Class", "test"])
  45. };
  46. ModelVerseConnector.curr_model = model_name;
  47. ModelVerseConnector.send_command(model_create)
  48. .then(ModelVerseConnector.get_output)
  49. .then(ModelVerseConnector.send_command(model_edit))
  50. .then(ModelVerseConnector.get_output)
  51. .then(ModelVerseConnector.send_command(node_add))
  52. .then(ModelVerseConnector.get_output)
  53. .then(function(data){
  54. let node_creation_promises = [];
  55. for (const [key, node] of Object.entries(m.nodes)) {
  56. if (node.name == undefined){
  57. continue;
  58. }
  59. if (!(node.linktype == undefined)){
  60. continue;
  61. }
  62. let node_name = node.name.value;
  63. let node_type = node.$type.split("/").slice(-1)[0];
  64. node_creation_promises.push(ModelVerseConnector.send_command(
  65. {"data": utils.jsons(["instantiate_node", node_type, node_name])}
  66. ));
  67. let set_id = function (id){
  68. ModelVerseConnector.element_map[key] = id.split(" ")[1].replace("\"", "");
  69. };
  70. node_creation_promises.push(ModelVerseConnector.get_output(set_id));
  71. }
  72. let simple_type = ["String", "Int", "Float", "Boolean", "Code", "File", "Map", "List", "ENUM"];
  73. for (let st of simple_type){
  74. node_creation_promises.push(ModelVerseConnector.send_command(
  75. {"data": utils.jsons(["instantiate_node", "SimpleAttribute", st])}
  76. ));
  77. node_creation_promises.push(ModelVerseConnector.get_output());
  78. }
  79. Promise.all(node_creation_promises).then( function(){
  80. let edge_creation_promises = [];
  81. for (const [key, node] of Object.entries(m.nodes)) {
  82. if (node.name == undefined || node.linktype != undefined) {
  83. let node_type = node.$type.split("/").slice(-1)[0];
  84. let node_name = null;
  85. if (node.name != undefined) {
  86. node_name = node.name.value;
  87. }else{
  88. node_name = node_type + key;
  89. }
  90. let src = null;
  91. let dest = null;
  92. for (const [edge_key, edge] of Object.entries(m.edges)) {
  93. if (edge['src'] == key) {
  94. let ed = edge['dest'];
  95. dest = ModelVerseConnector.element_map[ed];
  96. } else if (edge['dest'] == key) {
  97. let es = edge['src'];
  98. src = ModelVerseConnector.element_map[es];
  99. }
  100. }
  101. let set_id = function (id){
  102. ModelVerseConnector.element_map[key] = id.split(" ")[1].replace("\"", "");
  103. };
  104. edge_creation_promises.push(ModelVerseConnector.send_command(
  105. {"data": utils.jsons(["instantiate_edge", node_type, node_name, src, dest])}
  106. ));
  107. edge_creation_promises.push(ModelVerseConnector.get_output(set_id));
  108. }
  109. }
  110. Promise.all(edge_creation_promises).then(function() {
  111. let attrib_creation_promises = [];
  112. for (const [key, node] of Object.entries(m.nodes)) {
  113. let ele = ModelVerseConnector.element_map[key];
  114. let node_type = node.$type.split("/").slice(-1)[0];
  115. if (node.abstract != undefined && node.abstract.value){
  116. attrib_creation_promises.push(ModelVerseConnector.send_command(
  117. {"data": utils.jsons(["attr_add", ele, "abstract", true])}
  118. ));
  119. attrib_creation_promises.push(ModelVerseConnector.get_output());
  120. }
  121. if (node.name != undefined && node_type != "GlobalConstraint"){
  122. attrib_creation_promises.push(ModelVerseConnector.send_command(
  123. {"data": utils.jsons(["attr_add", ele, "name", node.name.value])}
  124. ));
  125. attrib_creation_promises.push(ModelVerseConnector.get_output());
  126. }
  127. //TODO: Cardinalities
  128. if (node.attributes != undefined) {
  129. console.log(node);
  130. for (const [key, attrib] of Object.entries(node.attributes.value)) {
  131. //console.log(attrib);
  132. let type = attrib.type[0].toUpperCase() + attrib.type.substring(1);
  133. if (type.startsWith("ENUM")){
  134. type = "ENUM";
  135. }
  136. type = type.split("<")[0];
  137. attrib_creation_promises.push(ModelVerseConnector.send_command(
  138. {"data": utils.jsons(["define_attribute", ele, attrib.name, type])}
  139. ));
  140. attrib_creation_promises.push(ModelVerseConnector.get_output());
  141. }
  142. }
  143. }
  144. ModelVerseConnector.set_status(ModelVerseConnector.OKAY);
  145. });
  146. });
  147. });
  148. }
  149. static load_MV_model(AS, CS) {
  150. return new Promise(
  151. function (resolve, reject) {
  152. console.log("Load MV Model");
  153. console.log(AS);
  154. console.log(CS);
  155. let metamodel = "Formalisms/__LanguageSyntax__/SimpleClassDiagram/SimpleClassDiagram.defaultIcons.metamodel";
  156. let class_type = "/Formalisms/__LanguageSyntax__/SimpleClassDiagram/SimpleClassDiagram.defaultIcons/ClassIcon";
  157. DataUtils.loadmm(metamodel,
  158. function(){
  159. console.log("Metamodel loaded: " + metamodel);
  160. });
  161. let model_classes = [];
  162. let model_associations = [];
  163. let model_inheris = [];
  164. let model_attribs = {};
  165. for (let i in AS) {
  166. let obj = AS[i];
  167. let obj_type = obj["__type"];
  168. if (obj_type == "Class") {
  169. model_classes.push(obj["__id"]);
  170. }else if (obj_type == "Association"){
  171. model_associations.push([obj["__source"], obj["__target"], obj["__id"]]);
  172. }else if (obj_type == "Inheritance"){
  173. model_inheris.push([obj["__source"], obj["__target"]]);
  174. }else if (obj_type == "AttributeLink") {
  175. if (model_attribs[obj["__source"]] == undefined){
  176. model_attribs[obj["__source"]] = [];
  177. }
  178. model_attribs[obj["__source"]].push([obj["__target"], obj["__id"]]);
  179. }
  180. }
  181. let class_locs = {};
  182. for (const cs_ele of CS){
  183. if (!(cs_ele["__type"] == "Group")){
  184. continue;
  185. }
  186. let asid = cs_ele["__asid"];
  187. let pos = [cs_ele["x"], cs_ele["y"]];
  188. class_locs[asid] = pos;
  189. }
  190. let ele_ids = {};
  191. __typeToCreate = class_type;
  192. let map_promises = [];
  193. for (const id of model_classes){
  194. map_promises.push(new Promise(function(resolve, reject){
  195. let updateClass =
  196. function(status, resp){
  197. let data = JSON.parse(resp);
  198. let uri = class_type + "/" + data["data"] + ".instance";
  199. ele_ids[id] = uri;
  200. let changes = {"name": id};
  201. if (model_attribs[id] != undefined){
  202. let attrib_changes = [];
  203. for (let attrib of model_attribs[id]){
  204. //console.log(attrib);
  205. let attrib_change = {
  206. "name": attrib[1],
  207. "type" : attrib[0]
  208. };
  209. attrib_changes.push(attrib_change);
  210. }
  211. changes["attributes"] = attrib_changes;
  212. }
  213. DataUtils.update(uri, changes);
  214. resolve();
  215. };
  216. let pos = class_locs[id];
  217. if (pos == undefined || pos == null){
  218. pos = [100, 100];
  219. }
  220. let vert_offset = 200;
  221. DataUtils.create(pos[0], pos[1] + vert_offset, updateClass);
  222. }));
  223. }
  224. Promise.all(map_promises).then(function(){
  225. for (const inheri of model_inheris){
  226. let connectionType = "/Formalisms/__LanguageSyntax__/SimpleClassDiagram/SimpleClassDiagram.defaultIcons/InheritanceLink.type";
  227. let source = ele_ids[inheri[0]];
  228. let target = ele_ids[inheri[1]];
  229. if (source == undefined || target == undefined){
  230. console.log("ERROR: Can't create inheritance between " + inheri[0] + " and " + inheri[1]);
  231. continue;
  232. }
  233. HttpUtils.httpReq(
  234. 'POST',
  235. HttpUtils.url(connectionType,__NO_USERNAME),
  236. {'src':source,
  237. 'dest':target,
  238. 'pos':undefined,
  239. 'segments':undefined});
  240. }
  241. })
  242. .then(function(){
  243. let assoc_create_promises = [];
  244. for (const assoc of model_associations){
  245. assoc_create_promises.push(new Promise(function(resolve, reject){
  246. let connectionType = "/Formalisms/__LanguageSyntax__/SimpleClassDiagram/SimpleClassDiagram.defaultIcons/AssociationLink.type";
  247. let source = ele_ids[assoc[0]];
  248. let target = ele_ids[assoc[1]];
  249. if (source == undefined || target == undefined){
  250. console.log("ERROR: Can't create association between " + assoc[0] + " and " + assoc[1]);
  251. resolve();
  252. }
  253. let assoc_create_callback = function(status, resp){
  254. let id = JSON.parse(resp)["data"];
  255. let assoc_id = connectionType.replace(".type", "/") + id + ".instance";
  256. ele_ids[assoc[2]] = assoc_id;
  257. resolve();
  258. };
  259. HttpUtils.httpReq(
  260. 'POST',
  261. HttpUtils.url(connectionType,__NO_USERNAME),
  262. {'src':source,
  263. 'dest':target,
  264. 'pos':undefined,
  265. 'segments':undefined},
  266. assoc_create_callback);
  267. }));
  268. }
  269. Promise.all(assoc_create_promises).then(function(){
  270. for (const assoc of model_associations){
  271. let uri = ele_ids[assoc[2]];
  272. let changes = {"name" : assoc[2]};
  273. console.log("Updating " + uri);
  274. DataUtils.update(uri, changes);
  275. }
  276. });
  277. });
  278. resolve();
  279. });
  280. }
  281. /*********COMMUNICATION FUNCTIONS**********/
  282. static send_command(param_dict) {
  283. return new Promise(
  284. function (resolve, reject) {
  285. let callback = function (status, resp) {
  286. if (utils.isHttpSuccessCode(status)) {
  287. //console.log("send_command Resolve: " + resp);
  288. resolve(resp);
  289. } else {
  290. console.log("send_command Reject: " + resp);
  291. reject(resp);
  292. }
  293. };
  294. if (!("op" in param_dict)) {
  295. param_dict["op"] = "set_input";
  296. }
  297. if (!("taskname" in param_dict)) {
  298. param_dict["taskname"] = ModelVerseConnector.taskname;
  299. }
  300. let params = "";
  301. for (const [key, value] of Object.entries(param_dict)) {
  302. params += key + "=" + value + "&";
  303. }
  304. //take off last &
  305. params = params.slice(0, -1);
  306. console.log("Sending: " + params);
  307. HttpUtils.httpReq("POST", ModelVerseConnector.address,
  308. params,
  309. callback
  310. );
  311. });
  312. }
  313. static get_output(clbk) {
  314. return new Promise(
  315. function (resolve, reject) {
  316. let callback = function (status, resp) {
  317. if (utils.isHttpSuccessCode(status)) {
  318. console.log("get_output Resolve: " + resp);
  319. if (clbk != undefined && typeof clbk == "function"){
  320. clbk(resp);
  321. }
  322. resolve(resp);
  323. } else {
  324. console.log("get_output reject: " + resp);
  325. reject(resp);
  326. }
  327. };
  328. let params = "op=get_output&taskname=" + ModelVerseConnector.taskname;
  329. HttpUtils.httpReq("POST", ModelVerseConnector.address,
  330. params,
  331. callback
  332. );
  333. }
  334. );
  335. }
  336. /*********END COMMUNICATION FUNCTIONS**********/
  337. /*********WRAPPER FUNCTIONS**********/
  338. static connect(username_param, password_param) {
  339. console.log("Connecting to: " + ModelVerseConnector.address);
  340. ModelVerseConnector.set_status(ModelVerseConnector.WORKING);
  341. let username = username_param || "admin";
  342. let password = password_param || "admin";
  343. let username_params = {
  344. "value": "\"" + username + "\""
  345. };
  346. let password_params = {
  347. "value": "\"" + password + "\""
  348. };
  349. let quiet_mode_params = {
  350. "value": "\"quiet\""
  351. };
  352. this.get_output().then(
  353. function(data){
  354. data = data.replace(/"/g, "");
  355. ModelVerseConnector.taskname = data;
  356. }
  357. )
  358. .then(() => this.send_command(username_params)).then(this.get_output)
  359. .then(() => this.send_command(password_params)).then(this.get_output)
  360. .then(() => this.send_command(quiet_mode_params)).then(this.get_output)
  361. .then(this.get_output)
  362. .then(function () {
  363. ModelVerseConnector.set_status(ModelVerseConnector.OKAY);
  364. })
  365. .catch(
  366. function () {
  367. WindowManagement.openDialog(_ERROR, 'failed to login to the ModelVerse!');
  368. ModelVerseConnector.set_status(ModelVerseConnector.ERROR);
  369. }
  370. );
  371. };
  372. //TODO: Cache this data if too slow
  373. static async get_files_in_folder(folder_name){
  374. return await ModelVerseConnector.model_list(folder_name);
  375. }
  376. static model_list(folder_name){
  377. return new Promise(function(resolve, reject) {
  378. console.log("Listing models in: '" + folder_name + "'");
  379. let folder_param = folder_name;
  380. //fix slashes on filename
  381. if (folder_param.endsWith("/")){
  382. folder_param = folder_param.slice(0, -1);
  383. }
  384. if (folder_param.startsWith("/")){
  385. folder_param = folder_param.slice(1);
  386. }
  387. let model_types = {
  388. "data": utils.jsons(["model_list", folder_param])
  389. };
  390. ModelVerseConnector.send_command(model_types).then(ModelVerseConnector.get_output)
  391. .then(function (data) {
  392. let files = [];
  393. data = data.replace("Success: ", "");
  394. let new_files = JSON.parse(data).split("\n");
  395. for (let i in new_files) {
  396. let file = new_files[i];
  397. files.push(folder_name + file);
  398. }
  399. files.sort();
  400. resolve(files);
  401. });
  402. });
  403. }
  404. static choose_model(){
  405. console.log("Choosing model: ");
  406. let folders = [""];
  407. let files = [];
  408. ModelVerseConnector.set_status(ModelVerseConnector.WORKING);
  409. if (ModelVerseConnector.curr_model){
  410. let command = {"data": utils.jsons(["exit"])};
  411. this.send_command(command).then(this.get_output)
  412. .then(function(data){
  413. //console.log(command);
  414. //console.log(data);
  415. ModelVerseConnector.curr_model = null;
  416. });
  417. }
  418. let startDir = "/";
  419. let fileb = FileBrowser.getFileBrowser(ModelVerseConnector.get_files_in_folder, false, false, __getRecentDir(startDir));
  420. let feedback = GUIUtils.getTextSpan('', "feedback");
  421. let title = "ModelVerse Explorer";
  422. let callback = function (filenames) {
  423. ModelVerseConnector.load_model(filenames[0]);
  424. };
  425. GUIUtils.setupAndShowDialog(
  426. [fileb['filebrowser'], null, null, feedback],
  427. function () {
  428. let value = [fileb['getselection']()];
  429. if (value.length > 0 && value[0] != "" && startDir) {
  430. __setRecentDir(startDir, value[0].substring(0, value[0].lastIndexOf('/') + 1));
  431. }
  432. return value;
  433. },
  434. __TWO_BUTTONS,
  435. title,
  436. callback);
  437. ModelVerseConnector.set_status(ModelVerseConnector.OKAY);
  438. }
  439. static load_model(filename) {
  440. let model_name = filename;
  441. let metamodel = "formalisms/SimpleClassDiagrams";
  442. //fix slashes on filename
  443. if (model_name.endsWith("/")){
  444. model_name = model_name.slice(0, -1);
  445. }
  446. if (model_name.startsWith("/")){
  447. model_name = model_name.slice(1);
  448. }
  449. console.log("Loading model: " + model_name);
  450. ModelVerseConnector.set_status(ModelVerseConnector.WORKING);
  451. ModelVerseConnector.curr_model = filename;
  452. //get CS for model
  453. let SCD = "formalisms/SimpleClassDiagrams";
  454. let MM_render = "formalisms/SCD_graphical";
  455. let render_trans_model = "models/render_SCD";
  456. let render_MM = this.get_render_mm();
  457. let render_trans_code = this.get_render_trans();
  458. let render_model_add = {
  459. 'data': encodeURIComponent(utils.jsons(["model_add", SCD, MM_render, render_MM]))};
  460. let transformation_between = {
  461. 'data' : encodeURIComponent(utils.jsons(["transformation_add_AL", "rendered", MM_render, "abstract", SCD, "", "rendered", MM_render, "", render_trans_model]))
  462. };
  463. let transformation_data = {
  464. 'data' : encodeURIComponent(utils.jsons(["transformation_add_AL", render_trans_code]))
  465. };
  466. let model_rendered = {
  467. 'data' : encodeURIComponent(utils.jsons(["model_render", model_name, render_trans_model, "models/rendered_model"]))
  468. };
  469. //get AS for model
  470. let model_types = {
  471. "data": utils.jsons(["model_types", model_name])
  472. };
  473. let model_modify = {
  474. "data": utils.jsons(["model_modify", model_name, metamodel])
  475. };
  476. let model_dump = {
  477. "data": utils.jsons(["JSON"])
  478. };
  479. let model_CS = null;
  480. //CS COMMANDS
  481. //TODO: only need to add models if not present
  482. this.send_command(render_model_add).then(this.get_output)
  483. .then(this.send_command(transformation_between)).then(this.get_output)
  484. .then(this.send_command({})).then(this.get_output)
  485. .then(this.send_command(transformation_data)).then(this.get_output)
  486. .then(this.send_command(model_rendered)).then(this.get_output)
  487. .then(function(data){
  488. data = data.replace("Success: ", "");
  489. model_CS = eval(JSON.parse(data));
  490. })
  491. //AS COMMANDS
  492. .then(this.send_command(model_types)).then(this.get_output)
  493. .then(function(data){
  494. console.log("model_types");
  495. console.log(data);
  496. })
  497. .then(this.send_command(model_modify)).then(this.get_output)
  498. .then(function(data){
  499. console.log("model_modify");
  500. console.log(data);
  501. })
  502. .then(this.send_command(model_dump)).then(this.get_output)
  503. .then(function(data){
  504. data = data.replace("Success: ", "");
  505. let AS = eval(JSON.parse(data));
  506. ModelVerseConnector.load_MV_model(AS, model_CS)
  507. })
  508. .then(function () {
  509. ModelVerseConnector.set_status(ModelVerseConnector.OKAY);
  510. })
  511. .catch(
  512. function (err) {
  513. console.log("Error with model loading!");
  514. console.log(err);
  515. ModelVerseConnector.set_status(ModelVerseConnector.ERROR);
  516. }
  517. );
  518. }
  519. /*********END WRAPPER FUNCTIONS**********/
  520. static get_render_mm(){
  521. let mm = "include \"primitives.alh\"\n" +
  522. "\n" +
  523. "SimpleAttribute Natural {}\n" +
  524. "SimpleAttribute String {}\n" +
  525. "SimpleAttribute Boolean {}\n" +
  526. "\n" +
  527. "Class GraphicalElement {\n" +
  528. " x : Natural\n" +
  529. " y : Natural\n" +
  530. " layer : Natural\n" +
  531. "}\n" +
  532. "\n" +
  533. "Class Group : GraphicalElement {\n" +
  534. " __asid : String\n" +
  535. " dirty : Boolean\n" +
  536. "}\n" +
  537. "\n" +
  538. "Association ConnectingLine (Group, Group) {\n" +
  539. " offsetSourceX : Natural\n" +
  540. " offsetSourceY : Natural\n" +
  541. " offsetTargetX : Natural\n" +
  542. " offsetTargetY : Natural\n" +
  543. " lineWidth : Natural\n" +
  544. " lineColour : String\n" +
  545. " arrow : Boolean\n" +
  546. " __asid : String\n" +
  547. " dirty : Boolean\n" +
  548. " layer : Natural\n" +
  549. "}\n" +
  550. "\n" +
  551. "Class LineElement : GraphicalElement {\n" +
  552. " lineWidth : Natural\n" +
  553. " lineColour : String\n" +
  554. "}\n" +
  555. "\n" +
  556. "Class Text : LineElement {\n" +
  557. " text : String\n" +
  558. "}\n" +
  559. "\n" +
  560. "Class Line : LineElement {\n" +
  561. " targetX : Natural\n" +
  562. " targetY : Natural\n" +
  563. " arrow : Boolean\n" +
  564. "}\n" +
  565. "\n" +
  566. "Class Shape : LineElement {\n" +
  567. " fillColour : String\n" +
  568. " width : Natural\n" +
  569. " height : Natural\n" +
  570. "}\n" +
  571. "\n" +
  572. "Class Figure : GraphicalElement {\n" +
  573. " width : Natural\n" +
  574. " height : Natural\n" +
  575. "}\n" +
  576. "\n" +
  577. "Class SVG {\n" +
  578. " data : String\n" +
  579. "}\n" +
  580. "\n" +
  581. "Class Rectangle : Shape {\n" +
  582. "}\n" +
  583. "\n" +
  584. "Class Ellipse : Shape {\n" +
  585. "}\n" +
  586. "\n" +
  587. "Association contains (Group, GraphicalElement) {}\n" +
  588. "Association renders (Figure, SVG) {\n" +
  589. " source_lower_cardinality = 1\n" +
  590. " target_lower_cardinality = 1\n" +
  591. " target_upper_cardinality = 1\n" +
  592. "}"
  593. ;
  594. return mm;
  595. }
  596. static get_render_trans(){
  597. let trans = "include \"primitives.alh\"\n" +
  598. "include \"modelling.alh\"\n" +
  599. "include \"object_operations.alh\"\n" +
  600. "include \"utils.alh\"\n" +
  601. "\n" +
  602. "Boolean function main(model : Element):\n" +
  603. "\tElement elements\n" +
  604. "\tString class\n" +
  605. "\tElement attrs\n" +
  606. "\tElement attr_keys\n" +
  607. "\tString attr_key\n" +
  608. "\tString group\n" +
  609. "\tString elem\n" +
  610. "\tInteger loc\n" +
  611. "\tInteger text_loc\n" +
  612. "\tElement related_groups\n" +
  613. "\tloc = 10\n" +
  614. "\n" +
  615. "\tElement groups\n" +
  616. "\tgroups = dict_create()\n" +
  617. "\n" +
  618. "\telements = allInstances(model, \"rendered/Group\")\n" +
  619. "\twhile (set_len(elements) > 0):\n" +
  620. "\t\tgroup = set_pop(elements)\n" +
  621. "\t\tif (set_len(allIncomingAssociationInstances(model, group, \"TracabilityClass\")) == 0):\n" +
  622. "\t\t\tElement to_remove\n" +
  623. "\t\t\tString elem_to_remove\n" +
  624. "\t\t\tto_remove = allAssociationDestinations(model, group, \"rendered/contains\")\n" +
  625. "\t\t\twhile (set_len(to_remove) > 0):\n" +
  626. "\t\t\t\telem_to_remove = set_pop(to_remove)\n" +
  627. "\t\t\t\tif (read_type(model, elem_to_remove) == \"rendered/Group\"):\n" +
  628. "\t\t\t\t\tset_add(to_remove, elem_to_remove)\n" +
  629. "\t\t\t\telse:\n" +
  630. "\t\t\t\t\tmodel_delete_element(model, elem_to_remove)\n" +
  631. "\t\t\tmodel_delete_element(model, group)\n" +
  632. "\n" +
  633. "\telements = allInstances(model, \"abstract/Class\")\n" +
  634. "\twhile (set_len(elements) > 0):\n" +
  635. "\t\tclass = set_pop(elements)\n" +
  636. "\t\t\n" +
  637. "\t\tInteger x\n" +
  638. "\t\tInteger y\n" +
  639. "\t\tx = loc\n" +
  640. "\t\ty = 10\n" +
  641. "\n" +
  642. "\t\t// Check if there is already an associated element\n" +
  643. "\t\tif (set_len(allOutgoingAssociationInstances(model, class, \"TracabilityClass\")) > 0):\n" +
  644. "\t\t\t// Yes, but is it still clean?\n" +
  645. "\t\t\tBoolean dirty\n" +
  646. "\t\t\tdirty = False\n" +
  647. "\n" +
  648. "\t\t\trelated_groups = allAssociationDestinations(model, class, \"TracabilityClass\")\n" +
  649. "\t\t\twhile (set_len(related_groups) > 0):\n" +
  650. "\t\t\t\tgroup = set_pop(related_groups)\n" +
  651. "\t\t\t\tif (value_eq(read_attribute(model, group, \"dirty\"), True)):\n" +
  652. "\t\t\t\t\t// No, so mark all as dirty\n" +
  653. "\t\t\t\t\tdirty = True\n" +
  654. "\t\t\t\t\tbreak!\n" +
  655. "\t\t\t\telse:\n" +
  656. "\t\t\t\t\t// Yes, so just ignore this!\n" +
  657. "\t\t\t\t\tcontinue!\n" +
  658. "\n" +
  659. "\t\t\tif (bool_not(dirty)):\n" +
  660. "\t\t\t\tdict_add(groups, class, group)\n" +
  661. "\t\t\t\tcontinue!\n" +
  662. "\t\t\telse:\n" +
  663. "\t\t\t\trelated_groups = allAssociationDestinations(model, class, \"TracabilityClass\")\n" +
  664. "\t\t\t\tElement to_remove\n" +
  665. "\t\t\t\tString elem_to_remove\n" +
  666. "\t\t\t\twhile (set_len(related_groups) > 0):\n" +
  667. "\t\t\t\t\tgroup = set_pop(related_groups)\n" +
  668. "\t\t\t\t\tto_remove = allAssociationDestinations(model, group, \"rendered/contains\")\n" +
  669. "\t\t\t\t\tx = create_value(read_attribute(model, group, \"x\"))\n" +
  670. "\t\t\t\t\ty = create_value(read_attribute(model, group, \"y\"))\n" +
  671. "\t\t\t\t\twhile (set_len(to_remove) > 0):\n" +
  672. "\t\t\t\t\t\telem_to_remove = set_pop(to_remove)\n" +
  673. "\t\t\t\t\t\tif (read_type(model, elem_to_remove) == \"rendered/Group\"):\n" +
  674. "\t\t\t\t\t\t\tset_add(to_remove, elem_to_remove)\n" +
  675. "\t\t\t\t\t\telse:\n" +
  676. "\t\t\t\t\t\t\tmodel_delete_element(model, elem_to_remove)\n" +
  677. "\t\t\t\t\tmodel_delete_element(model, group)\n" +
  678. "\n" +
  679. "\t\tattr_keys = dict_keys(getAttributeList(model, class))\n" +
  680. "\t\ttext_loc = 5\n" +
  681. "\n" +
  682. "\t\tgroup = instantiate_node(model, \"rendered/Group\", \"\")\n" +
  683. "\t\tinstantiate_attribute(model, group, \"x\", x)\n" +
  684. "\t\tinstantiate_attribute(model, group, \"y\", y)\n" +
  685. "\t\tinstantiate_attribute(model, group, \"__asid\", list_read(string_split_nr(class, \"/\", 1), 1))\n" +
  686. "\t\tinstantiate_attribute(model, group, \"layer\", 0)\n" +
  687. "\t\tdict_add(groups, class, group)\n" +
  688. "\t\tloc = loc + 200\n" +
  689. "\n" +
  690. "\t\telem = instantiate_node(model, \"rendered/Rectangle\", \"\")\n" +
  691. "\t\tinstantiate_attribute(model, elem, \"x\", 0)\n" +
  692. "\t\tinstantiate_attribute(model, elem, \"y\", 0)\n" +
  693. "\t\tinstantiate_attribute(model, elem, \"height\", 40 + set_len(getInstantiatableAttributes(model, class, \"abstract/AttributeLink\")) * 20)\n" +
  694. "\t\tinstantiate_attribute(model, elem, \"width\", 150)\n" +
  695. "\t\tinstantiate_attribute(model, elem, \"lineWidth\", 2) \n" +
  696. "\t\tinstantiate_attribute(model, elem, \"lineColour\", \"black\")\n" +
  697. "\t\tinstantiate_attribute(model, elem, \"fillColour\", \"white\")\n" +
  698. "\t\tinstantiate_attribute(model, elem, \"layer\", 1)\n" +
  699. "\t\tinstantiate_link(model, \"rendered/contains\", \"\", group, elem)\n" +
  700. "\n" +
  701. "\t\tString multiplicities\n" +
  702. "\t\tString lower_card\n" +
  703. "\t\tString upper_card\n" +
  704. "\t\tif (element_eq(read_attribute(model, class, \"lower_cardinality\"), read_root())):\n" +
  705. "\t\t\tlower_card = \"*\"\n" +
  706. "\t\telse:\n" +
  707. "\t\t\tlower_card = cast_value(read_attribute(model, class, \"lower_cardinality\"))\n" +
  708. "\t\tif (element_eq(read_attribute(model, class, \"upper_cardinality\"), read_root())):\n" +
  709. "\t\t\tupper_card = \"*\"\n" +
  710. "\t\telse:\n" +
  711. "\t\t\tupper_card = cast_value(read_attribute(model, class, \"upper_cardinality\"))\n" +
  712. "\t\tmultiplicities = (((\"[\" + lower_card) + \"..\") + upper_card) + \"]\"\n" +
  713. "\n" +
  714. "\t\telem = instantiate_node(model, \"rendered/Text\", \"\")\n" +
  715. "\t\tinstantiate_attribute(model, elem, \"x\", 5)\n" +
  716. "\t\tinstantiate_attribute(model, elem, \"y\", 3)\n" +
  717. "\t\tinstantiate_attribute(model, elem, \"lineWidth\", 1)\n" +
  718. "\t\tinstantiate_attribute(model, elem, \"lineColour\", \"black\")\n" +
  719. "\t\tif (element_neq(read_attribute(model, class, \"name\"), read_root())):\n" +
  720. "\t\t\tinstantiate_attribute(model, elem, \"text\", string_join(read_attribute(model, class, \"name\"), \" \" + multiplicities))\n" +
  721. "\t\telse:\n" +
  722. "\t\t\tinstantiate_attribute(model, elem, \"text\", \"(unnamed) \" + multiplicities)\n" +
  723. "\t\tinstantiate_attribute(model, elem, \"layer\", 2)\n" +
  724. "\t\tinstantiate_link(model, \"rendered/contains\", \"\", group, elem)\n" +
  725. "\n" +
  726. "\t\telem = instantiate_node(model, \"rendered/Line\", \"\")\n" +
  727. "\t\tinstantiate_attribute(model, elem, \"x\", 0)\n" +
  728. "\t\tinstantiate_attribute(model, elem, \"y\", 20)\n" +
  729. "\t\tinstantiate_attribute(model, elem, \"targetX\", 150)\n" +
  730. "\t\tinstantiate_attribute(model, elem, \"targetY\", 20)\n" +
  731. "\t\tinstantiate_attribute(model, elem, \"lineWidth\", 1)\n" +
  732. "\t\tinstantiate_attribute(model, elem, \"lineColour\", \"black\")\n" +
  733. "\t\tinstantiate_attribute(model, elem, \"arrow\", False)\n" +
  734. "\t\tinstantiate_attribute(model, elem, \"layer\", 2)\n" +
  735. "\t\tinstantiate_link(model, \"rendered/contains\", \"\", group, elem)\n" +
  736. "\n" +
  737. "\t\tattrs = getInstantiatableAttributes(model, class, \"abstract/AttributeLink\")\n" +
  738. "\t\tattr_keys = dict_keys(attrs)\n" +
  739. "\t\twhile (dict_len(attr_keys) > 0):\n" +
  740. "\t\t\tattr_key = set_pop(attr_keys)\n" +
  741. "\t\t\telem = instantiate_node(model, \"rendered/Text\", \"\")\n" +
  742. "\t\t\tinstantiate_attribute(model, elem, \"x\", 5)\n" +
  743. "\t\t\tinstantiate_attribute(model, elem, \"y\", text_loc + 20)\n" +
  744. "\t\t\tinstantiate_attribute(model, elem, \"lineWidth\", 1)\n" +
  745. "\t\t\tinstantiate_attribute(model, elem, \"lineColour\", \"black\")\n" +
  746. "\t\t\tinstantiate_attribute(model, elem, \"text\", (attr_key + \" : \") + cast_string(list_read(string_split_nr(attrs[attr_key], \"/\", 1), 1)))\n" +
  747. "\t\t\tinstantiate_attribute(model, elem, \"layer\", 2)\n" +
  748. "\t\t\tinstantiate_link(model, \"rendered/contains\", \"\", group, elem)\n" +
  749. "\t\t\ttext_loc = text_loc + 15\n" +
  750. "\n" +
  751. "\t\tinstantiate_link(model, \"TracabilityClass\", \"\", class, group)\n" +
  752. "\n" +
  753. "\t// Flush all associations\n" +
  754. "\telements = allInstances(model, \"rendered/ConnectingLine\")\n" +
  755. "\twhile (set_len(elements) > 0):\n" +
  756. "\t\tclass = set_pop(elements)\n" +
  757. "\t\tmodel_delete_element(model, class)\n" +
  758. "\n" +
  759. "\t// Rerender associations\n" +
  760. "\telements = allInstances(model, \"abstract/Association\")\n" +
  761. "\twhile (set_len(elements) > 0):\n" +
  762. "\t\tclass = set_pop(elements)\n" +
  763. "\n" +
  764. "\t\tattr_keys = dict_keys(getAttributeList(model, class))\n" +
  765. "\n" +
  766. "\t\telem = instantiate_link(model, \"rendered/ConnectingLine\", \"\", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])\n" +
  767. "\t\tinstantiate_attribute(model, elem, \"offsetSourceX\", 75)\n" +
  768. "\t\tinstantiate_attribute(model, elem, \"offsetSourceY\", 30)\n" +
  769. "\t\tinstantiate_attribute(model, elem, \"offsetTargetX\", 75)\n" +
  770. "\t\tinstantiate_attribute(model, elem, \"offsetTargetY\", 30)\n" +
  771. "\t\tinstantiate_attribute(model, elem, \"lineWidth\", 1)\n" +
  772. "\t\tinstantiate_attribute(model, elem, \"lineColour\", \"black\")\n" +
  773. "\t\tinstantiate_attribute(model, elem, \"arrow\", True)\n" +
  774. "\t\tinstantiate_attribute(model, elem, \"__asid\", list_read(string_split_nr(class, \"/\", 1), 1))\n" +
  775. "\t\tinstantiate_attribute(model, elem, \"layer\", 0)\n" +
  776. "\t\tlog(\"Real ASID: \" + cast_value(class))\n" +
  777. "\t\tlog(\"Found ASID \" + cast_value(list_read(string_split_nr(class, \"/\", 1), 1)))\n" +
  778. "\t\tinstantiate_link(model, \"rendered/contains\", \"\", group, elem)\n" +
  779. "\n" +
  780. "\treturn True!";
  781. return trans;
  782. }
  783. }