data_utils.js 12 KB

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