data_utils.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  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. /* delete specified file/folder */
  6. DataUtils = function(){
  7. /*
  8. NOTE:: information about the pathString is bundled with the request... if the
  9. request succeeds, it is returned along with the changelog and used to
  10. draw the requested connection [and center-piece]
  11. NOTE:: DataUtils.connect() may be called from the behaviour statechart with a single
  12. parameter (i.e., event.target)... in such cases, we construct an
  13. appropriate 2-parameter call to DataUtils.connect() and recurse
  14. */
  15. /**
  16. * Requests a connection of specified instances with center-piece (if and when any)
  17. * at center of ConnectionUtils.getConnectionPath(). In practice, before this request
  18. * is sent, the user is prompted to either choose a connection type (this choice is
  19. * made for him when exactly one type is available) or to be told that no legal
  20. * connection exists
  21. */
  22. this.connect = function(uri1,uri2){
  23. if( uri2 == undefined )
  24. return DataUtils.connect(ConnectionUtils.getConnectionSource(), __vobj2uri(uri1));
  25. var segments = __path2segments(ConnectionUtils.getConnectionPath()),
  26. pathCenter = segments.splice(1,1)[0],
  27. callback =
  28. function(connectionType)
  29. {
  30. HttpUtils.httpReq(
  31. 'POST',
  32. HttpUtils.url(connectionType,__NO_USERNAME),
  33. {'src':uri1,
  34. 'dest':uri2,
  35. 'pos':[pathCenter.x,pathCenter.y],
  36. 'segments':segments});
  37. };
  38. ConnectionUtils.hideConnectionPath();
  39. WindowManagement.openDialog(
  40. _LEGAL_CONNECTIONS,
  41. {'uri1':uri1,'uri2':uri2,'ctype':__VISUAL_LINK},
  42. callback);
  43. };
  44. /**
  45. * Request creation of an instance of __typeToCreate at the specified
  46. * x and y coordinates
  47. */
  48. this.create = function (x, y, callback) {
  49. if (__typeToCreate == undefined) {
  50. WindowManagement.openDialog(_ERROR, 'you must select a type to create');
  51. } else {
  52. HttpUtils.httpReq(
  53. 'POST',
  54. HttpUtils.url(__typeToCreate + '.type', __NO_USERNAME),
  55. {'pos': [x, y]},
  56. callback);
  57. }
  58. };
  59. /**
  60. * Deletes the current selection entities
  61. */
  62. this.del = function(){
  63. var requests = [];
  64. __selection['items'].forEach(
  65. function(it)
  66. {
  67. if( it in __icons )
  68. requests.push(
  69. {'method':'DELETE',
  70. 'uri':HttpUtils.url(it,__NO_USERNAME+__NO_WID)});
  71. });
  72. HttpUtils.httpReq(
  73. 'POST',
  74. HttpUtils.url('/batchEdit',__NO_USERNAME),
  75. requests);
  76. };
  77. /**
  78. * Deletes the file from the cloud storage by URI
  79. *
  80. * @param fileuri - the file/folder to delete
  81. * @param callback - the callback function after the operation
  82. * has completed
  83. */
  84. this.deleteFromCloud = function(fileuri,callback){
  85. HttpUtils.httpReq(
  86. 'DELETE',
  87. fileuri,
  88. undefined,
  89. callback);
  90. };
  91. /**
  92. * Create a folder
  93. *
  94. * @param fileuri - the folder to create
  95. * @param callback - the callback function after the operation
  96. * has completed
  97. */
  98. this.createFolder = function(folderuri,callback){
  99. HttpUtils.httpReq(
  100. 'POST',
  101. folderuri,
  102. undefined,
  103. callback);
  104. };
  105. /**
  106. * Rename a file/folder in the cloud
  107. *
  108. * @param fileuri - the file/folder to rename
  109. * @param newname - the new name of the file/folder
  110. * @param callback - the callback function after the operation
  111. * has completed
  112. */
  113. this.renameInCloud = function(folderuri,newname,callback){
  114. HttpUtils.httpReq(
  115. 'PUT',
  116. folderuri,
  117. newname,
  118. callback);
  119. };
  120. /**
  121. * Move a file/folder in the cloud
  122. *
  123. * @param fileuri - the file/folder to rename
  124. * @param newlocation - the new location of the file/folder (needs to start with a '/')
  125. * @param callback - the callback function after the operation
  126. * has completed
  127. */
  128. this.moveInCloud = function(folderuri,newlocation,callback){
  129. HttpUtils.httpReq(
  130. 'PUT',
  131. folderuri,
  132. newlocation,
  133. callback);
  134. };
  135. /*
  136. 1. retrieve and validate uri associated to 'into'
  137. 2. validate and/or setup 'items' (see NOTE)
  138. 3. prompt for connection type
  139. *. return connection type or undefined via 'callback'
  140. NOTE:: when 'items' is undefined, __selection.items is used as the default
  141. */
  142. /**
  143. * Prompt user to select a containment link type (or chooses it for him if there
  144. * is only one) and pass the choice to the callback function.
  145. *
  146. * @param into - where to put the connection
  147. * @param items - items to insert
  148. * @param callback - function to call when finished with the request
  149. */
  150. this.getInsertConnectionType = function(into,items,callback){
  151. var intouri = into.getAttribute('__csuri');
  152. if( intouri == undefined ||
  153. !(intouri in __icons) ||
  154. __isConnectionType(intouri) )
  155. return callback();
  156. if( (items == undefined || items.length == 0) &&
  157. (__selection == undefined || __selection['items'].length == 0) )
  158. return callback();
  159. items = (items || __selection['items']);
  160. WindowManagement.openDialog(
  161. _LEGAL_CONNECTIONS,
  162. {'uri1':intouri,
  163. 'uri2':items[0],
  164. 'ctype':__CONTAINMENT_LINK,
  165. 'forceCallback':true},
  166. function(ctype)
  167. {
  168. if( utils.isObject(ctype) && '$err' in ctype )
  169. callback();
  170. else
  171. callback(ctype);
  172. });
  173. };
  174. /*
  175. 1. foreach non-connection type icon in 'items' that is not already inside
  176. 'into' or any other icon in 'items'
  177. a. synthesize a path from 'into''s top-left to the icon's center
  178. b. save that path's center and 2 halves
  179. c. remove the path
  180. d. remember connection request
  181. 2. send all requests from step 1d as a single batchEdit or return them
  182. NOTE:: similarly to what is done in DataUtils.connect(), each connection request is
  183. bundled with 'pos' and 'segments'... here however, since the user drew
  184. no path, these are both synthesic... this serves 2 purposes: first, it
  185. shields the csworker from receiving different queries for containment
  186. and visual connections, but most importantly, it ensures that
  187. containment links have an existing visual representation if one is
  188. needed
  189. NOTE:: the 'context' parameter contains a list of pending changes computed by
  190. GeometryUtils.transformSelection() but not yet persisted onto the canvas... this
  191. seemingly odd passing around of pending information is necessary to
  192. enable atomicity of icon transformations and insertions
  193. */
  194. /**
  195. * Inserts 'items' into 'into' (connects them via a containment link of type
  196. * 'connectionType'). This sends a bundle of batched connection requets to csworker.
  197. */
  198. this.insert = function(into,items,connectionType,context,dryRun) {
  199. var intobbox = __getBBox(into,context),
  200. requests = [];
  201. items.forEach(
  202. function(it)
  203. {
  204. if( ! (it in __icons) ||
  205. __isConnectionType(it) ||
  206. __isDirectlyContainedIn(it,into) ||
  207. items.some(
  208. function(_it)
  209. {
  210. return __isDirectlyContainedIn(it,_it);
  211. }) )
  212. return;
  213. var itbbox = __getBBox(it,context),
  214. itcenter = [itbbox.x+itbbox.width/2, itbbox.y+itbbox.height/2],
  215. path = __canvas.path(
  216. 'M'+intobbox.x+','+intobbox.y+'L'+itcenter),
  217. segments = __path2segments(path),
  218. pathCenter = segments.splice(1,1)[0];
  219. path.remove();
  220. requests.push(
  221. {'method':'POST',
  222. 'uri':HttpUtils.url(connectionType,__NO_USERNAME+__NO_WID),
  223. 'reqData':
  224. {'src':into,
  225. 'dest':it,
  226. 'pos':[pathCenter.x,pathCenter.y],
  227. 'segments':segments}});
  228. __icons[it]['edgesIn'].forEach(
  229. function(edgeId)
  230. {
  231. var linkIn = __edgeId2ends(edgeId)[0];
  232. if( __isContainmentConnectionType(linkIn) ) {
  233. requests.push(
  234. {'method':'DELETE',
  235. 'uri':HttpUtils.url(linkIn,__NO_USERNAME+__NO_WID)});
  236. }
  237. });
  238. });
  239. if( dryRun )
  240. return requests;
  241. else if( requests.length > 0 )
  242. HttpUtils.httpReq(
  243. 'POST',
  244. HttpUtils.url('/batchEdit',__NO_USERNAME),
  245. requests);
  246. };
  247. /**
  248. * Loads the Button Model
  249. *
  250. * @param bm - the button model to load
  251. */
  252. this.loadbm = function (bm) {
  253. HttpUtils.httpReq(
  254. 'GET',
  255. HttpUtils.url(bm, true),
  256. undefined,
  257. function (statusCode, resp) {
  258. if (!utils.isHttpSuccessCode(statusCode)) {
  259. if (resp.includes("ENOENT")) {
  260. let err_msg = "Error! File not found: " + bm;
  261. WindowManagement.openDialog(_ERROR, err_msg);
  262. } else {
  263. WindowManagement.openDialog(_ERROR, resp);
  264. }
  265. return;
  266. }
  267. GUIUtils.setupAndShowToolbar(
  268. bm,
  269. eval('(' + resp + ')'),
  270. __BUTTON_TOOLBAR);
  271. });
  272. };
  273. /*
  274. 1. does the deed
  275. 2. if a 'missing metamodel' error is returned
  276. a. request that the missing metamodel be loaded
  277. i. if an error is returned, show it
  278. ii. otherwise, return to step 1. */
  279. /**
  280. * Request that the specified model be loaded
  281. */
  282. this.loadm = function (fname, insert) {
  283. HttpUtils.httpReq(
  284. 'PUT',
  285. HttpUtils.url('/current.model', __NO_USERNAME),
  286. {
  287. 'm': HttpUtils.url(fname, __NO_WID),
  288. 'insert': insert
  289. },
  290. function (statusCode, resp) {
  291. if (utils.isHttpSuccessCode(statusCode)) {
  292. WindowManagement.setWindowTitle();
  293. return;
  294. }
  295. if ((matches = resp.match(/metamodel not loaded :: (.*)/))) {
  296. var missing = matches[1] + '.metamodel';
  297. console.warn('auto-loading missing metamodel :: ' + missing);
  298. DataUtils.loadmm(missing,
  299. function (_statusCode, _resp) {
  300. if (!utils.isHttpSuccessCode(_statusCode)) {
  301. if (_resp.includes("ENOENT")) {
  302. _resp = utils.jsonp(_resp);
  303. _resp = "Error! File not found: " + _resp['path'];
  304. }
  305. WindowManagement.openDialog(_ERROR, _resp);
  306. }
  307. else {
  308. DataUtils.loadm(fname, insert);
  309. }
  310. });
  311. } else {
  312. if (resp.includes("cannot read")) {
  313. let err_msg = "Error! File cannot be read: " + fname;
  314. WindowManagement.openDialog(_ERROR, err_msg);
  315. } else {
  316. WindowManagement.openDialog(_ERROR, resp);
  317. }
  318. }
  319. });
  320. };
  321. /*
  322. CASE 1: asmm is already loaded but with a different csmm
  323. > request params only contain csmm
  324. > triggers back-end CS-switch
  325. CASE 2: asmm is not loaded or is loaded with the specified csmm
  326. > request params contain asmm and csmm
  327. > triggers back-end metamodel (re-)load */
  328. /**
  329. * Loads (or reloads) the specified metamodel
  330. */
  331. this.loadmm = function(imm,callback){
  332. var asmm = __iconMetamodelToMetamodel(imm),
  333. sameASMM = function(mm) {
  334. return __isIconMetamodel(mm) &&
  335. __iconMetamodelToMetamodel(mm) == asmm;
  336. },
  337. params;
  338. if( !(imm in __loadedToolbars) &&
  339. utils.keys(__loadedToolbars).some(sameASMM) )
  340. params = {'csmm':HttpUtils.url(imm,__NO_WID)};
  341. else
  342. params = {'csmm':HttpUtils.url(imm,__NO_WID), 'asmm':HttpUtils.url(asmm,__NO_WID)};
  343. HttpUtils.httpReq(
  344. 'PUT',
  345. HttpUtils.url('/current.metamodels', __NO_USERNAME),
  346. params,
  347. callback);
  348. };
  349. /**
  350. * Saves the current model to the specified file
  351. */
  352. this.savem = function(fname){
  353. HttpUtils.httpReq(
  354. 'PUT',
  355. HttpUtils.url(fname,__FORCE_GET));
  356. };
  357. /**
  358. * Unloads the selected button model
  359. */
  360. this.unloadbm = function(bm){
  361. GUIUtils.removeToolbar(bm);
  362. };
  363. /**
  364. * Unloads the selected metamodel
  365. */
  366. this.unloadmm = function(mm){
  367. HttpUtils.httpReq(
  368. 'DELETE',
  369. HttpUtils.url(mm,__NO_USERNAME));
  370. };
  371. /**
  372. * Updates the current model with the listed
  373. * changes
  374. */
  375. this.update = function(uri,changes){
  376. if( utils.keys(changes).length > 0 )
  377. HttpUtils.httpReq(
  378. 'PUT',
  379. HttpUtils.url(uri,__NO_USERNAME),
  380. {'changes':changes});
  381. };
  382. /**
  383. * Updates using a worker thread?
  384. */
  385. this.updatecs = function(uri,changes){
  386. HttpUtils.httpReq(
  387. 'PUT',
  388. HttpUtils.url(uri+'.cs',__NO_USERNAME),
  389. {'changes':changes});
  390. };
  391. /**
  392. * Uploads the data to a file specified by the tofolder entry
  393. *
  394. * @param tofolder - the folder to upload the data to
  395. * @param data - the data to upload
  396. * @param callback - the callback function after the operation
  397. * has completed
  398. */
  399. this.uploadToCloud = function(tofolder,data,callback){
  400. HttpUtils.httpReq(
  401. 'PUT',
  402. HttpUtils.url(tofolder+'.file',__NO_WID),
  403. data,
  404. callback);
  405. };
  406. return this;
  407. }();