modelverse_connector.js 35 KB

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