data_utils.js 11 KB

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