data_utils.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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. {
  259. GUIUtils.setupAndShowToolbar(
  260. bm,
  261. eval('('+resp+')'),
  262. __BUTTON_TOOLBAR);
  263. });
  264. };
  265. /*
  266. 1. does the deed
  267. 2. if a 'missing metamodel' error is returned
  268. a. request that the missing metamodel be loaded
  269. i. if an error is returned, show it
  270. ii. otherwise, return to step 1. */
  271. /**
  272. * Request that the specified model be loaded
  273. */
  274. this.loadm = function (fname, insert) {
  275. HttpUtils.httpReq(
  276. 'PUT',
  277. HttpUtils.url('/current.model', __NO_USERNAME),
  278. {
  279. 'm': HttpUtils.url(fname, __NO_WID),
  280. 'insert': insert
  281. },
  282. function (statusCode, resp) {
  283. if (utils.isHttpSuccessCode(statusCode)) {
  284. WindowManagement.setWindowTitle();
  285. return;
  286. }
  287. if ((matches = resp.match(/metamodel not loaded :: (.*)/))) {
  288. var missing = matches[1] + '.metamodel';
  289. console.warn('auto-loading missing metamodel :: ' + missing);
  290. DataUtils.loadmm(missing,
  291. function (_statusCode, _resp) {
  292. if (!utils.isHttpSuccessCode(_statusCode)) {
  293. if (_resp.includes("ENOENT")) {
  294. _resp = utils.jsonp(_resp);
  295. _resp = "Error! File not found: " + _resp['path'];
  296. }
  297. WindowManagement.openDialog(_ERROR, _resp);
  298. }
  299. else {
  300. DataUtils.loadm(fname, insert);
  301. }
  302. });
  303. }
  304. else
  305. WindowManagement.openDialog(_ERROR, resp);
  306. });
  307. };
  308. /*
  309. CASE 1: asmm is already loaded but with a different csmm
  310. > request params only contain csmm
  311. > triggers back-end CS-switch
  312. CASE 2: asmm is not loaded or is loaded with the specified csmm
  313. > request params contain asmm and csmm
  314. > triggers back-end metamodel (re-)load */
  315. /**
  316. * Loads (or reloads) the specified metamodel
  317. */
  318. this.loadmm = function(imm,callback){
  319. var asmm = __iconMetamodelToMetamodel(imm),
  320. sameASMM = function(mm) {
  321. return __isIconMetamodel(mm) &&
  322. __iconMetamodelToMetamodel(mm) == asmm;
  323. },
  324. params;
  325. if( !(imm in __loadedToolbars) &&
  326. utils.keys(__loadedToolbars).some(sameASMM) )
  327. params = {'csmm':HttpUtils.url(imm,__NO_WID)};
  328. else
  329. params = {'csmm':HttpUtils.url(imm,__NO_WID), 'asmm':HttpUtils.url(asmm,__NO_WID)};
  330. HttpUtils.httpReq(
  331. 'PUT',
  332. HttpUtils.url('/current.metamodels', __NO_USERNAME),
  333. params,
  334. callback);
  335. };
  336. /**
  337. * Saves the current model to the specified file
  338. */
  339. this.savem = function(fname){
  340. HttpUtils.httpReq(
  341. 'PUT',
  342. HttpUtils.url(fname,__FORCE_GET));
  343. };
  344. /**
  345. * Unloads the selected button model
  346. */
  347. this.unloadbm = function(bm){
  348. GUIUtils.removeToolbar(bm);
  349. };
  350. /**
  351. * Unloads the selected metamodel
  352. */
  353. this.unloadmm = function(mm){
  354. HttpUtils.httpReq(
  355. 'DELETE',
  356. HttpUtils.url(mm,__NO_USERNAME));
  357. };
  358. /**
  359. * Updates the current model with the listed
  360. * changes
  361. */
  362. this.update = function(uri,changes){
  363. if( utils.keys(changes).length > 0 )
  364. HttpUtils.httpReq(
  365. 'PUT',
  366. HttpUtils.url(uri,__NO_USERNAME),
  367. {'changes':changes});
  368. };
  369. /**
  370. * Updates using a worker thread?
  371. */
  372. this.updatecs = function(uri,changes){
  373. HttpUtils.httpReq(
  374. 'PUT',
  375. HttpUtils.url(uri+'.cs',__NO_USERNAME),
  376. {'changes':changes});
  377. };
  378. /**
  379. * Uploads the data to a file specified by the tofolder entry
  380. *
  381. * @param tofolder - the folder to upload the data to
  382. * @param data - the data to upload
  383. * @param callback - the callback function after the operation
  384. * has completed
  385. */
  386. this.uploadToCloud = function(tofolder,data,callback){
  387. HttpUtils.httpReq(
  388. 'PUT',
  389. HttpUtils.url(tofolder+'.file',__NO_WID),
  390. data,
  391. callback);
  392. };
  393. return this;
  394. }();