client.js 29 KB

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