data_utils.js 12 KB

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