client.js 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  1. /* This file is part of AToMPM - A Tool for Multi-Paradigm Modelling
  2. * Copyright 2011 by the AToMPM team and licensed under the LGPL
  3. * See COPYING.lesser and README.md in the root of this project for full details
  4. */
  5. /*TODO: look into reworking naming convention to be more intuitive
  6. *ie:
  7. * button: btn_someFunc
  8. * window: wnd_someFunc
  9. * private: _someFunc
  10. * etc
  11. */
  12. /* NOTES:
  13. NAMING CONVENTION... functions and variables starting with '_' are meant to
  14. be used from within Button code (most of them are directly associated to a
  15. native back-end operation)... functions starting with '__' are meant to be
  16. private and should only be used from within application code
  17. WINDOW TITLE... window titles are set to pretty-print '__saveas'... if any
  18. changelogs have been received since we loaded/saved the model, the title is
  19. changed to explicit this
  20. the BACKDOOR API section contains methods that are accessible from the
  21. backend (or from anyone who has access to the backend, e.g., a synthesized
  22. application)... they are all void (i.e., they don't return anything or any
  23. feedback to the 'caller') and should only be accessed remotely, via
  24. 'PUT /GET/console {CLIENT_BDAPI:...}' to the backend
  25. TBI:: add caching mechanism to avoid recompiling the same icon models into
  26. the same SVG over and over
  27. TBI:: add helper functions for parsing and manipulating path strings (see
  28. Raphael.parsePathString()... not only would this elevate abstraction,
  29. but a lot of our connection-related operations could be optimized
  30. (including less string matching and splitting) if segments were arrays
  31. of points rather than strings
  32. TBI:: when SVG 1.2 gets Chrome support, the __SVG_TEXT_EDITOR dialog could be
  33. removed in favor of native SVG text editing facilities */
  34. /******************************** GLOBAL VARS *********************************/
  35. var __user = undefined,
  36. __wid,
  37. __aswid,
  38. __prefs,
  39. __typeToCreate,
  40. __loadedToolbars = {},
  41. __icons = {},
  42. __edges = {},
  43. __canvas,
  44. __saveas;
  45. __option = '',
  46. __trafo = '',
  47. __msg = '',
  48. __name = '';
  49. /******************************** GLOBAL VARS *********************************/
  50. AtomPMClient = function(){
  51. /**
  52. * Log deprecated function calls
  53. */
  54. this.alertDeprecatedFunctionCall = function( funcName ){
  55. console.warn("Deprecated function call: " + funcName);
  56. };
  57. return this;
  58. }();
  59. /**
  60. * Automatically saves the current model.
  61. *
  62. * If mode == backup, save the current model into a backup file
  63. * If mode == overwrite, overwrite the current file model
  64. */
  65. function __autosave(mode)
  66. {
  67. if( mode == 'backup' )
  68. {
  69. if( __saveas )
  70. {
  71. var matches = __saveas.match(/(.*\/)(.*)/);
  72. _saveModel(matches[1]+'.autosave.'+matches[2],true,true);
  73. }
  74. else
  75. _saveModel(undefined,true,true);
  76. }
  77. else if( mode == 'overwrite' )
  78. _saveModel(undefined,false,true);
  79. }
  80. /**
  81. * Launches the autosave daemon, which automatically tries to
  82. * save the model based on the interval stored in the preferences
  83. * array
  84. */
  85. function __launchAutosave()
  86. {
  87. if( __prefs['autosave-delay']['value'] > 0 )
  88. window.setInterval(
  89. __autosave,
  90. __prefs['autosave-delay']['value'] * 1000,
  91. __prefs['autosave-mode']['value']);
  92. }
  93. /********************************* 'USER' API *********************************/
  94. /**
  95. * Creates an SVG blob out of the current SVG elements on the canvas
  96. *
  97. * Note 1: an alternative to the current implementation (though less
  98. * efficient) would be to POST the data to the server and then have
  99. * the returned file be downloadable
  100. *
  101. * Note 2: a click is simulated instead of using
  102. * window.location.assign() so that the target filename can be
  103. * chosen
  104. *
  105. * Note 3: the output width of the image is altered in order to fit
  106. * the content. This would be fixed if we utilized a dynamically
  107. * expanding canvas
  108. *
  109. * Note 4: the 'href' tags are changed to 'xlink:href' tags in the
  110. * generated SVG file. All images are embedded as data uris in the
  111. * output in order to increase robustness.
  112. */
  113. function _exportSVG(fname)
  114. {
  115. var BlobBuilder = window.WebKitBlobBuilder || window.MozBlobBuilder,
  116. URL = window.URL || window.webkitURL,
  117. a = $('<a>'),
  118. bb = undefined,
  119. iconsbbox = __getGlobalBBox(
  120. utils.keys(__icons).concat(utils.keys(__edges)) ),
  121. svg = $('#div_canvas').html().
  122. replace(/^(<svg.*? width=")(.*?)(".*?>)/,
  123. '$1'+(2*iconsbbox.x+iconsbbox.width)+'$3').
  124. replace(/^(<svg.*? height=")(.*?)(".*?>)/,
  125. '$1'+(2*iconsbbox.y+iconsbbox.height)+'$3'),
  126. exportSVG =
  127. function()
  128. {
  129. bb = new Blob([svg], {"type": "text\/xml"});
  130. a.attr("href", URL.createObjectURL(bb));
  131. a.attr("download", fname || "model.svg");
  132. a.get(0).click();
  133. URL.revokeObjectURL(a.href);
  134. };
  135. if( (images = svg.match(/<image.*? href=".*?".*?>/g)) )
  136. {
  137. var datauris = [];
  138. images.forEach(
  139. function(image,i)
  140. {
  141. HttpUtils.imageToDataURI(
  142. image.match(/^<image.*? href="(.*?)".*?>$/)[1],
  143. function(datauri)
  144. {
  145. datauris[i] = datauri;
  146. if( datauris.length == images.length &&
  147. ! utils.contains(datauris,undefined) )
  148. {
  149. svg = svg.replace(
  150. /(<image.*? )href=".*?"(.*?>)/g,
  151. function(p0,p1,p2)
  152. {
  153. return p1+' xlink:href="'+datauris.shift()+'"'+p2;
  154. });
  155. exportSVG();
  156. }
  157. });
  158. });
  159. }
  160. else
  161. exportSVG();
  162. }
  163. /**
  164. * Retrieves the value that matches the subset, and then passes
  165. * it back into the callback function
  166. *
  167. * @param callback the function that the value is passed to
  168. * @param subset the matching preference entry
  169. */
  170. function _getUserPreferences(callback,subset)
  171. {
  172. console.debug("Get User Preferences");
  173. console.debug(subset);
  174. HttpUtils.httpReq(
  175. 'GET',
  176. HttpUtils.url('/prefs',__NO_WID),
  177. (subset == undefined ?
  178. undefined :
  179. '?subset='+encodeURIComponent(utils.jsons(subset))),
  180. function(statusCode,resp)
  181. {
  182. console.debug("Callback Get User Preferences");
  183. console.debug(statusCode);
  184. console.debug(resp);
  185. if( ! utils.isHttpSuccessCode(statusCode) )
  186. UserManagement.logout();
  187. else
  188. callback(utils.jsonp(resp));
  189. });
  190. }
  191. /**
  192. * Generates an HTTP request
  193. *
  194. * @param method GET/DELETE/POST/PUT
  195. * @param url the URL to hit
  196. * @param params the parameters to pass in
  197. * @param onresponse the callback function to perform on response
  198. * @param sync whether or not this request is synchronous
  199. */
  200. function _httpReq(method,url,params,onresponse,sync)
  201. {
  202. if( method != 'GET' )
  203. BehaviorManager.handleUserEvent(__EVENT_CODED_CANVAS_EDIT);
  204. HttpUtils.httpReq(method,url,params,onresponse,sync);
  205. }
  206. /**
  207. * Inserts another model into the current canvas
  208. */
  209. function _insertModel(fname)
  210. {
  211. if( ! __isModel(fname) )
  212. WindowManagement.openDialog(
  213. _ERROR,
  214. 'invalid extension... loadable models are "*.model" files');
  215. else
  216. DataUtils.loadm(fname,true);
  217. }
  218. /**
  219. * Loads a model from the selected file name. This automatically
  220. * strips out the .autosave portion of the filename, if it is
  221. * present
  222. *
  223. * @param fname the name of the file to load
  224. */
  225. function _loadModel(fname)
  226. {
  227. if( ! __isModel(fname) )
  228. WindowManagement.openDialog(
  229. _ERROR,
  230. 'invalid extension... loadable models are "*.model" files');
  231. else
  232. {
  233. if( (matches = fname.match(/(.*)\.autosave\.(.+\.model)/)) )
  234. __saveas = matches[1]+matches[2];
  235. else
  236. __saveas = fname;
  237. DataUtils.loadm(fname);
  238. if (__msg != '' && __msg != null)
  239. WindowManagement.openDialog(_CUSTOM,{'widgets':[{'id':'1','type':'text','label':'text message','default':''}],"title":__msg});
  240. }
  241. }
  242. /**
  243. * Loads a new toolbar onto the current canvas
  244. * @param fname the name of the file to load
  245. */
  246. function _loadToolbar(fname)
  247. {
  248. if( __isButtonModel(fname) )
  249. DataUtils.loadbm(fname);
  250. else if( __isIconMetamodel(fname) )
  251. DataUtils.loadmm(fname);
  252. if (__msg != '' && __msg != null)
  253. WindowManagement.openDialog(_CUSTOM,{'widgets':[{'id':'1','type':'text','label':'text message','default':''}],"title":__msg});
  254. }
  255. /* save model
  256. 1. if no filename is specified,
  257. a) if autosave is specified,
  258. - if __saveas is specified, use it
  259. - otherwise, use __DEFAULT_SAVEAS
  260. b) else, ask the user to choose a file to save to (first time user saves a model)
  261. 2. otherwise, if an incorrect filename is specified, show error and return
  262. 3. save model
  263. 4. if this isn't an automated backup (i.e., the backup flag is unset),
  264. remember filename in __saveas and adjust window title to reflect fact that
  265. all changes are saved */
  266. function _saveModel(fname,backup,autosave)
  267. {
  268. if( fname == undefined ) {
  269. if (!autosave && (__saveas == undefined || __saveas == null)) {
  270. var options = {'extensions':['\\.model'],
  271. 'multipleChoice':false,
  272. 'manualInput':true,
  273. 'title':'specify target model\nextension: .model',
  274. 'startDir':'model'},
  275. callback =
  276. function(fnames)
  277. {
  278. _saveModel(fnames[0]);
  279. };
  280. WindowManagement.openDialog(_FILE_BROWSER,options,callback);
  281. return;
  282. } else {
  283. fname = (__saveas || __DEFAULT_SAVEAS);
  284. }
  285. } else if( ! __isModel(fname) ) {
  286. WindowManagement.openDialog(
  287. _ERROR,
  288. 'invalid extension... models must be saved as "*.model" files');
  289. return;
  290. }
  291. DataUtils.savem(fname);
  292. if( ! backup )
  293. {
  294. __saveas = fname;
  295. WindowManagement.setWindowTitle();
  296. }
  297. }
  298. /* TBI::
  299. . unselect invisible items
  300. . remember visibility settings s.t. newly created items (e.g., by
  301. collaborator) inherit them */
  302. function _setInvisibleMetamodels(mms)
  303. {
  304. mms = mms.map( function(mm) {return mm.match(/(.*)\.metamodel/)[1];} );
  305. function hideOrShow(uri,icon)
  306. {
  307. if( ! mms.some(
  308. function(mm)
  309. {
  310. if( uri.match(mm+'/') )
  311. {
  312. icon.hide();
  313. return true;
  314. }
  315. }) )
  316. icon.show();
  317. }
  318. for( var uri in __icons )
  319. hideOrShow(uri,__icons[uri]['icon']);
  320. for( var uri in __edges )
  321. hideOrShow(uri,__edges[uri]['icon']);
  322. }
  323. /**
  324. * Updates the current user preferences and then
  325. * executes the passed in callback function
  326. *
  327. * @param prefs the new user preferences
  328. * @param callback the function to be executed
  329. */
  330. function _setUserPreferences(prefs,callback)
  331. {
  332. HttpUtils.httpReq(
  333. 'PUT',
  334. HttpUtils.url('/prefs',__NO_WID),
  335. prefs,
  336. function(statusCode,resp)
  337. {
  338. if( ! utils.isHttpSuccessCode(statusCode) )
  339. WindowManagement.openDialog(_ERROR, 'failed to update user preferences :: '+resp);
  340. else if( callback )
  341. callback();
  342. });
  343. }
  344. /**
  345. * Creates a new formalism under /Formalisms/ with the specified name.
  346. *
  347. * @param formalism_name the name of the new formalism
  348. */
  349. function _newFormalism(formalism_name) {
  350. HttpUtils.httpReq(
  351. 'POST',
  352. window.localStorage.getItem('user') + "/" + formalism_name + '.formalism',
  353. undefined,
  354. function(statusCode,resp)
  355. {
  356. if( ! utils.isHttpSuccessCode(statusCode) ) {
  357. WindowManagement.openDialog(_ERROR, 'failed to create new formalism :: '+resp);
  358. } else {
  359. WindowManagement.spawnClient("/Formalisms/" + formalism_name + "/" + formalism_name + ".model");
  360. WindowManagement.spawnClient("/Formalisms/" + formalism_name + "/" + formalism_name + ".defaultIcons.model");
  361. }
  362. });
  363. }
  364. /**
  365. * Creates a new transformation on the specified location.
  366. *
  367. * @param transformation_loc the location of the new transformation
  368. */
  369. function _newTransformation(transformation_loc) {
  370. if (transformation_loc.match(/.*\/T_.*\.model$/)) {
  371. HttpUtils.httpReq(
  372. 'POST',
  373. window.localStorage.getItem('user') + transformation_loc + '.transformation',
  374. undefined,
  375. function(statusCode,resp)
  376. {
  377. if( ! utils.isHttpSuccessCode(statusCode) ) {
  378. WindowManagement.openDialog(_ERROR, 'failed to create new transformation :: '+resp);
  379. } else {
  380. WindowManagement.spawnClient(transformation_loc);
  381. }
  382. });
  383. } else {
  384. WindowManagement.openDialog(_ERROR, 'failed to create new transformation :: '+transformation_loc+" is not a valid transformation name");
  385. }
  386. }
  387. /**
  388. * Creates a new rule on the specified location.
  389. *
  390. * @param rule_loc the location of the new rule
  391. */
  392. function _newRule(rule_loc) {
  393. if (rule_loc.match(/.*\/R_.*\.model$/)) {
  394. HttpUtils.httpReq(
  395. 'POST',
  396. window.localStorage.getItem('user') + rule_loc + '.rule',
  397. undefined,
  398. function(statusCode,resp)
  399. {
  400. if( ! utils.isHttpSuccessCode(statusCode) ) {
  401. WindowManagement.openDialog(_ERROR, 'failed to create new rule :: '+resp);
  402. } else {
  403. WindowManagement.spawnClient(rule_loc);
  404. }
  405. });
  406. } else {
  407. WindowManagement.openDialog(_ERROR, 'failed to create new rule :: '+rule_loc+" is not a valid rule name");
  408. }
  409. }
  410. /**
  411. * Sets the current type of entity to be created
  412. * @param fulltype the type to be created
  413. */
  414. function _setTypeToCreate(fulltype)
  415. {
  416. __typeToCreate = fulltype;
  417. }
  418. /**
  419. * Unloads the selected toolbar from the current canvas
  420. * @param tb the toolbar to be unloaded
  421. */
  422. function _unloadToolbar(tb)
  423. {
  424. if( __isButtonModel(tb) )
  425. DataUtils.unloadbm(tb);
  426. else if( __isIconMetamodel(tb) )
  427. DataUtils.unloadmm(tb);
  428. }
  429. /**
  430. * Validates the current model
  431. */
  432. function _validate()
  433. {
  434. HttpUtils.httpReq(
  435. 'GET',
  436. HttpUtils.url('/validatem',__NO_USERNAME));
  437. }
  438. /******************************* 'BACKDOOR' API *******************************/
  439. /* highlight the specified node or unhighlight any highlighted nodes... the
  440. 'followCrossFormalismLinks' parameter indicates whether or not (and which)
  441. neighbors along cross-formalism links should also be highlighted... the
  442. 'timeout' parameter, if specified, indicates the duration of the highlight */
  443. function _highlight(args/*asid[,followCrossFormalismLinks,timeout]*/)
  444. {
  445. if( args == undefined )
  446. __unhighlight();
  447. else
  448. {
  449. var uri = __asid2csuri(args['asid']),
  450. fcfl = args['followCrossFormalismLinks'],
  451. timeout = args['timeout'];
  452. __highlight(uri,fcfl,timeout);
  453. }
  454. }
  455. function _highlightState(args/*asid[,followCrossFormalismLinks,timeout]*/)
  456. {
  457. var uri = __asid2csuri(args['asid']),
  458. fcfl = args['followCrossFormalismLinks'],
  459. timeout = args['timeout'];
  460. __highlight(uri,fcfl,timeout);
  461. }
  462. /* unhighlight any highlighted nodes - sadaf */
  463. function _unhighlight()
  464. {
  465. __unhighlight();
  466. }
  467. /* unhighlight any highlighted nodes - sadaf */
  468. function _unhighlightState(args/*asid*/)
  469. {
  470. //var uri = __asid2csuri(args['asid']);
  471. //__icons[uri]['icon'].unhighlight();
  472. __unhighlight(__asid2csuri(args['asid']));
  473. }
  474. /* interface to WindowManagement.spawnClient() 'USER' API function */
  475. function _loadModelInNewWindow(args/*fname[,callback-url]*/)
  476. {
  477. WindowManagement.spawnClient(args['fname'],args['callback-url']);
  478. }
  479. /**
  480. * Function to load a model in a new window, it's part of Workflows components
  481. * @param args json that contains the parameter list
  482. */
  483. function _loadModelInWindow(args/*fname[]*/)
  484. {
  485. var aid = args['atompmId'];
  486. var jsontext = args['fname'];
  487. var res = jsontext.replace('{', '{"');
  488. var res = res.replace('}', '"}');
  489. var res = res.replace(/:/g, '":"');
  490. var res = res.replace(/,/g, '","');
  491. var res = res.replace(/;/g, ',');
  492. loc = JSON.parse(res);
  493. var path = parseInt(aid)+2;
  494. var msg = parseInt(aid)+1;
  495. vas = '';
  496. if (loc[path] == undefined){
  497. vas = 'VAS';
  498. path = parseInt(aid);}
  499. as = loc[aid].indexOf("MM");
  500. cs = loc[aid].indexOf("Icons");
  501. tr = loc[aid].indexOf("R_");
  502. tf = loc[path].indexOf("T_");
  503. option = '';
  504. if( as > 0 )
  505. option = 'AS';
  506. else if(cs > 0 )
  507. option = 'CS';
  508. else if(tr > 0 )
  509. option = 'TR';
  510. else if(tf > 0 )
  511. option = 'TF';
  512. else if (vas == 'VAS')
  513. option = 'VAS';
  514. WindowManagement.spawnClientOption(loc[aid],'',loc[path],option,loc[msg]);
  515. }
  516. /**
  517. * Function to open a popup dialog for run-time parameters, it's part of Workflows components
  518. * @param args list of parameters of the workflow
  519. */
  520. function _openNewDialog(args)
  521. {
  522. var jsontext = JSON.stringify(args['args']),
  523. jsontext=JSON.parse(jsontext),
  524. ext = args['labels'],
  525. pid = args['paramId'],
  526. res = ext.replace('{', '{"'),
  527. res = res.replace('}', '"}'),
  528. res = res.replace(/:/g, '":"'),
  529. res = res.replace(/,/g, '","'),
  530. msg = args['msg'];
  531. if( ext == '{}' )
  532. WindowManagement.openDialog(_ERROR, 'No parameters to load');
  533. else {
  534. ext = JSON.parse(res);
  535. data = '';
  536. i = 0;
  537. callback =
  538. function(inputs)
  539. {
  540. for( var x in inputs ){
  541. if (data){
  542. data += ',';
  543. }
  544. lab = jsontext.widgets[i].label;
  545. n = lab.lastIndexOf("(");
  546. lab = lab.substring(n);
  547. i = i + 1;
  548. t = [];
  549. switch(lab) {
  550. case '(OpenModel)Location@2':
  551. data += x+':'+inputs[x]+'.'+ext[x];
  552. break;
  553. case '(SaveModel)Location@2':
  554. if (ext[x] == 'Icons.model' || ext[x] == 'Icons.metamodel'|| ext[x] == 'Icons.pattern.metamodel')
  555. data += x+':'+inputs[x]+ext[x];
  556. else
  557. data += x+':'+inputs[x]+'.'+ext[x];
  558. break;
  559. case '(LoadToolbar)Location@2':
  560. toolbars = inputs[x].split(";");
  561. extensions = ext[x].split(";");
  562. for ( var n in toolbars){
  563. if (extensions[n] == 'Icons.model' || extensions[n] == 'Icons.metamodel'|| extensions[n] == 'Icons.pattern.metamodel')
  564. t[n] = toolbars[n]+extensions[n];
  565. else
  566. t[n] = toolbars[n]+'.'+extensions[n];
  567. }
  568. txt = t.join(";");
  569. data += x+':'+txt;
  570. break;
  571. case '(GeneratePMM)Location@2':
  572. data += x+':'+inputs[x]+'.'+ext[x];
  573. break;
  574. case '(OpenTransformation)Location@2':
  575. data += x+':'+inputs[x]+'.'+ext[x];
  576. break;
  577. }
  578. _updateAttr({"asid":x,"attr":"Location@2","val":inputs[x]});
  579. }
  580. data += ','+msg;
  581. data = '{'+data;
  582. data += '}';
  583. _updateAttr({"asid":pid,"attr":"parameterList","val":data});
  584. play = function()
  585. {
  586. _httpReq(
  587. 'PUT',
  588. '/__mt/execmode?wid='+__wid,
  589. {'mode':'play'});
  590. };
  591. _httpReq(
  592. 'PUT',
  593. '/__mt/current.transform?wid='+__wid,
  594. {'transfs':['/Formalisms/Workflows/simulate/T_WorkflowsAddDependParam.model'],
  595. 'username':__user},
  596. play);
  597. };
  598. WindowManagement.openDialog(
  599. _CUSTOM,
  600. args['args'],
  601. callback);
  602. }
  603. }
  604. /**
  605. * Function to load a toolbar in a new window, it's part of Workflows components
  606. * @param args json that contains the parameter list
  607. */
  608. function _loadToolbarInWindow(args/*fname[]*/)
  609. {
  610. var aid = args['atompmId'];
  611. var jsontext = args['fname'];
  612. var res = jsontext.replace('{', '{"');
  613. var res = res.replace('}', '"}');
  614. var res = res.replace(/:/g, '":"');
  615. var res = res.replace(/,/g, '","');
  616. var res = res.replace(/;/g, ',');
  617. loc = JSON.parse(res);
  618. var path = parseInt(aid)+2;
  619. var msg = parseInt(aid)+1;
  620. as = loc[aid].indexOf("SimpleClassDiagram");
  621. cs = loc[aid].indexOf("ConcreteSyntax");
  622. tr = loc[aid].indexOf("Rule");
  623. tf = loc[aid].indexOf("MoTif");
  624. option = '';
  625. if( as > 0 )
  626. option = 'AS';
  627. else if(cs > 0 )
  628. option = 'CS';
  629. else if(tr > 0 )
  630. option = 'TR';
  631. else if(tf > 0 )
  632. option = 'TF';
  633. WindowManagement.spawnClientOption(loc[path],loc[aid],option,'',loc[msg]);
  634. }
  635. /**
  636. * Function to compile a Pattern metamodel, it's part of Workflows components
  637. * @param args json that contains the parameter list
  638. */
  639. function _compilePMMInWindow(args/*fname[]*/)
  640. {
  641. var aid = args['atompmId'];
  642. var jsontext = args['fname'];
  643. var res = jsontext.replace('{', '{"');
  644. var res = res.replace('}', '"}');
  645. var res = res.replace(/:/g, '":"');
  646. var res = res.replace(/,/g, '","');
  647. loc = JSON.parse(res);
  648. console.log(loc[aid]);
  649. CompileUtils.compileToPatternMM(loc[aid]);
  650. }
  651. /* tag the specified node with some text, possibly appending it to an existing
  652. tag... the 'timeout' parameter, if specified, indicates how long the tag
  653. should be displayed */
  654. function _tag(args/*asid,text[,style,append,timeout]*/)
  655. {
  656. var uri = __asid2csuri(args['asid']),
  657. text = args['text'],
  658. style = utils.mergeDicts(
  659. [{'font-size':'16px', 'font-style':'italic', 'fill':'#ffffff'},
  660. args['style']]),
  661. append = args['append'],
  662. timeout = args['timeout'];
  663. __tag(uri,text,style,append,timeout);
  664. }
  665. /* update an attribute of the specified node, possibly highlighting the node to
  666. indicate the change (note that this doesn't unhighlight any currently
  667. highlighted nodes) */
  668. function _updateAttr(args/*asid,attr,val[,highlight]*/)
  669. {
  670. var uri = __asid2csuri(args['asid']),
  671. changes = {};
  672. changes[args['attr']] = args['val'];
  673. DataUtils.update(uri,changes);
  674. if( args['highlight'] )
  675. __flash(uri);
  676. }
  677. /******************************** CRUD QUERIES ********************************/
  678. /*************************** HANDLE QUERY RESPONSE ****************************/
  679. /***************************** EDIT CONFLICTS... ******************************/
  680. var __watchList = {};
  681. function __changed(uri,set)
  682. {
  683. if( set )
  684. __watchList[uri] = __EDIT_CONFLICT;
  685. else
  686. return __watchList[uri] == __EDIT_CONFLICT;
  687. }
  688. //TBC place calls to this appropriately (with CS/AS uris...)
  689. function __unwatch(uri)
  690. {
  691. delete __watchList[uri];
  692. }
  693. //TBC place calls to this appropriately (with CS/AS uris...)
  694. function __watch(uri)
  695. {
  696. __watchList[uri] = __NO_CONFLICT;
  697. }
  698. function __watching(uri)
  699. {
  700. return uri in __watchList;
  701. }
  702. /***************************** MMM-RELATED LOGIC ******************************/
  703. /**************************** CANVAS BEHAVIOUR... *****************************/
  704. /*------------------------ BEHAVIOUR-RELATED UTILITIES -----------------------*/
  705. /*------------------------- SELECTING ICONS/EDGES... -------------------------*/
  706. /*--------------------------- DRAWING CONNECTIONS ----------------------------*/
  707. /*------------------------------ HIGHLIGHTING --------------------------------*/
  708. /*--------------------------------- TAGGING ----------------------------------*/
  709. /* tag the specified node and setup delayed tag removal, when applicable */
  710. function __tag(uri,text,style,append,timeout)
  711. {
  712. __icons[uri]['icon'].tag(text,style,append);
  713. if( timeout != undefined )
  714. window.setTimeout(__icons[uri]['icon'].tag,timeout,'');
  715. }
  716. /*------------------------------- LAYERING... --------------------------------*/
  717. function __iconToBack(tgt)
  718. {
  719. __icons[__vobj2uri(tgt)]['icon'].toBack();
  720. }
  721. function __iconToFront(tgt)
  722. {
  723. __icons[__vobj2uri(tgt)]['icon'].toFront();
  724. }
  725. /*---------------------------- LAYOUT -----------------------------*/
  726. function _autolayout()
  727. {
  728. Layout.autolayout();
  729. }
  730. /*---------------------------- SELECTION OVERLAY -----------------------------*/
  731. /*---------------- GEOMETRY CONTROLS AND TRANSFORMATIONS... ------------------*/
  732. /*-------------------------- CONNECTION EDITING... ---------------------------*/
  733. /************************* GRAPH TRAVERSAL UTILITIES **************************/
  734. /* return the ids of edges connected to the specified node */
  735. function __getConnectedEdges(uri)
  736. {
  737. var edgeIds = [];
  738. for( var edgeId in __edges )
  739. if( __edges[edgeId]['start'] == uri ||
  740. __edges[edgeId]['end'] == uri )
  741. edgeIds.push(edgeId);
  742. return edgeIds;
  743. }
  744. /* given an edge, returns an array containing that edge's start and/or end
  745. linktype(s), and its(their) connected edges (which include the given edge) */
  746. function __getConnectionParticipants(edgeId)
  747. {
  748. var start = __edges[edgeId]['start'],
  749. end = __edges[edgeId]['end'],
  750. cm = [];
  751. if( __isConnectionType(start) )
  752. cm = cm.concat(start, __getConnectedEdges(start));
  753. if( __isConnectionType(end) )
  754. cm = cm.concat(end, __getConnectedEdges(end));
  755. return cm;
  756. }
  757. /* return all of the edges and nodes directly or indirectly connected to 'uri'
  758. via cross-formalism links in direction 'dir'... the meaning of 'dir' follows
  759. from the convention that cross-formalism link go from higher-level constructs
  760. to lower-level ones
  761. 1. filter __edges keeping only cross-formalism ones
  762. 2. if dir is '*' or 'DOWN', recursively navigate the edges from step 1.
  763. out of 'uri' marking appropriate nodes and edges
  764. 3. if dir is '*' or 'UP', recursively navigate the edges from step 1.
  765. into 'uri' marking appropriate nodes and edges */
  766. function __getCrossFormalismNeighbors(uri,dir)
  767. {
  768. var crossFormalismEdges = [];
  769. for( var edgeId in __edges )
  770. if( __getMetamodel(__edges[edgeId]['start']) !=
  771. __getMetamodel(__edges[edgeId]['end']) )
  772. crossFormalismEdges.push(edgeId);
  773. function _(neighbors,lookfor,append)
  774. {
  775. var tovisit = [uri];
  776. while( tovisit.length > 0 )
  777. {
  778. var curr = tovisit.shift();
  779. neighbors.nodes.push(curr);
  780. crossFormalismEdges.forEach(
  781. function(edgeId)
  782. {
  783. if( __edges[edgeId][lookfor] == curr )
  784. {
  785. var ext = __edges[edgeId][append];
  786. if( ! utils.contains(neighbors.nodes,ext) )
  787. tovisit.push(ext);
  788. if( ! utils.contains(neighbors.edges,edgeId) )
  789. neighbors.edges.push(edgeId);
  790. }
  791. });
  792. }
  793. return neighbors;
  794. }
  795. var dn = {'nodes':[],'edges':[]}, un = {'nodes':[],'edges':[]};
  796. if( dir == '*' || dir == 'DOWN' )
  797. _(dn,'start','end');
  798. if( dir == '*' || dir == 'UP' )
  799. _(un,'end','start');
  800. return {'nodes':utils.toSet(dn.nodes.concat(un.nodes)),
  801. 'edges':utils.toSet(dn.nodes.concat(un.nodes))};
  802. }
  803. /***************************** HTML-GUI UTILITIES *****************************/
  804. /****************************** SVG... UTILITIES ******************************/
  805. /******************************* MISC UTILITIES *******************************/
  806. /* returns the csuri associated to the given asid */
  807. function __asid2csuri(asid)
  808. {
  809. for( var uri in __icons )
  810. if( __icons[uri]['icon'].getAttr('__asuri').
  811. match(/.*\/(.*)\.instance/)[1] == asid )
  812. return uri;
  813. }
  814. /* returns the edgeId associated to the given edge DOM element */
  815. function __edge2edgeId(edge)
  816. {
  817. return edge.parentNode.getAttribute('__edgeId');
  818. }
  819. /* returns both ends contained in the given edgeId */
  820. function __edgeId2ends(edgeId)
  821. {
  822. if( edgeId in __edges )
  823. return [__edges[edgeId]['start'],__edges[edgeId]['end']];
  824. else
  825. return edgeId.match(/^(.*\.instance)--(.*\.instance)$/).slice(1);
  826. }
  827. /* returns the linkuri associated to the given edgeId */
  828. function __edgeId2linkuri(edgeId)
  829. {
  830. return __edges[edgeId]['icon'].getAttr('__linkuri');
  831. }
  832. /* filter a list of filenames given the specified extensions */
  833. function __filterFilenamesByExtension(fnames,extensions)
  834. {
  835. var ffnames = fnames.filter(
  836. function(fname)
  837. {
  838. return extensions.some(
  839. function(ext)
  840. {
  841. return fname.match(ext+'$');
  842. });
  843. });
  844. return ffnames;
  845. }
  846. /* return the icon associated to the given csuri or edgeid */
  847. function __getIcon(_)
  848. {
  849. return (_ in __icons ?
  850. __icons[_]['icon'] :
  851. (_ in __edges ?
  852. __edges[_]['icon'] :
  853. undefined));
  854. }
  855. /* return true if the current model contains no unsaved changes */
  856. function __isSaved()
  857. {
  858. return ! document.title.match(__TITLE+' - \\+');
  859. }
  860. /* return true if the given element is a toolbar or inside a toolbar */
  861. function __isAToolbar(el)
  862. {
  863. return Boolean(
  864. (el.id && el.id.match(/^div_toolbar_/)) ||
  865. (el.parentNode && __isAToolbar(el.parentNode)) );
  866. }
  867. /* return true if the given element is the canvas or something drawn on it */
  868. function __isCanvasElement(el)
  869. {
  870. return el.attr("id") == 'div_canvas' ||
  871. ( (el.parent().length > 0) && __isCanvasElement(el.parent()));
  872. }
  873. /* returns the $segments hash associated to the given edgeId */
  874. function __linkuri2segments(linkuri)
  875. {
  876. return utils.jsonp(__icons[linkuri]['icon'].getAttr('__segments'));
  877. }
  878. /* truncate './users/<username>' from a list of filenames */
  879. function __localizeFilenames(fnames)
  880. {
  881. return fnames.map(
  882. function(n)
  883. {
  884. return n.match(/^\.\/users\/.*?(\/.*)/)[1];
  885. });
  886. }
  887. /* modify a URL as needed to ensure GETting it will produce desired result:
  888. . prepend username to user files
  889. . do nothing for WWW files */
  890. function __relativizeURL(url)
  891. {
  892. if( url.charAt(0) == '.' || url.charAt(0) == '/' )
  893. return HttpUtils.url(url,__NO_WID);
  894. return url;
  895. }
  896. /* returns the csuri of the icon that contains the specified VisualObject */
  897. function __vobj2uri(vobj) {
  898. if (vobj != document.body) {
  899. return vobj.parentNode.getAttribute('__csuri') ||
  900. vobj.parentNode.getAttribute('__linkuri') ||
  901. __vobj2uri(vobj.parentNode);
  902. }
  903. }
  904. function __getRecentDir(name) {
  905. return utils.readCookie('recentDir'+name);
  906. }
  907. function __setRecentDir(name,value) {
  908. utils.createCookie('recentDir'+name,value);
  909. }